studiokit-scaffolding-js 7.0.12-next.1.4 → 7.0.12-next.2.2

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 (258) hide show
  1. package/lib/components/ActionList.js +170 -34
  2. package/lib/components/AlertDialog.js +133 -9
  3. package/lib/components/AlertWithIcon.js +92 -25
  4. package/lib/components/ConnectedModal.js +43 -13
  5. package/lib/components/Dropdowns/GroupsDropdown.js +69 -44
  6. package/lib/components/Dropdowns/ManagedNavDropdown.js +100 -67
  7. package/lib/components/Dropdowns/UserDropdown.js +111 -21
  8. package/lib/components/Dropdowns/index.js +27 -9
  9. package/lib/components/EntityOwnerList.js +52 -18
  10. package/lib/components/Error.js +106 -11
  11. package/lib/components/ErrorBoundary.js +134 -35
  12. package/lib/components/ErrorMessage.js +44 -9
  13. package/lib/components/Forms/DateField.js +61 -42
  14. package/lib/components/Forms/TimeField.js +81 -42
  15. package/lib/components/Forms/index.js +27 -4
  16. package/lib/components/Groups/CreateEditCopySaveButtons.js +114 -11
  17. package/lib/components/Groups/ExternalGroups/Attach.js +212 -148
  18. package/lib/components/Groups/ExternalGroups/Table.js +181 -45
  19. package/lib/components/Groups/GroupCreateOrEditCommonProps.js +5 -1
  20. package/lib/components/Groups/RosterSyncInfo.js +147 -20
  21. package/lib/components/HOC/AccessibleAppComponent.js +98 -73
  22. package/lib/components/HOC/ActivityRequiredComponent.js +92 -49
  23. package/lib/components/HOC/AsyncComponent.js +54 -39
  24. package/lib/components/HOC/AuthenticatedComponent.js +58 -38
  25. package/lib/components/HOC/CollectionComponent.js +170 -110
  26. package/lib/components/HOC/CollectionFirstItemComponent.js +51 -38
  27. package/lib/components/HOC/CollectionItemComponent.js +168 -106
  28. package/lib/components/HOC/ConnectedModalComponent.js +109 -80
  29. package/lib/components/HOC/DataDependentComponent.js +29 -21
  30. package/lib/components/HOC/EntityComponent.js +71 -57
  31. package/lib/components/HOC/FullscreenModalComponent.js +163 -123
  32. package/lib/components/HOC/GroupActivityRequiredComponent.js +45 -31
  33. package/lib/components/HOC/GuidComponent.js +29 -22
  34. package/lib/components/HOC/ModelContextDependencyVerifyComponent.js +41 -31
  35. package/lib/components/HOC/ModelErrorRedirectComponent.js +51 -47
  36. package/lib/components/HOC/SearchPersistorComponent.js +240 -166
  37. package/lib/components/HOC/UnauthenticatedComponent.js +37 -25
  38. package/lib/components/HOC/UserComponent.js +12 -7
  39. package/lib/components/Icons/IconAlphaList.js +33 -5
  40. package/lib/components/Icons/IconExternalUser.js +33 -5
  41. package/lib/components/Icons/IconImpersonation.js +33 -5
  42. package/lib/components/Icons/IconStopImpersonating.js +33 -5
  43. package/lib/components/Icons/IconTable.js +35 -7
  44. package/lib/components/Icons/IconTableDeleteCol.js +33 -5
  45. package/lib/components/Icons/IconTableDeleteRow.js +33 -5
  46. package/lib/components/Icons/IconTableInsertCol.js +33 -5
  47. package/lib/components/Icons/IconTableInsertRow.js +33 -5
  48. package/lib/components/Impersonation/Button.js +77 -13
  49. package/lib/components/Impersonation/Link.js +77 -13
  50. package/lib/components/Impersonation/UserDetail.js +66 -9
  51. package/lib/components/Loading.js +26 -4
  52. package/lib/components/LockDownBrowser/Check.js +194 -49
  53. package/lib/components/LockDownBrowser/ExitButton.js +26 -9
  54. package/lib/components/LockDownBrowser/Launch.js +70 -62
  55. package/lib/components/Lti/Confirm.js +152 -11
  56. package/lib/components/Lti/CreateNonLtiGroupAlertDialog.js +170 -33
  57. package/lib/components/Lti/Launch.js +105 -24
  58. package/lib/components/Lti/LaunchGroup.js +85 -13
  59. package/lib/components/ManageTable.js +309 -87
  60. package/lib/components/ManageTableNoDataComponent.js +42 -4
  61. package/lib/components/NewVersionAlert.js +82 -46
  62. package/lib/components/NotFound.js +86 -10
  63. package/lib/components/Notifications.js +185 -126
  64. package/lib/components/PaginationNextButton.js +33 -6
  65. package/lib/components/PaginationPreviousButton.js +33 -6
  66. package/lib/components/Quill/CustomToolbar.js +432 -218
  67. package/lib/components/Quill/Formats/Image.js +73 -63
  68. package/lib/components/Quill/Formats/List.js +45 -45
  69. package/lib/components/Quill/Formats/Video.js +28 -24
  70. package/lib/components/Quill/ImageDropModule.js +147 -117
  71. package/lib/components/Quill/ImageWarning.js +47 -9
  72. package/lib/components/Quill/ImageWithAltTextModal.js +425 -86
  73. package/lib/components/Quill/Specs/CustomImageSpec.js +42 -34
  74. package/lib/components/Quill/Specs/CustomVideoSpec.js +34 -28
  75. package/lib/components/Quill/TableModule/Blots/BaseTableBlot.js +98 -98
  76. package/lib/components/Quill/TableModule/Blots/TableBlot.js +52 -47
  77. package/lib/components/Quill/TableModule/Blots/TableBodyBlot.js +53 -48
  78. package/lib/components/Quill/TableModule/Blots/TableCellBlot.js +224 -221
  79. package/lib/components/Quill/TableModule/Blots/TableContainer.js +80 -83
  80. package/lib/components/Quill/TableModule/Blots/TableRowBlot.js +75 -70
  81. package/lib/components/Quill/TableModule/constants.js +45 -41
  82. package/lib/components/Quill/TableModule/index.js +362 -301
  83. package/lib/components/Quill/TableModule/utils.js +42 -38
  84. package/lib/components/Quill/accessibilityFix.js +234 -232
  85. package/lib/components/Quill/index.js +34 -28
  86. package/lib/components/RefreshIndicator/Bordered.js +47 -6
  87. package/lib/components/RefreshIndicator/Inline.js +47 -8
  88. package/lib/components/RefreshIndicator/index.js +263 -59
  89. package/lib/components/SearchControls.js +216 -11
  90. package/lib/components/SentryRoute.js +11 -6
  91. package/lib/components/Tables/RoleFilter.js +69 -32
  92. package/lib/components/Tables/TextFilter.js +62 -13
  93. package/lib/components/UserRoles/Add.js +199 -96
  94. package/lib/components/UserRoles/Context.js +11 -7
  95. package/lib/components/UserRoles/RoleCell.js +181 -72
  96. package/lib/components/UserRoles/Select.js +157 -17
  97. package/lib/components/UserRoles/Table.js +221 -80
  98. package/lib/components/UserRoles/index.js +534 -384
  99. package/lib/config/eslint/index.js +32 -28
  100. package/lib/config/eslint/lib/order.js +26 -27
  101. package/lib/config/eslint/lib/prettier.js +20 -18
  102. package/lib/config/eslint/lib/typescript.js +93 -112
  103. package/lib/config/eslint/react.js +24 -14
  104. package/lib/constants/baseActivity.js +30 -26
  105. package/lib/constants/baseRole.js +14 -10
  106. package/lib/constants/configuration.js +33 -29
  107. package/lib/constants/externalProviderType.js +10 -6
  108. package/lib/constants/fetchErrorData.js +15 -11
  109. package/lib/constants/index.js +137 -14
  110. package/lib/constants/lockDownBrowser.js +28 -24
  111. package/lib/constants/mockData.js +382 -297
  112. package/lib/constants/modelStatus.js +15 -11
  113. package/lib/constants/notificationType.js +12 -8
  114. package/lib/constants/operatingSystem.js +12 -8
  115. package/lib/constants/shard.js +11 -7
  116. package/lib/constants/table.js +21 -21
  117. package/lib/constants/tier.js +12 -8
  118. package/lib/constants/userRole.js +15 -5
  119. package/lib/endpointMappings.js +197 -181
  120. package/lib/hooks/useCollection.js +82 -62
  121. package/lib/hooks/useCollectionConfiguration.js +228 -83
  122. package/lib/hooks/useCollectionItem.js +154 -54
  123. package/lib/hooks/useGuid.js +20 -8
  124. package/lib/hooks/usePrevious.js +19 -13
  125. package/lib/index.js +157 -25
  126. package/lib/redux/actionCreator.js +50 -28
  127. package/lib/redux/actions/AuthAction.js +44 -31
  128. package/lib/redux/actions/ModalAction.js +10 -6
  129. package/lib/redux/actions/ModelAction.js +77 -39
  130. package/lib/redux/actions/NotificationAction.js +10 -6
  131. package/lib/redux/actions/SearchAction.js +9 -5
  132. package/lib/redux/actions/index.js +60 -7
  133. package/lib/redux/configureReducers.js +60 -49
  134. package/lib/redux/configureStore.js +83 -87
  135. package/lib/redux/helpers.js +6 -2
  136. package/lib/redux/reducers/authReducer.js +50 -43
  137. package/lib/redux/reducers/index.js +41 -13
  138. package/lib/redux/reducers/modalsReducer.js +47 -29
  139. package/lib/redux/reducers/modelsReducer.js +178 -173
  140. package/lib/redux/reducers/notificationsReducer.js +24 -18
  141. package/lib/redux/reducers/searchReducer.js +25 -19
  142. package/lib/redux/sagas/appInsightsSaga.js +22 -18
  143. package/lib/redux/sagas/authSaga.js +253 -218
  144. package/lib/redux/sagas/caliperSaga.js +159 -143
  145. package/lib/redux/sagas/clockOffsetSaga.js +34 -31
  146. package/lib/redux/sagas/configurationSaga.js +11 -7
  147. package/lib/redux/sagas/downtimeApiErrorSaga.js +20 -17
  148. package/lib/redux/sagas/errorSaga.js +27 -21
  149. package/lib/redux/sagas/googleAnalyticsSaga.js +28 -24
  150. package/lib/redux/sagas/identityProviderSaga.js +22 -18
  151. package/lib/redux/sagas/initialDataLoadSaga.js +37 -28
  152. package/lib/redux/sagas/lockDownBrowserErrorSaga.js +29 -20
  153. package/lib/redux/sagas/modelFetchSaga.js +355 -322
  154. package/lib/redux/sagas/noStoreSaga.js +61 -48
  155. package/lib/redux/sagas/postLoginDataSaga.js +45 -34
  156. package/lib/redux/sagas/postLoginRedirectSaga.js +27 -27
  157. package/lib/redux/sagas/rootSaga.js +82 -57
  158. package/lib/redux/sagas/sentrySaga.js +29 -25
  159. package/lib/redux/sagas/userIdSaga.js +16 -12
  160. package/lib/services/codeProviderService.js +25 -19
  161. package/lib/services/dateService.js +12 -7
  162. package/lib/services/documentService.js +17 -12
  163. package/lib/services/fetchService.js +129 -112
  164. package/lib/services/persistenceService.js +33 -29
  165. package/lib/services/ticketProviderService.js +29 -23
  166. package/lib/services/tokenPersistenceService.js +12 -8
  167. package/lib/services/windowService.js +18 -14
  168. package/lib/startup.js +132 -114
  169. package/lib/types/AppConfiguration.js +5 -1
  170. package/lib/types/Artifact.js +11 -7
  171. package/lib/types/BaseReduxState.js +5 -1
  172. package/lib/types/Client.js +5 -1
  173. package/lib/types/Collection.js +5 -1
  174. package/lib/types/Configuration.js +5 -1
  175. package/lib/types/DeepLinkingResponseRequest.js +5 -1
  176. package/lib/types/DeletableModel.js +5 -1
  177. package/lib/types/Event.js +5 -1
  178. package/lib/types/ExternalGroup.js +5 -1
  179. package/lib/types/ExternalProvider.js +5 -1
  180. package/lib/types/ExternalTerm.js +5 -1
  181. package/lib/types/Group.js +5 -1
  182. package/lib/types/IdentityProvider.js +5 -1
  183. package/lib/types/LtiLaunch.js +5 -1
  184. package/lib/types/NameOnlyEntity.js +5 -1
  185. package/lib/types/Notification.js +5 -1
  186. package/lib/types/OptionalRecord.js +5 -1
  187. package/lib/types/OwnerSchedule.js +5 -1
  188. package/lib/types/PropertyOfType.js +5 -1
  189. package/lib/types/Quill.js +5 -1
  190. package/lib/types/RoleDescription.js +5 -1
  191. package/lib/types/Search.js +5 -1
  192. package/lib/types/SimpleLocation.js +5 -1
  193. package/lib/types/UniTime.js +5 -1
  194. package/lib/types/User.js +5 -1
  195. package/lib/types/UserRole.js +5 -1
  196. package/lib/types/auth/AuthState.js +5 -1
  197. package/lib/types/auth/CasV1LoginRequestBody.js +5 -1
  198. package/lib/types/auth/ClientCredentials.js +5 -1
  199. package/lib/types/auth/CodeProviderService.js +5 -1
  200. package/lib/types/auth/LocalLoginRequestBody.js +5 -1
  201. package/lib/types/auth/TicketProviderService.js +5 -1
  202. package/lib/types/auth/TokenPersistenceService.js +5 -1
  203. package/lib/types/auth/index.js +82 -9
  204. package/lib/types/externals.d.js +2 -0
  205. package/lib/types/index.js +313 -30
  206. package/lib/types/net/EndpointConfig.js +5 -1
  207. package/lib/types/net/EndpointMapping.js +5 -1
  208. package/lib/types/net/EndpointMappings.js +5 -1
  209. package/lib/types/net/ErrorHandler.js +5 -1
  210. package/lib/types/net/FetchConfig.js +5 -1
  211. package/lib/types/net/FetchErrorData.js +10 -6
  212. package/lib/types/net/FetchResult.js +5 -1
  213. package/lib/types/net/HTTPMethod.js +5 -1
  214. package/lib/types/net/HTTPStatusCode.js +16 -12
  215. package/lib/types/net/Metadata.js +5 -1
  216. package/lib/types/net/Model.js +5 -1
  217. package/lib/types/net/ModelCollection.js +5 -1
  218. package/lib/types/net/ModelsState.js +5 -1
  219. package/lib/types/net/OAuthToken.js +5 -1
  220. package/lib/types/net/OAuthTokenOrNull.js +5 -1
  221. package/lib/types/net/TokenAccessFunction.js +5 -1
  222. package/lib/types/net/index.js +181 -18
  223. package/lib/utils/baseActivity.js +133 -123
  224. package/lib/utils/baseRole.js +37 -33
  225. package/lib/utils/collection.js +425 -298
  226. package/lib/utils/cookies.js +22 -19
  227. package/lib/utils/date.js +303 -279
  228. package/lib/utils/dom.js +176 -165
  229. package/lib/utils/domainIdentifier.js +9 -5
  230. package/lib/utils/entityUserRole.js +6 -2
  231. package/lib/utils/error.js +17 -15
  232. package/lib/utils/events.js +40 -31
  233. package/lib/utils/externalGroup.js +22 -18
  234. package/lib/utils/externalProviders.js +8 -4
  235. package/lib/utils/externalTerms.js +10 -3
  236. package/lib/utils/fetch.js +179 -180
  237. package/lib/utils/group.js +18 -7
  238. package/lib/utils/groupDates.js +37 -33
  239. package/lib/utils/groupRoles.js +25 -21
  240. package/lib/utils/lockDownBrowser.js +15 -11
  241. package/lib/utils/logger.js +26 -22
  242. package/lib/utils/lti.js +9 -4
  243. package/lib/utils/model.js +36 -41
  244. package/lib/utils/number.js +21 -18
  245. package/lib/utils/promise.js +28 -21
  246. package/lib/utils/quill.js +65 -62
  247. package/lib/utils/route.js +58 -55
  248. package/lib/utils/search.js +76 -80
  249. package/lib/utils/shard.js +37 -37
  250. package/lib/utils/sort.js +50 -42
  251. package/lib/utils/string.js +13 -8
  252. package/lib/utils/table.js +38 -33
  253. package/lib/utils/timezone.js +10 -6
  254. package/lib/utils/url.js +142 -142
  255. package/lib/utils/user.js +58 -55
  256. package/lib/utils/userAgent.js +10 -10
  257. package/lib/utils/userRole.js +57 -49
  258. package/package.json +17 -3
