@effect-app/cli 1.24.0 → 1.26.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 (37) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/dist/gist.d.ts +231 -0
  3. package/dist/gist.d.ts.map +1 -0
  4. package/dist/gist.js +447 -0
  5. package/dist/index.js +35 -65
  6. package/dist/os-command.d.ts +18 -0
  7. package/dist/os-command.d.ts.map +1 -0
  8. package/dist/os-command.js +47 -0
  9. package/package.json +12 -18
  10. package/src/gist.ts +615 -0
  11. package/src/index.ts +50 -73
  12. package/src/os-command.ts +63 -0
  13. package/test.gists.yaml +20 -0
  14. package/dist/link.d.ts +0 -2
  15. package/dist/link.d.ts.map +0 -1
  16. package/dist/link.js +0 -17
  17. package/dist/old.d.ts +0 -2
  18. package/dist/old.d.ts.map +0 -1
  19. package/dist/old.js +0 -246
  20. package/dist/sync.d.ts +0 -2
  21. package/dist/sync.d.ts.map +0 -1
  22. package/dist/sync.js +0 -16
  23. package/dist/unlink.d.ts +0 -2
  24. package/dist/unlink.d.ts.map +0 -1
  25. package/dist/unlink.js +0 -13
  26. package/src/link.ts +0 -20
  27. package/src/old.ts +0 -283
  28. package/src/sync.ts +0 -17
  29. package/src/unlink.ts +0 -14
  30. package/vitest.config.ts.timestamp-1709838404819-f2fb28517168c.mjs +0 -33
  31. package/vitest.config.ts.timestamp-1709838418683-9c399c96f9d78.mjs +0 -33
  32. package/vitest.config.ts.timestamp-1709838649058-0e8f9431c893d.mjs +0 -33
  33. package/vitest.config.ts.timestamp-1711724061889-4985ba59def8.mjs +0 -37
  34. package/vitest.config.ts.timestamp-1711743471019-3c5e0c6ca2188.mjs +0 -37
  35. package/vitest.config.ts.timestamp-1711743489536-5ca18d3f67759.mjs +0 -37
  36. package/vitest.config.ts.timestamp-1711743593444-e40a8dcd4fc31.mjs +0 -37
  37. package/vitest.config.ts.timestamp-1711744615239-6a156fd39b9c9.mjs +0 -37
