@ditojs/server 0.274.0 → 1.0.0-rc.1
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.
- package/package.json +25 -43
- package/src/app/Application.js +110 -112
- package/src/app/Validator.js +6 -3
- package/src/app/index.js +2 -2
- package/src/cli/db/createMigration.js +1 -1
- package/src/cli/db/index.js +7 -7
- package/src/cli/db/listAssetConfig.js +1 -1
- package/src/cli/db/reset.js +1 -1
- package/src/cli/index.js +14 -5
- package/src/controllers/AdminController.js +164 -158
- package/src/controllers/CollectionController.js +8 -29
- package/src/controllers/Controller.js +71 -76
- package/src/controllers/ControllerAction.js +39 -17
- package/src/controllers/MemberAction.js +2 -2
- package/src/controllers/ModelController.js +4 -4
- package/src/controllers/RelationController.js +3 -3
- package/src/controllers/{UserController.js → UsersController.js} +8 -13
- package/src/controllers/index.js +5 -5
- package/src/decorators/action.js +3 -3
- package/src/decorators/authorize.js +1 -1
- package/src/decorators/index.js +6 -6
- package/src/decorators/parameters.js +1 -1
- package/src/decorators/returns.js +1 -1
- package/src/decorators/scope.js +1 -1
- package/src/decorators/transacted.js +1 -1
- package/src/errors/AssetError.js +1 -1
- package/src/errors/AuthenticationError.js +1 -1
- package/src/errors/AuthorizationError.js +1 -1
- package/src/errors/ControllerError.js +1 -1
- package/src/errors/DatabaseError.js +12 -3
- package/src/errors/GraphError.js +1 -1
- package/src/errors/ModelError.js +1 -1
- package/src/errors/NotFoundError.js +1 -1
- package/src/errors/NotImplementedError.js +1 -1
- package/src/errors/QueryBuilderError.js +1 -1
- package/src/errors/RelationError.js +1 -1
- package/src/errors/ValidationError.js +1 -1
- package/src/errors/WrappedError.js +1 -1
- package/src/errors/index.js +14 -14
- package/src/graph/DitoGraphProcessor.js +2 -1
- package/src/graph/graph.js +1 -1
- package/src/graph/index.js +3 -3
- package/src/index.js +11 -9
- package/src/lib/index.js +2 -2
- package/src/middleware/createTransaction.js +1 -1
- package/src/middleware/findRoute.js +3 -2
- package/src/middleware/handleConnectMiddleware.js +88 -0
- package/src/middleware/handleError.js +1 -1
- package/src/middleware/handleRoute.js +3 -3
- package/src/middleware/index.js +8 -7
- package/src/mixins/AssetMixin.js +1 -1
- package/src/mixins/UserMixin.js +1 -1
- package/src/mixins/index.js +4 -4
- package/src/models/AssetModel.js +2 -2
- package/src/models/Model.js +16 -12
- package/src/models/RelationAccessor.js +1 -1
- package/src/models/SessionModel.js +2 -2
- package/src/models/TimeStampedModel.js +2 -2
- package/src/models/UserModel.js +2 -2
- package/src/models/definitions/assets.js +1 -1
- package/src/models/definitions/filters.js +57 -44
- package/src/models/definitions/hooks.js +1 -1
- package/src/models/definitions/index.js +9 -9
- package/src/models/definitions/modifiers.js +1 -1
- package/src/models/definitions/options.js +1 -1
- package/src/models/definitions/properties.js +2 -2
- package/src/models/definitions/relations.js +1 -1
- package/src/models/definitions/schema.js +1 -1
- package/src/models/definitions/scopes.js +2 -2
- package/src/models/index.js +5 -5
- package/src/query/QueryBuilder.js +5 -5
- package/src/query/QueryFilters.js +50 -50
- package/src/query/QueryParameters.js +2 -2
- package/src/query/index.js +3 -3
- package/src/schema/formats/index.js +2 -2
- package/src/schema/index.js +4 -4
- package/src/schema/keywords/_relate.js +1 -1
- package/src/schema/keywords/index.js +12 -12
- package/src/schema/properties.test.js +1 -1
- package/src/schema/relations.js +1 -1
- package/src/schema/relations.test.js +2 -2
- package/src/services/index.js +1 -1
- package/src/storage/DiskStorage.js +1 -1
- package/src/storage/S3Storage.js +4 -4
- package/src/storage/Storage.js +1 -1
- package/src/storage/index.js +4 -4
- package/src/utils/function.test.js +1 -1
- package/src/utils/handler.js +17 -0
- package/src/utils/index.js +8 -7
- package/src/utils/object.test.js +1 -1
- package/lib/app/Application.js +0 -961
- package/lib/app/SessionStore.js +0 -40
- package/lib/app/Validator.js +0 -355
- package/lib/app/index.js +0 -26
- package/lib/cli/console.js +0 -175
- package/lib/cli/db/createMigration.js +0 -237
- package/lib/cli/db/index.js +0 -66
- package/lib/cli/db/listAssetConfig.js +0 -16
- package/lib/cli/db/migrate.js +0 -15
- package/lib/cli/db/reset.js +0 -27
- package/lib/cli/db/rollback.js +0 -15
- package/lib/cli/db/seed.js +0 -104
- package/lib/cli/db/unlock.js +0 -15
- package/lib/cli/index.js +0 -90
- package/lib/controllers/AdminController.js +0 -258
- package/lib/controllers/CollectionController.js +0 -263
- package/lib/controllers/Controller.js +0 -462
- package/lib/controllers/ControllerAction.js +0 -276
- package/lib/controllers/MemberAction.js +0 -22
- package/lib/controllers/ModelController.js +0 -64
- package/lib/controllers/RelationController.js +0 -82
- package/lib/controllers/UserController.js +0 -98
- package/lib/controllers/index.js +0 -50
- package/lib/decorators/action.js +0 -14
- package/lib/decorators/authorize.js +0 -13
- package/lib/decorators/index.js +0 -58
- package/lib/decorators/parameters.js +0 -35
- package/lib/decorators/returns.js +0 -26
- package/lib/decorators/scope.js +0 -14
- package/lib/decorators/transacted.js +0 -12
- package/lib/errors/AssetError.js +0 -19
- package/lib/errors/AuthenticationError.js +0 -19
- package/lib/errors/AuthorizationError.js +0 -19
- package/lib/errors/ControllerError.js +0 -24
- package/lib/errors/DatabaseError.js +0 -27
- package/lib/errors/GraphError.js +0 -19
- package/lib/errors/ModelError.js +0 -24
- package/lib/errors/NotFoundError.js +0 -19
- package/lib/errors/NotImplementedError.js +0 -19
- package/lib/errors/QueryBuilderError.js +0 -19
- package/lib/errors/RelationError.js +0 -36
- package/lib/errors/ResponseError.js +0 -46
- package/lib/errors/ValidationError.js +0 -19
- package/lib/errors/WrappedError.js +0 -24
- package/lib/errors/index.js +0 -122
- package/lib/graph/DitoGraphProcessor.js +0 -185
- package/lib/graph/expression.js +0 -76
- package/lib/graph/graph.js +0 -300
- package/lib/graph/index.js +0 -34
- package/lib/index.js +0 -82
- package/lib/lib/EventEmitter.js +0 -76
- package/lib/lib/KnexHelper.js +0 -40
- package/lib/lib/index.js +0 -26
- package/lib/middleware/attachLogger.js +0 -16
- package/lib/middleware/createTransaction.js +0 -36
- package/lib/middleware/findRoute.js +0 -35
- package/lib/middleware/handleError.js +0 -26
- package/lib/middleware/handleRoute.js +0 -29
- package/lib/middleware/handleUser.js +0 -36
- package/lib/middleware/index.js +0 -66
- package/lib/middleware/logRequests.js +0 -122
- package/lib/mixins/AssetMixin.js +0 -81
- package/lib/mixins/SessionMixin.js +0 -22
- package/lib/mixins/TimeStampedMixin.js +0 -47
- package/lib/mixins/UserMixin.js +0 -151
- package/lib/mixins/index.js +0 -42
- package/lib/models/AssetModel.js +0 -12
- package/lib/models/Model.js +0 -953
- package/lib/models/RelationAccessor.js +0 -41
- package/lib/models/SessionModel.js +0 -12
- package/lib/models/TimeStampedModel.js +0 -12
- package/lib/models/UserModel.js +0 -12
- package/lib/models/definitions/assets.js +0 -11
- package/lib/models/definitions/filters.js +0 -101
- package/lib/models/definitions/hooks.js +0 -11
- package/lib/models/definitions/index.js +0 -38
- package/lib/models/definitions/modifiers.js +0 -11
- package/lib/models/definitions/options.js +0 -11
- package/lib/models/definitions/properties.js +0 -87
- package/lib/models/definitions/relations.js +0 -11
- package/lib/models/definitions/schema.js +0 -11
- package/lib/models/definitions/scopes.js +0 -51
- package/lib/models/index.js +0 -50
- package/lib/query/QueryBuilder.js +0 -745
- package/lib/query/QueryFilters.js +0 -82
- package/lib/query/QueryParameters.js +0 -77
- package/lib/query/Registry.js +0 -40
- package/lib/query/index.js +0 -34
- package/lib/schema/formats/_empty.js +0 -10
- package/lib/schema/formats/_required.js +0 -10
- package/lib/schema/formats/index.js +0 -26
- package/lib/schema/index.js +0 -49
- package/lib/schema/keywords/_computed.js +0 -11
- package/lib/schema/keywords/_foreign.js +0 -11
- package/lib/schema/keywords/_hidden.js +0 -11
- package/lib/schema/keywords/_index.js +0 -11
- package/lib/schema/keywords/_instanceof.js +0 -49
- package/lib/schema/keywords/_primary.js +0 -11
- package/lib/schema/keywords/_range.js +0 -26
- package/lib/schema/keywords/_relate.js +0 -19
- package/lib/schema/keywords/_specificType.js +0 -11
- package/lib/schema/keywords/_unique.js +0 -11
- package/lib/schema/keywords/_unsigned.js +0 -11
- package/lib/schema/keywords/_validate.js +0 -80
- package/lib/schema/keywords/index.js +0 -106
- package/lib/schema/properties.js +0 -227
- package/lib/schema/properties.test.js +0 -573
- package/lib/schema/relations.js +0 -274
- package/lib/schema/relations.test.js +0 -155
- package/lib/services/Service.js +0 -34
- package/lib/services/index.js +0 -18
- package/lib/storage/AssetFile.js +0 -97
- package/lib/storage/DiskStorage.js +0 -125
- package/lib/storage/S3Storage.js +0 -171
- package/lib/storage/Storage.js +0 -209
- package/lib/storage/index.js +0 -34
- package/lib/utils/decorator.js +0 -16
- package/lib/utils/deprecate.js +0 -46
- package/lib/utils/emitter.js +0 -13
- package/lib/utils/function.js +0 -14
- package/lib/utils/function.test.js +0 -49
- package/lib/utils/index.js +0 -66
- package/lib/utils/json.js +0 -9
- package/lib/utils/object.js +0 -92
- package/lib/utils/object.test.js +0 -65
- package/lib/utils/scope.js +0 -14
package/lib/app/Application.js
DELETED
|
@@ -1,961 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
exports.__esModule = true;
|
|
4
|
-
exports.Application = void 0;
|
|
5
|
-
|
|
6
|
-
require("core-js/modules/esnext.async-iterator.filter.js");
|
|
7
|
-
|
|
8
|
-
require("core-js/modules/esnext.iterator.constructor.js");
|
|
9
|
-
|
|
10
|
-
require("core-js/modules/esnext.iterator.filter.js");
|
|
11
|
-
|
|
12
|
-
require("core-js/modules/es.error.cause.js");
|
|
13
|
-
|
|
14
|
-
require("core-js/modules/esnext.async-iterator.reduce.js");
|
|
15
|
-
|
|
16
|
-
require("core-js/modules/esnext.iterator.reduce.js");
|
|
17
|
-
|
|
18
|
-
require("core-js/modules/esnext.async-iterator.find.js");
|
|
19
|
-
|
|
20
|
-
require("core-js/modules/esnext.iterator.find.js");
|
|
21
|
-
|
|
22
|
-
require("core-js/modules/esnext.async-iterator.map.js");
|
|
23
|
-
|
|
24
|
-
require("core-js/modules/esnext.iterator.map.js");
|
|
25
|
-
|
|
26
|
-
var _koa = _interopRequireDefault(require("koa"));
|
|
27
|
-
|
|
28
|
-
var _knex2 = _interopRequireDefault(require("knex"));
|
|
29
|
-
|
|
30
|
-
var _util = _interopRequireDefault(require("util"));
|
|
31
|
-
|
|
32
|
-
var _axios = _interopRequireDefault(require("axios"));
|
|
33
|
-
|
|
34
|
-
var _picocolors = _interopRequireDefault(require("picocolors"));
|
|
35
|
-
|
|
36
|
-
var _zlib = _interopRequireDefault(require("zlib"));
|
|
37
|
-
|
|
38
|
-
var _pino = _interopRequireDefault(require("pino"));
|
|
39
|
-
|
|
40
|
-
var _os = _interopRequireDefault(require("os"));
|
|
41
|
-
|
|
42
|
-
var _parseDuration = _interopRequireDefault(require("parse-duration"));
|
|
43
|
-
|
|
44
|
-
var _koaBodyparser = _interopRequireDefault(require("koa-bodyparser"));
|
|
45
|
-
|
|
46
|
-
var _cors = _interopRequireDefault(require("@koa/cors"));
|
|
47
|
-
|
|
48
|
-
var _koaCompose = _interopRequireDefault(require("koa-compose"));
|
|
49
|
-
|
|
50
|
-
var _koaCompress = _interopRequireDefault(require("koa-compress"));
|
|
51
|
-
|
|
52
|
-
var _koaConditionalGet = _interopRequireDefault(require("koa-conditional-get"));
|
|
53
|
-
|
|
54
|
-
var _koaPassport = _interopRequireDefault(require("koa-passport"));
|
|
55
|
-
|
|
56
|
-
var _koaSession = _interopRequireDefault(require("koa-session"));
|
|
57
|
-
|
|
58
|
-
var _koaEtag = _interopRequireDefault(require("koa-etag"));
|
|
59
|
-
|
|
60
|
-
var _koaHelmet = _interopRequireDefault(require("koa-helmet"));
|
|
61
|
-
|
|
62
|
-
var _koaResponseTime = _interopRequireDefault(require("koa-response-time"));
|
|
63
|
-
|
|
64
|
-
var _router = _interopRequireDefault(require("@ditojs/router"));
|
|
65
|
-
|
|
66
|
-
var _lib = require("../lib");
|
|
67
|
-
|
|
68
|
-
var _controllers = require("../controllers");
|
|
69
|
-
|
|
70
|
-
var _services = require("../services");
|
|
71
|
-
|
|
72
|
-
var _storage = require("../storage");
|
|
73
|
-
|
|
74
|
-
var _schema = require("../schema");
|
|
75
|
-
|
|
76
|
-
var _utils = require("../utils");
|
|
77
|
-
|
|
78
|
-
var _errors = require("../errors");
|
|
79
|
-
|
|
80
|
-
var _SessionStore = _interopRequireDefault(require("./SessionStore"));
|
|
81
|
-
|
|
82
|
-
var _Validator = require("./Validator");
|
|
83
|
-
|
|
84
|
-
var _middleware = require("../middleware");
|
|
85
|
-
|
|
86
|
-
var _utils2 = require("@ditojs/utils");
|
|
87
|
-
|
|
88
|
-
var _objection = require("objection");
|
|
89
|
-
|
|
90
|
-
function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; }
|
|
91
|
-
|
|
92
|
-
class Application extends _koa.default {
|
|
93
|
-
constructor({
|
|
94
|
-
config = {},
|
|
95
|
-
validator,
|
|
96
|
-
router,
|
|
97
|
-
events,
|
|
98
|
-
middleware,
|
|
99
|
-
models,
|
|
100
|
-
services,
|
|
101
|
-
controllers
|
|
102
|
-
} = {}) {
|
|
103
|
-
super();
|
|
104
|
-
|
|
105
|
-
this._setupEmitter(events);
|
|
106
|
-
|
|
107
|
-
const {
|
|
108
|
-
app: {
|
|
109
|
-
keys,
|
|
110
|
-
...app
|
|
111
|
-
} = {},
|
|
112
|
-
log = {},
|
|
113
|
-
...rest
|
|
114
|
-
} = config;
|
|
115
|
-
this.config = {
|
|
116
|
-
app,
|
|
117
|
-
log: log.silent || process.env.DITO_SILENT ? {} : log,
|
|
118
|
-
...rest
|
|
119
|
-
};
|
|
120
|
-
this.keys = keys;
|
|
121
|
-
this.proxy = !!app.proxy;
|
|
122
|
-
this.validator = validator || new _Validator.Validator();
|
|
123
|
-
this.router = router || new _router.default();
|
|
124
|
-
this.validator.app = this;
|
|
125
|
-
this.storages = Object.create(null);
|
|
126
|
-
this.models = Object.create(null);
|
|
127
|
-
this.services = Object.create(null);
|
|
128
|
-
this.controllers = Object.create(null);
|
|
129
|
-
this.hasControllerMiddleware = false;
|
|
130
|
-
this.setupLogger();
|
|
131
|
-
this.setupKnex();
|
|
132
|
-
this.setupGlobalMiddleware();
|
|
133
|
-
|
|
134
|
-
if (middleware) {
|
|
135
|
-
this.use(middleware);
|
|
136
|
-
}
|
|
137
|
-
|
|
138
|
-
if (config.storages) {
|
|
139
|
-
this.addStorages(config.storages);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
if (models) {
|
|
143
|
-
this.addModels(models);
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
if (services) {
|
|
147
|
-
this.addServices(services);
|
|
148
|
-
}
|
|
149
|
-
|
|
150
|
-
if (controllers) {
|
|
151
|
-
this.addControllers(controllers);
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
addRoute(verb, path, transacted, handlers, controller = null, action = null) {
|
|
156
|
-
handlers = (0, _utils2.asArray)(handlers);
|
|
157
|
-
const handler = handlers.length > 1 ? (0, _koaCompose.default)(handlers) : handlers[0];
|
|
158
|
-
const route = {
|
|
159
|
-
verb,
|
|
160
|
-
path,
|
|
161
|
-
transacted,
|
|
162
|
-
handler,
|
|
163
|
-
controller,
|
|
164
|
-
action
|
|
165
|
-
};
|
|
166
|
-
this.router[verb](path, route);
|
|
167
|
-
}
|
|
168
|
-
|
|
169
|
-
addModels(models) {
|
|
170
|
-
for (const modelClass of Object.values(models)) {
|
|
171
|
-
this.addModel(modelClass);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
|
-
this.models = this.sortModels(this.models);
|
|
175
|
-
const sortedModels = Object.values(this.models).filter(modelClass => models[modelClass.name] === modelClass);
|
|
176
|
-
|
|
177
|
-
for (const modelClass of sortedModels) {
|
|
178
|
-
if (models[modelClass.name] === modelClass) {
|
|
179
|
-
modelClass.setup(this.knex);
|
|
180
|
-
modelClass.initialize();
|
|
181
|
-
this.validator.addSchema(modelClass.getJsonSchema());
|
|
182
|
-
}
|
|
183
|
-
}
|
|
184
|
-
|
|
185
|
-
const {
|
|
186
|
-
log
|
|
187
|
-
} = this.config;
|
|
188
|
-
|
|
189
|
-
if (log.schema || log.relations) {
|
|
190
|
-
for (const modelClass of sortedModels) {
|
|
191
|
-
const shouldLog = option => option === true || (0, _utils2.asArray)(option).includes(modelClass.name);
|
|
192
|
-
|
|
193
|
-
const data = {};
|
|
194
|
-
|
|
195
|
-
if (shouldLog(log.schema)) {
|
|
196
|
-
data.schema = modelClass.getJsonSchema();
|
|
197
|
-
}
|
|
198
|
-
|
|
199
|
-
if (shouldLog(log.relations)) {
|
|
200
|
-
data.relations = (0, _utils2.clone)(modelClass.relationMappings, value => _objection.Model.isPrototypeOf(value) ? `[Model: ${value.name}]` : value);
|
|
201
|
-
}
|
|
202
|
-
|
|
203
|
-
if (Object.keys(data).length > 0) {
|
|
204
|
-
console.info(_picocolors.default.yellow.bold(`\n${modelClass.name}:\n`), _util.default.inspect(data, {
|
|
205
|
-
colors: true,
|
|
206
|
-
depth: null,
|
|
207
|
-
maxArrayLength: null
|
|
208
|
-
}));
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
}
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
addModel(modelClass) {
|
|
215
|
-
if (_objection.Model.isPrototypeOf(modelClass)) {
|
|
216
|
-
modelClass.app = this;
|
|
217
|
-
this.models[modelClass.name] = modelClass;
|
|
218
|
-
} else {
|
|
219
|
-
throw new Error(`Invalid model class: ${modelClass}`);
|
|
220
|
-
}
|
|
221
|
-
}
|
|
222
|
-
|
|
223
|
-
sortModels(models) {
|
|
224
|
-
const sortByRelations = (list, collected = {}, excluded = {}) => {
|
|
225
|
-
for (const modelClass of list) {
|
|
226
|
-
const {
|
|
227
|
-
name
|
|
228
|
-
} = modelClass;
|
|
229
|
-
|
|
230
|
-
if (!collected[name] && !excluded[name]) {
|
|
231
|
-
for (const relation of Object.values(modelClass.getRelations())) {
|
|
232
|
-
if (!(relation instanceof _objection.BelongsToOneRelation)) {
|
|
233
|
-
const {
|
|
234
|
-
relatedModelClass,
|
|
235
|
-
joinTableModelClass
|
|
236
|
-
} = relation;
|
|
237
|
-
|
|
238
|
-
for (const related of [joinTableModelClass, relatedModelClass]) {
|
|
239
|
-
if (related && related !== modelClass && models[related.name]) {
|
|
240
|
-
sortByRelations([related], collected, {
|
|
241
|
-
[name]: modelClass,
|
|
242
|
-
...excluded
|
|
243
|
-
});
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
}
|
|
248
|
-
|
|
249
|
-
collected[name] = modelClass;
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
return Object.values(collected);
|
|
254
|
-
};
|
|
255
|
-
|
|
256
|
-
return sortByRelations(Object.values(models).reverse()).reverse().reduce((models, modelClass) => {
|
|
257
|
-
models[modelClass.name] = modelClass;
|
|
258
|
-
return models;
|
|
259
|
-
}, Object.create(null));
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
getModel(name) {
|
|
263
|
-
return this.models[name] || !name.endsWith('Model') && this.models[`${name}Model`] || null;
|
|
264
|
-
}
|
|
265
|
-
|
|
266
|
-
findModel(callback) {
|
|
267
|
-
return Object.values(this.models).find(callback);
|
|
268
|
-
}
|
|
269
|
-
|
|
270
|
-
addServices(services) {
|
|
271
|
-
for (const [name, service] of Object.entries(services)) {
|
|
272
|
-
if (name === 'default' && (0, _utils2.isPlainObject)(service)) {
|
|
273
|
-
this.addServices(service);
|
|
274
|
-
} else {
|
|
275
|
-
this.addService(service, name);
|
|
276
|
-
}
|
|
277
|
-
}
|
|
278
|
-
}
|
|
279
|
-
|
|
280
|
-
addService(service, name) {
|
|
281
|
-
if (_services.Service.isPrototypeOf(service)) {
|
|
282
|
-
service = new service(this, name);
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
if (!(service instanceof _services.Service)) {
|
|
286
|
-
throw new Error(`Invalid service: ${service}`);
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
({
|
|
290
|
-
name
|
|
291
|
-
} = service);
|
|
292
|
-
const config = this.config.services[name];
|
|
293
|
-
|
|
294
|
-
if (config === undefined) {
|
|
295
|
-
throw new Error(`Configuration missing for service '${name}'`);
|
|
296
|
-
}
|
|
297
|
-
|
|
298
|
-
if (config !== false) {
|
|
299
|
-
service.setup(config);
|
|
300
|
-
this.services[name] = service;
|
|
301
|
-
service.initialize();
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
|
|
305
|
-
getService(name) {
|
|
306
|
-
return this.services[name] || null;
|
|
307
|
-
}
|
|
308
|
-
|
|
309
|
-
findService(callback) {
|
|
310
|
-
return Object.values(this.services).find(callback);
|
|
311
|
-
}
|
|
312
|
-
|
|
313
|
-
forEachService(callback) {
|
|
314
|
-
return Promise.all(Object.values(this.services).map(callback));
|
|
315
|
-
}
|
|
316
|
-
|
|
317
|
-
addControllers(controllers, namespace) {
|
|
318
|
-
for (const [key, value] of Object.entries(controllers)) {
|
|
319
|
-
if ((0, _utils2.isPlainObject)(value)) {
|
|
320
|
-
this.addControllers(value, namespace ? `${namespace}/${key}` : key);
|
|
321
|
-
} else {
|
|
322
|
-
this.addController(value, namespace);
|
|
323
|
-
}
|
|
324
|
-
}
|
|
325
|
-
}
|
|
326
|
-
|
|
327
|
-
addController(controller, namespace) {
|
|
328
|
-
this.setupControllerMiddleware();
|
|
329
|
-
|
|
330
|
-
if (_controllers.Controller.isPrototypeOf(controller)) {
|
|
331
|
-
controller = new controller(this, namespace);
|
|
332
|
-
}
|
|
333
|
-
|
|
334
|
-
if (!(controller instanceof _controllers.Controller)) {
|
|
335
|
-
throw new Error(`Invalid controller: ${controller}`);
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
controller.setup();
|
|
339
|
-
this.controllers[controller.url] = controller;
|
|
340
|
-
controller.initialize();
|
|
341
|
-
const middleware = controller.compose();
|
|
342
|
-
|
|
343
|
-
if (middleware) {
|
|
344
|
-
this.use(middleware);
|
|
345
|
-
}
|
|
346
|
-
}
|
|
347
|
-
|
|
348
|
-
getController(url) {
|
|
349
|
-
return this.controllers[url] || null;
|
|
350
|
-
}
|
|
351
|
-
|
|
352
|
-
findController(callback) {
|
|
353
|
-
return Object.values(this.controllers).find(callback);
|
|
354
|
-
}
|
|
355
|
-
|
|
356
|
-
getAdminController() {
|
|
357
|
-
return this.findController(controller => controller instanceof _controllers.AdminController);
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
getAdminVueConfig() {
|
|
361
|
-
var _this$getAdminControl;
|
|
362
|
-
|
|
363
|
-
return ((_this$getAdminControl = this.getAdminController()) == null ? void 0 : _this$getAdminControl.getVueConfig()) || null;
|
|
364
|
-
}
|
|
365
|
-
|
|
366
|
-
getAssetConfig({
|
|
367
|
-
models = Object.keys(this.models),
|
|
368
|
-
normalizeDbNames = this.config.knex.normalizeDbNames
|
|
369
|
-
} = {}) {
|
|
370
|
-
const assetConfig = {};
|
|
371
|
-
|
|
372
|
-
for (const modelName of models) {
|
|
373
|
-
const modelClass = this.models[modelName];
|
|
374
|
-
const {
|
|
375
|
-
assets
|
|
376
|
-
} = modelClass.definition;
|
|
377
|
-
|
|
378
|
-
if (assets) {
|
|
379
|
-
const normalizedModelName = normalizeDbNames ? this.normalizeIdentifier(modelName) : modelName;
|
|
380
|
-
const convertedAssets = {};
|
|
381
|
-
|
|
382
|
-
for (const [assetDataPath, config] of Object.entries(assets)) {
|
|
383
|
-
const {
|
|
384
|
-
property,
|
|
385
|
-
nestedDataPath,
|
|
386
|
-
name,
|
|
387
|
-
index
|
|
388
|
-
} = modelClass.getPropertyOrRelationAtDataPath(assetDataPath);
|
|
389
|
-
|
|
390
|
-
if (property && index === 0) {
|
|
391
|
-
const normalizedName = normalizeDbNames ? this.normalizeIdentifier(name) : name;
|
|
392
|
-
const dataPath = (0, _utils2.normalizeDataPath)([normalizedName, ...(0, _utils2.parseDataPath)(nestedDataPath)]);
|
|
393
|
-
const assetConfigs = convertedAssets[normalizedName] || (convertedAssets[normalizedName] = {});
|
|
394
|
-
assetConfigs[dataPath] = config;
|
|
395
|
-
} else {
|
|
396
|
-
throw new Error('Nested graph properties are not supported yet');
|
|
397
|
-
}
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
assetConfig[normalizedModelName] = convertedAssets;
|
|
401
|
-
}
|
|
402
|
-
}
|
|
403
|
-
|
|
404
|
-
return assetConfig;
|
|
405
|
-
}
|
|
406
|
-
|
|
407
|
-
addStorages(storages) {
|
|
408
|
-
for (const [name, config] of Object.entries(storages)) {
|
|
409
|
-
this.addStorage(config, name);
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
addStorage(config, name) {
|
|
414
|
-
let storage = null;
|
|
415
|
-
|
|
416
|
-
if ((0, _utils2.isPlainObject)(config)) {
|
|
417
|
-
const storageClass = _storage.Storage.get(config.type);
|
|
418
|
-
|
|
419
|
-
if (!storageClass) {
|
|
420
|
-
throw new Error(`Unsupported storage: ${config}`);
|
|
421
|
-
}
|
|
422
|
-
|
|
423
|
-
storage = new storageClass(this, config);
|
|
424
|
-
} else if (config instanceof _storage.Storage) {
|
|
425
|
-
storage = config;
|
|
426
|
-
}
|
|
427
|
-
|
|
428
|
-
if (storage) {
|
|
429
|
-
if (name) {
|
|
430
|
-
storage.name = name;
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
this.storages[storage.name] = storage;
|
|
434
|
-
}
|
|
435
|
-
|
|
436
|
-
return storage;
|
|
437
|
-
}
|
|
438
|
-
|
|
439
|
-
getStorage(name) {
|
|
440
|
-
return this.storages[name] || null;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
compileValidator(jsonSchema, options) {
|
|
444
|
-
return jsonSchema ? this.validator.compile(jsonSchema, options) : null;
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
compileParametersValidator(parameters, options = {}) {
|
|
448
|
-
const list = [];
|
|
449
|
-
const {
|
|
450
|
-
dataName = 'data'
|
|
451
|
-
} = options;
|
|
452
|
-
let properties = null;
|
|
453
|
-
|
|
454
|
-
const addParameter = (name, schema) => {
|
|
455
|
-
list.push({
|
|
456
|
-
name: name != null ? name : null,
|
|
457
|
-
...schema
|
|
458
|
-
});
|
|
459
|
-
|
|
460
|
-
if (!schema.member) {
|
|
461
|
-
properties || (properties = {});
|
|
462
|
-
properties[name || dataName] = schema;
|
|
463
|
-
}
|
|
464
|
-
};
|
|
465
|
-
|
|
466
|
-
let asObject = false;
|
|
467
|
-
|
|
468
|
-
if ((0, _utils2.isArray)(parameters)) {
|
|
469
|
-
for (const {
|
|
470
|
-
name,
|
|
471
|
-
...schema
|
|
472
|
-
} of parameters) {
|
|
473
|
-
addParameter(name, schema);
|
|
474
|
-
}
|
|
475
|
-
} else if ((0, _utils2.isObject)(parameters)) {
|
|
476
|
-
asObject = true;
|
|
477
|
-
|
|
478
|
-
for (const [name, schema] of Object.entries(parameters)) {
|
|
479
|
-
if (schema) {
|
|
480
|
-
addParameter(name, schema);
|
|
481
|
-
}
|
|
482
|
-
}
|
|
483
|
-
} else if (parameters) {
|
|
484
|
-
throw new Error(`Invalid parameters definition: ${parameters}`);
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
const schema = (0, _schema.convertSchema)(properties, options);
|
|
488
|
-
const validate = this.compileValidator(schema, {
|
|
489
|
-
coerceTypes: 'array',
|
|
490
|
-
...options
|
|
491
|
-
});
|
|
492
|
-
const ctx = {
|
|
493
|
-
app: this,
|
|
494
|
-
validator: this.validator,
|
|
495
|
-
options
|
|
496
|
-
};
|
|
497
|
-
return {
|
|
498
|
-
list,
|
|
499
|
-
schema,
|
|
500
|
-
asObject,
|
|
501
|
-
dataName,
|
|
502
|
-
validate: validate ? data => validate.call(ctx, data) : null
|
|
503
|
-
};
|
|
504
|
-
}
|
|
505
|
-
|
|
506
|
-
createValidationError({
|
|
507
|
-
type,
|
|
508
|
-
message,
|
|
509
|
-
errors,
|
|
510
|
-
options,
|
|
511
|
-
json
|
|
512
|
-
}) {
|
|
513
|
-
var _this$config$log$erro;
|
|
514
|
-
|
|
515
|
-
return new _errors.ValidationError({
|
|
516
|
-
type,
|
|
517
|
-
message,
|
|
518
|
-
errors: this.validator.parseErrors(errors, options),
|
|
519
|
-
json: (_this$config$log$erro = this.config.log.errors) != null && _this$config$log$erro.json ? json : undefined
|
|
520
|
-
});
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
createDatabaseError(error) {
|
|
524
|
-
var _this$config$log$erro2;
|
|
525
|
-
|
|
526
|
-
const [, sql, message] = error.message.match(/^([\s\S]*) - ([\s\S]*?)$/) || [null, null, error.message];
|
|
527
|
-
return new _errors.DatabaseError(error, {
|
|
528
|
-
message,
|
|
529
|
-
sql: (_this$config$log$erro2 = this.config.log.errors) != null && _this$config$log$erro2.sql ? sql : undefined
|
|
530
|
-
});
|
|
531
|
-
}
|
|
532
|
-
|
|
533
|
-
setupGlobalMiddleware() {
|
|
534
|
-
const {
|
|
535
|
-
app,
|
|
536
|
-
log
|
|
537
|
-
} = this.config;
|
|
538
|
-
this.use((0, _middleware.attachLogger)(this.logger));
|
|
539
|
-
|
|
540
|
-
if (app.responseTime !== false) {
|
|
541
|
-
this.use((0, _koaResponseTime.default)(getOptions(app.responseTime)));
|
|
542
|
-
}
|
|
543
|
-
|
|
544
|
-
if (log.requests) {
|
|
545
|
-
this.use((0, _middleware.logRequests)());
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
this.use((0, _middleware.handleError)());
|
|
549
|
-
|
|
550
|
-
if (app.helmet !== false) {
|
|
551
|
-
this.use((0, _koaHelmet.default)(getOptions(app.helmet)));
|
|
552
|
-
}
|
|
553
|
-
|
|
554
|
-
if (app.cors !== false) {
|
|
555
|
-
this.use((0, _cors.default)(getOptions(app.cors)));
|
|
556
|
-
}
|
|
557
|
-
|
|
558
|
-
if (app.compress !== false) {
|
|
559
|
-
this.use((0, _koaCompress.default)((0, _utils2.merge)({
|
|
560
|
-
br: {
|
|
561
|
-
params: {
|
|
562
|
-
[_zlib.default.constants.BROTLI_PARAM_QUALITY]: 4
|
|
563
|
-
}
|
|
564
|
-
}
|
|
565
|
-
}, getOptions(app.compress))));
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
if (app.etag !== false) {
|
|
569
|
-
this.use((0, _koaConditionalGet.default)());
|
|
570
|
-
this.use((0, _koaEtag.default)());
|
|
571
|
-
}
|
|
572
|
-
}
|
|
573
|
-
|
|
574
|
-
setupControllerMiddleware() {
|
|
575
|
-
if (!this.hasControllerMiddleware) {
|
|
576
|
-
const {
|
|
577
|
-
app
|
|
578
|
-
} = this.config;
|
|
579
|
-
this.use((0, _koaBodyparser.default)(getOptions(app.bodyParser)));
|
|
580
|
-
this.use((0, _middleware.findRoute)(this.router));
|
|
581
|
-
this.use((0, _middleware.createTransaction)());
|
|
582
|
-
|
|
583
|
-
if (app.session) {
|
|
584
|
-
const {
|
|
585
|
-
modelClass,
|
|
586
|
-
...options
|
|
587
|
-
} = getOptions(app.session);
|
|
588
|
-
|
|
589
|
-
if (modelClass) {
|
|
590
|
-
options.ContextStore = (0, _SessionStore.default)(modelClass);
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
this.use((0, _koaSession.default)(options, this));
|
|
594
|
-
}
|
|
595
|
-
|
|
596
|
-
if (app.passport) {
|
|
597
|
-
this.use(_koaPassport.default.initialize());
|
|
598
|
-
|
|
599
|
-
if (app.session) {
|
|
600
|
-
this.use(_koaPassport.default.session());
|
|
601
|
-
}
|
|
602
|
-
|
|
603
|
-
this.use((0, _middleware.handleUser)());
|
|
604
|
-
}
|
|
605
|
-
|
|
606
|
-
this.use((0, _middleware.handleRoute)());
|
|
607
|
-
this.hasControllerMiddleware = true;
|
|
608
|
-
}
|
|
609
|
-
}
|
|
610
|
-
|
|
611
|
-
setupLogger() {
|
|
612
|
-
const {
|
|
613
|
-
err,
|
|
614
|
-
req,
|
|
615
|
-
res
|
|
616
|
-
} = _pino.default.stdSerializers;
|
|
617
|
-
|
|
618
|
-
const user = user => ({
|
|
619
|
-
id: user.id
|
|
620
|
-
});
|
|
621
|
-
|
|
622
|
-
const serializers = {
|
|
623
|
-
err,
|
|
624
|
-
req,
|
|
625
|
-
res,
|
|
626
|
-
user
|
|
627
|
-
};
|
|
628
|
-
const logger = (0, _pino.default)((0, _utils2.merge)({
|
|
629
|
-
level: 'info',
|
|
630
|
-
serializers,
|
|
631
|
-
prettyPrint: {
|
|
632
|
-
ignore: 'req,res,durationMs,user,requestId',
|
|
633
|
-
translateTime: 'SYS:HH:MM:ss.l'
|
|
634
|
-
},
|
|
635
|
-
redact: ['*.headers["cookie"]', '*.headers["set-cookie"]', '*.headers["authorization"]'],
|
|
636
|
-
base: null
|
|
637
|
-
}, getOptions(this.config.logger)));
|
|
638
|
-
this.logger = logger.child({
|
|
639
|
-
name: 'app'
|
|
640
|
-
});
|
|
641
|
-
}
|
|
642
|
-
|
|
643
|
-
setupKnex() {
|
|
644
|
-
var _knex;
|
|
645
|
-
|
|
646
|
-
let {
|
|
647
|
-
knex,
|
|
648
|
-
log
|
|
649
|
-
} = this.config;
|
|
650
|
-
|
|
651
|
-
if ((_knex = knex) != null && _knex.client) {
|
|
652
|
-
const snakeCaseOptions = knex.normalizeDbNames === true ? {} : knex.normalizeDbNames;
|
|
653
|
-
|
|
654
|
-
if (snakeCaseOptions) {
|
|
655
|
-
knex = { ...knex,
|
|
656
|
-
...(0, _objection.knexSnakeCaseMappers)(snakeCaseOptions)
|
|
657
|
-
};
|
|
658
|
-
}
|
|
659
|
-
|
|
660
|
-
this.knex = (0, _knex2.default)(knex);
|
|
661
|
-
|
|
662
|
-
if (knex.client === 'postgresql' && knex.typeParsers) {
|
|
663
|
-
for (const [type, parser] of Object.entries(knex.typeParsers)) {
|
|
664
|
-
this.knex.client.driver.types.setTypeParser(type, parser);
|
|
665
|
-
}
|
|
666
|
-
}
|
|
667
|
-
|
|
668
|
-
if (log.sql) {
|
|
669
|
-
this.setupKnexLogging();
|
|
670
|
-
}
|
|
671
|
-
}
|
|
672
|
-
}
|
|
673
|
-
|
|
674
|
-
setupKnexLogging() {
|
|
675
|
-
const startTimes = {};
|
|
676
|
-
const logger = this.logger.child({
|
|
677
|
-
name: 'sql'
|
|
678
|
-
});
|
|
679
|
-
|
|
680
|
-
function end(query, {
|
|
681
|
-
response,
|
|
682
|
-
error
|
|
683
|
-
}) {
|
|
684
|
-
const id = query.__knexQueryUid;
|
|
685
|
-
const diff = process.hrtime(startTimes[id]);
|
|
686
|
-
const duration = diff[0] * 1e3 + diff[1] / 1e6;
|
|
687
|
-
delete startTimes[id];
|
|
688
|
-
const {
|
|
689
|
-
sql,
|
|
690
|
-
bindings
|
|
691
|
-
} = query;
|
|
692
|
-
response = Object.fromEntries(Object.entries(response).filter(([key]) => !key.startsWith('_')));
|
|
693
|
-
logger.info({
|
|
694
|
-
duration,
|
|
695
|
-
bindings,
|
|
696
|
-
response,
|
|
697
|
-
error
|
|
698
|
-
}, sql);
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
this.knex.on('query', query => {
|
|
702
|
-
startTimes[query.__knexQueryUid] = process.hrtime();
|
|
703
|
-
}).on('query-response', (response, query) => {
|
|
704
|
-
end(query, {
|
|
705
|
-
response
|
|
706
|
-
});
|
|
707
|
-
}).on('query-error', (error, query) => {
|
|
708
|
-
end(query, {
|
|
709
|
-
error
|
|
710
|
-
});
|
|
711
|
-
});
|
|
712
|
-
}
|
|
713
|
-
|
|
714
|
-
normalizeIdentifier(identifier) {
|
|
715
|
-
return this.knex.client.wrapIdentifier(identifier).replace(/['`"]/g, '');
|
|
716
|
-
}
|
|
717
|
-
|
|
718
|
-
denormalizeIdentifier(identifier) {
|
|
719
|
-
const obj = this.knex.client.postProcessResponse({
|
|
720
|
-
[identifier]: 1
|
|
721
|
-
});
|
|
722
|
-
return Object.keys(obj)[0];
|
|
723
|
-
}
|
|
724
|
-
|
|
725
|
-
normalizePath(path) {
|
|
726
|
-
return this.config.app.normalizePaths ? (0, _utils2.hyphenate)(path) : path;
|
|
727
|
-
}
|
|
728
|
-
|
|
729
|
-
formatError(err) {
|
|
730
|
-
var _this$config$log$erro3;
|
|
731
|
-
|
|
732
|
-
const message = err.toJSON ? (0, _utils.formatJson)(err.toJSON()) : err.message || err;
|
|
733
|
-
const str = `${err.name}: ${message}`;
|
|
734
|
-
return err.stack && ((_this$config$log$erro3 = this.config.log.errors) == null ? void 0 : _this$config$log$erro3.stack) !== false ? `${str}\n${err.stack.split(/\n|\r\n|\r/).slice(1).join(_os.default.EOL)}` : str;
|
|
735
|
-
}
|
|
736
|
-
|
|
737
|
-
logError(err, ctx) {
|
|
738
|
-
if (!err.expose && !this.silent) {
|
|
739
|
-
try {
|
|
740
|
-
const text = this.formatError(err);
|
|
741
|
-
const level = err instanceof _errors.ResponseError && err.status < 500 ? 'info' : 'error';
|
|
742
|
-
const logger = (ctx == null ? void 0 : ctx.logger) || this.logger;
|
|
743
|
-
logger[level](text);
|
|
744
|
-
} catch (e) {
|
|
745
|
-
console.error('Could not log error', e);
|
|
746
|
-
}
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
|
|
750
|
-
async start() {
|
|
751
|
-
if (this.config.log.errors !== false) {
|
|
752
|
-
this.on('error', this.logError);
|
|
753
|
-
}
|
|
754
|
-
|
|
755
|
-
await this.emit('before:start');
|
|
756
|
-
await this.forEachService(service => service.start());
|
|
757
|
-
const {
|
|
758
|
-
server: {
|
|
759
|
-
host,
|
|
760
|
-
port
|
|
761
|
-
},
|
|
762
|
-
env
|
|
763
|
-
} = this.config;
|
|
764
|
-
this.server = await new Promise((resolve, reject) => {
|
|
765
|
-
const server = this.listen(port, host, () => {
|
|
766
|
-
const {
|
|
767
|
-
port
|
|
768
|
-
} = server.address();
|
|
769
|
-
console.info(`${env} server started at http://${host}:${port}`);
|
|
770
|
-
resolve(server);
|
|
771
|
-
});
|
|
772
|
-
|
|
773
|
-
if (!server) {
|
|
774
|
-
reject(new Error(`Unable to start server at http://${host}:${port}`));
|
|
775
|
-
}
|
|
776
|
-
});
|
|
777
|
-
await this.emit('after:start');
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
async stop() {
|
|
781
|
-
await this.emit('before:stop');
|
|
782
|
-
this.server = await new Promise((resolve, reject) => {
|
|
783
|
-
const {
|
|
784
|
-
server
|
|
785
|
-
} = this;
|
|
786
|
-
|
|
787
|
-
if (server) {
|
|
788
|
-
server.close(err => {
|
|
789
|
-
if (err) {
|
|
790
|
-
reject(err);
|
|
791
|
-
} else {
|
|
792
|
-
resolve(null);
|
|
793
|
-
}
|
|
794
|
-
});
|
|
795
|
-
setImmediate(() => server.emit('close'));
|
|
796
|
-
} else {
|
|
797
|
-
reject(new Error('Server is not running'));
|
|
798
|
-
}
|
|
799
|
-
});
|
|
800
|
-
await this.forEachService(service => service.stop());
|
|
801
|
-
await this.emit('after:stop');
|
|
802
|
-
|
|
803
|
-
if (this.config.log.errors !== false) {
|
|
804
|
-
this.off('error', this.logError);
|
|
805
|
-
}
|
|
806
|
-
}
|
|
807
|
-
|
|
808
|
-
async startOrExit() {
|
|
809
|
-
try {
|
|
810
|
-
await this.start();
|
|
811
|
-
} catch (err) {
|
|
812
|
-
this.logError(err);
|
|
813
|
-
process.exit(-1);
|
|
814
|
-
}
|
|
815
|
-
}
|
|
816
|
-
|
|
817
|
-
async createAssets(storage, files, count = 0, trx = null) {
|
|
818
|
-
const AssetModel = this.getModel('Asset');
|
|
819
|
-
|
|
820
|
-
if (AssetModel) {
|
|
821
|
-
const assets = files.map(file => ({
|
|
822
|
-
key: file.key,
|
|
823
|
-
file,
|
|
824
|
-
storage: storage.name,
|
|
825
|
-
count
|
|
826
|
-
}));
|
|
827
|
-
return AssetModel.query(trx).insert(assets);
|
|
828
|
-
}
|
|
829
|
-
|
|
830
|
-
return null;
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
async handleAdddedAndRemovedAssets(storage, addedFiles, removedFiles, trx = null) {
|
|
834
|
-
const {
|
|
835
|
-
assets: {
|
|
836
|
-
cleanupTimeThreshold = 0
|
|
837
|
-
} = {}
|
|
838
|
-
} = this.config;
|
|
839
|
-
const timeThreshold = (0, _utils2.isString)(cleanupTimeThreshold) ? (0, _parseDuration.default)(cleanupTimeThreshold) : cleanupTimeThreshold;
|
|
840
|
-
const importedFiles = [];
|
|
841
|
-
const AssetModel = this.getModel('Asset');
|
|
842
|
-
|
|
843
|
-
if (AssetModel) {
|
|
844
|
-
importedFiles.push(...(await this.addForeignAssets(storage, addedFiles, trx)));
|
|
845
|
-
|
|
846
|
-
if (addedFiles.length > 0 || removedFiles.length > 0) {
|
|
847
|
-
const changeCount = (files, increment) => files.length > 0 && AssetModel.query(trx).whereIn('key', files.map(file => file.key)).increment('count', increment);
|
|
848
|
-
|
|
849
|
-
await Promise.all([changeCount(addedFiles, 1), changeCount(removedFiles, -1)]);
|
|
850
|
-
|
|
851
|
-
if (timeThreshold > 0) {
|
|
852
|
-
setTimeout(() => this.releaseUnusedAssets(timeThreshold), timeThreshold);
|
|
853
|
-
}
|
|
854
|
-
}
|
|
855
|
-
|
|
856
|
-
await this.releaseUnusedAssets(timeThreshold, trx);
|
|
857
|
-
return importedFiles;
|
|
858
|
-
}
|
|
859
|
-
}
|
|
860
|
-
|
|
861
|
-
async addForeignAssets(storage, files, trx = null) {
|
|
862
|
-
const importedFiles = [];
|
|
863
|
-
const AssetModel = this.getModel('Asset');
|
|
864
|
-
|
|
865
|
-
if (AssetModel) {
|
|
866
|
-
await Promise.all(files.map(async file => {
|
|
867
|
-
const asset = await AssetModel.query(trx).findOne('key', file.key);
|
|
868
|
-
|
|
869
|
-
if (!asset) {
|
|
870
|
-
if (file.data || file.url) {
|
|
871
|
-
let {
|
|
872
|
-
data
|
|
873
|
-
} = file;
|
|
874
|
-
|
|
875
|
-
if (!data) {
|
|
876
|
-
console.info(`${_picocolors.default.red('INFO:')} Asset ${_picocolors.default.green(`'${file.name}'`)} is from a foreign source, fetching from ${_picocolors.default.green(`'${file.url}'`)} and adding to storage ${_picocolors.default.green(`'${storage.name}'`)}...`);
|
|
877
|
-
const response = await _axios.default.request({
|
|
878
|
-
method: 'get',
|
|
879
|
-
url: file.url,
|
|
880
|
-
responseType: 'arraybuffer'
|
|
881
|
-
});
|
|
882
|
-
data = response.data;
|
|
883
|
-
}
|
|
884
|
-
|
|
885
|
-
const importedFile = await storage.addFile(file, data);
|
|
886
|
-
await this.createAssets(storage, [importedFile], 0, trx);
|
|
887
|
-
Object.assign(file, importedFile);
|
|
888
|
-
importedFiles.push(importedFile);
|
|
889
|
-
} else {
|
|
890
|
-
throw new _errors.AssetError(`Unable to import asset from foreign source: '${file.name}' ('${file.key}')`);
|
|
891
|
-
}
|
|
892
|
-
} else {
|
|
893
|
-
Object.assign(file, asset.file);
|
|
894
|
-
}
|
|
895
|
-
}));
|
|
896
|
-
}
|
|
897
|
-
|
|
898
|
-
return importedFiles;
|
|
899
|
-
}
|
|
900
|
-
|
|
901
|
-
async handleModifiedAssets(storage, files, trx = null) {
|
|
902
|
-
const modifiedFiles = [];
|
|
903
|
-
const AssetModel = this.getModel('Asset');
|
|
904
|
-
|
|
905
|
-
if (AssetModel) {
|
|
906
|
-
await Promise.all(files.map(async file => {
|
|
907
|
-
if (file.data) {
|
|
908
|
-
const asset = await AssetModel.query(trx).findOne('key', file.key);
|
|
909
|
-
|
|
910
|
-
if (asset) {
|
|
911
|
-
const changedFile = await storage.addFile(file, file.data);
|
|
912
|
-
Object.assign(file, changedFile);
|
|
913
|
-
modifiedFiles.push(changedFile);
|
|
914
|
-
} else {
|
|
915
|
-
throw new _errors.AssetError(`Unable to update modified asset from memory source: '${file.name}' ('${file.key}')`);
|
|
916
|
-
}
|
|
917
|
-
}
|
|
918
|
-
}));
|
|
919
|
-
}
|
|
920
|
-
|
|
921
|
-
return modifiedFiles;
|
|
922
|
-
}
|
|
923
|
-
|
|
924
|
-
async releaseUnusedAssets(timeThreshold = 0, trx = null) {
|
|
925
|
-
const AssetModel = this.getModel('Asset');
|
|
926
|
-
|
|
927
|
-
if (AssetModel) {
|
|
928
|
-
return AssetModel.transaction(trx, async trx => {
|
|
929
|
-
const date = new Date();
|
|
930
|
-
date.setMilliseconds(date.getMilliseconds() - timeThreshold);
|
|
931
|
-
const orphanedAssets = await AssetModel.query(trx).where('count', 0).andWhere('updatedAt', '<=', date).andWhere('updatedAt', '>', (0, _objection.ref)('createdAt'));
|
|
932
|
-
|
|
933
|
-
if (orphanedAssets.length > 0) {
|
|
934
|
-
const orphanedKeys = await Promise.all(orphanedAssets.map(async asset => {
|
|
935
|
-
try {
|
|
936
|
-
await this.getStorage(asset.storage).removeFile(asset.file);
|
|
937
|
-
} catch (error) {
|
|
938
|
-
this.emit('error', error);
|
|
939
|
-
asset.error = error;
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
return asset.key;
|
|
943
|
-
}));
|
|
944
|
-
await AssetModel.query(trx).delete().whereIn('key', orphanedKeys);
|
|
945
|
-
}
|
|
946
|
-
|
|
947
|
-
return orphanedAssets;
|
|
948
|
-
});
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
|
|
952
|
-
}
|
|
953
|
-
|
|
954
|
-
exports.Application = Application;
|
|
955
|
-
|
|
956
|
-
_lib.EventEmitter.mixin(Application.prototype);
|
|
957
|
-
|
|
958
|
-
function getOptions(options) {
|
|
959
|
-
return (0, _utils2.isObject)(options) ? options : {};
|
|
960
|
-
}
|
|
961
|
-
//# sourceMappingURL=data:application/json;charset=utf-8;base64,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hcHAvQXBwbGljYXRpb24uanMiXSwibmFtZXMiOlsiQXBwbGljYXRpb24iLCJLb2EiLCJjb25zdHJ1Y3RvciIsImNvbmZpZyIsInZhbGlkYXRvciIsInJvdXRlciIsImV2ZW50cyIsIm1pZGRsZXdhcmUiLCJtb2RlbHMiLCJzZXJ2aWNlcyIsImNvbnRyb2xsZXJzIiwiX3NldHVwRW1pdHRlciIsImFwcCIsImtleXMiLCJsb2ciLCJyZXN0Iiwic2lsZW50IiwicHJvY2VzcyIsImVudiIsIkRJVE9fU0lMRU5UIiwicHJveHkiLCJWYWxpZGF0b3IiLCJSb3V0ZXIiLCJzdG9yYWdlcyIsIk9iamVjdCIsImNyZWF0ZSIsImhhc0NvbnRyb2xsZXJNaWRkbGV3YXJlIiwic2V0dXBMb2dnZXIiLCJzZXR1cEtuZXgiLCJzZXR1cEdsb2JhbE1pZGRsZXdhcmUiLCJ1c2UiLCJhZGRTdG9yYWdlcyIsImFkZE1vZGVscyIsImFkZFNlcnZpY2VzIiwiYWRkQ29udHJvbGxlcnMiLCJhZGRSb3V0ZSIsInZlcmIiLCJwYXRoIiwidHJhbnNhY3RlZCIsImhhbmRsZXJzIiwiY29udHJvbGxlciIsImFjdGlvbiIsImhhbmRsZXIiLCJsZW5ndGgiLCJyb3V0ZSIsIm1vZGVsQ2xhc3MiLCJ2YWx1ZXMiLCJhZGRNb2RlbCIsInNvcnRNb2RlbHMiLCJzb3J0ZWRNb2RlbHMiLCJmaWx0ZXIiLCJuYW1lIiwic2V0dXAiLCJrbmV4IiwiaW5pdGlhbGl6ZSIsImFkZFNjaGVtYSIsImdldEpzb25TY2hlbWEiLCJzY2hlbWEiLCJyZWxhdGlvbnMiLCJzaG91bGRMb2ciLCJvcHRpb24iLCJpbmNsdWRlcyIsImRhdGEiLCJyZWxhdGlvbk1hcHBpbmdzIiwidmFsdWUiLCJNb2RlbCIsImlzUHJvdG90eXBlT2YiLCJjb25zb2xlIiwiaW5mbyIsInBpY28iLCJ5ZWxsb3ciLCJib2xkIiwidXRpbCIsImluc3BlY3QiLCJjb2xvcnMiLCJkZXB0aCIsIm1heEFycmF5TGVuZ3RoIiwiRXJyb3IiLCJzb3J0QnlSZWxhdGlvbnMiLCJsaXN0IiwiY29sbGVjdGVkIiwiZXhjbHVkZWQiLCJyZWxhdGlvbiIsImdldFJlbGF0aW9ucyIsIkJlbG9uZ3NUb09uZVJlbGF0aW9uIiwicmVsYXRlZE1vZGVsQ2xhc3MiLCJqb2luVGFibGVNb2RlbENsYXNzIiwicmVsYXRlZCIsInJldmVyc2UiLCJyZWR1Y2UiLCJnZXRNb2RlbCIsImVuZHNXaXRoIiwiZmluZE1vZGVsIiwiY2FsbGJhY2siLCJmaW5kIiwic2VydmljZSIsImVudHJpZXMiLCJhZGRTZXJ2aWNlIiwiU2VydmljZSIsInVuZGVmaW5lZCIsImdldFNlcnZpY2UiLCJmaW5kU2VydmljZSIsImZvckVhY2hTZXJ2aWNlIiwiUHJvbWlzZSIsImFsbCIsIm1hcCIsIm5hbWVzcGFjZSIsImtleSIsImFkZENvbnRyb2xsZXIiLCJzZXR1cENvbnRyb2xsZXJNaWRkbGV3YXJlIiwiQ29udHJvbGxlciIsInVybCIsImNvbXBvc2UiLCJnZXRDb250cm9sbGVyIiwiZmluZENvbnRyb2xsZXIiLCJnZXRBZG1pbkNvbnRyb2xsZXIiLCJBZG1pbkNvbnRyb2xsZXIiLCJnZXRBZG1pblZ1ZUNvbmZpZyIsImdldFZ1ZUNvbmZpZyIsImdldEFzc2V0Q29uZmlnIiwibm9ybWFsaXplRGJOYW1lcyIsImFzc2V0Q29uZmlnIiwibW9kZWxOYW1lIiwiYXNzZXRzIiwiZGVmaW5pdGlvbiIsIm5vcm1hbGl6ZWRNb2RlbE5hbWUiLCJub3JtYWxpemVJZGVudGlmaWVyIiwiY29udmVydGVkQXNzZXRzIiwiYXNzZXREYXRhUGF0aCIsInByb3BlcnR5IiwibmVzdGVkRGF0YVBhdGgiLCJpbmRleCIsImdldFByb3BlcnR5T3JSZWxhdGlvbkF0RGF0YVBhdGgiLCJub3JtYWxpemVkTmFtZSIsImRhdGFQYXRoIiwiYXNzZXRDb25maWdzIiwiYWRkU3RvcmFnZSIsInN0b3JhZ2UiLCJzdG9yYWdlQ2xhc3MiLCJTdG9yYWdlIiwiZ2V0IiwidHlwZSIsImdldFN0b3JhZ2UiLCJjb21waWxlVmFsaWRhdG9yIiwianNvblNjaGVtYSIsIm9wdGlvbnMiLCJjb21waWxlIiwiY29tcGlsZVBhcmFtZXRlcnNWYWxpZGF0b3IiLCJwYXJhbWV0ZXJzIiwiZGF0YU5hbWUiLCJwcm9wZXJ0aWVzIiwiYWRkUGFyYW1ldGVyIiwicHVzaCIsIm1lbWJlciIsImFzT2JqZWN0IiwidmFsaWRhdGUiLCJjb2VyY2VUeXBlcyIsImN0eCIsImNhbGwiLCJjcmVhdGVWYWxpZGF0aW9uRXJyb3IiLCJtZXNzYWdlIiwiZXJyb3JzIiwianNvbiIsIlZhbGlkYXRpb25FcnJvciIsInBhcnNlRXJyb3JzIiwiY3JlYXRlRGF0YWJhc2VFcnJvciIsImVycm9yIiwic3FsIiwibWF0Y2giLCJEYXRhYmFzZUVycm9yIiwibG9nZ2VyIiwicmVzcG9uc2VUaW1lIiwiZ2V0T3B0aW9ucyIsInJlcXVlc3RzIiwiaGVsbWV0IiwiY29ycyIsImNvbXByZXNzIiwiYnIiLCJwYXJhbXMiLCJ6bGliIiwiY29uc3RhbnRzIiwiQlJPVExJX1BBUkFNX1FVQUxJVFkiLCJldGFnIiwiYm9keVBhcnNlciIsInNlc3Npb24iLCJDb250ZXh0U3RvcmUiLCJwYXNzcG9ydCIsImVyciIsInJlcSIsInJlcyIsInBpbm8iLCJzdGRTZXJpYWxpemVycyIsInVzZXIiLCJpZCIsInNlcmlhbGl6ZXJzIiwibGV2ZWwiLCJwcmV0dHlQcmludCIsImlnbm9yZSIsInRyYW5zbGF0ZVRpbWUiLCJyZWRhY3QiLCJiYXNlIiwiY2hpbGQiLCJjbGllbnQiLCJzbmFrZUNhc2VPcHRpb25zIiwidHlwZVBhcnNlcnMiLCJwYXJzZXIiLCJkcml2ZXIiLCJ0eXBlcyIsInNldFR5cGVQYXJzZXIiLCJzZXR1cEtuZXhMb2dnaW5nIiwic3RhcnRUaW1lcyIsImVuZCIsInF1ZXJ5IiwicmVzcG9uc2UiLCJfX2tuZXhRdWVyeVVpZCIsImRpZmYiLCJocnRpbWUiLCJkdXJhdGlvbiIsImJpbmRpbmdzIiwiZnJvbUVudHJpZXMiLCJzdGFydHNXaXRoIiwib24iLCJpZGVudGlmaWVyIiwid3JhcElkZW50aWZpZXIiLCJyZXBsYWNlIiwiZGVub3JtYWxpemVJZGVudGlmaWVyIiwib2JqIiwicG9zdFByb2Nlc3NSZXNwb25zZSIsIm5vcm1hbGl6ZVBhdGgiLCJub3JtYWxpemVQYXRocyIsImZvcm1hdEVycm9yIiwidG9KU09OIiwic3RyIiwic3RhY2siLCJzcGxpdCIsInNsaWNlIiwiam9pbiIsIm9zIiwiRU9MIiwibG9nRXJyb3IiLCJleHBvc2UiLCJ0ZXh0IiwiUmVzcG9uc2VFcnJvciIsInN0YXR1cyIsImUiLCJzdGFydCIsImVtaXQiLCJzZXJ2ZXIiLCJob3N0IiwicG9ydCIsInJlc29sdmUiLCJyZWplY3QiLCJsaXN0ZW4iLCJhZGRyZXNzIiwic3RvcCIsImNsb3NlIiwic2V0SW1tZWRpYXRlIiwib2ZmIiwic3RhcnRPckV4aXQiLCJleGl0IiwiY3JlYXRlQXNzZXRzIiwiZmlsZXMiLCJjb3VudCIsInRyeCIsIkFzc2V0TW9kZWwiLCJmaWxlIiwiaW5zZXJ0IiwiaGFuZGxlQWRkZGVkQW5kUmVtb3ZlZEFzc2V0cyIsImFkZGVkRmlsZXMiLCJyZW1vdmVkRmlsZXMiLCJjbGVhbnVwVGltZVRocmVzaG9sZCIsInRpbWVUaHJlc2hvbGQiLCJpbXBvcnRlZEZpbGVzIiwiYWRkRm9yZWlnbkFzc2V0cyIsImNoYW5nZUNvdW50IiwiaW5jcmVtZW50Iiwid2hlcmVJbiIsInNldFRpbWVvdXQiLCJyZWxlYXNlVW51c2VkQXNzZXRzIiwiYXNzZXQiLCJmaW5kT25lIiwicmVkIiwiZ3JlZW4iLCJheGlvcyIsInJlcXVlc3QiLCJtZXRob2QiLCJyZXNwb25zZVR5cGUiLCJpbXBvcnRlZEZpbGUiLCJhZGRGaWxlIiwiYXNzaWduIiwiQXNzZXRFcnJvciIsImhhbmRsZU1vZGlmaWVkQXNzZXRzIiwibW9kaWZpZWRGaWxlcyIsImNoYW5nZWRGaWxlIiwidHJhbnNhY3Rpb24iLCJkYXRlIiwiRGF0ZSIsInNldE1pbGxpc2Vjb25kcyIsImdldE1pbGxpc2Vjb25kcyIsIm9ycGhhbmVkQXNzZXRzIiwid2hlcmUiLCJhbmRXaGVyZSIsIm9ycGhhbmVkS2V5cyIsInJlbW92ZUZpbGUiLCJkZWxldGUiLCJFdmVudEVtaXR0ZXIiLCJtaXhpbiIsInByb3RvdHlwZSJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQU1BOztBQUNBOztBQUNBOztBQVNBOztBQUlBOzs7O0FBT08sTUFBTUEsV0FBTixTQUEwQkMsWUFBMUIsQ0FBOEI7QUFDbkNDLEVBQUFBLFdBQVcsQ0FBQztBQUNWQyxJQUFBQSxNQUFNLEdBQUcsRUFEQztBQUVWQyxJQUFBQSxTQUZVO0FBR1ZDLElBQUFBLE1BSFU7QUFJVkMsSUFBQUEsTUFKVTtBQUtWQyxJQUFBQSxVQUxVO0FBTVZDLElBQUFBLE1BTlU7QUFPVkMsSUFBQUEsUUFQVTtBQVFWQyxJQUFBQTtBQVJVLE1BU1IsRUFUTyxFQVNIO0FBQ047O0FBQ0EsU0FBS0MsYUFBTCxDQUFtQkwsTUFBbkI7O0FBQ0EsVUFBTTtBQUVKTSxNQUFBQSxHQUFHLEVBQUU7QUFBRUMsUUFBQUEsSUFBRjtBQUFRLFdBQUdEO0FBQVgsVUFBbUIsRUFGcEI7QUFHSkUsTUFBQUEsR0FBRyxHQUFHLEVBSEY7QUFJSixTQUFHQztBQUpDLFFBS0ZaLE1BTEo7QUFNQSxTQUFLQSxNQUFMLEdBQWM7QUFDWlMsTUFBQUEsR0FEWTtBQUVaRSxNQUFBQSxHQUFHLEVBQUVBLEdBQUcsQ0FBQ0UsTUFBSixJQUFjQyxPQUFPLENBQUNDLEdBQVIsQ0FBWUMsV0FBMUIsR0FBd0MsRUFBeEMsR0FBNkNMLEdBRnRDO0FBR1osU0FBR0M7QUFIUyxLQUFkO0FBS0EsU0FBS0YsSUFBTCxHQUFZQSxJQUFaO0FBQ0EsU0FBS08s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N0I7O0FBT0EsWUFBSUYsY0FBYyxDQUFDaFEsTUFBZixHQUF3QixDQUE1QixFQUErQjtBQUM3QixnQkFBTW1RLFlBQVksR0FBRyxNQUFNdk0sT0FBTyxDQUFDQyxHQUFSLENBQ3pCbU0sY0FBYyxDQUFDbE0sR0FBZixDQUFtQixNQUFNOEssS0FBTixJQUFlO0FBQ2hDLGdCQUFJO0FBQ0Ysb0JBQU0sS0FBS3pJLFVBQUwsQ0FBZ0J5SSxLQUFLLENBQUM5SSxPQUF0QixFQUErQnNLLFVBQS9CLENBQTBDeEIsS0FBSyxDQUFDZCxJQUFoRCxDQUFOO0FBQ0QsYUFGRCxDQUVFLE9BQU9uRyxLQUFQLEVBQWM7QUFDZCxtQkFBS2dGLElBQUwsQ0FBVSxPQUFWLEVBQW1CaEYsS0FBbkI7QUFDQWlILGNBQUFBLEtBQUssQ0FBQ2pILEtBQU4sR0FBY0EsS0FBZDtBQUNEOztBQUNELG1CQUFPaUgsS0FBSyxDQUFDNUssR0FBYjtBQUNELFdBUkQsQ0FEeUIsQ0FBM0I7QUFXQSxnQkFBTTZKLFVBQVUsQ0FDYnBELEtBREcsQ0FDR21ELEdBREgsRUFFSHlDLE1BRkcsR0FHSDVCLE9BSEcsQ0FHSyxLQUhMLEVBR1kwQixZQUhaLENBQU47QUFJRDs7QUFDRCxlQUFPSCxjQUFQO0FBQ0QsT0E5Qk0sQ0FBUDtBQStCRDtBQUNGOztBQS80QmtDOzs7O0FBbzVCckNNLGtCQUFhQyxLQUFiLENBQW1CbFQsV0FBVyxDQUFDbVQsU0FBL0I7O0FBRUEsU0FBU3ZJLFVBQVQsQ0FBb0IzQixPQUFwQixFQUE2QjtBQUMzQixTQUFPLHNCQUFTQSxPQUFULElBQW9CQSxPQUFwQixHQUE4QixFQUFyQztBQUNEIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IEtvYSBmcm9tICdrb2EnXG5pbXBvcnQgS25leCBmcm9tICdrbmV4J1xuaW1wb3J0IHV0aWwgZnJvbSAndXRpbCdcbmltcG9ydCBheGlvcyBmcm9tICdheGlvcydcbmltcG9ydCBwaWNvIGZyb20gJ3BpY29jb2xvcnMnXG5pbXBvcnQgemxpYiBmcm9tICd6bGliJ1xuaW1wb3J0IHBpbm8gZnJvbSAncGlubydcbmltcG9ydCBvcyBmcm9tICdvcydcbmltcG9ydCBwYXJzZUR1cmF0aW9uIGZyb20gJ3BhcnNlLWR1cmF0aW9uJ1xuaW1wb3J0IGJvZHlQYXJzZXIgZnJvbSAna29hLWJvZHlwYXJzZXInXG5pbXBvcnQgY29ycyBmcm9tICdAa29hL2NvcnMnXG5pbXBvcnQgY29tcG9zZSBmcm9tICdrb2EtY29tcG9zZSdcbmltcG9ydCBjb21wcmVzcyBmcm9tICdrb2EtY29tcHJlc3MnXG5pbXBvcnQgY29uZGl0aW9uYWwgZnJvbSAna29hLWNvbmRpdGlvbmFsLWdldCdcbmltcG9ydCBwYXNzcG9ydCBmcm9tICdrb2EtcGFzc3BvcnQnXG5pbXBvcnQgc2Vzc2lvbiBmcm9tICdrb2Etc2Vzc2lvbidcbmltcG9ydCBldGFnIGZyb20gJ2tvYS1ldGFnJ1xuaW1wb3J0IGhlbG1ldCBmcm9tICdrb2EtaGVsbWV0J1xuaW1wb3J0IHJlc3BvbnNlVGltZSBmcm9tICdrb2EtcmVzcG9uc2UtdGltZSdcbmltcG9ydCBSb3V0ZXIgZnJvbSAnQGRpdG9qcy9yb3V0ZXInXG5pbXBvcnQgeyBFdmVudEVtaXR0ZXIgfSBmcm9tICdAL2xpYidcbmltcG9ydCB7IENvbnRyb2xsZXIsIEFkbWluQ29udHJvbGxlciB9IGZyb20gJ0AvY29udHJvbGxlcnMnXG5pbXBvcnQgeyBTZXJ2aWNlIH0gZnJvbSAnQC9zZXJ2aWNlcydcbmltcG9ydCB7IFN0b3JhZ2UgfSBmcm9tICdAL3N0b3JhZ2UnXG5pbXBvcnQgeyBjb252ZXJ0U2NoZW1hIH0gZnJvbSAnQC9zY2hlbWEnXG5pbXBvcnQgeyBmb3JtYXRKc29uIH0gZnJvbSAnQC91dGlscydcbmltcG9ydCB7XG4gIFJlc3BvbnNlRXJyb3IsXG4gIFZhbGlkYXRpb25FcnJvcixcbiAgRGF0YWJhc2VFcnJvcixcbiAgQXNzZXRFcnJvclxufSBmcm9tICdAL2Vycm9ycydcbmltcG9ydCBTZXNzaW9uU3RvcmUgZnJvbSAnLi9TZXNzaW9uU3RvcmUnXG5pbXBvcnQgeyBWYWxpZGF0b3IgfSBmcm9tICcuL1ZhbGlkYXRvcidcbmltcG9ydCB7XG4gIGF0dGFjaExvZ2dlcixcbiAgY3JlYXRlVHJhbnNhY3Rpb24sXG4gIGZpbmRSb3V0ZSxcbiAgaGFuZGxlRXJyb3IsXG4gIGhhbmRsZVJvdXRlLFxuICBoYW5kbGVVc2VyLFxuICBsb2dSZXF1ZXN0c1xufSBmcm9tICdAL21pZGRsZXdhcmUnXG5pbXBvcnQge1xuICBpc0FycmF5LCBpc09iamVjdCwgaXNTdHJpbmcsIGFzQXJyYXksIGlzUGxhaW5PYmplY3QsIGh5cGhlbmF0ZSwgY2xvbmUsIG1lcmdlLFxuICBwYXJzZURhdGFQYXRoLCBub3JtYWxpemVEYXRhUGF0aFxufSBmcm9tICdAZGl0b2pzL3V0aWxzJ1xuaW1wb3J0IHtcbiAgTW9kZWwsXG4gIEJlbG9uZ3NUb09uZVJlbGF0aW9uLFxuICBrbmV4U25ha2VDYXNlTWFwcGVycyxcbiAgcmVmXG59IGZyb20gJ29iamVjdGlvbidcblxuZXhwb3J0IGNsYXNzIEFwcGxpY2F0aW9uIGV4dGVuZHMgS29hIHtcbiAgY29uc3RydWN0b3Ioe1xuICAgIGNvbmZpZyA9IHt9LFxuICAgIHZhbGlkYXRvcixcbiAgICByb3V0ZXIsXG4gICAgZXZlbnRzLFxuICAgIG1pZGRsZXdhcmUsXG4gICAgbW9kZWxzLFxuICAgIHNlcnZpY2VzLFxuICAgIGNvbnRyb2xsZXJzXG4gIH0gPSB7fSkge1xuICAgIHN1cGVyKClcbiAgICB0aGlzLl9zZXR1cEVtaXR0ZXIoZXZlbnRzKVxuICAgIGNvbnN0IHtcbiAgICAgIC8vIFBsdWNrIGtleXMgb3V0IG9mIGBjb25maWcuYXBwYCB0byBrZWVwIHRoZW0gc2VjcmV0XG4gICAgICBhcHA6IHsga2V5cywgLi4uYXBwIH0gPSB7fSxcbiAgICAgIGxvZyA9IHt9LFxuICAgICAgLi4ucmVzdFxuICAgIH0gPSBjb25maWdcbiAgICB0aGlzLmNvbmZpZyA9IHtcbiAgICAgIGFwcCxcbiAgICAgIGxvZzogbG9nLnNpbGVudCB8fCBwcm9jZXNzLmVudi5ESVRPX1NJTEVOVCA/IHt9IDogbG9nLFxuICAgICAgLi4ucmVzdFxuICAgIH1cbiAgICB0aGlzLmtleXMgPSBrZXlzXG4gICAgdGhpcy5wcm94eSA9ICEhYXBwLnByb3h5XG4gICAgdGhpcy52YWxpZGF0b3IgPSB2YWxpZGF0b3IgfHwgbmV3IFZhbGlkYXRvcigpXG4gICAgdGhpcy5yb3V0ZXIgPSByb3V0ZXIgfHwgbmV3IFJvdXRlcigpXG4gICAgdGhpcy52YWxpZGF0b3IuYXBwID0gdGhpc1xuICAgIHRoaXMuc3RvcmFnZXMgPSBPYmplY3QuY3JlYXRlKG51bGwpXG4gICAgdGhpcy5tb2RlbHMgPSBPYmplY3QuY3JlYXRlKG51bGwpXG4gICAgdGhpcy5zZXJ2aWNlcyA9IE9iamVjdC5jcmVhdGUobnVsbClcbiAgICB0aGlzLmNvbnRyb2xsZXJzID0gT2JqZWN0LmNyZWF0ZShudWxsKVxuICAgIHRoaXMuaGFzQ29udHJvbGxlck1pZGRsZXdhcmUgPSBmYWxzZVxuICAgIHRoaXMuc2V0dXBMb2dnZXIoKVxuICAgIHRoaXMuc2V0dXBLbmV4KClcbiAgICB0aGlzLnNldHVwR2xvYmFsTWlkZGxld2FyZSgpXG4gICAgaWYgKG1pZGRsZXdhcmUpIHtcbiAgICAgIHRoaXMudXNlKG1pZGRsZXdhcmUpXG4gICAgfVxuICAgIGlmIChjb25maWcuc3RvcmFnZXMpIHtcbiAgICAgIHRoaXMuYWRkU3RvcmFnZXMoY29uZmlnLnN0b3JhZ2VzKVxuICAgIH1cbiAgICBpZiAobW9kZWxzKSB7XG4gICAgICB0aGlzLmFkZE1vZGVscyhtb2RlbHMpXG4gICAgfVxuICAgIGlmIChzZXJ2aWNlcykge1xuICAgICAgdGhpcy5hZGRTZXJ2aWNlcyhzZXJ2aWNlcylcbiAgICB9XG4gICAgaWYgKGNvbnRyb2xsZXJzKSB7XG4gICAgICB0aGlzLmFkZENvbnRyb2xsZXJzKGNvbnRyb2xsZXJzKVxuICAgIH1cbiAgfVxuXG4gIGFkZFJvdXRlKHZlcmIsIHBhdGgsIHRyYW5zYWN0ZWQsIGhhbmRsZXJzLCBjb250cm9sbGVyID0gbnVsbCwgYWN0aW9uID0gbnVsbCkge1xuICAgIGhhbmRsZXJzID0gYXNBcnJheShoYW5kbGVycylcbiAgICBjb25zdCBoYW5kbGVyID0gaGFuZGxlcnMubGVuZ3RoID4gMSA/IGNvbXBvc2UoaGFuZGxlcnMpIDogaGFuZGxlcnNbMF1cbiAgICAvLyBJbnN0ZWFkIG9mIGRpcmVjdGx5IHBhc3NpbmcgYGhhbmRsZXJgLCBwYXNzIGEgYHJvdXRlYCBvYmplY3QgdGhhdCBhbHNvXG4gICAgLy8gd2lsbCBiZSBleHBvc2VkIHRocm91Z2ggYGN0eC5yb3V0ZWAsIHNlZSBgcm91dGVySGFuZGxlcigpYDpcbiAgICBjb25zdCByb3V0ZSA9IHtcbiAgICAgIHZlcmIsXG4gICAgICBwYXRoLFxuICAgICAgdHJhbnNhY3RlZCxcbiAgICAgIGhhbmRsZXIsXG4gICAgICBjb250cm9sbGVyLFxuICAgICAgYWN0aW9uXG4gICAgfVxuICAgIHRoaXMucm91dGVyW3ZlcmJdKHBhdGgsIHJvdXRlKVxuICB9XG5cbiAgYWRkTW9kZWxzKG1vZGVscykge1xuICAgIC8vIEZpcnN0IGFkZCBhbGwgbW9kZWxzIHRoZW4gY2FsbCBpbml0aWFsaXplKCkgZm9yIGVhY2ggaW4gYSBzZWNvbmQgbG9vcCxcbiAgICAvLyBzaW5jZSB0aGV5IG1heSBiZSByZWZlcmVuY2luZyBlYWNoIG90aGVyIGluIHJlbGF0aW9ucy5cbiAgICBmb3IgKGNvbnN0IG1vZGVsQ2xhc3Mgb2YgT2JqZWN0LnZhbHVlcyhtb2RlbHMpKSB7XG4gICAgICB0aGlzLmFkZE1vZGVsKG1vZGVsQ2xhc3MpXG4gICAgfVxuICAgIC8vIE5vdyAocmUtKXNvcnQgYWxsIG1vZGVscyBiYXNlZCBvbiB0aGVpciByZWxhdGlvbnMuXG4gICAgdGhpcy5tb2RlbHMgPSB0aGlzLnNvcnRNb2RlbHModGhpcy5tb2RlbHMpXG4gICAgLy8gRmlsdGVyIHRocm91Z2ggYWxsIHNvcnRlZCBtb2RlbHMsIGtlZXBpbmcgb25seSB0aGUgbmV3bHkgYWRkZWQgb25lcy5cbiAgICBjb25zdCBzb3J0ZWRNb2RlbHMgPSBPYmplY3QudmFsdWVzKHRoaXMubW9kZWxzKS5maWx0ZXIoXG4gICAgICBtb2RlbENsYXNzID0+IG1vZGVsc1ttb2RlbENsYXNzLm5hbWVdID09PSBtb2RlbENsYXNzXG4gICAgKVxuICAgIC8vIEluaXRpYWxpemUgdGhlIGFkZGVkIG1vZGVscyBpbiBjb3JyZWN0IHNvcnRlZCBzZXF1ZW5jZSwgc28gdGhhdCBmb3IgZXZlcnlcbiAgICAvLyBtb2RlbCwgZ2V0UmVsYXRlZFJlbGF0aW9ucygpIHJldHVybnMgdGhlIGZ1bGwgbGlzdCBvZiByZWxhdGluZyByZWxhdGlvbnMuXG4gICAgZm9yIChjb25zdCBtb2RlbENsYXNzIG9mIHNvcnRlZE1vZGVscykge1xuICAgICAgaWYgKG1vZGVsc1ttb2RlbENsYXNzLm5hbWVdID09PSBtb2RlbENsYXNzKSB7XG4gICAgICAgIG1vZGVsQ2xhc3Muc2V0dXAodGhpcy5rbmV4KVxuICAgICAgICAvLyBOb3cgdGhhdCB0aGUgbW9kZWxDbGFzcyBpcyBzZXQgdXAsIGNhbGwgYGluaXRpYWxpemUoKWAsIHdoaWNoIGNhbiBiZVxuICAgICAgICAvLyBvdmVycmlkZGVuIGJ5IHN1Yi1jbGFzc2VzLHdpdGhvdXQgaGF2aW5nIHRvIGNhbGwgYHN1cGVyLmluaXRpYWxpemUoKWBcbiAgICAgICAgbW9kZWxDbGFzcy5pbml0aWFsaXplKClcbiAgICAgICAgdGhpcy52YWxpZGF0b3IuYWRkU2NoZW1hKG1vZGVsQ2xhc3MuZ2V0SnNvblNjaGVtYSgpKVxuICAgICAgfVxuICAgIH1cbiAgICBjb25zdCB7IGxvZyB9ID0gdGhpcy5jb25maWdcbiAgICBpZiAobG9nLnNjaGVtYSB8fCBsb2cucmVsYXRpb25zKSB7XG4gICAgICBmb3IgKGNvbnN0IG1vZGVsQ2xhc3Mgb2Ygc29ydGVkTW9kZWxzKSB7XG4gICAgICAgIGNvbnN0IHNob3VsZExvZyA9IG9wdGlvbiA9PiAoXG4gICAgICAgICAgb3B0aW9uID09PSB0cnVlIHx8XG4gICAgICAgICAgYXNBcnJheShvcHRpb24pLmluY2x1ZGVzKG1vZGVsQ2xhc3MubmFtZSlcbiAgICAgICAgKVxuICAgICAgICBjb25zdCBkYXRhID0ge31cbiAgICAgICAgaWYgKHNob3VsZExvZyhsb2cuc2NoZW1hKSkge1xuICAgICAgICAgIGRhdGEuc2NoZW1hID0gbW9kZWxDbGFzcy5nZXRKc29uU2NoZW1hKClcbiAgICAgICAgfVxuICAgICAgICBpZiAoc2hvdWxkTG9nKGxvZy5yZWxhdGlvbnMpKSB7XG4gICAgICAgICAgZGF0YS5yZWxhdGlvbnMgPSBjbG9uZShtb2RlbENsYXNzLnJlbGF0aW9uTWFwcGluZ3MsIHZhbHVlID0+XG4gICAgICAgICAgICBNb2RlbC5pc1Byb3RvdHlwZU9mKHZhbHVlKSA/IGBbTW9kZWw6ICR7dmFsdWUubmFtZX1dYCA6IHZhbHVlXG4gICAgICAgICAgKVxuICAgICAgICB9XG4gICAgICAgIGlmIChPYmplY3Qua2V5cyhkYXRhKS5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgY29uc29sZS5pbmZvKFxuICAgICAgICAgICAgcGljby55ZWxsb3cuYm9sZChgXFxuJHttb2RlbENsYXNzLm5hbWV9OlxcbmApLFxuICAgICAgICAgICAgdXRpbC5pbnNwZWN0KGRhdGEsIHtcbiAgICAgICAgICAgICAgY29sb3JzOiB0cnVlLFxuICAgICAgICAgICAgICBkZXB0aDogbnVsbCxcbiAgICAgICAgICAgICAgbWF4QXJyYXlMZW5ndGg6IG51bGxcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgYWRkTW9kZWwobW9kZWxDbGFzcykge1xuICAgIGlmIChNb2RlbC5pc1Byb3RvdHlwZU9mKG1vZGVsQ2xhc3MpKSB7XG4gICAgICBtb2RlbENsYXNzLmFwcCA9IHRoaXNcbiAgICAgIHRoaXMubW9kZWxzW21vZGVsQ2xhc3MubmFtZV0gPSBtb2RlbENsYXNzXG4gICAgfSBlbHNlIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBtb2RlbCBjbGFzczogJHttb2RlbENsYXNzfWApXG4gICAgfVxuICB9XG5cbiAgc29ydE1vZGVscyhtb2RlbHMpIHtcbiAgICBjb25zdCBzb3J0QnlSZWxhdGlvbnMgPSAobGlzdCwgY29sbGVjdGVkID0ge30sIGV4Y2x1ZGVkID0ge30pID0+IHtcbiAgICAgIGZvciAoY29uc3QgbW9kZWxDbGFzcyBvZiBsaXN0KSB7XG4gICAgICAgIGNvbnN0IHsgbmFtZSB9ID0gbW9kZWxDbGFzc1xuICAgICAgICBpZiAoIWNvbGxlY3RlZFtuYW1lXSAmJiAhZXhjbHVkZWRbbmFtZV0pIHtcbiAgICAgICAgICBmb3IgKGNvbnN0IHJlbGF0aW9uIG9mIE9iamVjdC52YWx1ZXMobW9kZWxDbGFzcy5nZXRSZWxhdGlvbnMoKSkpIHtcbiAgICAgICAgICAgIGlmICghKHJlbGF0aW9uIGluc3RhbmNlb2YgQmVsb25nc1RvT25lUmVsYXRpb24pKSB7XG4gICAgICAgICAgICAgIGNvbnN0IHsgcmVsYXRlZE1vZGVsQ2xhc3MsIGpvaW5UYWJsZU1vZGVsQ2xhc3MgfSA9IHJlbGF0aW9uXG4gICAgICAgICAgICAgIGZvciAoY29uc3QgcmVsYXRlZCBvZiBbam9pblRhYmxlTW9kZWxDbGFzcywgcmVsYXRlZE1vZGVsQ2xhc3NdKSB7XG4gICAgICAgICAgICAgICAgLy8gRXhjbHVkZSBzZWxmLXJlZmVyZW5jZXMgYW5kIGdlbmVyYXRlZCBqb2luIG1vZGVsczpcbiAgICAgICAgICAgICAgICBpZiAocmVsYXRlZCAmJiByZWxhdGVkICE9PSBtb2RlbENsYXNzICYmIG1vZGVsc1tyZWxhdGVkLm5hbWVdKSB7XG4gICAgICAgICAgICAgICAgICBzb3J0QnlSZWxhdGlvbnMoW3JlbGF0ZWRdLCBjb2xsZWN0ZWQsIHtcbiAgICAgICAgICAgICAgICAgICAgLy8gRXhjbHVkZSBtb2RlbENsYXNzIHRvIHByZXZlbnQgZW5kbGVzcyByZWN1cnNpb25zOlxuICAgICAgICAgICAgICAgICAgICBbbmFtZV06IG1vZGVsQ2xhc3MsXG4gICAgICAgICAgICAgICAgICAgIC4uLmV4Y2x1ZGVkXG4gICAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgICBjb2xsZWN0ZWRbbmFtZV0gPSBtb2RlbENsYXNzXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICAgIHJldHVybiBPYmplY3QudmFsdWVzKGNvbGxlY3RlZClcbiAgICB9XG4gICAgLy8gUmV0dXJuIGEgbmV3IG9iamVjdCB3aXRoIHRoZSBzb3J0ZWQgbW9kZWxzIGFzIGl0cyBrZXkvdmFsdWUgcGFpcnMuXG4gICAgLy8gTk9URTogV2UgbmVlZCB0byByZXZlcnNlIGZvciB0aGUgYWJvdmUgYWxnb3JpdGhtIHRvIHNvcnQgcHJvcGVybHksXG4gICAgLy8gYW5kIHRoZW4gcmV2ZXJzZSB0aGUgcmVzdWx0IGJhY2suXG4gICAgcmV0dXJuIHNvcnRCeVJlbGF0aW9ucyhPYmplY3QudmFsdWVzKG1vZGVscykucmV2ZXJzZSgpKS5yZXZlcnNlKCkucmVkdWNlKFxuICAgICAgKG1vZGVscywgbW9kZWxDbGFzcykgPT4ge1xuICAgICAgICBtb2RlbHNbbW9kZWxDbGFzcy5uYW1lXSA9IG1vZGVsQ2xhc3NcbiAgICAgICAgcmV0dXJuIG1vZGVsc1xuICAgICAgfSxcbiAgICAgIE9iamVjdC5jcmVhdGUobnVsbClcbiAgICApXG4gIH1cblxuICBnZXRNb2RlbChuYW1lKSB7XG4gICAgcmV0dXJuIChcbiAgICAgIHRoaXMubW9kZWxzW25hbWVdIHx8XG4gICAgICAhbmFtZS5lbmRzV2l0aCgnTW9kZWwnKSAmJiB0aGlzLm1vZGVsc1tgJHtuYW1lfU1vZGVsYF0gfHxcbiAgICAgIG51bGxcbiAgICApXG4gIH1cblxuICBmaW5kTW9kZWwoY2FsbGJhY2spIHtcbiAgICByZXR1cm4gT2JqZWN0LnZhbHVlcyh0aGlzLm1vZGVscykuZmluZChjYWxsYmFjaylcbiAgfVxuXG4gIGFkZFNlcnZpY2VzKHNlcnZpY2VzKSB7XG4gICAgZm9yIChjb25zdCBbbmFtZSwgc2VydmljZV0gb2YgT2JqZWN0LmVudHJpZXMoc2VydmljZXMpKSB7XG4gICAgICAvLyBIYW5kbGUgRVM2IG1vZHVsZSB3ZWlyZG5lc3MgdGhhdCBjYW4gaGFwcGVuLCBhcHBhcmVudGx5OlxuICAgICAgaWYgKG5hbWUgPT09ICdkZWZhdWx0JyAmJiBpc1BsYWluT2JqZWN0KHNlcnZpY2UpKSB7XG4gICAgICAgIHRoaXMuYWRkU2VydmljZXMoc2VydmljZSlcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuYWRkU2VydmljZShzZXJ2aWNlLCBuYW1lKVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGFkZFNlcnZpY2Uoc2VydmljZSwgbmFtZSkge1xuICAgIC8vIEF1dG8taW5zdGFudGlhdGUgY29udHJvbGxlciBjbGFzc2VzOlxuICAgIGlmIChTZXJ2aWNlLmlzUHJvdG90eXBlT2Yoc2VydmljZSkpIHtcbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuZXctY2FwXG4gICAgICBzZXJ2aWNlID0gbmV3IHNlcnZpY2UodGhpcywgbmFtZSlcbiAgICB9XG4gICAgaWYgKCEoc2VydmljZSBpbnN0YW5jZW9mIFNlcnZpY2UpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgc2VydmljZTogJHtzZXJ2aWNlfWApXG4gICAgfVxuICAgIC8vIE9ubHkgYWZ0ZXIgdGhlIGNvbnN0cnVjdG9yIGlzIGNhbGxlZCwgYHNlcnZpY2UubmFtZWAgaXMgZ3VhcmFudGVlZCB0byBiZVxuICAgIC8vIHNldCB0byB0aGUgY29ycmVjdCB2YWx1ZSwgZS5nLiB3aXRoIGFuIGFmdGVyLWNvbnN0cnVjdG9yIGNsYXNzIHByb3BlcnR5LlxuICAgICh7IG5hbWUgfSA9IHNlcnZpY2UpXG4gICAgY29uc3QgY29uZmlnID0gdGhpcy5jb25maWcuc2VydmljZXNbbmFtZV1cbiAgICBpZiAoY29uZmlnID09PSB1bmRlZmluZWQpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgQ29uZmlndXJhdGlvbiBtaXNzaW5nIGZvciBzZXJ2aWNlICcke25hbWV9J2ApXG4gICAgfVxuICAgIC8vIEFzIGEgY29udmVudGlvbiwgdGhlIGNvbmZpZ3VyYXRpb24gb2YgYSBzZXJ2aWNlIGNhbiBiZSBzZXQgdG8gYGZhbHNlYFxuICAgIC8vIGluIG9yZGVyIHRvIGVudGlyZWx5IGRlYWN0aXZhdGUgdGhlIHNlcnZpY2UuXG4gICAgaWYgKGNvbmZpZyAhPT0gZmFsc2UpIHtcbiAgICAgIHNlcnZpY2Uuc2V0dXAoY29uZmlnKVxuICAgICAgdGhpcy5zZXJ2aWNlc1tuYW1lXSA9IHNlcnZpY2VcbiAgICAgIC8vIE5vdyB0aGF0IHRoZSBzZXJ2aWNlIGlzIHNldCB1cCwgY2FsbCBgaW5pdGlhbGl6ZSgpYCB3aGljaCBjYW4gYmVcbiAgICAgIC8vIG92ZXJyaWRkZW4gYnkgc2VydmljZXMuXG4gICAgICBzZXJ2aWNlLmluaXRpYWxpemUoKVxuICAgIH1cbiAgfVxuXG4gIGdldFNlcnZpY2UobmFtZSkge1xuICAgIHJldHVybiB0aGlzLnNlcnZpY2VzW25hbWVdIHx8IG51bGxcbiAgfVxuXG4gIGZpbmRTZXJ2aWNlKGNhbGxiYWNrKSB7XG4gICAgcmV0dXJuIE9iamVjdC52YWx1ZXModGhpcy5zZXJ2aWNlcykuZmluZChjYWxsYmFjaylcbiAgfVxuXG4gIGZvckVhY2hTZXJ2aWNlKGNhbGxiYWNrKSB7XG4gICAgcmV0dXJuIFByb21pc2UuYWxsKE9iamVjdC52YWx1ZXModGhpcy5zZXJ2aWNlcykubWFwKGNhbGxiYWNrKSlcbiAgfVxuXG4gIGFkZENvbnRyb2xsZXJzKGNvbnRyb2xsZXJzLCBuYW1lc3BhY2UpIHtcbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhjb250cm9sbGVycykpIHtcbiAgICAgIGlmIChpc1BsYWluT2JqZWN0KHZhbHVlKSkge1xuICAgICAgICB0aGlzLmFkZENvbnRyb2xsZXJzKHZhbHVlLCBuYW1lc3BhY2UgPyBgJHtuYW1lc3BhY2V9LyR7a2V5fWAgOiBrZXkpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICB0aGlzLmFkZENvbnRyb2xsZXIodmFsdWUsIG5hbWVzcGFjZSlcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBhZGRDb250cm9sbGVyKGNvbnRyb2xsZXIsIG5hbWVzcGFjZSkge1xuICAgIC8vIENvbnRyb2xsZXJzIHJlcXVpcmUgYWRkaXRpb25hbCBtaWRkbGV3YXJlIHRvIGJlIGluc3RhbGxlZCBvbmNlLlxuICAgIHRoaXMuc2V0dXBDb250cm9sbGVyTWlkZGxld2FyZSgpXG4gICAgLy8gQXV0by1pbnN0YW50aWF0ZSBjb250cm9sbGVyIGNsYXNzZXM6XG4gICAgaWYgKENvbnRyb2xsZXIuaXNQcm90b3R5cGVPZihjb250cm9sbGVyKSkge1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5ldy1jYXBcbiAgICAgIGNvbnRyb2xsZXIgPSBuZXcgY29udHJvbGxlcih0aGlzLCBuYW1lc3BhY2UpXG4gICAgfVxuICAgIGlmICghKGNvbnRyb2xsZXIgaW5zdGFuY2VvZiBDb250cm9sbGVyKSkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIGNvbnRyb2xsZXI6ICR7Y29udHJvbGxlcn1gKVxuICAgIH1cbiAgICAvLyBJbmhlcml0YW5jZSBvZiBhY3Rpb24gbWV0aG9kcyBjYW5ub3QgaGFwcGVuIGluIHRoZSBjb25zdHJ1Y3RvciBpdHNlbGYsXG4gICAgLy8gc28gY2FsbCBzZXBhcmF0ZSBgc2V0dXAoKWAgbWV0aG9kIGFmdGVyIGluIG9yZGVyIHRvIHRha2UgY2FyZSBvZiBpdC5cbiAgICBjb250cm9sbGVyLnNldHVwKClcbiAgICB0aGlzLmNvbnRyb2xsZXJzW2NvbnRyb2xsZXIudXJsXSA9IGNvbnRyb2xsZXJcbiAgICAvLyBOb3cgdGhhdCB0aGUgY29udHJvbGxlciBpcyBzZXQgdXAsIGNhbGwgYGluaXRpYWxpemUoKWAgd2hpY2ggY2FuIGJlXG4gICAgLy8gb3ZlcnJpZGRlbiBieSBjb250cm9sbGVycy5cbiAgICBjb250cm9sbGVyLmluaXRpYWxpemUoKVxuICAgIC8vIEVhY2ggY29udHJvbGxlciBjYW4gYWxzbyBwcm92aWRlIGZ1cnRoZXIgbWlkZGxld2FyZSwgZS5nLlxuICAgIC8vIGBBZG1pbkNvbnRyb2xsZXJgOlxuICAgIGNvbnN0IG1pZGRsZXdhcmUgPSBjb250cm9sbGVyLmNvbXBvc2UoKVxuICAgIGlmIChtaWRkbGV3YXJlKSB7XG4gICAgICB0aGlzLnVzZShtaWRkbGV3YXJlKVxuICAgIH1cbiAgfVxuXG4gIGdldENvbnRyb2xsZXIodXJsKSB7XG4gICAgcmV0dXJuIHRoaXMuY29udHJvbGxlcnNbdXJsXSB8fCBudWxsXG4gIH1cblxuICBmaW5kQ29udHJvbGxlcihjYWxsYmFjaykge1xuICAgIHJldHVybiBPYmplY3QudmFsdWVzKHRoaXMuY29udHJvbGxlcnMpLmZpbmQoY2FsbGJhY2spXG4gIH1cblxuICBnZXRBZG1pbkNvbnRyb2xsZXIoKSB7XG4gICAgcmV0dXJuIHRoaXMuZmluZENvbnRyb2xsZXIoXG4gICAgICBjb250cm9sbGVyID0+IGNvbnRyb2xsZXIgaW5zdGFuY2VvZiBBZG1pbkNvbnRyb2xsZXJcbiAgICApXG4gIH1cblxuICBnZXRBZG1pblZ1ZUNvbmZpZygpIHtcbiAgICByZXR1cm4gdGhpcy5nZXRBZG1pbkNvbnRyb2xsZXIoKT8uZ2V0VnVlQ29uZmlnKCkgfHwgbnVsbFxuICB9XG5cbiAgZ2V0QXNzZXRDb25maWcoe1xuICAgIG1vZGVscyA9IE9iamVjdC5rZXlzKHRoaXMubW9kZWxzKSxcbiAgICBub3JtYWxpemVEYk5hbWVzID0gdGhpcy5jb25maWcua25leC5ub3JtYWxpemVEYk5hbWVzXG4gIH0gPSB7fSkge1xuICAgIGNvbnN0IGFzc2V0Q29uZmlnID0ge31cbiAgICBmb3IgKGNvbnN0IG1vZGVsTmFtZSBvZiBtb2RlbHMpIHtcbiAgICAgIGNvbnN0IG1vZGVsQ2xhc3MgPSB0aGlzLm1vZGVsc1ttb2RlbE5hbWVdXG4gICAgICBjb25zdCB7IGFzc2V0cyB9ID0gbW9kZWxDbGFzcy5kZWZpbml0aW9uXG4gICAgICBpZiAoYXNzZXRzKSB7XG4gICAgICAgIGNvbnN0IG5vcm1hbGl6ZWRNb2RlbE5hbWUgPSBub3JtYWxpemVEYk5hbWVzXG4gICAgICAgICAgPyB0aGlzLm5vcm1hbGl6ZUlkZW50aWZpZXIobW9kZWxOYW1lKVxuICAgICAgICAgIDogbW9kZWxOYW1lXG4gICAgICAgIGNvbnN0IGNvbnZlcnRlZEFzc2V0cyA9IHt9XG4gICAgICAgIGZvciAoY29uc3QgW2Fzc2V0RGF0YVBhdGgsIGNvbmZpZ10gb2YgT2JqZWN0LmVudHJpZXMoYXNzZXRzKSkge1xuICAgICAgICAgIGNvbnN0IHtcbiAgICAgICAgICAgIHByb3BlcnR5LFxuICAgICAgICAgICAgbmVzdGVkRGF0YVBhdGgsXG4gICAgICAgICAgICBuYW1lLFxuICAgICAgICAgICAgaW5kZXhcbiAgICAgICAgICB9ID0gbW9kZWxDbGFzcy5nZXRQcm9wZXJ0eU9yUmVsYXRpb25BdERhdGFQYXRoKGFzc2V0RGF0YVBhdGgpXG4gICAgICAgICAgaWYgKHByb3BlcnR5ICYmIGluZGV4ID09PSAwKSB7XG4gICAgICAgICAgICBjb25zdCBub3JtYWxpemVkTmFtZSA9IG5vcm1hbGl6ZURiTmFtZXNcbiAgICAgICAgICAgICAgPyB0aGlzLm5vcm1hbGl6ZUlkZW50aWZpZXIobmFtZSlcbiAgICAgICAgICAgICAgOiBuYW1lXG4gICAgICAgICAgICBjb25zdCBkYXRhUGF0aCA9IG5vcm1hbGl6ZURhdGFQYXRoKFtcbiAgICAgICAgICAgICAgbm9ybWFsaXplZE5hbWUsXG4gICAgICAgICAgICAgIC4uLnBhcnNlRGF0YVBhdGgobmVzdGVkRGF0YVBhdGgpXG4gICAgICAgICAgICBdKVxuICAgICAgICAgICAgY29uc3QgYXNzZXRDb25maWdzID0gY29udmVydGVkQXNzZXRzW25vcm1hbGl6ZWROYW1lXSB8fD0ge31cbiAgICAgICAgICAgIGFzc2V0Q29uZmlnc1tkYXRhUGF0aF0gPSBjb25maWdcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgdGhyb3cgbmV3IEVycm9yKCdOZXN0ZWQgZ3JhcGggcHJvcGVydGllcyBhcmUgbm90IHN1cHBvcnRlZCB5ZXQnKVxuICAgICAgICAgIH1cbiAgICAgICAgfVxuICAgICAgICBhc3NldENvbmZpZ1tub3JtYWxpemVkTW9kZWxOYW1lXSA9IGNvbnZlcnRlZEFzc2V0c1xuICAgICAgfVxuICAgIH1cbiAgICByZXR1cm4gYXNzZXRDb25maWdcbiAgfVxuXG4gIGFkZFN0b3JhZ2VzKHN0b3JhZ2VzKSB7XG4gICAgZm9yIChjb25zdCBbbmFtZSwgY29uZmlnXSBvZiBPYmplY3QuZW50cmllcyhzdG9yYWdlcykpIHtcbiAgICAgIHRoaXMuYWRkU3RvcmFnZShjb25maWcsIG5hbWUpXG4gICAgfVxuICB9XG5cbiAgYWRkU3RvcmFnZShjb25maWcsIG5hbWUpIHtcbiAgICBsZXQgc3RvcmFnZSA9IG51bGxcbiAgICBpZiAoaXNQbGFpbk9iamVjdChjb25maWcpKSB7XG4gICAgICBjb25zdCBzdG9yYWdlQ2xhc3MgPSBTdG9yYWdlLmdldChjb25maWcudHlwZSlcbiAgICAgIGlmICghc3RvcmFnZUNsYXNzKSB7XG4gICAgICAgIHRocm93IG5ldyBFcnJvcihgVW5zdXBwb3J0ZWQgc3RvcmFnZTogJHtjb25maWd9YClcbiAgICAgIH1cbiAgICAgIC8vIGVzbGludC1kaXNhYmxlLW5leHQtbGluZSBuZXctY2FwXG4gICAgICBzdG9yYWdlID0gbmV3IHN0b3JhZ2VDbGFzcyh0aGlzLCBjb25maWcpXG4gICAgfSBlbHNlIGlmIChjb25maWcgaW5zdGFuY2VvZiBTdG9yYWdlKSB7XG4gICAgICBzdG9yYWdlID0gY29uZmlnXG4gICAgfVxuICAgIGlmIChzdG9yYWdlKSB7XG4gICAgICBpZiAobmFtZSkge1xuICAgICAgICBzdG9yYWdlLm5hbWUgPSBuYW1lXG4gICAgICB9XG4gICAgICB0aGlzLnN0b3JhZ2VzW3N0b3JhZ2UubmFtZV0gPSBzdG9yYWdlXG4gICAgfVxuICAgIHJldHVybiBzdG9yYWdlXG4gIH1cblxuICBnZXRTdG9yYWdlKG5hbWUpIHtcbiAgICByZXR1cm4gdGhpcy5zdG9yYWdlc1tuYW1lXSB8fCBudWxsXG4gIH1cblxuICBjb21waWxlVmFsaWRhdG9yKGpzb25TY2hlbWEsIG9wdGlvbnMpIHtcbiAgICByZXR1cm4ganNvblNjaGVtYVxuICAgICAgPyB0aGlzLnZhbGlkYXRvci5jb21waWxlKGpzb25TY2hlbWEsIG9wdGlvbnMpXG4gICAgICA6IG51bGxcbiAgfVxuXG4gIGNvbXBpbGVQYXJhbWV0ZXJzVmFsaWRhdG9yKHBhcmFtZXRlcnMsIG9wdGlvbnMgPSB7fSkge1xuICAgIGNvbnN0IGxpc3QgPSBbXVxuICAgIGNvbnN0IHsgZGF0YU5hbWUgPSAnZGF0YScgfSA9IG9wdGlvbnNcblxuICAgIGxldCBwcm9wZXJ0aWVzID0gbnVsbFxuICAgIGNvbnN0IGFkZFBhcmFtZXRlciA9IChuYW1lLCBzY2hlbWEpID0+IHtcbiAgICAgIGxpc3QucHVzaCh7XG4gICAgICAgIG5hbWU6IG5hbWUgPz8gbnVsbCxcbiAgICAgICAgLi4uc2NoZW1hXG4gICAgICB9KVxuICAgICAgaWYgKCFzY2hlbWEubWVtYmVyKSB7XG4gICAgICAgIHByb3BlcnRpZXMgfHw9IHt9XG4gICAgICAgIHByb3BlcnRpZXNbbmFtZSB8fCBkYXRhTmFtZV0gPSBzY2hlbWFcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBTdXBwb3J0IHR3byBmb3JtYXRzIG9mIHBhcmFtZXRlcnMgZGVmaW5pdGlvbnM6XG4gICAgLy8gLSBBbiBhcnJheSBvZiBwYXJhbWV0ZXIgc2NoZW1hcywgbmFtZWQgYnkgdGhlaXIgYG5hbWVgIGtleS5cbiAgICAvLyAtIEFuIG9iamVjdCBvZiBwYXJhbWV0ZXIgc2NoZW1hcywgbmFtZWQgYnkgdGhlIGtleSB1bmRlciB3aGljaCBlYWNoXG4gICAgLy8gICBzY2hlbWEgaXMgc3RvcmVkIGluIHRoZSByb290IG9iamVjdC5cbiAgICAvLyBJZiBhbiBhcnJheSBpcyBwYXNzZWQsIHRoZW4gdGhlIGNvbnRyb2xsZXIgYWN0aW9ucyByZWNlaXZlcyB0aGVcbiAgICAvLyBwYXJhbWV0ZXJzIGFzIHNlcGFyYXRlIGFyZ3VtZW50cy4gSWYgYW4gb2JqZWN0IGlzIHBhc3NlZCwgdGhlbiB0aGVcbiAgICAvLyBhY3Rpb25zIHJlY2VpdmVzIG9uZSBwYXJhbWV0ZXIgb2JqZWN0IHdoZXJlIHVuZGVyIHRoZSBzYW1lIGtleXMgdGhlXG4gICAgLy8gc3BlY2lmaWVkIHBhcmFtZXRlciB2YWx1ZXMgYXJlIHN0b3JlZC5cbiAgICBsZXQgYXNPYmplY3QgPSBmYWxzZVxuICAgIGlmIChpc0FycmF5KHBhcmFtZXRlcnMpKSB7XG4gICAgICBmb3IgKGNvbnN0IHsgbmFtZSwgLi4uc2NoZW1hIH0gb2YgcGFyYW1ldGVycykge1xuICAgICAgICBhZGRQYXJhbWV0ZXIobmFtZSwgc2NoZW1hKVxuICAgICAgfVxuICAgIH0gZWxzZSBpZiAoaXNPYmplY3QocGFyYW1ldGVycykpIHtcbiAgICAgIGFzT2JqZWN0ID0gdHJ1ZVxuICAgICAgZm9yIChjb25zdCBbbmFtZSwgc2NoZW1hXSBvZiBPYmplY3QuZW50cmllcyhwYXJhbWV0ZXJzKSkge1xuICAgICAgICBpZiAoc2NoZW1hKSB7XG4gICAgICAgICAgYWRkUGFyYW1ldGVyKG5hbWUsIHNjaGVtYSlcbiAgICAgICAgfVxuICAgICAgfVxuICAgIH0gZWxzZSBpZiAocGFyYW1ldGVycykge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIHBhcmFtZXRlcnMgZGVmaW5pdGlvbjogJHtwYXJhbWV0ZXJzfWApXG4gICAgfVxuICAgIC8vIE5PVEU6IElmIHByb3BlcnRpZXMgaXMgbnVsbCwgc2NoZW1hIGFuZCB2YWxpZGF0ZSB3aWxsIGJlY29tZSBudWxsIHRvby5cbiAgICAvLyBOT1RFOiBJZiBpdCBpcyBub3QgbnVsbCwgaXQgd2lsbCBnZXQgZXhwYW5kZWQgdG8gYW4gb2JqZWN0IHNjaGVtYS5cbiAgICBjb25zdCBzY2hlbWEgPSBjb252ZXJ0U2NoZW1hKHByb3BlcnRpZXMsIG9wdGlvbnMpXG4gICAgY29uc3QgdmFsaWRhdGUgPSB0aGlzLmNvbXBpbGVWYWxpZGF0b3Ioc2NoZW1hLCB7XG4gICAgICAvLyBGb3IgcGFyYW1ldGVycywgYWx3YXlzIGNvZXJjZSB0eXBlcywgaW5jbHVkaW5nIGFycmF5cy5cbiAgICAgIGNvZXJjZVR5cGVzOiAnYXJyYXknLFxuICAgICAgLi4ub3B0aW9uc1xuICAgIH0pXG4gICAgY29uc3QgY3R4ID0ge1xuICAgICAgYXBwOiB0aGlzLFxuICAgICAgdmFsaWRhdG9yOiB0aGlzLnZhbGlkYXRvcixcbiAgICAgIG9wdGlvbnNcbiAgICB9XG4gICAgcmV0dXJuIHtcbiAgICAgIGxpc3QsXG4gICAgICBzY2hlbWEsXG4gICAgICBhc09iamVjdCxcbiAgICAgIGRhdGFOYW1lLFxuICAgICAgdmFsaWRhdGU6IHZhbGlkYXRlXG4gICAgICAgIC8vIFVzZSBgY2FsbCgpYCB0byBwYXNzIGN0eCBhcyBjb250ZXh0IHRvIEFqdiwgc2VlIHBhc3NDb250ZXh0OlxuICAgICAgICA/IGRhdGEgPT4gdmFsaWRhdGUuY2FsbChjdHgsIGRhdGEpXG4gICAgICAgIDogbnVsbFxuICAgIH1cbiAgfVxuXG4gIGNyZWF0ZVZhbGlkYXRpb25FcnJvcih7IHR5cGUsIG1lc3NhZ2UsIGVycm9ycywgb3B0aW9ucywganNvbiB9KSB7XG4gICAgcmV0dXJuIG5ldyBWYWxpZGF0aW9uRXJyb3Ioe1xuICAgICAgdHlwZSxcbiAgICAgIG1lc3NhZ2UsXG4gICAgICBlcnJvcnM6IHRoaXMudmFsaWRhdG9yLnBhcnNlRXJyb3JzKGVycm9ycywgb3B0aW9ucyksXG4gICAgICAvLyBPbmx5IGluY2x1ZGUgdGhlIEpTT04gZGF0YSBpbiB0aGUgZXJyb3IgaWYgYGxvZy5lcnJvcnMuanNvbmBpcyBzZXQuXG4gICAgICBqc29uOiB0aGlzLmNvbmZpZy5sb2cuZXJyb3JzPy5qc29uID8ganNvbiA6IHVuZGVmaW5lZFxuICAgIH0pXG4gIH1cblxuICBjcmVhdGVEYXRhYmFzZUVycm9yKGVycm9yKSB7XG4gICAgLy8gUmVtb3ZlIGtuZXggU1FMIHF1ZXJ5IGFuZCBtb3ZlIHRvIHNlcGFyYXRlIGBzcWxgIHByb3BlcnR5LlxuICAgIC8vIFRPRE86IEZpeCB0aGlzIHByb3Blcmx5IGluIEtuZXggLyBPYmplY3Rpb24gaW5zdGVhZCwgc2VlOlxuICAgIC8vIGh0dHBzOi8vZ2l0dGVyLmltL1ZpbmNpdC9vYmplY3Rpb24uanM/YXQ9NWE2ODcyOGY1YTllYmU0Zjc1Y2E0MGIwXG4gICAgY29uc3QgWywgc3FsLCBtZXNzYWdlXSA9IGVycm9yLm1lc3NhZ2UubWF0Y2goL14oW1xcc1xcU10qKSAtIChbXFxzXFxTXSo/KSQvKSB8fFxuICAgICAgW251bGwsIG51bGwsIGVycm9yLm1lc3NhZ2VdXG4gICAgcmV0dXJuIG5ldyBEYXRhYmFzZUVycm9yKGVycm9yLCB7XG4gICAgICBtZXNzYWdlLFxuICAgICAgLy8gT25seSBpbmNsdWRlIHRoZSBTUUwgcXVlcnkgaW4gdGhlIGVycm9yIGlmIGBsb2cuZXJyb3JzLnNxbGBpcyBzZXQuXG4gICAgICBzcWw6IHRoaXMuY29uZmlnLmxvZy5lcnJvcnM/LnNxbCA/IHNxbCA6IHVuZGVmaW5lZFxuICAgIH0pXG4gIH1cblxuICBzZXR1cEdsb2JhbE1pZGRsZXdhcmUoKSB7XG4gICAgY29uc3QgeyBhcHAsIGxvZyB9ID0gdGhpcy5jb25maWdcblxuICAgIHRoaXMudXNlKGF0dGFjaExvZ2dlcih0aGlzLmxvZ2dlcikpXG5cbiAgICBpZiAoYXBwLnJlc3BvbnNlVGltZSAhPT0gZmFsc2UpIHtcbiAgICAgIHRoaXMudXNlKHJlc3BvbnNlVGltZShnZXRPcHRpb25zKGFwcC5yZXNwb25zZVRpbWUpKSlcbiAgICB9XG4gICAgaWYgKGxvZy5yZXF1ZXN0cykge1xuICAgICAgdGhpcy51c2UobG9nUmVxdWVzdHMoKSlcbiAgICB9XG4gICAgLy8gTmVlZHMgdG8gYmUgcG9zaXRpb25lZCBhZnRlciB0aGUgcmVxdWVzdCBsb2dnZXIgdG8gbG9nIHRoZSBjb3JyZWN0XG4gICAgLy8gcmVzcG9uc2Ugc3RhdHVzLlxuICAgIHRoaXMudXNlKGhhbmRsZUVycm9yKCkpXG4gICAgaWYgKGFwcC5oZWxtZXQgIT09IGZhbHNlKSB7XG4gICAgICB0aGlzLnVzZShoZWxtZXQoZ2V0T3B0aW9ucyhhcHAuaGVsbWV0KSkpXG4gICAgfVxuICAgIGlmIChhcHAuY29ycyAhPT0gZmFsc2UpIHtcbiAgICAgIHRoaXMudXNlKGNvcnMoZ2V0T3B0aW9ucyhhcHAuY29ycykpKVxuICAgIH1cbiAgICBpZiAoYXBwLmNvbXByZXNzICE9PSBmYWxzZSkge1xuICAgICAgdGhpcy51c2UoY29tcHJlc3MobWVyZ2UoXG4gICAgICAgIHtcbiAgICAgICAgICAvLyBVc2UgYSByZWFzb25hYmxlIGRlZmF1bHQgZm9yIEJyb3RsaSBjb21wcmVzc2lvbi5cbiAgICAgICAgICAvLyBTZWUgaHR0cHM6Ly9naXRodWIuY29tL2tvYWpzL2NvbXByZXNzL2lzc3Vlcy8xMjZcbiAgICAgICAgICBicjoge1xuICAgICAgICAgICAgcGFyYW1zOiB7XG4gICAgICAgICAgICAgIFt6bGliLmNvbnN0YW50cy5CUk9UTElfUEFSQU1fUVVBTElUWV06IDRcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0sXG4gICAgICAgIGdldE9wdGlvbnMoYXBwLmNvbXByZXNzKVxuICAgICAgKSkpXG4gICAgfVxuICAgIGlmIChhcHAuZXRhZyAhPT0gZmFsc2UpIHtcbiAgICAgIHRoaXMudXNlKGNvbmRpdGlvbmFsKCkpXG4gICAgICB0aGlzLnVzZShldGFnKCkpXG4gICAgfVxuICB9XG5cbiAgc2V0dXBDb250cm9sbGVyTWlkZGxld2FyZSgpIHtcbiAgICAvLyBOT1RFOiBUaGlzIGlzIG5vdCBwYXJ0IG9mIHRoZSBhdXRvbWF0aWMgYHNldHVwR2xvYmFsTWlkZGxld2FyZSgpYCBzbyB0aGF0XG4gICAgLy8gYXBwcyBjYW4gc2V0IHVwIHRoZSBzdGF0aWMgc2VydmluZyBvZiBhc3NldHMgYmVmb3JlIGluc3RhbGxpbmcgdGhlXG4gICAgLy8gc2Vzc2lvbiBhbmQgcGFzc3BvcnQgbWlkZGxld2FyZS4gSXQgaXMgY2FsbGVkIGZyb20gYGFkZENvbnRyb2xsZXIoKWAuXG4gICAgLy8gVXNlIGEgZmxhZyB0byBvbmx5IGluc3RhbGwgdGhlIG1pZGRsZXdhcmUgb25jZTpcbiAgICBpZiAoIXRoaXMuaGFzQ29udHJvbGxlck1pZGRsZXdhcmUpIHtcbiAgICAgIGNvbnN0IHsgYXBwIH0gPSB0aGlzLmNvbmZpZ1xuICAgICAgLy8gU2VxdWVuY2UgaXMgaW1wb3J0YW50OlxuICAgICAgLy8gMS4gYm9keSBwYXJzZXJcbiAgICAgIHRoaXMudXNlKGJvZHlQYXJzZXIoZ2V0T3B0aW9ucyhhcHAuYm9keVBhcnNlcikpKVxuICAgICAgLy8gMi4gZmluZCByb3V0ZSBmcm9tIHJvdXRlcyBpbnN0YWxsZWQgYnkgY29udHJvbGxlcnMuXG4gICAgICB0aGlzLnVzZShmaW5kUm91dGUodGhpcy5yb3V0ZXIpKVxuICAgICAgLy8gMy4gcmVzcGVjdCB0cmFuc2FjdGVkIHNldHRpbmdzLCBjcmVhdGUgYW5kIGhhbmRsZSB0cmFuc2FjdGlvbnMuXG4gICAgICB0aGlzLnVzZShjcmVhdGVUcmFuc2FjdGlvbigpKVxuICAgICAgLy8gNC4gc2Vzc2lvblxuICAgICAgaWYgKGFwcC5zZXNzaW9uKSB7XG4gICAgICAgIGNvbnN0IHtcbiAgICAgICAgICBtb2RlbENsYXNzLFxuICAgICAgICAgIC4uLm9wdGlvbnNcbiAgICAgICAgfSA9IGdldE9wdGlvbnMoYXBwLnNlc3Npb24pXG4gICAgICAgIGlmIChtb2RlbENsYXNzKSB7XG4gICAgICAgICAgLy8gQ3JlYXRlIGEgQ29udGV4dFN0b3JlIHRoYXQgcmVzb2x2ZWQgdGhlIHNwZWNpZmllZCBtb2RlbCBjbGFzcyxcbiAgICAgICAgICAvLyB1c2VzIGl0IHRvIHBlcnNpc3QgYW5kIHJldHJpZXZlIHRoZSBzZXNzaW9uLCBhbmQgYXV0b21hdGljYWxseVxuICAgICAgICAgIC8vIGJpbmRzIGFsbCBkYiBvcGVyYXRpb25zIHRvIGBjdHgudHJhbnNhY3Rpb25gLCBpZiBpdCBpcyBzZXQuXG4gICAgICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5ldy1jYXBcbiAgICAgICAgICBvcHRpb25zLkNvbnRleHRTdG9yZSA9IFNlc3Npb25TdG9yZShtb2RlbENsYXNzKVxuICAgICAgICB9XG4gICAgICAgIHRoaXMudXNlKHNlc3Npb24ob3B0aW9ucywgdGhpcykpXG4gICAgICB9XG4gICAgICAvLyA1LiBwYXNzcG9ydFxuICAgICAgaWYgKGFwcC5wYXNzcG9ydCkge1xuICAgICAgICB0aGlzLnVzZShwYXNzcG9ydC5pbml0aWFsaXplKCkpXG4gICAgICAgIGlmIChhcHAuc2Vzc2lvbikge1xuICAgICAgICAgIHRoaXMudXNlKHBhc3Nwb3J0LnNlc3Npb24oKSlcbiAgICAgICAgfVxuICAgICAgICB0aGlzLnVzZShoYW5kbGVVc2VyKCkpXG4gICAgICB9XG5cbiAgICAgIC8vIDYuIGZpbmFsbHkgaGFuZGxlIHRoZSBmb3VuZCByb3V0ZSwgb3Igc2V0IHN0YXR1cyAvIGFsbG93IGFjY29yZGluZ2x5LlxuICAgICAgdGhpcy51c2UoaGFuZGxlUm91dGUoKSlcbiAgICAgIHRoaXMuaGFzQ29udHJvbGxlck1pZGRsZXdhcmUgPSB0cnVlXG4gICAgfVxuICB9XG5cbiAgc2V0dXBMb2dnZXIoKSB7XG4gICAgY29uc3QgeyBlcnIsIHJlcSwgcmVzIH0gPSBwaW5vLnN0ZFNlcmlhbGl6ZXJzXG4gICAgLy8gT25seSBpbmNsdWRlIGBpZGAgZnJvbSB0aGUgdXNlciwgdG8gbm90IGluYWR2ZXJ0ZW50bHkgbG9nIFBJSS5cbiAgICBjb25zdCB1c2VyID0gdXNlciA9PiAoeyBpZDogdXNlci5pZCB9KVxuICAgIGNvbnN0IHNlcmlhbGl6ZXJzID0geyBlcnIsIHJlcSwgcmVzLCB1c2VyIH1cblxuICAgIGNvbnN0IGxvZ2dlciA9IHBpbm8obWVyZ2UoXG4gICAgICB7XG4gICAgICAgIGxldmVsOiAnaW5mbycsXG4gICAgICAgIHNlcmlhbGl6ZXJzLFxuICAgICAgICBwcmV0dHlQcmludDoge1xuICAgICAgICAgIC8vIExpc3Qgb2Yga2V5cyB0byBpZ25vcmUgaW4gcHJldHR5IG1vZGUuXG4gICAgICAgICAgaWdub3JlOiAncmVxLHJlcyxkdXJhdGlvbk1zLHVzZXIscmVxdWVzdElkJyxcbiAgICAgICAgICAvLyBTWVMgdG8gdXNlIHN5c3RlbSB0aW1lIGFuZCBub3QgVVRDLlxuICAgICAgICAgIHRyYW5zbGF0ZVRpbWU6ICdTWVM6SEg6TU06c3MubCdcbiAgICAgICAgfSxcbiAgICAgICAgLy8gUmVkYWN0IGNvbW1vbiBzZW5zaXRpdmUgaGVhZGVycy5cbiAgICAgICAgcmVkYWN0OiBbXG4gICAgICAgICAgJyouaGVhZGVyc1tcImNvb2tpZVwiXScsXG4gICAgICAgICAgJyouaGVhZGVyc1tcInNldC1jb29raWVcIl0nLFxuICAgICAgICAgICcqLmhlYWRlcnNbXCJhdXRob3JpemF0aW9uXCJdJ1xuICAgICAgICBdLFxuICAgICAgICBiYXNlOiBudWxsIC8vIG5vIHBpZCxob3N0bmFtZSxuYW1lXG4gICAgICB9LFxuICAgICAgZ2V0T3B0aW9ucyh0aGlzLmNvbmZpZy5sb2dnZXIpXG4gICAgKSlcblxuICAgIHRoaXMubG9nZ2VyID0gbG9nZ2VyLmNoaWxkKHsgbmFtZTogJ2FwcCcgfSlcbiAgfVxuXG4gIHNldHVwS25leCgpIHtcbiAgICBsZXQgeyBrbmV4LCBsb2cgfSA9IHRoaXMuY29uZmlnXG4gICAgaWYgKGtuZXg/LmNsaWVudCkge1xuICAgICAgY29uc3Qgc25ha2VDYXNlT3B0aW9ucyA9IGtuZXgubm9ybWFsaXplRGJOYW1lcyA9PT0gdHJ1ZVxuICAgICAgICA/IHt9XG4gICAgICAgIDoga25leC5ub3JtYWxpemVEYk5hbWVzXG4gICAgICBpZiAoc25ha2VDYXNlT3B0aW9ucykge1xuICAgICAgICBrbmV4ID0ge1xuICAgICAgICAgIC4uLmtuZXgsXG4gICAgICAgICAgLi4ua25leFNuYWtlQ2FzZU1hcHBlcnMoc25ha2VDYXNlT3B0aW9ucylcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgdGhpcy5rbmV4ID0gS25leChrbmV4KVxuICAgICAgLy8gU3VwcG9ydCBQb3N0Z3JlU1FMIHR5cGUgcGFyc2VyIG1hcHBpbmdzIGluIHRoZSBjb25maWcuXG4gICAgICBpZiAoa25leC5jbGllbnQgPT09ICdwb3N0Z3Jlc3FsJyAmJiBrbmV4LnR5cGVQYXJzZXJzKSB7XG4gICAgICAgIGZvciAoY29uc3QgW3R5cGUsIHBhcnNlcl0gb2YgT2JqZWN0LmVudHJpZXMoa25leC50eXBlUGFyc2VycykpIHtcbiAgICAgICAgICB0aGlzLmtuZXguY2xpZW50LmRyaXZlci50eXBlcy5zZXRUeXBlUGFyc2VyKHR5cGUsIHBhcnNlcilcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgaWYgKGxvZy5zcWwpIHtcbiAgICAgICAgdGhpcy5zZXR1cEtuZXhMb2dnaW5nKClcbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBzZXR1cEtuZXhMb2dnaW5nKCkge1xuICAgIGNvbnN0IHN0YXJ0VGltZXMgPSB7fVxuICAgIGNvbnN0IGxvZ2dlciA9IHRoaXMubG9nZ2VyLmNoaWxkKHsgbmFtZTogJ3NxbCcgfSlcbiAgICBmdW5jdGlvbiBlbmQocXVlcnksIHsgcmVzcG9uc2UsIGVycm9yIH0pIHtcbiAgICAgIGNvbnN0IGlkID0gcXVlcnkuX19rbmV4UXVlcnlVaWRcbiAgICAgIGNvbnN0IGRpZmYgPSBwcm9jZXNzLmhydGltZShzdGFydFRpbWVzW2lkXSlcbiAgICAgIGNvbnN0IGR1cmF0aW9uID0gZGlmZlswXSAqIDFlMyArIGRpZmZbMV0gLyAxZTZcbiAgICAgIGRlbGV0ZSBzdGFydFRpbWVzW2lkXVxuICAgICAgY29uc3QgeyBzcWwsIGJpbmRpbmdzIH0gPSBxdWVyeVxuICAgICAgcmVzcG9uc2UgPSBPYmplY3QuZnJvbUVudHJpZXMoXG4gICAgICAgIE9iamVjdC5lbnRyaWVzKHJlc3BvbnNlKS5maWx0ZXIoXG4gICAgICAgICAgKFtrZXldKSA9PiAha2V5LnN0YXJ0c1dpdGgoJ18nKVxuICAgICAgICApXG4gICAgICApXG4gICAgICBsb2dnZXIuaW5mbyh7IGR1cmF0aW9uLCBiaW5kaW5ncywgcmVzcG9uc2UsIGVycm9yIH0sIHNxbClcbiAgICB9XG5cbiAgICB0aGlzLmtuZXhcbiAgICAgIC5vbigncXVlcnknLCBxdWVyeSA9PiB7XG4gICAgICAgIHN0YXJ0VGltZXNbcXVlcnkuX19rbmV4UXVlcnlVaWRdID0gcHJvY2Vzcy5ocnRpbWUoKVxuICAgICAgfSlcbiAgICAgIC5vbigncXVlcnktcmVzcG9uc2UnLCAocmVzcG9uc2UsIHF1ZXJ5KSA9PiB7XG4gICAgICAgIGVuZChxdWVyeSwgeyByZXNwb25zZSB9KVxuICAgICAgfSlcbiAgICAgIC5vbigncXVlcnktZXJyb3InLCAoZXJyb3IsIHF1ZXJ5KSA9PiB7XG4gICAgICAgIGVuZChxdWVyeSwgeyBlcnJvciB9KVxuICAgICAgfSlcbiAgfVxuXG4gIG5vcm1hbGl6ZUlkZW50aWZpZXIoaWRlbnRpZmllcikge1xuICAgIHJldHVybiB0aGlzLmtuZXguY2xpZW50LndyYXBJZGVudGlmaWVyKGlkZW50aWZpZXIpLnJlcGxhY2UoL1snYFwiXS9nLCAnJylcbiAgfVxuXG4gIGRlbm9ybWFsaXplSWRlbnRpZmllcihpZGVudGlmaWVyKSB7XG4gICAgY29uc3Qgb2JqID0gdGhpcy5rbmV4LmNsaWVudC5wb3N0UHJvY2Vzc1Jlc3BvbnNlKHsgW2lkZW50aWZpZXJdOiAxIH0pXG4gICAgcmV0dXJuIE9iamVjdC5rZXlzKG9iailbMF1cbiAgfVxuXG4gIG5vcm1hbGl6ZVBhdGgocGF0aCkge1xuICAgIHJldHVybiB0aGlzLmNvbmZpZy5hcHAubm9ybWFsaXplUGF0aHMgPyBoeXBoZW5hdGUocGF0aCkgOiBwYXRoXG4gIH1cblxuICBmb3JtYXRFcnJvcihlcnIpIHtcbiAgICBjb25zdCBtZXNzYWdlID0gZXJyLnRvSlNPTlxuICAgICAgPyBmb3JtYXRKc29uKGVyci50b0pTT04oKSlcbiAgICAgIDogZXJyLm1lc3NhZ2UgfHwgZXJyXG4gICAgY29uc3Qgc3RyID0gYCR7ZXJyLm5hbWV9OiAke21lc3NhZ2V9YFxuICAgIHJldHVybiBlcnIuc3RhY2sgJiYgdGhpcy5jb25maWcubG9nLmVycm9ycz8uc3RhY2sgIT09IGZhbHNlXG4gICAgICA/IGAke3N0cn1cXG4ke2Vyci5zdGFjay5zcGxpdCgvXFxufFxcclxcbnxcXHIvKS5zbGljZSgxKS5qb2luKG9zLkVPTCl9YFxuICAgICAgOiBzdHJcbiAgfVxuXG4gIGxvZ0Vycm9yKGVyciwgY3R4KSB7XG4gICAgaWYgKCFlcnIuZXhwb3NlICYmICF0aGlzLnNpbGVudCkge1xuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgdGV4dCA9IHRoaXMuZm9ybWF0RXJyb3IoZXJyKVxuICAgICAgICBjb25zdCBsZXZlbCA9XG4gICAgICAgICAgZXJyIGluc3RhbmNlb2YgUmVzcG9uc2VFcnJvciAmJiBlcnIuc3RhdHVzIDwgNTAwID8gJ2luZm8nIDogJ2Vycm9yJ1xuICAgICAgICBjb25zdCBsb2dnZXIgPSBjdHg/LmxvZ2dlciB8fCB0aGlzLmxvZ2dlclxuICAgICAgICBsb2dnZXJbbGV2ZWxdKHRleHQpXG4gICAgICB9IGNhdGNoIChlKSB7XG4gICAgICAgIGNvbnNvbGUuZXJyb3IoJ0NvdWxkIG5vdCBsb2cgZXJyb3InLCBlKVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGFzeW5jIHN0YXJ0KCkge1xuICAgIGlmICh0aGlzLmNvbmZpZy5sb2cuZXJyb3JzICE9PSBmYWxzZSkge1xuICAgICAgdGhpcy5vbignZXJyb3InLCB0aGlzLmxvZ0Vycm9yKVxuICAgIH1cbiAgICBhd2FpdCB0aGlzLmVtaXQoJ2JlZm9yZTpzdGFydCcpXG4gICAgYXdhaXQgdGhpcy5mb3JFYWNoU2VydmljZShzZXJ2aWNlID0+IHNlcnZpY2Uuc3RhcnQoKSlcbiAgICBjb25zdCB7XG4gICAgICBzZXJ2ZXI6IHsgaG9zdCwgcG9ydCB9LFxuICAgICAgZW52XG4gICAgfSA9IHRoaXMuY29uZmlnXG4gICAgdGhpcy5zZXJ2ZXIgPSBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjb25zdCBzZXJ2ZXIgPSB0aGlzLmxpc3Rlbihwb3J0LCBob3N0LCAoKSA9PiB7XG4gICAgICAgIGNvbnN0IHsgcG9ydCB9ID0gc2VydmVyLmFkZHJlc3MoKVxuICAgICAgICBjb25zb2xlLmluZm8oXG4gICAgICAgICAgYCR7ZW52fSBzZXJ2ZXIgc3RhcnRlZCBhdCBodHRwOi8vJHtob3N0fToke3BvcnR9YFxuICAgICAgICApXG4gICAgICAgIHJlc29sdmUoc2VydmVyKVxuICAgICAgfSlcbiAgICAgIGlmICghc2VydmVyKSB7XG4gICAgICAgIHJlamVjdChuZXcgRXJyb3IoYFVuYWJsZSB0byBzdGFydCBzZXJ2ZXIgYXQgaHR0cDovLyR7aG9zdH06JHtwb3J0fWApKVxuICAgICAgfVxuICAgIH0pXG4gICAgYXdhaXQgdGhpcy5lbWl0KCdhZnRlcjpzdGFydCcpXG4gIH1cblxuICBhc3luYyBzdG9wKCkge1xuICAgIGF3YWl0IHRoaXMuZW1pdCgnYmVmb3JlOnN0b3AnKVxuICAgIHRoaXMuc2VydmVyID0gYXdhaXQgbmV3IFByb21pc2UoKHJlc29sdmUsIHJlamVjdCkgPT4ge1xuICAgICAgY29uc3QgeyBzZXJ2ZXIgfSA9IHRoaXNcbiAgICAgIGlmIChzZXJ2ZXIpIHtcbiAgICAgICAgc2VydmVyLmNsb3NlKGVyciA9PiB7XG4gICAgICAgICAgaWYgKGVycikge1xuICAgICAgICAgICAgcmVqZWN0KGVycilcbiAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgcmVzb2x2ZShudWxsKVxuICAgICAgICAgIH1cbiAgICAgICAgfSlcbiAgICAgICAgLy8gSGFjayB0byBtYWtlIHN1cmUgdGhhdCB3ZSBjbG9zZSB0aGUgc2VydmVyLFxuICAgICAgICAvLyAgZXZlbiBpZiBzb2NrZXRzIGFyZSBzdGlsbCBvcGVuLlxuICAgICAgICAvLyAgVGFrZW4gZnJvbSBodHRwczovL3N0YWNrb3ZlcmZsb3cuY29tL2EvMzY4MzAwNzIuXG4gICAgICAgIC8vICBBIHByb3BlciBzb2x1dGlvbiB3b3VsZCBiZSB0byB1c2UgYSBsaWJyYXJ5LCBleDogaHR0cHM6Ly9naXRodWIuY29tL2dvZGFkZHkvdGVybWludXNcbiAgICAgICAgc2V0SW1tZWRpYXRlKCgpID0+IHNlcnZlci5lbWl0KCdjbG9zZScpKVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgcmVqZWN0KG5ldyBFcnJvcignU2VydmVyIGlzIG5vdCBydW5uaW5nJykpXG4gICAgICB9XG4gICAgfSlcbiAgICBhd2FpdCB0aGlzLmZvckVhY2hTZXJ2aWNlKHNlcnZpY2UgPT4gc2VydmljZS5zdG9wKCkpXG4gICAgYXdhaXQgdGhpcy5lbWl0KCdhZnRlcjpzdG9wJylcbiAgICBpZiAodGhpcy5jb25maWcubG9nLmVycm9ycyAhPT0gZmFsc2UpIHtcbiAgICAgIHRoaXMub2ZmKCdlcnJvcicsIHRoaXMubG9nRXJyb3IpXG4gICAgfVxuICB9XG5cbiAgYXN5bmMgc3RhcnRPckV4aXQoKSB7XG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IHRoaXMuc3RhcnQoKVxuICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgdGhpcy5sb2dFcnJvcihlcnIpXG4gICAgICBwcm9jZXNzLmV4aXQoLTEpXG4gICAgfVxuICB9XG5cbiAgLy8gQXNzZXRzIGhhbmRsaW5nXG5cbiAgYXN5bmMgY3JlYXRlQXNzZXRzKHN0b3JhZ2UsIGZpbGVzLCBjb3VudCA9IDAsIHRyeCA9IG51bGwpIHtcbiAgICBjb25zdCBBc3NldE1vZGVsID0gdGhpcy5nZXRNb2RlbCgnQXNzZXQnKVxuICAgIGlmIChBc3NldE1vZGVsKSB7XG4gICAgICBjb25zdCBhc3NldHMgPSBmaWxlcy5tYXAoZmlsZSA9PiAoe1xuICAgICAgICBrZXk6IGZpbGUua2V5LFxuICAgICAgICBmaWxlLFxuICAgICAgICBzdG9yYWdlOiBzdG9yYWdlLm5hbWUsXG4gICAgICAgIGNvdW50XG4gICAgICB9KSlcbiAgICAgIHJldHVybiBBc3NldE1vZGVsXG4gICAgICAgIC5xdWVyeSh0cngpXG4gICAgICAgIC5pbnNlcnQoYXNzZXRzKVxuICAgIH1cbiAgICByZXR1cm4gbnVsbFxuICB9XG5cbiAgYXN5bmMgaGFuZGxlQWRkZGVkQW5kUmVtb3ZlZEFzc2V0cyhcbiAgICBzdG9yYWdlLFxuICAgIGFkZGVkRmlsZXMsXG4gICAgcmVtb3ZlZEZpbGVzLFxuICAgIHRyeCA9IG51bGxcbiAgKSB7XG4gICAgY29uc3Qge1xuICAgICAgYXNzZXRzOiB7XG4gICAgICAgIGNsZWFudXBUaW1lVGhyZXNob2xkID0gMFxuICAgICAgfSA9IHt9XG4gICAgfSA9IHRoaXMuY29uZmlnXG4gICAgLy8gT25seSByZW1vdmUgdW51c2VkIGFzc2V0cyB0aGF0IGhhdmVuJ3Qgc2VlbiBjaGFuZ2VzIGZvciBnaXZlbiB0aW1lZnJhbWUuXG4gICAgY29uc3QgdGltZVRocmVzaG9sZCA9IGlzU3RyaW5nKGNsZWFudXBUaW1lVGhyZXNob2xkKVxuICAgICAgPyBwYXJzZUR1cmF0aW9uKGNsZWFudXBUaW1lVGhyZXNob2xkKVxuICAgICAgOiBjbGVhbnVwVGltZVRocmVzaG9sZFxuXG4gICAgY29uc3QgaW1wb3J0ZWRGaWxlcyA9IFtdXG4gICAgY29uc3QgQXNzZXRNb2RlbCA9IHRoaXMuZ2V0TW9kZWwoJ0Fzc2V0JylcbiAgICBpZiAoQXNzZXRNb2RlbCkge1xuICAgICAgaW1wb3J0ZWRGaWxlcy5wdXNoKFxuICAgICAgICAuLi5hd2FpdCB0aGlzLmFkZEZvcmVpZ25Bc3NldHMoc3RvcmFnZSwgYWRkZWRGaWxlcywgdHJ4KVxuICAgICAgKVxuICAgICAgaWYgKFxuICAgICAgICBhZGRlZEZpbGVzLmxlbmd0aCA+IDAgfHxcbiAgICAgICAgcmVtb3ZlZEZpbGVzLmxlbmd0aCA+IDBcbiAgICAgICkge1xuICAgICAgICBjb25zdCBjaGFuZ2VDb3VudCA9IChmaWxlcywgaW5jcmVtZW50KSA9PiAoXG4gICAgICAgICAgZmlsZXMubGVuZ3RoID4gMCAmJlxuICAgICAgICAgIEFzc2V0TW9kZWwucXVlcnkodHJ4KVxuICAgICAgICAgICAgLndoZXJlSW4oJ2tleScsIGZpbGVzLm1hcChmaWxlID0+IGZpbGUua2V5KSlcbiAgICAgICAgICAgIC5pbmNyZW1lbnQoJ2NvdW50JywgaW5jcmVtZW50KVxuICAgICAgICApXG4gICAgICAgIGF3YWl0IFByb21pc2UuYWxsKFtcbiAgICAgICAgICBjaGFuZ2VDb3VudChhZGRlZEZpbGVzLCAxKSxcbiAgICAgICAgICBjaGFuZ2VDb3VudChyZW1vdmVkRmlsZXMsIC0xKVxuICAgICAgICBdKVxuICAgICAgICBpZiAodGltZVRocmVzaG9sZCA+IDApIHtcbiAgICAgICAgICBzZXRUaW1lb3V0KFxuICAgICAgICAgICAgLy8gRG9uJ3QgcGFzcyBgdHJ4YCBoZXJlLCBhcyB3ZSB3YW50IHRoaXMgZGVsYXllZCBleGVjdXRpb24gdG9cbiAgICAgICAgICAgIC8vIGNyZWF0ZSBpdHMgb3duIHRyYW5zYWN0aW9uLlxuICAgICAgICAgICAgKCkgPT4gdGhpcy5yZWxlYXNlVW51c2VkQXNzZXRzKHRpbWVUaHJlc2hvbGQpLFxuICAgICAgICAgICAgdGltZVRocmVzaG9sZFxuICAgICAgICAgIClcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgLy8gQWxzbyBleGVjdXRlIHJlbGVhc2VVbnVzZWRBc3NldHMoKSBpbW1lZGlhdGVseSBpbiB0aGUgc2FtZVxuICAgICAgLy8gdHJhbnNhY3Rpb24sIHRvIHBvdGVudGlhbGx5IGNsZWFuIHVwIG90aGVyIHBlbmRpbmcgYXNzZXRzLlxuICAgICAgYXdhaXQgdGhpcy5yZWxlYXNlVW51c2VkQXNzZXRzKHRpbWVUaHJlc2hvbGQsIHRyeClcbiAgICAgIHJldHVybiBpbXBvcnRlZEZpbGVzXG4gICAgfVxuICB9XG5cbiAgYXN5bmMgYWRkRm9yZWlnbkFzc2V0cyhzdG9yYWdlLCBmaWxlcywgdHJ4ID0gbnVsbCkge1xuICAgIGNvbnN0IGltcG9ydGVkRmlsZXMgPSBbXVxuICAgIGNvbnN0IEFzc2V0TW9kZWwgPSB0aGlzLmdldE1vZGVsKCdBc3NldCcpXG4gICAgaWYgKEFzc2V0TW9kZWwpIHtcbiAgICAgIC8vIEZpbmQgbWlzc2luZyBhc3NldHMgKGNvcGllZCBmcm9tIGFub3RoZXIgc3lzdGVtKSwgYW5kIGFkZCB0aGVtLlxuICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgIGZpbGVzLm1hcChhc3luYyBmaWxlID0+IHtcbiAgICAgICAgICBjb25zdCBhc3NldCA9IGF3YWl0IEFzc2V0TW9kZWwucXVlcnkodHJ4KS5maW5kT25lKCdrZXknLCBmaWxlLmtleSlcbiAgICAgICAgICBpZiAoIWFzc2V0KSB7XG4gICAgICAgICAgICBpZiAoZmlsZS5kYXRhIHx8IGZpbGUudXJsKSB7XG4gICAgICAgICAgICAgIGxldCB7IGRhdGEgfSA9IGZpbGVcbiAgICAgICAgICAgICAgaWYgKCFkYXRhKSB7XG4gICAgICAgICAgICAgICAgY29uc29sZS5pbmZvKFxuICAgICAgICAgICAgICAgICAgYCR7XG4gICAgICAgICAgICAgICAgICAgIHBpY28ucmVkKCdJTkZPOicpXG4gICAgICAgICAgICAgICAgICB9IEFzc2V0ICR7XG4gICAgICAgICAgICAgICAgICAgIHBpY28uZ3JlZW4oYCcke2ZpbGUubmFtZX0nYClcbiAgICAgICAgICAgICAgICAgIH0gaXMgZnJvbSBhIGZvcmVpZ24gc291cmNlLCBmZXRjaGluZyBmcm9tICR7XG4gICAgICAgICAgICAgICAgICAgIHBpY28uZ3JlZW4oYCcke2ZpbGUudXJsfSdgKVxuICAgICAgICAgICAgICAgICAgfSBhbmQgYWRkaW5nIHRvIHN0b3JhZ2UgJHtcbiAgICAgICAgICAgICAgICAgICAgcGljby5ncmVlbihgJyR7c3RvcmFnZS5uYW1lfSdgKVxuICAgICAgICAgICAgICAgICAgfS4uLmBcbiAgICAgICAgICAgICAgICApXG4gICAgICAgICAgICAgICAgY29uc3QgcmVzcG9uc2UgPSBhd2FpdCBheGlvcy5yZXF1ZXN0KHtcbiAgICAgICAgICAgICAgICAgIG1ldGhvZDogJ2dldCcsXG4gICAgICAgICAgICAgICAgICB1cmw6IGZpbGUudXJsLFxuICAgICAgICAgICAgICAgICAgcmVzcG9uc2VUeXBlOiAnYXJyYXlidWZmZXInXG4gICAgICAgICAgICAgICAgfSlcbiAgICAgICAgICAgICAgICBkYXRhID0gcmVzcG9uc2UuZGF0YVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIGNvbnN0IGltcG9ydGVkRmlsZSA9IGF3YWl0IHN0b3JhZ2UuYWRkRmlsZShmaWxlLCBkYXRhKVxuICAgICAgICAgICAgICBhd2FpdCB0aGlzLmNyZWF0ZUFzc2V0cyhzdG9yYWdlLCBbaW1wb3J0ZWRGaWxlXSwgMCwgdHJ4KVxuICAgICAgICAgICAgICAvLyBNZXJnZSBiYWNrIHRoZSBjaGFuZ2VkIGZpbGUgcHJvcGVydGllcyBpbnRvIHRoZSBhY3R1YWwgZmlsZXNcbiAgICAgICAgICAgICAgLy8gb2JqZWN0LCBzbyB0aGF0IHRoZSBkYXRhIGZyb20gdGhlIHN0YXRpYyBtb2RlbCBob29rIGNhbiBiZSB1c2VkXG4gICAgICAgICAgICAgIC8vIGRpcmVjdGx5IGZvciB0aGUgYWN0dWFsIHJ1bm5pbmcgcXVlcnkuXG4gICAgICAgICAgICAgIE9iamVjdC5hc3NpZ24oZmlsZSwgaW1wb3J0ZWRGaWxlKVxuICAgICAgICAgICAgICBpbXBvcnRlZEZpbGVzLnB1c2goaW1wb3J0ZWRGaWxlKVxuICAgICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgICAgdGhyb3cgbmV3IEFzc2V0RXJyb3IoXG4gICAgICAgICAgICAgICAgYFVuYWJsZSB0byBpbXBvcnQgYXNzZXQgZnJvbSBmb3JlaWduIHNvdXJjZTogJyR7XG4gICAgICAgICAgICAgICAgICBmaWxlLm5hbWVcbiAgICAgICAgICAgICAgICB9JyAoJyR7XG4gICAgICAgICAgICAgICAgICBmaWxlLmtleVxuICAgICAgICAgICAgICAgIH0nKWBcbiAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAvLyBBc3NldCBpcyBmcm9tIGEgZm9yZWlnbiBzb3VyY2UsIGJ1dCB3YXMgYWxyZWFkeSBpbXBvcnRlZCBhbmQgY2FuXG4gICAgICAgICAgICAvLyBiZSByZXVzZWQuIFNlZSBhYm92ZSBmb3IgYW4gZXhwbGFuYXRpb24gb2YgdGhpcyBtZXJnZS5cbiAgICAgICAgICAgIE9iamVjdC5hc3NpZ24oZmlsZSwgYXNzZXQuZmlsZSlcbiAgICAgICAgICAgIC8vIE5PVEU6IE5vIG5lZWQgdG8gYWRkIGBmaWxlYCB0byBgaW1wb3J0ZWRGaWxlc2AsIHNpbmNlIGl0J3NcbiAgICAgICAgICAgIC8vIGFscmVhZHkgYmVlbiBpbXBvcnRlZCB0byB0aGUgc3RvcmFnZSBiZWZvcmUuXG4gICAgICAgICAgfVxuICAgICAgICB9KVxuICAgICAgKVxuICAgIH1cbiAgICByZXR1cm4gaW1wb3J0ZWRGaWxlc1xuICB9XG5cbiAgYXN5bmMgaGFuZGxlTW9kaWZpZWRBc3NldHMoc3RvcmFnZSwgZmlsZXMsIHRyeCA9IG51bGwpIHtcbiAgICBjb25zdCBtb2RpZmllZEZpbGVzID0gW11cbiAgICBjb25zdCBBc3NldE1vZGVsID0gdGhpcy5nZXRNb2RlbCgnQXNzZXQnKVxuICAgIGlmIChBc3NldE1vZGVsKSB7XG4gICAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgZmlsZXMubWFwKGFzeW5jIGZpbGUgPT4ge1xuICAgICAgICAgIGlmIChmaWxlLmRhdGEpIHtcbiAgICAgICAgICAgIGNvbnN0IGFzc2V0ID0gYXdhaXQgQXNzZXRNb2RlbC5xdWVyeSh0cngpLmZpbmRPbmUoJ2tleScsIGZpbGUua2V5KVxuICAgICAgICAgICAgaWYgKGFzc2V0KSB7XG4gICAgICAgICAgICAgIGNvbnN0IGNoYW5nZWRGaWxlID0gYXdhaXQgc3RvcmFnZS5hZGRGaWxlKGZpbGUsIGZpbGUuZGF0YSlcbiAgICAgICAgICAgICAgLy8gTWVyZ2UgYmFjayB0aGUgY2hhbmdlZCBmaWxlIHByb3BlcnRpZXMgaW50byB0aGUgYWN0dWFsIGZpbGVzXG4gICAgICAgICAgICAgIC8vIG9iamVjdCwgc28gdGhhdCB0aGUgZGF0YSBmcm9tIHRoZSBzdGF0aWMgbW9kZWwgaG9vayBjYW4gYmUgdXNlZFxuICAgICAgICAgICAgICAvLyBkaXJlY3RseSBmb3IgdGhlIGFjdHVhbCBydW5uaW5nIHF1ZXJ5LlxuICAgICAgICAgICAgICBPYmplY3QuYXNzaWduKGZpbGUsIGNoYW5nZWRGaWxlKVxuICAgICAgICAgICAgICBtb2RpZmllZEZpbGVzLnB1c2goY2hhbmdlZEZpbGUpXG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICB0aHJvdyBuZXcgQXNzZXRFcnJvcihcbiAgICAgICAgICAgICAgICBgVW5hYmxlIHRvIHVwZGF0ZSBtb2RpZmllZCBhc3NldCBmcm9tIG1lbW9yeSBzb3VyY2U6ICcke1xuICAgICAgICAgICAgICAgICAgZmlsZS5uYW1lXG4gICAgICAgICAgICAgICAgfScgKCcke1xuICAgICAgICAgICAgICAgICAgZmlsZS5rZXlcbiAgICAgICAgICAgICAgICB9JylgXG4gICAgICAgICAgICAgIClcbiAgICAgICAgICAgIH1cbiAgICAgICAgICB9XG4gICAgICAgIH0pXG4gICAgICApXG4gICAgfVxuICAgIHJldHVybiBtb2RpZmllZEZpbGVzXG4gIH1cblxuICBhc3luYyByZWxlYXNlVW51c2VkQXNzZXRzKHRpbWVUaHJlc2hvbGQgPSAwLCB0cnggPSBudWxsKSB7XG4gICAgY29uc3QgQXNzZXRNb2RlbCA9IHRoaXMuZ2V0TW9kZWwoJ0Fzc2V0JylcbiAgICBpZiAoQXNzZXRNb2RlbCkge1xuICAgICAgcmV0dXJuIEFzc2V0TW9kZWwudHJhbnNhY3Rpb24odHJ4LCBhc3luYyB0cnggPT4ge1xuICAgICAgICAvLyBEZXRlcm1pbmUgdGhlIHRpbWUgdGhyZXNob2xkIGluIEpTIGluc3RlYWQgb2YgU1FMLCBhcyB0aGVyZSBpcyBub1xuICAgICAgICAvLyBlYXN5IGNyb3NzLVNRTCB3YXkgdG8gZG8gYG5vdygpIC0gaW50ZXJ2YWwgWCBob3Vyc2A6XG4gICAgICAgIGNvbnN0IGRhdGUgPSBuZXcgRGF0ZSgpXG4gICAgICAgIGRhdGUuc2V0TWlsbGlzZWNvbmRzKGRhdGUuZ2V0TWlsbGlzZWNvbmRzKCkgLSB0aW1lVGhyZXNob2xkKVxuICAgICAgICBjb25zdCBvcnBoYW5lZEFzc2V0cyA9IGF3YWl0IEFzc2V0TW9kZWxcbiAgICAgICAgICAucXVlcnkodHJ4KVxuICAgICAgICAgIC53aGVyZSgnY291bnQnLCAwKVxuICAgICAgICAgIC5hbmRXaGVyZSgndXBkYXRlZEF0JywgJzw9JywgZGF0ZSlcbiAgICAgICAgICAvLyBQcm90ZWN0IGZyZXNobHkgY3JlYXRlZCBhc3NldHMgZnJvbSBiZWluZyBkZWxldGVkIGFnYWluIHJpZ2h0IGF3YXksXG4gICAgICAgICAgLy8gLmUuZy4gd2hlbiBgY29uZmlnLmFzc2V0cy5jbGVhbnVwVGltZVRocmVzaG9sZCA9IDBgXG4gICAgICAgICAgLmFuZFdoZXJlKCd1cGRhdGVkQXQnLCAnPicsIHJlZignY3JlYXRlZEF0JykpXG4gICAgICAgIGlmIChvcnBoYW5lZEFzc2V0cy5sZW5ndGggPiAwKSB7XG4gICAgICAgICAgY29uc3Qgb3JwaGFuZWRLZXlzID0gYXdhaXQgUHJvbWlzZS5hbGwoXG4gICAgICAgICAgICBvcnBoYW5lZEFzc2V0cy5tYXAoYXN5bmMgYXNzZXQgPT4ge1xuICAgICAgICAgICAgICB0cnkge1xuICAgICAgICAgICAgICAgIGF3YWl0IHRoaXMuZ2V0U3RvcmFnZShhc3NldC5zdG9yYWdlKS5yZW1vdmVGaWxlKGFzc2V0LmZpbGUpXG4gICAgICAgICAgICAgIH0gY2F0Y2ggKGVycm9yKSB7XG4gICAgICAgICAgICAgICAgdGhpcy5lbWl0KCdlcnJvcicsIGVycm9yKVxuICAgICAgICAgICAgICAgIGFzc2V0LmVycm9yID0gZXJyb3JcbiAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICByZXR1cm4gYXNzZXQua2V5XG4gICAgICAgICAgICB9KVxuICAgICAgICAgIClcbiAgICAgICAgICBhd2FpdCBBc3NldE1vZGVsXG4gICAgICAgICAgICAucXVlcnkodHJ4KVxuICAgICAgICAgICAgLmRlbGV0ZSgpXG4gICAgICAgICAgICAud2hlcmVJbigna2V5Jywgb3JwaGFuZWRLZXlzKVxuICAgICAgICB9XG4gICAgICAgIHJldHVybiBvcnBoYW5lZEFzc2V0c1xuICAgICAgfSlcbiAgICB9XG4gIH1cbn1cblxuLy8gT3ZlcnJpZGUgS29hJ3MgZXZlbnRzIHdpdGggb3VyIG93biBFdmVudEVtaXR0ZXIgdGhhdCBhZGRzIHN1cHBvcnQgZm9yXG4vLyBhc3luY2hyb25vdXMgZXZlbnRzLlxuRXZlbnRFbWl0dGVyLm1peGluKEFwcGxpY2F0aW9uLnByb3RvdHlwZSlcblxuZnVuY3Rpb24gZ2V0T3B0aW9ucyhvcHRpb25zKSB7XG4gIHJldHVybiBpc09iamVjdChvcHRpb25zKSA/IG9wdGlvbnMgOiB7fVxufVxuIl19
|