@@ -1,380 +1,413 @@
1
1
  "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.defaultErrorHandler = exports.defaultTokenAccessFunction = exports.takeMatchesTerminationAction = exports.matchesTerminationAction = exports.TRY_LIMIT = void 0;
4
- exports.setEndpointMappings = setEndpointMappings;
2
+
3
+ var _interopRequireDefault = require("@babel/runtime/helpers/interopRequireDefault");
4
+ Object.defineProperty(exports, "__esModule", {
5
+ value: true
6
+ });
7
+ exports.TRY_LIMIT = void 0;
8
+ exports.default = modelFetchSaga;
9
+ exports.matchesTerminationAction = exports.defaultTokenAccessFunction = exports.defaultErrorHandler = void 0;
5
10
  exports.modelFetch = modelFetch;
6
11
  exports.modelFetchLoop = modelFetchLoop;
7
12
  exports.modelFetchRecurring = modelFetchRecurring;
8
- exports.default = modelFetchSaga;
9
- const tslib_1 = require("tslib");
10
- const lodash_1 = require("lodash");
11
- const moment_timezone_1 = tslib_1.__importDefault(require("moment-timezone"));
12
- const effects_1 = require("redux-saga/effects");
13
- const fetchErrorData_1 = require("../../constants/fetchErrorData");
14
- const dateService_1 = require("../../services/dateService");
15
- const fetchService_1 = require("../../services/fetchService");
16
- const windowService_1 = require("../../services/windowService");
17
- const types_1 = require("../../types");
18
- const error_1 = require("../../utils/error");
19
- const fetch_1 = require("../../utils/fetch");
20
- const logger_1 = require("../../utils/logger");
21
- const actions_1 = require("../actions");
13
+ exports.setEndpointMappings = setEndpointMappings;
14
+ exports.takeMatchesTerminationAction = void 0;
15
+ var _lodash = require("lodash");
16
+ var _momentTimezone = _interopRequireDefault(require("moment-timezone"));
17
+ var _effects = require("redux-saga/effects");
18
+ var _fetchErrorData = require("../../constants/fetchErrorData");
19
+ var _dateService = require("../../services/dateService");
20
+ var _fetchService = require("../../services/fetchService");
21
+ var _windowService = require("../../services/windowService");
22
+ var _types = require("../../types");
23
+ var _error = require("../../utils/error");
24
+ var _fetch = require("../../utils/fetch");
25
+ var _logger = require("../../utils/logger");
26
+ var _actions = require("../actions");
22
27
  /** The total number of tries for `fetchData`, including the initial request. */
23
- exports.TRY_LIMIT = 5;
28
+ const TRY_LIMIT = exports.TRY_LIMIT = 5;
29
+
24
30
  //#region Helpers
25
- const matchesTerminationAction = (incomingAction, dataRequestAction) => incomingAction.type === actions_1.PERIODIC_MODEL_FETCH_TERMINATION_ACTION_TYPE.TERMINATE &&
26
- incomingAction.taskId === dataRequestAction.taskId;
31
+
32
+ const matchesTerminationAction = (incomingAction, dataRequestAction) => incomingAction.type === _actions.PERIODIC_MODEL_FETCH_TERMINATION_ACTION_TYPE.TERMINATE && incomingAction.taskId === dataRequestAction.taskId;
27
33
  exports.matchesTerminationAction = matchesTerminationAction;
28
- const takeMatchesTerminationAction = (dataRequestAction) => (incomingAction) => (0, exports.matchesTerminationAction)(incomingAction, dataRequestAction);
29
- exports.takeMatchesTerminationAction = takeMatchesTerminationAction;
34
+ const takeMatchesTerminationAction = dataRequestAction => incomingAction => matchesTerminationAction(incomingAction, dataRequestAction);
35
+
30
36
  /* istanbul ignore next */
31
37
  /* eslint-disable-next-line require-yield */
38
+ exports.takeMatchesTerminationAction = takeMatchesTerminationAction;
32
39
  const defaultTokenAccessFunction = function* () {
33
- return null;
40
+ return null;
34
41
  };
35
- exports.defaultTokenAccessFunction = defaultTokenAccessFunction;
42
+
36
43
  /* istanbul ignore next */
44
+ exports.defaultTokenAccessFunction = defaultTokenAccessFunction;
37
45
  const defaultErrorHandler = () => {
38
- return;
46
+ return;
39
47
  };
40
48
  exports.defaultErrorHandler = defaultErrorHandler;