package/dist/gist.js ADDED
@@ -0,0 +1,447 @@
1
+ /* eslint-disable no-constant-binary-expression */
2
+ /* eslint-disable no-empty-pattern */
3
+ // import necessary modules from the libraries
4
+ import { FileSystem, Path } from "@effect/platform";
5
+ import { Array, Config, Data, Effect, Option, ParseResult, pipe, Schema, SynchronizedRef } from "effect";
6
+ import * as yaml from "js-yaml";
7
+ import path from "path";
8
+ import { RunCommandService } from "./os-command.js";
9
+ //
10
+ //
11
+ // Schemas
12
+ //
13
+ export class GistEntry extends Schema.Class("GistEntry")({
14
+ description: Schema.String,
15
+ public: Schema.Boolean,
16
+ files: Schema.Array(Schema.String)
17
+ }) {
18
+ }
19
+ /**
20
+ * Extended gist entry that validates file_name uniqueness and extracts base filenames.
21
+ *
22
+ * GitHub Gists have a flat file structure and do not support directories/folders.
23
+ * All files within a gist must exist in the same namespace, meaning that files
24
+ * with identical names will collide, even if they originate from different local
25
+ * directories. When multiple files share the same basename, GitHub will either:
26
+ * - Reject the gist creation
27
+ * - Silently overwrite files (last one wins)
28
+ * - Display unpredictable behavior
29
+ *
30
+ * This validation prevents such collisions by detecting when multiple file paths
31
+ * would result in the same file_name when flattened to the gist structure.
32
+ *
33
+ * @example
34
+ * // These paths would collide in a gist
35
+ * ["src/config.json", "dist/config.json"] // Both become "config.json"
36
+ *
37
+ * @see {@link https://docs.github.com/articles/creating-gists | GitHub Gist Documentation}
38
+ * @see {@link https://github.com/orgs/community/discussions/29584 | Community Discussion on Gist Folder Support}
39
+ */
40
+ export class GistEntryDecoded extends GistEntry.transformOrFail("GistEntryDecoded")({
41
+ files_with_name: Schema.Array(Schema.Struct({
42
+ path: Schema.String,
43
+ name: Schema.String
44
+ }))
45
+ }, {
46
+ decode: Effect.fnUntraced(function* (entry, _, ast) {
47
+ const files_with_name = entry.files.map((file) => ({
48
+ path: file,
49
+ name: path.basename(file) // <-- I'm using Node's path module here so that this schema works without requirements on Effect's Path module
50
+ }));
51
+ // check for duplicate file names
52
+ const nameMap = new Map();
53
+ for (const { name, path: filePath } of files_with_name) {
54
+ if (!nameMap.has(name)) {
55
+ nameMap.set(name, []);
56
+ }
57
+ nameMap.get(name).push(filePath);
58
+ }
59
+ // find duplicates and collect all collisions
60
+ const collisions = [];
61
+ for (const [fileName, paths] of nameMap.entries()) {
62
+ if (paths.length > 1) {
63
+ collisions.push(new ParseResult.Type(ast, paths, `Duplicate file name detected: "${fileName}". Colliding paths: ${paths.join(", ")}`));
64
+ }
65
+ }
66
+ // if there are any collisions, fail with all of them
67
+ if (Array.isNonEmptyArray(collisions)) {
68
+ return yield* Effect.fail(new ParseResult.Composite(ast, entry.files, collisions));
69
+ }
70
+ return yield* Effect.succeed({
71
+ ...entry,
72
+ files_with_name
73
+ });
74
+ }),
75
+ encode: (({ files_with_name, ...entry }) => ParseResult.succeed(entry))
76
+ }) {
77
+ }
78
+ export class GistYAML extends Schema.Class("GistYAML")({
79
+ gists: Schema.Record({
80
+ key: Schema.String,
81
+ value: GistEntryDecoded
82
+ }),
83
+ settings: Schema.Struct({
84
+ token_env: Schema.String,
85
+ base_directory: Schema.String
86
+ })
87
+ }) {
88
+ }
89
+ export class GistCacheEntry extends Schema.Class("GistCacheEntry")({
90
+ name: Schema.String,
91
+ id: Schema.String
92
+ }) {
93
+ }
94
+ export const GistCacheEntries = Schema.Array(GistCacheEntry);
95
+ /**
96
+ * Gist cache mapping YAML configuration names to GitHub gist IDs.
97
+ *
98
+ * Since GitHub gists don't have user-defined names, we maintain a cache
99
+ * that maps the human-readable names from our YAML config to actual gist IDs.
100
+ * This allows us to:
101
+ * - Update existing gists instead of creating duplicates
102
+ * - Clean up obsolete entries when gists are removed from config
103
+ * - Persist the name->ID mapping across CLI runs
104
+ *
105
+ * The cache itself is stored as a secret GitHub gist for persistence.
106
+ */
107
+ export class GistCache {
108
+ entries;
109
+ gist_id;
110
+ constructor({ entries, gist_id }) {
111
+ this.entries = entries;
112
+ this.gist_id = gist_id;
113
+ }
114
+ }
115
+ //
116
+ //
117
+ // Errors
118
+ //
119
+ class GistCacheNotFound extends Data.TaggedError("GistCacheNotFound") {
120
+ }
121
+ class GistYAMLError extends Data.TaggedError("GistYAMLError") {
122
+ }
123
+ //
124
+ //
125
+ // Services
126
+ //
127
+ class GHGistService extends Effect.Service()("GHGistService", {
128
+ dependencies: [RunCommandService.Default],
129
+ effect: Effect.gen(function* () {
130
+ const CACHE_GIST_DESCRIPTION = "GIST_CACHE_DO_NOT_EDIT_effa_cli_internal";
131
+ const { runGetExitCode, runGetString } = yield* RunCommandService;
132
+ // the client cannot recover from PlatformErrors, so we convert failures into defects to clean up the signatures
133
+ const runGetExitCodeSuppressed = (...args) => {
134
+ return runGetExitCode(...args).pipe(Effect.catchAll((e) => Effect.dieMessage(`Command failed: ${args.join(" ")}\nError: ${e.message}`)), Effect.asVoid);
135
+ };
136
+ // the client cannot recover from PlatformErrors, so we convert failures into defects to clean up the signatures
137
+ const runGetStringSuppressed = (...args) => {
138
+ return runGetString(...args).pipe(Effect.catchAll((e) => Effect.dieMessage(`Command failed: ${args.join(" ")}\nError: ${e.message}`)));
139
+ };
140
+ /**
141
+ * Extracts the Gist ID from a given GitHub Gist URL: https://gist.github.com/user/ID
142
+ * @param url - The full URL of the GitHub Gist.
143
+ * @returns An Option containing the Gist ID if extraction is successful, otherwise None.
144
+ */
145
+ function extractGistIdFromUrl(url) {
146
+ const gist_id = url.trim().split("/").pop();
147
+ return gist_id && gist_id.length > 0 ? Option.some(gist_id) : Option.none();
148
+ }
149
+ const loadGistCache = Effect
150
+ .fn("effa-cli.gist.loadGistCache")(function* () {
151
+ // search for existing cache gist
152
+ const output = yield* runGetStringSuppressed(`gh gist list --filter "${CACHE_GIST_DESCRIPTION}"`)
153
+ .pipe(Effect.orElse(() => Effect.succeed("")));
154
+ const lines = output.trim().split("\n").filter((line) => line.trim());
155
+ // extract first gist ID (should be our cache gist)
156
+ const firstLine = lines[0];
157
+ if (!firstLine) {
158
+ return yield* new GistCacheNotFound({ reason: "Empty gist list output" });
159
+ }
160
+ const parts = firstLine.split(/\s+/);
161
+ const gist_id = parts[0]?.trim();
162
+ if (!gist_id) {
163
+ return yield* new GistCacheNotFound({ reason: "No gist ID found in output" });
164
+ }
165
+ else {
166
+ yield* Effect.logInfo(`Found existing cache gist with ID ${gist_id}`);
167
+ }
168
+ // read cache gist content
169
+ const cacheContent = yield* runGetStringSuppressed(`gh gist view ${gist_id}`)
170
+ .pipe(Effect.orElse(() => Effect.succeed("")));
171
+ const entries = yield* pipe(cacheContent.split(CACHE_GIST_DESCRIPTION)[1]?.trim(), pipe(Schema.parseJson(GistCacheEntries), Schema.decodeUnknown), Effect.orElse(() => new GistCacheNotFound({ reason: "Failed to parse cache JSON" })));
172
+ return { entries, gist_id };
173
+ }, Effect.catchTag("GistCacheNotFound", () => Effect.gen(function* () {
174
+ // cache doesn't exist, create it
175
+ yield* Effect.logInfo("Cache gist not found, creating new cache...");
176
+ const cacheJson = yield* pipe([], pipe(Schema.parseJson(GistCacheEntries), Schema.encodeUnknown),
177
+ // cannot recover from parse errors in any case, better to die here instead of cluttering the signature
178
+ Effect.orDie);
179
+ const gistUrl = yield* runGetStringSuppressed(`echo '${cacheJson}' | gh gist create --desc="${CACHE_GIST_DESCRIPTION}" -`);
180
+ const gist_id = yield* pipe(gistUrl, extractGistIdFromUrl, Option.match({
181
+ onNone: () => Effect.dieMessage(`Could not extract cache's gist ID from URL: ${gistUrl}`),
182
+ onSome: (id) => Effect.succeed(id).pipe(Effect.tap(Effect.logInfo(`Created new cache gist with ID ${id}`)))
183
+ }));
184
+ return { entries: [], gist_id };
185
+ })), Effect.map(({ entries, gist_id }) => new GistCache({ entries, gist_id })));
186
+ const saveGistCache = Effect.fn("effa-cli.gist.saveGistCache")(function* (cache) {
187
+ const cacheJson = yield* pipe(cache.entries, pipe(Schema.parseJson(GistCacheEntries), Schema.encodeUnknown),
188
+ // cannot recover from parse errors in any case, better to die here instead of cluttering the signature
189
+ Effect.orDie);
190
+ yield* runGetExitCodeSuppressed(`echo '${cacheJson}' | gh gist edit ${cache.gist_id} -`);
191
+ });
192
+ const createGistWithFiles = Effect.fn("GHGistService.createGistWithFiles")(function* ({ cache, description, files, gist_name, is_public }) {
193
+ yield* Effect.logInfo(`Creating gist ${gist_name} with ${files.length} file(s)`);
194
+ const ghCommand = [
195
+ "gh",
196
+ "gist",
197
+ "create",
198
+ `--desc="${description}"`,
199
+ is_public ? "--public" : "",
200
+ ...files.map((filePath) => `"${filePath}"`)
201
+ ]
202
+ .filter((x) => !!x)
203
+ .join(" ");
204
+ // create and capture the created gist URL
205
+ const gistUrl = yield* runGetStringSuppressed(ghCommand);
206
+ // extract ID from URL
207
+ return yield* pipe(gistUrl, extractGistIdFromUrl, Option.match({
208
+ onNone: () => Effect.dieMessage(`Failed to extract gist ID from URL: ${gistUrl}`),
209
+ onSome: (id) => Effect
210
+ .succeed(new GistCache({
211
+ gist_id: cache.gist_id,
212
+ entries: [...cache.entries, { name: gist_name, id }]
213
+ }))
214
+ .pipe(Effect.tap(Effect.logInfo(`Created gist with ID ${id}`)))
215
+ }));
216
+ });
217
+ const getGistFileNames = Effect.fn("getGistFileNames")(function* ({ gist_id, gist_name }) {
218
+ yield* Effect.logInfo(`Retrieving file names from gist ${gist_name} with ID ${gist_id}`);
219
+ const output = yield* runGetStringSuppressed(`gh gist view ${gist_id} --files`);
220
+ return output
221
+ .trim()
222
+ .split("\n")
223
+ .filter((line) => line.trim());
224
+ });
225
+ const removeFileFromGist = Effect.fn("removeFileFromGist")(function* ({ file_name, gist_id, gist_name }) {
226
+ yield* Effect.logInfo(`Removing file ${file_name} from gist ${gist_name}`);
227
+ return yield* runGetExitCodeSuppressed(`gh gist edit ${gist_id} --remove "${file_name}"`);
228
+ });
229
+ const updateFileOfGist = Effect.fn("updateFileOfGist")(function* ({ file_name, file_path, gist_id, gist_name }) {
230
+ yield* Effect.logInfo(`Updating file ${file_name} located at ${file_path} of gist ${gist_name}`);
231
+ const editCommand = [
232
+ "gh",
233
+ "gist",
234
+ "edit",
235
+ gist_id,
236
+ "-f",
237
+ file_name,
238
+ `"${file_path}"`
239
+ ]
240
+ .join(" ");
241
+ return yield* runGetExitCodeSuppressed(editCommand);
242
+ });
243
+ const addFileToGist = Effect.fn("addFileToGist")(function* ({ file_path, gist_id, gist_name }) {
244
+ yield* Effect.logInfo(`Adding file ${file_path} to gist ${gist_name}`);
245
+ const editCommand = [
246
+ "gh",
247
+ "gist",
248
+ "edit",
249
+ gist_id,
250
+ "-a",
251
+ `"${file_path}"`
252
+ ]
253
+ .join(" ");
254
+ return yield* runGetExitCodeSuppressed(editCommand);
255
+ });
256
+ return {
257
+ /**
258
+ * Loads the gist cache from GitHub, containing mappings of YAML configuration names to gist IDs.
259
+ * If no cache exists, creates a new empty cache gist.
260
+ *
261
+ * @returns An Effect that yields a GistCache containing the loaded cache entries and cache gist ID
262
+ */
263
+ loadGistCache,
264
+ /**
265
+ * Saves the current gist cache state to the GitHub cache gist.
266
+ * Updates the existing cache gist with the current mappings of names to gist IDs.
267
+ *
268
+ * @param cache - The GistCache instance to save
269
+ * @returns An Effect that succeeds when the cache is successfully saved
270
+ */
271
+ saveGistCache,
272
+ /**
273
+ * Creates a new GitHub gist with the specified files and updates the local cache.
274
+ * Generates a GitHub CLI command to create the gist and extracts the resulting gist ID.
275
+ *
276
+ * @param cache - The current GistCache instance
277
+ * @param name - The human-readable name for this gist (used in cache mapping)
278
+ * @param description - The description for the GitHub gist
279
+ * @param files - Array of file paths to include in the gist
280
+ * @param is_public - Whether the gist should be public or private
281
+ * @returns An Effect that yields an updated GistCache with the new gist entry
282
+ */
283
+ createGistWithFiles,
284
+ /**
285
+ * Retrieves file names from a GitHub gist.
286
+ * Fetches the list of files contained in the specified gist.
287
+ *
288
+ * @param gist_id - The GitHub gist ID to retrieve file names from
289
+ * @param gist_name - The human-readable name of the gist (for logging purposes)
290
+ * @returns An Effect that yields an array of file names
291
+ */
292
+ getGistFileNames,
293
+ /**
294
+ * Removes a file from a specified GitHub gist.
295
+ * @param gist_id - The ID of the gist to modify
296
+ * @param gist_name - The human-readable name of the gist (for logging purposes)
297
+ * @param file_name - The name of the file to remove from the gist
298
+ * @returns An Effect that succeeds when the file is removed
299
+ */
300
+ removeFileFromGist,
301
+ /**
302
+ * Updates a file in a specified GitHub gist.
303
+ * @param gist_id - The ID of the gist to modify
304
+ * @param gist_name - The human-readable name of the gist (for logging purposes)
305
+ * @param file_name - The name of the file to remove from the gist
306
+ * @param file_path - The local path of the file to update in the gist
307
+ * @returns An Effect that succeeds when the file is updated
308
+ */
309
+ updateFileOfGist,
310
+ /**
311
+ * Adds a new file to a specified GitHub gist.
312
+ * @param gist_id - The ID of the gist to modify
313
+ * @param gist_name - The human-readable name of the gist (for logging purposes)
314
+ * @param file_path - The local path of the file to add to the gist
315
+ * @returns An Effect that succeeds when the file is added
316
+ */
317
+ addFileToGist
318
+ };
319
+ })
320
+ }) {
321
+ }
322
+ // @effect-diagnostics-next-line missingEffectServiceDependency:off
323
+ export class GistHandler extends Effect.Service()("GistHandler", {
324
+ accessors: true,
325
+ dependencies: [GHGistService.Default],
326
+ effect: Effect.gen(function* () {
327
+ const GH = yield* GHGistService;
328
+ // I prefer to provide these two only once during the main CLI pipeline setup
329
+ const fs = yield* FileSystem.FileSystem;
330
+ const path = yield* Path.Path;
331
+ return {
332
+ handler: Effect.fn("effa-cli.gist.GistHandler")(function* ({ YAMLPath }) {
333
+ yield* Effect.logInfo(`Reading configuration from ${YAMLPath}`);
334
+ const configExists = yield* fs.exists(YAMLPath);
335
+ if (!configExists) {
336
+ return yield* Effect.fail(new Error(`Configuration file not found: ${YAMLPath}`));
337
+ }
338
+ const config = yield* pipe(YAMLPath, fs.readFileString, Effect.andThen((content) => Effect.try({
339
+ try: () => yaml.load(content),
340
+ catch(error) {
341
+ return new GistYAMLError({ reason: `Failed to parse YAML: ${error.message}` });
342
+ }
343
+ })), Effect.andThen(Schema.decodeUnknown(GistYAML)));
344
+ // load GitHub token securely from environment variable
345
+ const redactedToken = yield* Config.redacted(config.settings.token_env);
346
+ yield* Effect.logInfo(`Using GitHub token from environment variable: ${config.settings.token_env}`);
347
+ yield* Effect.logInfo(`Token loaded: ${redactedToken}`); // this will show <redacted> in logs
348
+ const cache = yield* SynchronizedRef.make(yield* GH.loadGistCache());
349
+ // handle each gist entry in the configuration
350
+ for (const [name, gistConfig] of Object.entries(config.gists)) {
351
+ const { description, files_with_name, public: is_public } = gistConfig;
352
+ yield* Effect.logInfo(`Processing gist ${name}`);
353
+ const filesOnDiskWithFullPath = yield* Effect
354
+ .all(files_with_name.map((f) => Effect.gen(function* () {
355
+ const fullPath = path.join(config.settings.base_directory, f.path);
356
+ const fileExists = yield* fs.exists(fullPath);
357
+ if (!fileExists) {
358
+ yield* Effect.logWarning(`File not found: ${fullPath}, skipping...`);
359
+ return Option.none();
360
+ }
361
+ return Option.some({
362
+ path: fullPath,
363
+ name: f.name
364
+ });
365
+ })), {
366
+ concurrency: "unbounded"
367
+ })
368
+ .pipe(Effect.map(Array.getSomes));
369
+ const gistFromCache = (yield* SynchronizedRef.get(cache)).entries.find((_) => _.name === name);
370
+ // if the gist's name exists in cache, update the existing gist
371
+ // otherwise, create a new gist and update the local cache
372
+ if (gistFromCache) {
373
+ yield* Effect.logInfo(`Updating existing gist ${gistFromCache.name} with ID ${gistFromCache.id}`);
374
+ // get current files in the gist to detect removed files
375
+ const gistFileNames = new Set(yield* GH.getGistFileNames({
376
+ gist_id: gistFromCache.id,
377
+ gist_name: gistFromCache.name
378
+ }));
379
+ const expectedFiles = new Set(filesOnDiskWithFullPath.map(({ name }) => name));
380
+ // remove files that are no longer in YAML configuration
381
+ for (const gf of gistFileNames) {
382
+ if (!expectedFiles.has(gf)) {
383
+ yield* GH.removeFileFromGist({
384
+ gist_id: gistFromCache.id,
385
+ gist_name: gistFromCache.name,
386
+ file_name: gf
387
+ });
388
+ }
389
+ }
390
+ // update/add files from configuration
391
+ for (const f of filesOnDiskWithFullPath) {
392
+ if (gistFileNames.has(f.name)) {
393
+ yield* GH.updateFileOfGist({
394
+ gist_id: gistFromCache.id,
395
+ gist_name: gistFromCache.name,
396
+ file_name: f.name,
397
+ file_path: f.path
398
+ });
399
+ }
400
+ else {
401
+ yield* GH.addFileToGist({
402
+ gist_id: gistFromCache.id,
403
+ gist_name: gistFromCache.name,
404
+ file_path: f.path
405
+ });
406
+ }
407
+ }
408
+ }
409
+ else {
410
+ if (filesOnDiskWithFullPath.length !== 0) {
411
+ yield* SynchronizedRef.getAndUpdateEffect(cache, (cache) => {
412
+ return GH.createGistWithFiles({
413
+ gist_name: name,
414
+ description,
415
+ is_public,
416
+ cache,
417
+ files: filesOnDiskWithFullPath.map((f) => f.path)
418
+ });
419
+ });
420
+ }
421
+ else {
422
+ yield* Effect.logWarning(`No valid files found for gist ${name}, skipping creation...`);
423
+ }
424
+ }
425
+ // here the local cache has been updated, but not yet saved to GitHub
426
+ // we still want to remove gists from cache that are no longer in the configuration
427
+ const configGistNames = new Set(Object.entries(config.gists).map(([name]) => name));
428
+ const newCache = yield* SynchronizedRef.updateAndGetEffect(cache, Effect.fnUntraced(function* (cache) {
429
+ const newEntries = [...cache.entries];
430
+ for (let i = newEntries.length - 1; i >= 0; i--) {
431
+ const cacheEntry = newEntries[i];
432
+ if (cacheEntry && !configGistNames.has(cacheEntry.name)) {
433
+ yield* Effect.logInfo(`Obsolete gist ${cacheEntry.name} with ID ${cacheEntry.id}) will be removed from cache`);
434
+ newEntries.splice(i, 1);
435
+ }
436
+ }
437
+ return { ...cache, entries: newEntries };
438
+ }));
439
+ yield* GH.saveGistCache(newCache);
440
+ yield* Effect.logInfo("Gist operations completed");
441
+ }
442
+ })
443
+ };
444
+ })
445
+ }) {
446
+ }
447
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZ2lzdC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9naXN0LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLGtEQUFrRDtBQUNsRCxxQ0FBcUM7QUFDckMsOENBQThDO0FBQzlDLE9BQU8sRUFBRSxVQUFVLEVBQUUsSUFBSSxFQUFFLE1BQU0sa0JBQWtCLENBQUE7QUFFbkQsT0FBTyxFQUFFLEtBQUssRUFBRSxNQUFNLEVBQUUsSUFBSSxFQUFFLE1BQU0sRUFBRSxNQUFNLEVBQUUsV0FBVyxFQUFFLElBQUksRUFBRSxNQUFNLEVBQUUsZUFBZSxFQUFFLE1BQU0sUUFBUSxDQUFBO0FBQ3hHLE9BQU8sS0FBSyxJQUFJLE1BQU0sU0FBUyxDQUFBO0FBQy9CLE9BQU8sSUFBSSxNQUFNLE1BQU0sQ0FBQTtBQUN2QixPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQTtBQUVuRCxFQUFFO0FBQ0YsRUFBRTtBQUNGLFVBQVU7QUFDVixFQUFFO0FBRUYsTUFBTSxPQUFPLFNBQVUsU0FBUSxNQUFNLENBQUMsS0FBSyxDQUFZLFdBQVcsQ0FBQyxDQUFDO0lBQ2xFLFdBQVcsRUFBRSxNQUFNLENBQUMsTUFBTTtJQUMxQixNQUFNLEVBQUUsTUFBTSxDQUFDLE9BQU87SUFDdEIsS0FBSyxFQUFFLE1BQU0sQ0FBQyxLQUFLLENBQUMsTUFBTSxDQUFDLE1BQU0sQ0FBQztDQUNuQyxDQUFDO0NBQUc7QUFFTDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0FvQkc7QUFDSCxNQUFNLE9BQU8sZ0JBQWlCLFNBQVEsU0FBUyxDQUFDLGVBQWUsQ0FBbUIsa0JBQWtCLENBQUMsQ0FBQztJQUNwRyxlQUFlLEVBQUUsTUFBTSxDQUFDLEtBQUssQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDO1FBQzFDLElBQUksRUFBRSxNQUFNLENBQUMsTUFBTTtRQUNuQixJQUFJLEVBQUUsTUFBTSxDQUFDLE1BQU07S0FDcEIsQ0FBQyxDQUFDO0NBQ0osRUFBRTtJQUNELE1BQU0sRUFBRSxNQUFNLENBQUMsVUFBVSxDQUFDLFFBQVEsQ0FBQyxFQUFDLEtBQUssRUFBRSxDQUFDLEVBQUUsR0FBRztRQUMvQyxNQUFNLGVBQWUsR0FBRyxLQUFLLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLElBQUksRUFBRSxFQUFFLENBQUMsQ0FBQztZQUNqRCxJQUFJLEVBQUUsSUFBSTtZQUNWLElBQUksRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLElBQUksQ0FBQyxDQUFDLCtHQUErRztTQUMxSSxDQUFDLENBQUMsQ0FBQTtRQUVILGlDQUFpQztRQUNqQyxNQUFNLE9BQU8sR0FBRyxJQUFJLEdBQUcsRUFBb0IsQ0FBQTtRQUMzQyxLQUFLLE1BQU0sRUFBRSxJQUFJLEVBQUUsSUFBSSxFQUFFLFFBQVEsRUFBRSxJQUFJLGVBQWUsRUFBRSxDQUFDO1lBQ3ZELElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7Z0JBQ3ZCLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLEVBQUUsQ0FBQyxDQUFBO1lBQ3ZCLENBQUM7WUFDRCxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBRSxDQUFDLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQTtRQUNuQyxDQUFDO1FBRUQsNkNBQTZDO1FBQzdDLE1BQU0sVUFBVSxHQUE2QixFQUFFLENBQUE7UUFDL0MsS0FBSyxNQUFNLENBQUMsUUFBUSxFQUFFLEtBQUssQ0FBQyxJQUFJLE9BQU8sQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDO1lBQ2xELElBQUksS0FBSyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDckIsVUFBVSxDQUFDLElBQUksQ0FDYixJQUFJLFdBQVcsQ0FBQyxJQUFJLENBQ2xCLEdBQUcsRUFDSCxLQUFLLEVBQ0wsa0NBQWtDLFFBQVEsdUJBQXVCLEtBQUssQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FDcEYsQ0FDRixDQUFBO1lBQ0gsQ0FBQztRQUNILENBQUM7UUFFRCxxREFBcUQ7UUFDckQsSUFBSSxLQUFLLENBQUMsZUFBZSxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7WUFDdEMsT0FBTyxLQUFLLENBQUMsQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUN2QixJQUFJLFdBQVcsQ0FBQyxTQUFTLENBQ3ZCLEdBQUcsRUFDSCxLQUFLLENBQUMsS0FBSyxFQUNYLFVBQVUsQ0FDWCxDQUNGLENBQUE7UUFDSCxDQUFDO1FBRUQsT0FBTyxLQUFLLENBQUMsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDO1lBQzNCLEdBQUcsS0FBSztZQUNSLGVBQWU7U0FDaEIsQ0FBQyxDQUFBO0lBQ0osQ0FBQyxDQUFDO0lBQ0YsTUFBTSxFQUFFLENBQUMsQ0FBQyxFQUFFLGVBQWUsRUFBRSxHQUFHLEtBQUssRUFBRSxFQUFFLEVBQUUsQ0FBQyxXQUFXLENBQUMsT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDO0NBQ3hFLENBQUM7Q0FBRztBQUVMLE1BQU0sT0FBTyxRQUFTLFNBQVEsTUFBTSxDQUFDLEtBQUssQ0FBVyxVQUFVLENBQUMsQ0FBQztJQUMvRCxLQUFLLEVBQUUsTUFBTSxDQUFDLE1BQU0sQ0FBQztRQUNuQixHQUFHLEVBQUUsTUFBTSxDQUFDLE1BQU07UUFDbEIsS0FBSyxFQUFFLGdCQUFnQjtLQUN4QixDQUFDO0lBQ0YsUUFBUSxFQUFFLE1BQU0sQ0FBQyxNQUFNLENBQUM7UUFDdEIsU0FBUyxFQUFFLE1BQU0sQ0FBQyxNQUFNO1FBQ3hCLGNBQWMsRUFBRSxNQUFNLENBQUMsTUFBTTtLQUM5QixDQUFDO0NBQ0gsQ0FBQztDQUFHO0FBRUwsTUFBTSxPQUFPLGNBQWUsU0FBUSxNQUFNLENBQUMsS0FBSyxDQUFpQixnQkFBZ0IsQ0FBQyxDQUFDO0lBQ2pGLElBQUksRUFBRSxNQUFNLENBQUMsTUFBTTtJQUNuQixFQUFFLEVBQUUsTUFBTSxDQUFDLE1BQU07Q0FDbEIsQ0FBQztDQUFHO0FBRUwsTUFBTSxDQUFDLE1BQU0sZ0JBQWdCLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxjQUFjLENBQUMsQ0FBQTtBQUc1RDs7Ozs7Ozs7Ozs7R0FXRztBQUNILE1BQU0sT0FBTyxTQUFTO0lBQ3BCLE9BQU8sQ0FBa0I7SUFDekIsT0FBTyxDQUFRO0lBRWYsWUFBWSxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQWtEO1FBQzlFLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFBO1FBQ3RCLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFBO0lBQ3hCLENBQUM7Q0FDRjtBQUVELEVBQUU7QUFDRixFQUFFO0FBQ0YsU0FBUztBQUNULEVBQUU7QUFDRixNQUFNLGlCQUFrQixTQUFRLElBQUksQ0FBQyxXQUFXLENBQUMsbUJBQW1CLENBRWxFO0NBQUc7QUFFTCxNQUFNLGFBQWMsU0FBUSxJQUFJLENBQUMsV0FBVyxDQUFDLGVBQWUsQ0FFMUQ7Q0FBRztBQUVMLEVBQUU7QUFDRixFQUFFO0FBQ0YsV0FBVztBQUNYLEVBQUU7QUFFRixNQUFNLGFBQWMsU0FBUSxNQUFNLENBQUMsT0FBTyxFQUFpQixDQUFDLGVBQWUsRUFBRTtJQUMzRSxZQUFZLEVBQUUsQ0FBQyxpQkFBaUIsQ0FBQyxPQUFPLENBQUM7SUFDekMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDO1FBQzFCLE1BQU0sc0JBQXNCLEdBQUcsMENBQTBDLENBQUE7UUFDekUsTUFBTSxFQUFFLGNBQWMsRUFBRSxZQUFZLEVBQUUsR0FBRyxLQUFLLENBQUMsQ0FBQyxpQkFBaUIsQ0FBQTtRQUVqRSxnSEFBZ0g7UUFDaEgsTUFBTSx3QkFBd0IsR0FBRyxDQUFDLEdBQUcsSUFBdUMsRUFBRSxFQUFFO1lBQzlFLE9BQU8sY0FBYyxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUMsSUFBSSxDQUNqQyxNQUFNLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLG1CQUFtQixJQUFJLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxZQUFZLENBQUMsQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDLEVBQ25HLE1BQU0sQ0FBQyxNQUFNLENBQ2QsQ0FBQTtRQUNILENBQUMsQ0FBQTtRQUVELGdIQUFnSDtRQUNoSCxNQUFNLHNCQUFzQixHQUFHLENBQUMsR0FBRyxJQUFxQyxFQUFFLEVBQUU7WUFDMUUsT0FBTyxZQUFZLENBQUMsR0FBRyxJQUFJLENBQUMsQ0FBQyxJQUFJLENBQy9CLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLEVBQUUsRUFBRSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsbUJBQW1CLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLFlBQVksQ0FBQyxDQUFDLE9BQU8sRUFBRSxDQUFDLENBQUMsQ0FDcEcsQ0FBQTtRQUNILENBQUMsQ0FBQTtRQUVEOzs7O1dBSUc7UUFDSCxTQUFTLG9CQUFvQixDQUFDLEdBQVc7WUFDdkMsTUFBTSxPQUFPLEdBQUcsR0FBRyxDQUFDLElBQUksRUFBRSxDQUFDLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLEVBQUUsQ0FBQTtZQUMzQyxPQUFPLE9BQU8sSUFBSSxPQUFPLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLENBQUMsTUFBTSxDQUFDLElBQUksRUFBRSxDQUFBO1FBQzdFLENBQUM7UUFFRCxNQUFNLGFBQWEsR0FBRyxNQUFNO2FBQ3pCLEVBQUUsQ0FBQyw2QkFBNkIsQ0FBQyxDQUNoQyxRQUFRLENBQUM7WUFDUCxpQ0FBaUM7WUFDakMsTUFBTSxNQUFNLEdBQUcsS0FBSyxDQUFDLENBQUMsc0JBQXNCLENBQUMsMEJBQTBCLHNCQUFzQixHQUFHLENBQUM7aUJBQzlGLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDLENBQUMsQ0FBQyxDQUFBO1lBRWhELE1BQU0sS0FBSyxHQUFHLE1BQU0sQ0FBQyxJQUFJLEVBQUUsQ0FBQyxLQUFLLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxDQUFDLENBQUMsSUFBWSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQTtZQUU3RSxtREFBbUQ7WUFDbkQsTUFBTSxTQUFTLEdBQUcsS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFBO1lBQzFCLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQztnQkFDZixPQUFPLEtBQUssQ0FBQyxDQUFDLElBQUksaUJBQWlCLENBQUMsRUFBRSxNQUFNLEVBQUUsd0JBQXdCLEVBQUUsQ0FBQyxDQUFBO1lBQzNFLENBQUM7WUFFRCxNQUFNLEtBQUssR0FBRyxTQUFTLENBQUMsS0FBSyxDQUFDLEtBQUssQ0FBQyxDQUFBO1lBQ3BDLE1BQU0sT0FBTyxHQUFHLEtBQUssQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLEVBQUUsQ0FBQTtZQUVoQyxJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQ2IsT0FBTyxLQUFLLENBQUMsQ0FBQyxJQUFJLGlCQUFpQixDQUFDLEVBQUUsTUFBTSxFQUFFLDRCQUE0QixFQUFFLENBQUMsQ0FBQTtZQUMvRSxDQUFDO2lCQUFNLENBQUM7Z0JBQ04sS0FBSyxDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxxQ0FBcUMsT0FBTyxFQUFFLENBQUMsQ0FBQTtZQUN2RSxDQUFDO1lBRUQsMEJBQTBCO1lBQzFCLE1BQU0sWUFBWSxHQUFHLEtBQUssQ0FBQyxDQUFDLHNCQUFzQixDQUFDLGdCQUFnQixPQUFPLEVBQUUsQ0FBQztpQkFDMUUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsR0FBRyxFQUFFLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFDLENBQUE7WUFFaEQsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLENBQUMsSUFBSSxDQUN6QixZQUFZLENBQUMsS0FBSyxDQUFDLHNCQUFzQixDQUFDLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLEVBQ3JELElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLGdCQUFnQixDQUFDLEVBQUUsTUFBTSxDQUFDLGFBQWEsQ0FBQyxFQUM5RCxNQUFNLENBQUMsTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDLElBQUksaUJBQWlCLENBQUMsRUFBRSxNQUFNLEVBQUUsNEJBQTRCLEVBQUUsQ0FBQyxDQUFDLENBQ3JGLENBQUE7WUFFRCxPQUFPLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxDQUFBO1FBQzdCLENBQUMsRUFDRCxNQUFNLENBQUMsUUFBUSxDQUFDLG1CQUFtQixFQUFFLEdBQUcsRUFBRSxDQUN4QyxNQUFNLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQztZQUNsQixpQ0FBaUM7WUFDakMsS0FBSyxDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyw2Q0FBNkMsQ0FBQyxDQUFBO1lBRXBFLE1BQU0sU0FBUyxHQUFHLEtBQUssQ0FBQyxDQUFDLElBQUksQ0FDM0IsRUFBRSxFQUNGLElBQUksQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLGdCQUFnQixDQUFDLEVBQUUsTUFBTSxDQUFDLGFBQWEsQ0FBQztZQUM5RCx1R0FBdUc7WUFDdkcsTUFBTSxDQUFDLEtBQUssQ0FDYixDQUFBO1lBRUQsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLENBQUMsc0JBQXNCLENBQzNDLFNBQVMsU0FBUyw4QkFBOEIsc0JBQXNCLEtBQUssQ0FDNUUsQ0FBQTtZQUVELE1BQU0sT0FBTyxHQUFHLEtBQUssQ0FBQyxDQUFDLElBQUksQ0FDekIsT0FBTyxFQUNQLG9CQUFvQixFQUNwQixNQUFNLENBQUMsS0FBSyxDQUFDO2dCQUNYLE1BQU0sRUFBRSxHQUFHLEVBQUUsQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLCtDQUErQyxPQUFPLEVBQUUsQ0FBQztnQkFDekYsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFLEVBQUUsQ0FDYixNQUFNLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsa0NBQWtDLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQzthQUM5RixDQUFDLENBQ0gsQ0FBQTtZQUVELE9BQU8sRUFBRSxPQUFPLEVBQUUsRUFBRSxFQUFFLE9BQU8sRUFBRSxDQUFBO1FBQ2pDLENBQUMsQ0FBQyxDQUFDLEVBQ0wsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsT0FBTyxFQUFFLE9BQU8sRUFBRSxFQUFFLEVBQUUsQ0FBQyxJQUFJLFNBQVMsQ0FBQyxFQUFFLE9BQU8sRUFBRSxPQUFPLEVBQUUsQ0FBQyxDQUFDLENBQzFFLENBQUE7UUFFSCxNQUFNLGFBQWEsR0FBRyxNQUFNLENBQUMsRUFBRSxDQUFDLDZCQUE2QixDQUFDLENBQzVELFFBQVEsQ0FBQyxFQUFDLEtBQWdCO1lBQ3hCLE1BQU0sU0FBUyxHQUFHLEtBQUssQ0FBQyxDQUFDLElBQUksQ0FDM0IsS0FBSyxDQUFDLE9BQU8sRUFDYixJQUFJLENBQUMsTUFBTSxDQUFDLFNBQVMsQ0FBQyxnQkFBZ0IsQ0FBQyxFQUFFLE1BQU0sQ0FBQyxhQUFhLENBQUM7WUFDOUQsdUdBQXVHO1lBQ3ZHLE1BQU0sQ0FBQyxLQUFLLENBQ2IsQ0FBQTtZQUVELEtBQUssQ0FBQyxDQUFDLHdCQUF3QixDQUFDLFNBQVMsU0FBUyxvQkFBb0IsS0FBSyxDQUFDLE9BQU8sSUFBSSxDQUFDLENBQUE7UUFDMUYsQ0FBQyxDQUNGLENBQUE7UUFFRCxNQUFNLG1CQUFtQixHQUFHLE1BQU0sQ0FBQyxFQUFFLENBQUMsbUNBQW1DLENBQUMsQ0FDeEUsUUFBUSxDQUFDLEVBQUMsRUFBRSxLQUFLLEVBQUUsV0FBVyxFQUFFLEtBQUssRUFBRSxTQUFTLEVBQUUsU0FBUyxFQU0xRDtZQUNDLEtBQUssQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsaUJBQWlCLFNBQVMsU0FBUyxLQUFLLENBQUMsTUFBTSxVQUFVLENBQUMsQ0FBQTtZQUVoRixNQUFNLFNBQVMsR0FBRztnQkFDaEIsSUFBSTtnQkFDSixNQUFNO2dCQUNOLFFBQVE7Z0JBQ1IsV0FBVyxXQUFXLEdBQUc7Z0JBQ3pCLFNBQVMsQ0FBQyxDQUFDLENBQUMsVUFBVSxDQUFDLENBQUMsQ0FBQyxFQUFFO2dCQUMzQixHQUFHLEtBQUssQ0FBQyxHQUFHLENBQUMsQ0FBQyxRQUFRLEVBQUUsRUFBRSxDQUFDLElBQUksUUFBUSxHQUFHLENBQUM7YUFDNUM7aUJBQ0UsTUFBTSxDQUFDLENBQUMsQ0FBQyxFQUFFLEVBQUUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO2lCQUNsQixJQUFJLENBQUMsR0FBRyxDQUFDLENBQUE7WUFFWiwwQ0FBMEM7WUFDMUMsTUFBTSxPQUFPLEdBQUcsS0FBSyxDQUFDLENBQUMsc0JBQXNCLENBQUMsU0FBUyxDQUFDLENBQUE7WUFFeEQsc0JBQXNCO1lBQ3RCLE9BQU8sS0FBSyxDQUFDLENBQUMsSUFBSSxDQUNoQixPQUFPLEVBQ1Asb0JBQW9CLEVBQ3BCLE1BQU0sQ0FBQyxLQUFLLENBQUM7Z0JBQ1gsTUFBTSxFQUFFLEdBQUcsRUFBRSxDQUFDLE1BQU0sQ0FBQyxVQUFVLENBQUMsdUNBQXVDLE9BQU8sRUFBRSxDQUFDO2dCQUNqRixNQUFNLEVBQUUsQ0FBQyxFQUFFLEVBQUUsRUFBRSxDQUNiLE1BQU07cUJBQ0gsT0FBTyxDQUNOLElBQUksU0FBUyxDQUFDO29CQUNaLE9BQU8sRUFBRSxLQUFLLENBQUMsT0FBTztvQkFDdEIsT0FBTyxFQUFFLENBQUMsR0FBRyxLQUFLLENBQUMsT0FBTyxFQUFFLEVBQUUsSUFBSSxFQUFFLFNBQVMsRUFBRSxFQUFFLEVBQUUsQ0FBQztpQkFDckQsQ0FBQyxDQUNIO3FCQUNBLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsd0JBQXdCLEVBQUUsRUFBRSxDQUFDLENBQUMsQ0FBQzthQUNwRSxDQUFDLENBQ0gsQ0FBQTtRQUNILENBQUMsQ0FDRixDQUFBO1FBRUQsTUFBTSxnQkFBZ0IsR0FBRyxNQUFNLENBQUMsRUFBRSxDQUFDLGtCQUFrQixDQUFDLENBQ3BELFFBQVEsQ0FBQyxFQUFDLEVBQUUsT0FBTyxFQUFFLFNBQVMsRUFHN0I7WUFDQyxLQUFLLENBQUMsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLG1DQUFtQyxTQUFTLFlBQVksT0FBTyxFQUFFLENBQUMsQ0FBQTtZQUN4RixNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsQ0FBQyxzQkFBc0IsQ0FBQyxnQkFBZ0IsT0FBTyxVQUFVLENBQUMsQ0FBQTtZQUMvRSxPQUFPLE1BQU07aUJBQ1YsSUFBSSxFQUFFO2lCQUNOLEtBQUssQ0FBQyxJQUFJLENBQUM7aUJBQ1gsTUFBTSxDQUFDLENBQUMsSUFBWSxFQUFFLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUMsQ0FBQTtRQUMxQyxDQUFDLENBQ0YsQ0FBQTtRQUVELE1BQU0sa0JBQWtCLEdBQUcsTUFBTSxDQUFDLEVBQUUsQ0FBQyxvQkFBb0IsQ0FBQyxDQUN4RCxRQUFRLENBQUMsRUFBQyxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUl4QztZQUNDLEtBQUssQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsaUJBQWlCLFNBQVMsY0FBYyxTQUFTLEVBQUUsQ0FBQyxDQUFBO1lBQzFFLE9BQU8sS0FBSyxDQUFDLENBQUMsd0JBQXdCLENBQUMsZ0JBQWdCLE9BQU8sY0FBYyxTQUFTLEdBQUcsQ0FBQyxDQUFBO1FBQzNGLENBQUMsQ0FDRixDQUFBO1FBRUQsTUFBTSxnQkFBZ0IsR0FBRyxNQUFNLENBQUMsRUFBRSxDQUFDLGtCQUFrQixDQUFDLENBQ3BELFFBQVEsQ0FBQyxFQUFDLEVBQUUsU0FBUyxFQUFFLFNBQVMsRUFBRSxPQUFPLEVBQUUsU0FBUyxFQUtuRDtZQUNDLEtBQUssQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsaUJBQWlCLFNBQVMsZUFBZSxTQUFTLFlBQVksU0FBUyxFQUFFLENBQUMsQ0FBQTtZQUNoRyxNQUFNLFdBQVcsR0FBRztnQkFDbEIsSUFBSTtnQkFDSixNQUFNO2dCQUNOLE1BQU07Z0JBQ04sT0FBTztnQkFDUCxJQUFJO2dCQUNKLFNBQVM7Z0JBQ1QsSUFBSSxTQUFTLEdBQUc7YUFDakI7aUJBQ0UsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFBO1lBRVosT0FBTyxLQUFLLENBQUMsQ0FBQyx3QkFBd0IsQ0FBQyxXQUFXLENBQUMsQ0FBQTtRQUNyRCxDQUFDLENBQ0YsQ0FBQTtRQUVELE1BQU0sYUFBYSxHQUFHLE1BQU0sQ0FBQyxFQUFFLENBQUMsZUFBZSxDQUFDLENBQzlDLFFBQVEsQ0FBQyxFQUFDLEVBQUUsU0FBUyxFQUFFLE9BQU8sRUFBRSxTQUFTLEVBSXhDO1lBQ0MsS0FBSyxDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxlQUFlLFNBQVMsWUFBWSxTQUFTLEVBQUUsQ0FBQyxDQUFBO1lBQ3RFLE1BQU0sV0FBVyxHQUFHO2dCQUNsQixJQUFJO2dCQUNKLE1BQU07Z0JBQ04sTUFBTTtnQkFDTixPQUFPO2dCQUNQLElBQUk7Z0JBQ0osSUFBSSxTQUFTLEdBQUc7YUFDakI7aUJBQ0UsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFBO1lBRVosT0FBTyxLQUFLLENBQUMsQ0FBQyx3QkFBd0IsQ0FBQyxXQUFXLENBQUMsQ0FBQTtRQUNyRCxDQUFDLENBQ0YsQ0FBQTtRQUVELE9BQU87WUFDTDs7Ozs7ZUFLRztZQUNILGFBQWE7WUFFYjs7Ozs7O2VBTUc7WUFDSCxhQUFhO1lBRWI7Ozs7Ozs7Ozs7ZUFVRztZQUNILG1CQUFtQjtZQUVuQjs7Ozs7OztlQU9HO1lBQ0gsZ0JBQWdCO1lBRWhCOzs7Ozs7ZUFNRztZQUNILGtCQUFrQjtZQUVsQjs7Ozs7OztlQU9HO1lBQ0gsZ0JBQWdCO1lBRWhCOzs7Ozs7ZUFNRztZQUNILGFBQWE7U0FDZCxDQUFBO0lBQ0gsQ0FBQyxDQUFDO0NBQ0gsQ0FBQztDQUFHO0FBRUwsbUVBQW1FO0FBQ25FLE1BQU0sT0FBTyxXQUFZLFNBQVEsTUFBTSxDQUFDLE9BQU8sRUFBZSxDQUFDLGFBQWEsRUFBRTtJQUM1RSxTQUFTLEVBQUUsSUFBSTtJQUNmLFlBQVksRUFBRSxDQUFDLGFBQWEsQ0FBQyxPQUFPLENBQUM7SUFDckMsTUFBTSxFQUFFLE1BQU0sQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDO1FBQzFCLE1BQU0sRUFBRSxHQUFHLEtBQUssQ0FBQyxDQUFDLGFBQWEsQ0FBQTtRQUUvQiw2RUFBNkU7UUFDN0UsTUFBTSxFQUFFLEdBQUcsS0FBSyxDQUFDLENBQUMsVUFBVSxDQUFDLFVBQVUsQ0FBQTtRQUN2QyxNQUFNLElBQUksR0FBRyxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFBO1FBRTdCLE9BQU87WUFDTCxPQUFPLEVBQUUsTUFBTSxDQUFDLEVBQUUsQ0FBQywyQkFBMkIsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxFQUFDLEVBQUUsUUFBUSxFQUF3QjtnQkFDMUYsS0FBSyxDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyw4QkFBOEIsUUFBUSxFQUFFLENBQUMsQ0FBQTtnQkFFL0QsTUFBTSxZQUFZLEdBQUcsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQTtnQkFDL0MsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO29CQUNsQixPQUFPLEtBQUssQ0FBQyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxLQUFLLENBQUMsaUNBQWlDLFFBQVEsRUFBRSxDQUFDLENBQUMsQ0FBQTtnQkFDbkYsQ0FBQztnQkFFRCxNQUFNLE1BQU0sR0FBRyxLQUFLLENBQUMsQ0FBQyxJQUFJLENBQ3hCLFFBQVEsRUFDUixFQUFFLENBQUMsY0FBYyxFQUNqQixNQUFNLENBQUMsT0FBTyxDQUFDLENBQUMsT0FBTyxFQUFFLEVBQUUsQ0FDekIsTUFBTSxDQUFDLEdBQUcsQ0FBQztvQkFDVCxHQUFHLEVBQUUsR0FBRyxFQUFFLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUM7b0JBQzdCLEtBQUssQ0FBQyxLQUFLO3dCQUNULE9BQU8sSUFBSSxhQUFhLENBQUMsRUFBRSxNQUFNLEVBQUUseUJBQTBCLEtBQWUsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLENBQUE7b0JBQzNGLENBQUM7aUJBQ0YsQ0FBQyxDQUNILEVBQ0QsTUFBTSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxDQUFDLENBQy9DLENBQUE7Z0JBRUQsdURBQXVEO2dCQUN2RCxNQUFNLGFBQWEsR0FBRyxLQUFLLENBQUMsQ0FBQyxNQUFNLENBQUMsUUFBUSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsU0FBUyxDQUFDLENBQUE7Z0JBRXZFLEtBQUssQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsaURBQWlELE1BQU0sQ0FBQyxRQUFRLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQTtnQkFDbkcsS0FBSyxDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxpQkFBaUIsYUFBYSxFQUFFLENBQUMsQ0FBQSxDQUFDLG9DQUFvQztnQkFFNUYsTUFBTSxLQUFLLEdBQUcsS0FBSyxDQUFDLENBQUMsZUFBZSxDQUFDLElBQUksQ0FBWSxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsYUFBYSxFQUFFLENBQUMsQ0FBQTtnQkFFL0UsOENBQThDO2dCQUM5QyxLQUFLLE1BQU0sQ0FBQyxJQUFJLEVBQUUsVUFBVSxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLEVBQUUsQ0FBQztvQkFDOUQsTUFBTSxFQUFFLFdBQVcsRUFBRSxlQUFlLEVBQUUsTUFBTSxFQUFFLFNBQVMsRUFBRSxHQUFHLFVBQVUsQ0FBQTtvQkFFdEUsS0FBSyxDQUFDLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxtQkFBbUIsSUFBSSxFQUFFLENBQUMsQ0FBQTtvQkFFaEQsTUFBTSx1QkFBdUIsR0FBRyxLQUFLLENBQUMsQ0FBQyxNQUFNO3lCQUMxQyxHQUFHLENBQ0YsZUFBZSxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQ3hCLE1BQU0sQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDO3dCQUNsQixNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsY0FBYyxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsQ0FBQTt3QkFDbEUsTUFBTSxVQUFVLEdBQUcsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsQ0FBQTt3QkFFN0MsSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDOzRCQUNoQixLQUFLLENBQUMsQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLG1CQUFtQixRQUFRLGVBQWUsQ0FBQyxDQUFBOzRCQUNwRSxPQUFPLE1BQU0sQ0FBQyxJQUFJLEVBQUUsQ0FBQTt3QkFDdEIsQ0FBQzt3QkFFRCxPQUFPLE1BQU0sQ0FBQyxJQUFJLENBQUM7NEJBQ2pCLElBQUksRUFBRSxRQUFROzRCQUNkLElBQUksRUFBRSxDQUFDLENBQUMsSUFBSTt5QkFDYixDQUFDLENBQUE7b0JBQ0osQ0FBQyxDQUFDLENBQ0gsRUFDRDt3QkFDRSxXQUFXLEVBQUUsV0FBVztxQkFDekIsQ0FDRjt5QkFDQSxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsUUFBUSxDQUFDLENBQUMsQ0FBQTtvQkFFbkMsTUFBTSxhQUFhLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksS0FBSyxJQUFJLENBQUMsQ0FBQTtvQkFFOUYsK0RBQStEO29CQUMvRCwwREFBMEQ7b0JBQzFELElBQUksYUFBYSxFQUFFLENBQUM7d0JBQ2xCLEtBQUssQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQUMsMEJBQTBCLGFBQWEsQ0FBQyxJQUFJLFlBQVksYUFBYSxDQUFDLEVBQUUsRUFBRSxDQUFDLENBQUE7d0JBRWpHLHdEQUF3RDt3QkFDeEQsTUFBTSxhQUFhLEdBQUcsSUFBSSxHQUFHLENBQzNCLEtBQUssQ0FBQyxDQUFDLEVBQUUsQ0FBQyxnQkFBZ0IsQ0FBQzs0QkFDekIsT0FBTyxFQUFFLGFBQWEsQ0FBQyxFQUFFOzRCQUN6QixTQUFTLEVBQUUsYUFBYSxDQUFDLElBQUk7eUJBQzlCLENBQUMsQ0FDSCxDQUFBO3dCQUVELE1BQU0sYUFBYSxHQUFHLElBQUksR0FBRyxDQUFDLHVCQUF1QixDQUFDLEdBQUcsQ0FBQyxDQUFDLEVBQUUsSUFBSSxFQUFFLEVBQUUsRUFBRSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUE7d0JBRTlFLHdEQUF3RDt3QkFDeEQsS0FBSyxNQUFNLEVBQUUsSUFBSSxhQUFhLEVBQUUsQ0FBQzs0QkFDL0IsSUFBSSxDQUFDLGFBQWEsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsQ0FBQztnQ0FDM0IsS0FBSyxDQUFDLENBQUMsRUFBRSxDQUFDLGtCQUFrQixDQUFDO29DQUMzQixPQUFPLEVBQUUsYUFBYSxDQUFDLEVBQUU7b0NBQ3pCLFNBQVMsRUFBRSxhQUFhLENBQUMsSUFBSTtvQ0FDN0IsU0FBUyxFQUFFLEVBQUU7aUNBQ2QsQ0FBQyxDQUFBOzRCQUNKLENBQUM7d0JBQ0gsQ0FBQzt3QkFFRCxzQ0FBc0M7d0JBQ3RDLEtBQUssTUFBTSxDQUFDLElBQUksdUJBQXVCLEVBQUUsQ0FBQzs0QkFDeEMsSUFBSSxhQUFhLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO2dDQUM5QixLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsZ0JBQWdCLENBQUM7b0NBQ3pCLE9BQU8sRUFBRSxhQUFhLENBQUMsRUFBRTtvQ0FDekIsU0FBUyxFQUFFLGFBQWEsQ0FBQyxJQUFJO29DQUM3QixTQUFTLEVBQUUsQ0FBQyxDQUFDLElBQUk7b0NBQ2pCLFNBQVMsRUFBRSxDQUFDLENBQUMsSUFBSTtpQ0FDbEIsQ0FBQyxDQUFBOzRCQUNKLENBQUM7aUNBQU0sQ0FBQztnQ0FDTixLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsYUFBYSxDQUFDO29DQUN0QixPQUFPLEVBQUUsYUFBYSxDQUFDLEVBQUU7b0NBQ3pCLFNBQVMsRUFBRSxhQUFhLENBQUMsSUFBSTtvQ0FDN0IsU0FBUyxFQUFFLENBQUMsQ0FBQyxJQUFJO2lDQUNsQixDQUFDLENBQUE7NEJBQ0osQ0FBQzt3QkFDSCxDQUFDO29CQUNILENBQUM7eUJBQU0sQ0FBQzt3QkFDTixJQUFJLHVCQUF1QixDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQzs0QkFDekMsS0FBSyxDQUFDLENBQUMsZUFBZSxDQUFDLGtCQUFrQixDQUFDLEtBQUssRUFBRSxDQUFDLEtBQUssRUFBRSxFQUFFO2dDQUN6RCxPQUFPLEVBQUUsQ0FBQyxtQkFBbUIsQ0FBQztvQ0FDNUIsU0FBUyxFQUFFLElBQUk7b0NBQ2YsV0FBVztvQ0FDWCxTQUFTO29DQUNULEtBQUs7b0NBQ0wsS0FBSyxFQUFFLHVCQUF1QixDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsRUFBRSxFQUFFLENBQUMsQ0FBQyxDQUFDLElBQUksQ0FBQztpQ0FDbEQsQ0FBQyxDQUFBOzRCQUNKLENBQUMsQ0FBQyxDQUFBO3dCQUNKLENBQUM7NkJBQU0sQ0FBQzs0QkFDTixLQUFLLENBQUMsQ0FBQyxNQUFNLENBQUMsVUFBVSxDQUFDLGlDQUFpQyxJQUFJLHdCQUF3QixDQUFDLENBQUE7d0JBQ3pGLENBQUM7b0JBQ0gsQ0FBQztvQkFFRCxxRUFBcUU7b0JBQ3JFLG1GQUFtRjtvQkFFbkYsTUFBTSxlQUFlLEdBQUcsSUFBSSxHQUFHLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxJQUFJLENBQUMsRUFBRSxFQUFFLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQTtvQkFFbkYsTUFBTSxRQUFRLEdBQUcsS0FBSyxDQUFDLENBQUMsZUFBZSxDQUFDLGtCQUFrQixDQUN4RCxLQUFLLEVBQ0wsTUFBTSxDQUFDLFVBQVUsQ0FBQyxRQUFRLENBQUMsRUFBQyxLQUFLO3dCQUMvQixNQUFNLFVBQVUsR0FBRyxDQUFDLEdBQUcsS0FBSyxDQUFDLE9BQU8sQ0FBQyxDQUFBO3dCQUVyQyxLQUFLLElBQUksQ0FBQyxHQUFHLFVBQVUsQ0FBQyxNQUFNLEdBQUcsQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxFQUFFLEVBQUUsQ0FBQzs0QkFDaEQsTUFBTSxVQUFVLEdBQUcsVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFBOzRCQUNoQyxJQUFJLFVBQVUsSUFBSSxDQUFDLGVBQWUsQ0FBQyxHQUFHLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUM7Z0NBQ3hELEtBQUssQ0FBQyxDQUFDLE1BQU0sQ0FBQyxPQUFPLENBQ25CLGlCQUFpQixVQUFVLENBQUMsSUFBSSxZQUFZLFVBQVUsQ0FBQyxFQUFFLDhCQUE4QixDQUN4RixDQUFBO2dDQUNELFVBQVUsQ0FBQyxNQUFNLENBQUMsQ0FBQyxFQUFFLENBQUMsQ0FBQyxDQUFBOzRCQUN6QixDQUFDO3dCQUNILENBQUM7d0JBRUQsT0FBTyxFQUFFLEdBQUcsS0FBSyxFQUFFLE9BQU8sRUFBRSxVQUFVLEVBQUUsQ0FBQTtvQkFDMUMsQ0FBQyxDQUFDLENBQ0gsQ0FBQTtvQkFFRCxLQUFLLENBQUMsQ0FBQyxFQUFFLENBQUMsYUFBYSxDQUFDLFFBQVEsQ0FBQyxDQUFBO29CQUVqQyxLQUFLLENBQUMsQ0FBQyxNQUFNLENBQUMsT0FBTyxDQUFDLDJCQUEyQixDQUFDLENBQUE7Z0JBQ3BELENBQUM7WUFDSCxDQUFDLENBQUM7U0FDSCxDQUFBO0lBQ0gsQ0FBQyxDQUFDO0NBQ0gsQ0FBQztDQUFHIn0=