@eggjs/core 7.0.0-beta.19 → 7.0.0-beta.21

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.
@@ -1,1184 +1,1572 @@
1
- import utils_default from "../utils/index.js";
2
- import { Timing } from "../utils/timing.js";
1
+ import fs from 'node:fs';
2
+ import path from 'node:path';
3
+ import assert from 'node:assert';
4
+ import { debuglog, inspect } from 'node:util';
5
+ import { homedir } from 'node-homedir';
6
+ import { isAsyncFunction, isClass, isGeneratorFunction, isObject, isPromise } from 'is-type-of';
7
+ import { getParamNames, readJSONSync, readJSON, exists } from 'utility';
8
+ import { extend } from '@eggjs/extend2';
9
+ import { Request, Response, Application, Context as KoaContext } from '@eggjs/koa';
10
+ import { register as tsconfigPathsRegister } from 'tsconfig-paths';
11
+ import { isESM, isSupportTypeScript } from '@eggjs/utils';
12
+ import { pathMatching } from 'egg-path-matching';
13
+ import { now, diff } from 'performance-ms';
3
14
  import { CaseStyle, FULLPATH, FileLoader } from "./file_loader.js";
4
15
  import { ContextLoader } from "./context_loader.js";
16
+ import utils, {} from "../utils/index.js";
5
17
  import { sequencify } from "../utils/sequencify.js";
6
- import { debuglog, inspect } from "node:util";
7
- import path from "node:path";
8
- import fs from "node:fs";
9
- import { isESM, isSupportTypeScript } from "@eggjs/utils";
10
- import assert from "node:assert";
11
- import { Application, Context, Request, Response } from "@eggjs/koa";
12
- import { isAsyncFunction, isClass, isGeneratorFunction, isObject, isPromise } from "is-type-of";
13
- import { homedir } from "node-homedir";
14
- import { exists, getParamNames, readJSON, readJSONSync } from "utility";
15
- import { extend } from "@eggjs/extend2";
16
- import { register } from "tsconfig-paths";
17
- import { pathMatching } from "egg-path-matching";
18
- import { diff, now } from "performance-ms";
19
-
20
- //#region src/loader/egg_loader.ts
21
- const debug = debuglog("egg/core/loader/egg_loader");
18
+ import { Timing } from "../utils/timing.js";
19
+ const debug = debuglog('egg/core/loader/egg_loader');
22
20
  const originalPrototypes = {
23
- request: Request.prototype,
24
- response: Response.prototype,
25
- context: Context.prototype,
26
- application: Application.prototype
27
- };
28
- var EggLoader = class {
29
- #requiredCount = 0;
30
- options;
31
- timing;
32
- pkg;
33
- eggPaths;
34
- serverEnv;
35
- serverScope;
36
- appInfo;
37
- dirs;
38
- /**
39
- * @class
40
- * @param {Object} options - options
41
- * @param {String} options.baseDir - the directory of application
42
- * @param {EggCore} options.app - Application instance
43
- * @param {Logger} options.logger - logger
44
- * @param {Object} [options.plugins] - custom plugins
45
- * @since 1.0.0
46
- */
47
- constructor(options) {
48
- this.options = options;
49
- assert(fs.existsSync(this.options.baseDir), `${this.options.baseDir} not exists`);
50
- assert(this.options.app, "options.app is required");
51
- assert(this.options.logger, "options.logger is required");
52
- this.timing = this.app.timing || new Timing();
53
- /**
54
- * @member {Object} EggLoader#pkg
55
- * @see {@link AppInfo#pkg}
56
- * @since 1.0.0
57
- */
58
- this.pkg = readJSONSync(path.join(this.options.baseDir, "package.json"));
59
- if (process.env.EGG_TYPESCRIPT === "true" || this.pkg.egg && this.pkg.egg.typescript) {
60
- const tsConfigFile = path.join(this.options.baseDir, "tsconfig.json");
61
- if (fs.existsSync(tsConfigFile)) register({ cwd: this.options.baseDir });
62
- else this.logger.info("[@eggjs/core/egg_loader] skip register \"tsconfig-paths\" because tsconfig.json not exists at %s", tsConfigFile);
63
- }
64
- /**
65
- * All framework directories.
66
- *
67
- * You can extend Application of egg, the entry point is options.app,
68
- *
69
- * loader will find all directories from the prototype of Application,
70
- * you should define `Symbol.for('egg#eggPath')` property.
71
- *
72
- * ```ts
73
- * // src/example.ts
74
- * import { Application } from 'egg';
75
- * class ExampleApplication extends Application {
76
- * get [Symbol.for('egg#eggPath')]() {
77
- * return baseDir;
78
- * }
79
- * }
80
- * ```
81
- * @member {Array} EggLoader#eggPaths
82
- * @see EggLoader#getEggPaths
83
- * @since 1.0.0
84
- */
85
- this.eggPaths = this.getEggPaths();
86
- debug("Loaded eggPaths %j", this.eggPaths);
87
- /**
88
- * @member {String} EggLoader#serverEnv
89
- * @see AppInfo#env
90
- * @since 1.0.0
91
- */
92
- this.serverEnv = this.getServerEnv();
93
- debug("Loaded serverEnv %j", this.serverEnv);
94
- /**
95
- * @member {String} EggLoader#serverScope
96
- * @see AppInfo#serverScope
97
- */
98
- this.serverScope = options.serverScope ?? this.getServerScope();
99
- /**
100
- * @member {AppInfo} EggLoader#appInfo
101
- * @since 1.0.0
102
- */
103
- this.appInfo = this.getAppInfo();
104
- }
105
- get app() {
106
- return this.options.app;
107
- }
108
- get lifecycle() {
109
- return this.app.lifecycle;
110
- }
111
- get logger() {
112
- return this.options.logger;
113
- }
114
- /**
115
- * Get {@link AppInfo#env}
116
- * @returns {String} env
117
- * @see AppInfo#env
118
- * @private
119
- * @since 1.0.0
120
- */
121
- getServerEnv() {
122
- let serverEnv = this.options.env;
123
- const envPath = path.join(this.options.baseDir, "config/env");
124
- if (!serverEnv && fs.existsSync(envPath)) serverEnv = fs.readFileSync(envPath, "utf8").trim();
125
- if (!serverEnv && process.env.EGG_SERVER_ENV) serverEnv = process.env.EGG_SERVER_ENV;
126
- if (serverEnv) serverEnv = serverEnv.trim();
127
- else if (process.env.NODE_ENV === "test") serverEnv = "unittest";
128
- else if (process.env.NODE_ENV === "production") serverEnv = "prod";
129
- else serverEnv = "local";
130
- return serverEnv;
131
- }
132
- /**
133
- * Get {@link AppInfo#scope}
134
- * @returns {String} serverScope
135
- * @private
136
- */
137
- getServerScope() {
138
- return process.env.EGG_SERVER_SCOPE ?? "";
139
- }
140
- /**
141
- * Get {@link AppInfo#name}
142
- * @returns {String} appname
143
- * @private
144
- * @since 1.0.0
145
- */
146
- getAppname() {
147
- if (this.pkg.name) {
148
- debug("Loaded appname(%s) from package.json", this.pkg.name);
149
- return this.pkg.name;
150
- }
151
- const pkg = path.join(this.options.baseDir, "package.json");
152
- throw new Error(`name is required from ${pkg}`);
153
- }
154
- /**
155
- * Get home directory
156
- * @returns {String} home directory
157
- * @since 3.4.0
158
- */
159
- getHomedir() {
160
- return process.env.EGG_HOME || homedir() || "/home/admin";
161
- }
162
- /**
163
- * Get app info
164
- * @returns {AppInfo} appInfo
165
- * @since 1.0.0
166
- */
167
- getAppInfo() {
168
- const env = this.serverEnv;
169
- const scope = this.serverScope;
170
- const home = this.getHomedir();
171
- const baseDir = this.options.baseDir;
172
- /**
173
- * Meta information of the application
174
- * @class AppInfo
175
- */
176
- return {
177
- name: this.getAppname(),
178
- baseDir,
179
- env,
180
- scope,
181
- HOME: home,
182
- pkg: this.pkg,
183
- root: env === "local" || env === "unittest" ? baseDir : home
184
- };
185
- }
186
- /**
187
- * Get {@link EggLoader#eggPaths}
188
- * @returns {Array} framework directories
189
- * @see {@link EggLoader#eggPaths}
190
- * @private
191
- * @since 1.0.0
192
- */
193
- getEggPaths() {
194
- const EggCore = this.options.EggCoreClass;
195
- const eggPaths = [];
196
- let proto = this.app;
197
- while (proto) {
198
- proto = Object.getPrototypeOf(proto);
199
- if (proto === Object.prototype || proto === EggCore?.prototype) break;
200
- const eggPath = Reflect.get(proto, Symbol.for("egg#eggPath"));
201
- if (!eggPath) continue;
202
- assert(typeof eggPath === "string", "Symbol.for('egg#eggPath') should be string");
203
- assert(fs.existsSync(eggPath), `${eggPath} not exists`);
204
- const realpath = fs.realpathSync(eggPath);
205
- if (!eggPaths.includes(realpath)) eggPaths.unshift(realpath);
206
- }
207
- return eggPaths;
208
- }
209
- /** start Plugin loader */
210
- lookupDirs;
211
- eggPlugins;
212
- appPlugins;
213
- customPlugins;
214
- allPlugins;
215
- orderPlugins;
216
- /** enable plugins */
217
- plugins;
218
- /**
219
- * Load config/plugin.js from {EggLoader#loadUnits}
220
- *
221
- * plugin.js is written below
222
- *
223
- * ```js
224
- * {
225
- * 'xxx-client': {
226
- * enable: true,
227
- * package: 'xxx-client',
228
- * dep: [],
229
- * env: [],
230
- * },
231
- * // short hand
232
- * 'rds': false,
233
- * 'depd': {
234
- * enable: true,
235
- * path: 'path/to/depd'
236
- * }
237
- * }
238
- * ```
239
- *
240
- * If the plugin has path, Loader will find the module from it.
241
- *
242
- * Otherwise Loader will lookup follow the order by packageName
243
- *
244
- * 1. $APP_BASE/node_modules/${package}
245
- * 2. $EGG_BASE/node_modules/${package}
246
- *
247
- * You can call `loader.plugins` that retrieve enabled plugins.
248
- *
249
- * ```js
250
- * loader.plugins['xxx-client'] = {
251
- * name: 'xxx-client', // the plugin name, it can be used in `dep`
252
- * package: 'xxx-client', // the package name of plugin
253
- * enable: true, // whether enabled
254
- * path: 'path/to/xxx-client', // the directory of the plugin package
255
- * dep: [], // the dependent plugins, you can use the plugin name
256
- * env: [ 'local', 'unittest' ], // specify the serverEnv that only enable the plugin in it
257
- * }
258
- * ```
259
- *
260
- * `loader.allPlugins` can be used when retrieve all plugins.
261
- * @function EggLoader#loadPlugin
262
- * @since 1.0.0
263
- */
264
- async loadPlugin() {
265
- this.timing.start("Load Plugin");
266
- this.lookupDirs = this.getLookupDirs();
267
- this.allPlugins = {};
268
- this.eggPlugins = await this.loadEggPlugins();
269
- this.appPlugins = await this.loadAppPlugins();
270
- this.customPlugins = this.loadCustomPlugins();
271
- this.#extendPlugins(this.allPlugins, this.eggPlugins);
272
- this.#extendPlugins(this.allPlugins, this.appPlugins);
273
- this.#extendPlugins(this.allPlugins, this.customPlugins);
274
- const enabledPluginNames = [];
275
- const plugins = {};
276
- const env = this.serverEnv;
277
- for (const name in this.allPlugins) {
278
- const plugin = this.allPlugins[name];
279
- plugin.path = this.getPluginPath(plugin);
280
- await this.#mergePluginConfig(plugin);
281
- if (env && plugin.env.length > 0 && !plugin.env.includes(env)) {
282
- this.logger.info("[egg/core] Plugin %o is disabled by env unmatched, require env(%o) but got env is %o", name, plugin.env, env);
283
- plugin.enable = false;
284
- continue;
285
- }
286
- plugins[name] = plugin;
287
- if (plugin.enable) enabledPluginNames.push(name);
288
- }
289
- this.orderPlugins = this.getOrderPlugins(plugins, enabledPluginNames, this.appPlugins);
290
- const enablePlugins = {};
291
- for (const plugin of this.orderPlugins) enablePlugins[plugin.name] = plugin;
292
- debug("Loaded enable plugins: %j", Object.keys(enablePlugins));
293
- /**
294
- * Retrieve enabled plugins
295
- * @member {Object} EggLoader#plugins
296
- * @since 1.0.0
297
- */
298
- this.plugins = enablePlugins;
299
- this.timing.end("Load Plugin");
300
- }
301
- async loadAppPlugins() {
302
- const appPlugins = await this.readPluginConfigs(path.join(this.options.baseDir, "config/plugin.default"));
303
- debug("Loaded app plugins: %j", Object.keys(appPlugins).map((k) => `${k}:${appPlugins[k].enable}`));
304
- return appPlugins;
305
- }
306
- async loadEggPlugins() {
307
- const eggPluginConfigPaths = this.eggPaths.map((eggPath) => path.join(eggPath, "config/plugin.default"));
308
- const eggPlugins = await this.readPluginConfigs(eggPluginConfigPaths);
309
- debug("Loaded egg plugins: %j", Object.keys(eggPlugins).map((k) => `${k}:${eggPlugins[k].enable}`));
310
- return eggPlugins;
311
- }
312
- loadCustomPlugins() {
313
- let customPlugins = {};
314
- const configPaths = [];
315
- if (process.env.EGG_PLUGINS) try {
316
- customPlugins = JSON.parse(process.env.EGG_PLUGINS);
317
- configPaths.push("<process.env.EGG_PLUGINS>");
318
- } catch (e) {
319
- debug("parse EGG_PLUGINS failed, %s", e);
320
- }
321
- if (this.options.plugins) {
322
- customPlugins = {
323
- ...customPlugins,
324
- ...this.options.plugins
325
- };
326
- configPaths.push("<options.plugins>");
327
- }
328
- if (customPlugins) {
329
- const configPath = configPaths.join(" or ");
330
- for (const name in customPlugins) this.#normalizePluginConfig(customPlugins, name, configPath);
331
- debug("Loaded custom plugins: %o", customPlugins);
332
- }
333
- return customPlugins;
334
- }
335
- async readPluginConfigs(configPaths) {
336
- if (!Array.isArray(configPaths)) configPaths = [configPaths];
337
- const newConfigPaths = [];
338
- for (const filename of this.getTypeFiles("plugin")) for (let configPath of configPaths) {
339
- configPath = path.join(path.dirname(configPath), filename);
340
- newConfigPaths.push(configPath);
341
- }
342
- const plugins = {};
343
- for (const configPath of newConfigPaths) {
344
- let filepath = this.resolveModule(configPath);
345
- if (configPath.endsWith("plugin.default") && !filepath) filepath = this.resolveModule(configPath.replace(/plugin\.default$/, "plugin"));
346
- if (!filepath) {
347
- debug("[readPluginConfigs:ignore] plugin config not found %o", configPath);
348
- continue;
349
- }
350
- const config = await utils_default.loadFile(filepath);
351
- for (const name in config) this.#normalizePluginConfig(config, name, filepath);
352
- this.#extendPlugins(plugins, config);
353
- }
354
- return plugins;
355
- }
356
- #normalizePluginConfig(plugins, name, configPath) {
357
- const plugin = plugins[name];
358
- if (typeof plugin === "boolean") {
359
- plugins[name] = {
360
- name,
361
- enable: plugin,
362
- dependencies: [],
363
- optionalDependencies: [],
364
- env: [],
365
- from: configPath
366
- };
367
- return;
368
- }
369
- if (!("enable" in plugin)) Reflect.set(plugin, "enable", true);
370
- plugin.name = name;
371
- plugin.dependencies = plugin.dependencies || [];
372
- plugin.optionalDependencies = plugin.optionalDependencies || [];
373
- plugin.env = plugin.env || [];
374
- plugin.from = plugin.from || configPath;
375
- depCompatible(plugin);
376
- }
377
- async #mergePluginConfig(plugin) {
378
- let pkg;
379
- let config;
380
- const pluginPackage = path.join(plugin.path, "package.json");
381
- if (await utils_default.existsPath(pluginPackage)) {
382
- pkg = await readJSON(pluginPackage);
383
- config = pkg.eggPlugin;
384
- if (pkg.version) plugin.version = pkg.version;
385
- plugin.path = await this.#formatPluginPathFromPackageJSON(plugin.path, pkg);
386
- }
387
- const logger = this.options.logger;
388
- if (!config) {
389
- logger.warn(`[@eggjs/core/egg_loader] pkg.eggPlugin is missing in ${pluginPackage}`);
390
- return;
391
- }
392
- if (config.name && config.strict !== false && config.name !== plugin.name) logger.warn(`[@eggjs/core/egg_loader] pluginName(${plugin.name}) is different from pluginConfigName(${config.name})`);
393
- depCompatible(config);
394
- for (const key of [
395
- "dependencies",
396
- "optionalDependencies",
397
- "env"
398
- ]) {
399
- const values = config[key];
400
- const existsValues = Reflect.get(plugin, key);
401
- if (Array.isArray(values) && !existsValues?.length) Reflect.set(plugin, key, values);
402
- }
403
- }
404
- getOrderPlugins(allPlugins, enabledPluginNames, appPlugins) {
405
- if (enabledPluginNames.length === 0) return [];
406
- const result = sequencify(allPlugins, enabledPluginNames);
407
- debug("Got plugins %j after sequencify", result);
408
- if (result.sequence.length === 0) {
409
- const err = /* @__PURE__ */ new Error(`sequencify plugins has problem, missing: [${result.missingTasks}], recursive: [${result.recursiveDependencies}]`);
410
- for (const missName of result.missingTasks) {
411
- const requires = [];
412
- for (const name in allPlugins) if (allPlugins[name].dependencies.includes(missName)) requires.push(name);
413
- err.message += `\n\t>> Plugin [${missName}] is disabled or missed, but is required by [${requires}]`;
414
- }
415
- err.name = "PluginSequencifyError";
416
- throw err;
417
- }
418
- const implicitEnabledPlugins = [];
419
- const requireMap = {};
420
- for (const name of result.sequence) {
421
- for (const depName of allPlugins[name].dependencies) {
422
- if (!requireMap[depName]) requireMap[depName] = [];
423
- requireMap[depName].push(name);
424
- }
425
- if (!allPlugins[name].enable) {
426
- implicitEnabledPlugins.push(name);
427
- allPlugins[name].enable = true;
428
- allPlugins[name].implicitEnable = true;
429
- }
430
- }
431
- for (const [name, dependents] of Object.entries(requireMap)) allPlugins[name].dependents = dependents;
432
- if (implicitEnabledPlugins.length > 0) {
433
- let message = implicitEnabledPlugins.map((name) => ` - ${name} required by [${requireMap[name]}]`).join("\n");
434
- this.options.logger.info(`Following plugins will be enabled implicitly.\n${message}`);
435
- const disabledPlugins = implicitEnabledPlugins.filter((name) => appPlugins[name] && appPlugins[name].enable === false);
436
- if (disabledPlugins.length > 0) {
437
- message = disabledPlugins.map((name) => ` - ${name} required by [${requireMap[name]}]`).join("\n");
438
- this.options.logger.warn(`Following plugins will be enabled implicitly that is disabled by application.\n${message}`);
439
- }
440
- }
441
- return result.sequence.map((name) => allPlugins[name]);
442
- }
443
- getLookupDirs() {
444
- const lookupDirs = /* @__PURE__ */ new Set();
445
- lookupDirs.add(this.options.baseDir);
446
- for (let i = this.eggPaths.length - 1; i >= 0; i--) {
447
- const eggPath = this.eggPaths[i];
448
- lookupDirs.add(eggPath);
449
- }
450
- lookupDirs.add(process.cwd());
451
- return lookupDirs;
452
- }
453
- getPluginPath(plugin) {
454
- if (plugin.path) return plugin.path;
455
- if (plugin.package) assert(isValidatePackageName(plugin.package), `plugin ${plugin.name} invalid, use 'path' instead of package: "${plugin.package}"`);
456
- return this.#resolvePluginPath(plugin);
457
- }
458
- #resolvePluginPath(plugin) {
459
- const name = plugin.package || plugin.name;
460
- try {
461
- const pluginPkgFile = utils_default.resolvePath(`${name}/package.json`, { paths: [...this.lookupDirs] });
462
- return path.dirname(pluginPkgFile);
463
- } catch (err) {
464
- debug("[resolvePluginPath] error: %o, plugin info: %o", err, plugin);
465
- throw new Error(`Can not find plugin ${name} in "${[...this.lookupDirs].join(", ")}"`, { cause: err });
466
- }
467
- }
468
- async #formatPluginPathFromPackageJSON(pluginPath, pluginPkg) {
469
- let realPluginPath = pluginPath;
470
- const exports = pluginPkg.eggPlugin?.exports;
471
- if (exports) {
472
- if (isESM) {
473
- if (exports.import) realPluginPath = path.join(pluginPath, exports.import);
474
- } else if (exports.require) realPluginPath = path.join(pluginPath, exports.require);
475
- if (exports.typescript && isSupportTypeScript() && !await exists(realPluginPath)) {
476
- realPluginPath = path.join(pluginPath, exports.typescript);
477
- debug("[formatPluginPathFromPackageJSON] use typescript path %o", realPluginPath);
478
- }
479
- } else if (pluginPkg.exports?.["."] && pluginPkg.type === "module") {
480
- let defaultExport = pluginPkg.exports["."];
481
- if (typeof defaultExport === "string") realPluginPath = path.dirname(path.join(pluginPath, defaultExport));
482
- else if (defaultExport?.import) {
483
- if (typeof defaultExport.import === "string") realPluginPath = path.dirname(path.join(pluginPath, defaultExport.import));
484
- else if (defaultExport.import.default) realPluginPath = path.dirname(path.join(pluginPath, defaultExport.import.default));
485
- }
486
- debug("[formatPluginPathFromPackageJSON] resolve plugin path from %o to %o, defaultExport: %o", pluginPath, realPluginPath, defaultExport);
487
- }
488
- return realPluginPath;
489
- }
490
- #extendPlugins(targets, plugins) {
491
- if (!plugins) return;
492
- for (const name in plugins) {
493
- const plugin = plugins[name];
494
- let targetPlugin = targets[name];
495
- if (!targetPlugin) {
496
- targetPlugin = {};
497
- targets[name] = targetPlugin;
498
- }
499
- if (targetPlugin.package && targetPlugin.package === plugin.package) this.logger.warn("[@eggjs/core] plugin %s has been defined that is %j, but you define again in %s", name, targetPlugin, plugin.from);
500
- if (plugin.path || plugin.package) {
501
- delete targetPlugin.path;
502
- delete targetPlugin.package;
503
- }
504
- for (const [prop, value] of Object.entries(plugin)) {
505
- if (value === void 0) continue;
506
- if (Reflect.get(targetPlugin, prop) && Array.isArray(value) && value.length === 0) continue;
507
- Reflect.set(targetPlugin, prop, value);
508
- }
509
- }
510
- }
511
- /** end Plugin loader */
512
- /** start Config loader */
513
- configMeta;
514
- config;
515
- /**
516
- * Load config/config.js
517
- *
518
- * Will merge config.default.js 和 config.${env}.js
519
- *
520
- * @function EggLoader#loadConfig
521
- * @since 1.0.0
522
- */
523
- async loadConfig() {
524
- this.timing.start("Load Config");
525
- this.configMeta = {};
526
- const target = {
527
- middleware: [],
528
- coreMiddleware: []
529
- };
530
- const appConfig = await this.#preloadAppConfig();
531
- for (const filename of this.getTypeFiles("config")) for (const unit of this.getLoadUnits()) {
532
- const isApp = unit.type === "app";
533
- const config = await this.#loadConfig(unit.path, filename, isApp ? void 0 : appConfig, unit.type);
534
- if (!config) continue;
535
- debug("[loadConfig] Loaded config %s/%s, %j", unit.path, filename, config);
536
- extend(true, target, config);
537
- }
538
- const envConfig = this.#loadConfigFromEnv();
539
- debug("[loadConfig] Loaded config from env, %j", envConfig);
540
- extend(true, target, envConfig);
541
- target.coreMiddleware = target.coreMiddleware || [];
542
- target.coreMiddlewares = target.coreMiddleware;
543
- target.appMiddleware = target.middleware || [];
544
- target.appMiddlewares = target.appMiddleware;
545
- this.config = target;
546
- debug("[loadConfig] all config: %o", this.config);
547
- this.timing.end("Load Config");
548
- }
549
- async #preloadAppConfig() {
550
- const names = ["config.default", `config.${this.serverEnv}`];
551
- const target = {};
552
- for (const filename of names) {
553
- const config = await this.#loadConfig(this.options.baseDir, filename, void 0, "app");
554
- if (!config) continue;
555
- extend(true, target, config);
556
- }
557
- return target;
558
- }
559
- async #loadConfig(dirpath, filename, extraInject, type) {
560
- const isPlugin = type === "plugin";
561
- const isApp = type === "app";
562
- let filepath = this.resolveModule(path.join(dirpath, "config", filename));
563
- if (filename === "config.default" && !filepath) filepath = this.resolveModule(path.join(dirpath, "config/config"));
564
- if (!filepath) return;
565
- const config = await this.loadFile(filepath, this.appInfo, extraInject);
566
- if (!config) return;
567
- if (isPlugin || isApp) assert(!config.coreMiddleware, "Can not define coreMiddleware in app or plugin");
568
- if (!isApp) assert(!config.middleware, "Can not define middleware in " + filepath);
569
- this.#setConfigMeta(config, filepath);
570
- return config;
571
- }
572
- #loadConfigFromEnv() {
573
- const envConfigStr = process.env.EGG_APP_CONFIG;
574
- if (!envConfigStr) return;
575
- try {
576
- const envConfig = JSON.parse(envConfigStr);
577
- this.#setConfigMeta(envConfig, "<process.env.EGG_APP_CONFIG>");
578
- return envConfig;
579
- } catch {
580
- this.options.logger.warn("[egg-loader] process.env.EGG_APP_CONFIG is not invalid JSON: %s", envConfigStr);
581
- }
582
- }
583
- #setConfigMeta(config, filepath) {
584
- config = extend(true, {}, config);
585
- this.#setConfig(config, filepath);
586
- extend(true, this.configMeta, config);
587
- }
588
- #setConfig(obj, filepath) {
589
- for (const key of Object.keys(obj)) {
590
- const val = obj[key];
591
- if (key === "console" && val && typeof val.Console === "function" && val.Console === console.Console) {
592
- obj[key] = filepath;
593
- continue;
594
- }
595
- if (val && Object.getPrototypeOf(val) === Object.prototype && Object.keys(val).length > 0) {
596
- this.#setConfig(val, filepath);
597
- continue;
598
- }
599
- obj[key] = filepath;
600
- }
601
- }
602
- /** end Config loader */
603
- /** start Extend loader */
604
- /**
605
- * mixin Agent.prototype
606
- * @function EggLoader#loadAgentExtend
607
- * @since 1.0.0
608
- */
609
- async loadAgentExtend() {
610
- await this.loadExtend("agent", this.app);
611
- }
612
- /**
613
- * mixin Application.prototype
614
- * @function EggLoader#loadApplicationExtend
615
- * @since 1.0.0
616
- */
617
- async loadApplicationExtend() {
618
- await this.loadExtend("application", this.app);
619
- }
620
- /**
621
- * mixin Request.prototype
622
- * @function EggLoader#loadRequestExtend
623
- * @since 1.0.0
624
- */
625
- async loadRequestExtend() {
626
- await this.loadExtend("request", this.app.request);
627
- }
628
- /**
629
- * mixin Response.prototype
630
- * @function EggLoader#loadResponseExtend
631
- * @since 1.0.0
632
- */
633
- async loadResponseExtend() {
634
- await this.loadExtend("response", this.app.response);
635
- }
636
- /**
637
- * mixin Context.prototype
638
- * @function EggLoader#loadContextExtend
639
- * @since 1.0.0
640
- */
641
- async loadContextExtend() {
642
- await this.loadExtend("context", this.app.context);
643
- }
644
- /**
645
- * mixin app.Helper.prototype
646
- * @function EggLoader#loadHelperExtend
647
- * @since 1.0.0
648
- */
649
- async loadHelperExtend() {
650
- if (this.app.Helper) await this.loadExtend("helper", this.app.Helper.prototype);
651
- }
652
- /**
653
- * Find all extend file paths by name
654
- * can be override in top level framework to support load `app/extends/{name}.js`
655
- *
656
- * @param {String} name - filename which may be `app/extend/{name}.js`
657
- * @returns {Array} filepaths extend file paths
658
- * @private
659
- */
660
- getExtendFilePaths(name) {
661
- return this.getLoadUnits().map((unit) => path.join(unit.path, "app/extend", name));
662
- }
663
- /**
664
- * Loader app/extend/xx.js to `prototype`,
665
- * @function loadExtend
666
- * @param {String} name - filename which may be `app/extend/{name}.js`
667
- * @param {Object} proto - prototype that mixed
668
- * @since 1.0.0
669
- */
670
- async loadExtend(name, proto) {
671
- this.timing.start(`Load extend/${name}.js`);
672
- const filepaths = this.getExtendFilePaths(name);
673
- const needUnittest = "EGG_MOCK_SERVER_ENV" in process.env && this.serverEnv !== "unittest";
674
- const length = filepaths.length;
675
- for (let i = 0; i < length; i++) {
676
- const filepath = filepaths[i];
677
- filepaths.push(filepath + `.${this.serverEnv}`);
678
- if (needUnittest) filepaths.push(filepath + ".unittest");
679
- }
680
- debug("loadExtend %s, filepaths: %j", name, filepaths);
681
- const mergeRecord = /* @__PURE__ */ new Map();
682
- for (const rawFilepath of filepaths) {
683
- const filepath = this.resolveModule(rawFilepath);
684
- if (!filepath) continue;
685
- if (filepath.endsWith("/index.js")) this.app.deprecate(`app/extend/${name}/index.js is deprecated, use app/extend/${name}.js instead`);
686
- else if (filepath.endsWith("/index.ts")) this.app.deprecate(`app/extend/${name}/index.ts is deprecated, use app/extend/${name}.ts instead`);
687
- let ext = await this.requireFile(filepath);
688
- if (isClass(ext)) ext = ext.prototype;
689
- const properties = Object.getOwnPropertyNames(ext).concat(Object.getOwnPropertySymbols(ext)).filter((name$1) => name$1 !== "constructor");
690
- for (const property of properties) {
691
- if (mergeRecord.has(property)) debug("Property: \"%s\" already exists in \"%s\",it will be redefined by \"%s\"", property, mergeRecord.get(property), filepath);
692
- let descriptor = Object.getOwnPropertyDescriptor(ext, property);
693
- let originalDescriptor = Object.getOwnPropertyDescriptor(proto, property);
694
- if (!originalDescriptor) {
695
- const originalProto = originalPrototypes[name];
696
- if (originalProto) originalDescriptor = Object.getOwnPropertyDescriptor(originalProto, property);
697
- }
698
- if (originalDescriptor) {
699
- descriptor = { ...descriptor };
700
- if (!descriptor.set && originalDescriptor.set) descriptor.set = originalDescriptor.set;
701
- if (!descriptor.get && originalDescriptor.get) descriptor.get = originalDescriptor.get;
702
- }
703
- Object.defineProperty(proto, property, descriptor);
704
- mergeRecord.set(property, filepath);
705
- }
706
- debug("merge %j to %s from %s", properties, name, filepath);
707
- }
708
- this.timing.end(`Load extend/${name}.js`);
709
- }
710
- /** end Extend loader */
711
- /** start Custom loader */
712
- /**
713
- * load app.js
714
- *
715
- * @example
716
- * - old:
717
- *
718
- * ```js
719
- * module.exports = function(app) {
720
- * doSomething();
721
- * }
722
- * ```
723
- *
724
- * - new:
725
- *
726
- * ```js
727
- * module.exports = class Boot {
728
- * constructor(app) {
729
- * this.app = app;
730
- * }
731
- * configDidLoad() {
732
- * doSomething();
733
- * }
734
- * }
735
- * @since 1.0.0
736
- */
737
- async loadCustomApp() {
738
- await this.#loadBootHook("app");
739
- this.lifecycle.triggerConfigWillLoad();
740
- }
741
- /**
742
- * Load agent.js, same as {@link EggLoader#loadCustomApp}
743
- */
744
- async loadCustomAgent() {
745
- await this.#loadBootHook("agent");
746
- this.lifecycle.triggerConfigWillLoad();
747
- }
748
- loadBootHook() {}
749
- async #loadBootHook(fileName) {
750
- this.timing.start(`Load ${fileName}.js`);
751
- for (const unit of this.getLoadUnits()) {
752
- const bootFile = path.join(unit.path, fileName);
753
- const bootFilePath = this.resolveModule(bootFile);
754
- if (!bootFilePath) {
755
- debug("[loadBootHook:ignore] %o not found", bootFile);
756
- continue;
757
- }
758
- debug("[loadBootHook:success] %o => %o", bootFile, bootFilePath);
759
- const bootHook = await this.requireFile(bootFilePath);
760
- if (isClass(bootHook)) {
761
- bootHook.prototype.fullPath = bootFilePath;
762
- this.lifecycle.addBootHook(bootHook);
763
- debug("[loadBootHook] add BootHookClass from %o", bootFilePath);
764
- } else if (typeof bootHook === "function") {
765
- this.lifecycle.addFunctionAsBootHook(bootHook, bootFilePath);
766
- debug("[loadBootHook] add bootHookFunction from %o", bootFilePath);
767
- } else this.options.logger.warn("[@eggjs/core/egg_loader] %s must exports a boot class", bootFilePath);
768
- }
769
- this.lifecycle.init();
770
- this.timing.end(`Load ${fileName}.js`);
771
- }
772
- /** end Custom loader */
773
- /** start Service loader */
774
- /**
775
- * Load app/service
776
- * @function EggLoader#loadService
777
- * @param {Object} options - LoaderOptions
778
- * @since 1.0.0
779
- */
780
- async loadService(options) {
781
- this.timing.start("Load Service");
782
- const servicePaths = this.getLoadUnits().map((unit) => path.join(unit.path, "app/service"));
783
- options = {
784
- call: true,
785
- caseStyle: CaseStyle.lower,
786
- fieldClass: "serviceClasses",
787
- directory: servicePaths,
788
- ...options
789
- };
790
- debug("[loadService] options: %o", options);
791
- await this.loadToContext(servicePaths, "service", options);
792
- this.timing.end("Load Service");
793
- }
794
- /** end Service loader */
795
- /** start Middleware loader */
796
- /**
797
- * Load app/middleware
798
- *
799
- * app.config.xx is the options of the middleware xx that has same name as config
800
- *
801
- * @function EggLoader#loadMiddleware
802
- * @param {Object} opt - LoaderOptions
803
- * @example
804
- * ```js
805
- * // app/middleware/status.js
806
- * module.exports = function(options, app) {
807
- * // options == app.config.status
808
- * return async next => {
809
- * await next();
810
- * }
811
- * }
812
- * ```
813
- * @since 1.0.0
814
- */
815
- async loadMiddleware(opt) {
816
- this.timing.start("Load Middleware");
817
- const app = this.app;
818
- const middlewarePaths = this.getLoadUnits().map((unit) => path.join(unit.path, "app/middleware"));
819
- opt = {
820
- call: false,
821
- override: true,
822
- caseStyle: CaseStyle.lower,
823
- directory: middlewarePaths,
824
- ...opt
825
- };
826
- await this.loadToApp(middlewarePaths, "middlewares", opt);
827
- debug("[loadMiddleware] middlewarePaths: %j", middlewarePaths);
828
- for (const name in app.middlewares) Object.defineProperty(app.middleware, name, {
829
- get() {
830
- return app.middlewares[name];
831
- },
832
- enumerable: false,
833
- configurable: false
834
- });
835
- this.options.logger.info("Use coreMiddleware order: %j", this.config.coreMiddleware);
836
- this.options.logger.info("Use appMiddleware order: %j", this.config.appMiddleware);
837
- const middlewareNames = this.config.coreMiddleware.concat(this.config.appMiddleware);
838
- debug("[loadMiddleware] middlewareNames: %j", middlewareNames);
839
- const middlewaresMap = /* @__PURE__ */ new Map();
840
- for (const name of middlewareNames) {
841
- const createMiddleware = app.middlewares[name];
842
- if (!createMiddleware) throw new TypeError(`Middleware ${name} not found`);
843
- if (middlewaresMap.has(name)) throw new TypeError(`Middleware ${name} redefined`);
844
- middlewaresMap.set(name, true);
845
- const options = this.config[name] || {};
846
- let mw$1 = createMiddleware(options, app);
847
- assert(typeof mw$1 === "function", `Middleware ${name} must be a function, but actual is ${inspect(mw$1)}`);
848
- if (isGeneratorFunction(mw$1)) {
849
- const fullpath = Reflect.get(createMiddleware, FULLPATH);
850
- throw new TypeError(`Support for generators was removed, middleware: ${name}, fullpath: ${fullpath}`);
851
- }
852
- mw$1._name = name;
853
- mw$1 = wrapMiddleware(mw$1, options);
854
- if (mw$1) {
855
- if (debug.enabled) mw$1 = debugMiddlewareWrapper(mw$1);
856
- app.use(mw$1);
857
- debug("[loadMiddleware] Use middleware: %s with options: %j", name, options);
858
- this.options.logger.info("[@eggjs/core/egg_loader] Use middleware: %s", name);
859
- } else this.options.logger.info("[@eggjs/core/egg_loader] Disable middleware: %s", name);
860
- }
861
- this.options.logger.info("[@eggjs/core/egg_loader] Loaded middleware from %j", middlewarePaths);
862
- this.timing.end("Load Middleware");
863
- const mw = this.app.router.middleware();
864
- Reflect.set(mw, "_name", "routerMiddleware");
865
- this.app.use(mw);
866
- }
867
- /** end Middleware loader */
868
- /** start Controller loader */
869
- /**
870
- * Load app/controller
871
- * @param {Object} opt - LoaderOptions
872
- * @since 1.0.0
873
- */
874
- async loadController(opt) {
875
- this.timing.start("Load Controller");
876
- const controllerBase = path.join(this.options.baseDir, "app/controller");
877
- opt = {
878
- caseStyle: CaseStyle.lower,
879
- directory: controllerBase,
880
- initializer: (obj, opt$1) => {
881
- if (isGeneratorFunction(obj)) throw new TypeError(`Support for generators was removed, fullpath: ${opt$1.path}`);
882
- if (!isClass(obj) && !isAsyncFunction(obj) && typeof obj === "function") {
883
- obj = obj(this.app);
884
- debug("[loadController] after init(app) => %o, meta: %j", obj, opt$1);
885
- if (isGeneratorFunction(obj)) throw new TypeError(`Support for generators was removed, fullpath: ${opt$1.path}`);
886
- }
887
- if (isClass(obj)) {
888
- obj.prototype.pathName = opt$1.pathName;
889
- obj.prototype.fullPath = opt$1.path;
890
- return wrapControllerClass(obj, opt$1.path);
891
- }
892
- if (isObject(obj)) return wrapObject(obj, opt$1.path);
893
- if (isAsyncFunction(obj)) return wrapObject({ "module.exports": obj }, opt$1.path)["module.exports"];
894
- return obj;
895
- },
896
- ...opt
897
- };
898
- await this.loadToApp(controllerBase, "controller", opt);
899
- debug("[loadController] app.controller => %o", this.app.controller);
900
- this.options.logger.info("[@eggjs/core/egg_loader] Controller loaded: %s", controllerBase);
901
- this.timing.end("Load Controller");
902
- }
903
- /** end Controller loader */
904
- /** start Router loader */
905
- /**
906
- * Load app/router.js
907
- * @function EggLoader#loadRouter
908
- * @since 1.0.0
909
- */
910
- async loadRouter() {
911
- this.timing.start("Load Router");
912
- await this.loadFile(path.join(this.options.baseDir, "app/router"));
913
- this.timing.end("Load Router");
914
- }
915
- /** end Router loader */
916
- /** start CustomLoader loader */
917
- async loadCustomLoader() {
918
- assert(this.config, "should loadConfig first");
919
- const customLoader = this.config.customLoader || {};
920
- for (const property of Object.keys(customLoader)) {
921
- const loaderConfig = { ...customLoader[property] };
922
- assert(loaderConfig.directory, `directory is required for config.customLoader.${property}`);
923
- let directory;
924
- if (loaderConfig.loadunit === true) directory = this.getLoadUnits().map((unit) => path.join(unit.path, loaderConfig.directory));
925
- else directory = path.join(this.appInfo.baseDir, loaderConfig.directory);
926
- const inject = loaderConfig.inject || "app";
927
- debug("[loadCustomLoader] loaderConfig: %o, inject: %o, directory: %o", loaderConfig, inject, directory);
928
- switch (inject) {
929
- case "ctx": {
930
- assert(!(property in this.app.context), `customLoader should not override ctx.${property}`);
931
- const options = {
932
- caseStyle: CaseStyle.lower,
933
- fieldClass: `${property}Classes`,
934
- ...loaderConfig,
935
- directory
936
- };
937
- await this.loadToContext(directory, property, options);
938
- break;
939
- }
940
- case "app": {
941
- assert(!(property in this.app), `customLoader should not override app.${property}`);
942
- const options = {
943
- caseStyle: CaseStyle.lower,
944
- initializer: (Clazz) => {
945
- return isClass(Clazz) ? new Clazz(this.app) : Clazz;
946
- },
947
- ...loaderConfig,
948
- directory
949
- };
950
- await this.loadToApp(directory, property, options);
951
- break;
952
- }
953
- default: throw new Error("inject only support app or ctx");
954
- }
955
- }
956
- }
957
- /** end CustomLoader loader */
958
- /**
959
- * Load single file, will invoke when export is function
960
- *
961
- * @param {String} filepath - fullpath
962
- * @param {Array} inject - pass rest arguments into the function when invoke
963
- * @returns {Object} exports
964
- * @example
965
- * ```js
966
- * app.loader.loadFile(path.join(app.options.baseDir, 'config/router.js'));
967
- * ```
968
- * @since 1.0.0
969
- */
970
- async loadFile(filepath, ...inject) {
971
- const fullpath = filepath && this.resolveModule(filepath);
972
- if (!fullpath) return null;
973
- if (inject.length === 0) inject = [this.app];
974
- let mod = await this.requireFile(fullpath);
975
- if (typeof mod === "function" && !isClass(mod)) {
976
- mod = mod(...inject);
977
- if (isPromise(mod)) mod = await mod;
978
- }
979
- return mod;
980
- }
981
- /**
982
- * @param {String} filepath - fullpath
983
- * @private
984
- */
985
- async requireFile(filepath) {
986
- const timingKey = `Require(${this.#requiredCount++}) ${utils_default.getResolvedFilename(filepath, this.options.baseDir)}`;
987
- this.timing.start(timingKey);
988
- const mod = await utils_default.loadFile(filepath);
989
- this.timing.end(timingKey);
990
- return mod;
991
- }
992
- /**
993
- * Get all loadUnit
994
- *
995
- * loadUnit is a directory that can be loaded by EggLoader, it has the same structure.
996
- * loadUnit has a path and a type(app, framework, plugin).
997
- *
998
- * The order of the loadUnits:
999
- *
1000
- * 1. plugin
1001
- * 2. framework
1002
- * 3. app
1003
- *
1004
- * @returns {Array} loadUnits
1005
- * @since 1.0.0
1006
- */
1007
- getLoadUnits() {
1008
- if (this.dirs) return this.dirs;
1009
- this.dirs = [];
1010
- if (this.orderPlugins) for (const plugin of this.orderPlugins) this.dirs.push({
1011
- path: plugin.path,
1012
- type: "plugin"
1013
- });
1014
- for (const eggPath of this.eggPaths) this.dirs.push({
1015
- path: eggPath,
1016
- type: "framework"
1017
- });
1018
- this.dirs.push({
1019
- path: this.options.baseDir,
1020
- type: "app"
1021
- });
1022
- debug("Loaded dirs %j", this.dirs);
1023
- return this.dirs;
1024
- }
1025
- /**
1026
- * Load files using {@link FileLoader}, inject to {@link Application}
1027
- * @param {String|Array} directory - see {@link FileLoader}
1028
- * @param {String} property - see {@link FileLoader}, e.g.: 'controller', 'middlewares'
1029
- * @param {Object} options - see {@link FileLoader}
1030
- * @since 1.0.0
1031
- */
1032
- async loadToApp(directory, property, options) {
1033
- const target = {};
1034
- Reflect.set(this.app, property, target);
1035
- const loadOptions = {
1036
- ...options,
1037
- directory: options?.directory ?? directory,
1038
- target,
1039
- inject: this.app
1040
- };
1041
- const timingKey = `Load "${String(property)}" to Application`;
1042
- this.timing.start(timingKey);
1043
- await new FileLoader(loadOptions).load();
1044
- this.timing.end(timingKey);
1045
- }
1046
- /**
1047
- * Load files using {@link ContextLoader}
1048
- * @param {String|Array} directory - see {@link ContextLoader}
1049
- * @param {String} property - see {@link ContextLoader}
1050
- * @param {Object} options - see {@link ContextLoader}
1051
- * @since 1.0.0
1052
- */
1053
- async loadToContext(directory, property, options) {
1054
- const loadOptions = {
1055
- ...options,
1056
- directory: options?.directory || directory,
1057
- property,
1058
- inject: this.app
1059
- };
1060
- const timingKey = `Load "${String(property)}" to Context`;
1061
- this.timing.start(timingKey);
1062
- await new ContextLoader(loadOptions).load();
1063
- this.timing.end(timingKey);
1064
- }
1065
- /**
1066
- * @member {FileLoader} EggLoader#FileLoader
1067
- * @since 1.0.0
1068
- */
1069
- get FileLoader() {
1070
- return FileLoader;
1071
- }
1072
- /**
1073
- * @member {ContextLoader} EggLoader#ContextLoader
1074
- * @since 1.0.0
1075
- */
1076
- get ContextLoader() {
1077
- return ContextLoader;
1078
- }
1079
- getTypeFiles(filename) {
1080
- const files = [`${filename}.default`];
1081
- if (this.serverScope) files.push(`${filename}.${this.serverScope}`);
1082
- if (this.serverEnv === "default") return files;
1083
- files.push(`${filename}.${this.serverEnv}`);
1084
- if (this.serverScope) files.push(`${filename}.${this.serverScope}_${this.serverEnv}`);
1085
- return files;
1086
- }
1087
- resolveModule(filepath) {
1088
- let fullPath;
1089
- try {
1090
- fullPath = utils_default.resolvePath(filepath);
1091
- } catch {
1092
- return;
1093
- }
1094
- return fullPath;
1095
- }
21
+ request: Request.prototype,
22
+ response: Response.prototype,
23
+ context: KoaContext.prototype,
24
+ application: Application.prototype,
1096
25
  };
