@growsober/sdk 1.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (129) hide show
  1. package/README.md +276 -0
  2. package/dist/__tests__/e2e.test.d.ts +7 -0
  3. package/dist/__tests__/e2e.test.js +472 -0
  4. package/dist/api/client.d.ts +11 -0
  5. package/dist/api/client.js +61 -0
  6. package/dist/api/mutations/admin.d.ts +167 -0
  7. package/dist/api/mutations/admin.js +326 -0
  8. package/dist/api/mutations/ambassadors.d.ts +52 -0
  9. package/dist/api/mutations/ambassadors.js +148 -0
  10. package/dist/api/mutations/auth.d.ts +267 -0
  11. package/dist/api/mutations/auth.js +332 -0
  12. package/dist/api/mutations/bookings.d.ts +59 -0
  13. package/dist/api/mutations/bookings.js +143 -0
  14. package/dist/api/mutations/event-chat.d.ts +35 -0
  15. package/dist/api/mutations/event-chat.js +147 -0
  16. package/dist/api/mutations/events.d.ts +87 -0
  17. package/dist/api/mutations/events.js +205 -0
  18. package/dist/api/mutations/grow90.d.ts +36 -0
  19. package/dist/api/mutations/grow90.js +132 -0
  20. package/dist/api/mutations/hubs.d.ts +111 -0
  21. package/dist/api/mutations/hubs.js +240 -0
  22. package/dist/api/mutations/index.d.ts +22 -0
  23. package/dist/api/mutations/index.js +39 -0
  24. package/dist/api/mutations/jack.d.ts +61 -0
  25. package/dist/api/mutations/jack.js +104 -0
  26. package/dist/api/mutations/library.d.ts +67 -0
  27. package/dist/api/mutations/library.js +168 -0
  28. package/dist/api/mutations/map.d.ts +153 -0
  29. package/dist/api/mutations/map.js +181 -0
  30. package/dist/api/mutations/matching.d.ts +130 -0
  31. package/dist/api/mutations/matching.js +204 -0
  32. package/dist/api/mutations/notifications.d.ts +63 -0
  33. package/dist/api/mutations/notifications.js +106 -0
  34. package/dist/api/mutations/offers.d.ts +26 -0
  35. package/dist/api/mutations/offers.js +47 -0
  36. package/dist/api/mutations/subscriptions.d.ts +127 -0
  37. package/dist/api/mutations/subscriptions.js +140 -0
  38. package/dist/api/mutations/support.d.ts +165 -0
  39. package/dist/api/mutations/support.js +307 -0
  40. package/dist/api/mutations/users.d.ts +211 -0
  41. package/dist/api/mutations/users.js +261 -0
  42. package/dist/api/queries/admin.d.ts +257 -0
  43. package/dist/api/queries/admin.js +320 -0
  44. package/dist/api/queries/ambassadors.d.ts +53 -0
  45. package/dist/api/queries/ambassadors.js +98 -0
  46. package/dist/api/queries/auth.d.ts +16 -0
  47. package/dist/api/queries/auth.js +25 -0
  48. package/dist/api/queries/bookings.d.ts +91 -0
  49. package/dist/api/queries/bookings.js +102 -0
  50. package/dist/api/queries/businesses.d.ts +212 -0
  51. package/dist/api/queries/businesses.js +154 -0
  52. package/dist/api/queries/event-chat.d.ts +19 -0
  53. package/dist/api/queries/event-chat.js +75 -0
  54. package/dist/api/queries/events.d.ts +322 -0
  55. package/dist/api/queries/events.js +221 -0
  56. package/dist/api/queries/grow90.d.ts +26 -0
  57. package/dist/api/queries/grow90.js +85 -0
  58. package/dist/api/queries/hubs.d.ts +165 -0
  59. package/dist/api/queries/hubs.js +143 -0
  60. package/dist/api/queries/index.d.ts +23 -0
  61. package/dist/api/queries/index.js +40 -0
  62. package/dist/api/queries/jack.d.ts +63 -0
  63. package/dist/api/queries/jack.js +92 -0
  64. package/dist/api/queries/library.d.ts +132 -0
  65. package/dist/api/queries/library.js +120 -0
  66. package/dist/api/queries/map.d.ts +216 -0
  67. package/dist/api/queries/map.js +278 -0
  68. package/dist/api/queries/matching.d.ts +136 -0
  69. package/dist/api/queries/matching.js +161 -0
  70. package/dist/api/queries/notifications.d.ts +78 -0
  71. package/dist/api/queries/notifications.js +88 -0
  72. package/dist/api/queries/offers.d.ts +91 -0
  73. package/dist/api/queries/offers.js +103 -0
  74. package/dist/api/queries/subscriptions.d.ts +56 -0
  75. package/dist/api/queries/subscriptions.js +73 -0
  76. package/dist/api/queries/support.d.ts +106 -0
  77. package/dist/api/queries/support.js +202 -0
  78. package/dist/api/queries/users.d.ts +293 -0
  79. package/dist/api/queries/users.js +370 -0
  80. package/dist/api/types.d.ts +464 -0
  81. package/dist/api/types.js +9 -0
  82. package/dist/hooks/useAuth.d.ts +5 -0
  83. package/dist/hooks/useAuth.js +39 -0
  84. package/dist/hooks/useUser.d.ts +43 -0
  85. package/dist/hooks/useUser.js +44 -0
  86. package/dist/index.d.ts +36 -0
  87. package/dist/index.js +67 -0
  88. package/package.json +62 -0
  89. package/src/__tests__/e2e.test.ts +502 -0
  90. package/src/api/client.ts +71 -0
  91. package/src/api/mutations/admin.ts +531 -0
  92. package/src/api/mutations/ambassadors.ts +185 -0
  93. package/src/api/mutations/auth.ts +350 -0
  94. package/src/api/mutations/bookings.ts +190 -0
  95. package/src/api/mutations/event-chat.ts +177 -0
  96. package/src/api/mutations/events.ts +273 -0
  97. package/src/api/mutations/grow90.ts +169 -0
  98. package/src/api/mutations/hubs.ts +385 -0
  99. package/src/api/mutations/index.ts +23 -0
  100. package/src/api/mutations/jack.ts +130 -0
  101. package/src/api/mutations/library.ts +212 -0
  102. package/src/api/mutations/map.ts +230 -0
  103. package/src/api/mutations/matching.ts +271 -0
  104. package/src/api/mutations/notifications.ts +114 -0
  105. package/src/api/mutations/offers.ts +73 -0
  106. package/src/api/mutations/subscriptions.ts +162 -0
  107. package/src/api/mutations/support.ts +390 -0
  108. package/src/api/mutations/users.ts +271 -0
  109. package/src/api/queries/admin.ts +480 -0
  110. package/src/api/queries/ambassadors.ts +139 -0
  111. package/src/api/queries/auth.ts +24 -0
  112. package/src/api/queries/bookings.ts +135 -0
  113. package/src/api/queries/businesses.ts +203 -0
  114. package/src/api/queries/event-chat.ts +78 -0
  115. package/src/api/queries/events.ts +272 -0
  116. package/src/api/queries/grow90.ts +98 -0
  117. package/src/api/queries/hubs.ts +211 -0
  118. package/src/api/queries/index.ts +24 -0
  119. package/src/api/queries/jack.ts +127 -0
  120. package/src/api/queries/library.ts +166 -0
  121. package/src/api/queries/map.ts +331 -0
  122. package/src/api/queries/matching.ts +238 -0
  123. package/src/api/queries/notifications.ts +103 -0
  124. package/src/api/queries/offers.ts +136 -0
  125. package/src/api/queries/subscriptions.ts +91 -0
  126. package/src/api/queries/support.ts +235 -0
  127. package/src/api/queries/users.ts +393 -0
  128. package/src/api/types.ts +596 -0
  129. package/src/index.ts +57 -0
