http-request-manager 15.0.24 → 15.0.26

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 (232) hide show
  1. package/ng-package.json +8 -0
  2. package/package.json +1 -14
  3. package/src/lib/http-request-manager.module.ts +101 -0
  4. package/src/lib/http-request-services-demo/database-data-demo/database-data-demo.component.html +3 -0
  5. package/src/lib/http-request-services-demo/database-data-demo/database-data-demo.component.scss +0 -0
  6. package/src/lib/http-request-services-demo/database-data-demo/database-data-demo.component.ts +105 -0
  7. package/src/lib/http-request-services-demo/http-request-services-demo.component.html +64 -0
  8. package/src/lib/http-request-services-demo/http-request-services-demo.component.scss +6 -0
  9. package/src/lib/http-request-services-demo/http-request-services-demo.component.ts +34 -0
  10. package/src/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.html +195 -0
  11. package/src/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.scss +17 -0
  12. package/src/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.ts +205 -0
  13. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.html +59 -0
  14. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.scss +60 -0
  15. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.ts +71 -0
  16. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-download.module.ts +28 -0
  17. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.html +10 -0
  18. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.scss +29 -0
  19. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.ts +99 -0
  20. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/models/download-labels-model.ts +22 -0
  21. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.html +8 -0
  22. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.scss +19 -0
  23. package/src/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.ts +25 -0
  24. package/src/lib/http-request-services-demo/request-manager-demo/models/app-session.model.ts +30 -0
  25. package/src/lib/http-request-services-demo/request-manager-demo/models/app.model.ts +19 -0
  26. package/src/lib/http-request-services-demo/request-manager-demo/models/get-sample.model.ts +25 -0
  27. package/src/lib/http-request-services-demo/request-manager-demo/models/sample-ai-prompt.ts +19 -0
  28. package/src/lib/http-request-services-demo/request-manager-demo/models/sample-client-details.ts +24 -0
  29. package/src/lib/http-request-services-demo/request-manager-demo/models/sample-client-info.ts +30 -0
  30. package/src/lib/http-request-services-demo/request-manager-demo/models/sample-client.model.ts +49 -0
  31. package/src/lib/http-request-services-demo/request-manager-demo/models/sample-mapper-client-info.ts +33 -0
  32. package/src/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.html +336 -0
  33. package/src/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.scss +24 -0
  34. package/src/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.ts +403 -0
  35. package/src/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.html +328 -0
  36. package/src/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.scss +24 -0
  37. package/src/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.ts +347 -0
  38. package/src/lib/http-request-services-demo/request-manager-state-demo/services/state-manager-demo.service.ts +88 -0
  39. package/src/lib/index.ts +3 -0
  40. package/src/lib/interceptors/credentials.interceptor.ts +18 -0
  41. package/{lib/interceptors/index.d.ts → src/lib/interceptors/index.ts} +2 -0
  42. package/src/lib/interceptors/models/error-settings.model.ts +22 -0
  43. package/src/lib/interceptors/proxy-debugger.interceptor.ts +46 -0
  44. package/src/lib/interceptors/request-error.interceptor.ts +65 -0
  45. package/src/lib/interceptors/request-header.interceptor.ts +58 -0
  46. package/src/lib/models/config-http-options.model.ts +42 -0
  47. package/src/lib/models/config-local-storage-options.model.ts +27 -0
  48. package/src/lib/models/config-options.model.ts +27 -0
  49. package/{lib/models/config-token.model.d.ts → src/lib/models/config-token.model.ts} +2 -1
  50. package/src/lib/models/data-type.enum.ts +5 -0
  51. package/src/lib/models/database-storage.model.ts +24 -0
  52. package/src/lib/models/index.ts +9 -0
  53. package/src/lib/models/retry-options.model.ts +22 -0
  54. package/src/lib/services/database-manager-services/database.manager.service.ts +193 -0
  55. package/src/lib/services/database-manager-services/db.storage.service.ts +191 -0
  56. package/{lib/services/database-manager-services/index.d.ts → src/lib/services/database-manager-services/index.ts} +1 -0
  57. package/src/lib/services/database-manager-services/models/table-schema.ts +35 -0
  58. package/{lib/services/index.d.ts → src/lib/services/index.ts} +4 -0
  59. package/src/lib/services/local-storage-manager-service/index.ts +2 -0
  60. package/src/lib/services/local-storage-manager-service/local-storage-manager.service.spec.ts +71 -0
  61. package/src/lib/services/local-storage-manager-service/local-storage-manager.service.ts +421 -0
  62. package/src/lib/services/local-storage-manager-service/models/global-store-options.model.ts +30 -0
  63. package/{lib/services/local-storage-manager-service/models/index.d.ts → src/lib/services/local-storage-manager-service/models/index.ts} +2 -1
  64. package/src/lib/services/local-storage-manager-service/models/setting-options.model.ts +30 -0
  65. package/src/lib/services/local-storage-manager-service/models/storage-data.model.ts +24 -0
  66. package/src/lib/services/local-storage-manager-service/models/storage-option.model.ts +29 -0
  67. package/src/lib/services/local-storage-manager-service/models/storage-type.enum.ts +5 -0
  68. package/src/lib/services/request-manager-services/README.md +268 -0
  69. package/src/lib/services/request-manager-services/http-manager.service.spec.ts +230 -0
  70. package/src/lib/services/request-manager-services/http-manager.service.ts +274 -0
  71. package/{lib/services/request-manager-services/index.d.ts → src/lib/services/request-manager-services/index.ts} +2 -0
  72. package/src/lib/services/request-manager-services/request.service.ts +261 -0
  73. package/src/lib/services/request-manager-services/rxjs-operators/countdown.ts +17 -0
  74. package/src/lib/services/request-manager-services/rxjs-operators/delay-retry.ts +16 -0
  75. package/src/lib/services/request-manager-services/rxjs-operators/request-polling.ts +21 -0
  76. package/src/lib/services/request-manager-services/rxjs-operators/request-streaming.ts +32 -0
  77. package/src/lib/services/request-manager-state-service/http-manager-state.store.ts +402 -0
  78. package/{lib/services/request-manager-state-service/index.d.ts → src/lib/services/request-manager-state-service/index.ts} +1 -0
  79. package/src/lib/services/request-manager-state-service/models/api-request.model.ts +50 -0
  80. package/{lib/services/request-manager-state-service/models/index.d.ts → src/lib/services/request-manager-state-service/models/index.ts} +1 -0
  81. package/src/lib/services/request-manager-state-service/models/request-options.model.ts +22 -0
  82. package/src/lib/services/utils/app.service.spec.ts +25 -0
  83. package/src/lib/services/utils/app.service.ts +21 -0
  84. package/src/lib/services/utils/encryption/README.md +79 -0
  85. package/src/lib/services/utils/encryption/asymmetrical-encryption.service.ts +282 -0
  86. package/src/lib/services/utils/encryption/encryption-test.service.ts +39 -0
  87. package/{lib/services/utils/encryption/index.d.ts → src/lib/services/utils/encryption/index.ts} +2 -0
  88. package/src/lib/services/utils/encryption/random.ts +69 -0
  89. package/src/lib/services/utils/encryption/symmetrical-encryption.service.ts +93 -0
  90. package/src/lib/services/utils/headers.service.spec.ts +80 -0
  91. package/src/lib/services/utils/headers.service.ts +18 -0
  92. package/{lib/services/utils/index.d.ts → src/lib/services/utils/index.ts} +2 -0
  93. package/src/lib/services/utils/object-merger.service.spec.ts +16 -0
  94. package/src/lib/services/utils/object-merger.service.ts +60 -0
  95. package/src/lib/services/utils/path-query.service.spec.ts +117 -0
  96. package/src/lib/services/utils/path-query.service.ts +69 -0
  97. package/src/lib/services/utils/utils.service.spec.ts +164 -0
  98. package/src/lib/services/utils/utils.service.ts +192 -0
  99. package/{public-api.d.ts → src/public-api.ts} +7 -0
  100. package/tsconfig.lib.json +32 -0
  101. package/tsconfig.lib.prod.json +10 -0
  102. package/tsconfig.spec.json +14 -0
  103. package/esm2022/http-request-manager.mjs +0 -5
  104. package/esm2022/lib/http-request-manager.module.mjs +0 -146
  105. package/esm2022/lib/http-request-services-demo/database-data-demo/database-data-demo.component.mjs +0 -71
  106. package/esm2022/lib/http-request-services-demo/http-request-services-demo.component.mjs +0 -41
  107. package/esm2022/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.mjs +0 -173
  108. package/esm2022/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.mjs +0 -80
  109. package/esm2022/lib/http-request-services-demo/request-manager-demo/file-downloader/file-download.module.mjs +0 -42
  110. package/esm2022/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.mjs +0 -88
  111. package/esm2022/lib/http-request-services-demo/request-manager-demo/file-downloader/models/download-labels-model.mjs +0 -11
  112. package/esm2022/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.mjs +0 -29
  113. package/esm2022/lib/http-request-services-demo/request-manager-demo/models/sample-ai-prompt.mjs +0 -9
  114. package/esm2022/lib/http-request-services-demo/request-manager-demo/models/sample-client-info.mjs +0 -12
  115. package/esm2022/lib/http-request-services-demo/request-manager-demo/models/sample-mapper-client-info.mjs +0 -14
  116. package/esm2022/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.mjs +0 -315
  117. package/esm2022/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.mjs +0 -270
  118. package/esm2022/lib/http-request-services-demo/request-manager-state-demo/services/state-manager-demo.service.mjs +0 -67
  119. package/esm2022/lib/index.mjs +0 -4
  120. package/esm2022/lib/interceptors/credentials.interceptor.mjs +0 -14
  121. package/esm2022/lib/interceptors/index.mjs +0 -5
  122. package/esm2022/lib/interceptors/models/error-settings.model.mjs +0 -10
  123. package/esm2022/lib/interceptors/proxy-debugger.interceptor.mjs +0 -47
  124. package/esm2022/lib/interceptors/request-error.interceptor.mjs +0 -49
  125. package/esm2022/lib/interceptors/request-header.interceptor.mjs +0 -41
  126. package/esm2022/lib/models/config-http-options.model.mjs +0 -18
  127. package/esm2022/lib/models/config-local-storage-options.model.mjs +0 -12
  128. package/esm2022/lib/models/config-options.model.mjs +0 -12
  129. package/esm2022/lib/models/config-token.model.mjs +0 -8
  130. package/esm2022/lib/models/data-type.enum.mjs +0 -7
  131. package/esm2022/lib/models/database-storage.model.mjs +0 -10
  132. package/esm2022/lib/models/index.mjs +0 -7
  133. package/esm2022/lib/models/retry-options.model.mjs +0 -10
  134. package/esm2022/lib/services/database-manager-services/database.manager.service.mjs +0 -119
  135. package/esm2022/lib/services/database-manager-services/db.storage.service.mjs +0 -143
  136. package/esm2022/lib/services/database-manager-services/index.mjs +0 -4
  137. package/esm2022/lib/services/database-manager-services/models/table-schema.mjs +0 -20
  138. package/esm2022/lib/services/index.mjs +0 -6
  139. package/esm2022/lib/services/local-storage-manager-service/index.mjs +0 -3
  140. package/esm2022/lib/services/local-storage-manager-service/local-storage-manager.service.mjs +0 -302
  141. package/esm2022/lib/services/local-storage-manager-service/models/global-store-options.model.mjs +0 -13
  142. package/esm2022/lib/services/local-storage-manager-service/models/index.mjs +0 -6
  143. package/esm2022/lib/services/local-storage-manager-service/models/setting-options.model.mjs +0 -13
  144. package/esm2022/lib/services/local-storage-manager-service/models/storage-data.model.mjs +0 -10
  145. package/esm2022/lib/services/local-storage-manager-service/models/storage-option.model.mjs +0 -12
  146. package/esm2022/lib/services/local-storage-manager-service/models/storage-type.enum.mjs +0 -7
  147. package/esm2022/lib/services/request-manager-services/http-manager.service.mjs +0 -207
  148. package/esm2022/lib/services/request-manager-services/index.mjs +0 -5
  149. package/esm2022/lib/services/request-manager-services/request.service.mjs +0 -189
  150. package/esm2022/lib/services/request-manager-services/rxjs-operators/countdown.mjs +0 -9
  151. package/esm2022/lib/services/request-manager-services/rxjs-operators/delay-retry.mjs +0 -10
  152. package/esm2022/lib/services/request-manager-services/rxjs-operators/index.mjs +0 -5
  153. package/esm2022/lib/services/request-manager-services/rxjs-operators/request-polling.mjs +0 -14
  154. package/esm2022/lib/services/request-manager-services/rxjs-operators/request-streaming.mjs +0 -19
  155. package/esm2022/lib/services/request-manager-state-service/http-manager-state.store.mjs +0 -267
  156. package/esm2022/lib/services/request-manager-state-service/index.mjs +0 -3
  157. package/esm2022/lib/services/request-manager-state-service/models/api-request.model.mjs +0 -20
  158. package/esm2022/lib/services/request-manager-state-service/models/index.mjs +0 -3
  159. package/esm2022/lib/services/request-manager-state-service/models/request-options.model.mjs +0 -10
  160. package/esm2022/lib/services/utils/app.service.mjs +0 -26
  161. package/esm2022/lib/services/utils/encryption/asymmetrical-encryption.service.mjs +0 -186
  162. package/esm2022/lib/services/utils/encryption/encryption-test.service.mjs +0 -35
  163. package/esm2022/lib/services/utils/encryption/index.mjs +0 -4
  164. package/esm2022/lib/services/utils/encryption/random.mjs +0 -52
  165. package/esm2022/lib/services/utils/encryption/symmetrical-encryption.service.mjs +0 -77
  166. package/esm2022/lib/services/utils/headers.service.mjs +0 -21
  167. package/esm2022/lib/services/utils/index.mjs +0 -6
  168. package/esm2022/lib/services/utils/object-merger.service.mjs +0 -50
  169. package/esm2022/lib/services/utils/path-query.service.mjs +0 -54
  170. package/esm2022/lib/services/utils/utils.service.mjs +0 -155
  171. package/esm2022/public-api.mjs +0 -11
  172. package/fesm2022/http-request-manager.mjs +0 -3444
  173. package/fesm2022/http-request-manager.mjs.map +0 -1
  174. package/http-request-manager-15.0.24.tgz +0 -0
  175. package/index.d.ts +0 -5
  176. package/lib/http-request-manager.module.d.ts +0 -33
  177. package/lib/http-request-services-demo/database-data-demo/database-data-demo.component.d.ts +0 -19
  178. package/lib/http-request-services-demo/http-request-services-demo.component.d.ts +0 -24
  179. package/lib/http-request-services-demo/local-storage-demo/local-storage-demo.component.d.ts +0 -56
  180. package/lib/http-request-services-demo/request-manager-demo/file-downloader/download-file/download-file.component.d.ts +0 -26
  181. package/lib/http-request-services-demo/request-manager-demo/file-downloader/file-download.module.d.ts +0 -13
  182. package/lib/http-request-services-demo/request-manager-demo/file-downloader/file-downloader.component.d.ts +0 -27
  183. package/lib/http-request-services-demo/request-manager-demo/file-downloader/models/download-labels-model.d.ts +0 -12
  184. package/lib/http-request-services-demo/request-manager-demo/file-downloader/spinner/spinner.component.d.ts +0 -16
  185. package/lib/http-request-services-demo/request-manager-demo/models/sample-ai-prompt.d.ts +0 -8
  186. package/lib/http-request-services-demo/request-manager-demo/models/sample-client-info.d.ts +0 -14
  187. package/lib/http-request-services-demo/request-manager-demo/models/sample-mapper-client-info.d.ts +0 -14
  188. package/lib/http-request-services-demo/request-manager-demo/request-manager-demo.component.d.ts +0 -107
  189. package/lib/http-request-services-demo/request-manager-state-demo/request-manager-state-demo.component.d.ts +0 -122
  190. package/lib/http-request-services-demo/request-manager-state-demo/services/state-manager-demo.service.d.ts +0 -15
  191. package/lib/index.d.ts +0 -3
  192. package/lib/interceptors/credentials.interceptor.d.ts +0 -8
  193. package/lib/interceptors/models/error-settings.model.d.ts +0 -10
  194. package/lib/interceptors/proxy-debugger.interceptor.d.ts +0 -12
  195. package/lib/interceptors/request-error.interceptor.d.ts +0 -10
  196. package/lib/interceptors/request-header.interceptor.d.ts +0 -15
  197. package/lib/models/config-http-options.model.d.ts +0 -21
  198. package/lib/models/config-local-storage-options.model.d.ts +0 -13
  199. package/lib/models/config-options.model.d.ts +0 -12
  200. package/lib/models/data-type.enum.d.ts +0 -5
  201. package/lib/models/database-storage.model.d.ts +0 -10
  202. package/lib/models/index.d.ts +0 -6
  203. package/lib/models/retry-options.model.d.ts +0 -10
  204. package/lib/services/database-manager-services/database.manager.service.d.ts +0 -31
  205. package/lib/services/database-manager-services/db.storage.service.d.ts +0 -26
  206. package/lib/services/database-manager-services/models/table-schema.d.ts +0 -11
  207. package/lib/services/local-storage-manager-service/index.d.ts +0 -2
  208. package/lib/services/local-storage-manager-service/local-storage-manager.service.d.ts +0 -86
  209. package/lib/services/local-storage-manager-service/models/global-store-options.model.d.ts +0 -15
  210. package/lib/services/local-storage-manager-service/models/setting-options.model.d.ts +0 -15
  211. package/lib/services/local-storage-manager-service/models/storage-data.model.d.ts +0 -10
  212. package/lib/services/local-storage-manager-service/models/storage-option.model.d.ts +0 -13
  213. package/lib/services/local-storage-manager-service/models/storage-type.enum.d.ts +0 -5
  214. package/lib/services/request-manager-services/http-manager.service.d.ts +0 -41
  215. package/lib/services/request-manager-services/request.service.d.ts +0 -27
  216. package/lib/services/request-manager-services/rxjs-operators/countdown.d.ts +0 -2
  217. package/lib/services/request-manager-services/rxjs-operators/delay-retry.d.ts +0 -2
  218. package/lib/services/request-manager-services/rxjs-operators/request-polling.d.ts +0 -7
  219. package/lib/services/request-manager-services/rxjs-operators/request-streaming.d.ts +0 -2
  220. package/lib/services/request-manager-state-service/http-manager-state.store.d.ts +0 -51
  221. package/lib/services/request-manager-state-service/models/api-request.model.d.ts +0 -27
  222. package/lib/services/request-manager-state-service/models/request-options.model.d.ts +0 -10
  223. package/lib/services/utils/app.service.d.ts +0 -8
  224. package/lib/services/utils/encryption/asymmetrical-encryption.service.d.ts +0 -17
  225. package/lib/services/utils/encryption/encryption-test.service.d.ts +0 -10
  226. package/lib/services/utils/encryption/random.d.ts +0 -7
  227. package/lib/services/utils/encryption/symmetrical-encryption.service.d.ts +0 -14
  228. package/lib/services/utils/headers.service.d.ts +0 -10
  229. package/lib/services/utils/object-merger.service.d.ts +0 -12
  230. package/lib/services/utils/path-query.service.d.ts +0 -11
  231. package/lib/services/utils/utils.service.d.ts +0 -24
  232. /package/{lib/services/request-manager-services/rxjs-operators/index.d.ts → src/lib/services/request-manager-services/rxjs-operators/index.ts} +0 -0