26
+ export class EggLoader {
27
+ #requiredCount = 0;
28
+ options;
29
+ timing;
30
+ pkg;
31
+ eggPaths;
32
+ serverEnv;
33
+ serverScope;
34
+ appInfo;
35
+ dirs;
36
+ /**
37
+ * @class
38
+ * @param {Object} options - options
39
+ * @param {String} options.baseDir - the directory of application
40
+ * @param {EggCore} options.app - Application instance
41
+ * @param {Logger} options.logger - logger
42
+ * @param {Object} [options.plugins] - custom plugins
43
+ * @since 1.0.0
44
+ */
45
+ constructor(options) {
46
+ this.options = options;
47
+ assert(fs.existsSync(this.options.baseDir), `${this.options.baseDir} not exists`);
48
+ assert(this.options.app, 'options.app is required');
49
+ assert(this.options.logger, 'options.logger is required');
50
+ this.timing = this.app.timing || new Timing();
51
+ /**
52
+ * @member {Object} EggLoader#pkg
53
+ * @see {@link AppInfo#pkg}
54
+ * @since 1.0.0
55
+ */
56
+ this.pkg = readJSONSync(path.join(this.options.baseDir, 'package.json'));
57
+ // auto require('tsconfig-paths/register') on typescript app
58
+ // support env.EGG_TYPESCRIPT = true or { "egg": { "typescript": true } } on package.json
59
+ if (process.env.EGG_TYPESCRIPT === 'true' || (this.pkg.egg && this.pkg.egg.typescript)) {
60
+ // skip require tsconfig-paths if tsconfig.json not exists
61
+ const tsConfigFile = path.join(this.options.baseDir, 'tsconfig.json');
62
+ if (fs.existsSync(tsConfigFile)) {
63
+ // @ts-expect-error only cwd is required
64
+ tsconfigPathsRegister({ cwd: this.options.baseDir });
65
+ }
66
+ else {
67
+ this.logger.info('[@eggjs/core/egg_loader] skip register "tsconfig-paths" because tsconfig.json not exists at %s', tsConfigFile);
68
+ }
69
+ }
70
+ /**
71
+ * All framework directories.
72
+ *
73
+ * You can extend Application of egg, the entry point is options.app,
74
+ *
75
+ * loader will find all directories from the prototype of Application,
76
+ * you should define `Symbol.for('egg#eggPath')` property.
77
+ *
78
+ * ```ts
79
+ * // src/example.ts
80
+ * import { Application } from 'egg';
81
+ * class ExampleApplication extends Application {
82
+ * get [Symbol.for('egg#eggPath')]() {
83
+ * return baseDir;
84
+ * }
85
+ * }
86
+ * ```
87
+ * @member {Array} EggLoader#eggPaths
88
+ * @see EggLoader#getEggPaths
89
+ * @since 1.0.0
90
+ */
91
+ this.eggPaths = this.getEggPaths();
92
+ debug('Loaded eggPaths %j', this.eggPaths);
93
+ /**
94
+ * @member {String} EggLoader#serverEnv
95
+ * @see AppInfo#env
96
+ * @since 1.0.0
97
+ */
98
+ this.serverEnv = this.getServerEnv();
99
+ debug('Loaded serverEnv %j', this.serverEnv);
100
+ /**
101
+ * @member {String} EggLoader#serverScope
102
+ * @see AppInfo#serverScope
103
+ */
104
+ this.serverScope = options.serverScope ?? this.getServerScope();
105
+ /**
106
+ * @member {AppInfo} EggLoader#appInfo
107
+ * @since 1.0.0
108
+ */
109
+ this.appInfo = this.getAppInfo();
110
+ }
111
+ get app() {
112
+ return this.options.app;
113
+ }
114
+ get lifecycle() {
115
+ return this.app.lifecycle;
116
+ }
117
+ get logger() {
118
+ return this.options.logger;
119
+ }
120
+ /**
121
+ * Get {@link AppInfo#env}
122
+ * @returns {String} env
123
+ * @see AppInfo#env
124
+ * @private
125
+ * @since 1.0.0
126
+ */
127
+ getServerEnv() {
128
+ let serverEnv = this.options.env;
129
+ const envPath = path.join(this.options.baseDir, 'config/env');
130
+ if (!serverEnv && fs.existsSync(envPath)) {
131
+ serverEnv = fs.readFileSync(envPath, 'utf8').trim();
132
+ }
133
+ if (!serverEnv && process.env.EGG_SERVER_ENV) {
134
+ serverEnv = process.env.EGG_SERVER_ENV;
135
+ }
136
+ if (serverEnv) {
137
+ serverEnv = serverEnv.trim();
138
+ }
139
+ else {
140
+ // oxlint-disable-next-line eslint/no-lonely-if
141
+ if (process.env.NODE_ENV === 'test') {
142
+ serverEnv = 'unittest';
143
+ }
144
+ else if (process.env.NODE_ENV === 'production') {
145
+ serverEnv = 'prod';
146
+ }
147
+ else {
148
+ serverEnv = 'local';
149
+ }
150
+ }
151
+ return serverEnv;
152
+ }
153
+ /**
154
+ * Get {@link AppInfo#scope}
155
+ * @returns {String} serverScope
156
+ * @private
157
+ */
158
+ getServerScope() {
159
+ return process.env.EGG_SERVER_SCOPE ?? '';
160
+ }
161
+ /**
162
+ * Get {@link AppInfo#name}
163
+ * @returns {String} appname
164
+ * @private
165
+ * @since 1.0.0
166
+ */
167
+ getAppname() {
168
+ if (this.pkg.name) {
169
+ debug('Loaded appname(%s) from package.json', this.pkg.name);
170
+ return this.pkg.name;
171
+ }
172
+ const pkg = path.join(this.options.baseDir, 'package.json');
173
+ throw new Error(`name is required from ${pkg}`);
174
+ }
175
+ /**
176
+ * Get home directory
177
+ * @returns {String} home directory
178
+ * @since 3.4.0
179
+ */
180
+ getHomedir() {
181
+ // EGG_HOME for test
182
+ return process.env.EGG_HOME || homedir() || '/home/admin';
183
+ }
184
+ /**
185
+ * Get app info
186
+ * @returns {AppInfo} appInfo
187
+ * @since 1.0.0
188
+ */
189
+ getAppInfo() {
190
+ const env = this.serverEnv;
191
+ const scope = this.serverScope;
192
+ const home = this.getHomedir();
193
+ const baseDir = this.options.baseDir;
194
+ /**
195
+ * Meta information of the application
196
+ * @class AppInfo
197
+ */
198
+ return {
199
+ /**
200
+ * The name of the application, retrieve from the name property in `package.json`.
201
+ * @member {String} AppInfo#name
202
+ */
203
+ name: this.getAppname(),
204
+ /**
205
+ * The current directory, where the application code is.
206
+ * @member {String} AppInfo#baseDir
207
+ */
208
+ baseDir,
209
+ /**
210
+ * The environment of the application, **it's not NODE_ENV**
211
+ *
212
+ * 1. from `$baseDir/config/env`
213
+ * 2. from EGG_SERVER_ENV
214
+ * 3. from NODE_ENV
215
+ *
216
+ * env | description
217
+ * --- | ---
218
+ * test | system integration testing
219
+ * prod | production
220
+ * local | local on your own computer
221
+ * unittest | unit test
222
+ *
223
+ * @member {String} AppInfo#env
224
+ * @see https://eggjs.org/zh-cn/basics/env.html
225
+ */
226
+ env,
227
+ /**
228
+ * @member {String} AppInfo#scope
229
+ */
230
+ scope,
231
+ /**
232
+ * The use directory, same as `process.env.HOME`
233
+ * @member {String} AppInfo#HOME
234
+ */
235
+ HOME: home,
236
+ /**
237
+ * parsed from `package.json`
238
+ * @member {Object} AppInfo#pkg
239
+ */
240
+ pkg: this.pkg,
241
+ /**
242
+ * The directory whether is baseDir or HOME depend on env.
243
+ * it's good for test when you want to write some file to HOME,
244
+ * but don't want to write to the real directory,
245
+ * so use root to write file to baseDir instead of HOME when unittest.
246
+ * keep root directory in baseDir when local and unittest
247
+ * @member {String} AppInfo#root
248
+ */
249
+ root: env === 'local' || env === 'unittest' ? baseDir : home,
250
+ };
251
+ }
252
+ /**
253
+ * Get {@link EggLoader#eggPaths}
254
+ * @returns {Array} framework directories
255
+ * @see {@link EggLoader#eggPaths}
256
+ * @private
257
+ * @since 1.0.0
258
+ */
259
+ getEggPaths() {
260
+ // avoid require recursively
261
+ const EggCore = this.options.EggCoreClass;
262
+ const eggPaths = [];
263
+ let proto = this.app;
264
+ // Loop for the prototype chain
265
+ while (proto) {
266
+ proto = Object.getPrototypeOf(proto);
267
+ // stop the loop if
268
+ // - object extends Object
269
+ // - object extends EggCore
270
+ if (proto === Object.prototype || proto === EggCore?.prototype) {
271
+ break;
272
+ }
273
+ const eggPath = Reflect.get(proto, Symbol.for('egg#eggPath'));
274
+ if (!eggPath) {
275
+ // if (EggCore) {
276
+ // throw new TypeError('Symbol.for(\'egg#eggPath\') is required on Application');
277
+ // }
278
+ continue;
279
+ }
280
+ assert(typeof eggPath === 'string', "Symbol.for('egg#eggPath') should be string");
281
+ assert(fs.existsSync(eggPath), `${eggPath} not exists`);
282
+ const realpath = fs.realpathSync(eggPath);
283
+ if (!eggPaths.includes(realpath)) {
284
+ eggPaths.unshift(realpath);
285
+ }
286
+ }
287
+ return eggPaths;
288
+ }
289
+ /** start Plugin loader */
290
+ lookupDirs;
291
+ eggPlugins;
292
+ appPlugins;
293
+ customPlugins;
294
+ allPlugins;
295
+ orderPlugins;
296
+ /** enable plugins */
297
+ plugins;
298
+ /**
299
+ * Load config/plugin.js from {EggLoader#loadUnits}
300
+ *
301
+ * plugin.js is written below
302
+ *
303
+ * ```js
304
+ * {
305
+ * 'xxx-client': {
306
+ * enable: true,
307
+ * package: 'xxx-client',
308
+ * dep: [],
309
+ * env: [],
310
+ * },
311
+ * // short hand
312
+ * 'rds': false,
313
+ * 'depd': {
314
+ * enable: true,
315
+ * path: 'path/to/depd'
316
+ * }
317
+ * }
318
+ * ```
319
+ *
320
+ * If the plugin has path, Loader will find the module from it.
321
+ *
322
+ * Otherwise Loader will lookup follow the order by packageName
323
+ *
324
+ * 1. $APP_BASE/node_modules/${package}
325
+ * 2. $EGG_BASE/node_modules/${package}
326
+ *
327
+ * You can call `loader.plugins` that retrieve enabled plugins.
328
+ *
329
+ * ```js
330
+ * loader.plugins['xxx-client'] = {
331
+ * name: 'xxx-client', // the plugin name, it can be used in `dep`
332
+ * package: 'xxx-client', // the package name of plugin
333
+ * enable: true, // whether enabled
334
+ * path: 'path/to/xxx-client', // the directory of the plugin package
335
+ * dep: [], // the dependent plugins, you can use the plugin name
336
+ * env: [ 'local', 'unittest' ], // specify the serverEnv that only enable the plugin in it
337
+ * }
338
+ * ```
339
+ *
340
+ * `loader.allPlugins` can be used when retrieve all plugins.
341
+ * @function EggLoader#loadPlugin
342
+ * @since 1.0.0
343
+ */
344
+ async loadPlugin() {
345
+ this.timing.start('Load Plugin');
346
+ this.lookupDirs = this.getLookupDirs();
347
+ this.allPlugins = {};
348
+ this.eggPlugins = await this.loadEggPlugins();
349
+ this.appPlugins = await this.loadAppPlugins();
350
+ this.customPlugins = this.loadCustomPlugins();
351
+ this.#extendPlugins(this.allPlugins, this.eggPlugins);
352
+ this.#extendPlugins(this.allPlugins, this.appPlugins);
353
+ this.#extendPlugins(this.allPlugins, this.customPlugins);
354
+ const enabledPluginNames = []; // enabled plugins that configured explicitly
355
+ const plugins = {};
356
+ const env = this.serverEnv;
357
+ for (const name in this.allPlugins) {
358
+ const plugin = this.allPlugins[name];
359
+ // resolve the real plugin.path based on plugin or package
360
+ plugin.path = this.getPluginPath(plugin);
361
+ // read plugin information from ${plugin.path}/package.json
362
+ await this.#mergePluginConfig(plugin);
363
+ // disable the plugin that not match the serverEnv
364
+ if (env && plugin.env.length > 0 && !plugin.env.includes(env)) {
365
+ this.logger.info('[egg/core] Plugin %o is disabled by env unmatched, require env(%o) but got env is %o', name, plugin.env, env);
366
+ plugin.enable = false;
367
+ continue;
368
+ }
369
+ plugins[name] = plugin;
370
+ if (plugin.enable) {
371
+ enabledPluginNames.push(name);
372
+ }
373
+ }
374
+ // retrieve the ordered plugins
375
+ this.orderPlugins = this.getOrderPlugins(plugins, enabledPluginNames, this.appPlugins);
376
+ const enablePlugins = {};
377
+ for (const plugin of this.orderPlugins) {
378
+ enablePlugins[plugin.name] = plugin;
379
+ }
380
+ debug('Loaded enable plugins: %j', Object.keys(enablePlugins));
381
+ /**
382
+ * Retrieve enabled plugins
383
+ * @member {Object} EggLoader#plugins
384
+ * @since 1.0.0
385
+ */
386
+ this.plugins = enablePlugins;
387
+ this.timing.end('Load Plugin');
388
+ }
389
+ async loadAppPlugins() {
390
+ // loader plugins from application
391
+ const appPlugins = await this.readPluginConfigs(path.join(this.options.baseDir, 'config/plugin.default'));
392
+ debug('Loaded app plugins: %j', Object.keys(appPlugins).map(k => `${k}:${appPlugins[k].enable}`));
393
+ return appPlugins;
394
+ }
395
+ async loadEggPlugins() {
396
+ // loader plugins from framework
397
+ const eggPluginConfigPaths = this.eggPaths.map(eggPath => path.join(eggPath, 'config/plugin.default'));
398
+ const eggPlugins = await this.readPluginConfigs(eggPluginConfigPaths);
399
+ debug('Loaded egg plugins: %j', Object.keys(eggPlugins).map(k => `${k}:${eggPlugins[k].enable}`));
400
+ return eggPlugins;
401
+ }
402
+ loadCustomPlugins() {
403
+ // loader plugins from process.env.EGG_PLUGINS
404
+ let customPlugins = {};
405
+ const configPaths = [];
406
+ if (process.env.EGG_PLUGINS) {
407
+ try {
408
+ customPlugins = JSON.parse(process.env.EGG_PLUGINS);
409
+ configPaths.push('<process.env.EGG_PLUGINS>');
410
+ }
411
+ catch (e) {
412
+ debug('parse EGG_PLUGINS failed, %s', e);
413
+ }
414
+ }
415
+ // loader plugins from options.plugins
416
+ if (this.options.plugins) {
417
+ customPlugins = {
418
+ ...customPlugins,
419
+ ...this.options.plugins,
420
+ };
421
+ configPaths.push('<options.plugins>');
422
+ }
423
+ if (customPlugins) {
424
+ const configPath = configPaths.join(' or ');
425
+ for (const name in customPlugins) {
426
+ this.#normalizePluginConfig(customPlugins, name, configPath);
427
+ }
428
+ debug('Loaded custom plugins: %o', customPlugins);
429
+ }
430
+ return customPlugins;
431
+ }
432
+ /*
433
+ * Read plugin.js from multiple directory
434
+ */
435
+ async readPluginConfigs(configPaths) {
436
+ if (!Array.isArray(configPaths)) {
437
+ configPaths = [configPaths];
438
+ }
439
+ // Get all plugin configurations
440
+ // plugin.default.js
441
+ // plugin.${scope}.js
442
+ // plugin.${env}.js
443
+ // plugin.${scope}_${env}.js
444
+ const newConfigPaths = [];
445
+ for (const filename of this.getTypeFiles('plugin')) {
446
+ for (let configPath of configPaths) {
447
+ configPath = path.join(path.dirname(configPath), filename);
448
+ newConfigPaths.push(configPath);
449
+ }
450
+ }
451
+ const plugins = {};
452
+ for (const configPath of newConfigPaths) {
453
+ let filepath = this.resolveModule(configPath);
454
+ // let plugin.js compatible
455
+ if (configPath.endsWith('plugin.default') && !filepath) {
456
+ filepath = this.resolveModule(configPath.replace(/plugin\.default$/, 'plugin'));
457
+ }
458
+ if (!filepath) {
459
+ debug('[readPluginConfigs:ignore] plugin config not found %o', configPath);
460
+ continue;
461
+ }
462
+ const config = await utils.loadFile(filepath);
463
+ for (const name in config) {
464
+ this.#normalizePluginConfig(config, name, filepath);
465
+ }
466
+ this.#extendPlugins(plugins, config);
467
+ }
468
+ return plugins;
469
+ }
470
+ #normalizePluginConfig(plugins, name, configPath) {
471
+ const plugin = plugins[name];
472
+ // plugin_name: false
473
+ if (typeof plugin === 'boolean') {
474
+ plugins[name] = {
475
+ name,
476
+ enable: plugin,
477
+ dependencies: [],
478
+ optionalDependencies: [],
479
+ env: [],
480
+ from: configPath,
481
+ };
482
+ return;
483
+ }
484
+ if (!('enable' in plugin)) {
485
+ Reflect.set(plugin, 'enable', true);
486
+ }
487
+ plugin.name = name;
488
+ plugin.dependencies = plugin.dependencies || [];
489
+ plugin.optionalDependencies = plugin.optionalDependencies || [];
490
+ plugin.env = plugin.env || [];
491
+ plugin.from = plugin.from || configPath;
492
+ depCompatible(plugin);
493
+ }
494
+ // Read plugin information from package.json and merge
495
+ // {
496
+ // eggPlugin: {
497
+ // "name": "", plugin name, must be same as name in config/plugin.js
498
+ // "dep": [], dependent plugins
499
+ // "env": "" env
500
+ // "strict": true, whether check plugin name, default to true.
501
+ // }
502
+ // }
503
+ async #mergePluginConfig(plugin) {
504
+ let pkg;
505
+ let config;
506
+ const pluginPackage = path.join(plugin.path, 'package.json');
507
+ if (await utils.existsPath(pluginPackage)) {
508
+ pkg = await readJSON(pluginPackage);
509
+ config = pkg.eggPlugin;
510
+ if (pkg.version) {
511
+ plugin.version = pkg.version;
512
+ }
513
+ // support commonjs and esm dist files
514
+ plugin.path = await this.#formatPluginPathFromPackageJSON(plugin.path, pkg);
515
+ }
516
+ const logger = this.options.logger;
517
+ if (!config) {
518
+ logger.warn(`[@eggjs/core/egg_loader] pkg.eggPlugin is missing in ${pluginPackage}`);
519
+ return;
520
+ }
521
+ if (config.name && config.strict !== false && config.name !== plugin.name) {
522
+ // pluginName is configured in config/plugin.js
523
+ // pluginConfigName is pkg.eggPlugin.name
524
+ logger.warn(`[@eggjs/core/egg_loader] pluginName(${plugin.name}) is different from pluginConfigName(${config.name})`);
525
+ }
526
+ // dep compatible
527
+ depCompatible(config);
528
+ for (const key of ['dependencies', 'optionalDependencies', 'env']) {
529
+ const values = config[key];
530
+ const existsValues = Reflect.get(plugin, key);
531
+ if (Array.isArray(values) && !existsValues?.length) {
532
+ Reflect.set(plugin, key, values);
533
+ }
534
+ }
535
+ }
536
+ getOrderPlugins(allPlugins, enabledPluginNames, appPlugins) {
537
+ // no plugins enabled
538
+ if (enabledPluginNames.length === 0) {
539
+ return [];
540
+ }
541
+ const result = sequencify(allPlugins, enabledPluginNames);
542
+ debug('Got plugins %j after sequencify', result);
543
+ // catch error when result.sequence is empty
544
+ if (result.sequence.length === 0) {
545
+ const err = new Error(`sequencify plugins has problem, missing: [${result.missingTasks}], recursive: [${result.recursiveDependencies}]`);
546
+ // find plugins which is required by the missing plugin
547
+ for (const missName of result.missingTasks) {
548
+ const requires = [];
549
+ for (const name in allPlugins) {
550
+ if (allPlugins[name].dependencies.includes(missName)) {
551
+ requires.push(name);
552
+ }
553
+ }
554
+ err.message += `\n\t>> Plugin [${missName}] is disabled or missed, but is required by [${requires}]`;
555
+ }
556
+ err.name = 'PluginSequencifyError';
557
+ throw err;
558
+ }
559
+ // log the plugins that be enabled implicitly
560
+ const implicitEnabledPlugins = [];
561
+ const requireMap = {};
562
+ for (const name of result.sequence) {
563
+ for (const depName of allPlugins[name].dependencies) {
564
+ if (!requireMap[depName]) {
565
+ requireMap[depName] = [];
566
+ }
567
+ requireMap[depName].push(name);
568
+ }
569
+ if (!allPlugins[name].enable) {
570
+ implicitEnabledPlugins.push(name);
571
+ allPlugins[name].enable = true;
572
+ allPlugins[name].implicitEnable = true;
573
+ }
574
+ }
575
+ for (const [name, dependents] of Object.entries(requireMap)) {
576
+ // note:`dependents` will not includes `optionalDependencies`
577
+ allPlugins[name].dependents = dependents;
578
+ }
579
+ // Following plugins will be enabled implicitly.
580
+ // - configclient required by [rpcClient]
581
+ // - monitor required by [rpcClient]
582
+ // - diamond required by [rpcClient]
583
+ if (implicitEnabledPlugins.length > 0) {
584
+ let message = implicitEnabledPlugins.map(name => ` - ${name} required by [${requireMap[name]}]`).join('\n');
585
+ this.options.logger.info(`Following plugins will be enabled implicitly.\n${message}`);
586
+ // should warn when the plugin is disabled by app
587
+ const disabledPlugins = implicitEnabledPlugins.filter(name => appPlugins[name] && appPlugins[name].enable === false);
588
+ if (disabledPlugins.length > 0) {
589
+ message = disabledPlugins.map(name => ` - ${name} required by [${requireMap[name]}]`).join('\n');
590
+ this.options.logger.warn(`Following plugins will be enabled implicitly that is disabled by application.\n${message}`);
591
+ }
592
+ }
593
+ return result.sequence.map(name => allPlugins[name]);
594
+ }
595
+ getLookupDirs() {
596
+ const lookupDirs = new Set();
597
+ // try to locate the plugin in the following directories's node_modules
598
+ // -> {APP_PATH} -> {EGG_PATH} -> $CWD
599
+ lookupDirs.add(this.options.baseDir);
600
+ // try to locate the plugin at framework from upper to lower
601
+ for (let i = this.eggPaths.length - 1; i >= 0; i--) {
602
+ const eggPath = this.eggPaths[i];
603
+ lookupDirs.add(eggPath);
604
+ }
605
+ // should find the $cwd when test the plugins under npm3
606
+ lookupDirs.add(process.cwd());
607
+ return lookupDirs;
608
+ }
609
+ // Get the real plugin path
610
+ getPluginPath(plugin) {
611
+ if (plugin.path) {
612
+ return plugin.path;
613
+ }
614
+ if (plugin.package) {
615
+ assert(isValidatePackageName(plugin.package), `plugin ${plugin.name} invalid, use 'path' instead of package: "${plugin.package}"`);
616
+ }
617
+ return this.#resolvePluginPath(plugin);
618
+ }
619
+ #resolvePluginPath(plugin) {
620
+ const name = plugin.package || plugin.name;
621
+ try {
622
+ // should find the plugin directory
623
+ // pnpm will lift the node_modules to the sibling directory
624
+ // 'node_modules/.pnpm/yadan@2.0.0/node_modules/yadan/node_modules',
625
+ // 'node_modules/.pnpm/yadan@2.0.0/node_modules', <- this is the sibling directory
626
+ // 'node_modules/.pnpm/egg@2.33.1/node_modules/egg/node_modules',
627
+ // 'node_modules/.pnpm/egg@2.33.1/node_modules', <- this is the sibling directory
628
+ const pluginPkgFile = utils.resolvePath(`${name}/package.json`, {
629
+ paths: [...this.lookupDirs],
630
+ });
631
+ return path.dirname(pluginPkgFile);
632
+ }
633
+ catch (err) {
634
+ debug('[resolvePluginPath] error: %o, plugin info: %o', err, plugin);
635
+ throw new Error(`Can not find plugin ${name} in "${[...this.lookupDirs].join(', ')}"`, {
636
+ cause: err,
637
+ });
638
+ }
639
+ }
640
+ async #formatPluginPathFromPackageJSON(pluginPath, pluginPkg) {
641
+ let realPluginPath = pluginPath;
642
+ const exports = pluginPkg.eggPlugin?.exports;
643
+ if (exports) {
644
+ if (isESM) {
645
+ if (exports.import) {
646
+ realPluginPath = path.join(pluginPath, exports.import);
647
+ }
648
+ }
649
+ else if (exports.require) {
650
+ realPluginPath = path.join(pluginPath, exports.require);
651
+ }
652
+ if (exports.typescript && isSupportTypeScript() && !(await exists(realPluginPath))) {
653
+ // if require/import path not exists, use typescript path for development stage
654
+ realPluginPath = path.join(pluginPath, exports.typescript);
655
+ debug('[formatPluginPathFromPackageJSON] use typescript path %o', realPluginPath);
656
+ }
657
+ }
658
+ else if (pluginPkg.exports?.['.'] && pluginPkg.type === 'module') {
659
+ // support esm exports
660
+ let defaultExport = pluginPkg.exports['.'];
661
+ if (typeof defaultExport === 'string') {
662
+ // "exports": {
663
+ // ".": "./src/index.ts",
664
+ // "./app": "./src/app.ts",
665
+ // }
666
+ realPluginPath = path.dirname(path.join(pluginPath, defaultExport));
667
+ }
668
+ else if (defaultExport?.import) {
669
+ if (typeof defaultExport.import === 'string') {
670
+ // {
671
+ // "exports": {
672
+ // ".": {
673
+ // "import": "./src/index.ts",
674
+ // },
675
+ // }
676
+ // }
677
+ realPluginPath = path.dirname(path.join(pluginPath, defaultExport.import));
678
+ }
679
+ else if (defaultExport.import.default) {
680
+ // {
681
+ // "exports": {
682
+ // ".": {
683
+ // "import": {
684
+ // "default": "./src/index.ts",
685
+ // },
686
+ // },
687
+ // }
688
+ // }
689
+ realPluginPath = path.dirname(path.join(pluginPath, defaultExport.import.default));
690
+ }
691
+ }
692
+ debug('[formatPluginPathFromPackageJSON] resolve plugin path from %o to %o, defaultExport: %o', pluginPath, realPluginPath, defaultExport);
693
+ }
694
+ return realPluginPath;
695
+ }
696
+ #extendPlugins(targets, plugins) {
697
+ if (!plugins) {
698
+ return;
699
+ }
700
+ for (const name in plugins) {
701
+ const plugin = plugins[name];
702
+ let targetPlugin = targets[name];
703
+ if (!targetPlugin) {
704
+ targetPlugin = {};
705
+ targets[name] = targetPlugin;
706
+ }
707
+ if (targetPlugin.package && targetPlugin.package === plugin.package) {
708
+ this.logger.warn('[@eggjs/core] plugin %s has been defined that is %j, but you define again in %s', name, targetPlugin, plugin.from);
709
+ }
710
+ if (plugin.path || plugin.package) {
711
+ delete targetPlugin.path;
712
+ delete targetPlugin.package;
713
+ }
714
+ for (const [prop, value] of Object.entries(plugin)) {
715
+ if (value === undefined) {
716
+ continue;
717
+ }
718
+ if (Reflect.get(targetPlugin, prop) && Array.isArray(value) && value.length === 0) {
719
+ continue;
720
+ }
721
+ Reflect.set(targetPlugin, prop, value);
722
+ }
723
+ }
724
+ }
725
+ /** end Plugin loader */
726
+ /** start Config loader */
727
+ configMeta;
728
+ config;
729
+ /**
730
+ * Load config/config.js
731
+ *
732
+ * Will merge config.default.js 和 config.${env}.js
733
+ *
734
+ * @function EggLoader#loadConfig
735
+ * @since 1.0.0
736
+ */
737
+ async loadConfig() {
738
+ this.timing.start('Load Config');
739
+ this.configMeta = {};
740
+ const target = {
741
+ middleware: [],
742
+ coreMiddleware: [],
743
+ };
744
+ // Load Application config first
745
+ const appConfig = await this.#preloadAppConfig();
746
+ // plugin config.default
747
+ // framework config.default
748
+ // app config.default
749
+ // plugin config.{env}
750
+ // framework config.{env}
751
+ // app config.{env}
752
+ for (const filename of this.getTypeFiles('config')) {
753
+ for (const unit of this.getLoadUnits()) {
754
+ const isApp = unit.type === 'app';
755
+ const config = await this.#loadConfig(unit.path, filename, isApp ? undefined : appConfig, unit.type);
756
+ if (!config) {
757
+ continue;
758
+ }
759
+ debug('[loadConfig] Loaded config %s/%s, %j', unit.path, filename, config);
760
+ extend(true, target, config);
761
+ }
762
+ }
763
+ // load env from process.env.EGG_APP_CONFIG
764
+ const envConfig = this.#loadConfigFromEnv();
765
+ debug('[loadConfig] Loaded config from env, %j', envConfig);
766
+ extend(true, target, envConfig);
767
+ // You can manipulate the order of app.config.coreMiddleware and app.config.appMiddleware in app.js
768
+ target.coreMiddleware = target.coreMiddleware || [];
769
+ // alias for coreMiddleware
770
+ target.coreMiddlewares = target.coreMiddleware;
771
+ target.appMiddleware = target.middleware || [];
772
+ // alias for appMiddleware
773
+ target.appMiddlewares = target.appMiddleware;
774
+ this.config = target;
775
+ debug('[loadConfig] all config: %o', this.config);
776
+ this.timing.end('Load Config');
777
+ }
778
+ async #preloadAppConfig() {
779
+ const names = ['config.default', `config.${this.serverEnv}`];
780
+ const target = {};
781
+ for (const filename of names) {
782
+ const config = await this.#loadConfig(this.options.baseDir, filename, undefined, 'app');
783
+ if (!config) {
784
+ continue;
785
+ }
786
+ extend(true, target, config);
787
+ }
788
+ return target;
789
+ }
790
+ async #loadConfig(dirpath, filename, extraInject, type) {
791
+ const isPlugin = type === 'plugin';
792
+ const isApp = type === 'app';
793
+ let filepath = this.resolveModule(path.join(dirpath, 'config', filename));
794
+ // let config.js compatible
795
+ if (filename === 'config.default' && !filepath) {
796
+ filepath = this.resolveModule(path.join(dirpath, 'config/config'));
797
+ }
798
+ if (!filepath) {
799
+ return;
800
+ }
801
+ const config = await this.loadFile(filepath, this.appInfo, extraInject);
802
+ if (!config)
803
+ return;
804
+ if (isPlugin || isApp) {
805
+ assert(!config.coreMiddleware, 'Can not define coreMiddleware in app or plugin');
806
+ }
807
+ if (!isApp) {
808
+ assert(!config.middleware, 'Can not define middleware in ' + filepath);
809
+ }
810
+ // store config meta, check where is the property of config come from.
811
+ this.#setConfigMeta(config, filepath);
812
+ return config;
813
+ }
814
+ #loadConfigFromEnv() {
815
+ const envConfigStr = process.env.EGG_APP_CONFIG;
816
+ if (!envConfigStr)
817
+ return;
818
+ try {
819
+ const envConfig = JSON.parse(envConfigStr);
820
+ this.#setConfigMeta(envConfig, '<process.env.EGG_APP_CONFIG>');
821
+ return envConfig;
822
+ }
823
+ catch {
824
+ this.options.logger.warn('[egg-loader] process.env.EGG_APP_CONFIG is not invalid JSON: %s', envConfigStr);
825
+ }
826
+ }
827
+ #setConfigMeta(config, filepath) {
828
+ config = extend(true, {}, config);
829
+ this.#setConfig(config, filepath);
830
+ extend(true, this.configMeta, config);
831
+ }
832
+ #setConfig(obj, filepath) {
833
+ for (const key of Object.keys(obj)) {
834
+ const val = obj[key];
835
+ // ignore console
836
+ if (key === 'console' && val && typeof val.Console === 'function' && val.Console === console.Console) {
837
+ obj[key] = filepath;
838
+ continue;
839
+ }
840
+ if (val && Object.getPrototypeOf(val) === Object.prototype && Object.keys(val).length > 0) {
841
+ this.#setConfig(val, filepath);
842
+ continue;
843
+ }
844
+ obj[key] = filepath;
845
+ }
846
+ }
847
+ /** end Config loader */
848
+ /** start Extend loader */
849
+ /**
850
+ * mixin Agent.prototype
851
+ * @function EggLoader#loadAgentExtend
852
+ * @since 1.0.0
853
+ */
854
+ async loadAgentExtend() {
855
+ await this.loadExtend('agent', this.app);
856
+ }
857
+ /**
858
+ * mixin Application.prototype
859
+ * @function EggLoader#loadApplicationExtend
860
+ * @since 1.0.0
861
+ */
862
+ async loadApplicationExtend() {
863
+ await this.loadExtend('application', this.app);
864
+ }
865
+ /**
866
+ * mixin Request.prototype
867
+ * @function EggLoader#loadRequestExtend
868
+ * @since 1.0.0
869
+ */
870
+ async loadRequestExtend() {
871
+ await this.loadExtend('request', this.app.request);
872
+ }
873
+ /**
874
+ * mixin Response.prototype
875
+ * @function EggLoader#loadResponseExtend
876
+ * @since 1.0.0
877
+ */
878
+ async loadResponseExtend() {
879
+ await this.loadExtend('response', this.app.response);
880
+ }
881
+ /**
882
+ * mixin Context.prototype
883
+ * @function EggLoader#loadContextExtend
884
+ * @since 1.0.0
885
+ */
886
+ async loadContextExtend() {
887
+ await this.loadExtend('context', this.app.context);
888
+ }
889
+ /**
890
+ * mixin app.Helper.prototype
891
+ * @function EggLoader#loadHelperExtend
892
+ * @since 1.0.0
893
+ */
894
+ async loadHelperExtend() {
895
+ if (this.app.Helper) {
896
+ await this.loadExtend('helper', this.app.Helper.prototype);
897
+ }
898
+ }
899
+ /**
900
+ * Find all extend file paths by name
901
+ * can be override in top level framework to support load `app/extends/{name}.js`
902
+ *
903
+ * @param {String} name - filename which may be `app/extend/{name}.js`
904
+ * @returns {Array} filepaths extend file paths
905
+ * @private
906
+ */
907
+ getExtendFilePaths(name) {
908
+ return this.getLoadUnits().map(unit => path.join(unit.path, 'app/extend', name));
909
+ }
910
+ /**
911
+ * Loader app/extend/xx.js to `prototype`,
912
+ * @function loadExtend
913
+ * @param {String} name - filename which may be `app/extend/{name}.js`
914
+ * @param {Object} proto - prototype that mixed
915
+ * @since 1.0.0
916
+ */
917
+ async loadExtend(name, proto) {
918
+ this.timing.start(`Load extend/${name}.js`);
919
+ // All extend files
920
+ const filepaths = this.getExtendFilePaths(name);
921
+ // if use mm.env and serverEnv is not unittest
922
+ const needUnittest = 'EGG_MOCK_SERVER_ENV' in process.env && this.serverEnv !== 'unittest';
923
+ const length = filepaths.length;
924
+ for (let i = 0; i < length; i++) {
925
+ const filepath = filepaths[i];
926
+ filepaths.push(filepath + `.${this.serverEnv}`);
927
+ if (needUnittest) {
928
+ filepaths.push(filepath + '.unittest');
929
+ }
930
+ }
931
+ debug('loadExtend %s, filepaths: %j', name, filepaths);
932
+ const mergeRecord = new Map();
933
+ for (const rawFilepath of filepaths) {
934
+ const filepath = this.resolveModule(rawFilepath);
935
+ if (!filepath) {
936
+ // debug('loadExtend %o not found', rawFilepath);
937
+ continue;
938
+ }
939
+ if (filepath.endsWith('/index.js')) {
940
+ this.app.deprecate(`app/extend/${name}/index.js is deprecated, use app/extend/${name}.js instead`);
941
+ }
942
+ else if (filepath.endsWith('/index.ts')) {
943
+ this.app.deprecate(`app/extend/${name}/index.ts is deprecated, use app/extend/${name}.ts instead`);
944
+ }
945
+ let ext = await this.requireFile(filepath);
946
+ // if extend object is Class, should use Class.prototype instead
947
+ if (isClass(ext)) {
948
+ ext = ext.prototype;
949
+ }
950
+ const properties = Object.getOwnPropertyNames(ext)
951
+ .concat(Object.getOwnPropertySymbols(ext))
952
+ .filter(name => name !== 'constructor'); // ignore class constructor for extend
953
+ for (const property of properties) {
954
+ if (mergeRecord.has(property)) {
955
+ debug('Property: "%s" already exists in "%s",it will be redefined by "%s"', property, mergeRecord.get(property), filepath);
956
+ }
957
+ // Copy descriptor
958
+ let descriptor = Object.getOwnPropertyDescriptor(ext, property);
959
+ let originalDescriptor = Object.getOwnPropertyDescriptor(proto, property);
960
+ if (!originalDescriptor) {
961
+ // try to get descriptor from originalPrototypes
962
+ const originalProto = originalPrototypes[name];
963
+ if (originalProto) {
964
+ originalDescriptor = Object.getOwnPropertyDescriptor(originalProto, property);
965
+ }
966
+ }
967
+ if (originalDescriptor) {
968
+ // don't override descriptor
969
+ descriptor = {
970
+ ...descriptor,
971
+ };
972
+ if (!descriptor.set && originalDescriptor.set) {
973
+ descriptor.set = originalDescriptor.set;
974
+ }
975
+ if (!descriptor.get && originalDescriptor.get) {
976
+ descriptor.get = originalDescriptor.get;
977
+ }
978
+ }
979
+ Object.defineProperty(proto, property, descriptor);
980
+ mergeRecord.set(property, filepath);
981
+ }
982
+ debug('merge %j to %s from %s', properties, name, filepath);
983
+ }
984
+ this.timing.end(`Load extend/${name}.js`);
985
+ }
986
+ /** end Extend loader */
987
+ /** start Custom loader */
988
+ /**
989
+ * load app.js
990
+ *
991
+ * @example
992
+ * - old:
993
+ *
994
+ * ```js
995
+ * module.exports = function(app) {
996
+ * doSomething();
997
+ * }
998
+ * ```
999
+ *
1000
+ * - new:
1001
+ *
1002
+ * ```js
1003
+ * module.exports = class Boot {
1004
+ * constructor(app) {
1005
+ * this.app = app;
1006
+ * }
1007
+ * configDidLoad() {
1008
+ * doSomething();
1009
+ * }
1010
+ * }
1011
+ * @since 1.0.0
1012
+ */
1013
+ async loadCustomApp() {
1014
+ await this.#loadBootHook('app');
1015
+ this.lifecycle.triggerConfigWillLoad();
1016
+ }
1017
+ /**
1018
+ * Load agent.js, same as {@link EggLoader#loadCustomApp}
1019
+ */
1020
+ async loadCustomAgent() {
1021
+ await this.#loadBootHook('agent');
1022
+ this.lifecycle.triggerConfigWillLoad();
1023
+ }
1024
+ // FIXME: no logger used after egg removed
1025
+ loadBootHook() {
1026
+ // do nothing
1027
+ }
1028
+ async #loadBootHook(fileName) {
1029
+ this.timing.start(`Load ${fileName}.js`);
1030
+ for (const unit of this.getLoadUnits()) {
1031
+ const bootFile = path.join(unit.path, fileName);
1032
+ const bootFilePath = this.resolveModule(bootFile);
1033
+ if (!bootFilePath) {
1034
+ debug('[loadBootHook:ignore] %o not found', bootFile);
1035
+ continue;
1036
+ }
1037
+ debug('[loadBootHook:success] %o => %o', bootFile, bootFilePath);
1038
+ const bootHook = await this.requireFile(bootFilePath);
1039
+ if (isClass(bootHook)) {
1040
+ bootHook.prototype.fullPath = bootFilePath;
1041
+ // if is boot class, add to lifecycle
1042
+ this.lifecycle.addBootHook(bootHook);
1043
+ debug('[loadBootHook] add BootHookClass from %o', bootFilePath);
1044
+ }
1045
+ else if (typeof bootHook === 'function') {
1046
+ // if is boot function, wrap to class
1047
+ // for compatibility
1048
+ this.lifecycle.addFunctionAsBootHook(bootHook, bootFilePath);
1049
+ debug('[loadBootHook] add bootHookFunction from %o', bootFilePath);
1050
+ }
1051
+ else {
1052
+ this.options.logger.warn('[@eggjs/core/egg_loader] %s must exports a boot class', bootFilePath);
1053
+ }
1054
+ }
1055
+ // init boots
1056
+ this.lifecycle.init();
1057
+ this.timing.end(`Load ${fileName}.js`);
1058
+ }
1059
+ /** end Custom loader */
1060
+ /** start Service loader */
1061
+ /**
1062
+ * Load app/service
1063
+ * @function EggLoader#loadService
1064
+ * @param {Object} options - LoaderOptions
1065
+ * @since 1.0.0
1066
+ */
1067
+ async loadService(options) {
1068
+ this.timing.start('Load Service');
1069
+ // 载入到 app.serviceClasses
1070
+ const servicePaths = this.getLoadUnits().map(unit => path.join(unit.path, 'app/service'));
1071
+ options = {
1072
+ call: true,
1073
+ caseStyle: CaseStyle.lower,
1074
+ fieldClass: 'serviceClasses',
1075
+ directory: servicePaths,
1076
+ ...options,
1077
+ };
1078
+ debug('[loadService] options: %o', options);
1079
+ await this.loadToContext(servicePaths, 'service', options);
1080
+ this.timing.end('Load Service');
1081
+ }
1082
+ /** end Service loader */
1083
+ /** start Middleware loader */
1084
+ /**
1085
+ * Load app/middleware
1086
+ *
1087
+ * app.config.xx is the options of the middleware xx that has same name as config
1088
+ *
1089
+ * @function EggLoader#loadMiddleware
1090
+ * @param {Object} opt - LoaderOptions
1091
+ * @example
1092
+ * ```js
1093
+ * // app/middleware/status.js
1094
+ * module.exports = function(options, app) {
1095
+ * // options == app.config.status
1096
+ * return async next => {
1097
+ * await next();
1098
+ * }
1099
+ * }
1100
+ * ```
1101
+ * @since 1.0.0
1102
+ */
1103
+ async loadMiddleware(opt) {
1104
+ this.timing.start('Load Middleware');
1105
+ const app = this.app;
1106
+ // load middleware to app.middleware
1107
+ const middlewarePaths = this.getLoadUnits().map(unit => path.join(unit.path, 'app/middleware'));
1108
+ opt = {
1109
+ call: false,
1110
+ override: true,
1111
+ caseStyle: CaseStyle.lower,
1112
+ directory: middlewarePaths,
1113
+ ...opt,
1114
+ };
1115
+ await this.loadToApp(middlewarePaths, 'middlewares', opt);
1116
+ debug('[loadMiddleware] middlewarePaths: %j', middlewarePaths);
1117
+ for (const name in app.middlewares) {
1118
+ Object.defineProperty(app.middleware, name, {
1119
+ get() {
1120
+ return app.middlewares[name];
1121
+ },
1122
+ enumerable: false,
1123
+ configurable: false,
1124
+ });
1125
+ }
1126
+ this.options.logger.info('Use coreMiddleware order: %j', this.config.coreMiddleware);
1127
+ this.options.logger.info('Use appMiddleware order: %j', this.config.appMiddleware);
1128
+ // use middleware ordered by app.config.coreMiddleware and app.config.appMiddleware
1129
+ const middlewareNames = this.config.coreMiddleware.concat(this.config.appMiddleware);
1130
+ debug('[loadMiddleware] middlewareNames: %j', middlewareNames);
1131
+ const middlewaresMap = new Map();
1132
+ for (const name of middlewareNames) {
1133
+ const createMiddleware = app.middlewares[name];
1134
+ if (!createMiddleware) {
1135
+ throw new TypeError(`Middleware ${name} not found`);
1136
+ }
1137
+ if (middlewaresMap.has(name)) {
1138
+ throw new TypeError(`Middleware ${name} redefined`);
1139
+ }
1140
+ middlewaresMap.set(name, true);
1141
+ const options = this.config[name] || {};
1142
+ let mw = createMiddleware(options, app);
1143
+ assert(typeof mw === 'function', `Middleware ${name} must be a function, but actual is ${inspect(mw)}`);
1144
+ if (isGeneratorFunction(mw)) {
1145
+ const fullpath = Reflect.get(createMiddleware, FULLPATH);
1146
+ throw new TypeError(`Support for generators was removed, middleware: ${name}, fullpath: ${fullpath}`);
1147
+ }
1148
+ mw._name = name;
1149
+ // middlewares support options.enable, options.ignore and options.match
1150
+ mw = wrapMiddleware(mw, options);
1151
+ if (mw) {
1152
+ if (debug.enabled) {
1153
+ // show mw debug log on every request
1154
+ mw = debugMiddlewareWrapper(mw);
1155
+ }
1156
+ app.use(mw);
1157
+ debug('[loadMiddleware] Use middleware: %s with options: %j', name, options);
1158
+ this.options.logger.info('[@eggjs/core/egg_loader] Use middleware: %s', name);
1159
+ }
1160
+ else {
1161
+ this.options.logger.info('[@eggjs/core/egg_loader] Disable middleware: %s', name);
1162
+ }
1163
+ }
1164
+ this.options.logger.info('[@eggjs/core/egg_loader] Loaded middleware from %j', middlewarePaths);
1165
+ this.timing.end('Load Middleware');
1166
+ // add router middleware, make sure router is the last middleware
1167
+ const mw = this.app.router.middleware();
1168
+ Reflect.set(mw, '_name', 'routerMiddleware');
1169
+ this.app.use(mw);
1170
+ }
1171
+ /** end Middleware loader */
1172
+ /** start Controller loader */
1173
+ /**
1174
+ * Load app/controller
1175
+ * @param {Object} opt - LoaderOptions
1176
+ * @since 1.0.0
1177
+ */
1178
+ async loadController(opt) {
1179
+ this.timing.start('Load Controller');
1180
+ const controllerBase = path.join(this.options.baseDir, 'app/controller');
1181
+ opt = {
1182
+ caseStyle: CaseStyle.lower,
1183
+ directory: controllerBase,
1184
+ initializer: (obj, opt) => {
1185
+ // return class if it exports a function
1186
+ // ```js
1187
+ // module.exports = app => {
1188
+ // return class HomeController extends app.Controller {};
1189
+ // }
1190
+ // ```
1191
+ if (isGeneratorFunction(obj)) {
1192
+ throw new TypeError(`Support for generators was removed, fullpath: ${opt.path}`);
1193
+ }
1194
+ if (!isClass(obj) && !isAsyncFunction(obj) && typeof obj === 'function') {
1195
+ obj = obj(this.app);
1196
+ debug('[loadController] after init(app) => %o, meta: %j', obj, opt);
1197
+ if (isGeneratorFunction(obj)) {
1198
+ throw new TypeError(`Support for generators was removed, fullpath: ${opt.path}`);
1199
+ }
1200
+ }
1201
+ if (isClass(obj)) {
1202
+ obj.prototype.pathName = opt.pathName;
1203
+ obj.prototype.fullPath = opt.path;
1204
+ return wrapControllerClass(obj, opt.path);
1205
+ }
1206
+ if (isObject(obj)) {
1207
+ return wrapObject(obj, opt.path);
1208
+ }
1209
+ if (isAsyncFunction(obj)) {
1210
+ return wrapObject({ 'module.exports': obj }, opt.path)['module.exports'];
1211
+ }
1212
+ return obj;
1213
+ },
1214
+ ...opt,
1215
+ };
1216
+ await this.loadToApp(controllerBase, 'controller', opt);
1217
+ debug('[loadController] app.controller => %o', this.app.controller);
1218
+ this.options.logger.info('[@eggjs/core/egg_loader] Controller loaded: %s', controllerBase);
1219
+ this.timing.end('Load Controller');
1220
+ }
1221
+ /** end Controller loader */
1222
+ /** start Router loader */
1223
+ /**
1224
+ * Load app/router.js
1225
+ * @function EggLoader#loadRouter
1226
+ * @since 1.0.0
1227
+ */
1228
+ async loadRouter() {
1229
+ this.timing.start('Load Router');
1230
+ await this.loadFile(path.join(this.options.baseDir, 'app/router'));
1231
+ this.timing.end('Load Router');
1232
+ }
1233
+ /** end Router loader */
1234
+ /** start CustomLoader loader */
1235
+ async loadCustomLoader() {
1236
+ assert(this.config, 'should loadConfig first');
1237
+ const customLoader = this.config.customLoader || {};
1238
+ for (const property of Object.keys(customLoader)) {
1239
+ const loaderConfig = {
1240
+ ...customLoader[property],
1241
+ };
1242
+ assert(loaderConfig.directory, `directory is required for config.customLoader.${property}`);
1243
+ let directory;
1244
+ if (loaderConfig.loadunit === true) {
1245
+ directory = this.getLoadUnits().map(unit => path.join(unit.path, loaderConfig.directory));
1246
+ }
1247
+ else {
1248
+ directory = path.join(this.appInfo.baseDir, loaderConfig.directory);
1249
+ }
1250
+ const inject = loaderConfig.inject || 'app';
1251
+ debug('[loadCustomLoader] loaderConfig: %o, inject: %o, directory: %o', loaderConfig, inject, directory);
1252
+ switch (inject) {
1253
+ case 'ctx': {
1254
+ assert(!(property in this.app.context), `customLoader should not override ctx.${property}`);
1255
+ const options = {
1256
+ caseStyle: CaseStyle.lower,
1257
+ fieldClass: `${property}Classes`,
1258
+ ...loaderConfig,
1259
+ directory,
1260
+ };
1261
+ await this.loadToContext(directory, property, options);
1262
+ break;
1263
+ }
1264
+ case 'app': {
1265
+ assert(!(property in this.app), `customLoader should not override app.${property}`);
1266
+ const options = {
1267
+ caseStyle: CaseStyle.lower,
1268
+ initializer: (Clazz) => {
1269
+ return isClass(Clazz) ? new Clazz(this.app) : Clazz;
1270
+ },
1271
+ ...loaderConfig,
1272
+ directory,
1273
+ };
1274
+ await this.loadToApp(directory, property, options);
1275
+ break;
1276
+ }
1277
+ default:
1278
+ throw new Error('inject only support app or ctx');
1279
+ }
1280
+ }
1281
+ }
1282
+ /** end CustomLoader loader */
1283
+ // Low Level API
1284
+ /**
1285
+ * Load single file, will invoke when export is function
1286
+ *
1287
+ * @param {String} filepath - fullpath
1288
+ * @param {Array} inject - pass rest arguments into the function when invoke
1289
+ * @returns {Object} exports
1290
+ * @example
1291
+ * ```js
1292
+ * app.loader.loadFile(path.join(app.options.baseDir, 'config/router.js'));
1293
+ * ```
1294
+ * @since 1.0.0
1295
+ */
1296
+ async loadFile(filepath, ...inject) {
1297
+ const fullpath = filepath && this.resolveModule(filepath);
1298
+ if (!fullpath) {
1299
+ return null;
1300
+ }
1301
+ // function(arg1, args, ...) {}
1302
+ if (inject.length === 0) {
1303
+ inject = [this.app];
1304
+ }
1305
+ let mod = await this.requireFile(fullpath);
1306
+ if (typeof mod === 'function' && !isClass(mod)) {
1307
+ mod = mod(...inject);
1308
+ if (isPromise(mod)) {
1309
+ mod = await mod;
1310
+ }
1311
+ }
1312
+ return mod;
1313
+ }
1314
+ /**
1315
+ * @param {String} filepath - fullpath
1316
+ * @private
1317
+ */
1318
+ async requireFile(filepath) {
1319
+ const timingKey = `Require(${this.#requiredCount++}) ${utils.getResolvedFilename(filepath, this.options.baseDir)}`;
1320
+ this.timing.start(timingKey);
1321
+ const mod = await utils.loadFile(filepath);
1322
+ this.timing.end(timingKey);
1323
+ return mod;
1324
+ }
1325
+ /**
1326
+ * Get all loadUnit
1327
+ *
1328
+ * loadUnit is a directory that can be loaded by EggLoader, it has the same structure.
1329
+ * loadUnit has a path and a type(app, framework, plugin).
1330
+ *
1331
+ * The order of the loadUnits:
1332
+ *
1333
+ * 1. plugin
1334
+ * 2. framework
1335
+ * 3. app
1336
+ *
1337
+ * @returns {Array} loadUnits
1338
+ * @since 1.0.0
1339
+ */
1340
+ getLoadUnits() {
1341
+ if (this.dirs) {
1342
+ return this.dirs;
1343
+ }
1344
+ this.dirs = [];
1345
+ if (this.orderPlugins) {
1346
+ for (const plugin of this.orderPlugins) {
1347
+ this.dirs.push({
1348
+ path: plugin.path,
1349
+ type: 'plugin',
1350
+ });
1351
+ }
1352
+ }
1353
+ // framework or egg path
1354
+ for (const eggPath of this.eggPaths) {
1355
+ this.dirs.push({
1356
+ path: eggPath,
1357
+ type: 'framework',
1358
+ });
1359
+ }
1360
+ // application
1361
+ this.dirs.push({
1362
+ path: this.options.baseDir,
1363
+ type: 'app',
1364
+ });
1365
+ debug('Loaded dirs %j', this.dirs);
1366
+ return this.dirs;
1367
+ }
1368
+ /**
1369
+ * Load files using {@link FileLoader}, inject to {@link Application}
1370
+ * @param {String|Array} directory - see {@link FileLoader}
1371
+ * @param {String} property - see {@link FileLoader}, e.g.: 'controller', 'middlewares'
1372
+ * @param {Object} options - see {@link FileLoader}
1373
+ * @since 1.0.0
1374
+ */
1375
+ async loadToApp(directory, property, options) {
1376
+ const target = {};
1377
+ Reflect.set(this.app, property, target);
1378
+ const loadOptions = {
1379
+ ...options,
1380
+ directory: options?.directory ?? directory,
1381
+ target,
1382
+ inject: this.app,
1383
+ };
1384
+ const timingKey = `Load "${String(property)}" to Application`;
1385
+ this.timing.start(timingKey);
1386
+ await new FileLoader(loadOptions).load();
1387
+ this.timing.end(timingKey);
1388
+ }
1389
+ /**
1390
+ * Load files using {@link ContextLoader}
1391
+ * @param {String|Array} directory - see {@link ContextLoader}
1392
+ * @param {String} property - see {@link ContextLoader}
1393
+ * @param {Object} options - see {@link ContextLoader}
1394
+ * @since 1.0.0
1395
+ */
1396
+ async loadToContext(directory, property, options) {
1397
+ const loadOptions = {
1398
+ ...options,
1399
+ directory: options?.directory || directory,
1400
+ property,
1401
+ inject: this.app,
1402
+ };
1403
+ const timingKey = `Load "${String(property)}" to Context`;
1404
+ this.timing.start(timingKey);
1405
+ await new ContextLoader(loadOptions).load();
1406
+ this.timing.end(timingKey);
1407
+ }
1408
+ /**
1409
+ * @member {FileLoader} EggLoader#FileLoader
1410
+ * @since 1.0.0
1411
+ */
1412
+ get FileLoader() {
1413
+ return FileLoader;
1414
+ }
1415
+ /**
1416
+ * @member {ContextLoader} EggLoader#ContextLoader
1417
+ * @since 1.0.0
1418
+ */
1419
+ get ContextLoader() {
1420
+ return ContextLoader;
1421
+ }
1422
+ getTypeFiles(filename) {
1423
+ const files = [`${filename}.default`];
1424
+ if (this.serverScope)
1425
+ files.push(`${filename}.${this.serverScope}`);
1426
+ if (this.serverEnv === 'default')
1427
+ return files;
1428
+ files.push(`${filename}.${this.serverEnv}`);
1429
+ if (this.serverScope) {
1430
+ files.push(`${filename}.${this.serverScope}_${this.serverEnv}`);
1431
+ }
1432
+ return files;
1433
+ }
1434
+ resolveModule(filepath) {
1435
+ let fullPath;
1436
+ try {
1437
+ fullPath = utils.resolvePath(filepath);
1438
+ }
1439
+ catch {
1440
+ // debug('[resolveModule] Module %o resolve error: %s', filepath, err.stack);
1441
+ return undefined;
1442
+ }
1443
+ // if (process.env.EGG_TYPESCRIPT !== 'true' && fullPath.endsWith('.ts')) {
1444
+ // return undefined;
1445
+ // }
1446
+ return fullPath;
1447
+ }
1448
+ }
1097
1449
  function depCompatible(plugin) {
1098
- if (plugin.dep && !(Array.isArray(plugin.dependencies) && plugin.dependencies.length > 0)) {
1099
- plugin.dependencies = plugin.dep;
1100
- delete plugin.dep;
1101
- }
1450
+ if (plugin.dep && !(Array.isArray(plugin.dependencies) && plugin.dependencies.length > 0)) {
1451
+ plugin.dependencies = plugin.dep;
1452
+ delete plugin.dep;
1453
+ }
1102
1454
  }