@@ -0,0 +1,370 @@
1
+ "use strict";
2
+ /**
3
+ * Users Query Hooks
4
+ *
5
+ * TanStack Query hooks for user-related read operations.
6
+ * These hooks handle fetching user data, profiles, library items, and subscriptions.
7
+ *
8
+ * @module api/queries/users
9
+ */
10
+ Object.defineProperty(exports, "__esModule", { value: true });
11
+ exports.userKeys = void 0;
12
+ exports.useCurrentUser = useCurrentUser;
13
+ exports.useUser = useUser;
14
+ exports.usePublicProfile = usePublicProfile;
15
+ exports.useMyBookmarks = useMyBookmarks;
16
+ exports.useMyProgress = useMyProgress;
17
+ exports.useMyRedeemedOffers = useMyRedeemedOffers;
18
+ const react_query_1 = require("@tanstack/react-query");
19
+ const client_1 = require("../client");
20
+ // ============================================================================
21
+ // QUERY KEYS
22
+ // ============================================================================
23
+ /**
24
+ * Query key factory for user-related queries
25
+ * @see https://tkdodo.eu/blog/effective-react-query-keys
26
+ */
27
+ exports.userKeys = {
28
+ all: ['users'],
29
+ me: () => [...exports.userKeys.all, 'me'],
30
+ detail: (id) => [...exports.userKeys.all, 'detail', id],
31
+ public: (id) => [...exports.userKeys.all, 'public', id],
32
+ library: {
33
+ all: () => [...exports.userKeys.me(), 'library'],
34
+ bookmarks: () => [...exports.userKeys.library.all(), 'bookmarks'],
35
+ progress: () => [...exports.userKeys.library.all(), 'progress'],
36
+ },
37
+ offers: {
38
+ all: () => [...exports.userKeys.me(), 'offers'],
39
+ redeemed: () => [...exports.userKeys.offers.all(), 'redeemed'],
40
+ },
41
+ subscription: () => [...exports.userKeys.me(), 'subscription'],
42
+ };
43
+ // ============================================================================
44
+ // QUERY HOOKS
45
+ // ============================================================================
46
+ /**
47
+ * Get current user's profile
48
+ *
49
+ * @description
50
+ * Retrieves the currently authenticated user's complete profile information.
51
+ * Requires a valid access token to be set via the SDK configuration.
52
+ *
53
+ * @endpoint GET /api/v1/users/me
54
+ *
55
+ * @example
56
+ * ```tsx
57
+ * import { useCurrentUser } from '@growsober/sdk';
58
+ *
59
+ * function ProfileScreen() {
60
+ * const { data: user, isLoading, error } = useCurrentUser();
61
+ *
62
+ * if (isLoading) return <Spinner />;
63
+ * if (error) return <Error message={error.message} />;
64
+ * if (!user) return <NotFound />;
65
+ *
66
+ * return (
67
+ * <div>
68
+ * <h1>{user.name}</h1>
69
+ * <p>{user.email}</p>
70
+ * <p>Sober Since: {user.soberDate}</p>
71
+ * </div>
72
+ * );
73
+ * }
74
+ * ```
75
+ *
76
+ * @example
77
+ * With custom options:
78
+ * ```tsx
79
+ * const { data: user } = useCurrentUser({
80
+ * refetchOnMount: false,
81
+ * staleTime: 5 * 60 * 1000, // 5 minutes
82
+ * });
83
+ * ```
84
+ *
85
+ * @param options - TanStack Query options for customizing the query behavior
86
+ * @returns TanStack Query result with user data
87
+ */
88
+ function useCurrentUser(options) {
89
+ return (0, react_query_1.useQuery)({
90
+ queryKey: exports.userKeys.me(),
91
+ queryFn: async () => {
92
+ const client = (0, client_1.getApiClient)();
93
+ const response = await client.get('/api/v1/users/me');
94
+ return response.data;
95
+ },
96
+ ...options,
97
+ });
98
+ }
99
+ /**
100
+ * Get a specific user's full profile by ID
101
+ *
102
+ * @description
103
+ * Retrieves a user's complete profile information by their ID.
104
+ * This may include private information depending on the requesting user's permissions.
105
+ *
106
+ * @endpoint GET /api/v1/users/{id}
107
+ *
108
+ * @example
109
+ * ```tsx
110
+ * import { useUser } from '@growsober/sdk';
111
+ *
112
+ * function UserProfileScreen({ userId }: { userId: string }) {
113
+ * const { data: user, isLoading } = useUser(userId);
114
+ *
115
+ * if (isLoading) return <Spinner />;
116
+ *
117
+ * return (
118
+ * <div>
119
+ * <Avatar src={user.avatar} />
120
+ * <h1>{user.name}</h1>
121
+ * <p>{user.bio}</p>
122
+ * </div>
123
+ * );
124
+ * }
125
+ * ```
126
+ *
127
+ * @example
128
+ * With conditional fetching:
129
+ * ```tsx
130
+ * const { data: user } = useUser(userId, {
131
+ * enabled: !!userId, // Only fetch when userId is defined
132
+ * });
133
+ * ```
134
+ *
135
+ * @param id - The user ID to fetch
136
+ * @param options - TanStack Query options for customizing the query behavior
137
+ * @returns TanStack Query result with user data
138
+ */
139
+ function useUser(id, options) {
140
+ return (0, react_query_1.useQuery)({
141
+ queryKey: exports.userKeys.detail(id),
142
+ queryFn: async () => {
143
+ const client = (0, client_1.getApiClient)();
144
+ const response = await client.get(`/api/v1/users/${id}`);
145
+ return response.data;
146
+ },
147
+ ...options,
148
+ });
149
+ }
150
+ /**
151
+ * Get a user's public profile by ID
152
+ *
153
+ * @description
154
+ * Retrieves a user's public profile information.
155
+ * This endpoint returns only publicly visible information and doesn't require authentication.
156
+ *
157
+ * @endpoint GET /api/v1/users/{id}/public
158
+ *
159
+ * @example
160
+ * ```tsx
161
+ * import { usePublicProfile } from '@growsober/sdk';
162
+ *
163
+ * function PublicProfileCard({ userId }: { userId: string }) {
164
+ * const { data: profile, isLoading } = usePublicProfile(userId);
165
+ *
166
+ * if (isLoading) return <Skeleton />;
167
+ *
168
+ * return (
169
+ * <div>
170
+ * <Avatar src={profile.avatar} />
171
+ * <h2>{profile.displayName}</h2>
172
+ * <p>{profile.city}</p>
173
+ * {profile.soberSince && (
174
+ * <p>Sober since: {new Date(profile.soberSince).toLocaleDateString()}</p>
175
+ * )}
176
+ * </div>
177
+ * );
178
+ * }
179
+ * ```
180
+ *
181
+ * @param id - The user ID to fetch
182
+ * @param options - TanStack Query options for customizing the query behavior
183
+ * @returns TanStack Query result with public profile data
184
+ */
185
+ function usePublicProfile(id, options) {
186
+ return (0, react_query_1.useQuery)({
187
+ queryKey: exports.userKeys.public(id),
188
+ queryFn: async () => {
189
+ const client = (0, client_1.getApiClient)();
190
+ const response = await client.get(`/api/v1/users/${id}/public`);
191
+ return response.data;
192
+ },
193
+ ...options,
194
+ });
195
+ }
196
+ /**
197
+ * Get current user's bookmarked library content
198
+ *
199
+ * @description
200
+ * Retrieves all library content (articles, videos, podcasts, etc.) that the user has bookmarked.
201
+ * This allows users to save content for later reading/viewing.
202
+ *
203
+ * @endpoint GET /api/v1/users/me/library/bookmarks
204
+ *
205
+ * @example
206
+ * ```tsx
207
+ * import { useMyBookmarks } from '@growsober/sdk';
208
+ *
209
+ * function BookmarksScreen() {
210
+ * const { data: bookmarks, isLoading } = useMyBookmarks();
211
+ *
212
+ * if (isLoading) return <Loading />;
213
+ *
214
+ * return (
215
+ * <div>
216
+ * <h1>My Saved Content</h1>
217
+ * {bookmarks?.map(content => (
218
+ * <ContentCard key={content.id} content={content} />
219
+ * ))}
220
+ * </div>
221
+ * );
222
+ * }
223
+ * ```
224
+ *
225
+ * @example
226
+ * With auto-refresh:
227
+ * ```tsx
228
+ * const { data: bookmarks } = useMyBookmarks({
229
+ * refetchInterval: 60000, // Refresh every minute
230
+ * });
231
+ * ```
232
+ *
233
+ * @param options - TanStack Query options for customizing the query behavior
234
+ * @returns TanStack Query result with array of bookmarked content
235
+ */
236
+ function useMyBookmarks(options) {
237
+ return (0, react_query_1.useQuery)({
238
+ queryKey: exports.userKeys.library.bookmarks(),
239
+ queryFn: async () => {
240
+ const client = (0, client_1.getApiClient)();
241
+ const response = await client.get('/api/v1/users/me/library/bookmarks');
242
+ return response.data;
243
+ },
244
+ ...options,
245
+ });
246
+ }
247
+ /**
248
+ * Get current user's library content progress
249
+ *
250
+ * @description
251
+ * Retrieves the user's progress on library content items.
252
+ * Tracks which content has been started, completed, or partially viewed/read.
253
+ *
254
+ * @endpoint GET /api/v1/users/me/library/progress
255
+ *
256
+ * @example
257
+ * ```tsx
258
+ * import { useMyProgress } from '@growsober/sdk';
259
+ *
260
+ * function LibraryProgressScreen() {
261
+ * const { data: progress, isLoading } = useMyProgress();
262
+ *
263
+ * if (isLoading) return <Loading />;
264
+ *
265
+ * const completed = progress?.filter(p => p.completed) || [];
266
+ * const inProgress = progress?.filter(p => !p.completed && p.progress > 0) || [];
267
+ *
268
+ * return (
269
+ * <div>
270
+ * <h2>Completed: {completed.length}</h2>
271
+ * <h2>In Progress: {inProgress.length}</h2>
272
+ * </div>
273
+ * );
274
+ * }
275
+ * ```
276
+ *
277
+ * @example
278
+ * Check progress for specific content:
279
+ * ```tsx
280
+ * function ContentProgress({ contentId }: { contentId: string }) {
281
+ * const { data: progress } = useMyProgress();
282
+ * const contentProgress = progress?.find(p => p.contentId === contentId);
283
+ *
284
+ * return (
285
+ * <ProgressBar
286
+ * value={contentProgress?.progress || 0}
287
+ * max={100}
288
+ * />
289
+ * );
290
+ * }
291
+ * ```
292
+ *
293
+ * @param options - TanStack Query options for customizing the query behavior
294
+ * @returns TanStack Query result with array of progress records
295
+ */
296
+ function useMyProgress(options) {
297
+ return (0, react_query_1.useQuery)({
298
+ queryKey: exports.userKeys.library.progress(),
299
+ queryFn: async () => {
300
+ const client = (0, client_1.getApiClient)();
301
+ const response = await client.get('/api/v1/users/me/library/progress');
302
+ return response.data;
303
+ },
304
+ ...options,
305
+ });
306
+ }
307
+ /**
308
+ * Get current user's redeemed offers
309
+ *
310
+ * @description
311
+ * Retrieves all offers/deals that the user has redeemed.
312
+ * Shows history of partner offers used by the user.
313
+ *
314
+ * @endpoint GET /api/v1/users/me/offers/redeemed
315
+ *
316
+ * @example
317
+ * ```tsx
318
+ * import { useMyRedeemedOffers } from '@growsober/sdk';
319
+ *
320
+ * function RedeemedOffersScreen() {
321
+ * const { data: offers, isLoading } = useMyRedeemedOffers();
322
+ *
323
+ * if (isLoading) return <Loading />;
324
+ *
325
+ * return (
326
+ * <div>
327
+ * <h1>My Redeemed Offers</h1>
328
+ * {offers?.map(offer => (
329
+ * <div key={offer.id}>
330
+ * <h3>{offer.title}</h3>
331
+ * <p>Redeemed: {new Date(offer.redeemedAt).toLocaleDateString()}</p>
332
+ * <p>Code: {offer.code}</p>
333
+ * </div>
334
+ * ))}
335
+ * </div>
336
+ * );
337
+ * }
338
+ * ```
339
+ *
340
+ * @example
341
+ * Check if specific offer was redeemed:
342
+ * ```tsx
343
+ * function OfferCard({ offerId }: { offerId: string }) {
344
+ * const { data: redeemedOffers } = useMyRedeemedOffers();
345
+ * const isRedeemed = redeemedOffers?.some(o => o.id === offerId);
346
+ *
347
+ * return (
348
+ * <button disabled={isRedeemed}>
349
+ * {isRedeemed ? 'Already Redeemed' : 'Redeem Offer'}
350
+ * </button>
351
+ * );
352
+ * }
353
+ * ```
354
+ *
355
+ * @param options - TanStack Query options for customizing the query behavior
356
+ * @returns TanStack Query result with array of redeemed offers
357
+ */
358
+ function useMyRedeemedOffers(options) {
359
+ return (0, react_query_1.useQuery)({
360
+ queryKey: exports.userKeys.offers.redeemed(),
361
+ queryFn: async () => {
362
+ const client = (0, client_1.getApiClient)();
363
+ const response = await client.get('/api/v1/users/me/offers/redeemed');
364
+ return response.data;
365
+ },
366
+ ...options,
367
+ });
368
+ }
369
+ // Note: useMySubscription is available from '@growsober/sdk' via ./subscriptions
370
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoidXNlcnMuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi9zcmMvYXBpL3F1ZXJpZXMvdXNlcnMudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IjtBQUFBOzs7Ozs7O0dBT0c7OztBQW9GSCx3Q0FZQztBQTBDRCwwQkFhQztBQXFDRCw0Q0FhQztBQTBDRCx3Q0FZQztBQW1ERCxzQ0FZQztBQXFERCxrREFZQztBQTdYRCx1REFBa0Y7QUFDbEYsc0NBQXlDO0FBVXpDLCtFQUErRTtBQUMvRSxhQUFhO0FBQ2IsK0VBQStFO0FBRS9FOzs7R0FHRztBQUNVLFFBQUEsUUFBUSxHQUFHO0lBQ3RCLEdBQUcsRUFBRSxDQUFDLE9BQU8sQ0FBVTtJQUN2QixFQUFFLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQyxHQUFHLGdCQUFRLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBVTtJQUMxQyxNQUFNLEVBQUUsQ0FBQyxFQUFVLEVBQUUsRUFBRSxDQUFDLENBQUMsR0FBRyxnQkFBUSxDQUFDLEdBQUcsRUFBRSxRQUFRLEVBQUUsRUFBRSxDQUFVO0lBQ2hFLE1BQU0sRUFBRSxDQUFDLEVBQVUsRUFBRSxFQUFFLENBQUMsQ0FBQyxHQUFHLGdCQUFRLENBQUMsR0FBRyxFQUFFLFFBQVEsRUFBRSxFQUFFLENBQVU7SUFDaEUsT0FBTyxFQUFFO1FBQ1AsR0FBRyxFQUFFLEdBQUcsRUFBRSxDQUFDLENBQUMsR0FBRyxnQkFBUSxDQUFDLEVBQUUsRUFBRSxFQUFFLFNBQVMsQ0FBVTtRQUNqRCxTQUFTLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQyxHQUFHLGdCQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFFLFdBQVcsQ0FBVTtRQUNsRSxRQUFRLEVBQUUsR0FBRyxFQUFFLENBQUMsQ0FBQyxHQUFHLGdCQUFRLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxFQUFFLFVBQVUsQ0FBVTtLQUNqRTtJQUNELE1BQU0sRUFBRTtRQUNOLEdBQUcsRUFBRSxHQUFHLEVB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Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWdERztBQUNILFNBQWdCLGFBQWEsQ0FDM0IsT0FBa0Y7SUFFbEYsT0FBTyxJQUFBLHNCQUFRLEVBQUM7UUFDZCxRQUFRLEVBQUUsZ0JBQVEsQ0FBQyxPQUFPLENBQUMsUUFBUSxFQUFFO1FBQ3JDLE9BQU8sRUFBRSxLQUFLLElBQXdDLEVBQUU7WUFDdEQsTUFBTSxNQUFNLEdBQUcsSUFBQSxxQkFBWSxHQUFFLENBQUM7WUFDOUIsTUFBTSxRQUFRLEdBQUcsTUFBTSxNQUFNLENBQUMsR0FBRyxDQUE0QixtQ0FBbUMsQ0FBQyxDQUFDO1lBQ2xHLE9BQU8sUUFBUSxDQUFDLElBQUksQ0FBQztRQUN2QixDQUFDO1FBQ0QsR0FBRyxPQUFPO0tBQ1gsQ0FBQyxDQUFDO0FBQ0wsQ0FBQztBQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWtERztBQUNILFNBQWdCLG1CQUFtQixDQUNqQyxPQUF3RTtJQUV4RSxPQUFPLElBQUEsc0JBQVEsRUFBQztRQUNkLFFBQVEsRUFBRSxnQkFBUSxDQUFDLE1BQU0sQ0FBQyxRQUFRLEVBQUU7UUFDcEMsT0FBTyxFQUFFLEtBQUssSUFBOEIsRUFBRTtZQUM1QyxNQUFNLE1BQU0sR0FBRyxJQUFBLHFCQUFZLEdBQUUsQ0FBQztZQUM5QixNQUFNLFFBQVEsR0FBRyxNQUFNLE1BQU0sQ0FBQyxHQUFHLENBQWtCLGtDQUFrQyxDQUFDLENBQUM7WUFDdkYsT0FBTyxRQUFRLENBQUMsSUFBSSxDQUFDO1FBQ3ZCLENBQUM7UUFDRCxHQUFHLE9BQU87S0FDWCxDQUFDLENBQUM7QUFDTCxDQUFDO0FBRUQsaUZBQWlGIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBVc2VycyBRdWVyeSBIb29rc1xuICpcbiAqIFRhblN0YWNrIFF1ZXJ5IGhvb2tzIGZvciB1c2VyLXJlbGF0ZWQgcmVhZCBvcGVyYXRpb25zLlxuICogVGhlc2UgaG9va3MgaGFuZGxlIGZldGNoaW5nIHVzZXIgZGF0YSwgcHJvZmlsZXMsIGxpYnJhcnkgaXRlbXMsIGFuZCBzdWJzY3JpcHRpb25zLlxuICpcbiAqIEBtb2R1bGUgYXBpL3F1ZXJpZXMvdXNlcnNcbiAqL1xuXG5pbXBvcnQgeyB1c2VRdWVyeSwgVXNlUXVlcnlPcHRpb25zLCBVc2VRdWVyeVJlc3VsdCB9IGZyb20gJ0B0YW5zdGFjay9yZWFjdC1xdWVyeSc7XG5pbXBvcnQgeyBnZXRBcGlDbGllbnQgfSBmcm9tICcuLi9jbGllbnQnO1xuaW1wb3J0IHR5cGUge1xuICBVc2VyUmVzcG9uc2UsXG4gIFVzZXJQdWJsaWNSZXNwb25zZSxcbiAgTGlicmFyeUNvbnRlbnRSZXNwb25zZSxcbiAgTGlicmFyeVByb2dyZXNzUmVzcG9uc2UsXG4gIE9mZmVyUmVzcG9uc2UsXG4gIFN1YnNjcmlwdGlvblJlc3BvbnNlLFxufSBmcm9tICcuLi90eXBlcyc7XG5cbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbi8vIFFVRVJZIEtFWVNcbi8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cblxuLyoqXG4gKiBRdWVyeSBrZXkgZmFjdG9yeSBmb3IgdXNlci1yZWxhdGVkIHF1ZXJpZXNcbiAqIEBzZWUgaHR0cHM6Ly90a2RvZG8uZXUvYmxvZy9lZmZlY3RpdmUtcmVhY3QtcXVlcnkta2V5c1xuICovXG5leHBvcnQgY29uc3QgdXNlcktleXMgPSB7XG4gIGFsbDogWyd1c2VycyddIGFzIGNvbnN0LFxuICBtZTogKCkgPT4gWy4uLnVzZXJLZXlzLmFsbCwgJ21lJ10gYXMgY29uc3QsXG4gIGRldGFpbDogKGlkOiBzdHJpbmcpID0+IFsuLi51c2VyS2V5cy5hbGwsICdkZXRhaWwnLCBpZF0gYXMgY29uc3QsXG4gIHB1YmxpYzogKGlkOiBzdHJpbmcpID0+IFsuLi51c2VyS2V5cy5hbGwsICdwdWJsaWMnLCBpZF0gYXMgY29uc3QsXG4gIGxpYnJhcnk6IHtcbiAgICBhbGw6ICgpID0+IFsuLi51c2VyS2V5cy5tZSgpLCAnbGlicmFyeSddIGFzIGNvbnN0LFxuICAgIGJvb2ttYXJrczogKCkgPT4gWy4uLnVzZXJLZXlzLmxpYnJhcnkuYWxsKCksICdib29rbWFya3MnXSBhcyBjb25zdCxcbiAgICBwcm9ncmVzczogKCkgPT4gWy4uLnVzZXJLZXlzLmxpYnJhcnkuYWxsKCksICdwcm9ncmVzcyddIGFzIGNvbnN0LFxuICB9LFxuICBvZmZlcnM6IHtcbiAgICBhbGw6ICgpID0+IFsuLi51c2VyS2V5cy5tZSgpLCAnb2ZmZXJzJ10gYXMgY29uc3QsXG4gICAgcmVkZWVtZWQ6ICgpID0+IFsuLi51c2VyS2V5cy5vZmZlcnMuYWxsKCksICdyZWRlZW1lZCddIGFzIGNvbnN0LFxuICB9LFxuICBzdWJzY3JpcHRpb246ICgpID0+IFsuLi51c2VyS2V5cy5tZSgpLCAnc3Vic2NyaXB0aW9uJ10gYXMgY29uc3QsXG59O1xuXG4vLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4vLyBRVUVSWSBIT09LU1xuLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4vKipcbiAqIEdldCBjdXJyZW50IHVzZXIncyBwcm9maWxlXG4gKlxuICogQGRlc2NyaXB0aW9uXG4gKiBSZXRyaWV2ZXMgdGhlIGN1cnJlbnRseSBhdXRoZW50aWNhdGVkIHVzZXIncyBjb21wbGV0ZSBwcm9maWxlIGluZm9ybWF0aW9uLlxuICogUmVxdWlyZXMgYSB2YWxpZCBhY2Nlc3MgdG9rZW4gdG8gYmUgc2V0IHZpYSB0aGUgU0RLIGNvbmZpZ3VyYXRpb24uXG4gKlxuICogQGVuZHBvaW50IEdFVCAvYXBpL3YxL3VzZXJzL21lXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHRzeFxuICogaW1wb3J0IHsgdXNlQ3VycmVudFVzZXIgfSBmcm9tICdAZ3Jvd3NvYmVyL3Nkayc7XG4gKlxuICogZnVuY3Rpb24gUHJvZmlsZVNjcmVlbigpIHtcbiAqICAgY29uc3QgeyBkYXRhOiB1c2VyLCBpc0xvYWRpbmcsIGVycm9yIH0gPSB1c2VDdXJyZW50VXNlcigpO1xuICpcbiAqICAgaWYgKGlzTG9hZGluZykgcmV0dXJuIDxTcGlubmVyIC8+O1xuICogICBpZiAoZXJyb3IpIHJldHVybiA8RXJyb3IgbWVzc2FnZT17ZXJyb3IubWVzc2FnZX0gLz47XG4gKiAgIGlmICghdXNlcikgcmV0dXJuIDxOb3RGb3VuZCAvPjtcbiAqXG4gKiAgIHJldHVybiAoXG4gKiAgICAgPGRpdj5cbiAqICAgICAgIDxoMT57dXNlci5uYW1lfTwvaDE+XG4gKiAgICAgICA8cD57dXNlci5lbWFpbH08L3A+XG4gKiAgICAgICA8cD5Tb2JlciBTaW5jZToge3VzZXIuc29iZXJEYXRlfTwvcD5cbiAqICAgICA8L2Rpdj5cbiAqICAgKTtcbiAqIH1cbiAqIGBgYFxuICpcbiAqIEBleGFtcGxlXG4gKiBXaXRoIGN1c3RvbSBvcHRpb25zOlxuICogYGBgdHN4XG4gKiBjb25zdCB7IGRhdGE6IHVzZXIgfSA9IHVzZUN1cnJlbnRVc2VyKHtcbiAqICAgcmVmZXRjaE9uTW91bnQ6IGZhbHNlLFxuICogICBzdGFsZVRpbWU6IDUgKiA2MCAqIDEwMDAsIC8vIDUgbWludXRlc1xuICogfSk7XG4gKiBgYGBcbiAqXG4gKiBAcGFyYW0gb3B0aW9ucyAtIFRhblN0YWNrIFF1ZXJ5IG9wdGlvbnMgZm9yIGN1c3RvbWl6aW5nIHRoZSBxdWVyeSBiZWhhdmlvclxuICogQHJldHVybnMgVGFuU3RhY2sgUXVlcnkgcmVzdWx0IHdpdGggdXNlciBkYXRhXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB1c2VDdXJyZW50VXNlcihcbiAgb3B0aW9ucz86IE9taXQ8VXNlUXVlcnlPcHRpb25zPFVzZXJSZXNwb25zZT4sICdxdWVyeUtleScgfCAncXVlcnlGbic+XG4pOiBVc2VRdWVyeVJlc3VsdDxVc2VyUmVzcG9uc2U+IHtcbiAgcmV0dXJuIHVzZVF1ZXJ5KHtcbiAgICBxdWVyeUtleTogdXNlcktleXMubWUoKSxcbiAgICBxdWVyeUZuOiBhc3luYyAoKTogUHJvbWlzZTxVc2VyUmVzcG9uc2U+ID0+IHtcbiAgICAgIGNvbnN0IGNsaWVudCA9IGdldEFwaUNsaWVudCgpO1xuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBjbGllbnQuZ2V0PFVzZXJSZXNwb25zZT4oJy9hcGkvdjEvdXNlcnMvbWUnKTtcbiAgICAgIHJldHVybiByZXNwb25zZS5kYXRhO1xuICAgIH0sXG4gICAgLi4ub3B0aW9ucyxcbiAgfSk7XG59XG5cbi8qKlxuICogR2V0IGEgc3BlY2lmaWMgdXNlcidzIGZ1bGwgcHJvZmlsZSBieSBJRFxuICpcbiAqIEBkZXNjcmlwdGlvblxuICogUmV0cmlldmVzIGEgdXNlcidzIGNvbXBsZXRlIHByb2ZpbGUgaW5mb3JtYXRpb24gYnkgdGhlaXIgSUQuXG4gKiBUaGlzIG1heSBpbmNsdWRlIHByaXZhdGUgaW5mb3JtYXRpb24gZGVwZW5kaW5nIG9uIHRoZSByZXF1ZXN0aW5nIHVzZXIncyBwZXJtaXNzaW9ucy5cbiAqXG4gKiBAZW5kcG9pbnQgR0VUIC9hcGkvdjEvdXNlcnMve2lkfVxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0c3hcbiAqIGltcG9ydCB7IHVzZVVzZXIgfSBmcm9tICdAZ3Jvd3NvYmVyL3Nkayc7XG4gKlxuICogZnVuY3Rpb24gVXNlclByb2ZpbGVTY3JlZW4oeyB1c2VySWQgfTogeyB1c2VySWQ6IHN0cmluZyB9KSB7XG4gKiAgIGNvbnN0IHsgZGF0YTogdXNlciwgaXNMb2FkaW5nIH0gPSB1c2VVc2VyKHVzZXJJZCk7XG4gKlxuICogICBpZiAoaXNMb2FkaW5nKSByZXR1cm4gPFNwaW5uZXIgLz47XG4gKlxuICogICByZXR1cm4gKFxuICogICAgIDxkaXY+XG4gKiAgICAgICA8QXZhdGFyIHNyYz17dXNlci5hdmF0YXJ9IC8+XG4gKiAgICAgICA8aDE+e3VzZXIubmFtZX08L2gxPlxuICogICAgICAgPHA+e3VzZXIuYmlvfTwvcD5cbiAqICAgICA8L2Rpdj5cbiAqICAgKTtcbiAqIH1cbiAqIGBgYFxuICpcbiAqIEBleGFtcGxlXG4gKiBXaXRoIGNvbmRpdGlvbmFsIGZldGNoaW5nOlxuICogYGBgdHN4XG4gKiBjb25zdCB7IGRhdGE6IHVzZXIgfSA9IHVzZVVzZXIodXNlcklkLCB7XG4gKiAgIGVuYWJsZWQ6ICEhdXNlcklkLCAvLyBPbmx5IGZldGNoIHdoZW4gdXNlcklkIGlzIGRlZmluZWRcbiAqIH0pO1xuICogYGBgXG4gKlxuICogQHBhcmFtIGlkIC0gVGhlIHVzZXIgSUQgdG8gZmV0Y2hcbiAqIEBwYXJhbSBvcHRpb25zIC0gVGFuU3RhY2sgUXVlcnkgb3B0aW9ucyBmb3IgY3VzdG9taXppbmcgdGhlIHF1ZXJ5IGJlaGF2aW9yXG4gKiBAcmV0dXJucyBUYW5TdGFjayBRdWVyeSByZXN1bHQgd2l0aCB1c2VyIGRhdGFcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVzZVVzZXIoXG4gIGlkOiBzdHJpbmcsXG4gIG9wdGlvbnM/OiBPbWl0PFVzZVF1ZXJ5T3B0aW9uczxVc2VyUmVzcG9uc2U+LCAncXVlcnlLZXknIHwgJ3F1ZXJ5Rm4nPlxuKTogVXNlUXVlcnlSZXN1bHQ8VXNlclJlc3BvbnNlPiB7XG4gIHJldHVybiB1c2VRdWVyeSh7XG4gICAgcXVlcnlLZXk6IHVzZXJLZXlzLmRldGFpbChpZCksXG4gICAgcXVlcnlGbjogYXN5bmMgKCk6IFByb21pc2U8VXNlclJlc3BvbnNlPiA9PiB7XG4gICAgICBjb25zdCBjbGllbnQgPSBnZXRBcGlDbGllbnQoKTtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgY2xpZW50LmdldDxVc2VyUmVzcG9uc2U+KGAvYXBpL3YxL3VzZXJzLyR7aWR9YCk7XG4gICAgICByZXR1cm4gcmVzcG9uc2UuZGF0YTtcbiAgICB9LFxuICAgIC4uLm9wdGlvbnMsXG4gIH0pO1xufVxuXG4vKipcbiAqIEdldCBhIHVzZXIncyBwdWJsaWMgcHJvZmlsZSBieSBJRFxuICpcbiAqIEBkZXNjcmlwdGlvblxuICogUmV0cmlldmVzIGEgdXNlcidzIHB1YmxpYyBwcm9maWxlIGluZm9ybWF0aW9uLlxuICogVGhpcyBlbmRwb2ludCByZXR1cm5zIG9ubHkgcHVibGljbHkgdmlzaWJsZSBpbmZvcm1hdGlvbiBhbmQgZG9lc24ndCByZXF1aXJlIGF1dGhlbnRpY2F0aW9uLlxuICpcbiAqIEBlbmRwb2ludCBHRVQgL2FwaS92MS91c2Vycy97aWR9L3B1YmxpY1xuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0c3hcbiAqIGltcG9ydCB7IHVzZVB1YmxpY1Byb2ZpbGUgfSBmcm9tICdAZ3Jvd3NvYmVyL3Nkayc7XG4gKlxuICogZnVuY3Rpb24gUHVibGljUHJvZmlsZUNhcmQoeyB1c2VySWQgfTogeyB1c2VySWQ6IHN0cmluZyB9KSB7XG4gKiAgIGNvbnN0IHsgZGF0YTogcHJvZmlsZSwgaXNMb2FkaW5nIH0gPSB1c2VQdWJsaWNQcm9maWxlKHVzZXJJZCk7XG4gKlxuICogICBpZiAoaXNMb2FkaW5nKSByZXR1cm4gPFNrZWxldG9uIC8+O1xuICpcbiAqICAgcmV0dXJuIChcbiAqICAgICA8ZGl2PlxuICogICAgICAgPEF2YXRhciBzcmM9e3Byb2ZpbGUuYXZhdGFyfSAvPlxuICogICAgICAgPGgyPntwcm9maWxlLmRpc3BsYXlOYW1lfTwvaDI+XG4gKiAgICAgICA8cD57cHJvZmlsZS5jaXR5fTwvcD5cbiAqICAgICAgIHtwcm9maWxlLnNvYmVyU2luY2UgJiYgKFxuICogICAgICAgICA8cD5Tb2JlciBzaW5jZToge25ldyBEYXRlKHByb2ZpbGUuc29iZXJTaW5jZSkudG9Mb2NhbGVEYXRlU3RyaW5nKCl9PC9wPlxuICogICAgICAgKX1cbiAqICAgICA8L2Rpdj5cbiAqICAgKTtcbiAqIH1cbiAqIGBgYFxuICpcbiAqIEBwYXJhbSBpZCAtIFRoZSB1c2VyIElEIHRvIGZldGNoXG4gKiBAcGFyYW0gb3B0aW9ucyAtIFRhblN0YWNrIFF1ZXJ5IG9wdGlvbnMgZm9yIGN1c3RvbWl6aW5nIHRoZSBxdWVyeSBiZWhhdmlvclxuICogQHJldHVybnMgVGFuU3RhY2sgUXVlcnkgcmVzdWx0IHdpdGggcHVibGljIHByb2ZpbGUgZGF0YVxuICovXG5leHBvcnQgZnVuY3Rpb24gdXNlUHVibGljUHJvZmlsZShcbiAgaWQ6IHN0cmluZyxcbiAgb3B0aW9ucz86IE9taXQ8VXNlUXVlcnlPcHRpb25zPFVzZXJQdWJsaWNSZXNwb25zZT4sICdxdWVyeUtleScgfCAncXVlcnlGbic+XG4pOiBVc2VRdWVyeVJlc3VsdDxVc2VyUHVibGljUmVzcG9uc2U+IHtcbiAgcmV0dXJuIHVzZVF1ZXJ5KHtcbiAgICBxdWVyeUtleTogdXNlcktleXMucHVibGljKGlkKSxcbiAgICBxdWVyeUZuOiBhc3luYyAoKTogUHJvbWlzZTxVc2VyUHVibGljUmVzcG9uc2U+ID0+IHtcbiAgICAgIGNvbnN0IGNsaWVudCA9IGdldEFwaUNsaWVudCgpO1xuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBjbGllbnQuZ2V0PFVzZXJQdWJsaWNSZXNwb25zZT4oYC9hcGkvdjEvdXNlcnMvJHtpZH0vcHVibGljYCk7XG4gICAgICByZXR1cm4gcmVzcG9uc2UuZGF0YTtcbiAgICB9LFxuICAgIC4uLm9wdGlvbnMsXG4gIH0pO1xufVxuXG4vKipcbiAqIEdldCBjdXJyZW50IHVzZXIncyBib29rbWFya2VkIGxpYnJhcnkgY29udGVudFxuICpcbiAqIEBkZXNjcmlwdGlvblxuICogUmV0cmlldmVzIGFsbCBsaWJyYXJ5IGNvbnRlbnQgKGFydGljbGVzLCB2aWRlb3MsIHBvZGNhc3RzLCBldGMuKSB0aGF0IHRoZSB1c2VyIGhhcyBib29rbWFya2VkLlxuICogVGhpcyBhbGxvd3MgdXNlcnMgdG8gc2F2ZSBjb250ZW50IGZvciBsYXRlciByZWFkaW5nL3ZpZXdpbmcuXG4gKlxuICogQGVuZHBvaW50IEdFVCAvYXBpL3YxL3VzZXJzL21lL2xpYnJhcnkvYm9va21hcmtzXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHRzeFxuICogaW1wb3J0IHsgdXNlTXlCb29rbWFya3MgfSBmcm9tICdAZ3Jvd3NvYmVyL3Nkayc7XG4gKlxuICogZnVuY3Rpb24gQm9va21hcmtzU2NyZWVuKCkge1xuICogICBjb25zdCB7IGRhdGE6IGJvb2ttYXJrcywgaXNMb2FkaW5nIH0gPSB1c2VNeUJvb2ttYXJrcygpO1xuICpcbiAqICAgaWYgKGlzTG9hZGluZykgcmV0dXJuIDxMb2FkaW5nIC8+O1xuICpcbiAqICAgcmV0dXJuIChcbiAqICAgICA8ZGl2PlxuICogICAgICAgPGgxPk15IFNhdmVkIENvbnRlbnQ8L2gxPlxuICogICAgICAge2Jvb2ttYXJrcz8ubWFwKGNvbnRlbnQgPT4gKFxuICogICAgICAgICA8Q29udGVudENhcmQga2V5PXtjb250ZW50LmlkfSBjb250ZW50PXtjb250ZW50fSAvPlxuICogICAgICAgKSl9XG4gKiAgICAgPC9kaXY+XG4gKiAgICk7XG4gKiB9XG4gKiBgYGBcbiAqXG4gKiBAZXhhbXBsZVxuICogV2l0aCBhdXRvLXJlZnJlc2g6XG4gKiBgYGB0c3hcbiAqIGNvbnN0IHsgZGF0YTogYm9va21hcmtzIH0gPSB1c2VNeUJvb2ttYXJrcyh7XG4gKiAgIHJlZmV0Y2hJbnRlcnZhbDogNjAwMDAsIC8vIFJlZnJlc2ggZXZlcnkgbWludXRlXG4gKiB9KTtcbiAqIGBgYFxuICpcbiAqIEBwYXJhbSBvcHRpb25zIC0gVGFuU3RhY2sgUXVlcnkgb3B0aW9ucyBmb3IgY3VzdG9taXppbmcgdGhlIHF1ZXJ5IGJlaGF2aW9yXG4gKiBAcmV0dXJucyBUYW5TdGFjayBRdWVyeSByZXN1bHQgd2l0aCBhcnJheSBvZiBib29rbWFya2VkIGNvbnRlbnRcbiAqL1xuZXhwb3J0IGZ1bmN0aW9uIHVzZU15Qm9va21hcmtzKFxuICBvcHRpb25zPzogT21pdDxVc2VRdWVyeU9wdGlvbnM8TGlicmFyeUNvbnRlbnRSZXNwb25zZVtdPiwgJ3F1ZXJ5S2V5JyB8ICdxdWVyeUZuJz5cbik6IFVzZVF1ZXJ5UmVzdWx0PExpYnJhcnlDb250ZW50UmVzcG9uc2VbXT4ge1xuICByZXR1cm4gdXNlUXVlcnkoe1xuICAgIHF1ZXJ5S2V5OiB1c2VyS2V5cy5saWJyYXJ5LmJvb2ttYXJrcygpLFxuICAgIHF1ZXJ5Rm46IGFzeW5jICgpOiBQcm9taXNlPExpYnJhcnlDb250ZW50UmVzcG9uc2VbXT4gPT4ge1xuICAgICAgY29uc3QgY2xpZW50ID0gZ2V0QXBpQ2xpZW50KCk7XG4gICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGNsaWVudC5nZXQ8TGlicmFyeUNvbnRlbnRSZXNwb25zZVtdPignL2FwaS92MS91c2Vycy9tZS9saWJyYXJ5L2Jvb2ttYXJrcycpO1xuICAgICAgcmV0dXJuIHJlc3BvbnNlLmRhdGE7XG4gICAgfSxcbiAgICAuLi5vcHRpb25zLFxuICB9KTtcbn1cblxuLyoqXG4gKiBHZXQgY3VycmVudCB1c2VyJ3MgbGlicmFyeSBjb250ZW50IHByb2dyZXNzXG4gKlxuICogQGRlc2NyaXB0aW9uXG4gKiBSZXRyaWV2ZXMgdGhlIHVzZXIncyBwcm9ncmVzcyBvbiBsaWJyYXJ5IGNvbnRlbnQgaXRlbXMuXG4gKiBUcmFja3Mgd2hpY2ggY29udGVudCBoYXMgYmVlbiBzdGFydGVkLCBjb21wbGV0ZWQsIG9yIHBhcnRpYWxseSB2aWV3ZWQvcmVhZC5cbiAqXG4gKiBAZW5kcG9pbnQgR0VUIC9hcGkvdjEvdXNlcnMvbWUvbGlicmFyeS9wcm9ncmVzc1xuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0c3hcbiAqIGltcG9ydCB7IHVzZU15UHJvZ3Jlc3MgfSBmcm9tICdAZ3Jvd3NvYmVyL3Nkayc7XG4gKlxuICogZnVuY3Rpb24gTGlicmFyeVByb2dyZXNzU2NyZWVuKCkge1xuICogICBjb25zdCB7IGRhdGE6IHByb2dyZXNzLCBpc0xvYWRpbmcgfSA9IHVzZU15UHJvZ3Jlc3MoKTtcbiAqXG4gKiAgIGlmIChpc0xvYWRpbmcpIHJldHVybiA8TG9hZGluZyAvPjtcbiAqXG4gKiAgIGNvbnN0IGNvbXBsZXRlZCA9IHByb2dyZXNzPy5maWx0ZXIocCA9PiBwLmNvbXBsZXRlZCkgfHwgW107XG4gKiAgIGNvbnN0IGluUHJvZ3Jlc3MgPSBwcm9ncmVzcz8uZmlsdGVyKHAgPT4gIXAuY29tcGxldGVkICYmIHAucHJvZ3Jlc3MgPiAwKSB8fCBbXTtcbiAqXG4gKiAgIHJldHVybiAoXG4gKiAgICAgPGRpdj5cbiAqICAgICAgIDxoMj5Db21wbGV0ZWQ6IHtjb21wbGV0ZWQubGVuZ3RofTwvaDI+XG4gKiAgICAgICA8aDI+SW4gUHJvZ3Jlc3M6IHtpblByb2dyZXNzLmxlbmd0aH08L2gyPlxuICogICAgIDwvZGl2PlxuICogICApO1xuICogfVxuICogYGBgXG4gKlxuICogQGV4YW1wbGVcbiAqIENoZWNrIHByb2dyZXNzIGZvciBzcGVjaWZpYyBjb250ZW50OlxuICogYGBgdHN4XG4gKiBmdW5jdGlvbiBDb250ZW50UHJvZ3Jlc3MoeyBjb250ZW50SWQgfTogeyBjb250ZW50SWQ6IHN0cmluZyB9KSB7XG4gKiAgIGNvbnN0IHsgZGF0YTogcHJvZ3Jlc3MgfSA9IHVzZU15UHJvZ3Jlc3MoKTtcbiAqICAgY29uc3QgY29udGVudFByb2dyZXNzID0gcHJvZ3Jlc3M/LmZpbmQocCA9PiBwLmNvbnRlbnRJZCA9PT0gY29udGVudElkKTtcbiAqXG4gKiAgIHJldHVybiAoXG4gKiAgICAgPFByb2dyZXNzQmFyXG4gKiAgICAgICB2YWx1ZT17Y29udGVudFByb2dyZXNzPy5wcm9ncmVzcyB8fCAwfVxuICogICAgICAgbWF4PXsxMDB9XG4gKiAgICAgLz5cbiAqICAgKTtcbiAqIH1cbiAqIGBgYFxuICpcbiAqIEBwYXJhbSBvcHRpb25zIC0gVGFuU3RhY2sgUXVlcnkgb3B0aW9ucyBmb3IgY3VzdG9taXppbmcgdGhlIHF1ZXJ5IGJlaGF2aW9yXG4gKiBAcmV0dXJucyBUYW5TdGFjayBRdWVyeSByZXN1bHQgd2l0aCBhcnJheSBvZiBwcm9ncmVzcyByZWNvcmRzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB1c2VNeVByb2dyZXNzKFxuICBvcHRpb25zPzogT21pdDxVc2VRdWVyeU9wdGlvbnM8TGlicmFyeVByb2dyZXNzUmVzcG9uc2VbXT4sICdxdWVyeUtleScgfCAncXVlcnlGbic+XG4pOiBVc2VRdWVyeVJlc3VsdDxMaWJyYXJ5UHJvZ3Jlc3NSZXNwb25zZVtdPiB7XG4gIHJldHVybiB1c2VRdWVyeSh7XG4gICAgcXVlcnlLZXk6IHVzZXJLZXlzLmxpYnJhcnkucHJvZ3Jlc3MoKSxcbiAgICBxdWVyeUZuOiBhc3luYyAoKTogUHJvbWlzZTxMaWJyYXJ5UHJvZ3Jlc3NSZXNwb25zZVtdPiA9PiB7XG4gICAgICBjb25zdCBjbGllbnQgPSBnZXRBcGlDbGllbnQoKTtcbiAgICAgIGNvbnN0IHJlc3BvbnNlID0gYXdhaXQgY2xpZW50LmdldDxMaWJyYXJ5UHJvZ3Jlc3NSZXNwb25zZVtdPignL2FwaS92MS91c2Vycy9tZS9saWJyYXJ5L3Byb2dyZXNzJyk7XG4gICAgICByZXR1cm4gcmVzcG9uc2UuZGF0YTtcbiAgICB9LFxuICAgIC4uLm9wdGlvbnMsXG4gIH0pO1xufVxuXG4vKipcbiAqIEdldCBjdXJyZW50IHVzZXIncyByZWRlZW1lZCBvZmZlcnNcbiAqXG4gKiBAZGVzY3JpcHRpb25cbiAqIFJldHJpZXZlcyBhbGwgb2ZmZXJzL2RlYWxzIHRoYXQgdGhlIHVzZXIgaGFzIHJlZGVlbWVkLlxuICogU2hvd3MgaGlzdG9yeSBvZiBwYXJ0bmVyIG9mZmVycyB1c2VkIGJ5IHRoZSB1c2VyLlxuICpcbiAqIEBlbmRwb2ludCBHRVQgL2FwaS92MS91c2Vycy9tZS9vZmZlcnMvcmVkZWVtZWRcbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHN4XG4gKiBpbXBvcnQgeyB1c2VNeVJlZGVlbWVkT2ZmZXJzIH0gZnJvbSAnQGdyb3dzb2Jlci9zZGsnO1xuICpcbiAqIGZ1bmN0aW9uIFJlZGVlbWVkT2ZmZXJzU2NyZWVuKCkge1xuICogICBjb25zdCB7IGRhdGE6IG9mZmVycywgaXNMb2FkaW5nIH0gPSB1c2VNeVJlZGVlbWVkT2ZmZXJzKCk7XG4gKlxuICogICBpZiAoaXNMb2FkaW5nKSByZXR1cm4gPExvYWRpbmcgLz47XG4gKlxuICogICByZXR1cm4gKFxuICogICAgIDxkaXY+XG4gKiAgICAgICA8aDE+TXkgUmVkZWVtZWQgT2ZmZXJzPC9oMT5cbiAqICAgICAgIHtvZmZlcnM/Lm1hcChvZmZlciA9PiAoXG4gKiAgICAgICAgIDxkaXYga2V5PXtvZmZlci5pZH0+XG4gKiAgICAgICAgICAgPGgzPntvZmZlci50aXRsZX08L2gzPlxuICogICAgICAgICAgIDxwPlJlZGVlbWVkOiB7bmV3IERhdGUob2ZmZXIucmVkZWVtZWRBdCkudG9Mb2NhbGVEYXRlU3RyaW5nKCl9PC9wPlxuICogICAgICAgICAgIDxwPkNvZGU6IHtvZmZlci5jb2RlfTwvcD5cbiAqICAgICAgICAgPC9kaXY+XG4gKiAgICAgICApKX1cbiAqICAgICA8L2Rpdj5cbiAqICAgKTtcbiAqIH1cbiAqIGBgYFxuICpcbiAqIEBleGFtcGxlXG4gKiBDaGVjayBpZiBzcGVjaWZpYyBvZmZlciB3YXMgcmVkZWVtZWQ6XG4gKiBgYGB0c3hcbiAqIGZ1bmN0aW9uIE9mZmVyQ2FyZCh7IG9mZmVySWQgfTogeyBvZmZlcklkOiBzdHJpbmcgfSkge1xuICogICBjb25zdCB7IGRhdGE6IHJlZGVlbWVkT2ZmZXJzIH0gPSB1c2VNeVJlZGVlbWVkT2ZmZXJzKCk7XG4gKiAgIGNvbnN0IGlzUmVkZWVtZWQgPSByZWRlZW1lZE9mZmVycz8uc29tZShvID0+IG8uaWQgPT09IG9mZmVySWQpO1xuICpcbiAqICAgcmV0dXJuIChcbiAqICAgICA8YnV0dG9uIGRpc2FibGVkPXtpc1JlZGVlbWVkfT5cbiAqICAgICAgIHtpc1JlZGVlbWVkID8gJ0FscmVhZHkgUmVkZWVtZWQnIDogJ1JlZGVlbSBPZmZlcid9XG4gKiAgICAgPC9idXR0b24+XG4gKiAgICk7XG4gKiB9XG4gKiBgYGBcbiAqXG4gKiBAcGFyYW0gb3B0aW9ucyAtIFRhblN0YWNrIFF1ZXJ5IG9wdGlvbnMgZm9yIGN1c3RvbWl6aW5nIHRoZSBxdWVyeSBiZWhhdmlvclxuICogQHJldHVybnMgVGFuU3RhY2sgUXVlcnkgcmVzdWx0IHdpdGggYXJyYXkgb2YgcmVkZWVtZWQgb2ZmZXJzXG4gKi9cbmV4cG9ydCBmdW5jdGlvbiB1c2VNeVJlZGVlbWVkT2ZmZXJzKFxuICBvcHRpb25zPzogT21pdDxVc2VRdWVyeU9wdGlvbnM8T2ZmZXJSZXNwb25zZVtdPiwgJ3F1ZXJ5S2V5JyB8ICdxdWVyeUZuJz5cbik6IFVzZVF1ZXJ5UmVzdWx0PE9mZmVyUmVzcG9uc2VbXT4ge1xuICByZXR1cm4gdXNlUXVlcnkoe1xuICAgIHF1ZXJ5S2V5OiB1c2VyS2V5cy5vZmZlcnMucmVkZWVtZWQoKSxcbiAgICBxdWVyeUZuOiBhc3luYyAoKTogUHJvbWlzZTxPZmZlclJlc3BvbnNlW10+ID0+IHtcbiAgICAgIGNvbnN0IGNsaWVudCA9IGdldEFwaUNsaWVudCgpO1xuICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBjbGllbnQuZ2V0PE9mZmVyUmVzcG9uc2VbXT4oJy9hcGkvdjEvdXNlcnMvbWUvb2ZmZXJzL3JlZGVlbWVkJyk7XG4gICAgICByZXR1cm4gcmVzcG9uc2UuZGF0YTtcbiAgICB9LFxuICAgIC4uLm9wdGlvbnMsXG4gIH0pO1xufVxuXG4vLyBOb3RlOiB1c2VNeVN1YnNjcmlwdGlvbiBpcyBhdmFpbGFibGUgZnJvbSAnQGdyb3dzb2Jlci9zZGsnIHZpYSAuL3N1YnNjcmlwdGlvbnNcbiJdfQ==