@@ -1,315 +0,0 @@
1
- import { Component, ViewChild, inject } from '@angular/core';
2
- import { BehaviorSubject, EMPTY, throwError } from 'rxjs';
3
- import { FormBuilder, Validators } from '@angular/forms';
4
- import { ClientInfo } from './models/sample-client-info';
5
- import { ClientInfoMapper } from './models/sample-mapper-client-info';
6
- import { AIPrompt } from './models/sample-ai-prompt';
7
- import { ApiRequest, HTTPManagerService } from '../..';
8
- import { catchError, map, tap } from 'rxjs/operators';
9
- import { ToastMessageService, ToastDisplay, ToastColors } from 'toast-message-display';
10
- import * as i0 from "@angular/core";
11
- import * as i1 from "@angular/common";
12
- import * as i2 from "@angular/forms";
13
- import * as i3 from "@angular/material/button";
14
- import * as i4 from "@angular/material/form-field";
15
- import * as i5 from "@angular/material/select";
16
- import * as i6 from "@angular/material/core";
17
- import * as i7 from "@angular/material/menu";
18
- import * as i8 from "@angular/material/icon";
19
- import * as i9 from "@angular/material/table";
20
- import * as i10 from "@angular/material/progress-bar";
21
- import * as i11 from "@angular/material/slide-toggle";
22
- import * as i12 from "@angular/material/divider";
23
- import * as i13 from "@angular/material/input";
24
- import * as i14 from "./file-downloader/file-downloader.component";
25
- export class RequestManagerDemoComponent {
26
- get retry() {
27
- return this.requestForm.get('retry')?.value;
28
- }
29
- get headers() {
30
- return this.requestForm.get('headers');
31
- }
32
- get isValid() {
33
- this.requestForm.markAllAsTouched();
34
- return this.requestForm.valid;
35
- }
36
- constructor() {
37
- this.displayedColumns = ['id', 'name', 'lastName', 'age'];
38
- this.fb = inject(FormBuilder);
39
- this.toastMessage = inject(ToastMessageService);
40
- this.httpManagerService = inject(HTTPManagerService);
41
- this.isPending$ = this.httpManagerService.isPending$;
42
- this.countdown$ = this.httpManagerService.countdown$;
43
- this.GET_error$ = new BehaviorSubject('');
44
- this.POST_error$ = new BehaviorSubject('');
45
- this.PUT_error$ = new BehaviorSubject('');
46
- this.DELETE_error$ = new BehaviorSubject('');
47
- this.STREAM_error$ = new BehaviorSubject('');
48
- this.STREAM_AI_error$ = new BehaviorSubject('');
49
- this.requestParams = {
50
- GET: ApiRequest.adapt(),
51
- POST: ApiRequest.adapt(),
52
- PUT: ApiRequest.adapt(),
53
- DELETE: ApiRequest.adapt(),
54
- STREAM: ApiRequest.adapt(),
55
- };
56
- this.questionControl = this.fb.control("", [Validators.required]);
57
- this.downloadRequest = ApiRequest.adapt({
58
- server: 'assets/images',
59
- path: ['me.jpg'],
60
- // saveAs: 'john.jpg' // Optional
61
- });
62
- // downloadRequest = ApiRequest.adapt({
63
- // server: 'oidc/ai/file'
64
- // })
65
- this.sampleClientData = {
66
- id: 0,
67
- name: "Old School Dates",
68
- domain: "osd.com",
69
- service: "osd",
70
- spiffe: "osd.com/osd",
71
- secret: "SMOPECXP-OS4P-USOG-X2II-3XMD1FQDR3IJX",
72
- created: 1693003138,
73
- modified: 1693003138,
74
- icon: "",
75
- imageFile: "",
76
- email: "wavecoders@gmail.com"
77
- };
78
- this.requestForm = this.fb.group({
79
- path: this.fb.control("ai/"),
80
- headers: this.fb.array([]),
81
- adapter: [null],
82
- mapper: [null],
83
- retry: this.fb.group({
84
- times: [3],
85
- delay: [3],
86
- }),
87
- polling: [3],
88
- });
89
- this.AIType = 0;
90
- this.sampleAdaptors = [
91
- { label: "ClientInfo Basic", value: ClientInfo.adapt },
92
- { label: "AI Prompt", value: AIPrompt.adapt },
93
- ];
94
- this.sampleMappers = [
95
- { label: "Mapper Basic", value: ClientInfoMapper.adapt },
96
- { label: "AI Prompt", value: AIPrompt.adapt },
97
- ];
98
- this.hasId = (arr) => {
99
- if (arr.length === 0)
100
- return false;
101
- return !isNaN(arr[arr.length - 1]);
102
- };
103
- this.props = (adapter) => {
104
- return (adapter) ? adapter() : null;
105
- };
106
- // server = `http://sample-endpoint/as/authorization.oauth2`
107
- this.arrayObjectsToObjects = (arr) => {
108
- return Array.isArray(arr) ? arr.reduce((obj, item) => Object.assign(obj, { [item.key]: item.value }), {}) : {};
109
- };
110
- }
111
- ngOnInit() {
112
- // const reqGet2 = ApiRequest.adapt({
113
- // server,
114
- // path: ['clients'],
115
- // headers: { authentication: "Bearer <KEY>" },
116
- // adapter: ClientInfo,
117
- // dataType: DataType.OBJECT,
118
- // // concurrent: false,
119
- // // polling: 3, //seconds
120
- // })
121
- // const req2 = [1024,1025,1026].map(item => {
122
- // return this.httpManagerService.getRequest<ClientInfo[]>(reqGet2, [item])
123
- // .pipe(
124
- // catchError(error => {
125
- // return throwError(() => new Error(error.error.message))
126
- // })
127
- // )
128
- // })
129
- // forkJoin(req2)
130
- // .subscribe(res => console.log(res))
131
- }
132
- addHeader() {
133
- const header = this.fb.group({
134
- key: ['', Validators.required],
135
- value: ['']
136
- });
137
- this.headers.push(header);
138
- }
139
- removeHeader(index) {
140
- this.headers.removeAt(index);
141
- }
142
- compileRequest() {
143
- const requestParams = this.requestForm.value;
144
- requestParams.headers = this.arrayObjectsToObjects(requestParams.headers || []);
145
- const pathReq = (requestParams.path === "") ? [] : (requestParams.path || "").split("/");
146
- if (!this.pollingState.checked)
147
- requestParams.polling = 0;
148
- if (!this.failedState.checked) {
149
- requestParams.retry = { times: 0, delay: 0 };
150
- }
151
- const apiOptions = ApiRequest.adapt(requestParams);
152
- apiOptions.path = [];
153
- return { apiOptions: apiOptions, path: pathReq };
154
- }
155
- onGetRequest() {
156
- if (!this.isValid)
157
- return;
158
- const reqParams = this.compileRequest();
159
- this.requestParams.GET = reqParams.apiOptions;
160
- this.GET$ = EMPTY; //Cancels Previous
161
- this.GET_error$.next('');
162
- this.GET$ = this.httpManagerService.getRequest(reqParams.apiOptions, reqParams.path)
163
- .pipe(
164
- // tap((data) => console.log("API GET response", data)),
165
- catchError(error => {
166
- return throwError(() => this.errorHandling(error, 'GET'));
167
- }));
168
- }
169
- onCreateRequest() {
170
- if (!this.isValid)
171
- return;
172
- const reqParams = this.compileRequest();
173
- this.requestParams.POST = reqParams.apiOptions;
174
- this.POST$ = EMPTY; //Cancels Previous
175
- this.POST_error$.next('');
176
- console.log("POST", this.sampleClientData);
177
- console.log("POST", reqParams.apiOptions);
178
- console.log("POST", reqParams.path);
179
- this.POST$ = this.httpManagerService.postRequest(this.sampleClientData, reqParams.apiOptions, reqParams.path)
180
- .pipe(
181
- // tap((data) => console.log("API POST response", data)),
182
- catchError(error => {
183
- return throwError(() => this.errorHandling(error, 'POST'));
184
- }));
185
- }
186
- onUpdateRequest() {
187
- if (!this.isValid)
188
- return;
189
- const reqParams = this.compileRequest();
190
- if (!this.hasId(reqParams.path)) {
191
- console.log("Missing ID");
192
- return;
193
- }
194
- this.sampleClientData.id = parseInt(reqParams.path[reqParams.path.length - 1]);
195
- this.requestParams.PUT = reqParams.apiOptions;
196
- this.PUT$ = EMPTY; //Cancels Previous
197
- this.PUT_error$.next('');
198
- this.PUT$ = this.httpManagerService.putRequest(this.sampleClientData, reqParams.apiOptions, reqParams.path)
199
- .pipe(
200
- // tap((data) => console.log("API PUT response", data)),
201
- catchError(error => {
202
- return throwError(() => this.errorHandling(error, 'PUT'));
203
- }));
204
- }
205
- onDeleteRequest() {
206
- if (!this.isValid)
207
- return;
208
- const reqParams = this.compileRequest();
209
- this.requestParams.DELETE = reqParams.apiOptions;
210
- if (!this.hasId(reqParams.path)) {
211
- console.log("Missing ID");
212
- return;
213
- }
214
- this.sampleClientData.id = parseInt(reqParams.path[reqParams.path.length - 1]);
215
- this.requestParams.DELETE = reqParams.apiOptions;
216
- this.DELETE$ = EMPTY; //Cancels Previous
217
- this.DELETE_error$.next('');
218
- this.DELETE$ = this.httpManagerService.deleteRequest(reqParams.apiOptions, reqParams.path)
219
- .pipe(
220
- // tap((data) => console.log("API DELETE response", data)),
221
- catchError(error => {
222
- return throwError(() => this.errorHandling(error, 'DELETE'));
223
- }));
224
- }
225
- onStreamPostRequest() {
226
- if (!this.isValid)
227
- return;
228
- const reqParams = this.compileRequest();
229
- let payload = {};
230
- let apiPath = reqParams.path;
231
- let apiOptions = reqParams.apiOptions;
232
- let responseMapper = (items) => items.response;
233
- if (this.AIType === 0) {
234
- // API request
235
- payload = { prompt: this.questionControl.value };
236
- }
237
- else {
238
- // Local Ollama request
239
- apiOptions.server = "api";
240
- apiPath = ["generate"];
241
- apiOptions.stream = true;
242
- payload = {
243
- model: "phi3:latest",
244
- prompt: this.questionControl.value,
245
- stream: true,
246
- };
247
- responseMapper = (items) => items.map((word) => word.response).flat().join('');
248
- }
249
- this.requestParams.STREAM = apiOptions;
250
- this.STREAM_AI$ = EMPTY;
251
- this.STREAM_AI_error$.next('');
252
- this.STREAM_AI$ = this.httpManagerService.postRequest(payload, apiOptions, apiPath).pipe(map(responseMapper), tap(() => this.questionControl.reset()), catchError(error => throwError(() => this.errorHandling(error, 'STREAM'))));
253
- }
254
- onStreamRequest() {
255
- if (!this.isValid)
256
- return;
257
- const reqParams = this.compileRequest();
258
- reqParams.apiOptions.stream = true;
259
- this.requestParams.GET = reqParams.apiOptions;
260
- this.STREAM$ = this.httpManagerService.getRequest(reqParams.apiOptions, reqParams.path)
261
- .pipe(
262
- // tap((data) => console.log("API STREAM response", data)),
263
- catchError(error => {
264
- return throwError(() => this.errorHandling(error, 'STREAM'));
265
- }));
266
- }
267
- onDownloadCompleted() {
268
- const message = "Download Completed";
269
- const display = ToastDisplay.adapt({
270
- message,
271
- action: 'Ok',
272
- color: ToastColors.SUCCESS,
273
- icon: 'sentiment_satisfied_alt',
274
- });
275
- this.toastMessage.toastMessage(display);
276
- }
277
- onDownloadFailed(err) {
278
- const message = "Download Failed";
279
- const display = ToastDisplay.adapt({
280
- message,
281
- action: 'Ok',
282
- color: ToastColors.ERROR,
283
- icon: 'warning',
284
- });
285
- this.toastMessage.toastMessage(display);
286
- }
287
- errorHandling(err, type) {
288
- if (type === 'GET')
289
- this.GET_error$.next(err.message);
290
- if (type === 'POST')
291
- this.POST_error$.next(err.message);
292
- if (type === 'PUT')
293
- this.PUT_error$.next(err.message);
294
- if (type === 'DELETE')
295
- this.DELETE_error$.next(err.message);
296
- if (type === 'STREAM')
297
- this.STREAM_error$.next(err.message);
298
- }
299
- onSelectAIType(type) {
300
- this.AIType = type;
301
- }
302
- static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestManagerDemoComponent, deps: [], target: i0.ɵɵFactoryTarget.Component }); }
303
- static { this.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "16.2.12", type: RequestManagerDemoComponent, selector: "app-request-manager-demo", viewQueries: [{ propertyName: "failedState", first: true, predicate: ["failedState"], descendants: true, static: true }, { propertyName: "pollingState", first: true, predicate: ["pollingState"], descendants: true, static: true }], ngImport: i0, template: "<div style=\"margin: 2rem;\">\n\n <h2>\n HTTP Request Manager\n </h2>\n\n <div [formGroup]=\"requestForm\" style=\"margin-top: 2rem;\">\n <div style=\"display: flex; gap: .5rem\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Adapter (Model)</mat-label>\n <mat-select formControlName=\"adapter\" #adapterSelect>\n <mat-option>None</mat-option>\n <mat-option *ngFor=\"let adapter of sampleAdaptors\" [value]=\"adapter.value\">\n {{adapter.label}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Mapper (Model)</mat-label>\n <mat-select formControlName=\"mapper\" #mapperSelect>\n <mat-option>None</mat-option>\n <mat-option *ngFor=\"let mapper of sampleMappers\" [value]=\"mapper.value\">\n {{mapper.label}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div style=\"display: flex; margin-bottom: 2rem;\" *ngIf=\"adapterSelect.value || mapperSelect.value\">\n <div style=\"flex:1\" class=\"box\">\n <h3>Adapter (Incoming)</h3>\n <div *ngIf=\"adapterSelect.value; else NO_ADAPTER\">\n {{ props(adapterSelect.value) | json }}\n </div>\n <ng-template #NO_ADAPTER>No Transformation</ng-template>\n </div>\n <div style=\"flex:1\" class=\"box\">\n <h3>Mapper (Outgoing)</h3>\n <div *ngIf=\"mapperSelect.value; else NO_MAPPER\">\n {{ props(mapperSelect.value) | json }}\n </div>\n <ng-template #NO_MAPPER>No Transformation</ng-template>\n </div>\n </div>\n <div>\n <mat-form-field appearance=\"outline\">\n <mat-label>RestPath (/ delimited)</mat-label>\n <input matInput placeholder=\"clients/list\" formControlName=\"path\">\n </mat-form-field>\n </div>\n <div>\n <div formArrayName=\"headers\">\n <div *ngFor=\"let task of headers.controls; let i = index\" [formGroupName]=\"i\">\n <div style=\"display: flex; gap: .5rem\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Key</mat-label>\n <input matInput placeholder=\"authentication\" formControlName=\"key\">\n </mat-form-field>\n <mat-form-field appearance=\"outline\" style=\"flex:1\">\n <mat-label>Value</mat-label>\n <input matInput placeholder=\"sample\" formControlName=\"value\">\n </mat-form-field>\n <div style=\"margin-top: .5rem;\">\n <button mat-icon-button (click)=\"removeHeader(i)\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n </div>\n </div>\n <button mat-stroked-button (click)=\"addHeader()\" class=\"btn\">Add Header</button>\n </div>\n <div style=\"margin-top: 2rem; display: flex; flex-direction:column; gap: 1rem;\">\n <div>\n <mat-slide-toggle #failedState>Retry on Failed</mat-slide-toggle>\n <div *ngIf=\"failedState.checked\" style=\"display: flex; gap: .5rem; margin-top: 1rem;\" formGroupName=\"retry\">\n <mat-form-field appearance=\"outline\">\n <mat-label>#of Times</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"times\" value=\"3\">\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Delay Until Next</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"delay\" value=\"3\">\n </mat-form-field>\n </div>\n </div>\n <div>\n <mat-slide-toggle #pollingState>Polling</mat-slide-toggle>\n <div *ngIf=\"pollingState.checked\">\n <mat-form-field appearance=\"outline\" style=\"margin-top: 1rem\">\n <mat-label>#of Seconds</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"polling\" value=\"3\">\n </mat-form-field>\n </div>\n </div>\n </div>\n </div>\n\n <div style=\"margin-bottom: 1rem; margin-top: 2rem;\">\n <mat-progress-bar mode=\"indeterminate\"\n *ngIf=\"(isPending$ | async)\"\n ></mat-progress-bar>\n <mat-progress-bar mode=\"determinate\"\n *ngIf=\"pollingState.checked && !(isPending$ | async)\"\n [value]=\"(this.countdown$ | async)\"\n ></mat-progress-bar>\n </div>\n\n <div style=\"margin-top: 1rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">GET Request</h2>\n <div>\n <button mat-raised-button (click)=\"onGetRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(GET_error$ | async) as get_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ get_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"(GET$ | async) as dataRecord\">\n <!-- <div [innerHTML]=\"(GET$ | async) | jsonv\"></div> -->\n {{ dataRecord | json }}\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">POST Request</h2>\n <div>\n <button mat-raised-button (click)=\"onCreateRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(POST_error$ | async) as post_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ post_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"(POST$ | async) as dataRecord\">\n <!-- <div [innerHTML]=\"(POST$ | async) | jsonv\"></div> -->\n {{ dataRecord | json }}\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">PUT Request</h2>\n <div>\n <button mat-raised-button (click)=\"onUpdateRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(PUT_error$ | async) as put_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ put_error }}</mat-error>\n </div>\n\n <h3>Include Record ID in the RestPath</h3>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"(PUT$ | async) as dataRecord\">\n <!-- <div [innerHTML]=\"(PUT$ | async) | jsonv\"></div> -->\n {{ dataRecord | json }}\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">DELETE Request</h2>\n <div>\n <button mat-raised-button (click)=\"onDeleteRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <h3>Include Record ID in the RestPath</h3>\n\n <div *ngIf=\"(DELETE_error$ | async) as delete_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ delete_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"(DELETE$ | async) as dataRecord\">\n <!-- <div [innerHTML]=\"(DELETE$ | async) | jsonv\"></div> -->\n {{ dataRecord | json }}\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">Streaming GET Request</h2>\n <div>\n <button mat-raised-button (click)=\"onStreamRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <!-- <div *ngIf=\"(STREAM_error$ | async) as stream_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ stream_error }}</mat-error>\n </div> -->\n\n <div style=\"margin-top: 1rem;\">\n <div *ngIf=\"(STREAM$ | async) as data\" class=\"container\">\n <table mat-table [dataSource]=\"data\">\n <ng-container matColumnDef=\"id\">\n <th mat-header-cell *matHeaderCellDef> ID </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.id}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef> First Name </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.name}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"lastName\">\n <th mat-header-cell *matHeaderCellDef> Last Name </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.lastName}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"age\">\n <th mat-header-cell *matHeaderCellDef> Age </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.age}} </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\"></tr>\n </table>\n </div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1; padding-top: .5rem;\">AI -<span *ngIf=\"AIType === 1\">STREAMING</span> POST Request</h2>\n <div style=\"display: flex; gap: 1rem;\">\n <button mat-raised-button [matMenuTriggerFor]=\"menu\" style=\"min-width: 120px;\">\n <mat-icon>lan</mat-icon>\n <span *ngIf=\"AIType === 0; else LOCAL\">Server</span>\n <ng-template #LOCAL>\n Local\n </ng-template>\n </button>\n <mat-menu #menu=\"matMenu\">\n <button mat-menu-item (click)=\"onSelectAIType(0)\">Server</button>\n <button mat-menu-item (click)=\"onSelectAIType(1)\">Local</button>\n </mat-menu>\n <div>\n <button mat-raised-button (click)=\"onStreamPostRequest()\" class=\"btn\">Ask Me</button>\n </div>\n </div>\n </div>\n\n <div style=\"display: flex;\">\n <mat-form-field appearance=\"outline\" style=\"flex:1\">\n <mat-label>Ask me a Question</mat-label>\n <textarea matInput placeholder=\"Why is the sky blue?\" [formControl]=\"questionControl\"></textarea>\n </mat-form-field>\n </div>\n\n <div *ngIf=\"(STREAM_AI_error$ | async) as stream_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ stream_error }}</mat-error>\n </div>\n\n <div *ngIf=\"AIType === 1; else ALTERNATIVE\" style=\"color: red;\">\n You must have Ollama active and the 'phi3:latest' model to use this feature.\n </div>\n <ng-template #ALTERNATIVE>\n <span style=\"color: gray;\">\n Define the RestPath to the API endpoint that will handle the AI request.\n Use: 'ai/chat' for server\n </span>\n </ng-template>\n\n <div>\n <div *ngIf=\"(STREAM_AI$ | async) as data\" style=\"margin-top: 1rem; font-size: 1.2rem; border-radius: 1rem; border: black 1px solid; padding: 2rem;\">\n <p style=\"margin-bottom: .5rem; white-space:pre-wrap; line-height: 1.6rem;\">{{data}}</p>\n </div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 1.5rem; margin-bottom: 1rem; line-height: 1.5rem;\">\n <mat-divider></mat-divider>\n </div>\n\n <div>\n <div style=\"display: flex;\">\n <h2 style=\"flex:1; margin-bottom: 0; padding-top: .5rem; display: flex;\">\n <div>\n Download File\n </div>\n <div style=\"flex:1; margin-left: 1rem;\">\n <mat-slide-toggle #disable>\n <span *ngIf=\"disable.checked; else DISABLE\">\n Enable\n </span>\n <ng-template #DISABLE>Disable</ng-template>\n </mat-slide-toggle>\n </div>\n </h2>\n <div>\n <app-file-downloader\n [disabled]=\"disable.checked\"\n [delayError]=\"3\"\n [apiRequest]=\"downloadRequest\"\n (completed)=\"onDownloadCompleted()\"\n (failed)=\"onDownloadFailed($event)\"\n ></app-file-downloader>\n </div>\n </div>\n </div>\n\n</div>\n", styles: [".btn{min-width:120px}.mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor;background-color:#f5f5f5}.container{height:400px;overflow:auto}.box{padding:10px;border:1px solid #ccc}\n"], dependencies: [{ kind: "directive", type: i1.NgForOf, selector: "[ngFor][ngForOf]", inputs: ["ngForOf", "ngForTrackBy", "ngForTemplate"] }, { kind: "directive", type: i1.NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }, { kind: "directive", type: i2.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i2.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i2.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i2.FormControlDirective, selector: "[formControl]", inputs: ["formControl", "disabled", "ngModel"], outputs: ["ngModelChange"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i2.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "directive", type: i2.FormGroupName, selector: "[formGroupName]", inputs: ["formGroupName"] }, { kind: "directive", type: i2.FormArrayName, selector: "[formArrayName]", inputs: ["formArrayName"] }, { kind: "component", type: i3.MatButton, selector: " button[mat-button], button[mat-raised-button], button[mat-flat-button], button[mat-stroked-button] ", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i3.MatIconButton, selector: "button[mat-icon-button]", inputs: ["disabled", "disableRipple", "color"], exportAs: ["matButton"] }, { kind: "component", type: i4.MatFormField, selector: "mat-form-field", inputs: ["hideRequiredMarker", "color", "floatLabel", "appearance", "subscriptSizing", "hintLabel"], exportAs: ["matFormField"] }, { kind: "directive", type: i4.MatLabel, selector: "mat-label" }, { kind: "directive", type: i4.MatError, selector: "mat-error, [matError]", inputs: ["id"] }, { kind: "component", type: i5.MatSelect, selector: "mat-select", inputs: ["disabled", "disableRipple", "tabIndex", "panelWidth", "hideSingleSelectionIndicator"], exportAs: ["matSelect"] }, { kind: "component", type: i6.MatOption, selector: "mat-option", exportAs: ["matOption"] }, { kind: "component", type: i7.MatMenu, selector: "mat-menu", exportAs: ["matMenu"] }, { kind: "component", type: i7.MatMenuItem, selector: "[mat-menu-item]", inputs: ["disabled", "disableRipple", "role"], exportAs: ["matMenuItem"] }, { kind: "directive", type: i7.MatMenuTrigger, selector: "[mat-menu-trigger-for], [matMenuTriggerFor]", exportAs: ["matMenuTrigger"] }, { kind: "component", type: i8.MatIcon, selector: "mat-icon", inputs: ["color", "inline", "svgIcon", "fontSet", "fontIcon"], exportAs: ["matIcon"] }, { kind: "component", type: i9.MatTable, selector: "mat-table, table[mat-table]", exportAs: ["matTable"] }, { kind: "directive", type: i9.MatHeaderCellDef, selector: "[matHeaderCellDef]" }, { kind: "directive", type: i9.MatHeaderRowDef, selector: "[matHeaderRowDef]", inputs: ["matHeaderRowDef", "matHeaderRowDefSticky"] }, { kind: "directive", type: i9.MatColumnDef, selector: "[matColumnDef]", inputs: ["sticky", "matColumnDef"] }, { kind: "directive", type: i9.MatCellDef, selector: "[matCellDef]" }, { kind: "directive", type: i9.MatRowDef, selector: "[matRowDef]", inputs: ["matRowDefColumns", "matRowDefWhen"] }, { kind: "directive", type: i9.MatHeaderCell, selector: "mat-header-cell, th[mat-header-cell]" }, { kind: "directive", type: i9.MatCell, selector: "mat-cell, td[mat-cell]" }, { kind: "component", type: i9.MatHeaderRow, selector: "mat-header-row, tr[mat-header-row]", exportAs: ["matHeaderRow"] }, { kind: "component", type: i9.MatRow, selector: "mat-row, tr[mat-row]", exportAs: ["matRow"] }, { kind: "component", type: i10.MatProgressBar, selector: "mat-progress-bar", inputs: ["color", "value", "bufferValue", "mode"], outputs: ["animationEnd"], exportAs: ["matProgressBar"] }, { kind: "component", type: i11.MatSlideToggle, selector: "mat-slide-toggle", inputs: ["disabled", "disableRipple", "color", "tabIndex"], exportAs: ["matSlideToggle"] }, { kind: "component", type: i12.MatDivider, selector: "mat-divider", inputs: ["vertical", "inset"] }, { kind: "directive", type: i13.MatInput, selector: "input[matInput], textarea[matInput], select[matNativeControl], input[matNativeControl], textarea[matNativeControl]", inputs: ["disabled", "id", "placeholder", "name", "required", "type", "errorStateMatcher", "aria-describedby", "value", "readonly"], exportAs: ["matInput"] }, { kind: "component", type: i14.FileDownloaderComponent, selector: "app-file-downloader", inputs: ["delayError", "apiRequest", "displayErrorMessage", "saveFileAs", "labels", "disabled"], outputs: ["completed", "failed"] }, { kind: "pipe", type: i1.AsyncPipe, name: "async" }, { kind: "pipe", type: i1.JsonPipe, name: "json" }] }); }
304
- }
305
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "16.2.12", ngImport: i0, type: RequestManagerDemoComponent, decorators: [{
306
- type: Component,
307
- args: [{ selector: 'app-request-manager-demo', template: "<div style=\"margin: 2rem;\">\n\n <h2>\n HTTP Request Manager\n </h2>\n\n <div [formGroup]=\"requestForm\" style=\"margin-top: 2rem;\">\n <div style=\"display: flex; gap: .5rem\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Adapter (Model)</mat-label>\n <mat-select formControlName=\"adapter\" #adapterSelect>\n <mat-option>None</mat-option>\n <mat-option *ngFor=\"let adapter of sampleAdaptors\" [value]=\"adapter.value\">\n {{adapter.label}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Mapper (Model)</mat-label>\n <mat-select formControlName=\"mapper\" #mapperSelect>\n <mat-option>None</mat-option>\n <mat-option *ngFor=\"let mapper of sampleMappers\" [value]=\"mapper.value\">\n {{mapper.label}}\n </mat-option>\n </mat-select>\n </mat-form-field>\n </div>\n <div style=\"display: flex; margin-bottom: 2rem;\" *ngIf=\"adapterSelect.value || mapperSelect.value\">\n <div style=\"flex:1\" class=\"box\">\n <h3>Adapter (Incoming)</h3>\n <div *ngIf=\"adapterSelect.value; else NO_ADAPTER\">\n {{ props(adapterSelect.value) | json }}\n </div>\n <ng-template #NO_ADAPTER>No Transformation</ng-template>\n </div>\n <div style=\"flex:1\" class=\"box\">\n <h3>Mapper (Outgoing)</h3>\n <div *ngIf=\"mapperSelect.value; else NO_MAPPER\">\n {{ props(mapperSelect.value) | json }}\n </div>\n <ng-template #NO_MAPPER>No Transformation</ng-template>\n </div>\n </div>\n <div>\n <mat-form-field appearance=\"outline\">\n <mat-label>RestPath (/ delimited)</mat-label>\n <input matInput placeholder=\"clients/list\" formControlName=\"path\">\n </mat-form-field>\n </div>\n <div>\n <div formArrayName=\"headers\">\n <div *ngFor=\"let task of headers.controls; let i = index\" [formGroupName]=\"i\">\n <div style=\"display: flex; gap: .5rem\">\n <mat-form-field appearance=\"outline\">\n <mat-label>Key</mat-label>\n <input matInput placeholder=\"authentication\" formControlName=\"key\">\n </mat-form-field>\n <mat-form-field appearance=\"outline\" style=\"flex:1\">\n <mat-label>Value</mat-label>\n <input matInput placeholder=\"sample\" formControlName=\"value\">\n </mat-form-field>\n <div style=\"margin-top: .5rem;\">\n <button mat-icon-button (click)=\"removeHeader(i)\">\n <mat-icon>close</mat-icon>\n </button>\n </div>\n </div>\n </div>\n </div>\n <button mat-stroked-button (click)=\"addHeader()\" class=\"btn\">Add Header</button>\n </div>\n <div style=\"margin-top: 2rem; display: flex; flex-direction:column; gap: 1rem;\">\n <div>\n <mat-slide-toggle #failedState>Retry on Failed</mat-slide-toggle>\n <div *ngIf=\"failedState.checked\" style=\"display: flex; gap: .5rem; margin-top: 1rem;\" formGroupName=\"retry\">\n <mat-form-field appearance=\"outline\">\n <mat-label>#of Times</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"times\" value=\"3\">\n </mat-form-field>\n <mat-form-field appearance=\"outline\">\n <mat-label>Delay Until Next</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"delay\" value=\"3\">\n </mat-form-field>\n </div>\n </div>\n <div>\n <mat-slide-toggle #pollingState>Polling</mat-slide-toggle>\n <div *ngIf=\"pollingState.checked\">\n <mat-form-field appearance=\"outline\" style=\"margin-top: 1rem\">\n <mat-label>#of Seconds</mat-label>\n <input matInput placeholder=\"3\" formControlName=\"polling\" value=\"3\">\n </mat-form-field>\n </div>\n </div>\n </div>\n </div>\n\n <div style=\"margin-bottom: 1rem; margin-top: 2rem;\">\n <mat-progress-bar mode=\"indeterminate\"\n *ngIf=\"(isPending$ | async)\"\n ></mat-progress-bar>\n <mat-progress-bar mode=\"determinate\"\n *ngIf=\"pollingState.checked && !(isPending$ | async)\"\n [value]=\"(this.countdown$ | async)\"\n ></mat-progress-bar>\n </div>\n\n <div style=\"margin-top: 1rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">GET Request</h2>\n <div>\n <button mat-raised-button (click)=\"onGetRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(GET_error$ | async) as get_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ get_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"(GET$ | async) as dataRecord\">\n <!-- <div [innerHTML]=\"(GET$ | async) | jsonv\"></div> -->\n {{ dataRecord | json }}\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">POST Request</h2>\n <div>\n <button mat-raised-button (click)=\"onCreateRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(POST_error$ | async) as post_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ post_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"(POST$ | async) as dataRecord\">\n <!-- <div [innerHTML]=\"(POST$ | async) | jsonv\"></div> -->\n {{ dataRecord | json }}\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">PUT Request</h2>\n <div>\n <button mat-raised-button (click)=\"onUpdateRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <div *ngIf=\"(PUT_error$ | async) as put_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ put_error }}</mat-error>\n </div>\n\n <h3>Include Record ID in the RestPath</h3>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"(PUT$ | async) as dataRecord\">\n <!-- <div [innerHTML]=\"(PUT$ | async) | jsonv\"></div> -->\n {{ dataRecord | json }}\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">DELETE Request</h2>\n <div>\n <button mat-raised-button (click)=\"onDeleteRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <h3>Include Record ID in the RestPath</h3>\n\n <div *ngIf=\"(DELETE_error$ | async) as delete_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ delete_error }}</mat-error>\n </div>\n\n <div style=\"margin-top: 1rem;\" *ngIf=\"(DELETE$ | async) as dataRecord\">\n <!-- <div [innerHTML]=\"(DELETE$ | async) | jsonv\"></div> -->\n {{ dataRecord | json }}\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1\">Streaming GET Request</h2>\n <div>\n <button mat-raised-button (click)=\"onStreamRequest()\" class=\"btn\">Request</button>\n </div>\n </div>\n\n <!-- <div *ngIf=\"(STREAM_error$ | async) as stream_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ stream_error }}</mat-error>\n </div> -->\n\n <div style=\"margin-top: 1rem;\">\n <div *ngIf=\"(STREAM$ | async) as data\" class=\"container\">\n <table mat-table [dataSource]=\"data\">\n <ng-container matColumnDef=\"id\">\n <th mat-header-cell *matHeaderCellDef> ID </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.id}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"name\">\n <th mat-header-cell *matHeaderCellDef> First Name </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.name}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"lastName\">\n <th mat-header-cell *matHeaderCellDef> Last Name </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.lastName}} </td>\n </ng-container>\n\n <ng-container matColumnDef=\"age\">\n <th mat-header-cell *matHeaderCellDef> Age </th>\n <td mat-cell *matCellDef=\"let element\"> {{element.age}} </td>\n </ng-container>\n\n <tr mat-header-row *matHeaderRowDef=\"displayedColumns\"></tr>\n <tr mat-row *matRowDef=\"let row; columns: displayedColumns;\"></tr>\n </table>\n </div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 2rem\">\n <mat-divider></mat-divider>\n </div>\n\n <div style=\"margin-top: 2rem\">\n <div style=\"display: flex;\">\n <h2 style=\"flex:1; padding-top: .5rem;\">AI -<span *ngIf=\"AIType === 1\">STREAMING</span> POST Request</h2>\n <div style=\"display: flex; gap: 1rem;\">\n <button mat-raised-button [matMenuTriggerFor]=\"menu\" style=\"min-width: 120px;\">\n <mat-icon>lan</mat-icon>\n <span *ngIf=\"AIType === 0; else LOCAL\">Server</span>\n <ng-template #LOCAL>\n Local\n </ng-template>\n </button>\n <mat-menu #menu=\"matMenu\">\n <button mat-menu-item (click)=\"onSelectAIType(0)\">Server</button>\n <button mat-menu-item (click)=\"onSelectAIType(1)\">Local</button>\n </mat-menu>\n <div>\n <button mat-raised-button (click)=\"onStreamPostRequest()\" class=\"btn\">Ask Me</button>\n </div>\n </div>\n </div>\n\n <div style=\"display: flex;\">\n <mat-form-field appearance=\"outline\" style=\"flex:1\">\n <mat-label>Ask me a Question</mat-label>\n <textarea matInput placeholder=\"Why is the sky blue?\" [formControl]=\"questionControl\"></textarea>\n </mat-form-field>\n </div>\n\n <div *ngIf=\"(STREAM_AI_error$ | async) as stream_error\" style=\"margin-top: .5rem;\">\n <mat-error>{{ stream_error }}</mat-error>\n </div>\n\n <div *ngIf=\"AIType === 1; else ALTERNATIVE\" style=\"color: red;\">\n You must have Ollama active and the 'phi3:latest' model to use this feature.\n </div>\n <ng-template #ALTERNATIVE>\n <span style=\"color: gray;\">\n Define the RestPath to the API endpoint that will handle the AI request.\n Use: 'ai/chat' for server\n </span>\n </ng-template>\n\n <div>\n <div *ngIf=\"(STREAM_AI$ | async) as data\" style=\"margin-top: 1rem; font-size: 1.2rem; border-radius: 1rem; border: black 1px solid; padding: 2rem;\">\n <p style=\"margin-bottom: .5rem; white-space:pre-wrap; line-height: 1.6rem;\">{{data}}</p>\n </div>\n </div>\n\n </div>\n\n <div style=\"margin-top: 1.5rem; margin-bottom: 1rem; line-height: 1.5rem;\">\n <mat-divider></mat-divider>\n </div>\n\n <div>\n <div style=\"display: flex;\">\n <h2 style=\"flex:1; margin-bottom: 0; padding-top: .5rem; display: flex;\">\n <div>\n Download File\n </div>\n <div style=\"flex:1; margin-left: 1rem;\">\n <mat-slide-toggle #disable>\n <span *ngIf=\"disable.checked; else DISABLE\">\n Enable\n </span>\n <ng-template #DISABLE>Disable</ng-template>\n </mat-slide-toggle>\n </div>\n </h2>\n <div>\n <app-file-downloader\n [disabled]=\"disable.checked\"\n [delayError]=\"3\"\n [apiRequest]=\"downloadRequest\"\n (completed)=\"onDownloadCompleted()\"\n (failed)=\"onDownloadFailed($event)\"\n ></app-file-downloader>\n </div>\n </div>\n </div>\n\n</div>\n", styles: [".btn{min-width:120px}.mat-mdc-row .mat-mdc-cell{border-bottom:1px solid transparent;border-top:1px solid transparent;cursor:pointer}.mat-mdc-row:hover .mat-mdc-cell{border-color:currentColor;background-color:#f5f5f5}.container{height:400px;overflow:auto}.box{padding:10px;border:1px solid #ccc}\n"] }]
308
- }], ctorParameters: function () { return []; }, propDecorators: { failedState: [{
309
- type: ViewChild,
310
- args: ["failedState", { static: true }]
311
- }], pollingState: [{
312
- type: ViewChild,
313
- args: ["pollingState", { static: true }]
314
- }] } });
315
- //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmVxdWVzdC1tYW5hZ2VyLWRlbW8uY29tcG9uZW50LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vcHJvamVjdHMvaHR0cC1yZXF1ZXN0LW1hbmFnZXIvc3JjL2xpYi9odHRwLXJlcXVlc3Qtc2VydmljZXMtZGVtby9yZXF1ZXN0LW1hbmFnZXItZGVtby9yZXF1ZXN0LW1hbmFnZXItZGVtby5jb21wb25lbnQudHMiLCIuLi8uLi8uLi8uLi8uLi8uLi9wcm9qZWN0cy9odHRwLXJlcXVlc3QtbWFuYWdlci9zcmMvbGliL2h0dHAtcmVxdWVzdC1zZXJ2aWNlcy1kZW1vL3JlcXVlc3QtbWFuYWdlci1kZW1vL3JlcXVlc3QtbWFuYWdlci1kZW1vLmNvbXBvbmVudC5odG1sIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQVUsU0FBUyxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQTtBQUVwRSxPQUFPLEVBQUUsZUFBZSxFQUFFLEtBQUssRUFBYyxVQUFVLEVBQUUsTUFBTSxNQUFNLENBQUE7QUFDckUsT0FBTyxFQUFhLFdBQVcsRUFBRSxVQUFVLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQTtBQUVuRSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sNkJBQTZCLENBQUE7QUFDeEQsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0sb0NBQW9DLENBQUE7QUFDckUsT0FBTyxFQUFFLFFBQVEsRUFBRSxNQUFNLDJCQUEyQixDQUFBO0FBQ3BELE9BQU8sRUFBRSxVQUFVLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxPQUFPLENBQUE7QUFDdEQsT0FBTyxFQUFFLFVBQVUsRUFBRSxHQUFHLEVBQUUsR0FBRyxFQUFFLE1BQU0sZ0JBQWdCLENBQUE7QUFFckQsT0FBTyxFQUFFLG1CQUFtQixFQUFFLFlBQVksRUFBRSxXQUFXLEVBQUUsTUFBTSx1QkFBdUIsQ0FBQTs7Ozs7Ozs7Ozs7Ozs7OztBQU90RixNQUFNLE9BQU8sMkJBQTJCO0lBeUZ0QyxJQUFJLEtBQUs7UUFDUCxPQUFPLElBQUksQ0FBQyxXQUFXLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxFQUFFLEtBQUssQ0FBQTtJQUM3QyxDQUFDO0lBRUQsSUFBSSxPQUFPO1FBQ1QsT0FBTyxJQUFJLENBQUMsV0FBVyxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQWMsQ0FBQTtJQUNyRCxDQUFDO0lBRUQsSUFBSSxPQUFPO1FBQ1QsSUFBSSxDQUFDLFdBQVcsQ0FBQyxnQkFBZ0IsRUFBRSxDQUFBO1FBQ25DLE9BQU8sSUFBSSxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUE7SUFDL0IsQ0FBQztJQWlCRDtRQW5IQSxxQkFBZ0IsR0FBRyxDQUFDLElBQUksRUFBQyxNQUFNLEVBQUUsVUFBVSxFQUFFLEtBQUssQ0FBQyxDQUFBO1FBRTNDLE9BQUUsR0FBRyxNQUFNLENBQUMsV0FBVyxDQUFDLENBQUE7UUFDeEIsaUJBQVksR0FBRyxNQUFNLENBQUMsbUJBQW1CLENBQUMsQ0FBQTtRQUVsRCx1QkFBa0IsR0FBRyxNQUFNLENBQUMsa0JBQWtCLENBQUMsQ0FBQTtRQUUvQyxlQUFVLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixDQUFDLFVBQVUsQ0FBQTtRQUMvQyxlQUFVLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixDQUFDLFVBQVUsQ0FBQTtRQUUvQyxlQUFVLEdBQUcsSUFBSSxlQUFlLENBQVMsRUFBRSxDQUFDLENBQUE7UUFDNUMsZ0JBQVcsR0FBRyxJQUFJLGVBQWUsQ0FBUyxFQUFFLENBQUMsQ0FBQTtRQUM3QyxlQUFVLEdBQUcsSUFBSSxlQUFlLENBQVMsRUFBRSxDQUFDLENBQUE7UUFDNUMsa0JBQWEsR0FBRyxJQUFJLGVBQWUsQ0FBUyxFQUFFLENBQUMsQ0FBQTtRQUUvQyxrQkFBYSxHQUFHLElBQUksZUFBZSxDQUFTLEVBQUUsQ0FBQyxDQUFBO1FBQy9DLHFCQUFnQixHQUFHLElBQUksZUFBZSxDQUFTLEVBQUUsQ0FBQyxDQUFBO1FBVWxELGtCQUFhLEdBQUc7WUFDZCxHQUFHLEVBQUUsVUFBVSxDQUFDLEtBQUssRUFBRTtZQUN2QixJQUFJLEVBQUUsVUFBVSxDQUFDLEtBQUssRUFBRTtZQUN4QixHQUFHLEVBQUUsVUFBVSxDQUFDLEtBQUssRUFBRTtZQUN2QixNQUFNLEVBQUUsVUFBVSxDQUFDLEtBQUssRUFBRTtZQUMxQixNQUFNLEVBQUUsVUFBVSxDQUFDLEtBQUssRUFBRTtTQUMzQixDQUFBO1FBS0Qsb0JBQWUsR0FBRyxJQUFJLENBQUMsRUFBRSxDQUFDLE9BQU8sQ0FBQyxFQUFFLEVBQUUsQ0FBQyxVQUFVLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQTtRQUU1RCxvQkFBZSxHQUFHLFVBQVUsQ0FBQyxLQUFLLENBQUM7WUFDakMsTUFBTSxFQUFFLGVBQWU7WUFDdkIsSUFBSSxFQUFFLENBQUMsUUFBUSxDQUFDO1lBQ2hCLGlDQUFpQztTQUNsQyxDQUFDLENBQUE7UUFFRix1Q0FBdUM7UUFDdkMsMkJBQTJCO1FBQzNCLEtBQUs7UUFFTCxxQkFBZ0IsR0FBRztZQUNmLEVBQUUsRUFBRSxDQUFDO1lBQ0wsSUFBSSxFQUFFLGtCQUFrQjtZQUN4QixNQUFNLEVBQUUsU0FBUztZQUNqQixPQUFPLEVBQUUsS0FBSztZQUNkLE1BQU0sRUFBRSxhQUFhO1lBQ3JCLE1BQU0sRUFBRSx1Q0FBdUM7WUFDL0MsT0FBTyxFQUFFLFVBQVU7WUFDbkIsUUFBUSxFQUFFLFVBQVU7WUFDcEIsSUFBSSxFQUFFLEVBQUU7WUFDUixTQUFTLEVBQUUsRUFBRTtZQUNiLEtBQUssRUFBRSxzQkFBc0I7U0FDaEMsQ0FBQTtRQUVELGdCQUFXLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUM7WUFDMUIsSUFBSSxFQUFFLElBQUksQ0FBQyxFQUFFLENBQUMsT0FBTyxDQUFTLEtBQUssQ0FBQztZQUNwQyxPQUFPLEVBQUUsSUFBSSxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQzFCLE9BQU8sRUFBRSxDQUFDLElBQUksQ0FBQztZQUNmLE1BQU0sRUFBRSxDQUFDLElBQUksQ0FBQztZQUNkLEtBQUssRUFBRSxJQUFJLENBQUMsRUFBRSxDQUFDLEtBQUssQ0FBQztnQkFDbkIsS0FBSyxFQUFFLENBQUMsQ0FBQyxDQUFDO2dCQUNWLEtBQUssRUFBRSxDQUFDLENBQUMsQ0FBQzthQUNYLENBQUM7WUFDRixPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQUM7U0FDYixDQUFDLENBQUE7UUFFRixXQUFNLEdBQUcsQ0FBQyxDQUFBO1FBRVYsbUJBQWMsR0FBRztZQUNmLEVBQUUsS0FBSyxFQUFFLGtCQUFrQixFQUFFLEtBQUssRUFBRSxVQUFVLENBQUMsS0FBSyxFQUFFO1lBQ3RELEVBQUUsS0FBSyxFQUFFLFdBQVcsRUFBRSxLQUFLLEVBQUUsUUFBUSxDQUFDLEtBQUssRUFBRTtTQUM5QyxDQUFBO1FBRUQsa0JBQWEsR0FBRztZQUNkLEVBQUUsS0FBSyxFQUFFLGNBQWMsRUFBRSxLQUFLLEVBQUUsZ0JBQWdCLENBQUMsS0FBSyxFQUFFO1lBQ3hELEVBQUUsS0FBSyxFQUFFLFdBQVcsRUFBRSxLQUFLLEVBQUUsUUFBUSxDQUFDLEtBQUssRUFBRTtTQUM5QyxDQUFBO1FBZUQsVUFBSyxHQUFHLENBQUMsR0FBVSxFQUFFLEVBQUU7WUFDckIsSUFBSSxHQUFHLENBQUMsTUFBTSxLQUFLLENBQUM7Z0JBQUUsT0FBTyxLQUFLLENBQUE7WUFDbEMsT0FBTyxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLE1BQU0sR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFBO1FBQ3BDLENBQUMsQ0FBQTtRQUVELFVBQUssR0FBRyxDQUFDLE9BQVksRUFBRSxFQUFFO1lBQ3ZCLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsT0FBTyxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQTtRQUNyQyxDQUFDLENBQUE7UUFFRCw0REFBNEQ7UUFFNUQsMEJBQXFCLEdBQUcsQ0FBQyxHQUFVLEVBQUUsRUFBRTtZQUNyQyxPQUFPLEtBQUssQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsQ0FBQyxHQUFHLEVBQUUsSUFBSSxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxFQUFFLElBQUksQ0FBQyxLQUFLLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUE7UUFDaEgsQ0FBQyxDQUFBO0lBRWUsQ0FBQztJQUVqQixRQUFRO1FBRU4scUNBQXFDO1FBQ3JDLFlBQVk7UUFDWix1QkFBdUI7UUFDdkIsaURBQWlEO1FBQ2pELHlCQUF5QjtRQUN6QiwrQkFBK0I7UUFDL0IsMEJBQTBCO1FBQzFCLDZCQUE2QjtRQUM3QixLQUFLO1FBRUwsOENBQThDO1FBQzlDLDZFQUE2RTtRQUM3RSxXQUFXO1FBQ1gsNEJBQTRCO1FBQzVCLGdFQUFnRTtRQUNoRSxTQUFTO1FBQ1QsTUFBTTtRQUNOLEtBQUs7UUFFTCxpQkFBaUI7UUFDakIsc0NBQXNDO0lBRXhDLENBQUM7SUFFRCxTQUFTO1FBQ1AsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLEVBQUUsQ0FBQyxLQUFLLENBQUM7WUFDM0IsR0FBRyxFQUFFLENBQUMsRUFBRSxFQUFFLFVBQVUsQ0FBQyxRQUFRLENBQUM7WUFDOUIsS0FBSyxFQUFFLENBQUMsRUFBRSxDQUFDO1NBQ1osQ0FBQyxDQUFBO1FBQ0YsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUE7SUFDM0IsQ0FBQztJQUVELFlBQVksQ0FBQyxLQUFhO1FBQ3hCLElBQUksQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEtBQUssQ0FBQyxDQUFBO0lBQzlCLENBQUM7SUFFRCxjQUFjO1FBRVosTUFBTSxhQUFhLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUE7UUFFNUMsYUFBYSxDQUFDLE9BQU8sR0FBRyxJQUFJLENBQUMscUJBQXFCLENBQ2hELGFBQWEsQ0FBQyxPQUFPLElBQUksRUFBRSxDQUM1QixDQUFBO1FBRUQsTUFBTSxPQUFPLEdBQUcsQ0FBQyxhQUFhLENBQUMsSUFBSSxLQUFLLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUMsYUFBYSxDQUFDLElBQUksSUFBSSxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLENBQUE7UUFFeEYsSUFBSSxDQUFDLElBQUksQ0FBQyxZQUFZLENBQUMsT0FBTztZQUFFLGFBQWEsQ0FBQyxPQUFPLEdBQUcsQ0FBQyxDQUFBO1FBRXpELElBQUksQ0FBQyxJQUFJLENBQUMsV0FBVyxDQUFDLE9BQU8sRUFBRTtZQUM3QixhQUFhLENBQUMsS0FBSyxHQUFHLEVBQUUsS0FBSyxFQUFFLENBQUMsRUFBQyxLQUFLLEVBQUUsQ0FBQyxFQUFFLENBQUE7U0FDNUM7UUFFRCxNQUFNLFVBQVUsR0FBRyxVQUFVLENBQUMsS0FBSyxDQUFDLGFBQWEsQ0FBQyxDQUFBO1FBQ2xELFVBQVUsQ0FBQyxJQUFJLEdBQUcsRUFBRSxDQUFBO1FBRXBCLE9BQU8sRUFBRSxVQUFVLEVBQUUsVUFBVSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsQ0FBQTtJQUVsRCxDQUFDO0lBRUQsWUFBWTtRQUVWLElBQUcsQ0FBQyxJQUFJLENBQUMsT0FBTztZQUFFLE9BQU07UUFFeEIsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFBO1FBRXZDLElBQUksQ0FBQyxhQUFhLENBQUMsR0FBRyxHQUFHLFNBQVMsQ0FBQyxVQUFVLENBQUE7UUFFN0MsSUFBSSxDQUFDLElBQUksR0FBRyxLQUFLLENBQUEsQ0FBQyxrQkFBa0I7UUFDcEMsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUE7UUFFeEIsSUFBSSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUMsVUFBVSxDQUFlLFNBQVMsQ0FBQyxVQUFVLEVBQUUsU0FBUyxDQUFDLElBQUksQ0FBQzthQUNqRyxJQUFJO1FBQ0gsd0RBQXdEO1FBQ3hELFVBQVUsQ0FBQyxLQUFLLENBQUMsRUFBRTtZQUNqQixPQUFPLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxLQUFLLENBQUMsQ0FBQyxDQUFBO1FBQzNELENBQUMsQ0FBQyxDQUNILENBQUE7SUFFSCxDQUFDO0lBRUQsZUFBZTtRQUViLElBQUcsQ0FBQyxJQUFJLENBQUMsT0FBTztZQUFFLE9BQU07UUFFeEIsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFBO1FBQ3ZDLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxHQUFHLFNBQVMsQ0FBQyxVQUFVLENBQUE7UUFFOUMsSUFBSSxDQUFDLEtBQUssR0FBRyxLQUFLLENBQUEsQ0FBQyxrQkFBa0I7UUFDckMsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLENBQUE7UUFFekIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsSUFBSSxDQUFDLGdCQUFnQixDQUFDLENBQUE7UUFDMUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsU0FBUyxDQUFDLFVBQVUsQ0FBQyxDQUFBO1FBQ3pDLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLFNBQVMsQ0FBQyxJQUFJLENBQUMsQ0FBQTtRQUVuQyxJQUFJLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxXQUFXLENBQWEsSUFBSSxDQUFDLGdCQUFnQixFQUFFLFNBQVMsQ0FBQyxVQUFVLEVBQUUsU0FBUyxDQUFDLElBQUksQ0FBQzthQUN4SCxJQUFJO1FBQ0gseURBQXlEO1FBQ3pELFVBQVUsQ0FBQyxLQUFLLENBQUMsRUFBRTtZQUNqQixPQUFPLFVBQVUsQ0FBQyxHQUFHLEVBQUUsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsQ0FBQyxDQUFBO1FBQzVELENBQUMsQ0FBQyxDQUNILENBQUE7SUFFSCxDQUFDO0lBRUQsZUFBZTtRQUViLElBQUcsQ0FBQyxJQUFJLENBQUMsT0FBTztZQUFFLE9BQU07UUFFeEIsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFBO1FBRXZDLElBQUcsQ0FBQyxJQUFJLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsRUFBRTtZQUM5QixPQUFPLENBQUMsR0FBRyxDQUFDLFlBQVksQ0FBQyxDQUFBO1lBQ3pCLE9BQU07U0FDUDtRQUVELElBQUksQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFFLEdBQUcsUUFBUSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLElBQUksQ0FBQyxNQUFNLEdBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQTtRQUM1RSxJQUFJLENBQUMsYUFBYSxDQUFDLEdBQUcsR0FBRyxTQUFTLENBQUMsVUFBVSxDQUFBO1FBRTdDLElBQUksQ0FBQyxJQUFJLEdBQUcsS0FBSyxDQUFBLENBQUMsa0JBQWtCO1FBQ3BDLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFBO1FBRXhCLElBQUksQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixDQUFDLFVBQVUsQ0FBTSxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsU0FBUyxDQUFDLFVBQVUsRUFBRSxTQUFTLENBQUMsSUFBSSxDQUFDO2FBQy9HLElBQUk7UUFDSCx3REFBd0Q7UUFDeEQsVUFBVSxDQUFDLEtBQUssQ0FBQyxFQUFFO1lBQ2pCLE9BQU8sVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsS0FBSyxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUE7UUFDM0QsQ0FBQyxDQUFDLENBQ0gsQ0FBQTtJQUVILENBQUM7SUFFRCxlQUFlO1FBRWIsSUFBRyxDQUFDLElBQUksQ0FBQyxPQUFPO1lBQUUsT0FBTTtRQUV4QixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUE7UUFDdkMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxNQUFNLEdBQUcsU0FBUyxDQUFDLFVBQVUsQ0FBQTtRQUVoRCxJQUFHLENBQUMsSUFBSSxDQUFDLEtBQUssQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLEVBQUU7WUFDOUIsT0FBTyxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsQ0FBQTtZQUN6QixPQUFNO1NBQ1A7UUFFRCxJQUFJLENBQUMsZ0JBQWdCLENBQUMsRUFBRSxHQUFHLFFBQVEsQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFNBQVMsQ0FBQyxJQUFJLENBQUMsTUFBTSxHQUFDLENBQUMsQ0FBQyxDQUFDLENBQUE7UUFDNUUsSUFBSSxDQUFDLGFBQWEsQ0FBQyxNQUFNLEdBQUcsU0FBUyxDQUFDLFVBQVUsQ0FBQTtRQUVoRCxJQUFJLENBQUMsT0FBTyxHQUFHLEtBQUssQ0FBQSxDQUFDLGtCQUFrQjtRQUN2QyxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQTtRQUUzQixJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxhQUFhLENBQWEsU0FBUyxDQUFDLFVBQVUsRUFBRSxTQUFTLENBQUMsSUFBSSxDQUFDO2FBQ3JHLElBQUk7UUFDSCwyREFBMkQ7UUFDM0QsVUFBVSxDQUFDLEtBQUssQ0FBQyxFQUFFO1lBQ2pCLE9BQU8sVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsS0FBSyxFQUFFLFFBQVEsQ0FBQyxDQUFDLENBQUE7UUFDOUQsQ0FBQyxDQUFDLENBQ0gsQ0FBQTtJQUVILENBQUM7SUFFRCxtQkFBbUI7UUFFakIsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPO1lBQUUsT0FBTTtRQUV6QixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUE7UUFFdkMsSUFBSSxPQUFPLEdBQUcsRUFBRSxDQUFBO1FBQ2hCLElBQUksT0FBTyxHQUFhLFNBQVMsQ0FBQyxJQUFJLENBQUE7UUFDdEMsSUFBSSxVQUFVLEdBQUcsU0FBUyxDQUFDLFVBQVUsQ0FBQTtRQUNyQyxJQUFJLGNBQWMsR0FBd0IsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLEtBQUssQ0FBQyxRQUFRLENBQUE7UUFFbkUsSUFBSSxJQUFJLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtZQUVyQixjQUFjO1lBQ2QsT0FBTyxHQUFHLEVBQUUsTUFBTSxFQUFFLElBQUksQ0FBQyxlQUFlLENBQUMsS0FBSyxFQUFFLENBQUE7U0FFakQ7YUFBTTtZQUVMLHVCQUF1QjtZQUN2QixVQUFVLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQTtZQUN6QixPQUFPLEdBQUcsQ0FBQyxVQUFVLENBQUMsQ0FBQTtZQUN0QixVQUFVLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQTtZQUN4QixPQUFPLEdBQUc7Z0JBQ1IsS0FBSyxFQUFFLGFBQWE7Z0JBQ3BCLE1BQU0sRUFBRSxJQUFJLENBQUMsZUFBZSxDQUFDLEtBQUs7Z0JBQ2xDLE1BQU0sRUFBRSxJQUFJO2FBQ2IsQ0FBQTtZQUVELGNBQWMsR0FBRyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQVMsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDLElBQUksRUFBRSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsQ0FBQTtTQUVwRjtRQUVELElBQUksQ0FBQyxhQUFhLENBQUMsTUFBTSxHQUFHLFVBQVUsQ0FBQTtRQUN0QyxJQUFJLENBQUMsVUFBVSxHQUFHLEtBQUssQ0FBQTtRQUN2QixJQUFJLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxDQUFBO1FBRTlCLElBQUksQ0FBQyxVQUFVLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixDQUFDLFdBQVcsQ0FBTSxPQUFPLEVBQUUsVUFBVSxFQUFFLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FDM0YsR0FBRyxDQUFDLGNBQWMsQ0FBQyxFQUNuQixHQUFHLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxLQUFLLEVBQUUsQ0FBQyxFQUN2QyxVQUFVLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQyxVQUFVLENBQUMsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxLQUFLLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQyxDQUMzRSxDQUFBO0lBRUgsQ0FBQztJQUdELGVBQWU7UUFFYixJQUFHLENBQUMsSUFBSSxDQUFDLE9BQU87WUFBRSxPQUFNO1FBRXhCLE1BQU0sU0FBUyxHQUFHLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQTtRQUV2QyxTQUFTLENBQUMsVUFBVSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUE7UUFFbEMsSUFBSSxDQUFDLGFBQWEsQ0FBQyxHQUFHLEdBQUcsU0FBUyxDQUFDLFVBQVUsQ0FBQTtRQUM3QyxJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxrQkFBa0IsQ0FBQyxVQUFVLENBQWUsU0FBUyxDQUFDLFVBQVUsRUFBRSxTQUFTLENBQUMsSUFBSSxDQUFDO2FBQ2hHLElBQUk7UUFDUCwyREFBMkQ7UUFDM0QsVUFBVSxDQUFDLEtBQUssQ0FBQyxFQUFFO1lBQ2pCLE9BQU8sVUFBVSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksQ0FBQyxhQUFhLENBQUMsS0FBSyxFQUFFLFFBQVEsQ0FBQyxDQUFDLENBQUE7UUFDOUQsQ0FBQyxDQUFDLENBQ0gsQ0FBQTtJQUVILENBQUM7SUFFRCxtQkFBbUI7UUFFakIsTUFBTSxPQUFPLEdBQUcsb0JBQW9CLENBQUE7UUFFcEMsTUFBTSxPQUFPLEdBQUcsWUFBWSxDQUFDLEtBQUssQ0FBQztZQUNqQyxPQUFPO1lBQ1AsTUFBTSxFQUFFLElBQUk7WUFDWixLQUFLLEVBQUUsV0FBVyxDQUFDLE9BQU87WUFDMUIsSUFBSSxFQUFFLHlCQUF5QjtTQUNoQyxDQUFDLENBQUE7UUFFRixJQUFJLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQTtJQUN6QyxDQUFDO0lBRUQsZ0JBQWdCLENBQUMsR0FBVztRQUUxQixNQUFNLE9BQU8sR0FBRyxpQkFBaUIsQ0FBQTtRQUVqQyxNQUFNLE9BQU8sR0FBRyxZQUFZLENBQUMsS0FBSyxDQUFDO1lBQ2pDLE9BQU87WUFDUCxNQUFNLEVBQUUsSUFBSTtZQUNaLEtBQUssRUFBRSxXQUFXLENBQUMsS0FBSztZQUN4QixJQUFJLEVBQUUsU0FBUztTQUNoQixDQUFDLENBQUE7UUFFRixJQUFJLENBQUMsWUFBWSxDQUFDLFlBQVksQ0FBQyxPQUFPLENBQUMsQ0FBQTtJQUN6QyxDQUFDO0lBRUQsYUFBYSxDQUFDLEdBQVEsRUFBRSxJQUFZO1FBQ2xDLElBQUcsSUFBSSxLQUFLLEtBQUs7WUFBRSxJQUFJLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUE7UUFDcEQsSUFBRyxJQUFJLEtBQUssTUFBTTtZQUFFLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQTtRQUN0RCxJQUFHLElBQUksS0FBSyxLQUFLO1lBQUUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFBO1FBQ3BELElBQUcsSUFBSSxLQUFLLFFBQVE7WUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLENBQUE7UUFDMUQsSUFBRyxJQUFJLEtBQUssUUFBUTtZQUFFLElBQUksQ0FBQyxhQUFhLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQTtJQUM1RCxDQUFDO0lBRUQsY0FBYyxDQUFDLElBQVk7UUFDekIsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUE7SUFDcEIsQ0FBQzsrR0E5WFUsMkJBQTJCO21HQUEzQiwyQkFBMkIsdVNDbEJ4QyxzNFhBZ1ZBOzs0RkQ5VGEsMkJBQTJCO2tCQUx2QyxTQUFTOytCQUNFLDBCQUEwQjswRUF3Q1EsV0FBVztzQkFBdEQsU0FBUzt1QkFBQyxhQUFhLEVBQUUsRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFO2dCQUNHLFlBQVk7c0JBQXhELFNBQVM7dUJBQUMsY0FBYyxFQUFFLEVBQUUsTUFBTSxFQUFFLElBQUksRUFBRSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCwgT25Jbml0LCBWaWV3Q2hpbGQsIGluamVjdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnXG5cbmltcG9ydCB7IEJlaGF2aW9yU3ViamVjdCwgRU1QVFksIE9ic2VydmFibGUsIHRocm93RXJyb3IgfSBmcm9tICdyeGpzJ1xuaW1wb3J0IHsgRm9ybUFycmF5LCBGb3JtQnVpbGRlciwgVmFsaWRhdG9ycyB9IGZyb20gJ0Bhbmd1bGFyL2Zvcm1zJ1xuXG5pbXBvcnQgeyBDbGllbnRJbmZvIH0gZnJvbSAnLi9tb2RlbHMvc2FtcGxlLWNsaWVudC1pbmZvJ1xuaW1wb3J0IHsgQ2xpZW50SW5mb01hcHBlciB9IGZyb20gJy4vbW9kZWxzL3NhbXBsZS1tYXBwZXItY2xpZW50LWluZm8nXG5pbXBvcnQgeyBBSVByb21wdCB9IGZyb20gJy4vbW9kZWxzL3NhbXBsZS1haS1wcm9tcHQnXG5pbXBvcnQgeyBBcGlSZXF1ZXN0LCBIVFRQTWFuYWdlclNlcnZpY2UgfSBmcm9tICcuLi8uLidcbmltcG9ydCB7IGNhdGNoRXJyb3IsIG1hcCwgdGFwIH0gZnJvbSAncnhqcy9vcGVyYXRvcnMnXG5cbmltcG9ydCB7IFRvYXN0TWVzc2FnZVNlcnZpY2UsIFRvYXN0RGlzcGxheSwgVG9hc3RDb2xvcnMgfSBmcm9tICd0b2FzdC1tZXNzYWdlLWRpc3BsYXknXG5cbkBDb21wb25lbnQoe1xuICBzZWxlY3RvcjogJ2FwcC1yZXF1ZXN0LW1hbmFnZXItZGVtbycsXG4gIHRlbXBsYXRlVXJsOiAnLi9yZXF1ZXN0LW1hbmFnZXItZGVtby5jb21wb25lbnQuaHRtbCcsXG4gIHN0eWxlVXJsczogWycuL3JlcXVlc3QtbWFuYWdlci1kZW1vLmNvbXBvbmVudC5zY3NzJ10sXG59KVxuZXhwb3J0IGNsYXNzIFJlcXVlc3RNYW5hZ2VyRGVtb0NvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCB7XG5cbiAgZGlzcGxheWVkQ29sdW1ucyA9IFsnaWQnLCduYW1lJywgJ2xhc3ROYW1lJywgJ2FnZSddXG5cbiAgcHJpdmF0ZSBmYiA9IGluamVjdChGb3JtQnVpbGRlcilcbiAgcHJpdmF0ZSB0b2FzdE1lc3NhZ2UgPSBpbmplY3QoVG9hc3RNZXNzYWdlU2VydmljZSlcblxuICBodHRwTWFuYWdlclNlcnZpY2UgPSBpbmplY3QoSFRUUE1hbmFnZXJTZXJ2aWNlKVxuXG4gIGlzUGVuZGluZyQgPSB0aGlzLmh0dHBNYW5hZ2VyU2VydmljZS5pc1BlbmRpbmckXG4gIGNvdW50ZG93biQgPSB0aGlzLmh0dHBNYW5hZ2VyU2VydmljZS5jb3VudGRvd24kXG5cbiAgR0VUX2Vycm9yJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8c3RyaW5nPignJylcbiAgUE9TVF9lcnJvciQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PHN0cmluZz4oJycpXG4gIFBVVF9lcnJvciQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PHN0cmluZz4oJycpXG4gIERFTEVURV9lcnJvciQgPSBuZXcgQmVoYXZpb3JTdWJqZWN0PHN0cmluZz4oJycpXG5cbiAgU1RSRUFNX2Vycm9yJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8c3RyaW5nPignJylcbiAgU1RSRUFNX0FJX2Vycm9yJCA9IG5ldyBCZWhhdmlvclN1YmplY3Q8c3RyaW5nPignJylcblxuICBHRVQkPzogT2JzZXJ2YWJsZTxhbnk+XG4gIFBPU1QkPzogT2JzZXJ2YWJsZTxhbnk+XG4gIFBVVCQ/OiBPYnNlcnZhYmxlPGFueT5cbiAgREVMRVRFJD86IE9ic2VydmFibGU8YW55PlxuXG4gIFNUUkVBTV9BSSQ/OiBPYnNlcnZhYmxlPGFueT5cbiAgU1RSRUFNJD86IE9ic2VydmFibGU8YW55PlxuXG4gIHJlcXVlc3RQYXJhbXMgPSB7XG4gICAgR0VUOiBBcGlSZXF1ZXN0LmFkYXB0KCksXG4gICAgUE9TVDogQXBpUmVxdWVzdC5hZGFwdCgpLFxuICAgIFBVVDogQXBpUmVxdWVzdC5hZGFwdCgpLFxuICAgIERFTEVURTogQXBpUmVxdWVzdC5hZGFwdCgpLFxuICAgIFNUUkVBTTogQXBpUmVxdWVzdC5hZGFwdCgpLFxuICB9XG5cbiAgQFZpZXdDaGlsZChcImZhaWxlZFN0YXRlXCIsIHsgc3RhdGljOiB0cnVlIH0pIGZhaWxlZFN0YXRlOiBhbnlcbiAgQFZpZXdDaGlsZChcInBvbGxpbmdTdGF0ZVwiLCB7IHN0YXRpYzogdHJ1ZSB9KSBwb2xsaW5nU3RhdGU6IGFueVxuXG4gIHF1ZXN0aW9uQ29udHJvbCA9IHRoaXMuZmIuY29udHJvbChcIlwiLCBbVmFsaWRhdG9ycy5yZXF1aXJlZF0pXG5cbiAgZG93bmxvYWRSZXF1ZXN0ID0gQXBpUmVxdWVzdC5hZGFwdCh7XG4gICAgc2VydmVyOiAnYXNzZXRzL2ltYWdlcycsXG4gICAgcGF0aDogWydtZS5qcGcnXSxcbiAgICAvLyBzYXZlQXM6ICdqb2huLmpwZycgLy8gT3B0aW9uYWxcbiAgfSlcblxuICAvLyBkb3dubG9hZFJlcXVlc3QgPSBBcGlSZXF1ZXN0LmFkYXB0KHtcbiAgLy8gICBzZXJ2ZXI6ICdvaWRjL2FpL2ZpbGUnXG4gIC8vIH0pXG5cbiAgc2FtcGxlQ2xpZW50RGF0YSA9IHtcbiAgICAgIGlkOiAwLFxuICAgICAgbmFtZTogXCJPbGQgU2Nob29sIERhdGVzXCIsXG4gICAgICBkb21haW46IFwib3NkLmNvbVwiLFxuICAgICAgc2VydmljZTogXCJvc2RcIixcbiAgICAgIHNwaWZmZTogXCJvc2QuY29tL29zZFwiLFxuICAgICAgc2VjcmV0OiBcIlNNT1BFQ1hQLU9TNFAtVVNPRy1YMklJLTNYTUQxRlFEUjNJSlhcIixcbiAgICAgIGNyZWF0ZWQ6IDE2OTMwMDMxMzgsXG4gICAgICBtb2RpZmllZDogMTY5MzAwMzEzOCxcbiAgICAgIGljb246IFwiXCIsXG4gICAgICBpbWFnZUZpbGU6IFwiXCIsXG4gICAgICBlbWFpbDogXCJ3YXZlY29kZXJzQGdtYWlsLmNvbVwiXG4gIH1cblxuICByZXF1ZXN0Rm9ybSA9IHRoaXMuZmIuZ3JvdXAoe1xuICAgIHBhdGg6IHRoaXMuZmIuY29udHJvbDxzdHJpbmc+KFwiYWkvXCIpLFxuICAgIGhlYWRlcnM6IHRoaXMuZmIuYXJyYXkoW10pLFxuICAgIGFkYXB0ZXI6IFtudWxsXSxcbiAgICBtYXBwZXI6IFtudWxsXSxcbiAgICByZXRyeTogdGhpcy5mYi5ncm91cCh7XG4gICAgICB0aW1lczogWzNdLFxuICAgICAgZGVsYXk6IFszXSxcbiAgICB9KSxcbiAgICBwb2xsaW5nOiBbM10sXG4gIH0pXG5cbiAgQUlUeXBlID0gMFxuXG4gIHNhbXBsZUFkYXB0b3JzID0gW1xuICAgIHsgbGFiZWw6IFwiQ2xpZW50SW5mbyBCYXNpY1wiLCB2YWx1ZTogQ2xpZW50SW5mby5hZGFwdCB9LFxuICAgIHsgbGFiZWw6IFwiQUkgUHJvbXB0XCIsIHZhbHVlOiBBSVByb21wdC5hZGFwdCB9LFxuICBdXG5cbiAgc2FtcGxlTWFwcGVycyA9IFtcbiAgICB7IGxhYmVsOiBcIk1hcHBlciBCYXNpY1wiLCB2YWx1ZTogQ2xpZW50SW5mb01hcHBlci5hZGFwdCB9LFxuICAgIHsgbGFiZWw6IFwiQUkgUHJvbXB0XCIsIHZhbHVlOiBBSVByb21wdC5hZGFwdCB9LFxuICBdXG5cbiAgZ2V0IHJldHJ5KCkge1xuICAgIHJldHVybiB0aGlzLnJlcXVlc3RGb3JtLmdldCgncmV0cnknKT8udmFsdWVcbiAgfVxuXG4gIGdldCBoZWFkZXJzKCk6IEZvcm1BcnJheSB7XG4gICAgcmV0dXJuIHRoaXMucmVxdWVzdEZvcm0uZ2V0KCdoZWFkZXJzJykgYXMgRm9ybUFycmF5XG4gIH1cblxuICBnZXQgaXNWYWxpZCgpIHtcbiAgICB0aGlzLnJlcXVlc3RGb3JtLm1hcmtBbGxBc1RvdWNoZWQoKVxuICAgIHJldHVybiB0aGlzLnJlcXVlc3RGb3JtLnZhbGlkXG4gIH1cblxuICBoYXNJZCA9IChhcnI6IGFueVtdKSA9PiB7XG4gICAgaWYgKGFyci5sZW5ndGggPT09IDApIHJldHVybiBmYWxzZVxuICAgIHJldHVybiAhaXNOYU4oYXJyW2Fyci5sZW5ndGggLSAxXSlcbiAgfVxuXG4gIHByb3BzID0gKGFkYXB0ZXI6IGFueSkgPT4ge1xuICAgIHJldHVybiAoYWRhcHRlcikgPyBhZGFwdGVyKCkgOiBudWxsXG4gIH1cblxuICAvLyBzZXJ2ZXIgPSBgaHR0cDovL3NhbXBsZS1lbmRwb2ludC9hcy9hdXRob3JpemF0aW9uLm9hdXRoMmBcblxuICBhcnJheU9iamVjdHNUb09iamVjdHMgPSAoYXJyOiBhbnlbXSkgPT4ge1xuICAgIHJldHVybiBBcnJheS5pc0FycmF5KGFycikgPyBhcnIucmVkdWNlKChvYmosIGl0ZW0pID0+IE9iamVjdC5hc3NpZ24ob2JqLCB7IFtpdGVtLmtleV06IGl0ZW0udmFsdWUgfSksIHt9KSA6IHt9XG4gIH1cblxuICBjb25zdHJ1Y3RvcigpIHsgfVxuXG4gIG5nT25Jbml0KCkge1xuXG4gICAgLy8gY29uc3QgcmVxR2V0MiA9IEFwaVJlcXVlc3QuYWRhcHQoe1xuICAgIC8vICAgc2VydmVyLFxuICAgIC8vICAgcGF0aDogWydjbGllbnRzJ10sXG4gICAgLy8gICBoZWFkZXJzOiB7IGF1dGhlbnRpY2F0aW9uOiBcIkJlYXJlciA8S0VZPlwiIH0sXG4gICAgLy8gICBhZGFwdGVyOiBDbGllbnRJbmZvLFxuICAgIC8vICAgZGF0YVR5cGU6IERhdGFUeXBlLk9CSkVDVCxcbiAgICAvLyAgIC8vIGNvbmN1cnJlbnQ6IGZhbHNlLFxuICAgIC8vICAgLy8gcG9sbGluZzogMywgLy9zZWNvbmRzXG4gICAgLy8gfSlcblxuICAgIC8vIGNvbnN0IHJlcTIgPSBbMTAyNCwxMDI1LDEwMjZdLm1hcChpdGVtID0+IHtcbiAgICAvLyAgIHJldHVybiB0aGlzLmh0dHBNYW5hZ2VyU2VydmljZS5nZXRSZXF1ZXN0PENsaWVudEluZm9bXT4ocmVxR2V0MiwgW2l0ZW1dKVxuICAgIC8vICAgLnBpcGUoXG4gICAgLy8gICAgIGNhdGNoRXJyb3IoZXJyb3IgPT4ge1xuICAgIC8vICAgICAgIHJldHVybiB0aHJvd0Vycm9yKCgpID0+IG5ldyBFcnJvcihlcnJvci5lcnJvci5tZXNzYWdlKSlcbiAgICAvLyAgICAgfSlcbiAgICAvLyAgIClcbiAgICAvLyB9KVxuXG4gICAgLy8gZm9ya0pvaW4ocmVxMilcbiAgICAvLyAuc3Vic2NyaWJlKHJlcyA9PiBjb25zb2xlLmxvZyhyZXMpKVxuXG4gIH1cblxuICBhZGRIZWFkZXIoKSB7XG4gICAgY29uc3QgaGVhZGVyID0gdGhpcy5mYi5ncm91cCh7XG4gICAgICBrZXk6IFsnJywgVmFsaWRhdG9ycy5yZXF1aXJlZF0sXG4gICAgICB2YWx1ZTogWycnXVxuICAgIH0pXG4gICAgdGhpcy5oZWFkZXJzLnB1c2goaGVhZGVyKVxuICB9XG5cbiAgcmVtb3ZlSGVhZGVyKGluZGV4OiBudW1iZXIpIHtcbiAgICB0aGlzLmhlYWRlcnMucmVtb3ZlQXQoaW5kZXgpXG4gIH1cblxuICBjb21waWxlUmVxdWVzdCgpIHtcblxuICAgIGNvbnN0IHJlcXVlc3RQYXJhbXMgPSB0aGlzLnJlcXVlc3RGb3JtLnZhbHVlXG5cbiAgICByZXF1ZXN0UGFyYW1zLmhlYWRlcnMgPSB0aGlzLmFycmF5T2JqZWN0c1RvT2JqZWN0cyhcbiAgICAgIHJlcXVlc3RQYXJhbXMuaGVhZGVycyB8fCBbXVxuICAgIClcblxuICAgIGNvbnN0IHBhdGhSZXEgPSAocmVxdWVzdFBhcmFtcy5wYXRoID09PSBcIlwiKSA/IFtdIDogKHJlcXVlc3RQYXJhbXMucGF0aCB8fCBcIlwiKS5zcGxpdChcIi9cIilcblxuICAgIGlmICghdGhpcy5wb2xsaW5nU3RhdGUuY2hlY2tlZCkgcmVxdWVzdFBhcmFtcy5wb2xsaW5nID0gMFxuXG4gICAgaWYgKCF0aGlzLmZhaWxlZFN0YXRlLmNoZWNrZWQpIHtcbiAgICAgIHJlcXVlc3RQYXJhbXMucmV0cnkgPSB7IHRpbWVzOiAwLGRlbGF5OiAwIH1cbiAgICB9XG5cbiAgICBjb25zdCBhcGlPcHRpb25zID0gQXBpUmVxdWVzdC5hZGFwdChyZXF1ZXN0UGFyYW1zKVxuICAgIGFwaU9wdGlvbnMucGF0aCA9IFtdXG5cbiAgICByZXR1cm4geyBhcGlPcHRpb25zOiBhcGlPcHRpb25zLCBwYXRoOiBwYXRoUmVxIH1cblxuICB9XG5cbiAgb25HZXRSZXF1ZXN0KCkge1xuXG4gICAgaWYoIXRoaXMuaXNWYWxpZCkgcmV0dXJuXG5cbiAgICBjb25zdCByZXFQYXJhbXMgPSB0aGlzLmNvbXBpbGVSZXF1ZXN0KClcblxuICAgIHRoaXMucmVxdWVzdFBhcmFtcy5HRVQgPSByZXFQYXJhbXMuYXBpT3B0aW9uc1xuXG4gICAgdGhpcy5HRVQkID0gRU1QVFkgLy9DYW5jZWxzIFByZXZpb3VzXG4gICAgdGhpcy5HRVRfZXJyb3IkLm5leHQoJycpXG5cbiAgICB0aGlzLkdFVCQgPSB0aGlzLmh0dHBNYW5hZ2VyU2VydmljZS5nZXRSZXF1ZXN0PENsaWVudEluZm9bXT4ocmVxUGFyYW1zLmFwaU9wdGlvbnMsIHJlcVBhcmFtcy5wYXRoKVxuICAgIC5waXBlKFxuICAgICAgLy8gdGFwKChkYXRhKSA9PiBjb25zb2xlLmxvZyhcIkFQSSBHRVQgcmVzcG9uc2VcIiwgZGF0YSkpLFxuICAgICAgY2F0Y2hFcnJvcihlcnJvciA9PiB7XG4gICAgICAgIHJldHVybiB0aHJvd0Vycm9yKCgpID0+IHRoaXMuZXJyb3JIYW5kbGluZyhlcnJvciwgJ0dFVCcpKVxuICAgICAgfSlcbiAgICApXG5cbiAgfVxuXG4gIG9uQ3JlYXRlUmVxdWVzdCgpIHtcblxuICAgIGlmKCF0aGlzLmlzVmFsaWQpIHJldHVyblxuXG4gICAgY29uc3QgcmVxUGFyYW1zID0gdGhpcy5jb21waWxlUmVxdWVzdCgpXG4gICAgdGhpcy5yZXF1ZXN0UGFyYW1zLlBPU1QgPSByZXFQYXJhbXMuYXBpT3B0aW9uc1xuXG4gICAgdGhpcy5QT1NUJCA9IEVNUFRZIC8vQ2FuY2VscyBQcmV2aW91c1xuICAgIHRoaXMuUE9TVF9lcnJvciQubmV4dCgnJylcblxuICAgIGNvbnNvbGUubG9nKFwiUE9TVFwiLCB0aGlzLnNhbXBsZUNsaWVudERhdGEpXG4gICAgY29uc29sZS5sb2coXCJQT1NUXCIsIHJlcVBhcmFtcy5hcGlPcHRpb25zKVxuICAgIGNvbnNvbGUubG9nKFwiUE9TVFwiLCByZXFQYXJhbXMucGF0aClcblxuICAgIHRoaXMuUE9TVCQgPSB0aGlzLmh0dHBNYW5hZ2VyU2VydmljZS5wb3N0UmVxdWVzdDxDbGllbnRJbmZvPih0aGlzLnNhbXBsZUNsaWVudERhdGEsIHJlcVBhcmFtcy5hcGlPcHRpb25zLCByZXFQYXJhbXMucGF0aClcbiAgICAucGlwZShcbiAgICAgIC8vIHRhcCgoZGF0YSkgPT4gY29uc29sZS5sb2coXCJBUEkgUE9TVCByZXNwb25zZVwiLCBkYXRhKSksXG4gICAgICBjYXRjaEVycm9yKGVycm9yID0+IHtcbiAgICAgICAgcmV0dXJuIHRocm93RXJyb3IoKCkgPT4gdGhpcy5lcnJvckhhbmRsaW5nKGVycm9yLCAnUE9TVCcpKVxuICAgICAgfSlcbiAgICApXG5cbiAgfVxuXG4gIG9uVXBkYXRlUmVxdWVzdCgpIHtcblxuICAgIGlmKCF0aGlzLmlzVmFsaWQpIHJldHVyblxuXG4gICAgY29uc3QgcmVxUGFyYW1zID0gdGhpcy5jb21waWxlUmVxdWVzdCgpXG5cbiAgICBpZighdGhpcy5oYXNJZChyZXFQYXJhbXMucGF0aCkpIHtcbiAgICAgIGNvbnNvbGUubG9nKFwiTWlzc2luZyBJRFwiKVxuICAgICAgcmV0dXJuXG4gICAgfVxuXG4gICAgdGhpcy5zYW1wbGVDbGllbnREYXRhLmlkID0gcGFyc2VJbnQocmVxUGFyYW1zLnBhdGhbcmVxUGFyYW1zLnBhdGgubGVuZ3RoLTFdKVxuICAgIHRoaXMucmVxdWVzdFBhcmFtcy5QVVQgPSByZXFQYXJhbXMuYXBpT3B0aW9uc1xuXG4gICAgdGhpcy5QVVQkID0gRU1QVFkgLy9DYW5jZWxzIFByZXZpb3VzXG4gICAgdGhpcy5QVVRfZXJyb3IkLm5leHQoJycpXG5cbiAgICB0aGlzLlBVVCQgPSB0aGlzLmh0dHBNYW5hZ2VyU2VydmljZS5wdXRSZXF1ZXN0PGFueT4odGhpcy5zYW1wbGVDbGllbnREYXRhLCByZXFQYXJhbXMuYXBpT3B0aW9ucywgcmVxUGFyYW1zLnBhdGgpXG4gICAgLnBpcGUoXG4gICAgICAvLyB0YXAoKGRhdGEpID0+IGNvbnNvbGUubG9nKFwiQVBJIFBVVCByZXNwb25zZVwiLCBkYXRhKSksXG4gICAgICBjYXRjaEVycm9yKGVycm9yID0+IHtcbiAgICAgICAgcmV0dXJuIHRocm93RXJyb3IoKCkgPT4gdGhpcy5lcnJvckhhbmRsaW5nKGVycm9yLCAnUFVUJykpXG4gICAgICB9KVxuICAgIClcblxuICB9XG5cbiAgb25EZWxldGVSZXF1ZXN0KCkge1xuXG4gICAgaWYoIXRoaXMuaXNWYWxpZCkgcmV0dXJuXG5cbiAgICBjb25zdCByZXFQYXJhbXMgPSB0aGlzLmNvbXBpbGVSZXF1ZXN0KClcbiAgICB0aGlzLnJlcXVlc3RQYXJhbXMuREVMRVRFID0gcmVxUGFyYW1zLmFwaU9wdGlvbnNcblxuICAgIGlmKCF0aGlzLmhhc0lkKHJlcVBhcmFtcy5wYXRoKSkge1xuICAgICAgY29uc29sZS5sb2coXCJNaXNzaW5nIElEXCIpXG4gICAgICByZXR1cm5cbiAgICB9XG5cbiAgICB0aGlzLnNhbXBsZUNsaWVudERhdGEuaWQgPSBwYXJzZUludChyZXFQYXJhbXMucGF0aFtyZXFQYXJhbXMucGF0aC5sZW5ndGgtMV0pXG4gICAgdGhpcy5yZXF1ZXN0UGFyYW1zLkRFTEVURSA9IHJlcVBhcmFtcy5hcGlPcHRpb25zXG5cbiAgICB0aGlzLkRFTEVURSQgPSBFTVBUWSAvL0NhbmNlbHMgUHJldmlvdXNcbiAgICB0aGlzLkRFTEVURV9lcnJvciQubmV4dCgnJylcblxuICAgIHRoaXMuREVMRVRFJCA9IHRoaXMuaHR0cE1hbmFnZXJTZXJ2aWNlLmRlbGV0ZVJlcXVlc3Q8Q2xpZW50SW5mbz4ocmVxUGFyYW1zLmFwaU9wdGlvbnMsIHJlcVBhcmFtcy5wYXRoKVxuICAgIC5waXBlKFxuICAgICAgLy8gdGFwKChkYXRhKSA9PiBjb25zb2xlLmxvZyhcIkFQSSBERUxFVEUgcmVzcG9uc2VcIiwgZGF0YSkpLFxuICAgICAgY2F0Y2hFcnJvcihlcnJvciA9PiB7XG4gICAgICAgIHJldHVybiB0aHJvd0Vycm9yKCgpID0+IHRoaXMuZXJyb3JIYW5kbGluZyhlcnJvciwgJ0RFTEVURScpKVxuICAgICAgfSlcbiAgICApXG5cbiAgfVxuXG4gIG9uU3RyZWFtUG9zdFJlcXVlc3QoKSB7XG5cbiAgICBpZiAoIXRoaXMuaXNWYWxpZCkgcmV0dXJuXG5cbiAgICBjb25zdCByZXFQYXJhbXMgPSB0aGlzLmNvbXBpbGVSZXF1ZXN0KClcblxuICAgIGxldCBwYXlsb2FkID0ge31cbiAgICBsZXQgYXBpUGF0aDogc3RyaW5nW10gPSByZXFQYXJhbXMucGF0aFxuICAgIGxldCBhcGlPcHRpb25zID0gcmVxUGFyYW1zLmFwaU9wdGlvbnNcbiAgICBsZXQgcmVzcG9uc2VNYXBwZXI6IChpdGVtczogYW55KSA9PiBhbnkgPSAoaXRlbXMpID0+IGl0ZW1zLnJlc3BvbnNlXG5cbiAgICBpZiAodGhpcy5BSVR5cGUgPT09IDApIHtcblxuICAgICAgLy8gQVBJIHJlcXVlc3RcbiAgICAgIHBheWxvYWQgPSB7IHByb21wdDogdGhpcy5xdWVzdGlvbkNvbnRyb2wudmFsdWUgfVxuXG4gICAgfSBlbHNlIHtcblxuICAgICAgLy8gTG9jYWwgT2xsYW1hIHJlcXVlc3RcbiAgICAgIGFwaU9wdGlvbnMuc2VydmVyID0gXCJhcGlcIlxuICAgICAgYXBpUGF0aCA9IFtcImdlbmVyYXRlXCJdXG4gICAgICBhcGlPcHRpb25zLnN0cmVhbSA9IHRydWVcbiAgICAgIHBheWxvYWQgPSB7XG4gICAgICAgIG1vZGVsOiBcInBoaTM6bGF0ZXN0XCIsXG4gICAgICAgIHByb21wdDogdGhpcy5xdWVzdGlvbkNvbnRyb2wudmFsdWUsXG4gICAgICAgIHN0cmVhbTogdHJ1ZSxcbiAgICAgIH1cblxuICAgICAgcmVzcG9uc2VNYXBwZXIgPSAoaXRlbXMpID0+IGl0ZW1zLm1hcCgod29yZDogYW55KSA9PiB3b3JkLnJlc3BvbnNlKS5mbGF0KCkuam9pbignJylcblxuICAgIH1cblxuICAgIHRoaXMucmVxdWVzdFBhcmFtcy5TVFJFQU0gPSBhcGlPcHRpb25zXG4gICAgdGhpcy5TVFJFQU1fQUkkID0gRU1QVFlcbiAgICB0aGlzLlNUUkVBTV9BSV9lcnJvciQubmV4dCgnJylcblxuICAgIHRoaXMuU1RSRUFNX0FJJCA9IHRoaXMuaHR0cE1hbmFnZXJTZXJ2aWNlLnBvc3RSZXF1ZXN0PGFueT4ocGF5bG9hZCwgYXBpT3B0aW9ucywgYXBpUGF0aCkucGlwZShcbiAgICAgIG1hcChyZXNwb25zZU1hcHBlciksXG4gICAgICB0YXAoKCkgPT4gdGhpcy5xdWVzdGlvbkNvbnRyb2wucmVzZXQoKSksXG4gICAgICBjYXRjaEVycm9yKGVycm9yID0+IHRocm93RXJyb3IoKCkgPT4gdGhpcy5lcnJvckhhbmRsaW5nKGVycm9yLCAnU1RSRUFNJykpKVxuICAgIClcblxuICB9XG5cblxuICBvblN0cmVhbVJlcXVlc3QoKSB7XG5cbiAgICBpZighdGhpcy5pc1ZhbGlkKSByZXR1cm5cblxuICAgIGNvbnN0IHJlcVBhcmFtcyA9IHRoaXMuY29tcGlsZVJlcXVlc3QoKVxuXG4gICAgcmVxUGFyYW1zLmFwaU9wdGlvbnMuc3RyZWFtID0gdHJ1ZVxuXG4gICAgdGhpcy5yZXF1ZXN0UGFyYW1zLkdFVCA9IHJlcVBhcmFtcy5hcGlPcHRpb25zXG4gICAgdGhpcy5TVFJFQU0kID0gdGhpcy5odHRwTWFuYWdlclNlcnZpY2UuZ2V0UmVxdWVzdDxDbGllbnRJbmZvW10+KHJlcVBhcmFtcy5hcGlPcHRpb25zLCByZXFQYXJhbXMucGF0aClcbiAgICAgICAgLnBpcGUoXG4gICAgICAvLyB0YXAoKGRhdGEpID0+IGNvbnNvbGUubG9nKFwiQVBJIFNUUkVBTSByZXNwb25zZVwiLCBkYXRhKSksXG4gICAgICBjYXRjaEVycm9yKGVycm9yID0+IHtcbiAgICAgICAgcmV0dXJuIHRocm93RXJyb3IoKCkgPT4gdGhpcy5lcnJvckhhbmRsaW5nKGVycm9yLCAnU1RSRUFNJykpXG4gICAgICB9KVxuICAgIClcblxuICB9XG5cbiAgb25Eb3dubG9hZENvbXBsZXRlZCgpIHtcblxuICAgIGNvbnN0IG1lc3NhZ2UgPSBcIkRvd25sb2FkIENvbXBsZXRlZFwiXG5cbiAgICBjb25zdCBkaXNwbGF5ID0gVG9hc3REaXNwbGF5LmFkYXB0KHtcbiAgICAgIG1lc3NhZ2UsXG4gICAgICBhY3Rpb246ICdPaycsXG4gICAgICBjb2xvcjogVG9hc3RDb2xvcnMuU1VDQ0VTUyxcbiAgICAgIGljb246ICdzZW50aW1lbnRfc2F0aXNmaWVkX2FsdCcsXG4gICAgfSlcblxuICAgIHRoaXMudG9hc3RNZXNzYWdlLnRvYXN0TWVzc2FnZShkaXNwbGF5KVxuICB9XG5cbiAgb25Eb3dubG9hZEZhaWxlZChlcnI6IHN0cmluZykge1xuXG4gICAgY29uc3QgbWVzc2FnZSA9IFwiRG93bmxvYWQgRmFpbGVkXCJcblxuICAgIGNvbnN0IGRpc3BsYXkgPSBUb2FzdERpc3BsYXkuYWRhcHQoe1xuICAgICAgbWVzc2FnZSxcbiAgICAgIGFjdGlvbjogJ09rJyxcbiAgICAgIGNvbG9yOiBUb2FzdENvbG9ycy5FUlJPUixcbiAgICAgIGljb246ICd3YXJuaW5nJyxcbiAgICB9KVxuXG4gICAgdGhpcy50b2FzdE1lc3NhZ2UudG9hc3RNZXNzYWdlKGRpc3BsYXkpXG4gIH1cblxuICBlcnJvckhhbmRsaW5nKGVycjogYW55LCB0eXBlOiBzdHJpbmcpIHtcbiAgICBpZih0eXBlID09PSAnR0VUJykgdGhpcy5HRVRfZXJyb3IkLm5leHQoZXJyLm1lc3NhZ2UpXG4gICAgaWYodHlwZSA9PT0gJ1BPU1QnKSB0aGlzLlBPU1RfZXJyb3IkLm5leHQoZXJyLm1lc3NhZ2UpXG4gICAgaWYodHlwZSA9PT0gJ1BVVCcpIHRoaXMuUFVUX2Vycm9yJC5uZXh0KGVyci5tZXNzYWdlKVxuICAgIGlmKHR5cGUgPT09ICdERUxFVEUnKSB0aGlzLkRFTEVURV9lcnJvciQubmV4dChlcnIubWVzc2FnZSlcbiAgICBpZih0eXBlID09PSAnU1RSRUFNJykgdGhpcy5TVFJFQU1fZXJyb3IkLm5leHQoZXJyLm1lc3NhZ2UpXG4gIH1cblxuICBvblNlbGVjdEFJVHlwZSh0eXBlOiBudW1iZXIpIHtcbiAgICB0aGlzLkFJVHlwZSA9IHR5cGVcbiAgfVxuXG59XG4iLCI8ZGl2IHN0eWxlPVwibWFyZ2luOiAycmVtO1wiPlxuXG4gIDxoMj5cbiAgICBIVFRQIFJlcXVlc3QgTWFuYWdlclxuICA8L2gyPlxuXG4gIDxkaXYgW2Zvcm1Hcm91cF09XCJyZXF1ZXN0Rm9ybVwiIHN0eWxlPVwibWFyZ2luLXRvcDogMnJlbTtcIj5cbiAgICA8ZGl2IHN0eWxlPVwiZGlzcGxheTogZmxleDsgZ2FwOiAuNXJlbVwiPlxuICAgICAgPG1hdC1mb3JtLWZpZWxkIGFwcGVhcmFuY2U9XCJvdXRsaW5lXCI+XG4gICAgICAgIDxtYXQtbGFiZWw+QWRhcHRlciAoTW9kZWwpPC9tYXQtbGFiZWw+XG4gICAgICAgIDxtYXQtc2VsZWN0IGZvcm1Db250cm9sTmFtZT1cImFkYXB0ZXJcIiAjYWRhcHRlclNlbGVjdD5cbiAgICAgICAgICA8bWF0LW9wdGlvbj5Ob25lPC9tYXQtb3B0aW9uPlxuICAgICAgICAgIDxtYXQtb3B0aW9uICpuZ0Zvcj1cImxldCBhZGFwdGVyIG9mIHNhbXBsZUFkYXB0b3JzXCIgW3ZhbHVlXT1cImFkYXB0ZXIudmFsdWVcIj5cbiAgICAgICAgICAgIHt7YWRhcHRlci5sYWJlbH19XG4gICAgICAgICAgPC9tYXQtb3B0aW9uPlxuICAgICAgICA8L21hdC1zZWxlY3Q+XG4gICAgICA8L21hdC1mb3JtLWZpZWxkPlxuICAgICAgPG1hdC1mb3JtLWZpZWxkIGFwcGVhcmFuY2U9XCJvdXRsaW5lXCI+XG4gICAgICAgIDxtYXQtbGFiZWw+TWFwcGVyIChNb2RlbCk8L21hdC1sYWJlbD5cbiAgICAgICAgPG1hdC1zZWxlY3QgZm9ybUNvbnRyb2xOYW1lPVwibWFwcGVyXCIgI21hcHBlclNlbGVjdD5cbiAgICAgICAgICA8bWF0LW9wdGlvbj5Ob25lPC9tYXQtb3B0aW9uPlxuICAgICAgICAgIDxtYXQtb3B0aW9uICpuZ0Zvcj1cImxldCBtYXBwZXIgb2Ygc2FtcGxlTWFwcGVyc1wiIFt2YWx1ZV09XCJtYXBwZXIudmFsdWVcIj5cbiAgICAgICAgICAgIHt7bWFwcGVyLmxhYmVsfX1cbiAgICAgICAgICA8L21hdC1vcHRpb24+XG4gICAgICAgIDwvbWF0LXNlbGVjdD5cbiAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XG4gICAgPC9kaXY+XG4gICAgPGRpdiBzdHlsZT1cImRpc3BsYXk6IGZsZXg7IG1hcmdpbi1ib3R0b206IDJyZW07XCIgKm5nSWY9XCJhZGFwdGVyU2VsZWN0LnZhbHVlIHx8IG1hcHBlclNlbGVjdC52YWx1ZVwiPlxuICAgICAgPGRpdiBzdHlsZT1cImZsZXg6MVwiIGNsYXNzPVwiYm94XCI+XG4gICAgICAgIDxoMz5BZGFwdGVyIChJbmNvbWluZyk8L2gzPlxuICAgICAgICA8ZGl2ICpuZ0lmPVwiYWRhcHRlclNlbGVjdC52YWx1ZTsgZWxzZSBOT19BREFQVEVSXCI+XG4gICAgICAgICAge3sgcHJvcHMoYWRhcHRlclNlbGVjdC52YWx1ZSkgfCBqc29uIH19XG4gICAgICAgIDwvZGl2PlxuICAgICAgICA8bmctdGVtcGxhdGUgI05PX0FEQVBURVI+Tm8gVHJhbnNmb3JtYXRpb248L25nLXRlbXBsYXRlPlxuICAgICAgPC9kaXY+XG4gICAgICA8ZGl2IHN0eWxlPVwiZmxleDoxXCIgY2xhc3M9XCJib3hcIj5cbiAgICAgICAgPGgzPk1hcHBlciAoT3V0Z29pbmcpPC9oMz5cbiAgICAgICAgPGRpdiAqbmdJZj1cIm1hcHBlclNlbGVjdC52YWx1ZTsgZWxzZSBOT19NQVBQRVJcIj5cbiAgICAgICAgICB7eyBwcm9wcyhtYXBwZXJTZWxlY3QudmFsdWUpIHwganNvbiB9fVxuICAgICAgICA8L2Rpdj5cbiAgICAgICAgPG5nLXRlbXBsYXRlICNOT19NQVBQRVI+Tm8gVHJhbnNmb3JtYXRpb248L25nLXRlbXBsYXRlPlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG4gICAgPGRpdj5cbiAgICAgIDxtYXQtZm9ybS1maWVsZCBhcHBlYXJhbmNlPVwib3V0bGluZVwiPlxuICAgICAgICA8bWF0LWxhYmVsPlJlc3RQYXRoICgvIGRlbGltaXRlZCk8L21hdC1sYWJlbD5cbiAgICAgICAgPGlucHV0IG1hdElucHV0IHBsYWNlaG9sZGVyPVwiY2xpZW50cy9saXN0XCIgZm9ybUNvbnRyb2xOYW1lPVwicGF0aFwiPlxuICAgICAgPC9tYXQtZm9ybS1maWVsZD5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2PlxuICAgICAgPGRpdiBmb3JtQXJyYXlOYW1lPVwiaGVhZGVyc1wiPlxuICAgICAgICA8ZGl2ICpuZ0Zvcj1cImxldCB0YXNrIG9mIGhlYWRlcnMuY29udHJvbHM7IGxldCBpID0gaW5kZXhcIiBbZm9ybUdyb3VwTmFtZV09XCJpXCI+XG4gICAgICAgICAgPGRpdiBzdHlsZT1cImRpc3BsYXk6IGZsZXg7IGdhcDogLjVyZW1cIj5cbiAgICAgICAgICAgIDxtYXQtZm9ybS1maWVsZCBhcHBlYXJhbmNlPVwib3V0bGluZVwiPlxuICAgICAgICAgICAgICA8bWF0LWxhYmVsPktleTwvbWF0LWxhYmVsPlxuICAgICAgICAgICAgICA8aW5wdXQgbWF0SW5wdXQgcGxhY2Vob2xkZXI9XCJhdXRoZW50aWNhdGlvblwiIGZvcm1Db250cm9sTmFtZT1cImtleVwiPlxuICAgICAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cbiAgICAgICAgICAgIDxtYXQtZm9ybS1maWVsZCBhcHBlYXJhbmNlPVwib3V0bGluZVwiIHN0eWxlPVwiZmxleDoxXCI+XG4gICAgICAgICAgICAgIDxtYXQtbGFiZWw+VmFsdWU8L21hdC1sYWJlbD5cbiAgICAgICAgICAgICAgPGlucHV0IG1hdElucHV0IHBsYWNlaG9sZGVyPVwic2FtcGxlXCIgZm9ybUNvbnRyb2xOYW1lPVwidmFsdWVcIj5cbiAgICAgICAgICAgIDwvbWF0LWZvcm0tZmllbGQ+XG4gICAgICAgICAgICA8ZGl2IHN0eWxlPVwibWFyZ2luLXRvcDogLjVyZW07XCI+XG4gICAgICAgICAgICAgIDxidXR0b24gbWF0LWljb24tYnV0dG9uIChjbGljayk9XCJyZW1vdmVIZWFkZXIoaSlcIj5cbiAgICAgICAgICAgICAgICAgIDxtYXQtaWNvbj5jbG9zZTwvbWF0LWljb24+XG4gICAgICAgICAgICAgIDwvYnV0dG9uPlxuICAgICAgICAgICAgPC9kaXY+XG4gICAgICAgICAgPC9kaXY+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9kaXY+XG4gICAgICA8YnV0dG9uIG1hdC1zdHJva2VkLWJ1dHRvbiAoY2xpY2spPVwiYWRkSGVhZGVyKClcIiBjbGFzcz1cImJ0blwiPkFkZCBIZWFkZXI8L2J1dHRvbj5cbiAgICA8L2Rpdj5cbiAgICA8ZGl2IHN0eWxlPVwibWFyZ2luLXRvcDogMnJlbTsgZGlzcGxheTogZmxleDsgZmxleC1kaXJlY3Rpb246Y29sdW1uOyBnYXA6IDFyZW07XCI+XG4gICAgICA8ZGl2PlxuICAgICAgICA8bWF0LXNsaWRlLXRvZ2dsZSAjZmFpbGVkU3RhdGU+UmV0cnkgb24gRmFpbGVkPC9tYXQtc2xpZGUtdG9nZ2xlPlxuICAgICAgICA8ZGl2ICpuZ0lmPVwiZmFpbGVkU3RhdGUuY2hlY2tlZFwiIHN0eWxlPVwiZGlzcGxheTogZmxleDsgZ2FwOiAuNXJlbTsgbWFyZ2luLXRvcDogMXJlbTtcIiBmb3JtR3JvdXBOYW1lPVwicmV0cnlcIj5cbiAgICAgICAgICA8bWF0LWZvcm0tZmllbGQgYXBwZWFyYW5jZT1cIm91dGxpbmVcIj5cbiAgICAgICAgICAgIDxtYXQtbGFiZWw+I29mIFRpbWVzPC9tYXQtbGFiZWw+XG4gICAgICAgICAgICA8aW5wdXQgbWF0SW5wdXQgcGxhY2Vob2xkZXI9XCIzXCIgZm9ybUNvbnRyb2xOYW1lPVwidGltZXNcIiB2YWx1ZT1cIjNcIj5cbiAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxuICAgICAgICAgIDxtYXQtZm9ybS1maWVsZCBhcHBlYXJhbmNlPVwib3V0bGluZVwiPlxuICAgICAgICAgICAgPG1hdC1sYWJlbD5EZWxheSBVbnRpbCBOZXh0PC9tYXQtbGFiZWw+XG4gICAgICAgICAgICA8aW5wdXQgbWF0SW5wdXQgcGxhY2Vob2xkZXI9XCIzXCIgZm9ybUNvbnRyb2xOYW1lPVwiZGVsYXlcIiB2YWx1ZT1cIjNcIj5cbiAgICAgICAgICA8L21hdC1mb3JtLWZpZWxkPlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgICAgPGRpdj5cbiAgICAgICAgPG1hdC1zbGlkZS10b2dnbGUgI3BvbGxpbmdTdGF0ZT5Qb2xsaW5nPC9tYXQtc2xpZGUtdG9nZ2xlPlxuICAgICAgICA8ZGl2ICpuZ0lmPVwicG9sbGluZ1N0YXRlLmNoZWNrZWRcIj5cbiAgICAgICAgICA8bWF0LWZvcm0tZmllbGQgYXBwZWFyYW5jZT1cIm91dGxpbmVcIiBzdHlsZT1cIm1hcmdpbi10b3A6IDFyZW1cIj5cbiAgICAgICAgICAgIDxtYXQtbGFiZWw+I29mIFNlY29uZHM8L21hdC1sYWJlbD5cbiAgICAgICAgICAgIDxpbnB1dCBtYXRJbnB1dCBwbGFjZWhvbGRlcj1cIjNcIiBmb3JtQ29udHJvbE5hbWU9XCJwb2xsaW5nXCIgdmFsdWU9XCIzXCI+XG4gICAgICAgICAgPC9tYXQtZm9ybS1maWVsZD5cbiAgICAgICAgPC9kaXY+XG4gICAgICA8L2Rpdj5cbiAgICA8L2Rpdj5cbiAgPC9kaXY+XG5cbiAgPGRpdiBzdHlsZT1cIm1hcmdpbi1ib3R0b206IDFyZW07IG1hcmdpbi10b3A6IDJyZW07XCI+XG4gICAgPG1hdC1wcm9ncmVzcy1iYXIgbW9kZT1cImluZGV0ZXJtaW5hdGVcIlxuICAgICAgKm5nSWY9XCIoaXNQZW5kaW5nJCB8IGFzeW5jKVwiXG4gICAgPjwvbWF0LXByb2dyZXNzLWJhcj5cbiAgICA8bWF0LXByb2dyZXNzLWJhciBtb2RlPVwiZGV0ZXJtaW5hdGVcIlxuICAgICAgKm5nSWY9XCJwb2xsaW5nU3RhdGUuY2hlY2tlZCAmJiAhKGlzUGVuZGluZyQgfCBhc3luYylcIlxuICAgICAgW3ZhbHVlXT1cIih0aGlzLmNvdW50ZG93biQgfCBhc3luYylcIlxuICAgID48L21hdC1wcm9ncmVzcy1iYXI+XG4gIDwvZGl2PlxuXG4gIDxkaXYgc3R5bGU9XCJtYXJnaW4tdG9wOiAxcmVtXCI+XG4gICAgPG1hdC1kaXZpZGVyPjwvbWF0LWRpdmlkZXI+XG4gIDwvZGl2PlxuXG4gIDxkaXYgc3R5bGU9XCJtYXJnaW4tdG9wOiAycmVtXCI+XG4gICAgPGRpdiBzdHlsZT1cImRpc3BsYXk6IGZsZXg7XCI+XG4gICAgICA8aDIgc3R5bGU9XCJmbGV4OjFcIj5HRVQgUmVxdWVzdDwvaDI+XG4gICAgICA8ZGl2PlxuICAgICAgICA8YnV0dG9uIG1hdC1yYWlzZWQtYnV0dG9uIChjbGljayk9XCJvbkdldFJlcXVlc3QoKVwiIGNsYXNzPVwiYnRuXCI+UmVxdWVzdDwvYnV0dG9uPlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG5cbiAgICA8ZGl2ICpuZ0lmPVwiKEdFVF9lcnJvciQgfCBhc3luYykgYXMgZ2V0X2Vycm9yXCIgc3R5bGU9XCJtYXJnaW4tdG9wOiAuNXJlbTtcIj5cbiAgICAgIDxtYXQtZXJyb3I+e3sgZ2V0X2Vycm9yIH19PC9tYXQtZXJyb3I+XG4gICAgPC9kaXY+XG5cbiAgICA8ZGl2IHN0eWxlPVwibWFyZ2luLXRvcDogMXJlbTtcIiAqbmdJZj1cIihHRVQkIHwgYXN5bmMpIGFzIGRhdGFSZWNvcmRcIj5cbiAgICAgIDwhLS0gPGRpdiBbaW5uZXJIVE1MXT1cIihHRVQkIHwgYXN5bmMpIHwganNvbnZcIj48L2Rpdj4gLS0+XG4gICAgICB7eyBkYXRhUmVjb3JkIHwganNvbiB9fVxuICAgIDwvZGl2PlxuXG4gIDwvZGl2PlxuXG4gIDxkaXYgc3R5bGU9XCJtYXJnaW4tdG9wOiAycmVtXCI+XG4gICAgPG1hdC1kaXZpZGVyPjwvbWF0LWRpdmlkZXI+XG4gIDwvZGl2PlxuXG4gIDxkaXYgc3R5bGU9XCJtYXJnaW4tdG9wOiAycmVtXCI+XG4gICAgPGRpdiBzdHlsZT1cImRpc3BsYXk6IGZsZXg7XCI+XG4gICAgICA8aDIgc3R5bGU9XCJmbGV4OjFcIj5QT1NUIFJlcXVlc3Q8L2gyPlxuICAgICAgPGRpdj5cbiAgICAgICAgPGJ1dHRvbiBtYXQtcmFpc2VkLWJ1dHRvbiAoY2xpY2spPVwib25DcmVhdGVSZXF1ZXN0KClcIiBjbGFzcz1cImJ0blwiPlJlcXVlc3Q8L2J1dHRvbj5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuXG4gICAgPGRpdiAqbmdJZj1cIihQT1NUX2Vycm9yJCB8IGFzeW5jKSBhcyBwb3N0X2Vycm9yXCIgc3R5bGU9XCJtYXJnaW4tdG9wOiAuNXJlbTtcIj5cbiAgICAgIDxtYXQtZXJyb3I+e3sgcG9zdF9lcnJvciB9fTwvbWF0LWVycm9yPlxuICAgIDwvZGl2PlxuXG4gICAgPGRpdiBzdHlsZT1cIm1hcmdpbi10b3A6IDFyZW07XCIgKm5nSWY9XCIoUE9TVCQgfCBhc3luYykgYXMgZGF0YVJlY29yZFwiPlxuICAgICAgPCEtLSA8ZGl2IFtpbm5lckhUTUxdPVwiKFBPU1QkIHwgYXN5bmMpIHwganNvbnZcIj48L2Rpdj4gLS0+XG4gICAgICB7eyBkYXRhUmVjb3JkIHwganNvbiB9fVxuICAgIDwvZGl2PlxuXG4gIDwvZGl2PlxuXG4gIDxkaXYgc3R5bGU9XCJtYXJnaW4tdG9wOiAycmVtXCI+XG4gICAgPG1hdC1kaXZpZGVyPjwvbWF0LWRpdmlkZXI+XG4gIDwvZGl2PlxuXG4gIDxkaXYgc3R5bGU9XCJtYXJnaW4tdG9wOiAycmVtXCI+XG4gICAgPGRpdiBzdHlsZT1cImRpc3BsYXk6IGZsZXg7XCI+XG4gICAgICA8aDIgc3R5bGU9XCJmbGV4OjFcIj5QVVQgUmVxdWVzdDwvaDI+XG4gICAgICA8ZGl2PlxuICAgICAgICA8YnV0dG9uIG1hdC1yYWlzZWQtYnV0dG9uIChjbGljayk9XCJvblVwZGF0ZVJlcXVlc3QoKVwiIGNsYXNzPVwiYnRuXCI+UmVxdWVzdDwvYnV0dG9uPlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG5cbiAgICA8ZGl2ICpuZ0lmPVwiKFBVVF9lcnJvciQgfCBhc3luYykgYXMgcHV0X2Vycm9yXCIgc3R5bGU9XCJtYXJnaW4tdG9wOiAuNXJlbTtcIj5cbiAgICAgIDxtYXQtZXJyb3I+e3sgcHV0X2Vycm9yIH19PC9tYXQtZXJyb3I+XG4gICAgPC9kaXY+XG5cbiAgICA8aDM+SW5jbHVkZSBSZWNvcmQgSUQgaW4gdGhlIFJlc3RQYXRoPC9oMz5cblxuICAgIDxkaXYgc3R5bGU9XCJtYXJnaW4tdG9wOiAxcmVtO1wiICpuZ0lmPVwiKFBVVCQgfCBhc3luYykgYXMgZGF0YVJlY29yZFwiPlxuICAgICAgPCEtLSA8ZGl2IFtpbm5lckhUTUxdPVwiKFBVVCQgfCBhc3luYykgfCBqc29udlwiPjwvZGl2PiAtLT5cbiAgICAgICB7eyBkYXRhUmVjb3JkIHwganNvbiB9fVxuICAgIDwvZGl2PlxuXG4gIDwvZGl2PlxuXG4gIDxkaXYgc3R5bGU9XCJtYXJnaW4tdG9wOiAycmVtXCI+XG4gICAgPG1hdC1kaXZpZGVyPjwvbWF0LWRpdmlkZXI+XG4gIDwvZGl2PlxuXG4gIDxkaXYgc3R5bGU9XCJtYXJnaW4tdG9wOiAycmVtXCI+XG4gICAgPGRpdiBzdHlsZT1cImRpc3BsYXk6IGZsZXg7XCI+XG4gICAgICA8aDIgc3R5bGU9XCJmbGV4OjFcIj5ERUxFVEUgUmVxdWVzdDwvaDI+XG4gICAgICA8ZGl2PlxuICAgICAgICA8YnV0dG9uIG1hdC1yYWlzZWQtYnV0dG9uIChjbGljayk9XCJvbkRlbGV0ZVJlcXVlc3QoKVwiIGNsYXNzPVwiYnRuXCI+UmVxdWVzdDwvYnV0dG9uPlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG5cbiAgICA8aDM+SW5jbHVkZSBSZWNvcmQgSUQgaW4gdGhlIFJlc3RQYXRoPC9oMz5cblxuICAgIDxkaXYgKm5nSWY9XCIoREVMRVRFX2Vycm9yJCB8IGFzeW5jKSBhcyBkZWxldGVfZXJyb3JcIiBzdHlsZT1cIm1hcmdpbi10b3A6IC41cmVtO1wiPlxuICAgICAgPG1hdC1lcnJvcj57eyBkZWxldGVfZXJyb3IgfX08L21hdC1lcnJvcj5cbiAgICA8L2Rpdj5cblxuICAgIDxkaXYgc3R5bGU9XCJtYXJnaW4tdG9wOiAxcmVtO1wiICpuZ0lmPVwiKERFTEVURSQgfCBhc3luYykgYXMgZGF0YVJlY29yZFwiPlxuICAgICAgPCEtLSA8ZGl2IFtpbm5lckhUTUxdPVwiKERFTEVURSQgfCBhc3luYykgfCBqc29udlwiPjwvZGl2PiAtLT5cbiAgICAgIHt7IGRhdGFSZWNvcmQgfCBqc29uIH19XG4gICAgPC9kaXY+XG5cbiAgPC9kaXY+XG5cbiAgPGRpdiBzdHlsZT1cIm1hcmdpbi10b3A6IDJyZW1cIj5cbiAgICA8bWF0LWRpdmlkZXI+PC9tYXQtZGl2aWRlcj5cbiAgPC9kaXY+XG5cbiAgPGRpdiBzdHlsZT1cIm1hcmdpbi10b3A6IDJyZW1cIj5cbiAgICA8ZGl2IHN0eWxlPVwiZGlzcGxheTogZmxleDtcIj5cbiAgICAgIDxoMiBzdHlsZT1cImZsZXg6MVwiPlN0cmVhbWluZyBHRVQgUmVxdWVzdDwvaDI+XG4gICAgICA8ZGl2PlxuICAgICAgICA8YnV0dG9uIG1hdC1yYWlzZWQtYnV0dG9uIChjbGljayk9XCJvblN0cmVhbVJlcXVlc3QoKVwiIGNsYXNzPVwiYnRuXCI+UmVxdWVzdDwvYnV0dG9uPlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG5cbiAgICA8IS0tIDxkaXYgKm5nSWY9XCIoU1RSRUFNX2Vycm9yJCB8IGFzeW5jKSBhcyBzdHJlYW1fZXJyb3JcIiBzdHlsZT1cIm1hcmdpbi10b3A6IC41cmVtO1wiPlxuICAgICAgPG1hdC1lcnJvcj57eyBzdHJlYW1fZXJyb3IgfX08L21hdC1lcnJvcj5cbiAgICA8L2Rpdj4gLS0+XG5cbiAgICA8ZGl2IHN0eWxlPVwibWFyZ2luLXRvcDogMXJlbTtcIj5cbiAgICAgIDxkaXYgKm5nSWY9XCIoU1RSRUFNJCB8IGFzeW5jKSBhcyBkYXRhXCIgY2xhc3M9XCJjb250YWluZXJcIj5cbiAgICAgICAgPHRhYmxlIG1hdC10YWJsZSBbZGF0YVNvdXJjZV09XCJkYXRhXCI+XG4gICAgICAgICAgPG5nLWNvbnRhaW5lciBtYXRDb2x1bW5EZWY9XCJpZFwiPlxuICAgICAgICAgICAgPHRoIG1hdC1oZWFkZXItY2VsbCAqbWF0SGVhZGVyQ2VsbERlZj4gSUQgPC90aD5cbiAgICAgICAgICAgIDx0ZCBtYXQtY2VsbCAqbWF0Q2VsbERlZj1cImxldCBlbGVtZW50XCI+IHt7ZWxlbWVudC5pZH19IDwvdGQ+XG4gICAgICAgICAgPC9uZy1jb250YWluZXI+XG5cbiAgICAgICAgICA8bmctY29udGFpbmVyIG1hdENvbHVtbkRlZj1cIm5hbWVcIj5cbiAgICAgICAgICAgIDx0aCBtYXQtaGVhZGVyLWNlbGwgKm1hdEhlYWRlckNlbGxEZWY+IEZpcnN0IE5hbWUgPC90aD5cbiAgICAgICAgICAgIDx0ZCBtYXQtY2VsbCAqbWF0Q2VsbERlZj1cImxldCBlbGVtZW50XCI+IHt7ZWxlbWVudC5uYW1lfX0gPC90ZD5cbiAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgICAgIDxuZy1jb250YWluZXIgbWF0Q29sdW1uRGVmPVwibGFzdE5hbWVcIj5cbiAgICAgICAgICAgIDx0aCBtYXQtaGVhZGVyLWNlbGwgKm1hdEhlYWRlckNlbGxEZWY+IExhc3QgTmFtZSA8L3RoPlxuICAgICAgICAgICAgPHRkIG1hdC1jZWxsICptYXRDZWxsRGVmPVwibGV0IGVsZW1lbnRcIj4ge3tlbGVtZW50Lmxhc3ROYW1lfX0gPC90ZD5cbiAgICAgICAgICA8L25nLWNvbnRhaW5lcj5cblxuICAgICAgICAgIDxuZy1jb250YWluZXIgbWF0Q29sdW1uRGVmPVwiYWdlXCI+XG4gICAgICAgICAgICA8dGggbWF0LWhlYWRlci1jZWxsICptYXRIZWFkZXJDZWxsRGVmPiBBZ2UgPC90aD5cbiAgICAgICAgICAgIDx0ZCBtYXQtY2VsbCAqbWF0Q2VsbERlZj1cImxldCBlbGVtZW50XCI+IHt7ZWxlbWVudC5hZ2V9fSA8L3RkPlxuICAgICAgICAgIDwvbmctY29udGFpbmVyPlxuXG4gICAgICAgICAgPHRyIG1hdC1oZWFkZXItcm93ICptYXRIZWFkZXJSb3dEZWY9XCJkaXNwbGF5ZWRDb2x1bW5zXCI+PC90cj5cbiAgICAgICAgICA8dHIgbWF0LXJvdyAqbWF0Um93RGVmPVwibGV0IHJvdzsgY29sdW1uczogZGlzcGxheWVkQ29sdW1ucztcIj48L3RyPlxuICAgICAgICA8L3RhYmxlPlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG5cbiAgPC9kaXY+XG5cbiAgPGRpdiBzdHlsZT1cIm1hcmdpbi10b3A6IDJyZW1cIj5cbiAgICA8bWF0LWRpdmlkZXI+PC9tYXQtZGl2aWRlcj5cbiAgPC9kaXY+XG5cbiAgPGRpdiBzdHlsZT1cIm1hcmdpbi10b3A6IDJyZW1cIj5cbiAgICA8ZGl2IHN0eWxlPVwiZGlzcGxheTogZmxleDtcIj5cbiAgICAgIDxoMiBzdHlsZT1cImZsZXg6MTsgcGFkZGluZy10b3A6IC41cmVtO1wiPkFJIC08c3BhbiAqbmdJZj1cIkFJVHlwZSA9PT0gMVwiPlNUUkVBTUlORzwvc3Bhbj4gUE9TVCBSZXF1ZXN0PC9oMj5cbiAgICAgIDxkaXYgc3R5bGU9XCJkaXNwbGF5OiBmbGV4OyBnYXA6IDFyZW07XCI+XG4gICAgICAgIDxidXR0b24gbWF0LXJhaXNlZC1idXR0b24gW21hdE1lbnVUcmlnZ2VyRm9yXT1cIm1lbnVcIiBzdHlsZT1cIm1pbi13aWR0aDogMTIwcHg7XCI+XG4gICAgICAgICAgPG1hdC1pY29uPmxhbjwvbWF0LWljb24+XG4gICAgICAgICAgICA8c3BhbiAqbmdJZj1cIkFJVHlwZSA9PT0gMDsgZWxzZSBMT0NBTFwiPlNlcnZlcjwvc3Bhbj5cbiAgICAgICAgICAgIDxuZy10ZW1wbGF0ZSAjTE9DQUw+XG4gICAgICAgICAgICAgIExvY2FsXG4gICAgICAgICAgICA8L25nLXRlbXBsYXRlPlxuICAgICAgICA8L2J1dHRvbj5cbiAgICAgICAgPG1hdC1tZW51ICNtZW51PVwibWF0TWVudVwiPlxuICAgICAgICAgIDxidXR0b24gbWF0LW1lbnUtaXRlbSAoY2xpY2spPVwib25TZWxlY3RBSVR5cGUoMClcIj5TZXJ2ZXI8L2J1dHRvbj5cbiAgICAgICAgICA8YnV0dG9uIG1hdC1tZW51LWl0ZW0gKGNsaWNrKT1cIm9uU2VsZWN0QUlUeXBlKDEpXCI+TG9jYWw8L2J1dHRvbj5cbiAgICAgICAgPC9tYXQtbWVudT5cbiAgICAgICAgPGRpdj5cbiAgICAgICAgICA8YnV0dG9uIG1hdC1yYWlzZWQtYnV0dG9uIChjbGljayk9XCJvblN0cmVhbVBvc3RSZXF1ZXN0KClcIiBjbGFzcz1cImJ0blwiPkFzayBNZTwvYnV0dG9uPlxuICAgICAgICA8L2Rpdj5cbiAgICAgIDwvZGl2PlxuICAgIDwvZGl2PlxuXG4gICAgPGRpdiBzdHlsZT1cImRpc3BsYXk6IGZsZXg7XCI+XG4gICAgICA8bWF0LWZvcm0tZmllbGQgYXBwZWFyYW5jZT1cIm91dGxpbmVcIiBzdHlsZT1cImZsZXg6MVwiPlxuICAgICAgICA8bWF0LWxhYmVsPkFzayBtZSBhIFF1ZXN0aW9uPC9tYXQtbGFiZWw+XG4gICAgICAgIDx0ZXh0YXJlYSBtYXRJbnB1dCBwbGFjZWhvbGRlcj1cIldoeSBpcyB0aGUgc2t5IGJsdWU/XCIgW2Zvcm1Db250cm9sXT1cInF1ZXN0aW9uQ29udHJvbFwiPjwvdGV4dGFyZWE+XG4gICAgICA8L21hdC1mb3JtLWZpZWxkPlxuICAgIDwvZGl2PlxuXG4gICAgPGRpdiAqbmdJZj1cIihTVFJFQU1fQUlfZXJyb3IkIHwgYXN5bmMpIGFzIHN0cmVhbV9lcnJvclwiIHN0eWxlPVwibWFyZ2luLXRvcDogLjVyZW07XCI+XG4gICAgICA8bWF0LWVycm9yPnt7IHN0cmVhbV9lcnJvciB9fTwvbWF0LWVycm9yPlxuICAgIDwvZGl2PlxuXG4gICAgPGRpdiAqbmdJZj1cIkFJVHlwZSA9PT0gMTsgZWxzZSBBTFRFUk5BVElWRVwiIHN0eWxlPVwiY29sb3I6IHJlZDtcIj5cbiAgICAgIFlvdSBtdXN0IGhhdmUgT2xsYW1hIGFjdGl2ZSBhbmQgdGhlICdwaGkzOmxhdGVzdCcgbW9kZWwgdG8gdXNlIHRoaXMgZmVhdHVyZS5cbiAgICA8L2Rpdj5cbiAgICA8bmctdGVtcGxhdGUgI0FMVEVSTkFUSVZFPlxuICAgICAgPHNwYW4gc3R5bGU9XCJjb2xvcjogZ3JheTtcIj5cbiAgICAgICAgRGVmaW5lIHRoZSBSZXN0UGF0aCB0byB0aGUgQVBJIGVuZHBvaW50IHRoYXQgd2lsbCBoYW5kbGUgdGhlIEFJIHJlcXVlc3QuXG4gICAgICAgIFVzZTogJ2FpL2NoYXQnIGZvciBzZXJ2ZXJcbiAgICAgIDwvc3Bhbj5cbiAgICA8L25nLXRlbXBsYXRlPlxuXG4gICAgPGRpdj5cbiAgICAgIDxkaXYgKm5nSWY9XCIoU1RSRUFNX0FJJCB8IGFzeW5jKSBhcyBkYXRhXCIgc3R5bGU9XCJtYXJnaW4tdG9wOiAxcmVtOyBmb250LXNpemU6IDEuMnJlbTsgYm9yZGVyLXJhZGl1czogMXJlbTsgYm9yZGVyOiBibGFjayAxcHggc29saWQ7IHBhZGRpbmc6IDJyZW07XCI+XG4gICAgICAgIDxwIHN0eWxlPVwibWFyZ2luLWJvdHRvbTogLjVyZW07IHdoaXRlLXNwYWNlOnByZS13cmFwOyBsaW5lLWhlaWdodDogMS42cmVtO1wiPnt7ZGF0YX19PC9wPlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG5cbiAgPC9kaXY+XG5cbiAgPGRpdiBzdHlsZT1cIm1hcmdpbi10b3A6IDEuNXJlbTsgbWFyZ2luLWJvdHRvbTogMXJlbTsgbGluZS1oZWlnaHQ6IDEuNXJlbTtcIj5cbiAgICA8bWF0LWRpdmlkZXI+PC9tYXQtZGl2aWRlcj5cbiAgPC9kaXY+XG5cbiAgPGRpdj5cbiAgICA8ZGl2IHN0eWxlPVwiZGlzcGxheTogZmxleDtcIj5cbiAgICAgIDxoMiBzdHlsZT1cImZsZXg6MTsgbWFyZ2luLWJvdHRvbTogMDsgcGFkZGluZy10b3A6IC41cmVtOyBkaXNwbGF5OiBmbGV4O1wiPlxuICAgICAgICA8ZGl2PlxuICAgICAgICAgIERvd25sb2FkIEZpbGVcbiAgICAgICAgPC9kaXY+XG4gICAgICAgIDxkaXYgc3R5bGU9XCJmbGV4OjE7IG1hcmdpbi1sZWZ0OiAxcmVtO1wiPlxuICAgICAgICAgIDxtYXQtc2xpZGUtdG9nZ2xlICNkaXNhYmxlPlxuICAgICAgICAgICAgPHNwYW4gKm5nSWY9XCJkaXNhYmxlLmNoZWNrZWQ7IGVsc2UgRElTQUJMRVwiPlxuICAgICAgICAgICAgICBFbmFibGVcbiAgICAgICAgICAgIDwvc3Bhbj5cbiAgICAgICAgICAgIDxuZy10ZW1wbGF0ZSAjRElTQUJMRT5EaXNhYmxlPC9uZy10ZW1wbGF0ZT5cbiAgICAgICAgICA8L21hdC1zbGlkZS10b2dnbGU+XG4gICAgICAgIDwvZGl2PlxuICAgICAgPC9oMj5cbiAgICAgIDxkaXY+XG4gICAgICAgIDxhcHAtZmlsZS1kb3dubG9hZGVyXG4gICAgICAgICAgW2Rpc2FibGVkXT1cImRpc2FibGUuY2hlY2tlZFwiXG4gICAgICAgICAgW2RlbGF5RXJyb3JdPVwiM1wiXG4gICAgICAgICAgW2FwaVJlcXVlc3RdPVwiZG93bmxvYWRSZXF1ZXN0XCJcbiAgICAgICAgICAoY29tcGxldGVkKT1cIm9uRG93bmxvYWRDb21wbGV0ZWQoKVwiXG4gICAgICAgICAgKGZhaWxlZCk9XCJvbkRvd25sb2FkRmFpbGVkKCRldmVudClcIlxuICAgICAgICA+PC9hcHAtZmlsZS1kb3dubG9hZGVyPlxuICAgICAgPC9kaXY+XG4gICAgPC9kaXY+XG4gIDwvZGl2PlxuXG48L2Rpdj5cbiJdfQ==