1103
1455
  function isValidatePackageName(name) {
1104
- if (name.startsWith(".")) return false;
1105
- if (name.startsWith("/")) return false;
1106
- if (name.includes(":")) return false;
1107
- return true;
1456
+ // only check file path style
1457
+ if (name.startsWith('.'))
1458
+ return false;
1459
+ if (name.startsWith('/'))
1460
+ return false;
1461
+ if (name.includes(':'))
1462
+ return false;
1463
+ return true;
1108
1464
  }
1465
+ // support pathMatching on middleware
1109
1466
  function wrapMiddleware(mw, options) {
1110
- if (options.enable === false) return null;
1111
- if (!options.match && !options.ignore) return mw;
1112
- const match = pathMatching(options);
1113
- const fn = (ctx, next) => {
1114
- if (!match(ctx)) return next();
1115
- return mw(ctx, next);
1116
- };
1117
- fn._name = `${mw._name}middlewareWrapper`;
1118
- return fn;
1467
+ // support options.enable
1468
+ if (options.enable === false) {
1469
+ return null;
1470
+ }
1471
+ // support options.match and options.ignore
1472
+ if (!options.match && !options.ignore) {
1473
+ return mw;
1474
+ }
1475
+ const match = pathMatching(options);
1476
+ const fn = (ctx, next) => {
1477
+ if (!match(ctx))
1478
+ return next();
1479
+ return mw(ctx, next);
1480
+ };
1481
+ fn._name = `${mw._name}middlewareWrapper`;
1482
+ return fn;
1119
1483
  }