41
- const getChildCollectionKeys = (endpointMapping) => Object.keys(endpointMapping).reduce((out, key) => {
42
- const value = endpointMapping[key];
43
- if (!value || !Object.prototype.hasOwnProperty.call(value, '_config')) {
44
- return out;
45
- }
46
- const em = value;
47
- if (!!em._config && !!em._config.isCollection) {
48
- out.push(key);
49
- }
49
+ const getChildCollectionKeys = endpointMapping => Object.keys(endpointMapping).reduce((out, key) => {
50
+ const value = endpointMapping[key];
51
+ if (!value || !Object.prototype.hasOwnProperty.call(value, '_config')) {
50
52
  return out;
53
+ }
54
+ const em = value;
55
+ if (!!em._config && !!em._config.isCollection) {
56
+ out.push(key);
57
+ }
58
+ return out;
51
59
  }, []);
52
60
  const convertCollections = (endpointMapping, prepareFetchResult, data) => {
53
- const { endpointConfig, fetchConfig, isCollectionItemCreate, isCollectionItemFetch } = prepareFetchResult;
54
- const childCollectionKeys = getChildCollectionKeys(endpointMapping);
55
- const hasChildCollections = childCollectionKeys.length > 0;
56
- // no collections, return as-is
57
- if (!endpointConfig.isCollection && !hasChildCollections) {
58
- return data;
59
- }
60
- // delete returns no data
61
- if (fetchConfig.method === 'DELETE') {
62
- return {};
63
- }
64
- // data is a collection item, convert any child collections in item response
65
- if (isCollectionItemFetch || isCollectionItemCreate) {
66
- return convertDataCollectionItem(data, childCollectionKeys, endpointMapping);
67
- }
68
- // data is a collection, convert collection response, and any child collections in each item
69
- return endpointConfig.isCollection
70
- ? convertDataToCollection(data, childCollectionKeys, endpointMapping)
71
- : convertDataCollectionItem(data, childCollectionKeys, endpointMapping);
61
+ const {
62
+ endpointConfig,
63
+ fetchConfig,
64
+ isCollectionItemCreate,
65
+ isCollectionItemFetch
66
+ } = prepareFetchResult;
67
+ const childCollectionKeys = getChildCollectionKeys(endpointMapping);
68
+ const hasChildCollections = childCollectionKeys.length > 0;
69
+ // no collections, return as-is
70
+ if (!endpointConfig.isCollection && !hasChildCollections) {
71
+ return data;
72
+ }
73
+ // delete returns no data
74
+ if (fetchConfig.method === 'DELETE') {
75
+ return {};
76
+ }
77
+ // data is a collection item, convert any child collections in item response
78
+ if (isCollectionItemFetch || isCollectionItemCreate) {
79
+ return convertDataCollectionItem(data, childCollectionKeys, endpointMapping);
80
+ }
81
+ // data is a collection, convert collection response, and any child collections in each item
82
+ return endpointConfig.isCollection ? convertDataToCollection(data, childCollectionKeys, endpointMapping) : convertDataCollectionItem(data, childCollectionKeys, endpointMapping);
72
83
  };
73
84
  const convertDataCollectionItem = (data, collectionKeys, endpointMapping) => {
74
- if ((0, lodash_1.isNil)(data)) {
75
- return data;
85
+ if ((0, _lodash.isNil)(data)) {
86
+ return data;
87
+ }
88
+ return Object.keys(data).reduce((out, key) => {
89
+ let value = data[key];
90
+ if (collectionKeys.includes(key)) {
91
+ const childEndpointMapping = endpointMapping[key];
92
+ const childCollectionKeys = getChildCollectionKeys(childEndpointMapping);
93
+ value = convertDataToCollection(value, childCollectionKeys, childEndpointMapping);
76
94
  }
77
- return Object.keys(data).reduce((out, key) => {
78
- let value = data[key];
79
- if (collectionKeys.includes(key)) {
80
- const childEndpointMapping = endpointMapping[key];
81
- const childCollectionKeys = getChildCollectionKeys(childEndpointMapping);
82
- value = convertDataToCollection(value, childCollectionKeys, childEndpointMapping);
83
- }
84
- out[key] = value;
85
- return out;
86
- }, {});
95
+ out[key] = value;
96
+ return out;
97
+ }, {});
87
98
  };
88
99
  const convertDataToCollection = (data, collectionKeys, endpointMapping) => {
89
- if ((0, lodash_1.isNil)(data)) {
90
- return data;
100
+ if ((0, _lodash.isNil)(data)) {
101
+ return data;
102
+ }
103
+ return Object.keys(data).reduce((out, key) => {
104
+ const value = convertDataCollectionItem(data[key], collectionKeys, endpointMapping);
105
+ /* istanbul ignore else */
106
+ if (value && value.id) {
107
+ out[value.id] = value;
91
108
  }
92
- return Object.keys(data).reduce((out, key) => {
93
- const value = convertDataCollectionItem(data[key], collectionKeys, endpointMapping);
94
- /* istanbul ignore else */
95
- if (value && value.id) {
96
- out[value.id] = value;
97
- }
98
- return out;
99
- }, {});
109
+ return out;
110
+ }, {});
100
111
  };
101
- /**
102
- * Using the `lastActivityDate` set in local storage by "studiokit-caliper-js",
103
- * determine if the user has been idle, e.g. has had no activity in the last 15 minutes.
112
+
113
+ /**
114
+ * Using the `lastActivityDate` set in local storage by "studiokit-caliper-js",
115
+ * determine if the user has been idle, e.g. has had no activity in the last 15 minutes.
104
116
  */
105
117
  function isUserIdle() {
106
- const lastActivityDateString = (0, dateService_1.getLastActivityDate)();
107
- if (!lastActivityDateString) {
108
- return false;
109
- }
110
- const lastActivityDateUtc = moment_timezone_1.default.utc(lastActivityDateString);
111
- const nowUtc = moment_timezone_1.default.utc();
112
- const idleMinutesThreshold = 1000 * 60 * 15; // 15 minutes
113
- return nowUtc.diff(lastActivityDateUtc) >= idleMinutesThreshold;
118
+ const lastActivityDateString = (0, _dateService.getLastActivityDate)();
119
+ if (!lastActivityDateString) {
120
+ return false;
121
+ }
122
+ const lastActivityDateUtc = _momentTimezone.default.utc(lastActivityDateString);
123
+ const nowUtc = _momentTimezone.default.utc();
124
+ const idleMinutesThreshold = 1000 * 60 * 15; // 15 minutes
125
+
126
+ return nowUtc.diff(lastActivityDateUtc) >= idleMinutesThreshold;
114
127
  }
128
+
115
129
  //#endregion Helpers
130
+
116
131
  //#region Local Variables
132
+
117
133
  let endpointMappings;
118
134
  let tokenAccessFunction;
119
135
  let errorHandler;
120
136
  let logger;
137
+
121
138
  //#endregion Local Variables
139
+
122
140
  /** Set the shared EndpointMappings variable, exposed for testability */
123
141
  function setEndpointMappings(endpointMappingsParam) {
124
- endpointMappings = endpointMappingsParam;
142
+ endpointMappings = endpointMappingsParam;
125
143
  }
126
- /**
127
- * Construct a request based on the provided dataRequestAction, make a request with a configurable retry,
128
- * and handle errors, logging and dispatching all steps.
129
- *
130
- * @param modelFetchRequestAction A model fetch request action with the request configuration
144
+
145
+ /**
146
+ * Construct a request based on the provided dataRequestAction, make a request with a configurable retry,
147
+ * and handle errors, logging and dispatching all steps.
148
+ *
149
+ * @param modelFetchRequestAction A model fetch request action with the request configuration
131
150
  */
132
151
  function* modelFetch(modelFetchRequestAction) {
133
- let prepareFetchResult = undefined;
152
+ let prepareFetchResult = undefined;
153
+ try {
154
+ prepareFetchResult = (0, _fetch.prepareFetch)(modelFetchRequestAction, endpointMappings);
155
+ } catch (error) {
156
+ // Note: `prepareFetch` already ensures that `error` is an actual `Error`
157
+ logger.error(error);
158
+ errorHandler(error, modelFetchRequestAction);
159
+ return;
160
+ }
161
+
162
+ // get prepared variables
163
+ const {
164
+ modelPath,
165
+ fetchConfig,
166
+ endpointMapping,
167
+ isCollectionItemCreate,
168
+ isCollectionItemDelete
169
+ } = prepareFetchResult;
170
+
171
+ // Configure retry
172
+ const tryLimit = modelFetchRequestAction.noRetry ? 1 : TRY_LIMIT;
173
+ let tryCount = 0;
174
+ let didFail = false;
175
+ let lastFetchResult;
176
+ let lastError;
177
+ let lastErrorData;
178
+ const fetchResultUndefinedErrorMessage = "'fetchResult' is undefined";
179
+ const fetchResultNotOkErrorMessage = "'fetchResult.ok' is false";
180
+
181
+ // Run retry loop
182
+ do {
183
+ didFail = false;
184
+ tryCount++;
185
+
186
+ // dispatch that the fetch request started, which updates `_metadata` and `guid`, if provided, at the target redux `modelPath`
187
+ yield (0, _effects.put)({
188
+ type: modelFetchRequestAction.noStore ? _actions.MODEL_FETCH_START_ACTION_TYPE.TRANSIENT_FETCH_START : _actions.MODEL_FETCH_START_ACTION_TYPE.FETCH_START,
189
+ modelPath,
190
+ guid: modelFetchRequestAction.guid
191
+ });
192
+ let fetchResult = undefined;
134
193
  try {
135
- prepareFetchResult = (0, fetch_1.prepareFetch)(modelFetchRequestAction, endpointMappings);
136
- }
137
- catch (error) {
138
- // Note: `prepareFetch` already ensures that `error` is an actual `Error`
139
- logger.error(error);
140
- errorHandler(error, modelFetchRequestAction);
141
- return;
142
- }
143
- // get prepared variables
144
- const { modelPath, fetchConfig, endpointMapping, isCollectionItemCreate, isCollectionItemDelete } = prepareFetchResult;
145
- // Configure retry
146
- const tryLimit = modelFetchRequestAction.noRetry ? 1 : exports.TRY_LIMIT;
147
- let tryCount = 0;
148
- let didFail = false;
149
- let lastFetchResult;
150
- let lastError;
151
- let lastErrorData;
152
- const fetchResultUndefinedErrorMessage = "'fetchResult' is undefined";
153
- const fetchResultNotOkErrorMessage = "'fetchResult.ok' is false";
154
- // Run retry loop
155
- do {
156
- didFail = false;
157
- tryCount++;
158
- // dispatch that the fetch request started, which updates `_metadata` and `guid`, if provided, at the target redux `modelPath`
159
- yield (0, effects_1.put)({
160
- type: modelFetchRequestAction.noStore
161
- ? actions_1.MODEL_FETCH_START_ACTION_TYPE.TRANSIENT_FETCH_START
162
- : actions_1.MODEL_FETCH_START_ACTION_TYPE.FETCH_START,
163
- modelPath,
164
- guid: modelFetchRequestAction.guid
194
+ // get the OAuth Token, if any, and call `fetch`
195
+ const oauthToken = yield (0, _effects.call)(tokenAccessFunction, modelFetchRequestAction.modelName);
196
+ if (oauthToken?.access_token) {
197
+ fetchConfig.headers = (0, _lodash.merge)({}, fetchConfig.headers, {
198
+ Authorization: `Bearer ${oauthToken.access_token}`
165
199
  });
166
- let fetchResult = undefined;
167
- try {
168
- // get the OAuth Token, if any, and call `fetch`
169
- const oauthToken = yield (0, effects_1.call)(tokenAccessFunction, modelFetchRequestAction.modelName);
170
- if (oauthToken === null || oauthToken === void 0 ? void 0 : oauthToken.access_token) {
171
- fetchConfig.headers = (0, lodash_1.merge)({}, fetchConfig.headers, {
172
- Authorization: `Bearer ${oauthToken.access_token}`
173
- });
174
- }
175
- fetchResult = yield (0, effects_1.call)(fetchService_1.sendFetch, fetchConfig);
176
- // store `fetchResult` for reference after the do-while loop
177
- lastFetchResult = fetchResult;
178
- // throw on unsuccessful result to short-circuit and trigger catch+retry
179
- if (!fetchResult)
180
- throw new Error(fetchResultUndefinedErrorMessage);
181
- if (!fetchResult.ok)
182
- throw new Error(fetchResultNotOkErrorMessage);
183
- // handle success
184
- const resultActionType = modelFetchRequestAction.noStore
185
- ? actions_1.MODEL_FETCH_RESULT_ACTION_TYPE.TRANSIENT_FETCH_RESULT_RECEIVED
186
- : actions_1.MODEL_FETCH_RESULT_ACTION_TYPE.FETCH_RESULT_RECEIVED;
187
- const data = convertCollections(endpointMapping, prepareFetchResult, fetchResult.data);
188
- // attach guid to result data if it is an object
189
- if (modelFetchRequestAction.guid && (0, lodash_1.isPlainObject)(data)) {
190
- data.guid = modelFetchRequestAction.guid;
191
- }
192
- // POST new collection item
193
- if (isCollectionItemCreate) {
194
- const modelPathLevels = modelPath.split('.');
195
- // remove guid
196
- modelPathLevels.pop();
197
- // add by new result's id
198
- yield (0, effects_1.put)({
199
- type: resultActionType,
200
- modelPath: `${modelPathLevels.join('.')}.${data.id}`,
201
- guid: modelFetchRequestAction.guid,
202
- replaceValue: modelFetchRequestAction.replaceValue,
203
- data
204
- });
205
- // remove temp item under guid key
206
- yield (0, effects_1.put)({
207
- type: actions_1.MODEL_REMOVE_KEY_ACTION_TYPE,
208
- modelPath: modelPath
209
- });
210
- }
211
- // DELETE collection item
212
- else if (isCollectionItemDelete) {
213
- yield (0, effects_1.put)({
214
- type: actions_1.MODEL_REMOVE_KEY_ACTION_TYPE,
215
- modelPath: modelPath
216
- });
217
- }
218
- else {
219
- yield (0, effects_1.put)({
220
- type: resultActionType,
221
- modelPath: modelPath,
222
- guid: modelFetchRequestAction.guid,
223
- replaceValue: modelFetchRequestAction.replaceValue,
224
- data
225
- });
226
- }
227
- }
228
- catch (caughtError) {
229
- // construct `Error` using `caughtError`
230
- const baseErrorMessage = `'modelFetch' failed for '${modelPath}'`;
231
- const error = (0, error_1.constructErrorFromCaughtError)(caughtError, 'ModelFetchError', baseErrorMessage);
232
- // create a default `errorData` object
233
- const isNetworkOnline = windowService_1.windowService.getIsOnline();
234
- let errorData = isNetworkOnline ? fetchErrorData_1.unknownErrorData : fetchErrorData_1.networkOfflineErrorData;
235
- // update `errorData` from the `fetchResult.data`
236
- // for when the fetch got a result, but it was an unsuccessful status
237
- if ((fetchResult === null || fetchResult === void 0 ? void 0 : fetchResult.data) && (0, fetch_1.isFetchErrorData)(fetchResult.data)) {
238
- errorData = fetchResult.data;
239
- // update the error's message to include info from the fetch result
240
- error.message = `${baseErrorMessage}.\n${fetchConfig.method || 'GET'} ${fetchConfig.path} failed.\n${errorData.title} (${errorData.status})`;
241
- if (errorData.detail) {
242
- error.message += `: ${errorData.detail}`;
243
- }
244
- }
245
- // track `errorData` and `error` for after the while-loop
246
- lastErrorData = errorData;
247
- lastError = error;
248
- // dispatch that this try failed
249
- yield (0, effects_1.put)({
250
- type: actions_1.MODEL_FETCH_ERROR_ACTION_TYPE.TRY_FETCH_FAILED,
251
- modelPath: modelPath,
252
- guid: modelFetchRequestAction.guid,
253
- errorData
254
- });
255
- // log to the console
256
- logger.error(error);
257
- didFail = true;
258
- // Do not retry if the response is between 400-500 (except 408: request timeout)
259
- if (errorData.status >= types_1.HTTP_STATUS_CODE.BAD_REQUEST &&
260
- errorData.status < types_1.HTTP_STATUS_CODE.INTERNAL_SERVER_ERROR &&
261
- errorData.status !== types_1.HTTP_STATUS_CODE.REQUEST_TIMEOUT) {
262
- tryCount = tryLimit;
263
- }
264
- // if there are tries remaining, perform an exponential backoff
265
- if (tryCount < tryLimit) {
266
- yield (0, effects_1.delay)(Math.pow(2, (tryCount - 1)) * 100); // 100, 200, 400, 800
267
- }
268
- }
269
- } while (tryCount < tryLimit && didFail);
270
- // if fetch failed completely after all retries
271
- if (tryCount === tryLimit && didFail) {
272
- // these will always exist
273
- const errorData = lastErrorData;
274
- const error = lastError;
275
- // dispatch that the fetch failed, which updates `_metadata` (and `guid`, if provided) at the target redux `modelPath`
276
- yield (0, effects_1.put)({
277
- type: modelFetchRequestAction.noStore
278
- ? actions_1.MODEL_FETCH_ERROR_ACTION_TYPE.TRANSIENT_FETCH_FAILED
279
- : actions_1.MODEL_FETCH_ERROR_ACTION_TYPE.FETCH_FAILED,
280
- modelPath: modelPath,
281
- guid: modelFetchRequestAction.guid,
282
- errorData
200
+ }
201
+ fetchResult = yield (0, _effects.call)(_fetchService.sendFetch, fetchConfig);
202
+ // store `fetchResult` for reference after the do-while loop
203
+ lastFetchResult = fetchResult;
204
+
205
+ // throw on unsuccessful result to short-circuit and trigger catch+retry
206
+ if (!fetchResult) throw new Error(fetchResultUndefinedErrorMessage);
207
+ if (!fetchResult.ok) throw new Error(fetchResultNotOkErrorMessage);
208
+
209
+ // handle success
210
+ const resultActionType = modelFetchRequestAction.noStore ? _actions.MODEL_FETCH_RESULT_ACTION_TYPE.TRANSIENT_FETCH_RESULT_RECEIVED : _actions.MODEL_FETCH_RESULT_ACTION_TYPE.FETCH_RESULT_RECEIVED;
211
+ const data = convertCollections(endpointMapping, prepareFetchResult, fetchResult.data);
212
+ // attach guid to result data if it is an object
213
+ if (modelFetchRequestAction.guid && (0, _lodash.isPlainObject)(data)) {
214
+ data.guid = modelFetchRequestAction.guid;
215
+ }
216
+
217
+ // POST new collection item
218
+ if (isCollectionItemCreate) {
219
+ const modelPathLevels = modelPath.split('.');
220
+ // remove guid
221
+ modelPathLevels.pop();
222
+ // add by new result's id
223
+ yield (0, _effects.put)({
224
+ type: resultActionType,
225
+ modelPath: `${modelPathLevels.join('.')}.${data.id}`,
226
+ guid: modelFetchRequestAction.guid,
227
+ replaceValue: modelFetchRequestAction.replaceValue,
228
+ data
229
+ });
230
+ // remove temp item under guid key
231
+ yield (0, _effects.put)({
232
+ type: _actions.MODEL_REMOVE_KEY_ACTION_TYPE,
233
+ modelPath: modelPath
234
+ });
235
+ }
236
+ // DELETE collection item
237
+ else if (isCollectionItemDelete) {
238
+ yield (0, _effects.put)({
239
+ type: _actions.MODEL_REMOVE_KEY_ACTION_TYPE,
240
+ modelPath: modelPath
283
241
  });
284
- // Send error to error handler, except for 401s
285
- if (errorData.status !== types_1.HTTP_STATUS_CODE.UNAUTHORIZED) {
286
- errorHandler(error, modelFetchRequestAction, fetchConfig, lastFetchResult, errorData);
242
+ } else {
243
+ yield (0, _effects.put)({
244
+ type: resultActionType,
245
+ modelPath: modelPath,
246
+ guid: modelFetchRequestAction.guid,
247
+ replaceValue: modelFetchRequestAction.replaceValue,
248
+ data
249
+ });
250
+ }
251
+ } catch (caughtError) {
252
+ // construct `Error` using `caughtError`
253
+ const baseErrorMessage = `'modelFetch' failed for '${modelPath}'`;
254
+ const error = (0, _error.constructErrorFromCaughtError)(caughtError, 'ModelFetchError', baseErrorMessage);
255
+ // create a default `errorData` object
256
+ const isNetworkOnline = _windowService.windowService.getIsOnline();
257
+ let errorData = isNetworkOnline ? _fetchErrorData.unknownErrorData : _fetchErrorData.networkOfflineErrorData;
258
+ // update `errorData` from the `fetchResult.data`
259
+ // for when the fetch got a result, but it was an unsuccessful status
260
+ if (fetchResult?.data && (0, _fetch.isFetchErrorData)(fetchResult.data)) {
261
+ errorData = fetchResult.data;
262
+ // update the error's message to include info from the fetch result
263
+ error.message = `${baseErrorMessage}.\n${fetchConfig.method || 'GET'} ${fetchConfig.path} failed.\n${errorData.title} (${errorData.status})`;
264
+ if (errorData.detail) {
265
+ error.message += `: ${errorData.detail}`;
287
266
  }
267
+ }
268
+
269
+ // track `errorData` and `error` for after the while-loop
270
+ lastErrorData = errorData;
271
+ lastError = error;
272
+
273
+ // dispatch that this try failed
274
+ yield (0, _effects.put)({
275
+ type: _actions.MODEL_FETCH_ERROR_ACTION_TYPE.TRY_FETCH_FAILED,
276
+ modelPath: modelPath,
277
+ guid: modelFetchRequestAction.guid,
278
+ errorData
279
+ });
280
+
281
+ // log to the console
282
+ logger.error(error);
283
+ didFail = true;
284
+
285
+ // Do not retry if the response is between 400-500 (except 408: request timeout)
286
+ if (errorData.status >= _types.HTTP_STATUS_CODE.BAD_REQUEST && errorData.status < _types.HTTP_STATUS_CODE.INTERNAL_SERVER_ERROR && errorData.status !== _types.HTTP_STATUS_CODE.REQUEST_TIMEOUT) {
287
+ tryCount = tryLimit;
288
+ }
289
+
290
+ // if there are tries remaining, perform an exponential backoff
291
+ if (tryCount < tryLimit) {
292
+ yield (0, _effects.delay)(2 ** (tryCount - 1) * 100); // 100, 200, 400, 800
293
+ }
294
+ }
295
+ } while (tryCount < tryLimit && didFail);
296
+
297
+ // if fetch failed completely after all retries
298
+ if (tryCount === tryLimit && didFail) {
299
+ // these will always exist
300
+ const errorData = lastErrorData;
301
+ const error = lastError;
302
+
303
+ // dispatch that the fetch failed, which updates `_metadata` (and `guid`, if provided) at the target redux `modelPath`
304
+ yield (0, _effects.put)({
305
+ type: modelFetchRequestAction.noStore ? _actions.MODEL_FETCH_ERROR_ACTION_TYPE.TRANSIENT_FETCH_FAILED : _actions.MODEL_FETCH_ERROR_ACTION_TYPE.FETCH_FAILED,
306
+ modelPath: modelPath,
307
+ guid: modelFetchRequestAction.guid,
308
+ errorData
309
+ });
310
+
311
+ // Send error to error handler, except for 401s
312
+ if (errorData.status !== _types.HTTP_STATUS_CODE.UNAUTHORIZED) {
313
+ errorHandler(error, modelFetchRequestAction, fetchConfig, lastFetchResult, errorData);
288
314
  }
315
+ }
289
316
  }
290
- /**
291
- * The loop saga that makes the request every {action.period} milliseconds until cancelled
292
- *
293
- * @param action An action with the request configuration
317
+
318
+ /**
319
+ * The loop saga that makes the request every {action.period} milliseconds until cancelled
320
+ *
321
+ * @param action An action with the request configuration
294
322
  */
295
323
  function* modelFetchLoop(action) {
296
- try {
297
- let hasFetched = false;
298
- do {
299
- // call the fetch if this is the first loop iteration,
300
- // or if the user is not idle
301
- if (!hasFetched || !isUserIdle()) {
302
- yield (0, effects_1.call)(modelFetch, action);
303
- hasFetched = true;
304
- }
305
- yield (0, effects_1.delay)(action.period);
306
- } while (true);
307
- }
308
- catch (caughtError) {
309
- const error = (0, error_1.constructErrorFromCaughtError)(caughtError, 'ModelFetchLoopError', 'modelFetchLoop failed');
310
- logger.error(error);
311
- // catch and log any unexpected errors not caught inside `fetchData`
312
- errorHandler(error, action);
313
- }
314
- finally {
315
- if (yield (0, effects_1.cancelled)()) {
316
- yield (0, effects_1.put)({
317
- type: actions_1.PERIODIC_MODEL_FETCH_TERMINATION_ACTION_TYPE.SUCCEEDED,
318
- taskId: action.taskId
319
- });
320
- }
324
+ try {
325
+ let hasFetched = false;
326
+ do {
327
+ // call the fetch if this is the first loop iteration,
328
+ // or if the user is not idle
329
+ if (!hasFetched || !isUserIdle()) {
330
+ yield (0, _effects.call)(modelFetch, action);
331
+ hasFetched = true;
332
+ }
333
+ yield (0, _effects.delay)(action.period);
334
+ } while (true);
335
+ } catch (caughtError) {
336
+ const error = (0, _error.constructErrorFromCaughtError)(caughtError, 'ModelFetchLoopError', 'modelFetchLoop failed');
337
+ logger.error(error);
338
+ // catch and log any unexpected errors not caught inside `fetchData`
339
+ errorHandler(error, action);
340
+ } finally {
341
+ if (yield (0, _effects.cancelled)()) {
342
+ yield (0, _effects.put)({
343
+ type: _actions.PERIODIC_MODEL_FETCH_TERMINATION_ACTION_TYPE.SUCCEEDED,
344
+ taskId: action.taskId
345
+ });
321
346
  }
347
+ }
322
348
  }
323
- /**
324
- * Call the fetchData saga every {action.period} milliseconds. This saga requires the 'period' and 'taskId' properties
325
- * on the action parameter.
326
- *
327
- * @param action An action with the request configuration
349
+
350
+ /**
351
+ * Call the fetchData saga every {action.period} milliseconds. This saga requires the 'period' and 'taskId' properties
352
+ * on the action parameter.
353
+ *
354
+ * @param action An action with the request configuration
328
355
  */
329
356
  function* modelFetchRecurring(action) {
330
- if (!action.period) {
331
- throw new Error("'period' is required");
332
- }
333
- if (!action.taskId) {
334
- throw new Error("'taskId' is required");
335
- }
336
- const bgSyncTask = yield (0, effects_1.fork)(modelFetchLoop, action);
337
- yield (0, effects_1.take)((0, exports.takeMatchesTerminationAction)(action));
338
- yield (0, effects_1.cancel)(bgSyncTask);
357
+ if (!action.period) {
358
+ throw new Error("'period' is required");
359
+ }
360
+ if (!action.taskId) {
361
+ throw new Error("'taskId' is required");
362
+ }
363
+ const bgSyncTask = yield (0, _effects.fork)(modelFetchLoop, action);
364
+ yield (0, _effects.take)(takeMatchesTerminationAction(action));
365
+ yield (0, _effects.cancel)(bgSyncTask);
339
366
  }
340
- /**
341
- * The main saga for fetching models. Must be initialized with an EndpointMappings object that can be fetched
342
- * and an API root to prepend to any partial URLs specified in the EndpointMappings object. A logger should normally be provided
343
- * as well.
344
- *
345
- * `EndpointMappings` object require a form as follows (with optional nested models):
346
- * ```
347
- * {
348
- * fryModel: {
349
- * path: '/api/Foo'
350
- * },
351
- * groupOfModels: {
352
- * leelaModel: {
353
- * path: '/api/Bar'
354
- * },
355
- * benderModel: {
356
- * path: '/api/Baz'
357
- * }
358
- * }
359
- * }
360
- * ```
361
- * `EndpointMapping` objects are referenced in the actions.DATA_REQUESTED action by path, i.e.
362
- * `{ type: actions.DATA_REQUESTED, { modelName: 'fryModel' } }`
363
- * -- or --
364
- * `{ type: actions.DATA_REQUESTED, { modelName: 'groupOfModels.leelaModel' } }`
365
- *
366
- * @export
367
- * @param endpointMappingsParam A mapping of API endpoints available in the application
368
- * @param apiRootParam A url to which partial URLs are appended (i.e.) 'https://myapp.com'
369
- * @param tokenAccessFunctionParam function that returns an optional OAuth token
370
- * @param errorHandlerParam A function that is called when any fetch exceptions occur
367
+
368
+ /**
369
+ * The main saga for fetching models. Must be initialized with an EndpointMappings object that can be fetched
370
+ * and an API root to prepend to any partial URLs specified in the EndpointMappings object. A logger should normally be provided
371
+ * as well.
372
+ *
373
+ * `EndpointMappings` object require a form as follows (with optional nested models):
374
+ * ```
375
+ * {
376
+ * fryModel: {
377
+ * path: '/api/Foo'
378
+ * },
379
+ * groupOfModels: {
380
+ * leelaModel: {
381
+ * path: '/api/Bar'
382
+ * },
383
+ * benderModel: {
384
+ * path: '/api/Baz'
385
+ * }
386
+ * }
387
+ * }
388
+ * ```
389
+ * `EndpointMapping` objects are referenced in the actions.DATA_REQUESTED action by path, i.e.
390
+ * `{ type: actions.DATA_REQUESTED, { modelName: 'fryModel' } }`
391
+ * -- or --
392
+ * `{ type: actions.DATA_REQUESTED, { modelName: 'groupOfModels.leelaModel' } }`
393
+ *
394
+ * @export
395
+ * @param endpointMappingsParam A mapping of API endpoints available in the application
396
+ * @param apiRootParam A url to which partial URLs are appended (i.e.) 'https://myapp.com'
397
+ * @param tokenAccessFunctionParam function that returns an optional OAuth token
398
+ * @param errorHandlerParam A function that is called when any fetch exceptions occur
371
399
  */
372
- function* modelFetchSaga(endpointMappingsParam, apiRootParam, tokenAccessFunctionParam = exports.defaultTokenAccessFunction, errorHandlerParam = exports.defaultErrorHandler) {
373
- (0, fetchService_1.setApiRoot)(apiRootParam);
400
+ function modelFetchSaga(endpointMappingsParam, apiRootParam) {
401
+ let tokenAccessFunctionParam = arguments.length > 2 && arguments[2] !== undefined ? arguments[2] : defaultTokenAccessFunction;
402
+ let errorHandlerParam = arguments.length > 3 && arguments[3] !== undefined ? arguments[3] : defaultErrorHandler;
403
+ return function* () {
404
+ (0, _fetchService.setApiRoot)(apiRootParam);
374
405
  setEndpointMappings(endpointMappingsParam);
375
406
  errorHandler = errorHandlerParam;
376
407
  tokenAccessFunction = tokenAccessFunctionParam;
377
- logger = (0, logger_1.getLogger)();
378
- yield (0, effects_1.takeEvery)(actions_1.MODEL_FETCH_REQUEST_ACTION_TYPE.FETCH_REQUEST, modelFetch);
379
- yield (0, effects_1.takeEvery)(actions_1.MODEL_FETCH_REQUEST_ACTION_TYPE.PERIODIC_FETCH_REQUEST, modelFetchRecurring);
408
+ logger = (0, _logger.getLogger)();
409
+ yield (0, _effects.takeEvery)(_actions.MODEL_FETCH_REQUEST_ACTION_TYPE.FETCH_REQUEST, modelFetch);
410
+ yield (0, _effects.takeEvery)(_actions.MODEL_FETCH_REQUEST_ACTION_TYPE.PERIODIC_FETCH_REQUEST, modelFetchRecurring);
411
+ }();
380
412
  }
413
+ //# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJuYW1lcyI6WyJfbG9kYXNoIiwicmVxdWlyZSIsIl9tb21lbnRUaW1lem9uZSIsIl9pbnRlcm9wUmVxdWlyZURlZmF1bHQiLCJfZWZmZWN0cyIsIl9mZXRjaEVycm9yRGF0YSIsIl9kYXRlU2VydmljZSIsIl9mZXRjaFNlcnZpY2UiLCJfd2luZG93U2VydmljZSIsIl90eXBlcyIsIl9lcnJvciIsIl9mZXRjaCIsIl9sb2dnZXIiLCJfYWN0aW9ucyIsIlRSWV9MSU1JVCIsImV4cG9ydHMiLCJtYXRjaGVzVGVybWluYXRpb25BY3Rpb24iLCJpbmNvbWluZ0FjdGlvbiIsImRhdGFSZXF1ZXN0QWN0aW9uIiwidHlwZSIsIlBFUklPRElDX01PREVMX0ZFVENIX1RFUk1JTkFUSU9OX0FDVElPTl9UWVBFIiwiVEVSTUlOQVRFIiwidGFza0lkIiwidGFrZU1hdGNoZXNUZXJtaW5hdGlvbkFjdGlvbiIsImRlZmF1bHRUb2tlbkFjY2Vzc0Z1bmN0aW9uIiwiZGVmYXVsdEVycm9ySGFuZGxlciIsImdldENoaWxkQ29sbGVjdGlvbktleXMiLCJlbmRwb2ludE1hcHBpbmciLCJPYmplY3QiLCJrZXlzIiwicmVkdWNlIiwib3V0Iiwia2V5IiwidmFsdWUiLCJwcm90b3R5cGUiLCJoYXNPd25Qcm9wZXJ0eSIsImNhbGwiLCJlbSIsIl9jb25maWciLCJpc0NvbGxlY3Rpb24iLCJwdXNoIiwiY29udmVydENvbGxlY3Rpb25zIiwicHJlcGFyZUZldGNoUmVzdWx0IiwiZGF0YSIsImVuZHBvaW50Q29uZmlnIiwiZmV0Y2hDb25maWciLCJpc0NvbGxlY3Rpb25JdGVtQ3JlYXRlIiwiaXNDb2xsZWN0aW9uSXRlbUZldGNoIiwiY2hpbGRDb2xsZWN0aW9uS2V5cyIsImhhc0NoaWxkQ29sbGVjdGlvbnMiLCJsZW5ndGgiLCJtZXRob2QiLCJjb252ZXJ0RGF0YUNvbGxlY3Rpb25JdGVtIiwiY29udmVydERhdGFUb0NvbGxlY3Rpb24iLCJjb2xsZWN0aW9uS2V5cyIsImlzTmlsIiwiaW5jbHVkZXMiLCJjaGlsZEVuZHBvaW50TWFwcGluZyIsImlkIiwiaXNVc2VySWRsZSIsImxhc3RBY3Rpdml0eURhdGVTdHJpbmciLCJnZXRMYXN0QWN0aXZpdHlEYXRlIiwibGFzdEFjdGl2aXR5RGF0ZVV0YyIsIm1vbWVudCIsInV0YyIsIm5vd1V0YyIsImlkbGVNaW51dGVzVGhyZXNob2xkIiwiZGlmZiIsImVuZHBvaW50TWFwcGluZ3MiLCJ0b2tlbkFjY2Vzc0Z1bmN0aW9uIiwiZXJyb3JIYW5kbGVyIiwibG9nZ2VyIiwic2V0RW5kcG9pbnRNYXBwaW5ncyIsImVuZHBvaW50TWFwcGluZ3NQYXJhbSIsIm1vZGVsRmV0Y2giLCJtb2RlbEZldGNoUmVxdWVzdEFjdGlvbiIsInVuZGVmaW5lZCIsInByZXBhcmVGZXRjaCIsImVycm9yIiwibW9kZWxQYXRoIiwiaXNDb2xsZWN0aW9uSXRlbURlbGV0ZSIsInRyeUxpbWl0Iiwibm9SZXRyeSIsInRyeUNvdW50IiwiZGlkRmFpbCIsImxhc3RGZXRjaFJlc3VsdCIsImxhc3RFcnJvciIsImxhc3RFcnJvckRhdGEiLCJmZXRjaFJlc3VsdFVuZGVmaW5lZEVycm9yTWVzc2FnZSIsImZldGNoUmVzdWx0Tm90T2tFcnJvck1lc3NhZ2UiLCJwdXQiLCJub1N0b3JlIiwiTU9ERUxfRkVUQ0hfU1RBUlRfQUNUSU9OX1RZUEUiLCJUUkFOU0lFTlRfRkVUQ0hfU1RBUlQiLCJGRVRDSF9TVEFSVCIsImd1aWQiLCJmZXRjaFJlc3VsdCIsIm9hdXRoVG9rZW4iLCJtb2RlbE5hbWUiLCJhY2Nlc3NfdG9rZW4iLCJoZWFkZXJzIiwibWVyZ2UiLCJBdXRob3JpemF0aW9uIiwic2VuZEZldGNoIiwiRXJyb3IiLCJvayIsInJlc3VsdEFjdGlvblR5cGUiLCJNT0RFTF9GRVRDSF9SRVNVTFRfQUNUSU9OX1RZUEUiLCJUUkFOU0lFTlRfRkVUQ0hfUkVTVUxUX1JFQ0VJVkVEIiwiRkVUQ0hfUkVTVUxUX1JFQ0VJVkVEIiwiaXNQbGFpbk9iamVjdCIsIm1vZGVsUGF0aExldmVscyIsInNwbGl0IiwicG9wIiwiam9pbiIsInJlcGxhY2VWYWx1ZSIsIk1PREVMX1JFTU9WRV9LRVlfQUNUSU9OX1RZUEUiLCJjYXVnaHRFcnJvciIsImJhc2VFcnJvck1lc3NhZ2UiLCJjb25zdHJ1Y3RFcnJvckZyb21DYXVnaHRFcnJvciIsImlzTmV0d29ya09ubGluZSIsIndpbmRvd1NlcnZpY2UiLCJnZXRJc09ubGluZSIsImVycm9yRGF0YSIsInVua25vd25FcnJvckRhdGEiLCJuZXR3b3JrT2ZmbGluZUVycm9yRGF0YSIsImlzRmV0Y2hFcnJvckRhdGEiLCJtZXNzYWdlIiwicGF0aCIsInRpdGxlIiwic3RhdHVzIiwiZGV0YWlsIiwiTU9ERUxfRkVUQ0hfRVJST1JfQUNUSU9OX1RZUEUiLCJUUllfRkVUQ0hfRkFJTEVEIiwiSFRUUF9TVEFUVVNfQ09ERSIsIkJBRF9SRVFVRVNUIiwiSU5URVJOQUxfU0VSVkVSX0VSUk9SIiwiUkVRVUVTVF9USU1FT1VUIiwiZGVsYXkiLCJUUkFOU0lFTlRfRkVUQ0hfRkFJTEVEIiwiRkVUQ0hfRkFJTEVEIiwiVU5BVVRIT1JJWkVEIiwibW9kZWxGZXRjaExvb3AiLCJhY3Rpb24iLCJoYXNGZXRjaGVkIiwicGVyaW9kIiwiY2FuY2VsbGVkIiwiU1VDQ0VFREVEIiwibW9kZWxGZXRjaFJlY3VycmluZyIsImJnU3luY1Rhc2siLCJmb3JrIiwidGFrZSIsImNhbmNlbCIsIm1vZGVsRmV0Y2hTYWdhIiwiYXBpUm9vdFBhcmFtIiwidG9rZW5BY2Nlc3NGdW5jdGlvblBhcmFtIiwiYXJndW1lbnRzIiwiZXJyb3JIYW5kbGVyUGFyYW0iLCJzZXRBcGlSb290IiwiZ2V0TG9nZ2VyIiwidGFrZUV2ZXJ5IiwiTU9ERUxfRkVUQ0hfUkVRVUVTVF9BQ1RJT05fVFlQRSIsIkZFVENIX1JFUVVFU1QiLCJQRVJJT0RJQ19GRVRDSF9SRVFVRVNUIl0sInNvdXJjZXMiOlsiLi4vLi4vLi4vc3JjL3JlZHV4L3NhZ2FzL21vZGVsRmV0Y2hTYWdhLnRzIl0sInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IFNhZ2FJdGVyYXRvciwgVGFzayB9IGZyb20gJ0ByZWR1eC1zYWdhL2NvcmUnXHJcbmltcG9ydCB7IGlzTmlsLCBpc1BsYWluT2JqZWN0LCBtZXJnZSB9IGZyb20gJ2xvZGFzaCdcclxuaW1wb3J0IG1vbWVudCBmcm9tICdtb21lbnQtdGltZXpvbmUnXHJcbmltcG9ydCB7IEFueUFjdGlvbiB9IGZyb20gJ3JlZHV4J1xyXG5pbXBvcnQgeyBjYWxsLCBjYW5jZWwsIGNhbmNlbGxlZCwgZGVsYXksIGZvcmssIHB1dCwgdGFrZSwgdGFrZUV2ZXJ5IH0gZnJvbSAncmVkdXgtc2FnYS9lZmZlY3RzJ1xyXG5pbXBvcnQgeyBuZXR3b3JrT2ZmbGluZUVycm9yRGF0YSwgdW5rbm93bkVycm9yRGF0YSB9IGZyb20gJy4uLy4uL2NvbnN0YW50cy9mZXRjaEVycm9yRGF0YSdcclxuaW1wb3J0IHsgZ2V0TGFzdEFjdGl2aXR5RGF0ZSB9IGZyb20gJy4uLy4uL3NlcnZpY2VzL2RhdGVTZXJ2aWNlJ1xyXG5pbXBvcnQgeyBzZW5kRmV0Y2gsIHNldEFwaVJvb3QgfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy9mZXRjaFNlcnZpY2UnXHJcbmltcG9ydCB7IHdpbmRvd1NlcnZpY2UgfSBmcm9tICcuLi8uLi9zZXJ2aWNlcy93aW5kb3dTZXJ2aWNlJ1xyXG5pbXBvcnQge1xyXG5cdEVuZHBvaW50TWFwcGluZyxcclxuXHRFbmRwb2ludE1hcHBpbmdzLFxyXG5cdEVycm9ySGFuZGxlcixcclxuXHRGZXRjaEVycm9yRGF0YSxcclxuXHRGZXRjaFJlc3VsdCxcclxuXHRIVFRQX1NUQVRVU19DT0RFLFxyXG5cdE1vZGVsLFxyXG5cdE1vZGVsQ29sbGVjdGlvbixcclxuXHRPQXV0aFRva2VuT3JOdWxsLFxyXG5cdFRva2VuQWNjZXNzRnVuY3Rpb25cclxufSBmcm9tICcuLi8uLi90eXBlcydcclxuaW1wb3J0IHsgY29uc3RydWN0RXJyb3JGcm9tQ2F1Z2h0RXJyb3IgfSBmcm9tICcuLi8uLi91dGlscy9lcnJvcidcclxuaW1wb3J0IHsgaXNGZXRjaEVycm9yRGF0YSwgcHJlcGFyZUZldGNoLCBQcmVwYXJlRmV0Y2hSZXN1bHQgfSBmcm9tICcuLi8uLi91dGlscy9mZXRjaCdcclxuaW1wb3J0IHsgZ2V0TG9nZ2VyLCBMb2dnZXIgfSBmcm9tICcuLi8uLi91dGlscy9sb2dnZXInXHJcbmltcG9ydCB7XHJcblx0TU9ERUxfRkVUQ0hfRVJST1JfQUNUSU9OX1RZUEUsXHJcblx0TU9ERUxfRkVUQ0hfUkVRVUVTVF9BQ1RJT05fVFlQRSxcclxuXHRNT0RFTF9GRVRDSF9SRVNVTFRfQUNUSU9OX1RZUEUsXHJcblx0TU9ERUxfRkVUQ0hfU1RBUlRfQUNUSU9OX1RZUEUsXHJcblx0TU9ERUxfUkVNT1ZFX0tFWV9BQ1RJT05fVFlQRSxcclxuXHRNb2RlbEZldGNoRXJyb3JBY3Rpb24sXHJcblx0TW9kZWxGZXRjaFJlcXVlc3RBY3Rpb24sXHJcblx0TW9kZWxGZXRjaFJlc3VsdEFjdGlvbixcclxuXHRNb2RlbEZldGNoU3RhcnRBY3Rpb24sXHJcblx0TW9kZWxSZW1vdmVLZXlBY3Rpb24sXHJcblx0UEVSSU9ESUNfTU9ERUxfRkVUQ0hfVEVSTUlOQVRJT05fQUNUSU9OX1RZUEUsXHJcblx0UGVyaW9kaWNNb2RlbEZldGNoUmVxdWVzdEFjdGlvbixcclxuXHRQZXJpb2RpY01vZGVsRmV0Y2hUZXJtaW5hdGlvbkFjdGlvblxyXG59IGZyb20gJy4uL2FjdGlvbnMnXHJcblxyXG4vKiogVGhlIHRvdGFsIG51bWJlciBvZiB0cmllcyBmb3IgYGZldGNoRGF0YWAsIGluY2x1ZGluZyB0aGUgaW5pdGlhbCByZXF1ZXN0LiAqL1xyXG5leHBvcnQgY29uc3QgVFJZX0xJTUlUID0gNVxyXG5cclxuLy8jcmVnaW9uIEhlbHBlcnNcclxuXHJcbmV4cG9ydCBjb25zdCBtYXRjaGVzVGVybWluYXRpb25BY3Rpb24gPSAoXHJcblx0aW5jb21pbmdBY3Rpb246IEFueUFjdGlvbixcclxuXHRkYXRhUmVxdWVzdEFjdGlvbjogUGVyaW9kaWNNb2RlbEZldGNoUmVxdWVzdEFjdGlvblxyXG4pID0+XHJcblx0aW5jb21pbmdBY3Rpb24udHlwZSA9PT0gUEVSSU9ESUNfTU9ERUxfRkVUQ0hfVEVSTUlOQVRJT05fQUNUSU9OX1RZUEUuVEVSTUlOQVRFICYmXHJcblx0aW5jb21pbmdBY3Rpb24udGFza0lkID09PSBkYXRhUmVxdWVzdEFjdGlvbi50YXNrSWRcclxuXHJcbmV4cG9ydCBjb25zdCB0YWtlTWF0Y2hlc1Rlcm1pbmF0aW9uQWN0aW9uID1cclxuXHQoZGF0YVJlcXVlc3RBY3Rpb246IFBlcmlvZGljTW9kZWxGZXRjaFJlcXVlc3RBY3Rpb24pID0+IChpbmNvbWluZ0FjdGlvbjogQW55QWN0aW9uKSA9PlxyXG5cdFx0bWF0Y2hlc1Rlcm1pbmF0aW9uQWN0aW9uKGluY29taW5nQWN0aW9uLCBkYXRhUmVxdWVzdEFjdGlvbilcclxuXHJcbi8qIGlzdGFuYnVsIGlnbm9yZSBuZXh0ICovXHJcbi8qIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSByZXF1aXJlLXlpZWxkICovXHJcbmV4cG9ydCBjb25zdCBkZWZhdWx0VG9rZW5BY2Nlc3NGdW5jdGlvbjogVG9rZW5BY2Nlc3NGdW5jdGlvbiA9IGZ1bmN0aW9uKiAoKSB7XHJcblx0cmV0dXJuIG51bGxcclxufVxyXG5cclxuLyogaXN0YW5idWwgaWdub3JlIG5leHQgKi9cclxuZXhwb3J0IGNvbnN0IGRlZmF1bHRFcnJvckhhbmRsZXI6IEVycm9ySGFuZGxlciA9ICgpID0+IHtcclxuXHRyZXR1cm5cclxufVxyXG5cclxuaW50ZXJmYWNlIEdlbmVyaWNNb2RlbCBleHRlbmRzIE1vZGVsLCBSZWNvcmQ8c3RyaW5nLCBhbnk+IHt9XHJcblxyXG5jb25zdCBnZXRDaGlsZENvbGxlY3Rpb25LZXlzID0gKGVuZHBvaW50TWFwcGluZzogRW5kcG9pbnRNYXBwaW5nKSA9PlxyXG5cdE9iamVjdC5rZXlzKGVuZHBvaW50TWFwcGluZykucmVkdWNlKChvdXQ6IHN0cmluZ1tdLCBrZXkpID0+IHtcclxuXHRcdGNvbnN0IHZhbHVlID0gZW5kcG9pbnRNYXBwaW5nW2tleV1cclxuXHRcdGlmICghdmFsdWUgfHwgIU9iamVjdC5wcm90b3R5cGUuaGFzT3duUHJvcGVydHkuY2FsbCh2YWx1ZSwgJ19jb25maWcnKSkge1xyXG5cdFx0XHRyZXR1cm4gb3V0XHJcblx0XHR9XHJcblx0XHRjb25zdCBlbSA9IHZhbHVlIGFzIEVuZHBvaW50TWFwcGluZ1xyXG5cdFx0aWYgKCEhZW0uX2NvbmZpZyAmJiAhIWVtLl9jb25maWcuaXNDb2xsZWN0aW9uKSB7XHJcblx0XHRcdG91dC5wdXNoKGtleSlcclxuXHRcdH1cclxuXHRcdHJldHVybiBvdXRcclxuXHR9LCBbXSlcclxuXHJcbmNvbnN0IGNvbnZlcnRDb2xsZWN0aW9ucyA9IChlbmRwb2ludE1hcHBpbmc6IEVuZHBvaW50TWFwcGluZywgcHJlcGFyZUZldGNoUmVzdWx0OiBQcmVwYXJlRmV0Y2hSZXN1bHQsIGRhdGE6IGFueSkgPT4ge1xyXG5cdGNvbnN0IHsgZW5kcG9pbnRDb25maWcsIGZldGNoQ29uZmlnLCBpc0NvbGxlY3Rpb25JdGVtQ3JlYXRlLCBpc0NvbGxlY3Rpb25JdGVtRmV0Y2ggfSA9IHByZXBhcmVGZXRjaFJlc3VsdFxyXG5cdGNvbnN0IGNoaWxkQ29sbGVjdGlvbktleXMgPSBnZXRDaGlsZENvbGxlY3Rpb25LZXlzKGVuZHBvaW50TWFwcGluZylcclxuXHRjb25zdCBoYXNDaGlsZENvbGxlY3Rpb25zID0gY2hpbGRDb2xsZWN0aW9uS2V5cy5sZW5ndGggPiAwXHJcblx0Ly8gbm8gY29sbGVjdGlvbnMsIHJldHVybiBhcy1pc1xyXG5cdGlmICghZW5kcG9pbnRDb25maWcuaXNDb2xsZWN0aW9uICYmICFoYXNDaGlsZENvbGxlY3Rpb25zKSB7XHJcblx0XHRyZXR1cm4gZGF0YVxyXG5cdH1cclxuXHQvLyBkZWxldGUgcmV0dXJucyBubyBkYXRhXHJcblx0aWYgKGZldGNoQ29uZmlnLm1ldGhvZCA9PT0gJ0RFTEVURScpIHtcclxuXHRcdHJldHVybiB7fVxyXG5cdH1cclxuXHQvLyBkYXRhIGlzIGEgY29sbGVjdGlvbiBpdGVtLCBjb252ZXJ0IGFueSBjaGlsZCBjb2xsZWN0aW9ucyBpbiBpdGVtIHJlc3BvbnNlXHJcblx0aWYgKGlzQ29sbGVjdGlvbkl0ZW1GZXRjaCB8fCBpc0NvbGxlY3Rpb25JdGVtQ3JlYXRlKSB7XHJcblx0XHRyZXR1cm4gY29udmVydERhdGFDb2xsZWN0aW9uSXRlbShkYXRhLCBjaGlsZENvbGxlY3Rpb25LZXlzLCBlbmRwb2ludE1hcHBpbmcpXHJcblx0fVxyXG5cdC8vIGRhdGEgaXMgYSBjb2xsZWN0aW9uLCBjb252ZXJ0IGNvbGxlY3Rpb24gcmVzcG9uc2UsIGFuZCBhbnkgY2hpbGQgY29sbGVjdGlvbnMgaW4gZWFjaCBpdGVtXHJcblx0cmV0dXJuIGVuZHBvaW50Q29uZmlnLmlzQ29sbGVjdGlvblxyXG5cdFx0PyBjb252ZXJ0RGF0YVRvQ29sbGVjdGlvbihkYXRhLCBjaGlsZENvbGxlY3Rpb25LZXlzLCBlbmRwb2ludE1hcHBpbmcpXHJcblx0XHQ6IGNvbnZlcnREYXRhQ29sbGVjdGlvbkl0ZW0oZGF0YSwgY2hpbGRDb2xsZWN0aW9uS2V5cywgZW5kcG9pbnRNYXBwaW5nKVxyXG59XHJcblxyXG5jb25zdCBjb252ZXJ0RGF0YUNvbGxlY3Rpb25JdGVtID0gKGRhdGE6IGFueSwgY29sbGVjdGlvbktleXM6IHN0cmluZ1tdLCBlbmRwb2ludE1hcHBpbmc6IEVuZHBvaW50TWFwcGluZykgPT4ge1xyXG5cdGlmIChpc05pbChkYXRhKSkge1xyXG5cdFx0cmV0dXJuIGRhdGFcclxuXHR9XHJcblx0cmV0dXJuIE9iamVjdC5rZXlzKGRhdGEpLnJlZHVjZSgob3V0OiBHZW5lcmljTW9kZWwsIGtleSkgPT4ge1xyXG5cdFx0bGV0IHZhbHVlID0gZGF0YVtrZXldXHJcblx0XHRpZiAoY29sbGVjdGlvbktleXMuaW5jbHVkZXMoa2V5KSkge1xyXG5cdFx0XHRjb25zdCBjaGlsZEVuZHBvaW50TWFwcGluZyA9IGVuZHBvaW50TWFwcGluZ1trZXldIGFzIEVuZHBvaW50TWFwcGluZ1xyXG5cdFx0XHRjb25zdCBjaGlsZENvbGxlY3Rpb25LZXlzID0gZ2V0Q2hpbGRDb2xsZWN0aW9uS2V5cyhjaGlsZEVuZHBvaW50TWFwcGluZylcclxuXHRcdFx0dmFsdWUgPSBjb252ZXJ0RGF0YVRvQ29sbGVjdGlvbih2YWx1ZSwgY2hpbGRDb2xsZWN0aW9uS2V5cywgY2hpbGRFbmRwb2ludE1hcHBpbmcpXHJcblx0XHR9XHJcblx0XHRvdXRba2V5XSA9IHZhbHVlXHJcblx0XHRyZXR1cm4gb3V0XHJcblx0fSwge30pXHJcbn1cclxuXHJcbmNvbnN0IGNvbnZlcnREYXRhVG9Db2xsZWN0aW9uID0gKGRhdGE6IGFueSwgY29sbGVjdGlvbktleXM6IHN0cmluZ1tdLCBlbmRwb2ludE1hcHBpbmc6IEVuZHBvaW50TWFwcGluZykgPT4ge1xyXG5cdGlmIChpc05pbChkYXRhKSkge1xyXG5cdFx0cmV0dXJuIGRhdGFcclxuXHR9XHJcblx0cmV0dXJuIE9iamVjdC5rZXlzKGRhdGEpLnJlZHVjZSgob3V0OiBNb2RlbENvbGxlY3Rpb248YW55Piwga2V5KSA9PiB7XHJcblx0XHRjb25zdCB2YWx1ZSA9IGNvbnZlcnREYXRhQ29sbGVjdGlvbkl0ZW0oZGF0YVtrZXldLCBjb2xsZWN0aW9uS2V5cywgZW5kcG9pbnRNYXBwaW5nKVxyXG5cdFx0LyogaXN0YW5idWwgaWdub3JlIGVsc2UgKi9cclxuXHRcdGlmICh2YWx1ZSAmJiB2YWx1ZS5pZCkge1xyXG5cdFx0XHRvdXRbdmFsdWUuaWRdID0gdmFsdWVcclxuXHRcdH1cclxuXHRcdHJldHVybiBvdXRcclxuXHR9LCB7fSlcclxufVxyXG5cclxuLyoqXHJcbiAqIFVzaW5nIHRoZSBgbGFzdEFjdGl2aXR5RGF0ZWAgc2V0IGluIGxvY2FsIHN0b3JhZ2UgYnkgXCJzdHVkaW9raXQtY2FsaXBlci1qc1wiLFxyXG4gKiBkZXRlcm1pbmUgaWYgdGhlIHVzZXIgaGFzIGJlZW4gaWRsZSwgZS5nLiBoYXMgaGFkIG5vIGFjdGl2aXR5IGluIHRoZSBsYXN0IDE1IG1pbnV0ZXMuXHJcbiAqL1xyXG5mdW5jdGlvbiBpc1VzZXJJZGxlKCkge1xyXG5cdGNvbnN0IGxhc3RBY3Rpdml0eURhdGVTdHJpbmcgPSBnZXRMYXN0QWN0aXZpdHlEYXRlKClcclxuXHRpZiAoIWxhc3RBY3Rpdml0eURhdGVTdHJpbmcpIHtcclxuXHRcdHJldHVybiBmYWxzZVxyXG5cdH1cclxuXHJcblx0Y29uc3QgbGFzdEFjdGl2aXR5RGF0ZVV0YyA9IG1vbWVudC51dGMobGFzdEFjdGl2aXR5RGF0ZVN0cmluZylcclxuXHRjb25zdCBub3dVdGMgPSBtb21lbnQudXRjKClcclxuXHRjb25zdCBpZGxlTWludXRlc1RocmVzaG9sZCA9IDEwMDAgKiA2MCAqIDE1IC8vIDE1IG1pbnV0ZXNcclxuXHJcblx0cmV0dXJuIG5vd1V0Yy5kaWZmKGxhc3RBY3Rpdml0eURhdGVVdGMpID49IGlkbGVNaW51dGVzVGhyZXNob2xkXHJcbn1cclxuXHJcbi8vI2VuZHJlZ2lvbiBIZWxwZXJzXHJcblxyXG4vLyNyZWdpb24gTG9jYWwgVmFyaWFibGVzXHJcblxyXG5sZXQgZW5kcG9pbnRNYXBwaW5nczogRW5kcG9pbnRNYXBwaW5nc1xyXG5sZXQgdG9rZW5BY2Nlc3NGdW5jdGlvbjogVG9rZW5BY2Nlc3NGdW5jdGlvblxyXG5sZXQgZXJyb3JIYW5kbGVyOiBFcnJvckhhbmRsZXJcclxubGV0IGxvZ2dlcjogTG9nZ2VyXHJcblxyXG4vLyNlbmRyZWdpb24gTG9jYWwgVmFyaWFibGVzXHJcblxyXG4vKiogU2V0IHRoZSBzaGFyZWQgRW5kcG9pbnRNYXBwaW5ncyB2YXJpYWJsZSwgZXhwb3NlZCBmb3IgdGVzdGFiaWxpdHkgKi9cclxuZXhwb3J0IGZ1bmN0aW9uIHNldEVuZHBvaW50TWFwcGluZ3MoZW5kcG9pbnRNYXBwaW5nc1BhcmFtOiBFbmRwb2ludE1hcHBpbmdzKSB7XHJcblx0ZW5kcG9pbnRNYXBwaW5ncyA9IGVuZHBvaW50TWFwcGluZ3NQYXJhbVxyXG59XHJcblxyXG4vKipcclxuICogQ29uc3RydWN0IGEgcmVxdWVzdCBiYXNlZCBvbiB0aGUgcHJvdmlkZWQgZGF0YVJlcXVlc3RBY3Rpb24sIG1ha2UgYSByZXF1ZXN0IHdpdGggYSBjb25maWd1cmFibGUgcmV0cnksXHJcbiAqIGFuZCBoYW5kbGUgZXJyb3JzLCBsb2dnaW5nIGFuZCBkaXNwYXRjaGluZyBhbGwgc3RlcHMuXHJcbiAqXHJcbiAqIEBwYXJhbSBtb2RlbEZldGNoUmVxdWVzdEFjdGlvbiBBIG1vZGVsIGZldGNoIHJlcXVlc3QgYWN0aW9uIHdpdGggdGhlIHJlcXVlc3QgY29uZmlndXJhdGlvblxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uKiBtb2RlbEZldGNoKFxyXG5cdG1vZGVsRmV0Y2hSZXF1ZXN0QWN0aW9uOiBNb2RlbEZldGNoUmVxdWVzdEFjdGlvbiB8IFBlcmlvZGljTW9kZWxGZXRjaFJlcXVlc3RBY3Rpb25cclxuKTogU2FnYUl0ZXJhdG9yIHtcclxuXHRsZXQgcHJlcGFyZUZldGNoUmVzdWx0OiBQcmVwYXJlRmV0Y2hSZXN1bHQgfCB1bmRlZmluZWQgPSB1bmRlZmluZWRcclxuXHR0cnkge1xyXG5cdFx0cHJlcGFyZUZldGNoUmVzdWx0ID0gcHJlcGFyZUZldGNoKG1vZGVsRmV0Y2hSZXF1ZXN0QWN0aW9uLCBlbmRwb2ludE1hcHBpbmdzKVxyXG5cdH0gY2F0Y2ggKGVycm9yKSB7XHJcblx0XHQvLyBOb3RlOiBgcHJlcGFyZUZldGNoYCBhbHJlYWR5IGVuc3VyZXMgdGhhdCBgZXJyb3JgIGlzIGFuIGFjdHVhbCBgRXJyb3JgXHJcblx0XHRsb2dnZXIuZXJyb3IoZXJyb3IpXHJcblx0XHRlcnJvckhhbmRsZXIoZXJyb3IgYXMgRXJyb3IsIG1vZGVsRmV0Y2hSZXF1ZXN0QWN0aW9uKVxyXG5cdFx0cmV0dXJuXHJcblx0fVxyXG5cclxuXHQvLyBnZXQgcHJlcGFyZWQgdmFyaWFibGVzXHJcblx0Y29uc3QgeyBtb2RlbFBhdGgsIGZldGNoQ29uZmlnLCBlbmRwb2ludE1hcHBpbmcsIGlzQ29sbGVjdGlvbkl0ZW1DcmVhdGUsIGlzQ29sbGVjdGlvbkl0ZW1EZWxldGUgfSA9XHJcblx0XHRwcmVwYXJlRmV0Y2hSZXN1bHRcclxuXHJcblx0Ly8gQ29uZmlndXJlIHJldHJ5XHJcblx0Y29uc3QgdHJ5TGltaXQ6IG51bWJlciA9IG1vZGVsRmV0Y2hSZXF1ZXN0QWN0aW9uLm5vUmV0cnkgPyAxIDogVFJZX0xJTUlUXHJcblx0bGV0IHRyeUNvdW50ID0gMFxyXG5cdGxldCBkaWRGYWlsID0gZmFsc2VcclxuXHRsZXQgbGFzdEZldGNoUmVzdWx0OiBGZXRjaFJlc3VsdCB8IHVuZGVmaW5lZFxyXG5cdGxldCBsYXN0RXJyb3I6IEVycm9yIHwgdW5kZWZpbmVkXHJcblx0bGV0IGxhc3RFcnJvckRhdGE6IEZldGNoRXJyb3JEYXRhIHwgdW5kZWZpbmVkXHJcblxyXG5cdGNvbnN0IGZldGNoUmVzdWx0VW5kZWZpbmVkRXJyb3JNZXNzYWdlID0gXCInZmV0Y2hSZXN1bHQnIGlzIHVuZGVmaW5lZFwiXHJcblx0Y29uc3QgZmV0Y2hSZXN1bHROb3RPa0Vycm9yTWVzc2FnZSA9IFwiJ2ZldGNoUmVzdWx0Lm9rJyBpcyBmYWxzZVwiXHJcblxyXG5cdC8vIFJ1biByZXRyeSBsb29wXHJcblx0ZG8ge1xyXG5cdFx0ZGlkRmFpbCA9IGZhbHNlXHJcblx0XHR0cnlDb3VudCsrXHJcblxyXG5cdFx0Ly8gZGlzcGF0Y2ggdGhhdCB0aGUgZmV0Y2ggcmVxdWVzdCBzdGFydGVkLCB3aGljaCB1cGRhdGVzIGBfbWV0YWRhdGFgIGFuZCBgZ3VpZGAsIGlmIHByb3ZpZGVkLCBhdCB0aGUgdGFyZ2V0IHJlZHV4IGBtb2RlbFBhdGhgXHJcblx0XHR5aWVsZCBwdXQ8TW9kZWxGZXRjaFN0YXJ0QWN0aW9uPih7XHJcblx0XHRcdHR5cGU6IG1vZGVsRmV0Y2hSZXF1ZXN0QWN0aW9uLm5vU3RvcmVcclxuXHRcdFx0XHQ/IE1PREVMX0ZFVENIX1NUQVJUX0FDVElPTl9UWVBFLlRSQU5TSUVOVF9GRVRDSF9TVEFSVFxyXG5cdFx0XHRcdDogTU9ERUxfRkVUQ0hfU1RBUlRfQUNUSU9OX1RZUEUuRkVUQ0hfU1RBUlQsXHJcblx0XHRcdG1vZGVsUGF0aCxcclxuXHRcdFx0Z3VpZDogbW9kZWxGZXRjaFJlcXVlc3RBY3Rpb24uZ3VpZFxyXG5cdFx0fSlcclxuXHJcblx0XHRsZXQgZmV0Y2hSZXN1bHQ6IEZldGNoUmVzdWx0IHwgdW5kZWZpbmVkID0gdW5kZWZpbmVkXHJcblx0XHR0cnkge1xyXG5cdFx0XHQvLyBnZXQgdGhlIE9BdXRoIFRva2VuLCBpZiBhbnksIGFuZCBjYWxsIGBmZXRjaGBcclxuXHRcdFx0Y29uc3Qgb2F1dGhUb2tlbjogT0F1dGhUb2tlbk9yTnVsbCA9IHlpZWxkIGNhbGwodG9rZW5BY2Nlc3NGdW5jdGlvbiwgbW9kZWxGZXRjaFJlcXVlc3RBY3Rpb24ubW9kZWxOYW1lKVxyXG5cdFx0XHRpZiAob2F1dGhUb2tlbj8uYWNjZXNzX3Rva2VuKSB7XHJcblx0XHRcdFx0ZmV0Y2hDb25maWcuaGVhZGVycyA9IG1lcmdlKHt9LCBmZXRjaENvbmZpZy5oZWFkZXJzLCB7XHJcblx0XHRcdFx0XHRBdXRob3JpemF0aW9uOiBgQmVhcmVyICR7b2F1dGhUb2tlbi5hY2Nlc3NfdG9rZW59YFxyXG5cdFx0XHRcdH0pXHJcblx0XHRcdH1cclxuXHRcdFx0ZmV0Y2hSZXN1bHQgPSB5aWVsZCBjYWxsKHNlbmRGZXRjaCwgZmV0Y2hDb25maWcpXHJcblx0XHRcdC8vIHN0b3JlIGBmZXRjaFJlc3VsdGAgZm9yIHJlZmVyZW5jZSBhZnRlciB0aGUgZG8td2hpbGUgbG9vcFxyXG5cdFx0XHRsYXN0RmV0Y2hSZXN1bHQgPSBmZXRjaFJlc3VsdFxyXG5cclxuXHRcdFx0Ly8gdGhyb3cgb24gdW5zdWNjZXNzZnVsIHJlc3VsdCB0byBzaG9ydC1jaXJjdWl0IGFuZCB0cmlnZ2VyIGNhdGNoK3JldHJ5XHJcblx0XHRcdGlmICghZmV0Y2hSZXN1bHQpIHRocm93IG5ldyBFcnJvcihmZXRjaFJlc3VsdFVuZGVmaW5lZEVycm9yTWVzc2FnZSlcclxuXHRcdFx0aWYgKCFmZXRjaFJlc3VsdC5vaykgdGhyb3cgbmV3IEVycm9yKGZldGNoUmVzdWx0Tm90T2tFcnJvck1lc3NhZ2UpXHJcblxyXG5cdFx0XHQvLyBoYW5kbGUgc3VjY2Vzc1xyXG5cdFx0XHRjb25zdCByZXN1bHRBY3Rpb25UeXBlID0gbW9kZWxGZXRjaFJlcXVlc3RBY3Rpb24ubm9TdG9yZVxyXG5cdFx0XHRcdD8gTU9ERUxfRkVUQ0hfUkVTVUxUX0FDVElPTl9UWVBFLlRSQU5TSUVOVF9GRVRDSF9SRVNVTFRfUkVDRUlWRURcclxuXHRcdFx0XHQ6IE1PREVMX0ZFVENIX1JFU1VMVF9BQ1RJT05fVFlQRS5GRVRDSF9SRVNVTFRfUkVDRUlWRURcclxuXHJcblx0XHRcdGNvbnN0IGRhdGEgPSBjb252ZXJ0Q29sbGVjdGlvbnMoZW5kcG9pbnRNYXBwaW5nLCBwcmVwYXJlRmV0Y2hSZXN1bHQsIGZldGNoUmVzdWx0LmRhdGEpXHJcblx0XHRcdC8vIGF0dGFjaCBndWlkIHRvIHJlc3VsdCBkYXRhIGlmIGl0IGlzIGFuIG9iamVjdFxyXG5cdFx0XHRpZiAobW9kZWxGZXRjaFJlcXVlc3RBY3Rpb24uZ3VpZCAmJiBpc1BsYWluT2JqZWN0KGRhdGEpKSB7XHJcblx0XHRcdFx0ZGF0YS5ndWlkID0gbW9kZWxGZXRjaFJlcXVlc3RBY3Rpb24uZ3VpZFxyXG5cdFx0XHR9XHJcblxyXG5cdFx0XHQvLyBQT1NUIG5ldyBjb2xsZWN0aW9uIGl0ZW1cclxuXHRcdFx0aWYgKGlzQ29sbGVjdGlvbkl0ZW1DcmVhdGUpIHtcclxuXHRcdFx0XHRjb25zdCBtb2RlbFBhdGhMZXZlbHMgPSBtb2RlbFBhdGguc3BsaXQoJy4nKVxyXG5cdFx0XHRcdC8vIHJlbW92ZSBndWlkXHJcblx0XHRcdFx0bW9kZWxQYXRoTGV2ZWxzLnBvcCgpXHJcblx0XHRcdFx0Ly8gYWRkIGJ5IG5ldyByZXN1bHQncyBpZFxyXG5cdFx0XHRcdHlpZWxkIHB1dDxNb2RlbEZldGNoUmVzdWx0QWN0aW9uPih7XHJcblx0XHRcdFx0XHR0eXBlOiByZXN1bHRBY3Rpb25UeXBlLFxyXG5cdFx0XHRcdFx0bW9kZWxQYXRoOiBgJHttb2RlbFBhdGhMZXZlbHMuam9pbignLicpfS4ke2RhdGEuaWR9YCxcclxuXHRcdFx0XHRcdGd1aWQ6IG1vZGVsRmV0Y2hSZXF1ZXN0QWN0aW9uLmd1aWQsXHJcblx0XHRcdFx0XHRyZXBsYWNlVmFsdWU6IG1vZGVsRmV0Y2hSZXF1ZXN0QWN0aW9uLnJlcGxhY2VWYWx1ZSxcclxuXHRcdFx0XHRcdGRhdGFcclxuXHRcdFx0XHR9KVxyXG5cdFx0XHRcdC8vIHJlbW92ZSB0ZW1wIGl0ZW0gdW5kZXIgZ3VpZCBrZXlcclxuXHRcdFx0XHR5aWVsZCBwdXQ8TW9kZWxSZW1vdmVLZXlBY3Rpb24+KHtcclxuXHRcdFx0XHRcdHR5cGU6IE1PREVMX1JFTU9WRV9LRVlfQUNUSU9OX1RZUEUsXHJcblx0XHRcdFx0XHRtb2RlbFBhdGg6IG1vZGVsUGF0aFxyXG5cdFx0XHRcdH0pXHJcblx0XHRcdH1cclxuXHRcdFx0Ly8gREVMRVRFIGNvbGxlY3Rpb24gaXRlbVxyXG5cdFx0XHRlbHNlIGlmIChpc0NvbGxlY3Rpb25JdGVtRGVsZXRlKSB7XHJcblx0XHRcdFx0eWllbGQgcHV0PE1vZGVsUmVtb3ZlS2V5QWN0aW9uPih7XHJcblx0XHRcdFx0XHR0eXBlOiBNT0RFTF9SRU1PVkVfS0VZX0FDVElPTl9UWVBFLFxyXG5cdFx0XHRcdFx0bW9kZWxQYXRoOiBtb2RlbFBhdGhcclxuXHRcdFx0XHR9KVxyXG5cdFx0XHR9IGVsc2Uge1xyXG5cdFx0XHRcdHlpZWxkIHB1dDxNb2RlbEZldGNoUmVzdWx0QWN0aW9uPih7XHJcblx0XHRcdFx0XHR0eXBlOiByZXN1bHRBY3Rpb25UeXBlLFxyXG5cdFx0XHRcdFx0bW9kZWxQYXRoOiBtb2RlbFBhdGgsXHJcblx0XHRcdFx0XHRndWlkOiBtb2RlbEZldGNoUmVxdWVzdEFjdGlvbi5ndWlkLFxyXG5cdFx0XHRcdFx0cmVwbGFjZVZhbHVlOiBtb2RlbEZldGNoUmVxdWVzdEFjdGlvbi5yZXBsYWNlVmFsdWUsXHJcblx0XHRcdFx0XHRkYXRhXHJcblx0XHRcdFx0fSlcclxuXHRcdFx0fVxyXG5cdFx0fSBjYXRjaCAoY2F1Z2h0RXJyb3I6IHVua25vd24pIHtcclxuXHRcdFx0Ly8gY29uc3RydWN0IGBFcnJvcmAgdXNpbmcgYGNhdWdodEVycm9yYFxyXG5cdFx0XHRjb25zdCBiYXNlRXJyb3JNZXNzYWdlID0gYCdtb2RlbEZldGNoJyBmYWlsZWQgZm9yICcke21vZGVsUGF0aH0nYFxyXG5cdFx0XHRjb25zdCBlcnJvciA9IGNvbnN0cnVjdEVycm9yRnJvbUNhdWdodEVycm9yKGNhdWdodEVycm9yLCAnTW9kZWxGZXRjaEVycm9yJywgYmFzZUVycm9yTWVzc2FnZSlcclxuXHRcdFx0Ly8gY3JlYXRlIGEgZGVmYXVsdCBgZXJyb3JEYXRhYCBvYmplY3RcclxuXHRcdFx0Y29uc3QgaXNOZXR3b3JrT25saW5lID0gd2luZG93U2VydmljZS5nZXRJc09ubGluZSgpXHJcblx0XHRcdGxldCBlcnJvckRhdGE6IEZldGNoRXJyb3JEYXRhID0gaXNOZXR3b3JrT25saW5lID8gdW5rbm93bkVycm9yRGF0YSA6IG5ldHdvcmtPZmZsaW5lRXJyb3JEYXRhXHJcblx0XHRcdC8vIHVwZGF0ZSBgZXJyb3JEYXRhYCBmcm9tIHRoZSBgZmV0Y2hSZXN1bHQuZGF0YWBcclxuXHRcdFx0Ly8gZm9yIHdoZW4gdGhlIGZldGNoIGdvdCBhIHJlc3VsdCwgYnV0IGl0IHdhcyBhbiB1bnN1Y2Nlc3NmdWwgc3RhdHVzXHJcblx0XHRcdGlmIChmZXRjaFJlc3VsdD8uZGF0YSAmJiBpc0ZldGNoRXJyb3JEYXRhKGZldGNoUmVzdWx0LmRhdGEpKSB7XHJcblx0XHRcdFx0ZXJyb3JEYXRhID0gZmV0Y2hSZXN1bHQuZGF0YVxyXG5cdFx0XHRcdC8vIHVwZGF0ZSB0aGUgZXJyb3IncyBtZXNzYWdlIHRvIGluY2x1ZGUgaW5mbyBmcm9tIHRoZSBmZXRjaCByZXN1bHRcclxuXHRcdFx0XHRlcnJvci5tZXNzYWdlID0gYCR7YmFzZUVycm9yTWVzc2FnZX0uXFxuJHtmZXRjaENvbmZpZy5tZXRob2QgfHwgJ0dFVCd9ICR7ZmV0Y2hDb25maWcucGF0aH0gZmFpbGVkLlxcbiR7XHJcblx0XHRcdFx0XHRlcnJvckRhdGEudGl0bGVcclxuXHRcdFx0XHR9ICgke2Vycm9yRGF0YS5zdGF0dXN9KWBcclxuXHRcdFx0XHRpZiAoZXJyb3JEYXRhLmRldGFpbCkge1xyXG5cdFx0XHRcdFx0ZXJyb3IubWVzc2FnZSArPSBgOiAke2Vycm9yRGF0YS5kZXRhaWx9YFxyXG5cdFx0XHRcdH1cclxuXHRcdFx0fVxyXG5cclxuXHRcdFx0Ly8gdHJhY2sgYGVycm9yRGF0YWAgYW5kIGBlcnJvcmAgZm9yIGFmdGVyIHRoZSB3aGlsZS1sb29wXHJcblx0XHRcdGxhc3RFcnJvckRhdGEgPSBlcnJvckRhdGFcclxuXHRcdFx0bGFzdEVycm9yID0gZXJyb3JcclxuXHJcblx0XHRcdC8vIGRpc3BhdGNoIHRoYXQgdGhpcyB0cnkgZmFpbGVkXHJcblx0XHRcdHlpZWxkIHB1dDxNb2RlbEZldGNoRXJyb3JBY3Rpb24+KHtcclxuXHRcdFx0XHR0eXBlOiBNT0RFTF9GRVRDSF9FUlJPUl9BQ1RJT05fVFlQRS5UUllfRkVUQ0hfRkFJTEVELFxyXG5cdFx0XHRcdG1vZGVsUGF0aDogbW9kZWxQYXRoLFxyXG5cdFx0XHRcdGd1aWQ6IG1vZGVsRmV0Y2hSZXF1ZXN0QWN0aW9uLmd1aWQsXHJcblx0XHRcdFx0ZXJyb3JEYXRhXHJcblx0XHRcdH0pXHJcblxyXG5cdFx0XHQvLyBsb2cgdG8gdGhlIGNvbnNvbGVcclxuXHRcdFx0bG9nZ2VyLmVycm9yKGVycm9yKVxyXG5cclxuXHRcdFx0ZGlkRmFpbCA9IHRydWVcclxuXHJcblx0XHRcdC8vIERvIG5vdCByZXRyeSBpZiB0aGUgcmVzcG9uc2UgaXMgYmV0d2VlbiA0MDAtNTAwIChleGNlcHQgNDA4OiByZXF1ZXN0IHRpbWVvdXQpXHJcblx0XHRcdGlmIChcclxuXHRcdFx0XHRlcnJvckRhdGEuc3RhdHVzID49IEhUVFBfU1RBVFVTX0NPREUuQkFEX1JFUVVFU1QgJiZcclxuXHRcdFx0XHRlcnJvckRhdGEuc3RhdHVzIDwgSFRUUF9TVEFUVVNfQ09ERS5JTlRFUk5BTF9TRVJWRVJfRVJST1IgJiZcclxuXHRcdFx0XHRlcnJvckRhdGEuc3RhdHVzICE9PSBIVFRQX1NUQVRVU19DT0RFLlJFUVVFU1RfVElNRU9VVFxyXG5cdFx0XHQpIHtcclxuXHRcdFx0XHR0cnlDb3VudCA9IHRyeUxpbWl0XHJcblx0XHRcdH1cclxuXHJcblx0XHRcdC8vIGlmIHRoZXJlIGFyZSB0cmllcyByZW1haW5pbmcsIHBlcmZvcm0gYW4gZXhwb25lbnRpYWwgYmFja29mZlxyXG5cdFx0XHRpZiAodHJ5Q291bnQgPCB0cnlMaW1pdCkge1xyXG5cdFx0XHRcdHlpZWxkIGRlbGF5KDIgKiogKHRyeUNvdW50IC0gMSkgKiAxMDApIC8vIDEwMCwgMjAwLCA0MDAsIDgwMFxyXG5cdFx0XHR9XHJcblx0XHR9XHJcblx0fSB3aGlsZSAodHJ5Q291bnQgPCB0cnlMaW1pdCAmJiBkaWRGYWlsKVxyXG5cclxuXHQvLyBpZiBmZXRjaCBmYWlsZWQgY29tcGxldGVseSBhZnRlciBhbGwgcmV0cmllc1xyXG5cdGlmICh0cnlDb3VudCA9PT0gdHJ5TGltaXQgJiYgZGlkRmFpbCkge1xyXG5cdFx0Ly8gdGhlc2Ugd2lsbCBhbHdheXMgZXhpc3RcclxuXHRcdGNvbnN0IGVycm9yRGF0YSA9IGxhc3RFcnJvckRhdGEgYXMgRmV0Y2hFcnJvckRhdGFcclxuXHRcdGNvbnN0IGVycm9yID0gbGFzdEVycm9yIGFzIEVycm9yXHJcblxyXG5cdFx0Ly8gZGlzcGF0Y2ggdGhhdCB0aGUgZmV0Y2ggZmFpbGVkLCB3aGljaCB1cGRhdGVzIGBfbWV0YWRhdGFgIChhbmQgYGd1aWRgLCBpZiBwcm92aWRlZCkgYXQgdGhlIHRhcmdldCByZWR1eCBgbW9kZWxQYXRoYFxyXG5cdFx0eWllbGQgcHV0PE1vZGVsRmV0Y2hFcnJvckFjdGlvbj4oe1xyXG5cdFx0XHR0eXBlOiBtb2RlbEZldGNoUmVxdWVzdEFjdGlvbi5ub1N0b3JlXHJcblx0XHRcdFx0PyBNT0RFTF9GRVRDSF9FUlJPUl9BQ1RJT05fVFlQRS5UUkFOU0lFTlRfRkVUQ0hfRkFJTEVEXHJcblx0XHRcdFx0OiBNT0RFTF9GRVRDSF9FUlJPUl9BQ1RJT05fVFlQRS5GRVRDSF9GQUlMRUQsXHJcblx0XHRcdG1vZGVsUGF0aDogbW9kZWxQYXRoLFxyXG5cdFx0XHRndWlkOiBtb2RlbEZldGNoUmVxdWVzdEFjdGlvbi5ndWlkLFxyXG5cdFx0XHRlcnJvckRhdGFcclxuXHRcdH0pXHJcblxyXG5cdFx0Ly8gU2VuZCBlcnJvciB0byBlcnJvciBoYW5kbGVyLCBleGNlcHQgZm9yIDQwMXNcclxuXHRcdGlmIChlcnJvckRhdGEuc3RhdHVzICE9PSBIVFRQX1NUQVRVU19DT0RFLlVOQVVUSE9SSVpFRCkge1xyXG5cdFx0XHRlcnJvckhhbmRsZXIoZXJyb3IsIG1vZGVsRmV0Y2hSZXF1ZXN0QWN0aW9uLCBmZXRjaENvbmZpZywgbGFzdEZldGNoUmVzdWx0LCBlcnJvckRhdGEpXHJcblx0XHR9XHJcblx0fVxyXG59XHJcblxyXG4vKipcclxuICogVGhlIGxvb3Agc2FnYSB0aGF0IG1ha2VzIHRoZSByZXF1ZXN0IGV2ZXJ5IHthY3Rpb24ucGVyaW9kfSBtaWxsaXNlY29uZHMgdW50aWwgY2FuY2VsbGVkXHJcbiAqXHJcbiAqIEBwYXJhbSBhY3Rpb24gQW4gYWN0aW9uIHdpdGggdGhlIHJlcXVlc3QgY29uZmlndXJhdGlvblxyXG4gKi9cclxuZXhwb3J0IGZ1bmN0aW9uKiBtb2RlbEZldGNoTG9vcChhY3Rpb246IFBlcmlvZGljTW9kZWxGZXRjaFJlcXVlc3RBY3Rpb24pOiBTYWdhSXRlcmF0b3Ige1xyXG5cdHRyeSB7XHJcblx0XHRsZXQgaGFzRmV0Y2hlZCA9IGZhbHNlXHJcblx0XHRkbyB7XHJcblx0XHRcdC8vIGNhbGwgdGhlIGZldGNoIGlmIHRoaXMgaXMgdGhlIGZpcnN0IGxvb3AgaXRlcmF0aW9uLFxyXG5cdFx0XHQvLyBvciBpZiB0aGUgdXNlciBpcyBub3QgaWRsZVxyXG5cdFx0XHRpZiAoIWhhc0ZldGNoZWQgfHwgIWlzVXNlcklkbGUoKSkge1xyXG5cdFx0XHRcdHlpZWxkIGNhbGwobW9kZWxGZXRjaCwgYWN0aW9uKVxyXG5cdFx0XHRcdGhhc0ZldGNoZWQgPSB0cnVlXHJcblx0XHRcdH1cclxuXHRcdFx0eWllbGQgZGVsYXkoYWN0aW9uLnBlcmlvZClcclxuXHRcdH0gd2hpbGUgKHRydWUpXHJcblx0fSBjYXRjaCAoY2F1Z2h0RXJyb3I6IHVua25vd24pIHtcclxuXHRcdGNvbnN0IGVycm9yID0gY29uc3RydWN0RXJyb3JGcm9tQ2F1Z2h0RXJyb3IoY2F1Z2h0RXJyb3IsICdNb2RlbEZldGNoTG9vcEVycm9yJywgJ21vZGVsRmV0Y2hMb29wIGZhaWxlZCcpXHJcblx0XHRsb2dnZXIuZXJyb3IoZXJyb3IpXHJcblx0XHQvLyBjYXRjaCBhbmQgbG9nIGFueSB1bmV4cGVjdGVkIGVycm9ycyBub3QgY2F1Z2h0IGluc2lkZSBgZmV0Y2hEYXRhYFxyXG5cdFx0ZXJyb3JIYW5kbGVyKGVycm9yLCBhY3Rpb24pXHJcblx0fSBmaW5hbGx5IHtcclxuXHRcdGlmICh5aWVsZCBjYW5jZWxsZWQoKSkge1xyXG5cdFx0XHR5aWVsZCBwdXQ8UGVyaW9kaWNNb2RlbEZldGNoVGVybWluYXRpb25BY3Rpb24+KHtcclxuXHRcdFx0XHR0eXBlOiBQRVJJT0RJQ19NT0RFTF9GRVRDSF9URVJNSU5BVElPTl9BQ1RJT05fVFlQRS5TVUNDRUVERUQsXHJcblx0XHRcdFx0dGFza0lkOiBhY3Rpb24udGFza0lkXHJcblx0XHRcdH0pXHJcblx0XHR9XHJcblx0fVxyXG59XHJcblxyXG4vKipcclxuICogQ2FsbCB0aGUgZmV0Y2hEYXRhIHNhZ2EgZXZlcnkge2FjdGlvbi5wZXJpb2R9IG1pbGxpc2Vjb25kcy4gVGhpcyBzYWdhIHJlcXVpcmVzIHRoZSAncGVyaW9kJyBhbmQgJ3Rhc2tJZCcgcHJvcGVydGllc1xyXG4gKiBvbiB0aGUgYWN0aW9uIHBhcmFtZXRlci5cclxuICpcclxuICogQHBhcmFtIGFjdGlvbiBBbiBhY3Rpb24gd2l0aCB0aGUgcmVxdWVzdCBjb25maWd1cmF0aW9uXHJcbiAqL1xyXG5leHBvcnQgZnVuY3Rpb24qIG1vZGVsRmV0Y2hSZWN1cnJpbmcoYWN0aW9uOiBQZXJpb2RpY01vZGVsRmV0Y2hSZXF1ZXN0QWN0aW9uKTogU2FnYUl0ZXJhdG9yIHtcclxuXHRpZiAoIWFjdGlvbi5wZXJpb2QpIHtcclxuXHRcdHRocm93IG5ldyBFcnJvcihcIidwZXJpb2QnIGlzIHJlcXVpcmVkXCIpXHJcblx0fVxyXG5cdGlmICghYWN0aW9uLnRhc2tJZCkge1xyXG5cdFx0dGhyb3cgbmV3IEVycm9yKFwiJ3Rhc2tJZCcgaXMgcmVxdWlyZWRcIilcclxuXHR9XHJcblxyXG5cdGNvbnN0IGJnU3luY1Rhc2s6IFRhc2sgPSB5aWVsZCBmb3JrKG1vZGVsRmV0Y2hMb29wLCBhY3Rpb24pXHJcblx0eWllbGQgdGFrZSh0YWtlTWF0Y2hlc1Rlcm1pbmF0aW9uQWN0aW9uKGFjdGlvbikpXHJcblx0eWllbGQgY2FuY2VsKGJnU3luY1Rhc2spXHJcbn1cclxuXHJcbi8qKlxyXG4gKiBUaGUgbWFpbiBzYWdhIGZvciBmZXRjaGluZyBtb2RlbHMuIE11c3QgYmUgaW5pdGlhbGl6ZWQgd2l0aCBhbiBFbmRwb2ludE1hcHBpbmdzIG9iamVjdCB0aGF0IGNhbiBiZSBmZXRjaGVkXHJcbiAqIGFuZCBhbiBBUEkgcm9vdCB0byBwcmVwZW5kIHRvIGFueSBwYXJ0aWFsIFVSTHMgc3BlY2lmaWVkIGluIHRoZSBFbmRwb2ludE1hcHBpbmdzIG9iamVjdC4gQSBsb2dnZXIgc2hvdWxkIG5vcm1hbGx5IGJlIHByb3ZpZGVkXHJcbiAqIGFzIHdlbGwuXHJcbiAqXHJcbiAqIGBFbmRwb2ludE1hcHBpbmdzYCBvYmplY3QgcmVxdWlyZSBhIGZvcm0gYXMgZm9sbG93cyAod2l0aCBvcHRpb25hbCBuZXN0ZWQgbW9kZWxzKTpcclxuICogYGBgXHJcbiAqIHtcclxuICogXHRmcnlNb2RlbDoge1xyXG4gKiBcdFx0cGF0aDogJy9hcGkvRm9vJ1xyXG4gKiBcdH0sXHJcbiAqIFx0Z3JvdXBPZk1vZGVsczoge1xyXG4gKiBcdFx0bGVlbGFNb2RlbDoge1xyXG4gKiBcdFx0XHRwYXRoOiAnL2FwaS9CYXInXHJcbiAqIFx0XHR9LFxyXG4gKiBcdFx0YmVuZGVyTW9kZWw6IHtcclxuICogXHRcdFx0cGF0aDogJy9hcGkvQmF6J1xyXG4gKiBcdFx0fVxyXG4gKiBcdH1cclxuICogfVxyXG4gKiBgYGBcclxuICogYEVuZHBvaW50TWFwcGluZ2Agb2JqZWN0cyBhcmUgcmVmZXJlbmNlZCBpbiB0aGUgYWN0aW9ucy5EQVRBX1JFUVVFU1RFRCBhY3Rpb24gYnkgcGF0aCwgaS5lLlxyXG4gKiBgeyB0eXBlOiBhY3Rpb25zLkRBVEFfUkVRVUVTVEVELCB7IG1vZGVsTmFtZTogJ2ZyeU1vZGVsJyB9IH1gXHJcbiAqIC0tIG9yIC0tXHJcbiAqIGB7IHR5cGU6IGFjdGlvbnMuREFUQV9SRVFVRVNURUQsIHsgbW9kZWxOYW1lOiAnZ3JvdXBPZk1vZGVscy5sZWVsYU1vZGVsJyB9IH1gXHJcbiAqXHJcbiAqIEBleHBvcnRcclxuICogQHBhcmFtIGVuZHBvaW50TWFwcGluZ3NQYXJhbSBBIG1hcHBpbmcgb2YgQVBJIGVuZHBvaW50cyBhdmFpbGFibGUgaW4gdGhlIGFwcGxpY2F0aW9uXHJcbiAqIEBwYXJhbSBhcGlSb290UGFyYW0gQSB1cmwgdG8gd2hpY2ggcGFydGlhbCBVUkxzIGFyZSBhcHBlbmRlZCAoaS5lLikgJ2h0dHBzOi8vbXlhcHAuY29tJ1xyXG4gKiBAcGFyYW0gdG9rZW5BY2Nlc3NGdW5jdGlvblBhcmFtIGZ1bmN0aW9uIHRoYXQgcmV0dXJucyBhbiBvcHRpb25hbCBPQXV0aCB0b2tlblxyXG4gKiBAcGFyYW0gZXJyb3JIYW5kbGVyUGFyYW0gQSBmdW5jdGlvbiB0aGF0IGlzIGNhbGxlZCB3aGVuIGFueSBmZXRjaCBleGNlcHRpb25zIG9jY3VyXHJcbiAqL1xyXG5leHBvcnQgZGVmYXVsdCBmdW5jdGlvbiogbW9kZWxGZXRjaFNhZ2EoXHJcblx0ZW5kcG9pbnRNYXBwaW5nc1BhcmFtOiBFbmRwb2ludE1hcHBpbmdzLFxyXG5cdGFwaVJvb3RQYXJhbT86IHN0cmluZyxcclxuXHR0b2tlbkFjY2Vzc0Z1bmN0aW9uUGFyYW06IFRva2VuQWNjZXNzRnVuY3Rpb24gfCB1bmRlZmluZWQgPSBkZWZhdWx0VG9rZW5BY2Nlc3NGdW5jdGlvbixcclxuXHRlcnJvckhhbmRsZXJQYXJhbTogRXJyb3JIYW5kbGVyIHwgdW5kZWZpbmVkID0gZGVmYXVsdEVycm9ySGFuZGxlclxyXG4pOiBTYWdhSXRlcmF0b3Ige1xyXG5cdHNldEFwaVJvb3QoYXBpUm9vdFBhcmFtKVxyXG5cdHNldEVuZHBvaW50TWFwcGluZ3MoZW5kcG9pbnRNYXBwaW5nc1BhcmFtKVxyXG5cdGVycm9ySGFuZGxlciA9IGVycm9ySGFuZGxlclBhcmFtXHJcblx0dG9rZW5BY2Nlc3NGdW5jdGlvbiA9IHRva2VuQWNjZXNzRnVuY3Rpb25QYXJhbVxyXG5cdGxvZ2dlciA9IGdldExvZ2dlcigpXHJcblxyXG5cdHlpZWxkIHRha2VFdmVyeShNT0RFTF9GRVRDSF9SRVFVRVNUX0FDVElPTl9UWVBFLkZFVENIX1JFUVVFU1QsIG1vZGVsRmV0Y2gpXHJcblx0eWllbGQgdGFrZUV2ZXJ5KE1PREVMX0ZFVENIX1JFUVVFU1RfQUNUSU9OX1RZUEUuUEVSSU9ESUNfRkVUQ0hfUkVRVUVTVCwgbW9kZWxGZXRjaFJlY3VycmluZylcclxufVxyXG4iXSwibWFwcGluZ3MiOiI7Ozs7Ozs7Ozs7Ozs7O0FBQ0EsSUFBQUEsT0FBQSxHQUFBQyxPQUFBO0FBQ0EsSUFBQUMsZUFBQSxHQUFBQyxzQkFBQSxDQUFBRixPQUFBO0FBRUEsSUFBQUcsUUFBQSxHQUFBSCxPQUFBO0FBQ0EsSUFBQUksZUFBQSxHQUFBSixPQUFBO0FBQ0EsSUFBQUssWUFBQSxHQUFBTCxPQUFBO0FBQ0EsSUFBQU0sYUFBQSxHQUFBTixPQUFBO0FBQ0EsSUFBQU8sY0FBQSxHQUFBUCxPQUFBO0FBQ0EsSUFBQVEsTUFBQSxHQUFBUixPQUFBO0FBWUEsSUFBQVMsTUFBQSxHQUFBVCxPQUFBO0FBQ0EsSUFBQVUsTUFBQSxHQUFB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