1120
1484
  function debugMiddlewareWrapper(mw) {
1121
- const fn = async (ctx, next) => {
1122
- const startTime = now();
1123
- debug("[debugMiddlewareWrapper] [%s %s] enter middleware: %s", ctx.method, ctx.url, mw._name);
1124
- await mw(ctx, next);
1125
- const rt = diff(startTime);
1126
- debug("[debugMiddlewareWrapper] [%s %s] after middleware: %s [%sms]", ctx.method, ctx.url, mw._name, rt);
1127
- };
1128
- fn._name = `${mw._name}DebugWrapper`;
1129
- return fn;
1485
+ const fn = async (ctx, next) => {
1486
+ const startTime = now();
1487
+ debug('[debugMiddlewareWrapper] [%s %s] enter middleware: %s', ctx.method, ctx.url, mw._name);
1488
+ await mw(ctx, next);
1489
+ const rt = diff(startTime);
1490
+ debug('[debugMiddlewareWrapper] [%s %s] after middleware: %s [%sms]', ctx.method, ctx.url, mw._name, rt);
1491
+ };
1492
+ fn._name = `${mw._name}DebugWrapper`;
1493
+ return fn;
1130
1494
  }
1495
+ // wrap the controller class, yield a object with middlewares
1131
1496
  function wrapControllerClass(Controller, fullPath) {
1132
- let proto = Controller.prototype;
1133
- const ret = {};
1134
- while (proto !== Object.prototype) {
1135
- const keys = Object.getOwnPropertyNames(proto);
1136
- for (const key of keys) {
1137
- if (key === "constructor") continue;
1138
- const d = Object.getOwnPropertyDescriptor(proto, key);
1139
- if (typeof d?.value === "function" && !Object.hasOwn(ret, key)) {
1140
- const controllerMethodName = `${Controller.name}.${key}`;
1141
- if (isGeneratorFunction(d.value)) throw new TypeError(`Support for generators was removed, controller \`${controllerMethodName}\`, fullpath: ${fullPath}`);
1142
- ret[key] = controllerMethodToMiddleware(Controller, key);
1143
- ret[key][FULLPATH] = `${fullPath}#${controllerMethodName}()`;
1144
- }
1145
- }
1146
- proto = Object.getPrototypeOf(proto);
1147
- }
1148
- return ret;
1497
+ let proto = Controller.prototype;
1498
+ const ret = {};
1499
+ // tracing the prototype chain
1500
+ while (proto !== Object.prototype) {
1501
+ const keys = Object.getOwnPropertyNames(proto);
1502
+ for (const key of keys) {
1503
+ // getOwnPropertyNames will return constructor
1504
+ // that should be ignored
1505
+ if (key === 'constructor') {
1506
+ continue;
1507
+ }
1508
+ // skip getter, setter & non-function properties
1509
+ const d = Object.getOwnPropertyDescriptor(proto, key);
1510
+ // prevent to override sub method
1511
+ if (typeof d?.value === 'function' && !Object.hasOwn(ret, key)) {
1512
+ const controllerMethodName = `${Controller.name}.${key}`;
1513
+ if (isGeneratorFunction(d.value)) {
1514
+ throw new TypeError(`Support for generators was removed, controller \`${controllerMethodName}\`, fullpath: ${fullPath}`);
1515
+ }
1516
+ ret[key] = controllerMethodToMiddleware(Controller, key);
1517
+ ret[key][FULLPATH] = `${fullPath}#${controllerMethodName}()`;
1518
+ }
1519
+ }
1520
+ proto = Object.getPrototypeOf(proto);
1521
+ }
1522
+ return ret;
1149
1523
  }
1150
1524
  function controllerMethodToMiddleware(Controller, key) {
1151
- return function classControllerMiddleware(...args) {
1152
- const controller = new Controller(this);
1153
- if (!this.app.config.controller?.supportParams) args = [this];
1154
- return controller[key](...args);
1155
- };
1525
+ return function classControllerMiddleware(...args) {
1526
+ const controller = new Controller(this);
1527
+ if (!this.app.config.controller?.supportParams) {
1528
+ args = [this];
1529
+ }
1530
+ // @ts-expect-error key exists
1531
+ return controller[key](...args);
1532
+ };
1156
1533
  }
1534
+ // wrap the method of the object, method can receive ctx as it's first argument
1157
1535
  function wrapObject(obj, fullPath, prefix) {
1158
- const keys = Object.keys(obj);
1159
- const ret = {};
1160
- prefix = prefix ?? "";
1161
- for (const key of keys) {
1162
- const controllerMethodName = `${prefix}${key}`;
1163
- const item = obj[key];
1164
- if (isGeneratorFunction(item)) throw new TypeError(`Support for generators was removed, controller \`${controllerMethodName}\`, fullpath: ${fullPath}`);
1165
- if (typeof item === "function") {
1166
- if (getParamNames(item)[0] === "next") throw new Error(`controller \`${controllerMethodName}\` should not use next as argument from file ${fullPath}`);
1167
- ret[key] = objectFunctionToMiddleware(item);
1168
- ret[key][FULLPATH] = `${fullPath}#${controllerMethodName}()`;
1169
- } else if (isObject(item)) ret[key] = wrapObject(item, fullPath, `${controllerMethodName}.`);
1170
- }
1171
- debug("[wrapObject] fullPath: %s, prefix: %s => %o", fullPath, prefix, ret);
1172
- return ret;
1536
+ const keys = Object.keys(obj);
1537
+ const ret = {};
1538
+ prefix = prefix ?? '';
1539
+ for (const key of keys) {
1540
+ const controllerMethodName = `${prefix}${key}`;
1541
+ const item = obj[key];
1542
+ if (isGeneratorFunction(item)) {
1543
+ throw new TypeError(`Support for generators was removed, controller \`${controllerMethodName}\`, fullpath: ${fullPath}`);
1544
+ }
1545
+ if (typeof item === 'function') {
1546
+ const names = getParamNames(item);
1547
+ if (names[0] === 'next') {
1548
+ throw new Error(`controller \`${controllerMethodName}\` should not use next as argument from file ${fullPath}`);
1549
+ }
1550
+ ret[key] = objectFunctionToMiddleware(item);
1551
+ ret[key][FULLPATH] = `${fullPath}#${controllerMethodName}()`;
1552
+ }
1553
+ else if (isObject(item)) {
1554
+ ret[key] = wrapObject(item, fullPath, `${controllerMethodName}.`);
1555
+ }
1556
+ }
1557
+ debug('[wrapObject] fullPath: %s, prefix: %s => %o', fullPath, prefix, ret);
1558
+ return ret;
1173
1559
  }
1174
1560
  function objectFunctionToMiddleware(func) {
1175
- async function objectControllerMiddleware(...args) {
1176
- if (!this.app.config.controller?.supportParams) args = [this];
1177
- return await func.apply(this, args);
1178
- }
1179
- for (const key in func) Reflect.set(objectControllerMiddleware, key, Reflect.get(func, key));
1180
- return objectControllerMiddleware;
1561
+ async function objectControllerMiddleware(...args) {
1562
+ if (!this.app.config.controller?.supportParams) {
1563
+ args = [this];
1564
+ }
1565
+ return await func.apply(this, args);
1566
+ }
1567
+ for (const key in func) {
1568
+ Reflect.set(objectControllerMiddleware, key, Reflect.get(func, key));
1569
+ }
1570
+ return objectControllerMiddleware;
1181
1571
  }
1182
-
1183
- //#endregion
1184
- export { EggLoader };
1572
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZWdnX2xvYWRlci5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9sb2FkZXIvZWdnX2xvYWRlci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsTUFBTSxTQUFTLENBQUM7QUFDekIsT0FBTyxJQUFJLE1BQU0sV0FBVyxDQUFDO0FBQzdCLE9BQU8sTUFBTSxNQUFNLGFBQWEsQ0FBQztBQUNqQyxPQUFPLEVBQUUsUUFBUSxFQUFFLE9BQU8sRUFBRSxNQUFNLFdBQVcsQ0FBQztBQUU5QyxPQUFPLEVBQUUsT0FBTyxFQUFFLE1BQU0sY0FBYyxDQUFDO0FBQ3ZDLE9BQU8sRUFBRSxlQUFlLEVBQUUsT0FBTyxFQUFFLG1CQUFtQixFQUFFLFFBQVEsRUFBRSxTQUFTLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFFaEcsT0FBTyxFQUFFLGFBQWEsRUFBRSxZQUFZLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxNQUFNLFNBQVMsQ0FBQztBQUN4RSxPQUFPLEVBQUUsTUFBTSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFDeEMsT0FBTyxFQUFFLE9BQU8sRUFBRSxRQUFRLEVBQUUsV0FBVyxFQUFFLE9BQU8sSUFBSSxVQUFVLEVBQUUsTUFBTSxZQUFZLENBQUM7QUFDbkYsT0FBTyxFQUFFLFFBQVEsSUFBSSxxQkFBcUIsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBQ25FLE9BQU8sRUFBRSxLQUFLLEVBQUUsbUJBQW1CLEVBQUUsTUFBTSxjQUFjLENBQUM7QUFDMUQsT0FBTyxFQUFFLFlBQVksRUFBNEIsTUFBTSxtQkFBbUIsQ0FBQztBQUMzRSxPQUFPLEVBQUUsR0FBRyxFQUFFLElBQUksRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRTNDLE9BQU8sRUFBMEIsU0FBUyxFQUFFLFFBQVEsRUFBRSxVQUFVLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUMzRixPQUFPLEVBQTZCLGFBQWEsRUFBRSxNQUFNLHFCQUFxQixDQUFDO0FBQy9FLE9BQU8sS0FBSyxFQUFFLEVBQVksTUFBTSxtQkFBbUIsQ0FBQztBQUNwRCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sd0JBQXdCLENBQUM7QUFDcEQsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLG9CQUFvQixDQUFDO0FBSzVDLE1BQU0sS0FBSyxHQUFHLFFBQVEsQ0FBQyw0QkFBNEIsQ0FBQyxDQUFDO0FBRXJELE1BQU0sa0JBQWtCLEdBQTRCO0lBQ2xELE9BQU8sRUFBRSxPQUFPLENBQUMsU0FBUztJQUMxQixRQUFRLEVBQUUsUUFBUSxDQUFDLFNBQVM7SUFDNUIsT0FBTyxFQUFFLFVBQVUsQ0FBQyxTQUFTO0lBQzdCLFdBQVcsRUFBRSxXQUFXLENBQUMsU0FBUztDQUNuQyxDQUFDO0FBeUJGLE1BQU0sT0FBTyxTQUFTO0lBQ3BCLGNBQWMsR0FBRyxDQUFDLENBQUM7SUFDVixPQUFPLENBQW1CO0lBQzFCLE1BQU0sQ0FBUztJQUNmLEdBQUcsQ0FBc0I7SUFDekIsUUFBUSxDQUFXO0lBQ25CLFNBQVMsQ0FBUztJQUNsQixXQUFXLENBQVM7SUFDcEIsT0FBTyxDQUFhO0lBQzdCLElBQUksQ0FBZ0I7SUFFcEI7Ozs7Ozs7O09BUUc7SUFDSCxZQUFZLE9BQXlCO1FBQ25DLElBQUksQ0FBQyxPQUFPLEdBQUcsT0FBTyxDQUFDO1FBQ3ZCLE1BQU0sQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxDQUFDLEVBQUUsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sYUFBYSxDQUFDLENBQUM7UUFDbEYsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLHlCQUF5QixDQUFDLENBQUM7UUFDcEQsTUFBTSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxFQUFFLDRCQUE0QixDQUFDLENBQUM7UUFFMUQsSUFBSSxDQUFDLE1BQU0sR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sSUFBSSxJQUFJLE1BQU0sRUFBRSxDQUFDO1FBRTlDOzs7O1dBSUc7UUFDSCxJQUFJLENBQUMsR0FBRyxHQUFHLFlBQVksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLGNBQWMsQ0FBQyxDQUFDLENBQUM7UUFFekUsNERBQTREO1FBQzVELHlGQUF5RjtRQUN6RixJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsY0FBYyxLQUFLLE1BQU0sSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxJQUFJLElBQUksQ0FBQyxHQUFHLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxFQUFFLENBQUM7WUFDdkYsMERBQTBEO1lBQzFELE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsZUFBZSxDQUFDLENBQUM7WUFDdEUsSUFBSSxFQUFFLENBQUMsVUFBVSxDQUFDLFlBQVksQ0FBQyxFQUFFLENBQUM7Z0JBQ2hDLHdDQUF3QztnQkFDeEMscUJBQXFCLENBQUMsRUFBRSxHQUFHLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsQ0FBQyxDQUFDO1lBQ3ZELENBQUM7aUJBQU0sQ0FBQztnQkFDTixJQUFJLENBQUMsTUFBTSxDQUFDLElBQUksQ0FDZCxnR0FBZ0csRUFDaEcsWUFBWSxDQUNiLENBQUM7WUFDSixDQUFDO1FBQ0gsQ0FBQztRQUVEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7OztXQW9CRztRQUNILElBQUksQ0FBQyxRQUFRLEdBQUcsSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1FBQ25DLEtBQUssQ0FBQyxvQkFBb0IsRUFBRSxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7UUFFM0M7Ozs7V0FJRztRQUNILElBQUksQ0FBQyxTQUFTLEdBQUcsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO1FBQ3JDLEtBQUssQ0FBQyxxQkFBcUIsRUFBRSxJQUFJLENBQUMsU0FBUyxDQUFDLENBQUM7UUFFN0M7OztXQUdHO1FBQ0gsSUFBSSxDQUFDLFdBQVcsR0FBRyxPQUFPLENBQUMsV0FBVyxJQUFJLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUVoRTs7O1dBR0c7UUFDSCxJQUFJLENBQUMsT0FBTyxHQUFHLElBQUksQ0FBQyxVQUFVLEVBQUUsQ0FBQztJQUNuQyxDQUFDO0lBRUQsSUFBSSxHQUFHO1FBQ0wsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQztJQUMxQixDQUFDO0lBRUQsSUFBSSxTQUFTO1FBQ1gsT0FBTyxJQUFJLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQztJQUM1QixDQUFDO0lBRUQsSUFBSSxNQUFNO1FBQ1IsT0FBTyxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQztJQUM3QixDQUFDO0lBRUQ7Ozs7OztPQU1HO0lBQ08sWUFBWTtRQUNwQixJQUFJLFNBQVMsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQztRQUVqQyxNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLFlBQVksQ0FBQyxDQUFDO1FBQzlELElBQUksQ0FBQyxTQUFTLElBQUksRUFBRSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsRUFBRSxDQUFDO1lBQ3pDLFNBQVMsR0FBRyxFQUFFLENBQUMsWUFBWSxDQUFDLE9BQU8sRUFBRSxNQUFNLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUN0RCxDQUFDO1FBRUQsSUFBSSxDQUFDLFNBQVMsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLGNBQWMsRUFBRSxDQUFDO1lBQzdDLFNBQVMsR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLGNBQWMsQ0FBQztRQUN6QyxDQUFDO1FBRUQsSUFBSSxTQUFTLEVBQUUsQ0FBQztZQUNkLFNBQVMsR0FBRyxTQUFTLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDL0IsQ0FBQzthQUFNLENBQUM7WUFDTiwrQ0FBK0M7WUFDL0MsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVEsS0FBSyxNQUFNLEVBQUUsQ0FBQztnQkFDcEMsU0FBUyxHQUFHLFVBQVUsQ0FBQztZQUN6QixDQUFDO2lCQUFNLElBQUksT0FBTyxDQUFDLEdBQUcsQ0FBQyxRQUFRLEtBQUssWUFBWSxFQUFFLENBQUM7Z0JBQ2pELFNBQVMsR0FBRyxNQUFNLENBQUM7WUFDckIsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLFNBQVMsR0FBRyxPQUFPLENBQUM7WUFDdEIsQ0FBQztRQUNILENBQUM7UUFFRCxPQUFPLFNBQVMsQ0FBQztJQUNuQixDQUFDO0lBRUQ7Ozs7T0FJRztJQUNPLGNBQWM7UUFDdEIsT0FBTyxPQUFPLENBQUMsR0FBRyxDQUFDLGdCQUFnQixJQUFJLEVBQUUsQ0FBQztJQUM1QyxDQUFDO0lBRUQ7Ozs7O09BS0c7SUFDSCxVQUFVO1FBQ1IsSUFBSSxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ2xCLEtBQUssQ0FBQyxzQ0FBc0MsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQzdELE9BQU8sSUFBSSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUM7UUFDdkIsQ0FBQztRQUNELE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsY0FBYyxDQUFDLENBQUM7UUFDNUQsTUFBTSxJQUFJLEtBQUssQ0FBQyx5QkFBeUIsR0FBRyxFQUFFLENBQUMsQ0FBQztJQUNsRCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILFVBQVU7UUFDUixvQkFBb0I7UUFDcEIsT0FBTyxPQUFPLENBQUMsR0FBRyxDQUFDLFFBQVEsSUFBSSxPQUFPLEVBQUUsSUFBSSxhQUFhLENBQUM7SUFDNUQsQ0FBQztJQUVEOzs7O09BSUc7SUFDTyxVQUFVO1FBQ2xCLE1BQU0sR0FBRyxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUM7UUFDM0IsTUFBTSxLQUFLLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQztRQUMvQixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsVUFBVSxFQUFFLENBQUM7UUFDL0IsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUM7UUFFckM7OztXQUdHO1FBQ0gsT0FBTztZQUNMOzs7ZUFHRztZQUNILElBQUksRUFBRSxJQUFJLENBQUMsVUFBVSxFQUFFO1lBRXZCOzs7ZUFHRztZQUNILE9BQU87WUFFUDs7Ozs7Ozs7Ozs7Ozs7OztlQWdCRztZQUNILEdBQUc7WUFFSDs7ZUFFRztZQUNILEtBQUs7WUFFTDs7O2VBR0c7WUFDSCxJQUFJLEVBQUUsSUFBSTtZQUVWOzs7ZUFHRztZQUNILEdBQUcsRUFBRSxJQUFJLENBQUMsR0FBRztZQUViOzs7Ozs7O2VBT0c7WUFDSCxJQUFJLEVBQUUsR0FBRyxLQUFLLE9BQU8sSUFBSSxHQUFHLEtBQUssVUFBVSxDQUFDLENBQUMsQ0FBQyxPQUFPLENBQUMsQ0FBQyxDQUFDLElBQUk7U0FDN0QsQ0FBQztJQUNKLENBQUM7SUFFRDs7Ozs7O09BTUc7SUFDTyxXQUFXO1FBQ25CLDRCQUE0QjtRQUM1QixNQUFNLE9BQU8sR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLFlBQVksQ0FBQztRQUMxQyxNQUFNLFFBQVEsR0FBYSxFQUFFLENBQUM7UUFFOUIsSUFBSSxLQUFLLEdBQUcsSUFBSSxDQUFDLEdBQUcsQ0FBQztRQUVyQiwrQkFBK0I7UUFDL0IsT0FBTyxLQUFLLEVBQUUsQ0FBQztZQUNiLEtBQUssR0FBRyxNQUFNLENBQUMsY0FBYyxDQUFDLEtBQUssQ0FBQyxDQUFDO1lBQ3JDLG1CQUFtQjtZQUNuQiwwQkFBMEI7WUFDMUIsMkJBQTJCO1lBQzNCLElBQUksS0FBSyxLQUFLLE1BQU0sQ0FBQyxTQUFTLElBQUksS0FBSyxLQUFLLE9BQU8sRUFBRSxTQUFTLEVBQUUsQ0FBQztnQkFDL0QsTUFBTTtZQUNSLENBQUM7WUFDRCxNQUFNLE9BQU8sR0FBRyxPQUFPLENBQUMsR0FBRyxDQUFDLEtBQUssRUFBRSxNQUFNLENBQUMsR0FBRyxDQUFDLGFBQWEsQ0FBQyxDQUFDLENBQUM7WUFDOUQsSUFBSSxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUNiLGlCQUFpQjtnQkFDakIsbUZBQW1GO2dCQUNuRixJQUFJO2dCQUNKLFNBQVM7WUFDWCxDQUFDO1lBQ0QsTUFBTSxDQUFDLE9BQU8sT0FBTyxLQUFLLFFBQVEsRUFBRSw0Q0FBNEMsQ0FBQyxDQUFDO1lBQ2xGLE1BQU0sQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxFQUFFLEdBQUcsT0FBTyxhQUFhLENBQUMsQ0FBQztZQUN4RCxNQUFNLFFBQVEsR0FBRyxFQUFFLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1lBQzFDLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7Z0JBQ2pDLFFBQVEsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDN0IsQ0FBQztRQUNILENBQUM7UUFDRCxPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0lBRUQsMEJBQTBCO0lBQzFCLFVBQVUsQ0FBYztJQUN4QixVQUFVLENBQWdDO0lBQzFDLFVBQVUsQ0FBZ0M7SUFDMUMsYUFBYSxDQUFnQztJQUM3QyxVQUFVLENBQWdDO0lBQzFDLFlBQVksQ0FBa0I7SUFDOUIscUJBQXFCO0lBQ3JCLE9BQU8sQ0FBZ0M7SUFFdkM7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztPQTZDRztJQUNILEtBQUssQ0FBQyxVQUFVO1FBQ2QsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsYUFBYSxDQUFDLENBQUM7UUFFakMsSUFBSSxDQUFDLFVBQVUsR0FBRyxJQUFJLENBQUMsYUFBYSxFQUFFLENBQUM7UUFDdkMsSUFBSSxDQUFDLFVBQVUsR0FBRyxFQUFFLENBQUM7UUFDckIsSUFBSSxDQUFDLFVBQVUsR0FBRyxNQUFNLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQztRQUM5QyxJQUFJLENBQUMsVUFBVSxHQUFHLE1BQU0sSUFBSSxDQUFDLGNBQWMsRUFBRSxDQUFDO1FBQzlDLElBQUksQ0FBQyxhQUFhLEdBQUcsSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUM7UUFFOUMsSUFBSSxDQUFDLGNBQWMsQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztRQUN0RCxJQUFJLENBQUMsY0FBYyxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ3RELElBQUksQ0FBQyxjQUFjLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUM7UUFFekQsTUFBTSxrQkFBa0IsR0FBYSxFQUFFLENBQUMsQ0FBQyw2Q0FBNkM7UUFDdEYsTUFBTSxPQUFPLEdBQWtDLEVBQUUsQ0FBQztRQUNsRCxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsU0FBUyxDQUFDO1FBQzNCLEtBQUssTUFBTSxJQUFJLElBQUksSUFBSSxDQUFDLFVBQVUsRUFBRSxDQUFDO1lBQ25DLE1BQU0sTUFBTSxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUM7WUFFckMsMERBQTBEO1lBQzFELE1BQU0sQ0FBQyxJQUFJLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUV6QywyREFBMkQ7WUFDM0QsTUFBTSxJQUFJLENBQUMsa0JBQWtCLENBQUMsTUFBTSxDQUFDLENBQUM7WUFFdEMsa0RBQWtEO1lBQ2xELElBQUksR0FBRyxJQUFJLE1BQU0sQ0FBQyxHQUFHLENBQUMsTUFBTSxHQUFHLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQzlELElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUNkLHNGQUFzRixFQUN0RixJQUFJLEVBQ0osTUFBTSxDQUFDLEdBQUcsRUFDVixHQUFHLENBQ0osQ0FBQztnQkFDRixNQUFNLENBQUMsTUFBTSxHQUFHLEtBQUssQ0FBQztnQkFDdEIsU0FBUztZQUNYLENBQUM7WUFFRCxPQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsTUFBTSxDQUFDO1lBQ3ZCLElBQUksTUFBTSxDQUFDLE1BQU0sRUFBRSxDQUFDO2dCQUNsQixrQkFBa0IsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDaEMsQ0FBQztRQUNILENBQUM7UUFFRCwrQkFBK0I7UUFDL0IsSUFBSSxDQUFDLFlBQVksR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUM7UUFFdkYsTUFBTSxhQUFhLEdBQWtDLEVBQUUsQ0FBQztRQUN4RCxLQUFLLE1BQU0sTUFBTSxJQUFJLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQztZQUN2QyxhQUFhLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLE1BQU0sQ0FBQztRQUN0QyxDQUFDO1FBQ0QsS0FBSyxDQUFDLDJCQUEyQixFQUFFLE1BQU0sQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUMsQ0FBQztRQUUvRDs7OztXQUlHO1FBQ0gsSUFBSSxDQUFDLE9BQU8sR0FBRyxhQUFhLENBQUM7UUFDN0IsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFDLENBQUM7SUFDakMsQ0FBQztJQUVTLEtBQUssQ0FBQyxjQUFjO1FBQzVCLGtDQUFrQztRQUNsQyxNQUFNLFVBQVUsR0FBRyxNQUFNLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLHVCQUF1QixDQUFDLENBQUMsQ0FBQztRQUMxRyxLQUFLLENBQ0gsd0JBQXdCLEVBQ3hCLE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQ2pFLENBQUM7UUFDRixPQUFPLFVBQVUsQ0FBQztJQUNwQixDQUFDO0lBRVMsS0FBSyxDQUFDLGNBQWM7UUFDNUIsZ0NBQWdDO1FBQ2hDLE1BQU0sb0JBQW9CLEdBQUcsSUFBSSxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSx1QkFBdUIsQ0FBQyxDQUFDLENBQUM7UUFDdkcsTUFBTSxVQUFVLEdBQUcsTUFBTSxJQUFJLENBQUMsaUJBQWlCLENBQUMsb0JBQW9CLENBQUMsQ0FBQztRQUN0RSxLQUFLLENBQ0gsd0JBQXdCLEVBQ3hCLE1BQU0sQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksVUFBVSxDQUFDLENBQUMsQ0FBQyxDQUFDLE1BQU0sRUFBRSxDQUFDLENBQ2pFLENBQUM7UUFDRixPQUFPLFVBQVUsQ0FBQztJQUNwQixDQUFDO0lBRVMsaUJBQWlCO1FBQ3pCLDhDQUE4QztRQUM5QyxJQUFJLGFBQWEsR0FBa0MsRUFBRSxDQUFDO1FBQ3RELE1BQU0sV0FBVyxHQUFhLEVBQUUsQ0FBQztRQUNqQyxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsV0FBVyxFQUFFLENBQUM7WUFDNUIsSUFBSSxDQUFDO2dCQUNILGFBQWEsR0FBRyxJQUFJLENBQUMsS0FBSyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsV0FBVyxDQUFDLENBQUM7Z0JBQ3BELFdBQVcsQ0FBQyxJQUFJLENBQUMsMkJBQTJCLENBQUMsQ0FBQztZQUNoRCxDQUFDO1lBQUMsT0FBTyxDQUFDLEVBQUUsQ0FBQztnQkFDWCxLQUFLLENBQUMsOEJBQThCLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDM0MsQ0FBQztRQUNILENBQUM7UUFFRCxzQ0FBc0M7UUFDdEMsSUFBSSxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDO1lBQ3pCLGFBQWEsR0FBRztnQkFDZCxHQUFHLGFBQWE7Z0JBQ2hCLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPO2FBQ3hCLENBQUM7WUFDRixXQUFXLENBQUMsSUFBSSxDQUFDLG1CQUFtQixDQUFDLENBQUM7UUFDeEMsQ0FBQztRQUVELElBQUksYUFBYSxFQUFFLENBQUM7WUFDbEIsTUFBTSxVQUFVLEdBQUcsV0FBVyxDQUFDLElBQUksQ0FBQyxNQUFNLENBQUMsQ0FBQztZQUM1QyxLQUFLLE1BQU0sSUFBSSxJQUFJLGFBQWEsRUFBRSxDQUFDO2dCQUNqQyxJQUFJLENBQUMsc0JBQXNCLENBQUMsYUFBYSxFQUFFLElBQUksRUFBRSxVQUFVLENBQUMsQ0FBQztZQUMvRCxDQUFDO1lBQ0QsS0FBSyxDQUFDLDJCQUEyQixFQUFFLGFBQWEsQ0FBQyxDQUFDO1FBQ3BELENBQUM7UUFDRCxPQUFPLGFBQWEsQ0FBQztJQUN2QixDQUFDO0lBRUQ7O09BRUc7SUFDTyxLQUFLLENBQUMsaUJBQWlCLENBQUMsV0FBOEI7UUFDOUQsSUFBSSxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsV0FBVyxDQUFDLEVBQUUsQ0FBQztZQUNoQyxXQUFXLEdBQUcsQ0FBQyxXQUFXLENBQUMsQ0FBQztRQUM5QixDQUFDO1FBRUQsZ0NBQWdDO1FBQ2hDLG9CQUFvQjtRQUNwQixxQkFBcUI7UUFDckIsbUJBQW1CO1FBQ25CLDRCQUE0QjtRQUM1QixNQUFNLGNBQWMsR0FBYSxFQUFFLENBQUM7UUFDcEMsS0FBSyxNQUFNLFFBQVEsSUFBSSxJQUFJLENBQUMsWUFBWSxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7WUFDbkQsS0FBSyxJQUFJLFVBQVUsSUFBSSxXQUFXLEVBQUUsQ0FBQztnQkFDbkMsVUFBVSxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsRUFBRSxRQUFRLENBQUMsQ0FBQztnQkFDM0QsY0FBYyxDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FBQztZQUNsQyxDQUFDO1FBQ0gsQ0FBQztRQUVELE1BQU0sT0FBTyxHQUFrQyxFQUFFLENBQUM7UUFDbEQsS0FBSyxNQUFNLFVBQVUsSUFBSSxjQUFjLEVBQUUsQ0FBQztZQUN4QyxJQUFJLFFBQVEsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1lBRTlDLDJCQUEyQjtZQUMzQixJQUFJLFVBQVUsQ0FBQyxRQUFRLENBQUMsZ0JBQWdCLENBQUMsSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO2dCQUN2RCxRQUFRLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxVQUFVLENBQUMsT0FBTyxDQUFDLGtCQUFrQixFQUFFLFFBQVEsQ0FBQyxDQUFDLENBQUM7WUFDbEYsQ0FBQztZQUVELElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztnQkFDZCxLQUFLLENBQUMsdURBQXVELEVBQUUsVUFBVSxDQUFDLENBQUM7Z0JBQzNFLFNBQVM7WUFDWCxDQUFDO1lBRUQsTUFBTSxNQUFNLEdBQWtDLE1BQU0sS0FBSyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUM3RSxLQUFLLE1BQU0sSUFBSSxJQUFJLE1BQU0sRUFBRSxDQUFDO2dCQUMxQixJQUFJLENBQUMsc0JBQXNCLENBQUMsTUFBTSxFQUFFLElBQUksRUFBRSxRQUFRLENBQUMsQ0FBQztZQUN0RCxDQUFDO1lBQ0QsSUFBSSxDQUFDLGNBQWMsQ0FBQyxPQUFPLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDdkMsQ0FBQztRQUVELE9BQU8sT0FBTyxDQUFDO0lBQ2pCLENBQUM7SUFFRCxzQkFBc0IsQ0FBQyxPQUFnRCxFQUFFLElBQVksRUFBRSxVQUFrQjtRQUN2RyxNQUFNLE1BQU0sR0FBRyxPQUFPLENBQUMsSUFBSSxDQUFDLENBQUM7UUFFN0IscUJBQXFCO1FBQ3JCLElBQUksT0FBTyxNQUFNLEtBQUssU0FBUyxFQUFFLENBQUM7WUFDaEMsT0FBTyxDQUFDLElBQUksQ0FBQyxHQUFHO2dCQUNkLElBQUk7Z0JBQ0osTUFBTSxFQUFFLE1BQU07Z0JBQ2QsWUFBWSxFQUFFLEVBQUU7Z0JBQ2hCLG9CQUFvQixFQUFFLEVBQUU7Z0JBQ3hCLEdBQUcsRUFBRSxFQUFFO2dCQUNQLElBQUksRUFBRSxVQUFVO2FBQ08sQ0FBQztZQUMxQixPQUFPO1FBQ1QsQ0FBQztRQUVELElBQUksQ0FBQyxDQUFDLFFBQVEsSUFBSSxNQUFNLENBQUMsRUFBRSxDQUFDO1lBQzFCLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLFFBQVEsRUFBRSxJQUFJLENBQUMsQ0FBQztRQUN0QyxDQUFDO1FBQ0QsTUFBTSxDQUFDLElBQUksR0FBRyxJQUFJLENBQUM7UUFDbkIsTUFBTSxDQUFDLFlBQVksR0FBRyxNQUFNLENBQUMsWUFBWSxJQUFJLEVBQUUsQ0FBQztRQUNoRCxNQUFNLENBQUMsb0JBQW9CLEdBQUcsTUFBTSxDQUFDLG9CQUFvQixJQUFJLEVBQUUsQ0FBQztRQUNoRSxNQUFNLENBQUMsR0FBRyxHQUFHLE1BQU0sQ0FBQyxHQUFHLElBQUksRUFBRSxDQUFDO1FBQzlCLE1BQU0sQ0FBQyxJQUFJLEdBQUcsTUFBTSxDQUFDLElBQUksSUFBSSxVQUFVLENBQUM7UUFDeEMsYUFBYSxDQUFDLE1BQU0sQ0FBQyxDQUFDO0lBQ3hCLENBQUM7SUFFRCxzREFBc0Q7SUFDdEQsSUFBSTtJQUNKLGlCQUFpQjtJQUNqQiw0RUFBNEU7SUFDNUUsd0NBQXdDO0lBQ3hDLDBCQUEwQjtJQUMxQixrRUFBa0U7SUFDbEUsTUFBTTtJQUNOLElBQUk7SUFDSixLQUFLLENBQUMsa0JBQWtCLENBQUMsTUFBcUI7UUFDNUMsSUFBSSxHQUFRLENBQUM7UUFDYixJQUFJLE1BQVcsQ0FBQztRQUNoQixNQUFNLGFBQWEsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFjLEVBQUUsY0FBYyxDQUFDLENBQUM7UUFDdkUsSUFBSSxNQUFNLEtBQUssQ0FBQyxVQUFVLENBQUMsYUFBYSxDQUFDLEVBQUUsQ0FBQztZQUMxQyxHQUFHLEdBQUcsTUFBTSxRQUFRLENBQUMsYUFBYSxDQUFDLENBQUM7WUFDcEMsTUFBTSxHQUFHLEdBQUcsQ0FBQyxTQUFTLENBQUM7WUFDdkIsSUFBSSxHQUFHLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQ2hCLE1BQU0sQ0FBQyxPQUFPLEdBQUcsR0FBRyxDQUFDLE9BQU8sQ0FBQztZQUMvQixDQUFDO1lBQ0Qsc0NBQXNDO1lBQ3RDLE1BQU0sQ0FBQyxJQUFJLEdBQUcsTUFBTSxJQUFJLENBQUMsZ0NBQWdDLENBQUMsTUFBTSxDQUFDLElBQWMsRUFBRSxHQUFHLENBQUMsQ0FBQztRQUN4RixDQUFDO1FBRUQsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUM7UUFDbkMsSUFBSSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ1osTUFBTSxDQUFDLElBQUksQ0FBQyx3REFBd0QsYUFBYSxFQUFFLENBQUMsQ0FBQztZQUNyRixPQUFPO1FBQ1QsQ0FBQztRQUVELElBQUksTUFBTSxDQUFDLElBQUksSUFBSSxNQUFNLENBQUMsTUFBTSxLQUFLLEtBQUssSUFBSSxNQUFNLENBQUMsSUFBSSxLQUFLLE1BQU0sQ0FBQyxJQUFJLEVBQUUsQ0FBQztZQUMxRSwrQ0FBK0M7WUFDL0MseUNBQXlDO1lBQ3pDLE1BQU0sQ0FBQyxJQUFJLENBQ1QsdUNBQXVDLE1BQU0sQ0FBQyxJQUFJLHdDQUF3QyxNQUFNLENBQUMsSUFBSSxHQUFHLENBQ3pHLENBQUM7UUFDSixDQUFDO1FBRUQsaUJBQWlCO1FBQ2pCLGFBQWEsQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUV0QixLQUFLLE1BQU0sR0FBRyxJQUFJLENBQUMsY0FBYyxFQUFFLHNCQUFzQixFQUFFLEtBQUssQ0FBQyxFQUFFLENBQUM7WUFDbEUsTUFBTSxNQUFNLEdBQUcsTUFBTSxDQUFDLEdBQUcsQ0FBQyxDQUFDO1lBQzNCLE1BQU0sWUFBWSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxDQUFDO1lBQzlDLElBQUksS0FBSyxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLFlBQVksRUFBRSxNQUFNLEVBQUUsQ0FBQztnQkFDbkQsT0FBTyxDQUFDLEdBQUcsQ0FBQyxNQUFNLEVBQUUsR0FBRyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQ25DLENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUVTLGVBQWUsQ0FDdkIsVUFBeUMsRUFDekMsa0JBQTRCLEVBQzVCLFVBQXlDO1FBRXpDLHFCQUFxQjtRQUNyQixJQUFJLGtCQUFrQixDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztZQUNwQyxPQUFPLEVBQUUsQ0FBQztRQUNaLENBQUM7UUFFRCxNQUFNLE1BQU0sR0FBRyxVQUFVLENBQUMsVUFBVSxFQUFFLGtCQUFrQixDQUFDLENBQUM7UUFDMUQsS0FBSyxDQUFDLGlDQUFpQyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1FBRWpELDRDQUE0QztRQUM1QyxJQUFJLE1BQU0sQ0FBQyxRQUFRLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ2pDLE1BQU0sR0FBRyxHQUFHLElBQUksS0FBSyxDQUNuQiw2Q0FBNkMsTUFBTSxDQUFDLFlBQVksa0JBQWtCLE1BQU0sQ0FBQyxxQkFBcUIsR0FBRyxDQUNsSCxDQUFDO1lBQ0YsdURBQXVEO1lBQ3ZELEtBQUssTUFBTSxRQUFRLElBQUksTUFBTSxDQUFDLFlBQVksRUFBRSxDQUFDO2dCQUMzQyxNQUFNLFFBQVEsR0FBRyxFQUFFLENBQUM7Z0JBQ3BCLEtBQUssTUFBTSxJQUFJLElBQUksVUFBVSxFQUFFLENBQUM7b0JBQzlCLElBQUksVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLFlBQVksQ0FBQyxRQUFRLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQzt3QkFDckQsUUFBUSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztvQkFDdEIsQ0FBQztnQkFDSCxDQUFDO2dCQUNELEdBQUcsQ0FBQyxPQUFPLElBQUksa0JBQWtCLFFBQVEsZ0RBQWdELFFBQVEsR0FBRyxDQUFDO1lBQ3ZHLENBQUM7WUFFRCxHQUFHLENBQUMsSUFBSSxHQUFHLHVCQUF1QixDQUFDO1lBQ25DLE1BQU0sR0FBRyxDQUFDO1FBQ1osQ0FBQztRQUVELDZDQUE2QztRQUM3QyxNQUFNLHNCQUFzQixHQUFhLEVBQUUsQ0FBQztRQUM1QyxNQUFNLFVBQVUsR0FBNkIsRUFBRSxDQUFDO1FBQ2hELEtBQUssTUFBTSxJQUFJLElBQUksTUFBTSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ25DLEtBQUssTUFBTSxPQUFPLElBQUksVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLFlBQVksRUFBRSxDQUFDO2dCQUNwRCxJQUFJLENBQUMsVUFBVSxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7b0JBQ3pCLFVBQVUsQ0FBQyxPQUFPLENBQUMsR0FBRyxFQUFFLENBQUM7Z0JBQzNCLENBQUM7Z0JBQ0QsVUFBVSxDQUFDLE9BQU8sQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUNqQyxDQUFDO1lBRUQsSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLEVBQUUsQ0FBQztnQkFDN0Isc0JBQXNCLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUNsQyxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUMsTUFBTSxHQUFHLElBQUksQ0FBQztnQkFDL0IsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLGNBQWMsR0FBRyxJQUFJLENBQUM7WUFDekMsQ0FBQztRQUNILENBQUM7UUFFRCxLQUFLLE1BQU0sQ0FBQyxJQUFJLEVBQUUsVUFBVSxDQUFDLElBQUksTUFBTSxDQUFDLE9BQU8sQ0FBQyxVQUFVLENBQUMsRUFBRSxDQUFDO1lBQzVELDZEQUE2RDtZQUM3RCxVQUFVLENBQUMsSUFBSSxDQUFDLENBQUMsVUFBVSxHQUFHLFVBQVUsQ0FBQztRQUMzQyxDQUFDO1FBRUQsZ0RBQWdEO1FBQ2hELDJDQUEyQztRQUMzQyxzQ0FBc0M7UUFDdEMsc0NBQXNDO1FBQ3RDLElBQUksc0JBQXNCLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ3RDLElBQUksT0FBTyxHQUFHLHNCQUFzQixDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLE9BQU8sSUFBSSxpQkFBaUIsVUFBVSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7WUFDN0csSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLGtEQUFrRCxPQUFPLEVBQUUsQ0FBQyxDQUFDO1lBRXRGLGlEQUFpRDtZQUNqRCxNQUFNLGVBQWUsR0FBRyxzQkFBc0IsQ0FBQyxNQUFNLENBQ25ELElBQUksQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxJQUFJLFVBQVUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxNQUFNLEtBQUssS0FBSyxDQUM5RCxDQUFDO1lBQ0YsSUFBSSxlQUFlLENBQUMsTUFBTSxHQUFHLENBQUMsRUFBRSxDQUFDO2dCQUMvQixPQUFPLEdBQUcsZUFBZSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLE9BQU8sSUFBSSxpQkFBaUIsVUFBVSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ2xHLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksQ0FDdEIsa0ZBQWtGLE9BQU8sRUFBRSxDQUM1RixDQUFDO1lBQ0osQ0FBQztRQUNILENBQUM7UUFFRCxPQUFPLE1BQU0sQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDdkQsQ0FBQztJQUVTLGFBQWE7UUFDckIsTUFBTSxVQUFVLEdBQUcsSUFBSSxHQUFHLEVBQVUsQ0FBQztRQUVyQyx1RUFBdUU7UUFDdkUsc0NBQXNDO1FBQ3RDLFVBQVUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUVyQyw0REFBNEQ7UUFDNUQsS0FBSyxJQUFJLENBQUMsR0FBRyxJQUFJLENBQUMsUUFBUSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRSxDQUFDO1lBQ25ELE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUM7WUFDakMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztRQUMxQixDQUFDO1FBRUQsd0RBQXdEO1FBQ3hELFVBQVUsQ0FBQyxHQUFHLENBQUMsT0FBTyxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUM7UUFDOUIsT0FBTyxVQUFVLENBQUM7SUFDcEIsQ0FBQztJQUVELDJCQUEyQjtJQUNqQixhQUFhLENBQUMsTUFBcUI7UUFDM0MsSUFBSSxNQUFNLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDaEIsT0FBTyxNQUFNLENBQUMsSUFBSSxDQUFDO1FBQ3JCLENBQUM7UUFFRCxJQUFJLE1BQU0sQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUNuQixNQUFNLENBQ0oscUJBQXFCLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxFQUNyQyxVQUFVLE1BQU0sQ0FBQyxJQUFJLDZDQUE2QyxNQUFNLENBQUMsT0FBTyxHQUFHLENBQ3BGLENBQUM7UUFDSixDQUFDO1FBQ0QsT0FBTyxJQUFJLENBQUMsa0JBQWtCLENBQUMsTUFBTSxDQUFDLENBQUM7SUFDekMsQ0FBQztJQUVELGtCQUFrQixDQUFDLE1BQXFCO1FBQ3RDLE1BQU0sSUFBSSxHQUFHLE1BQU0sQ0FBQyxPQUFPLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQztRQUMzQyxJQUFJLENBQUM7WUFDSCxtQ0FBbUM7WUFDbkMsMkRBQTJEO1lBQzNELG9FQUFvRTtZQUNwRSxtRkFBbUY7WUFDbkYsaUVBQWlFO1lBQ2pFLGlGQUFpRjtZQUNqRixNQUFNLGFBQWEsR0FBRyxLQUFLLENBQUMsV0FBVyxDQUFDLEdBQUcsSUFBSSxlQUFlLEVBQUU7Z0JBQzlELEtBQUssRUFBRSxDQUFDLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQzthQUM1QixDQUFDLENBQUM7WUFDSCxPQUFPLElBQUksQ0FBQyxPQUFPLENBQUMsYUFBYSxDQUFDLENBQUM7UUFDckMsQ0FBQztRQUFDLE9BQU8sR0FBRyxFQUFFLENBQUM7WUFDYixLQUFLLENBQUMsZ0RBQWdELEVBQUUsR0FBRyxFQUFFLE1BQU0sQ0FBQyxDQUFDO1lBQ3JFLE1BQU0sSUFBSSxLQUFLLENBQUMsdUJBQXVCLElBQUksUUFBUSxDQUFDLEdBQUcsSUFBSSxDQUFDLFVBQVUsQ0FBQyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxFQUFFO2dCQUNyRixLQUFLLEVBQUUsR0FBRzthQUNYLENBQUMsQ0FBQztRQUNMLENBQUM7SUFDSCxDQUFDO0lBRUQsS0FBSyxDQUFDLGdDQUFnQyxDQUNwQyxVQUFrQixFQUNsQixTQW9CQztRQUVELElBQUksY0FBYyxHQUFHLFVBQVUsQ0FBQztRQUNoQyxNQUFNLE9BQU8sR0FBRyxTQUFTLENBQUMsU0FBUyxFQUFFLE9BQU8sQ0FBQztRQUM3QyxJQUFJLE9BQU8sRUFBRSxDQUFDO1lBQ1osSUFBSSxLQUFLLEVBQUUsQ0FBQztnQkFDVixJQUFJLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQztvQkFDbkIsY0FBYyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxNQUFNLENBQUMsQ0FBQztnQkFDekQsQ0FBQztZQUNILENBQUM7aUJBQU0sSUFBSSxPQUFPLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQzNCLGNBQWMsR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxPQUFPLENBQUMsT0FBTyxDQUFDLENBQUM7WUFDMUQsQ0FBQztZQUNELElBQUksT0FBTyxDQUFDLFVBQVUsSUFBSSxtQkFBbUIsRUFBRSxJQUFJLENBQUMsQ0FBQyxNQUFNLE1BQU0sQ0FBQyxjQUFjLENBQUMsQ0FBQyxFQUFFLENBQUM7Z0JBQ25GLCtFQUErRTtnQkFDL0UsY0FBYyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLE9BQU8sQ0FBQyxVQUFVLENBQUMsQ0FBQztnQkFDM0QsS0FBSyxDQUFDLDBEQUEwRCxFQUFFLGNBQWMsQ0FBQyxDQUFDO1lBQ3BGLENBQUM7UUFDSCxDQUFDO2FBQU0sSUFBSSxTQUFTLENBQUMsT0FBTyxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksU0FBUyxDQUFDLElBQUksS0FBSyxRQUFRLEVBQUUsQ0FBQztZQUNuRSxzQkFBc0I7WUFDdEIsSUFBSSxhQUFhLEdBQUcsU0FBUyxDQUFDLE9BQU8sQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUMzQyxJQUFJLE9BQU8sYUFBYSxLQUFLLFFBQVEsRUFBRSxDQUFDO2dCQUN0QyxlQUFlO2dCQUNmLDJCQUEyQjtnQkFDM0IsNkJBQTZCO2dCQUM3QixJQUFJO2dCQUNKLGNBQWMsR0FBRyxJQUFJLENBQUMsT0FBTyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsVUFBVSxFQUFFLGFBQWEsQ0FBQyxDQUFDLENBQUM7WUFDdEUsQ0FBQztpQkFBTSxJQUFJLGFBQWEsRUFBRSxNQUFNLEVBQUUsQ0FBQztnQkFDakMsSUFBSSxPQUFPLGFBQWEsQ0FBQyxNQUFNLEtBQUssUUFBUSxFQUFFLENBQUM7b0JBQzdDLElBQUk7b0JBQ0osaUJBQWlCO29CQUNqQixhQUFhO29CQUNiLG9DQUFvQztvQkFDcEMsU0FBUztvQkFDVCxNQUFNO29CQUNOLElBQUk7b0JBQ0osY0FBYyxHQUFHLElBQUksQ0FBQyxPQUFPLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxVQUFVLEVBQUUsYUFBYSxDQUFDLE1BQU0sQ0FBQyxDQUFDLENBQUM7Z0JBQzdFLENBQUM7cUJBQU0sSUFBSSxhQUFhLENBQUMsTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO29CQUN4QyxJQUFJO29CQUNKLGlCQUFpQjtvQkFDakIsYUFBYTtvQkFDYixvQkFBb0I7b0JBQ3BCLHVDQUF1QztvQkFDdkMsV0FBVztvQkFDWCxTQUFTO29CQUNULE1BQU07b0JBQ04sSUFBSTtvQkFDSixjQUFjLEdBQUcsSUFBSSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLFVBQVUsRUFBRSxhQUFhLENBQUMsTUFBTSxDQUFDLE9BQU8sQ0FBQyxDQUFDLENBQUM7Z0JBQ3JGLENBQUM7WUFDSCxDQUFDO1lBQ0QsS0FBSyxDQUNILHdGQUF3RixFQUN4RixVQUFVLEVBQ1YsY0FBYyxFQUNkLGFBQWEsQ0FDZCxDQUFDO1FBQ0osQ0FBQztRQUNELE9BQU8sY0FBYyxDQUFDO0lBQ3hCLENBQUM7SUFFRCxjQUFjLENBQUMsT0FBc0MsRUFBRSxPQUFzQztRQUMzRixJQUFJLENBQUMsT0FBTyxFQUFFLENBQUM7WUFDYixPQUFPO1FBQ1QsQ0FBQztRQUNELEtBQUssTUFBTSxJQUFJLElBQUksT0FBTyxFQUFFLENBQUM7WUFDM0IsTUFBTSxNQUFNLEdBQUcsT0FBTyxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQzdCLElBQUksWUFBWSxHQUFHLE9BQU8sQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUNqQyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUM7Z0JBQ2xCLFlBQVksR0FBRyxFQUFtQixDQUFDO2dCQUNuQyxPQUFPLENBQUMsSUFBSSxDQUFDLEdBQUcsWUFBWSxDQUFDO1lBQy9CLENBQUM7WUFDRCxJQUFJLFlBQVksQ0FBQyxPQUFPLElBQUksWUFBWSxDQUFDLE9BQU8sS0FBSyxNQUFNLENBQUMsT0FBTyxFQUFFLENBQUM7Z0JBQ3BFLElBQUksQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUNkLGlGQUFpRixFQUNqRixJQUFJLEVBQ0osWUFBWSxFQUNaLE1BQU0sQ0FBQyxJQUFJLENBQ1osQ0FBQztZQUNKLENBQUM7WUFDRCxJQUFJLE1BQU0sQ0FBQyxJQUFJLElBQUksTUFBTSxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUNsQyxPQUFPLFlBQVksQ0FBQyxJQUFJLENBQUM7Z0JBQ3pCLE9BQU8sWUFBWSxDQUFDLE9BQU8sQ0FBQztZQUM5QixDQUFDO1lBQ0QsS0FBSyxNQUFNLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxJQUFJLE1BQU0sQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQztnQkFDbkQsSUFBSSxLQUFLLEtBQUssU0FBUyxFQUFFLENBQUM7b0JBQ3hCLFNBQVM7Z0JBQ1gsQ0FBQztnQkFDRCxJQUFJLE9BQU8sQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFLElBQUksQ0FBQyxJQUFJLEtBQUssQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLElBQUksS0FBSyxDQUFDLE1BQU0sS0FBSyxDQUFDLEVBQUUsQ0FBQztvQkFDbEYsU0FBUztnQkFDWCxDQUFDO2dCQUNELE9BQU8sQ0FBQyxHQUFHLENBQUMsWUFBWSxFQUFFLElBQUksRUFBRSxLQUFLLENBQUMsQ0FBQztZQUN6QyxDQUFDO1FBQ0gsQ0FBQztJQUNILENBQUM7SUFDRCx3QkFBd0I7SUFFeEIsMEJBQTBCO0lBQzFCLFVBQVUsQ0FBc0I7SUFDaEMsTUFBTSxDQUFlO0lBRXJCOzs7Ozs7O09BT0c7SUFDSCxLQUFLLENBQUMsVUFBVTtRQUNkLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQ2pDLElBQUksQ0FBQyxVQUFVLEdBQUcsRUFBRSxDQUFDO1FBRXJCLE1BQU0sTUFBTSxHQUFpQjtZQUMzQixVQUFVLEVBQUUsRUFBRTtZQUNkLGNBQWMsRUFBRSxFQUFFO1NBQ25CLENBQUM7UUFFRixnQ0FBZ0M7UUFDaEMsTUFBTSxTQUFTLEdBQUcsTUFBTSxJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQztRQUVqRCwwQkFBMEI7UUFDMUIsK0JBQStCO1FBQy9CLDJCQUEyQjtRQUMzQiw4QkFBOEI7UUFDOUIsbUNBQW1DO1FBQ25DLCtCQUErQjtRQUMvQixLQUFLLE1BQU0sUUFBUSxJQUFJLElBQUksQ0FBQyxZQUFZLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztZQUNuRCxLQUFLLE1BQU0sSUFBSSxJQUFJLElBQUksQ0FBQyxZQUFZLEVBQUUsRUFBRSxDQUFDO2dCQUN2QyxNQUFNLEtBQUssR0FBRyxJQUFJLENBQUMsSUFBSSxLQUFLLEtBQUssQ0FBQztnQkFDbEMsTUFBTSxNQUFNLEdBQUcsTUFBTSxJQUFJLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsUUFBUSxFQUFFLEtBQUssQ0FBQyxDQUFDLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUNyRyxJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7b0JBQ1osU0FBUztnQkFDWCxDQUFDO2dCQUNELEtBQUssQ0FBQyxzQ0FBc0MsRUFBRSxJQUFJLENBQUMsSUFBSSxFQUFFLFFBQVEsRUFBRSxNQUFNLENBQUMsQ0FBQztnQkFDM0UsTUFBTSxDQUFDLElBQUksRUFBRSxNQUFNLEVBQUUsTUFBTSxDQUFDLENBQUM7WUFDL0IsQ0FBQztRQUNILENBQUM7UUFFRCwyQ0FBMkM7UUFDM0MsTUFBTSxTQUFTLEdBQUcsSUFBSSxDQUFDLGtCQUFrQixFQUFFLENBQUM7UUFDNUMsS0FBSyxDQUFDLHlDQUF5QyxFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBQzVELE1BQU0sQ0FBQyxJQUFJLEVBQUUsTUFBTSxFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBRWhDLG1HQUFtRztRQUNuRyxNQUFNLENBQUMsY0FBYyxHQUFHLE1BQU0sQ0FBQyxjQUFjLElBQUksRUFBRSxDQUFDO1FBQ3BELDJCQUEyQjtRQUMzQixNQUFNLENBQUMsZUFBZSxHQUFHLE1BQU0sQ0FBQyxjQUFjLENBQUM7UUFFL0MsTUFBTSxDQUFDLGFBQWEsR0FBRyxNQUFNLENBQUMsVUFBVSxJQUFJLEVBQUUsQ0FBQztRQUMvQywwQkFBMEI7UUFDMUIsTUFBTSxDQUFDLGNBQWMsR0FBRyxNQUFNLENBQUMsYUFBYSxDQUFDO1FBRTdDLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3JCLEtBQUssQ0FBQyw2QkFBNkIsRUFBRSxJQUFJLENBQUMsTUFBTSxDQUFDLENBQUM7UUFDbEQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFDLENBQUM7SUFDakMsQ0FBQztJQUVELEtBQUssQ0FBQyxpQkFBaUI7UUFDckIsTUFBTSxLQUFLLEdBQUcsQ0FBQyxnQkFBZ0IsRUFBRSxVQUFVLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFDO1FBQzdELE1BQU0sTUFBTSxHQUF3QixFQUFFLENBQUM7UUFDdkMsS0FBSyxNQUFNLFFBQVEsSUFBSSxLQUFLLEVBQUUsQ0FBQztZQUM3QixNQUFNLE1BQU0sR0FBRyxNQUFNLElBQUksQ0FBQyxXQUFXLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsUUFBUSxFQUFFLFNBQVMsRUFBRSxLQUFLLENBQUMsQ0FBQztZQUN4RixJQUFJLENBQUMsTUFBTSxFQUFFLENBQUM7Z0JBQ1osU0FBUztZQUNYLENBQUM7WUFDRCxNQUFNLENBQUMsSUFBSSxFQUFFLE1BQU0sRUFBRSxNQUFNLENBQUMsQ0FBQztRQUMvQixDQUFDO1FBQ0QsT0FBTyxNQUFNLENBQUM7SUFDaEIsQ0FBQztJQUVELEtBQUssQ0FBQyxXQUFXLENBQUMsT0FBZSxFQUFFLFFBQWdCLEVBQUUsV0FBK0IsRUFBRSxJQUFvQjtRQUN4RyxNQUFNLFFBQVEsR0FBRyxJQUFJLEtBQUssUUFBUSxDQUFDO1FBQ25DLE1BQU0sS0FBSyxHQUFHLElBQUksS0FBSyxLQUFLLENBQUM7UUFFN0IsSUFBSSxRQUFRLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxRQUFRLEVBQUUsUUFBUSxDQUFDLENBQUMsQ0FBQztRQUMxRSwyQkFBMkI7UUFDM0IsSUFBSSxRQUFRLEtBQUssZ0JBQWdCLElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztZQUMvQyxRQUFRLEdBQUcsSUFBSSxDQUFDLGFBQWEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sRUFBRSxlQUFlLENBQUMsQ0FBQyxDQUFDO1FBQ3JFLENBQUM7UUFDRCxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDZCxPQUFPO1FBQ1QsQ0FBQztRQUNELE1BQU0sTUFBTSxHQUF3QixNQUFNLElBQUksQ0FBQyxRQUFRLENBQUMsUUFBUSxFQUFFLElBQUksQ0FBQyxPQUFPLEVBQUUsV0FBVyxDQUFDLENBQUM7UUFDN0YsSUFBSSxDQUFDLE1BQU07WUFBRSxPQUFPO1FBQ3BCLElBQUksUUFBUSxJQUFJLEtBQUssRUFBRSxDQUFDO1lBQ3RCLE1BQU0sQ0FBQyxDQUFDLE1BQU0sQ0FBQyxjQUFjLEVBQUUsZ0RBQWdELENBQUMsQ0FBQztRQUNuRixDQUFDO1FBQ0QsSUFBSSxDQUFDLEtBQUssRUFBRSxDQUFDO1lBQ1gsTUFBTSxDQUFDLENBQUMsTUFBTSxDQUFDLFVBQVUsRUFBRSwrQkFBK0IsR0FBRyxRQUFRLENBQUMsQ0FBQztRQUN6RSxDQUFDO1FBQ0Qsc0VBQXNFO1FBQ3RFLElBQUksQ0FBQyxjQUFjLENBQUMsTUFBTSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBQ3RDLE9BQU8sTUFBTSxDQUFDO0lBQ2hCLENBQUM7SUFFRCxrQkFBa0I7UUFDaEIsTUFBTSxZQUFZLEdBQUcsT0FBTyxDQUFDLEdBQUcsQ0FBQyxjQUFjLENBQUM7UUFDaEQsSUFBSSxDQUFDLFlBQVk7WUFBRSxPQUFPO1FBQzFCLElBQUksQ0FBQztZQUNILE1BQU0sU0FBUyxHQUE0QixJQUFJLENBQUMsS0FBSyxDQUFDLFlBQVksQ0FBQyxDQUFDO1lBQ3BFLElBQUksQ0FBQyxjQUFjLENBQUMsU0FBUyxFQUFFLDhCQUE4QixDQUFDLENBQUM7WUFDL0QsT0FBTyxTQUFTLENBQUM7UUFDbkIsQ0FBQztRQUFDLE1BQU0sQ0FBQztZQUNQLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxpRUFBaUUsRUFBRSxZQUFZLENBQUMsQ0FBQztRQUM1RyxDQUFDO0lBQ0gsQ0FBQztJQUVELGNBQWMsQ0FBQyxNQUErQixFQUFFLFFBQWdCO1FBQzlELE1BQU0sR0FBRyxNQUFNLENBQUMsSUFBSSxFQUFFLEVBQUUsRUFBRSxNQUFNLENBQUMsQ0FBQztRQUNsQyxJQUFJLENBQUMsVUFBVSxDQUFDLE1BQU0sRUFBRSxRQUFRLENBQUMsQ0FBQztRQUNsQyxNQUFNLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxVQUFVLEVBQUUsTUFBTSxDQUFDLENBQUM7SUFDeEMsQ0FBQztJQUVELFVBQVUsQ0FBQyxHQUF3QixFQUFFLFFBQWdCO1FBQ25ELEtBQUssTUFBTSxHQUFHLElBQUksTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDO1lBQ25DLE1BQU0sR0FBRyxHQUFHLEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQztZQUNyQixpQkFBaUI7WUFDakIsSUFBSSxHQUFHLEtBQUssU0FBUyxJQUFJLEdBQUcsSUFBSSxPQUFPLEdBQUcsQ0FBQyxPQUFPLEtBQUssVUFBVSxJQUFJLEdBQUcsQ0FBQyxPQUFPLEtBQUssT0FBTyxDQUFDLE9BQU8sRUFBRSxDQUFDO2dCQUNyRyxHQUFHLENBQUMsR0FBRyxDQUFDLEdBQUcsUUFBUSxDQUFDO2dCQUNwQixTQUFTO1lBQ1gsQ0FBQztZQUNELElBQUksR0FBRyxJQUFJLE1BQU0sQ0FBQyxjQUFjLENBQUMsR0FBRyxDQUFDLEtBQUssTUFBTSxDQUFDLFNBQVMsSUFBSSxNQUFNLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDMUYsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLEVBQUUsUUFBUSxDQUFDLENBQUM7Z0JBQy9CLFNBQVM7WUFDWCxDQUFDO1lBQ0QsR0FBRyxDQUFDLEdBQUcsQ0FBQyxHQUFHLFFBQVEsQ0FBQztRQUN0QixDQUFDO0lBQ0gsQ0FBQztJQUNELHdCQUF3QjtJQUV4QiwwQkFBMEI7SUFDMUI7Ozs7T0FJRztJQUNILEtBQUssQ0FBQyxlQUFlO1FBQ25CLE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyxPQUFPLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO0lBQzNDLENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsS0FBSyxDQUFDLHFCQUFxQjtRQUN6QixNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsYUFBYSxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUNqRCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILEtBQUssQ0FBQyxpQkFBaUI7UUFDckIsTUFBTSxJQUFJLENBQUMsVUFBVSxDQUFDLFNBQVMsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxDQUFDO0lBQ3JELENBQUM7SUFFRDs7OztPQUlHO0lBQ0gsS0FBSyxDQUFDLGtCQUFrQjtRQUN0QixNQUFNLElBQUksQ0FBQyxVQUFVLENBQUMsVUFBVSxFQUFFLElBQUksQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLENBQUM7SUFDdkQsQ0FBQztJQUVEOzs7O09BSUc7SUFDSCxLQUFLLENBQUMsaUJBQWlCO1FBQ3JCLE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyxTQUFTLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxPQUFPLENBQUMsQ0FBQztJQUNyRCxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNILEtBQUssQ0FBQyxnQkFBZ0I7UUFDcEIsSUFBSSxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQ3BCLE1BQU0sSUFBSSxDQUFDLFVBQVUsQ0FBQyxRQUFRLEVBQUUsSUFBSSxDQUFDLEdBQUcsQ0FBQyxNQUFNLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDN0QsQ0FBQztJQUNILENBQUM7SUFFRDs7Ozs7OztPQU9HO0lBQ08sa0JBQWtCLENBQUMsSUFBWTtRQUN2QyxPQUFPLElBQUksQ0FBQyxZQUFZLEVBQUUsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLEVBQUUsWUFBWSxFQUFFLElBQUksQ0FBQyxDQUFDLENBQUM7SUFDbkYsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNILEtBQUssQ0FBQyxVQUFVLENBQUMsSUFBWSxFQUFFLEtBQWE7UUFDMUMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsZUFBZSxJQUFJLEtBQUssQ0FBQyxDQUFDO1FBQzVDLG1CQUFtQjtRQUNuQixNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsa0JBQWtCLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDaEQsOENBQThDO1FBQzlDLE1BQU0sWUFBWSxHQUFHLHFCQUFxQixJQUFJLE9BQU8sQ0FBQyxHQUFHLElBQUksSUFBSSxDQUFDLFNBQVMsS0FBSyxVQUFVLENBQUM7UUFDM0YsTUFBTSxNQUFNLEdBQUcsU0FBUyxDQUFDLE1BQU0sQ0FBQztRQUNoQyxLQUFLLElBQUksQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEdBQUcsTUFBTSxFQUFFLENBQUMsRUFBRSxFQUFFLENBQUM7WUFDaEMsTUFBTSxRQUFRLEdBQUcsU0FBUyxDQUFDLENBQUMsQ0FBQyxDQUFDO1lBQzlCLFNBQVMsQ0FBQyxJQUFJLENBQUMsUUFBUSxHQUFHLElBQUksSUFBSSxDQUFDLFNBQVMsRUFBRSxDQUFDLENBQUM7WUFDaEQsSUFBSSxZQUFZLEVBQUUsQ0FBQztnQkFDakIsU0FBUyxDQUFDLElBQUksQ0FBQyxRQUFRLEdBQUcsV0FBVyxDQUFDLENBQUM7WUFDekMsQ0FBQztRQUNILENBQUM7UUFDRCxLQUFLLENBQUMsOEJBQThCLEVBQUUsSUFBSSxFQUFFLFNBQVMsQ0FBQyxDQUFDO1FBRXZELE1BQU0sV0FBVyxHQUFHLElBQUksR0FBRyxFQUFFLENBQUM7UUFDOUIsS0FBSyxNQUFNLFdBQVcsSUFBSSxTQUFTLEVBQUUsQ0FBQztZQUNwQyxNQUFNLFFBQVEsR0FBRyxJQUFJLENBQUMsYUFBYSxDQUFDLFdBQVcsQ0FBQyxDQUFDO1lBQ2pELElBQUksQ0FBQyxRQUFRLEVBQUUsQ0FBQztnQkFDZCxpREFBaUQ7Z0JBQ2pELFNBQVM7WUFDWCxDQUFDO1lBQ0QsSUFBSSxRQUFRLENBQUMsUUFBUSxDQUFDLFdBQVcsQ0FBQyxFQUFFLENBQUM7Z0JBQ25DLElBQUksQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLGNBQWMsSUFBSSwyQ0FBMkMsSUFBSSxhQUFhLENBQUMsQ0FBQztZQUNyRyxDQUFDO2lCQUFNLElBQUksUUFBUSxDQUFDLFFBQVEsQ0FBQyxXQUFXLENBQUMsRUFBRSxDQUFDO2dCQUMxQyxJQUFJLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxjQUFjLElBQUksMkNBQTJDLElBQUksYUFBYSxDQUFDLENBQUM7WUFDckcsQ0FBQztZQUVELElBQUksR0FBRyxHQUFHLE1BQU0sSUFBSSxDQUFDLFdBQVcsQ0FBQyxRQUFRLENBQUMsQ0FBQztZQUMzQyxnRUFBZ0U7WUFDaEUsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztnQkFDakIsR0FBRyxHQUFHLEdBQUcsQ0FBQyxTQUFTLENBQUM7WUFDdEIsQ0FBQztZQUNELE1BQU0sVUFBVSxHQUFHLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxHQUFHLENBQUM7aUJBQy9DLE1BQU0sQ0FBQyxNQUFNLENBQUMscUJBQXFCLENBQUMsR0FBRyxDQUF3QixDQUFDO2lCQUNoRSxNQUFNLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQyxJQUFJLEtBQUssYUFBYSxDQUFDLENBQUMsQ0FBQyxzQ0FBc0M7WUFFakYsS0FBSyxNQUFNLFFBQVEsSUFBSSxVQUFVLEVBQUUsQ0FBQztnQkFDbEMsSUFBSSxXQUFXLENBQUMsR0FBRyxDQUFDLFFBQVEsQ0FBQyxFQUFFLENBQUM7b0JBQzlCLEtBQUssQ0FDSCxvRUFBb0UsRUFDcEUsUUFBUSxFQUNSLFdBQVcsQ0FBQyxHQUFHLENBQUMsUUFBUSxDQUFDLEVBQ3pCLFFBQVEsQ0FDVCxDQUFDO2dCQUNKLENBQUM7Z0JBRUQsa0JBQWtCO2dCQUNsQixJQUFJLFVBQVUsR0FBRyxNQUFNLENBQUMsd0JBQXdCLENBQUMsR0FBRyxFQUFFLFFBQVEsQ0FBdUIsQ0FBQztnQkFDdEYsSUFBSSxrQkFBa0IsR0FBRyxNQUFNLENBQUMsd0JBQXdCLENBQUMsS0FBSyxFQUFFLFFBQVEsQ0FBQyxDQUFDO2dCQUMxRSxJQUFJLENBQUMsa0JBQWtCLEVBQUUsQ0FBQztvQkFDeEIsZ0RBQWdEO29CQUNoRCxNQUFNLGFBQWEsR0FBRyxrQkFBa0IsQ0FBQyxJQUFJLENBQUMsQ0FBQztvQkFDL0MsSUFBSSxhQUFhLEVBQUUsQ0FBQzt3QkFDbEIsa0JBQWtCLEdBQUcsTUFBTSxDQUFDLHdCQUF3QixDQUFDLGFBQWEsRUFBRSxRQUFRLENBQUMsQ0FBQztvQkFDaEYsQ0FBQztnQkFDSCxDQUFDO2dCQUNELElBQUksa0JBQWtCLEVBQUUsQ0FBQztvQkFDdkIsNEJBQTRCO29CQUM1QixVQUFVLEdBQUc7d0JBQ1gsR0FBRyxVQUFVO3FCQUNkLENBQUM7b0JBQ0YsSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLElBQUksa0JBQWtCLENBQUMsR0FBRyxFQUFFLENBQUM7d0JBQzlDLFVBQVUsQ0FBQyxHQUFHLEdBQUcsa0JBQWtCLENBQUMsR0FBRyxDQUFDO29CQUMxQyxDQUFDO29CQUNELElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxJQUFJLGtCQUFrQixDQUFDLEdBQUcsRUFBRSxDQUFDO3dCQUM5QyxVQUFVLENBQUMsR0FBRyxHQUFHLGtCQUFrQixDQUFDLEdBQUcsQ0FBQztvQkFDMUMsQ0FBQztnQkFDSCxDQUFDO2dCQUNELE1BQU0sQ0FBQyxjQUFjLENBQUMsS0FBSyxFQUFFLFFBQVEsRUFBRSxVQUFVLENBQUMsQ0FBQztnQkFDbkQsV0FBVyxDQUFDLEdBQUcsQ0FBQyxRQUFRLEVBQUUsUUFBUSxDQUFDLENBQUM7WUFDdEMsQ0FBQztZQUNELEtBQUssQ0FBQyx3QkFBd0IsRUFBRSxVQUFVLEVBQUUsSUFBSSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1FBQzlELENBQUM7UUFDRCxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxlQUFlLElBQUksS0FBSyxDQUFDLENBQUM7SUFDNUMsQ0FBQztJQUNELHdCQUF3QjtJQUV4QiwwQkFBMEI7SUFDMUI7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztPQXdCRztJQUNILEtBQUssQ0FBQyxhQUFhO1FBQ2pCLE1BQU0sSUFBSSxDQUFDLGFBQWEsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUNoQyxJQUFJLENBQUMsU0FBUyxDQUFDLHFCQUFxQixFQUFFLENBQUM7SUFDekMsQ0FBQztJQUVEOztPQUVHO0lBQ0gsS0FBSyxDQUFDLGVBQWU7UUFDbkIsTUFBTSxJQUFJLENBQUMsYUFBYSxDQUFDLE9BQU8sQ0FBQyxDQUFDO1FBQ2xDLElBQUksQ0FBQyxTQUFTLENBQUMscUJBQXFCLEVBQUUsQ0FBQztJQUN6QyxDQUFDO0lBRUQsMENBQTBDO0lBQzFDLFlBQVk7UUFDVixhQUFhO0lBQ2YsQ0FBQztJQUVELEtBQUssQ0FBQyxhQUFhLENBQUMsUUFBZ0I7UUFDbEMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsUUFBUSxRQUFRLEtBQUssQ0FBQyxDQUFDO1FBQ3pDLEtBQUssTUFBTSxJQUFJLElBQUksSUFBSSxDQUFDLFlBQVksRUFBRSxFQUFFLENBQUM7WUFDdkMsTUFBTSxRQUFRLEdBQUcsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLFFBQVEsQ0FBQyxDQUFDO1lBQ2hELE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxhQUFhLENBQUMsUUFBUSxDQUFDLENBQUM7WUFDbEQsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO2dCQUNsQixLQUFLLENBQUMsb0NBQW9DLEVBQUUsUUFBUSxDQUFDLENBQUM7Z0JBQ3RELFNBQVM7WUFDWCxDQUFDO1lBQ0QsS0FBSyxDQUFDLGlDQUFpQyxFQUFFLFFBQVEsRUFBRSxZQUFZLENBQUMsQ0FBQztZQUNqRSxNQUFNLFFBQVEsR0FBRyxNQUFNLElBQUksQ0FBQyxXQUFXLENBQUMsWUFBWSxDQUFDLENBQUM7WUFDdEQsSUFBSSxPQUFPLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztnQkFDdEIsUUFBUSxDQUFDLFNBQVMsQ0FBQyxRQUFRLEdBQUcsWUFBWSxDQUFDO2dCQUMzQyxxQ0FBcUM7Z0JBQ3JDLElBQUksQ0FBQyxTQUFTLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBQyxDQUFDO2dCQUNyQyxLQUFLLENBQUMsMENBQTBDLEVBQUUsWUFBWSxDQUFDLENBQUM7WUFDbEUsQ0FBQztpQkFBTSxJQUFJLE9BQU8sUUFBUSxLQUFLLFVBQVUsRUFBRSxDQUFDO2dCQUMxQyxxQ0FBcUM7Z0JBQ3JDLG9CQUFvQjtnQkFDcEIsSUFBSSxDQUFDLFNBQVMsQ0FBQyxxQkFBcUIsQ0FBQyxRQUFRLEVBQUUsWUFBWSxDQUFDLENBQUM7Z0JBQzdELEtBQUssQ0FBQyw2Q0FBNkMsRUFBRSxZQUFZLENBQUMsQ0FBQztZQUNyRSxDQUFDO2lCQUFNLENBQUM7Z0JBQ04sSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLHVEQUF1RCxFQUFFLFlBQVksQ0FBQyxDQUFDO1lBQ2xHLENBQUM7UUFDSCxDQUFDO1FBQ0QsYUFBYTtRQUNiLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDdEIsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsUUFBUSxRQUFRLEtBQUssQ0FBQyxDQUFDO0lBQ3pDLENBQUM7SUFDRCx3QkFBd0I7SUFFeEIsMkJBQTJCO0lBQzNCOzs7OztPQUtHO0lBQ0gsS0FBSyxDQUFDLFdBQVcsQ0FBQyxPQUF1QztRQUN2RCxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxjQUFjLENBQUMsQ0FBQztRQUNsQyx5QkFBeUI7UUFDekIsTUFBTSxZQUFZLEdBQUcsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxhQUFhLENBQUMsQ0FBQyxDQUFDO1FBQzFGLE9BQU8sR0FBRztZQUNSLElBQUksRUFBRSxJQUFJO1lBQ1YsU0FBUyxFQUFFLFNBQVMsQ0FBQyxLQUFLO1lBQzFCLFVBQVUsRUFBRSxnQkFBZ0I7WUFDNUIsU0FBUyxFQUFFLFlBQVk7WUFDdkIsR0FBRyxPQUFPO1NBQ1gsQ0FBQztRQUNGLEtBQUssQ0FBQywyQkFBMkIsRUFBRSxPQUFPLENBQUMsQ0FBQztRQUM1QyxNQUFNLElBQUksQ0FBQyxhQUFhLENBQUMsWUFBWSxFQUFFLFNBQVMsRUFBRSxPQUErQixDQUFDLENBQUM7UUFDbkYsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsY0FBYyxDQUFDLENBQUM7SUFDbEMsQ0FBQztJQUNELHlCQUF5QjtJQUV6Qiw4QkFBOEI7SUFDOUI7Ozs7Ozs7Ozs7Ozs7Ozs7OztPQWtCRztJQUNILEtBQUssQ0FBQyxjQUFjLENBQUMsR0FBZ0M7UUFDbkQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsaUJBQWlCLENBQUMsQ0FBQztRQUNyQyxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDO1FBRXJCLG9DQUFvQztRQUNwQyxNQUFNLGVBQWUsR0FBRyxJQUFJLENBQUMsWUFBWSxFQUFFLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxFQUFFLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLGdCQUFnQixDQUFDLENBQUMsQ0FBQztRQUNoRyxHQUFHLEdBQUc7WUFDSixJQUFJLEVBQUUsS0FBSztZQUNYLFFBQVEsRUFBRSxJQUFJO1lBQ2QsU0FBUyxFQUFFLFNBQVMsQ0FBQyxLQUFLO1lBQzFCLFNBQVMsRUFBRSxlQUFlO1lBQzFCLEdBQUcsR0FBRztTQUNQLENBQUM7UUFDRixNQUFNLElBQUksQ0FBQyxTQUFTLENBQUMsZUFBZSxFQUFFLGFBQWEsRUFBRSxHQUF3QixDQUFDLENBQUM7UUFDL0UsS0FBSyxDQUFDLHNDQUFzQyxFQUFFLGVBQWUsQ0FBQyxDQUFDO1FBRS9ELEtBQUssTUFBTSxJQUFJLElBQUksR0FBRyxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ25DLE1BQU0sQ0FBQyxjQUFjLENBQUMsR0FBRyxDQUFDLFVBQVUsRUFBRSxJQUFJLEVBQUU7Z0JBQzFDLEdBQUc7b0JBQ0QsT0FBTyxHQUFHLENBQUMsV0FBVyxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUMvQixDQUFDO2dCQUNELFVBQVUsRUFBRSxLQUFLO2dCQUNqQixZQUFZLEVBQUUsS0FBSzthQUNwQixDQUFDLENBQUM7UUFDTCxDQUFDO1FBRUQsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLDhCQUE4QixFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLENBQUM7UUFDckYsSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLENBQUMsSUFBSSxDQUFDLDZCQUE2QixFQUFFLElBQUksQ0FBQyxNQUFNLENBQUMsYUFBYSxDQUFDLENBQUM7UUFFbkYsbUZBQW1GO1FBQ25GLE1BQU0sZUFBZSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsY0FBYyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsTUFBTSxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQ3JGLEtBQUssQ0FBQyxzQ0FBc0MsRUFBRSxlQUFlLENBQUMsQ0FBQztRQUMvRCxNQUFNLGNBQWMsR0FBRyxJQUFJLEdBQUcsRUFBbUIsQ0FBQztRQUNsRCxLQUFLLE1BQU0sSUFBSSxJQUFJLGVBQWUsRUFBRSxDQUFDO1lBQ25DLE1BQU0sZ0JBQWdCLEdBQUcsR0FBRyxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUMvQyxJQUFJLENBQUMsZ0JBQWdCLEVBQUUsQ0FBQztnQkFDdEIsTUFBTSxJQUFJLFNBQVMsQ0FBQyxjQUFjLElBQUksWUFBWSxDQUFDLENBQUM7WUFDdEQsQ0FBQztZQUNELElBQUksY0FBYyxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO2dCQUM3QixNQUFNLElBQUksU0FBUyxDQUFDLGNBQWMsSUFBSSxZQUFZLENBQUMsQ0FBQztZQUN0RCxDQUFDO1lBQ0QsY0FBYyxDQUFDLEdBQUcsQ0FBQyxJQUFJLEVBQUUsSUFBSSxDQUFDLENBQUM7WUFDL0IsTUFBTSxPQUFPLEdBQUcsSUFBSSxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsSUFBSSxFQUFFLENBQUM7WUFDeEMsSUFBSSxFQUFFLEdBQTBCLGdCQUFnQixDQUFDLE9BQU8sRUFBRSxHQUFHLENBQUMsQ0FBQztZQUMvRCxNQUFNLENBQUMsT0FBTyxFQUFFLEtBQUssVUFBVSxFQUFFLGNBQWMsSUFBSSxzQ0FBc0MsT0FBTyxDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUMsQ0FBQztZQUN4RyxJQUFJLG1CQUFtQixDQUFDLEVBQUUsQ0FBQyxFQUFFLENBQUM7Z0JBQzVCLE1BQU0sUUFBUSxHQUFHLE9BQU8sQ0FBQyxHQUFHLENBQUMsZ0JBQWdCLEVBQUUsUUFBUSxDQUFDLENBQUM7Z0JBQ3pELE1BQU0sSUFBSSxTQUFTLENBQUMsbURBQW1ELElBQUksZUFBZSxRQUFRLEVBQUUsQ0FBQyxDQUFDO1lBQ3hHLENBQUM7WUFDRCxFQUFFLENBQUMsS0FBSyxHQUFHLElBQUksQ0FBQztZQUNoQix1RUFBdUU7WUFDdkUsRUFBRSxHQUFHLGNBQWMsQ0FBQyxFQUFFLEVBQUUsT0FBTyxDQUFDLENBQUM7WUFDakMsSUFBSSxFQUFFLEVBQUUsQ0FBQztnQkFDUCxJQUFJLEtBQUssQ0FBQyxPQUFPLEVBQUUsQ0FBQztvQkFDbEIscUNBQXFDO29CQUNyQyxFQUFFLEdBQUcsc0JBQXNCLENBQUMsRUFBRSxDQUFDLENBQUM7Z0JBQ2xDLENBQUM7Z0JBQ0QsR0FBRyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztnQkFDWixLQUFLLENBQUMsc0RBQXNELEVBQUUsSUFBSSxFQUFFLE9BQU8sQ0FBQyxDQUFDO2dCQUM3RSxJQUFJLENBQUMsT0FBTyxDQUFDLE1BQU0sQ0FBQyxJQUFJLENBQUMsNkNBQTZDLEVBQUUsSUFBSSxDQUFDLENBQUM7WUFDaEYsQ0FBQztpQkFBTSxDQUFDO2dCQUNOLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxpREFBaUQsRUFBRSxJQUFJLENBQUMsQ0FBQztZQUNwRixDQUFDO1FBQ0gsQ0FBQztRQUVELElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxvREFBb0QsRUFBRSxlQUFlLENBQUMsQ0FBQztRQUNoRyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1FBRW5DLGlFQUFpRTtRQUNqRSxNQUFNLEVBQUUsR0FBRyxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxVQUFVLEVBQUUsQ0FBQztRQUN4QyxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUUsRUFBRSxPQUFPLEVBQUUsa0JBQWtCLENBQUMsQ0FBQztRQUM3QyxJQUFJLENBQUMsR0FBRyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUMsQ0FBQztJQUNuQixDQUFDO0lBQ0QsNEJBQTRCO0lBRTVCLDhCQUE4QjtJQUM5Qjs7OztPQUlHO0lBQ0gsS0FBSyxDQUFDLGNBQWMsQ0FBQyxHQUFnQztRQUNuRCxJQUFJLENBQUMsTUFBTSxDQUFDLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO1FBQ3JDLE1BQU0sY0FBYyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsZ0JBQWdCLENBQUMsQ0FBQztRQUN6RSxHQUFHLEdBQUc7WUFDSixTQUFTLEVBQUUsU0FBUyxDQUFDLEtBQUs7WUFDMUIsU0FBUyxFQUFFLGNBQWM7WUFDekIsV0FBVyxFQUFFLENBQUMsR0FBRyxFQUFFLEdBQUcsRUFBRSxFQUFFO2dCQUN4Qix3Q0FBd0M7Z0JBQ3hDLFFBQVE7Z0JBQ1IsNEJBQTRCO2dCQUM1QiwyREFBMkQ7Z0JBQzNELElBQUk7Z0JBQ0osTUFBTTtnQkFDTixJQUFJLG1CQUFtQixDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7b0JBQzdCLE1BQU0sSUFBSSxTQUFTLENBQUMsaURBQWlELEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO2dCQUNuRixDQUFDO2dCQUNELElBQUksQ0FBQyxPQUFPLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsR0FBRyxDQUFDLElBQUksT0FBTyxHQUFHLEtBQUssVUFBVSxFQUFFLENBQUM7b0JBQ3hFLEdBQUcsR0FBRyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsQ0FBQyxDQUFDO29CQUNwQixLQUFLLENBQUMsa0RBQWtELEVBQUUsR0FBRyxFQUFFLEdBQUcsQ0FBQyxDQUFDO29CQUNwRSxJQUFJLG1CQUFtQixDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7d0JBQzdCLE1BQU0sSUFBSSxTQUFTLENBQUMsaURBQWlELEdBQUcsQ0FBQyxJQUFJLEVBQUUsQ0FBQyxDQUFDO29CQUNuRixDQUFDO2dCQUNILENBQUM7Z0JBQ0QsSUFBSSxPQUFPLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztvQkFDakIsR0FBRyxDQUFDLFNBQVMsQ0FBQyxRQUFRLEdBQUcsR0FBRyxDQUFDLFFBQVEsQ0FBQztvQkFDdEMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxRQUFRLEdBQUcsR0FBRyxDQUFDLElBQUksQ0FBQztvQkFDbEMsT0FBTyxtQkFBbUIsQ0FBQyxHQUFHLEVBQUUsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO2dCQUM1QyxDQUFDO2dCQUNELElBQUksUUFBUSxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7b0JBQ2xCLE9BQU8sVUFBVSxDQUFDLEdBQUcsRUFBRSxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQ25DLENBQUM7Z0JBQ0QsSUFBSSxlQUFlLENBQUMsR0FBRyxDQUFDLEVBQUUsQ0FBQztvQkFDekIsT0FBTyxVQUFVLENBQUMsRUFBRSxnQkFBZ0IsRUFBRSxHQUFHLEVBQUUsRUFBRSxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUMsZ0JBQWdCLENBQUMsQ0FBQztnQkFDM0UsQ0FBQztnQkFDRCxPQUFPLEdBQUcsQ0FBQztZQUNiLENBQUM7WUFDRCxHQUFHLEdBQUc7U0FDUCxDQUFDO1FBQ0YsTUFBTSxJQUFJLENBQUMsU0FBUyxDQUFDLGNBQWMsRUFBRSxZQUFZLEVBQUUsR0FBd0IsQ0FBQyxDQUFDO1FBQzdFLEtBQUssQ0FBQyx1Q0FBdUMsRUFBRSxJQUFJLENBQUMsR0FBRyxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBQ3BFLElBQUksQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLElBQUksQ0FBQyxnREFBZ0QsRUFBRSxjQUFjLENBQUMsQ0FBQztRQUMzRixJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDO0lBQ3JDLENBQUM7SUFDRCw0QkFBNEI7SUFFNUIsMEJBQTBCO0lBQzFCOzs7O09BSUc7SUFDSCxLQUFLLENBQUMsVUFBVTtRQUNkLElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLGFBQWEsQ0FBQyxDQUFDO1FBQ2pDLE1BQU0sSUFBSSxDQUFDLFFBQVEsQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQyxPQUFPLENBQUMsT0FBTyxFQUFFLFlBQVksQ0FBQyxDQUFDLENBQUM7UUFDbkUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsYUFBYSxDQUFDLENBQUM7SUFDakMsQ0FBQztJQUNELHdCQUF3QjtJQUV4QixnQ0FBZ0M7SUFDaEMsS0FBSyxDQUFDLGdCQUFnQjtRQUNwQixNQUFNLENBQUMsSUFBSSxDQUFDLE1BQU0sRUFBRSx5QkFBeUIsQ0FBQyxDQUFDO1FBQy9DLE1BQU0sWUFBWSxHQUFHLElBQUksQ0FBQyxNQUFNLENBQUMsWUFBWSxJQUFJLEVBQUUsQ0FBQztRQUVwRCxLQUFLLE1BQU0sUUFBUSxJQUFJLE1BQU0sQ0FBQyxJQUFJLENBQUMsWUFBWSxDQUFDLEVBQUUsQ0FBQztZQUNqRCxNQUFNLFlBQVksR0FBRztnQkFDbkIsR0FBRyxZQUFZLENBQUMsUUFBUSxDQUFDO2FBQzFCLENBQUM7WUFDRixNQUFNLENBQUMsWUFBWSxDQUFDLFNBQVMsRUFBRSxpREFBaUQsUUFBUSxFQUFFLENBQUMsQ0FBQztZQUM1RixJQUFJLFNBQTRCLENBQUM7WUFDakMsSUFBSSxZQUFZLENBQUMsUUFBUSxLQUFLLElBQUksRUFBRSxDQUFDO2dCQUNuQyxTQUFTLEdBQUcsSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDLEdBQUcsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxZQUFZLENBQUMsU0FBUyxDQUFDLENBQUMsQ0FBQztZQUM1RixDQUFDO2lCQUFNLENBQUM7Z0JBQ04sU0FBUyxHQUFHLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsWUFBWSxDQUFDLFNBQVMsQ0FBQyxDQUFDO1lBQ3RFLENBQUM7WUFDRCxNQUFNLE1BQU0sR0FBRyxZQUFZLENBQUMsTUFBTSxJQUFJLEtBQUssQ0FBQztZQUM1QyxLQUFLLENBQUMsZ0VBQWdFLEVBQUUsWUFBWSxFQUFFLE1BQU0sRUFBRSxTQUFTLENBQUMsQ0FBQztZQUV6RyxRQUFRLE1BQU0sRUFBRSxDQUFDO2dCQUNmLEtBQUssS0FBSyxDQUFDLENBQUMsQ0FBQztvQkFDWCxNQUFNLENBQUMsQ0FBQyxDQUFDLFFBQVEsSUFBSSxJQUFJLENBQUMsR0FBRyxDQUFDLE9BQU8sQ0FBQyxFQUFFLHdDQUF3QyxRQUFRLEVBQUUsQ0FBQyxDQUFDO29CQUM1RixNQUFNLE9BQU8sR0FBRzt3QkFDZCxTQUFTLEVBQUUsU0FBUyxDQUFDLEtBQUs7d0JBQzFCLFVBQVUsRUFBRSxHQUFHLFFBQVEsU0FBUzt3QkFDaEMsR0FBRyxZQUFZO3dCQUNmLFNBQVM7cUJBQ1YsQ0FBQztvQkFDRixNQUFNLElBQUksQ0FBQyxhQUFhLENBQUMsU0FBUyxFQUFFLFFBQVEsRUFBRSxPQUFPLENBQUMsQ0FBQztvQkFDdkQsTUFBTTtnQkFDUixDQUFDO2dCQUNELEtBQUssS0FBSyxDQUFDLENBQUMsQ0FBQztvQkFDWCxNQUFNLENBQUMsQ0FBQyxDQUFDLFFBQVEsSUFBSSxJQUFJLENBQUMsR0FBRyxDQUFDLEVBQUUsd0NBQXdDLFFBQVEsRUFBRSxDQUFDLENBQUM7b0JBQ3BGLE1BQU0sT0FBTyxHQUFHO3dCQUNkLFNBQVMsRUFBRSxTQUFTLENBQUMsS0FBSzt3QkFDMUIsV0FBVyxFQUFFLENBQUMsS0FBYyxFQUFFLEVBQUU7NEJBQzlCLE9BQU8sT0FBTyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUMsQ0FBQyxJQUFJLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLENBQUMsQ0FBQyxDQUFDLEtBQUssQ0FBQzt3QkFDdEQsQ0FBQzt3QkFDRCxHQUFHLFlBQVk7d0JBQ2YsU0FBUztxQkFDVixDQUFDO29CQUNGLE1BQU0sSUFBSSxDQUFDLFNBQVMsQ0FBQyxTQUFTLEVBQUUsUUFBUSxFQUFFLE9BQU8sQ0FBQyxDQUFDO29CQUNuRCxNQUFNO2dCQUNSLENBQUM7Z0JBQ0Q7b0JBQ0UsTUFBTSxJQUFJLEtBQUssQ0FBQyxnQ0FBZ0MsQ0FBQyxDQUFDO1lBQ3RELENBQUM7UUFDSCxDQUFDO0lBQ0gsQ0FBQztJQUNELDhCQUE4QjtJQUU5QixnQkFBZ0I7SUFFaEI7Ozs7Ozs7Ozs7O09BV0c7SUFDSCxLQUFLLENBQUMsUUFBUSxDQUFDLFFBQWdCLEVBQUUsR0FBRyxNQUFpQjtRQUNuRCxNQUFNLFFBQVEsR0FBRyxRQUFRLElBQUksSUFBSSxDQUFDLGFBQWEsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUMxRCxJQUFJLENBQUMsUUFBUSxFQUFFLENBQUM7WUFDZCxPQUFPLElBQUksQ0FBQztRQUNkLENBQUM7UUFFRCwrQkFBK0I7UUFDL0IsSUFBSSxNQUFNLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRSxDQUFDO1lBQ3hCLE1BQU0sR0FBRyxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztRQUN0QixDQUFDO1FBQ0QsSUFBSSxHQUFHLEdBQUcsTUFBTSxJQUFJLENBQUMsV0FBVyxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQzNDLElBQUksT0FBTyxHQUFHLEtBQUssVUFBVSxJQUFJLENBQUMsT0FBTyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7WUFDL0MsR0FBRyxHQUFHLEdBQUcsQ0FBQyxHQUFHLE1BQU0sQ0FBQyxDQUFDO1lBQ3JCLElBQUksU0FBUyxDQUFDLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQ25CLEdBQUcsR0FBRyxNQUFNLEdBQUcsQ0FBQztZQUNsQixDQUFDO1FBQ0gsQ0FBQztRQUNELE9BQU8sR0FBRyxDQUFDO0lBQ2IsQ0FBQztJQUVEOzs7T0FHRztJQUNILEtBQUssQ0FBQyxXQUFXLENBQUMsUUFBZ0I7UUFDaEMsTUFBTSxTQUFTLEdBQUcsV0FBVyxJQUFJLENBQUMsY0FBYyxFQUFFLEtBQUssS0FBSyxDQUFDLG1CQUFtQixDQUFDLFFBQVEsRUFBRSxJQUFJLENBQUMsT0FBTyxDQUFDLE9BQU8sQ0FBQyxFQUFFLENBQUM7UUFDbkgsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDN0IsTUFBTSxHQUFHLEdBQUcsTUFBTSxLQUFLLENBQUMsUUFBUSxDQUFDLFFBQVEsQ0FBQyxDQUFDO1FBQzNDLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQzNCLE9BQU8sR0FBRyxDQUFDO0lBQ2IsQ0FBQztJQUVEOzs7Ozs7Ozs7Ozs7OztPQWNHO0lBQ0gsWUFBWTtRQUNWLElBQUksSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1lBQ2QsT0FBTyxJQUFJLENBQUMsSUFBSSxDQUFDO1FBQ25CLENBQUM7UUFFRCxJQUFJLENBQUMsSUFBSSxHQUFHLEVBQUUsQ0FBQztRQUNmLElBQUksSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO1lBQ3RCLEtBQUssTUFBTSxNQUFNLElBQUksSUFBSSxDQUFDLFlBQVksRUFBRSxDQUFDO2dCQUN2QyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksQ0FBQztvQkFDYixJQUFJLEVBQUUsTUFBTSxDQUFDLElBQWM7b0JBQzNCLElBQUksRUFBRSxRQUFRO2lCQUNmLENBQUMsQ0FBQztZQUNMLENBQUM7UUFDSCxDQUFDO1FBRUQsd0JBQXdCO1FBQ3hCLEtBQUssTUFBTSxPQUFPLElBQUksSUFBSSxDQUFDLFFBQVEsRUFBRSxDQUFDO1lBQ3BDLElBQUksQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDO2dCQUNiLElBQUksRUFBRSxPQUFPO2dCQUNiLElBQUksRUFBRSxXQUFXO2FBQ2xCLENBQUMsQ0FBQztRQUNMLENBQUM7UUFFRCxjQUFjO1FBQ2QsSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUM7WUFDYixJQUFJLEVBQUUsSUFBSSxDQUFDLE9BQU8sQ0FBQyxPQUFPO1lBQzFCLElBQUksRUFBRSxLQUFLO1NBQ1osQ0FBQyxDQUFDO1FBRUgsS0FBSyxDQUFDLGdCQUFnQixFQUFFLElBQUksQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNuQyxPQUFPLElBQUksQ0FBQyxJQUFJLENBQUM7SUFDbkIsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNILEtBQUssQ0FBQyxTQUFTLENBQ2IsU0FBNEIsRUFDNUIsUUFBeUIsRUFDekIsT0FBc0Q7UUFFdEQsTUFBTSxNQUFNLEdBQUcsRUFBRSxDQUFDO1FBQ2xCLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLEdBQUcsRUFBRSxRQUFRLEVBQUUsTUFBTSxDQUFDLENBQUM7UUFDeEMsTUFBTSxXQUFXLEdBQXNCO1lBQ3JDLEdBQUcsT0FBTztZQUNWLFNBQVMsRUFBRSxPQUFPLEVBQUUsU0FBUyxJQUFJLFNBQVM7WUFDMUMsTUFBTTtZQUNOLE1BQU0sRUFBRSxJQUFJLENBQUMsR0FBRztTQUNqQixDQUFDO1FBRUYsTUFBTSxTQUFTLEdBQUcsU0FBUyxNQUFNLENBQUMsUUFBUSxDQUFDLGtCQUFrQixDQUFDO1FBQzlELElBQUksQ0FBQyxNQUFNLENBQUMsS0FBSyxDQUFDLFNBQVMsQ0FBQyxDQUFDO1FBQzdCLE1BQU0sSUFBSSxVQUFVLENBQUMsV0FBVyxDQUFDLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDekMsSUFBSSxDQUFDLE1BQU0sQ0FBQyxHQUFHLENBQUMsU0FBUyxDQUFDLENBQUM7SUFDN0IsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNILEtBQUssQ0FBQyxhQUFhLENBQ2pCLFNBQTRCLEVBQzVCLFFBQXlCLEVBQ3pCLE9BQTJEO1FBRTNELE1BQU0sV0FBVyxHQUF5QjtZQUN4QyxHQUFHLE9BQU87WUFDVixTQUFTLEVBQUUsT0FBTyxFQUFFLFNBQVMsSUFBSSxTQUFTO1lBQzFDLFFBQVE7WUFDUixNQUFNLEVBQUUsSUFBSSxDQUFDLEdBQUc7U0FDakIsQ0FBQztRQUVGLE1BQU0sU0FBUyxHQUFHLFNBQVMsTUFBTSxDQUFDLFFBQVEsQ0FBQyxjQUFjLENBQUM7UUFDMUQsSUFBSSxDQUFDLE1BQU0sQ0FBQyxLQUFLLENBQUMsU0FBUyxDQUFDLENBQUM7UUFDN0IsTUFBTSxJQUFJLGFBQWEsQ0FBQyxXQUFXLENBQUMsQ0FBQyxJQUFJLEVBQUUsQ0FBQztRQUM1QyxJQUFJLENBQUMsTUFBTSxDQUFDLEdBQUcsQ0FBQyxTQUFTLENBQUMsQ0FBQztJQUM3QixDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsSUFBSSxVQUFVO1FBQ1osT0FBTyxVQUFVLENBQUM7SUFDcEIsQ0FBQztJQUVEOzs7T0FHRztJQUNILElBQUksYUFBYTtRQUNmLE9BQU8sYUFBYSxDQUFDO0lBQ3ZCLENBQUM7SUFFRCxZQUFZLENBQUMsUUFBZ0I7UUFDM0IsTUFBTSxLQUFLLEdBQUcsQ0FBQyxHQUFHLFFBQVEsVUFBVSxDQUFDLENBQUM7UUFDdEMsSUFBSSxJQUFJLENBQUMsV0FBVztZQUFFLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxRQUFRLElBQUksSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDLENBQUM7UUFDcEUsSUFBSSxJQUFJLENBQUMsU0FBUyxLQUFLLFNBQVM7WUFBRSxPQUFPLEtBQUssQ0FBQztRQUMvQyxLQUFLLENBQUMsSUFBSSxDQUFDLEdBQUcsUUFBUSxJQUFJLElBQUksQ0FBQyxTQUFTLEVBQUUsQ0FBQyxDQUFDO1FBQzVDLElBQUksSUFBSSxDQUFDLFdBQVcsRUFBRSxDQUFDO1lBQ3JCLEtBQUssQ0FBQyxJQUFJLENBQUMsR0FBRyxRQUFRLElBQUksSUFBSSxDQUFDLFdBQVcsSUFBSSxJQUFJLENBQUMsU0FBUyxFQUFFLENBQUMsQ0FBQztRQUNsRSxDQUFDO1FBQ0QsT0FBTyxLQUFLLENBQUM7SUFDZixDQUFDO0lBRUQsYUFBYSxDQUFDLFFBQWdCO1FBQzVCLElBQUksUUFBNEIsQ0FBQztRQUNqQyxJQUFJLENBQUM7WUFDSCxRQUFRLEdBQUcsS0FBSyxDQUFDLFdBQVcsQ0FBQyxRQUFRLENBQUMsQ0FBQztRQUN6QyxDQUFDO1FBQUMsTUFBTSxDQUFDO1lBQ1AsNkVBQTZFO1lBQzdFLE9BQU8sU0FBUyxDQUFDO1FBQ25CLENBQUM7UUFDRCwyRUFBMkU7UUFDM0Usc0JBQXNCO1FBQ3RCLElBQUk7UUFDSixPQUFPLFFBQVEsQ0FBQztJQUNsQixDQUFDO0NBQ0Y7QUFFRCxTQUFTLGFBQWEsQ0FBQyxNQUEwQztJQUMvRCxJQUFJLE1BQU0sQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDLEtBQUssQ0FBQyxPQUFPLENBQUMsTUFBTSxDQUFDLFlBQVksQ0FBQyxJQUFJLE1BQU0sQ0FBQyxZQUFZLENBQUMsTUFBTSxHQUFHLENBQUMsQ0FBQyxFQUFFLENBQUM7UUFDMUYsTUFBTSxDQUFDLFlBQVksR0FBRyxNQUFNLENBQUMsR0FBRyxDQUFDO1FBQ2pDLE9BQU8sTUFBTSxDQUFDLEdBQUcsQ0FBQztJQUNwQixDQUFDO0FBQ0gsQ0FBQztBQUVELFNBQVMscUJBQXFCLENBQUMsSUFBWTtJQUN6Qyw2QkFBNkI7SUFDN0IsSUFBSSxJQUFJLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQztRQUFFLE9BQU8sS0FBSyxDQUFDO0lBQ3ZDLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxHQUFHLENBQUM7UUFBRSxPQUFPLEtBQUssQ0FBQztJQUN2QyxJQUFJLElBQUksQ0FBQyxRQUFRLENBQUMsR0FBRyxDQUFDO1FBQUUsT0FBTyxLQUFLLENBQUM7SUFDckMsT0FBTyxJQUFJLENBQUM7QUFDZCxDQUFDO0FBRUQscUNBQXFDO0FBQ3JDLFNBQVMsY0FBYyxDQUNyQixFQUFrQixFQUNsQixPQUFtRDtJQUVuRCx5QkFBeUI7SUFDekIsSUFBSSxPQUFPLENBQUMsTUFBTSxLQUFLLEtBQUssRUFBRSxDQUFDO1FBQzdCLE9BQU8sSUFBSSxDQUFDO0lBQ2QsQ0FBQztJQUVELDJDQUEyQztJQUMzQyxJQUFJLENBQUMsT0FBTyxDQUFDLEtBQUssSUFBSSxDQUFDLE9BQU8sQ0FBQyxNQUFNLEVBQUUsQ0FBQztRQUN0QyxPQUFPLEVBQUUsQ0FBQztJQUNaLENBQUM7SUFDRCxNQUFNLEtBQUssR0FBRyxZQUFZLENBQUMsT0FBTyxDQUFDLENBQUM7SUFFcEMsTUFBTSxFQUFFLEdBQW1CLENBQUMsR0FBRyxFQUFFLElBQUksRUFBRSxFQUFFO1FBQ3ZDLElBQUksQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDO1lBQUUsT0FBTyxJQUFJLEVBQUUsQ0FBQztRQUMvQixPQUFPLEVBQUUsQ0FBQyxHQUFHLEVBQUUsSUFBSSxDQUFDLENBQUM7SUFDdkIsQ0FBQyxDQUFDO0lBQ0YsRUFBRSxDQUFDLEtBQUssR0FBRyxHQUFHLEVBQUUsQ0FBQyxLQUFLLG1CQUFtQixDQUFDO0lBQzFDLE9BQU8sRUFBRSxDQUFDO0FBQ1osQ0FBQztBQUVELFNBQVMsc0JBQXNCLENBQUMsRUFBa0I7SUFDaEQsTUFBTSxFQUFFLEdBQW1CLEtBQUssRUFBRSxHQUFHLEVBQUUsSUFBSSxFQUFFLEVBQUU7UUFDN0MsTUFBTSxTQUFTLEdBQUcsR0FBRyxFQUFFLENBQUM7UUFDeEIsS0FBSyxDQUFDLHVEQUF1RCxFQUFFLEdBQUcsQ0FBQyxNQUFNLEVBQUUsR0FBRyxDQUFDLEdBQUcsRUFBRSxFQUFFLENBQUMsS0FBSyxDQUFDLENBQUM7UUFDOUYsTUFBTSxFQUFFLENBQUMsR0FBRyxFQUFFLElBQUksQ0FBQyxDQUFDO1FBQ3BCLE1BQU0sRUFBRSxHQUFHLElBQUksQ0FBQyxTQUFTLENBQUMsQ0FBQztRQUMzQixLQUFLLENBQUMsOERBQThELEVBQUUsR0FBRyxDQUFDLE1BQU0sRUFBRSxHQUFHLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxLQUFLLEVBQUUsRUFBRSxDQUFDLENBQUM7SUFDM0csQ0FBQyxDQUFDO0lBQ0YsRUFBRSxDQUFDLEtBQUssR0FBRyxHQUFHLEVBQUUsQ0FBQyxLQUFLLGNBQWMsQ0FBQztJQUNyQyxPQUFPLEVBQUUsQ0FBQztBQUNaLENBQUM7QUFFRCw2REFBNkQ7QUFDN0QsU0FBUyxtQkFBbUIsQ0FBQyxVQUFtQyxFQUFFLFFBQWdCO0lBQ2hGLElBQUksS0FBSyxHQUFHLFVBQVUsQ0FBQyxTQUFTLENBQUM7SUFDakMsTUFBTSxHQUFHLEdBQXdCLEVBQUUsQ0FBQztJQUNwQyw4QkFBOEI7SUFDOUIsT0FBTyxLQUFLLEtBQUssTUFBTSxDQUFDLFNBQVMsRUFBRSxDQUFDO1FBQ2xDLE1BQU0sSUFBSSxHQUFHLE1BQU0sQ0FBQyxtQkFBbUIsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUMvQyxLQUFLLE1BQU0sR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDO1lBQ3ZCLDhDQUE4QztZQUM5Qyx5QkFBeUI7WUFDekIsSUFBSSxHQUFHLEtBQUssYUFBYSxFQUFFLENBQUM7Z0JBQzFCLFNBQVM7WUFDWCxDQUFDO1lBQ0QsZ0RBQWdEO1lBQ2hELE1BQU0sQ0FBQyxHQUFHLE1BQU0sQ0FBQyx3QkFBd0IsQ0FBQyxLQUFLLEVBQUUsR0FBRyxDQUFDLENBQUM7WUFDdEQsaUNBQWlDO1lBQ2pDLElBQUksT0FBTyxDQUFDLEVBQUUsS0FBSyxLQUFLLFVBQVUsSUFBSSxDQUFDLE1BQU0sQ0FBQyxNQUFNLENBQUMsR0FBRyxFQUFFLEdBQUcsQ0FBQyxFQUFFLENBQUM7Z0JBQy9ELE1BQU0sb0JBQW9CLEdBQUcsR0FBRyxVQUFVLENBQUMsSUFBSSxJQUFJLEdBQUcsRUFBRSxDQUFDO2dCQUN6RCxJQUFJLG1CQUFtQixDQUFDLENBQUMsQ0FBQyxLQUFLLENBQUMsRUFBRSxDQUFDO29CQUNqQyxNQUFNLElBQUksU0FBUyxDQUNqQixvREFBb0Qsb0JBQW9CLGlCQUFpQixRQUFRLEVBQUUsQ0FDcEcsQ0FBQztnQkFDSixDQUFDO2dCQUNELEdBQUcsQ0FBQyxHQUFHLENBQUMsR0FBRyw0QkFBNEIsQ0FBQyxVQUFVLEVBQUUsR0FBRyxDQUFDLENBQUM7Z0JBQ3pELEdBQUcsQ0FBQyxHQUFHLENBQUMsQ0FBQyxRQUFRLENBQUMsR0FBRyxHQUFHLFFBQVEsSUFBSSxvQkFBb0IsSUFBSSxDQUFDO1lBQy9ELENBQUM7UUFDSCxDQUFDO1FBQ0QsS0FBSyxHQUFHLE1BQU0sQ0FBQyxjQUFjLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDdkMsQ0FBQztJQUNELE9BQU8sR0FBRyxDQUFDO0FBQ2IsQ0FBQztBQUVELFNBQVMsNEJBQTRCLENBQUMsVUFBbUMsRUFBRSxHQUFXO0lBQ3BGLE9BQU8sU0FBUyx5QkFBeUIsQ0FBZ0IsR0FBRyxJQUFlO1FBQ3pFLE1BQU0sVUFBVSxHQUFHLElBQUksVUFBVSxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQ3hDLElBQUksQ0FBQyxJQUFJLENBQUMsR0FBRyxDQUFDLE1BQU0sQ0FBQyxVQUFVLEVBQUUsYUFBYSxFQUFFLENBQUM7WUFDL0MsSUFBSSxHQUFHLENBQUMsSUFBSSxDQUFDLENBQUM7UUFDaEIsQ0FBQztRQUNELDhCQUE4QjtRQUM5QixPQUFPLFVBQVUsQ0FBQyxHQUFHLENBQUMsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDO0lBQ2xDLENBQUMsQ0FBQztBQUNKLENBQUM7QUFFRCwrRUFBK0U7QUFDL0UsU0FBUyxVQUFVLENBQUMsR0FBd0IsRUFBRSxRQUFnQixFQUFFLE1BQWU7SUFDN0UsTUFBTSxJQUFJLEdBQUcsTUFBTSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsQ0FBQztJQUM5QixNQUFNLEdBQUcsR0FBd0IsRUFBRSxDQUFDO0lBQ3BDLE1BQU0sR0FBRyxNQUFNLElBQUksRUFBRSxDQUFDO0lBQ3RCLEtBQUssTUFBTSxHQUFHLElBQUksSUFBSSxFQUFFLENBQUM7UUFDdkIsTUFBTSxvQkFBb0IsR0FBRyxHQUFHLE1BQU0sR0FBRyxHQUFHLEVBQUUsQ0FBQztRQUMvQyxNQUFNLElBQUksR0FBRyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUM7UUFDdEIsSUFBSSxtQkFBbUIsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQzlCLE1BQU0sSUFBSSxTQUFTLENBQ2pCLG9EQUFvRCxvQkFBb0IsaUJBQWlCLFFBQVEsRUFBRSxDQUNwRyxDQUFDO1FBQ0osQ0FBQztRQUNELElBQUksT0FBTyxJQUFJLEtBQUssVUFBVSxFQUFFLENBQUM7WUFDL0IsTUFBTSxLQUFLLEdBQUcsYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDO1lBQ2xDLElBQUksS0FBSyxDQUFDLENBQUMsQ0FBQyxLQUFLLE1BQU0sRUFBRSxDQUFDO2dCQUN4QixNQUFNLElBQUksS0FBSyxDQUFDLGdCQUFnQixvQkFBb0IsZ0RBQWdELFFBQVEsRUFBRSxDQUFDLENBQUM7WUFDbEgsQ0FBQztZQUNELEdBQUcsQ0FBQyxHQUFHLENBQUMsR0FBRywwQkFBMEIsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUM1QyxHQUFHLENBQUMsR0FBRyxDQUFDLENBQUMsUUFBUSxDQUFDLEdBQUcsR0FBRyxRQUFRLElBQUksb0JBQW9CLElBQUksQ0FBQztRQUMvRCxDQUFDO2FBQU0sSUFBSSxRQUFRLENBQUMsSUFBSSxDQUFDLEVBQUUsQ0FBQztZQUMxQixHQUFHLENBQUMsR0FBRyxDQUFDLEdBQUcsVUFBVSxDQUFDLElBQUksRUFBRSxRQUFRLEVBQUUsR0FBRyxvQkFBb0IsR0FBRyxDQUFDLENBQUM7UUFDcEUsQ0FBQztJQUNILENBQUM7SUFDRCxLQUFLLENBQUMsNkNBQTZDLEVBQUUsUUFBUSxFQUFFLE1BQU0sRUFBRSxHQUFHLENBQUMsQ0FBQztJQUM1RSxPQUFPLEdBQUcsQ0FBQztBQUNiLENBQUM7QUFFRCxTQUFTLDBCQUEwQixDQUFDLElBQVM7SUFDM0MsS0FBSyxVQUFVLDBCQUEwQixDQUFnQixHQUFHLElBQWU7UUFDekUsSUFBSSxDQUFDLElBQUksQ0FBQyxHQUFHLENBQUMsTUFBTSxDQUFDLFVBQVUsRUFBRSxhQUFhLEVBQUUsQ0FBQztZQUMvQyxJQUFJLEdBQUcsQ0FBQyxJQUFJLENBQUMsQ0FBQztRQUNoQixDQUFDO1FBQ0QsT0FBTyxNQUFNLElBQUksQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ3RDLENBQUM7SUFDRCxLQUFLLE1BQU0sR0FBRyxJQUFJLElBQUksRUFBRSxDQUFDO1FBQ3ZCLE9BQU8sQ0FBQyxHQUFHLENBQUMsMEJBQTBCLEVBQUUsR0FBRyxFQUFFLE9BQU8sQ0FBQyxHQUFHLENBQUMsSUFBSSxFQUFFLEdBQUcsQ0FBQyxDQUFDLENBQUM7SUFDdkUsQ0FBQztJQUNELE9BQU8sMEJBQTBCLENBQUM7QUFDcEMsQ0FBQyJ9