@ditojs/server 0.275.0 → 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/package.json +25 -43
- package/src/app/Application.js +105 -111
- 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 +181 -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 && this.knex.client.driver) {
|
|
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,eyJ2ZXJzaW9uIjozLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9hcHAvQXBwbGljYXRpb24uanMiXSwibmFtZXMiOlsiQXBwbGljYXRpb24iLCJLb2EiLCJjb25zdHJ1Y3RvciIsImNvbmZpZyIsInZhbGlkYXRvciIsInJvdXRlciIsImV2ZW50cyIsIm1pZGRsZXdhcmUiLCJtb2RlbHMiLCJzZXJ2aWNlcyIsImNvbnRyb2xsZXJzIiwiX3NldHVwRW1pdHRlciIsImFwcCIsImtleXMiLCJsb2ciLCJyZXN0Iiwic2lsZW50IiwicHJvY2VzcyIsImVudiIsIkRJVE9fU0lMRU5UIiwicHJveHkiLCJWYWxpZGF0b3IiLCJSb3V0ZXIiLCJzdG9yYWdlcyIsIk9iamVjdCIsImNyZWF0ZSIsImhhc0NvbnRyb2xsZXJNaWRkbGV3YXJlIiwic2V0dXBMb2dnZXIiLCJzZXR1cEtuZXgiLCJzZXR1cEdsb2JhbE1pZGRsZXdhcmUiLCJ1c2UiLCJhZGRTdG9yYWdlcyIsImFkZE1vZGVscyIsImFkZFNlcnZpY2VzIiwiYWRkQ29udHJvbGxlcnMiLCJhZGRSb3V0ZSIsInZlcmIiLCJwYXRoIiwidHJhbnNhY3RlZCIsImhhbmRsZXJzIiwiY29udHJvbGxlciIsImFjdGlvbiIsImhhbmRsZXIiLCJsZW5ndGgiLCJyb3V0ZSIsIm1vZGVsQ2xhc3MiLCJ2YWx1ZXMiLCJhZGRNb2RlbCIsInNvcnRNb2RlbHMiLCJzb3J0ZWRNb2RlbHMiLCJmaWx0ZXIiLCJuYW1lIiwic2V0dXAiLCJrbmV4IiwiaW5pdGlhbGl6ZSIsImFkZFNjaGVtYSIsImdldEpzb25TY2hlbWEiLCJzY2hlbWEiLCJyZWxhdGlvbnMiLCJzaG91bGRMb2ciLCJvcHRpb24iLCJpbmNsdWRlcyIsImRhdGEiLCJyZWxhdGlvbk1hcHBpbmdzIiwidmFsdWUiLCJNb2RlbCIsImlzUHJvdG90eXBlT2YiLCJjb25zb2xlIiwiaW5mbyIsInBpY28iLCJ5ZWxsb3ciLCJib2xkIiwidXRpbCIsImluc3BlY3QiLCJjb2xvcnMiLCJkZXB0aCIsIm1heEFycmF5TGVuZ3RoIiwiRXJyb3IiLCJzb3J0QnlSZWxhdGlvbnMiLCJsaXN0IiwiY29sbGVjdGVkIiwiZXhjbHVkZWQiLCJyZWxhdGlvbiIsImdldFJlbGF0aW9ucyIsIkJlbG9uZ3NUb09uZVJlbGF0aW9uIiwicmVsYXRlZE1vZGVsQ2xhc3MiLCJqb2luVGFibGVNb2RlbENsYXNzIiwicmVsYXRlZCIsInJldmVyc2UiLCJyZWR1Y2UiLCJnZXRNb2RlbCIsImVuZHNXaXRoIiwiZmluZE1vZGVsIiwiY2FsbGJhY2siLCJmaW5kIiwic2VydmljZSIsImVudHJpZXMiLCJhZGRTZXJ2aWNlIiwiU2VydmljZSIsInVuZGVmaW5lZCIsImdldFNlcnZpY2UiLCJmaW5kU2VydmljZSIsImZvckVhY2hTZXJ2aWNlIiwiUHJvbWlzZSIsImFsbCIsIm1hcCIsIm5hbWVzcGFjZSIsImtleSIsImFkZENvbnRyb2xsZXIiLCJzZXR1cENvbnRyb2xsZXJNaWRkbGV3YXJlIiwiQ29udHJvbGxlciIsInVybCIsImNvbXBvc2UiLCJnZXRDb250cm9sbGVyIiwiZmluZENvbnRyb2xsZXIiLCJnZXRBZG1pbkNvbnRyb2xsZXIiLCJBZG1pbkNvbnRyb2xsZXIiLCJnZXRBZG1pblZ1ZUNvbmZpZyIsImdldFZ1ZUNvbmZpZyIsImdldEFzc2V0Q29uZmlnIiwibm9ybWFsaXplRGJOYW1lcyIsImFzc2V0Q29uZmlnIiwibW9kZWxOYW1lIiwiYXNzZXRzIiwiZGVmaW5pdGlvbiIsIm5vcm1hbGl6ZWRNb2RlbE5hbWUiLCJub3JtYWxpemVJZGVudGlmaWVyIiwiY29udmVydGVkQXNzZXRzIiwiYXNzZXREYXRhUGF0aCIsInByb3BlcnR5IiwibmVzdGVkRGF0YVBhdGgiLCJpbmRleCIsImdldFByb3BlcnR5T3JSZWxhdGlvbkF0RGF0YVBhdGgiLCJub3JtYWxpemVkTmFtZSIsImRhdGFQYXRoIiwiYXNzZXRDb25maWdzIiwiYWRkU3RvcmFnZSIsInN0b3JhZ2UiLCJzdG9yYWdlQ2xhc3MiLCJTdG9yYWdlIiwiZ2V0IiwidHlwZSIsImdldFN0b3JhZ2UiLCJjb21waWxlVmFsaWRhdG9yIiwianNvblNjaGVtYSIsIm9wdGlvbnMiLCJjb21waWxlIiwiY29tcGlsZVBhcmFtZXRlcnNWYWxpZGF0b3IiLCJwYXJhbWV0ZXJzIiwiZGF0YU5hbWUiLCJwcm9wZXJ0aWVzIiwiYWRkUGFyYW1ldGVyIiwicHVzaCIsIm1lbWJlciIsImFzT2JqZWN0IiwidmFsaWRhdGUiLCJjb2VyY2VUeXBlcyIsImN0eCIsImNhbGwiLCJjcmVhdGVWYWxpZGF0aW9uRXJyb3IiLCJtZXNzYWdlIiwiZXJyb3JzIiwianNvbiIsIlZhbGlkYXRpb25FcnJvciIsInBhcnNlRXJyb3JzIiwiY3JlYXRlRGF0YWJhc2VFcnJvciIsImVycm9yIiwic3FsIiwibWF0Y2giLCJEYXRhYmFzZUVycm9yIiwibG9nZ2VyIiwicmVzcG9uc2VUaW1lIiwiZ2V0T3B0aW9ucyIsInJlcXVlc3RzIiwiaGVsbWV0IiwiY29ycyIsImNvbXByZXNzIiwiYnIiLCJwYXJhbXMiLCJ6bGliIiwiY29uc3RhbnRzIiwiQlJPVExJX1BBUkFNX1FVQUxJVFkiLCJldGFnIiwiYm9keVBhcnNlciIsInNlc3Npb24iLCJDb250ZXh0U3RvcmUiLCJwYXNzcG9ydCIsImVyciIsInJlcSIsInJlcyIsInBpbm8iLCJzdGRTZXJpYWxpemVycyIsInVzZXIiLCJpZCIsInNlcmlhbGl6ZXJzIiwibGV2ZWwiLCJwcmV0dHlQcmludCIsImlnbm9yZSIsInRyYW5zbGF0ZVRpbWUiLCJyZWRhY3QiLCJiYXNlIiwiY2hpbGQiLCJjbGllbnQiLCJzbmFrZUNhc2VPcHRpb25zIiwidHlwZVBhcnNlcnMiLCJkcml2ZXIiLCJwYXJzZXIiLCJ0eXBlcyIsInNldFR5cGVQYXJzZXIiLCJzZXR1cEtuZXhMb2dnaW5nIiwic3RhcnRUaW1lcyIsImVuZCIsInF1ZXJ5IiwicmVzcG9uc2UiLCJfX2tuZXhRdWVyeVVpZCIsImRpZmYiLCJocnRpbWUiLCJkdXJhdGlvbiIsImJpbmRpbmdzIiwiZnJvbUVudHJpZXMiLCJzdGFydHNXaXRoIiwib24iLCJpZGVudGlmaWVyIiwid3JhcElkZW50aWZpZXIiLCJyZXBsYWNlIiwiZGVub3JtYWxpemVJZGVudGlmaWVyIiwib2JqIiwicG9zdFByb2Nlc3NSZXNwb25zZSIsIm5vcm1hbGl6ZVBhdGgiLCJub3JtYWxpemVQYXRocyIsImZvcm1hdEVycm9yIiwidG9KU09OIiwic3RyIiwic3RhY2siLCJzcGxpdCIsInNsaWNlIiwiam9pbiIsIm9zIiwiRU9MIiwibG9nRXJyb3IiLCJleHBvc2UiLCJ0ZXh0IiwiUmVzcG9uc2VFcnJvciIsInN0YXR1cyIsImUiLCJzdGFydCIsImVtaXQiLCJzZXJ2ZXIiLCJob3N0IiwicG9ydCIsInJlc29sdmUiLCJyZWplY3QiLCJsaXN0ZW4iLCJhZGRyZXNzIiwic3RvcCIsImNsb3NlIiwic2V0SW1tZWRpYXRlIiwib2ZmIiwic3RhcnRPckV4aXQiLCJleGl0IiwiY3JlYXRlQXNzZXRzIiwiZmlsZXMiLCJjb3VudCIsInRyeCIsIkFzc2V0TW9kZWwiLCJmaWxlIiwiaW5zZXJ0IiwiaGFuZGxlQWRkZGVkQW5kUmVtb3ZlZEFzc2V0cyIsImFkZGVkRmlsZXMiLCJyZW1vdmVkRmlsZXMiLCJjbGVhbnVwVGltZVRocmVzaG9sZCIsInRpbWVUaHJlc2hvbGQiLCJpbXBvcnRlZEZpbGVzIiwiYWRkRm9yZWlnbkFzc2V0cyIsImNoYW5nZUNvdW50IiwiaW5jcmVtZW50Iiwid2hlcmVJbiIsInNldFRpbWVvdXQiLCJyZWxlYXNlVW51c2VkQXNzZXRzIiwiYXNzZXQiLCJmaW5kT25lIiwicmVkIiwiZ3JlZW4iLCJheGlvcyIsInJlcXVlc3QiLCJtZXRob2QiLCJyZXNwb25zZVR5cGUiLCJpbXBvcnRlZEZpbGUiLCJhZGRGaWxlIiwiYXNzaWduIiwiQXNzZXRFcnJvciIsImhhbmRsZU1vZGlmaWVkQXNzZXRzIiwibW9kaWZpZWRGaWxlcyIsImNoYW5nZWRGaWxlIiwidHJhbnNhY3Rpb24iLCJkYXRlIiwiRGF0ZSIsInNldE1pbGxpc2Vjb25kcyIsImdldE1pbGxpc2Vjb25kcyIsIm9ycGhhbmVkQXNzZXRzIiwid2hlcmUiLCJhbmRXaGVyZSIsIm9ycGhhbmVkS2V5cyIsInJlbW92ZUZpbGUiLCJkZWxldGUiLCJFdmVudEVtaXR0ZXIiLCJtaXhpbiIsInByb3RvdHlwZSJdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztBQUFBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQUNBOztBQU1BOztBQUNBOztBQUNBOztBQVNBOztBQUlBOzs7O0FBT08sTUFBTUEsV0FBTixTQUEwQkMsWUFBMUIsQ0FBOEI7QUFDbkNDLEVBQUFBLFdBQVcsQ0FBQztBQUNWQyxJQUFBQSxNQUFNLEdBQUcsRUFEQztBQUVWQyxJQUFBQSxTQUZVO0FBR1ZDLElBQUFBLE1BSFU7QUFJVkMsSUFBQUEsTUFKVTtBQUtWQyxJQUFBQSxVQUxVO0FBTVZDLElBQUFBLE1BTlU7QUFPVkMsSUFBQUEsUUFQVTtBQVFWQyxJQUFBQTtBQVJVLE1BU1IsRUFUTyxFQVNIO0FBQ047O0FBQ0EsU0FBS0MsYUFBTCxDQUFtQkwsTUFBbkI7O0FBQ0EsVUFBTTtBQUVKTSxNQUFBQSxHQUFHLEVBQUU7QUFBRUMsUUFBQUEsSUFBRjtBQUFRLFdBQUdEO0FBQVgsVUFBbUIsRUFGcEI7QUFHSkUsTUFBQUEsR0FBRyxHQUFHLEVBSEY7QUFJSixTQUFHQztBQUpDLFFBS0ZaLE1BTEo7QUFNQSxTQUFLQSxNQUFMLEdBQWM7QUFDWlMsTUFBQUEsR0FEWTtBQUVaRSxNQUFBQSxHQUFHLEVBQUVBLEdBQUcsQ0FBQ0UsTUFBSixJQUFjQyxPQUFPLENBQUNDLEdBQVIsQ0FBWUMsV0FBMUIsR0FBd0MsRUFBeEMsR0FBNkNMLEdBRnRDO0FBR1osU0FBR0M7QUFIUyxLQUFkO0FBS0EsU0FBS0YsSUFBTCxHQUFZQSxJQUFaO0FBQ0EsU0FBS08s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TmlCLEVBTUosR0FOSSxFQU1DLG9CQUFJLFdBQUosQ0FORCxDQUE3Qjs7QUFPQSxZQUFJRixjQUFjLENBQUNoUSxNQUFmLEdBQXdCLENBQTVCLEVBQStCO0FBQzdCLGdCQUFNbVEsWUFBWSxHQUFHLE1BQU12TSxPQUFPLENBQUNDLEdBQVIsQ0FDekJtTSxjQUFjLENBQUNsTSxHQUFmLENBQW1CLE1BQU04SyxLQUFOLElBQWU7QUFDaEMsZ0JBQUk7QUFDRixvQkFBTSxLQUFLekksVUFBTCxDQUFnQnlJLEtBQUssQ0FBQzlJLE9BQXRCLEVBQStCc0ssVUFBL0IsQ0FBMEN4QixLQUFLLENBQUNkLElBQWhELENBQU47QUFDRCxhQUZELENBRUUsT0FBT25HLEtBQVAsRUFBYztBQUNkLG1CQUFLZ0YsSUFBTCxDQUFVLE9BQVYsRUFBbUJoRixLQUFuQjtBQUNBaUgsY0FBQUEsS0FBSyxDQUFDakgsS0FBTixHQUFjQSxLQUFkO0FBQ0Q7O0FBQ0QsbUJBQU9pSCxLQUFLLENBQUM1SyxHQUFiO0FBQ0QsV0FSRCxDQUR5QixDQUEzQjtBQVdBLGdCQUFNNkosVUFBVSxDQUNicEQsS0FERyxDQUNHbUQsR0FESCxFQUVIeUMsTUFGRyxHQUdINUIsT0FIRyxDQUdLLEtBSEwsRUFHWTBCLFlBSFosQ0FBTjtBQUlEOztBQUNELGVBQU9ILGNBQVA7QUFDRCxPQTlCTSxDQUFQO0FBK0JEO0FBQ0Y7O0FBbjVCa0M7Ozs7QUF3NUJyQ00sa0JBQWFDLEtBQWIsQ0FBbUJsVCxXQUFXLENBQUNtVCxTQUEvQjs7QUFFQSxTQUFTdkksVUFBVCxDQUFvQjNCLE9BQXBCLEVBQTZCO0FBQzNCLFNBQU8sc0JBQVNBLE9BQVQsSUFBb0JBLE9BQXBCLEdBQThCLEVBQXJDO0FBQ0QiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgS29hIGZyb20gJ2tvYSdcbmltcG9ydCBLbmV4IGZyb20gJ2tuZXgnXG5pbXBvcnQgdXRpbCBmcm9tICd1dGlsJ1xuaW1wb3J0IGF4aW9zIGZyb20gJ2F4aW9zJ1xuaW1wb3J0IHBpY28gZnJvbSAncGljb2NvbG9ycydcbmltcG9ydCB6bGliIGZyb20gJ3psaWInXG5pbXBvcnQgcGlubyBmcm9tICdwaW5vJ1xuaW1wb3J0IG9zIGZyb20gJ29zJ1xuaW1wb3J0IHBhcnNlRHVyYXRpb24gZnJvbSAncGFyc2UtZHVyYXRpb24nXG5pbXBvcnQgYm9keVBhcnNlciBmcm9tICdrb2EtYm9keXBhcnNlcidcbmltcG9ydCBjb3JzIGZyb20gJ0Brb2EvY29ycydcbmltcG9ydCBjb21wb3NlIGZyb20gJ2tvYS1jb21wb3NlJ1xuaW1wb3J0IGNvbXByZXNzIGZyb20gJ2tvYS1jb21wcmVzcydcbmltcG9ydCBjb25kaXRpb25hbCBmcm9tICdrb2EtY29uZGl0aW9uYWwtZ2V0J1xuaW1wb3J0IHBhc3Nwb3J0IGZyb20gJ2tvYS1wYXNzcG9ydCdcbmltcG9ydCBzZXNzaW9uIGZyb20gJ2tvYS1zZXNzaW9uJ1xuaW1wb3J0IGV0YWcgZnJvbSAna29hLWV0YWcnXG5pbXBvcnQgaGVsbWV0IGZyb20gJ2tvYS1oZWxtZXQnXG5pbXBvcnQgcmVzcG9uc2VUaW1lIGZyb20gJ2tvYS1yZXNwb25zZS10aW1lJ1xuaW1wb3J0IFJvdXRlciBmcm9tICdAZGl0b2pzL3JvdXRlcidcbmltcG9ydCB7IEV2ZW50RW1pdHRlciB9IGZyb20gJ0AvbGliJ1xuaW1wb3J0IHsgQ29udHJvbGxlciwgQWRtaW5Db250cm9sbGVyIH0gZnJvbSAnQC9jb250cm9sbGVycydcbmltcG9ydCB7IFNlcnZpY2UgfSBmcm9tICdAL3NlcnZpY2VzJ1xuaW1wb3J0IHsgU3RvcmFnZSB9IGZyb20gJ0Avc3RvcmFnZSdcbmltcG9ydCB7IGNvbnZlcnRTY2hlbWEgfSBmcm9tICdAL3NjaGVtYSdcbmltcG9ydCB7IGZvcm1hdEpzb24gfSBmcm9tICdAL3V0aWxzJ1xuaW1wb3J0IHtcbiAgUmVzcG9uc2VFcnJvcixcbiAgVmFsaWRhdGlvbkVycm9yLFxuICBEYXRhYmFzZUVycm9yLFxuICBBc3NldEVycm9yXG59IGZyb20gJ0AvZXJyb3JzJ1xuaW1wb3J0IFNlc3Npb25TdG9yZSBmcm9tICcuL1Nlc3Npb25TdG9yZSdcbmltcG9ydCB7IFZhbGlkYXRvciB9IGZyb20gJy4vVmFsaWRhdG9yJ1xuaW1wb3J0IHtcbiAgYXR0YWNoTG9nZ2VyLFxuICBjcmVhdGVUcmFuc2FjdGlvbixcbiAgZmluZFJvdXRlLFxuICBoYW5kbGVFcnJvcixcbiAgaGFuZGxlUm91dGUsXG4gIGhhbmRsZVVzZXIsXG4gIGxvZ1JlcXVlc3RzXG59IGZyb20gJ0AvbWlkZGxld2FyZSdcbmltcG9ydCB7XG4gIGlzQXJyYXksIGlzT2JqZWN0LCBpc1N0cmluZywgYXNBcnJheSwgaXNQbGFpbk9iamVjdCwgaHlwaGVuYXRlLCBjbG9uZSwgbWVyZ2UsXG4gIHBhcnNlRGF0YVBhdGgsIG5vcm1hbGl6ZURhdGFQYXRoXG59IGZyb20gJ0BkaXRvanMvdXRpbHMnXG5pbXBvcnQge1xuICBNb2RlbCxcbiAgQmVsb25nc1RvT25lUmVsYXRpb24sXG4gIGtuZXhTbmFrZUNhc2VNYXBwZXJzLFxuICByZWZcbn0gZnJvbSAnb2JqZWN0aW9uJ1xuXG5leHBvcnQgY2xhc3MgQXBwbGljYXRpb24gZXh0ZW5kcyBLb2Ege1xuICBjb25zdHJ1Y3Rvcih7XG4gICAgY29uZmlnID0ge30sXG4gICAgdmFsaWRhdG9yLFxuICAgIHJvdXRlcixcbiAgICBldmVudHMsXG4gICAgbWlkZGxld2FyZSxcbiAgICBtb2RlbHMsXG4gICAgc2VydmljZXMsXG4gICAgY29udHJvbGxlcnNcbiAgfSA9IHt9KSB7XG4gICAgc3VwZXIoKVxuICAgIHRoaXMuX3NldHVwRW1pdHRlcihldmVudHMpXG4gICAgY29uc3Qge1xuICAgICAgLy8gUGx1Y2sga2V5cyBvdXQgb2YgYGNvbmZpZy5hcHBgIHRvIGtlZXAgdGhlbSBzZWNyZXRcbiAgICAgIGFwcDogeyBrZXlzLCAuLi5hcHAgfSA9IHt9LFxuICAgICAgbG9nID0ge30sXG4gICAgICAuLi5yZXN0XG4gICAgfSA9IGNvbmZpZ1xuICAgIHRoaXMuY29uZmlnID0ge1xuICAgICAgYXBwLFxuICAgICAgbG9nOiBsb2cuc2lsZW50IHx8IHByb2Nlc3MuZW52LkRJVE9fU0lMRU5UID8ge30gOiBsb2csXG4gICAgICAuLi5yZXN0XG4gICAgfVxuICAgIHRoaXMua2V5cyA9IGtleXNcbiAgICB0aGlzLnByb3h5ID0gISFhcHAucHJveHlcbiAgICB0aGlzLnZhbGlkYXRvciA9IHZhbGlkYXRvciB8fCBuZXcgVmFsaWRhdG9yKClcbiAgICB0aGlzLnJvdXRlciA9IHJvdXRlciB8fCBuZXcgUm91dGVyKClcbiAgICB0aGlzLnZhbGlkYXRvci5hcHAgPSB0aGlzXG4gICAgdGhpcy5zdG9yYWdlcyA9IE9iamVjdC5jcmVhdGUobnVsbClcbiAgICB0aGlzLm1vZGVscyA9IE9iamVjdC5jcmVhdGUobnVsbClcbiAgICB0aGlzLnNlcnZpY2VzID0gT2JqZWN0LmNyZWF0ZShudWxsKVxuICAgIHRoaXMuY29udHJvbGxlcnMgPSBPYmplY3QuY3JlYXRlKG51bGwpXG4gICAgdGhpcy5oYXNDb250cm9sbGVyTWlkZGxld2FyZSA9IGZhbHNlXG4gICAgdGhpcy5zZXR1cExvZ2dlcigpXG4gICAgdGhpcy5zZXR1cEtuZXgoKVxuICAgIHRoaXMuc2V0dXBHbG9iYWxNaWRkbGV3YXJlKClcbiAgICBpZiAobWlkZGxld2FyZSkge1xuICAgICAgdGhpcy51c2UobWlkZGxld2FyZSlcbiAgICB9XG4gICAgaWYgKGNvbmZpZy5zdG9yYWdlcykge1xuICAgICAgdGhpcy5hZGRTdG9yYWdlcyhjb25maWcuc3RvcmFnZXMpXG4gICAgfVxuICAgIGlmIChtb2RlbHMpIHtcbiAgICAgIHRoaXMuYWRkTW9kZWxzKG1vZGVscylcbiAgICB9XG4gICAgaWYgKHNlcnZpY2VzKSB7XG4gICAgICB0aGlzLmFkZFNlcnZpY2VzKHNlcnZpY2VzKVxuICAgIH1cbiAgICBpZiAoY29udHJvbGxlcnMpIHtcbiAgICAgIHRoaXMuYWRkQ29udHJvbGxlcnMoY29udHJvbGxlcnMpXG4gICAgfVxuICB9XG5cbiAgYWRkUm91dGUodmVyYiwgcGF0aCwgdHJhbnNhY3RlZCwgaGFuZGxlcnMsIGNvbnRyb2xsZXIgPSBudWxsLCBhY3Rpb24gPSBudWxsKSB7XG4gICAgaGFuZGxlcnMgPSBhc0FycmF5KGhhbmRsZXJzKVxuICAgIGNvbnN0IGhhbmRsZXIgPSBoYW5kbGVycy5sZW5ndGggPiAxID8gY29tcG9zZShoYW5kbGVycykgOiBoYW5kbGVyc1swXVxuICAgIC8vIEluc3RlYWQgb2YgZGlyZWN0bHkgcGFzc2luZyBgaGFuZGxlcmAsIHBhc3MgYSBgcm91dGVgIG9iamVjdCB0aGF0IGFsc29cbiAgICAvLyB3aWxsIGJlIGV4cG9zZWQgdGhyb3VnaCBgY3R4LnJvdXRlYCwgc2VlIGByb3V0ZXJIYW5kbGVyKClgOlxuICAgIGNvbnN0IHJvdXRlID0ge1xuICAgICAgdmVyYixcbiAgICAgIHBhdGgsXG4gICAgICB0cmFuc2FjdGVkLFxuICAgICAgaGFuZGxlcixcbiAgICAgIGNvbnRyb2xsZXIsXG4gICAgICBhY3Rpb25cbiAgICB9XG4gICAgdGhpcy5yb3V0ZXJbdmVyYl0ocGF0aCwgcm91dGUpXG4gIH1cblxuICBhZGRNb2RlbHMobW9kZWxzKSB7XG4gICAgLy8gRmlyc3QgYWRkIGFsbCBtb2RlbHMgdGhlbiBjYWxsIGluaXRpYWxpemUoKSBmb3IgZWFjaCBpbiBhIHNlY29uZCBsb29wLFxuICAgIC8vIHNpbmNlIHRoZXkgbWF5IGJlIHJlZmVyZW5jaW5nIGVhY2ggb3RoZXIgaW4gcmVsYXRpb25zLlxuICAgIGZvciAoY29uc3QgbW9kZWxDbGFzcyBvZiBPYmplY3QudmFsdWVzKG1vZGVscykpIHtcbiAgICAgIHRoaXMuYWRkTW9kZWwobW9kZWxDbGFzcylcbiAgICB9XG4gICAgLy8gTm93IChyZS0pc29ydCBhbGwgbW9kZWxzIGJhc2VkIG9uIHRoZWlyIHJlbGF0aW9ucy5cbiAgICB0aGlzLm1vZGVscyA9IHRoaXMuc29ydE1vZGVscyh0aGlzLm1vZGVscylcbiAgICAvLyBGaWx0ZXIgdGhyb3VnaCBhbGwgc29ydGVkIG1vZGVscywga2VlcGluZyBvbmx5IHRoZSBuZXdseSBhZGRlZCBvbmVzLlxuICAgIGNvbnN0IHNvcnRlZE1vZGVscyA9IE9iamVjdC52YWx1ZXModGhpcy5tb2RlbHMpLmZpbHRlcihcbiAgICAgIG1vZGVsQ2xhc3MgPT4gbW9kZWxzW21vZGVsQ2xhc3MubmFtZV0gPT09IG1vZGVsQ2xhc3NcbiAgICApXG4gICAgLy8gSW5pdGlhbGl6ZSB0aGUgYWRkZWQgbW9kZWxzIGluIGNvcnJlY3Qgc29ydGVkIHNlcXVlbmNlLCBzbyB0aGF0IGZvciBldmVyeVxuICAgIC8vIG1vZGVsLCBnZXRSZWxhdGVkUmVsYXRpb25zKCkgcmV0dXJucyB0aGUgZnVsbCBsaXN0IG9mIHJlbGF0aW5nIHJlbGF0aW9ucy5cbiAgICBmb3IgKGNvbnN0IG1vZGVsQ2xhc3Mgb2Ygc29ydGVkTW9kZWxzKSB7XG4gICAgICBpZiAobW9kZWxzW21vZGVsQ2xhc3MubmFtZV0gPT09IG1vZGVsQ2xhc3MpIHtcbiAgICAgICAgbW9kZWxDbGFzcy5zZXR1cCh0aGlzLmtuZXgpXG4gICAgICAgIC8vIE5vdyB0aGF0IHRoZSBtb2RlbENsYXNzIGlzIHNldCB1cCwgY2FsbCBgaW5pdGlhbGl6ZSgpYCwgd2hpY2ggY2FuIGJlXG4gICAgICAgIC8vIG92ZXJyaWRkZW4gYnkgc3ViLWNsYXNzZXMsd2l0aG91dCBoYXZpbmcgdG8gY2FsbCBgc3VwZXIuaW5pdGlhbGl6ZSgpYFxuICAgICAgICBtb2RlbENsYXNzLmluaXRpYWxpemUoKVxuICAgICAgICB0aGlzLnZhbGlkYXRvci5hZGRTY2hlbWEobW9kZWxDbGFzcy5nZXRKc29uU2NoZW1hKCkpXG4gICAgICB9XG4gICAgfVxuICAgIGNvbnN0IHsgbG9nIH0gPSB0aGlzLmNvbmZpZ1xuICAgIGlmIChsb2cuc2NoZW1hIHx8IGxvZy5yZWxhdGlvbnMpIHtcbiAgICAgIGZvciAoY29uc3QgbW9kZWxDbGFzcyBvZiBzb3J0ZWRNb2RlbHMpIHtcbiAgICAgICAgY29uc3Qgc2hvdWxkTG9nID0gb3B0aW9uID0+IChcbiAgICAgICAgICBvcHRpb24gPT09IHRydWUgfHxcbiAgICAgICAgICBhc0FycmF5KG9wdGlvbikuaW5jbHVkZXMobW9kZWxDbGFzcy5uYW1lKVxuICAgICAgICApXG4gICAgICAgIGNvbnN0IGRhdGEgPSB7fVxuICAgICAgICBpZiAoc2hvdWxkTG9nKGxvZy5zY2hlbWEpKSB7XG4gICAgICAgICAgZGF0YS5zY2hlbWEgPSBtb2RlbENsYXNzLmdldEpzb25TY2hlbWEoKVxuICAgICAgICB9XG4gICAgICAgIGlmIChzaG91bGRMb2cobG9nLnJlbGF0aW9ucykpIHtcbiAgICAgICAgICBkYXRhLnJlbGF0aW9ucyA9IGNsb25lKG1vZGVsQ2xhc3MucmVsYXRpb25NYXBwaW5ncywgdmFsdWUgPT5cbiAgICAgICAgICAgIE1vZGVsLmlzUHJvdG90eXBlT2YodmFsdWUpID8gYFtNb2RlbDogJHt2YWx1ZS5uYW1lfV1gIDogdmFsdWVcbiAgICAgICAgICApXG4gICAgICAgIH1cbiAgICAgICAgaWYgKE9iamVjdC5rZXlzKGRhdGEpLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICBjb25zb2xlLmluZm8oXG4gICAgICAgICAgICBwaWNvLnllbGxvdy5ib2xkKGBcXG4ke21vZGVsQ2xhc3MubmFtZX06XFxuYCksXG4gICAgICAgICAgICB1dGlsLmluc3BlY3QoZGF0YSwge1xuICAgICAgICAgICAgICBjb2xvcnM6IHRydWUsXG4gICAgICAgICAgICAgIGRlcHRoOiBudWxsLFxuICAgICAgICAgICAgICBtYXhBcnJheUxlbmd0aDogbnVsbFxuICAgICAgICAgICAgfSlcbiAgICAgICAgICApXG4gICAgICAgIH1cbiAgICAgIH1cbiAgICB9XG4gIH1cblxuICBhZGRNb2RlbChtb2RlbENsYXNzKSB7XG4gICAgaWYgKE1vZGVsLmlzUHJvdG90eXBlT2YobW9kZWxDbGFzcykpIHtcbiAgICAgIG1vZGVsQ2xhc3MuYXBwID0gdGhpc1xuICAgICAgdGhpcy5tb2RlbHNbbW9kZWxDbGFzcy5uYW1lXSA9IG1vZGVsQ2xhc3NcbiAgICB9IGVsc2Uge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBJbnZhbGlkIG1vZGVsIGNsYXNzOiAke21vZGVsQ2xhc3N9YClcbiAgICB9XG4gIH1cblxuICBzb3J0TW9kZWxzKG1vZGVscykge1xuICAgIGNvbnN0IHNvcnRCeVJlbGF0aW9ucyA9IChsaXN0LCBjb2xsZWN0ZWQgPSB7fSwgZXhjbHVkZWQgPSB7fSkgPT4ge1xuICAgICAgZm9yIChjb25zdCBtb2RlbENsYXNzIG9mIGxpc3QpIHtcbiAgICAgICAgY29uc3QgeyBuYW1lIH0gPSBtb2RlbENsYXNzXG4gICAgICAgIGlmICghY29sbGVjdGVkW25hbWVdICYmICFleGNsdWRlZFtuYW1lXSkge1xuICAgICAgICAgIGZvciAoY29uc3QgcmVsYXRpb24gb2YgT2JqZWN0LnZhbHVlcyhtb2RlbENsYXNzLmdldFJlbGF0aW9ucygpKSkge1xuICAgICAgICAgICAgaWYgKCEocmVsYXRpb24gaW5zdGFuY2VvZiBCZWxvbmdzVG9PbmVSZWxhdGlvbikpIHtcbiAgICAgICAgICAgICAgY29uc3QgeyByZWxhdGVkTW9kZWxDbGFzcywgam9pblRhYmxlTW9kZWxDbGFzcyB9ID0gcmVsYXRpb25cbiAgICAgICAgICAgICAgZm9yIChjb25zdCByZWxhdGVkIG9mIFtqb2luVGFibGVNb2RlbENsYXNzLCByZWxhdGVkTW9kZWxDbGFzc10pIHtcbiAgICAgICAgICAgICAgICAvLyBFeGNsdWRlIHNlbGYtcmVmZXJlbmNlcyBhbmQgZ2VuZXJhdGVkIGpvaW4gbW9kZWxzOlxuICAgICAgICAgICAgICAgIGlmIChyZWxhdGVkICYmIHJlbGF0ZWQgIT09IG1vZGVsQ2xhc3MgJiYgbW9kZWxzW3JlbGF0ZWQubmFtZV0pIHtcbiAgICAgICAgICAgICAgICAgIHNvcnRCeVJlbGF0aW9ucyhbcmVsYXRlZF0sIGNvbGxlY3RlZCwge1xuICAgICAgICAgICAgICAgICAgICAvLyBFeGNsdWRlIG1vZGVsQ2xhc3MgdG8gcHJldmVudCBlbmRsZXNzIHJlY3Vyc2lvbnM6XG4gICAgICAgICAgICAgICAgICAgIFtuYW1lXTogbW9kZWxDbGFzcyxcbiAgICAgICAgICAgICAgICAgICAgLi4uZXhjbHVkZWRcbiAgICAgICAgICAgICAgICAgIH0pXG4gICAgICAgICAgICAgICAgfVxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICB9XG4gICAgICAgICAgfVxuICAgICAgICAgIGNvbGxlY3RlZFtuYW1lXSA9IG1vZGVsQ2xhc3NcbiAgICAgICAgfVxuICAgICAgfVxuICAgICAgcmV0dXJuIE9iamVjdC52YWx1ZXMoY29sbGVjdGVkKVxuICAgIH1cbiAgICAvLyBSZXR1cm4gYSBuZXcgb2JqZWN0IHdpdGggdGhlIHNvcnRlZCBtb2RlbHMgYXMgaXRzIGtleS92YWx1ZSBwYWlycy5cbiAgICAvLyBOT1RFOiBXZSBuZWVkIHRvIHJldmVyc2UgZm9yIHRoZSBhYm92ZSBhbGdvcml0aG0gdG8gc29ydCBwcm9wZXJseSxcbiAgICAvLyBhbmQgdGhlbiByZXZlcnNlIHRoZSByZXN1bHQgYmFjay5cbiAgICByZXR1cm4gc29ydEJ5UmVsYXRpb25zKE9iamVjdC52YWx1ZXMobW9kZWxzKS5yZXZlcnNlKCkpLnJldmVyc2UoKS5yZWR1Y2UoXG4gICAgICAobW9kZWxzLCBtb2RlbENsYXNzKSA9PiB7XG4gICAgICAgIG1vZGVsc1ttb2RlbENsYXNzLm5hbWVdID0gbW9kZWxDbGFzc1xuICAgICAgICByZXR1cm4gbW9kZWxzXG4gICAgICB9LFxuICAgICAgT2JqZWN0LmNyZWF0ZShudWxsKVxuICAgIClcbiAgfVxuXG4gIGdldE1vZGVsKG5hbWUpIHtcbiAgICByZXR1cm4gKFxuICAgICAgdGhpcy5tb2RlbHNbbmFtZV0gfHxcbiAgICAgICFuYW1lLmVuZHNXaXRoKCdNb2RlbCcpICYmIHRoaXMubW9kZWxzW2Ake25hbWV9TW9kZWxgXSB8fFxuICAgICAgbnVsbFxuICAgIClcbiAgfVxuXG4gIGZpbmRNb2RlbChjYWxsYmFjaykge1xuICAgIHJldHVybiBPYmplY3QudmFsdWVzKHRoaXMubW9kZWxzKS5maW5kKGNhbGxiYWNrKVxuICB9XG5cbiAgYWRkU2VydmljZXMoc2VydmljZXMpIHtcbiAgICBmb3IgKGNvbnN0IFtuYW1lLCBzZXJ2aWNlXSBvZiBPYmplY3QuZW50cmllcyhzZXJ2aWNlcykpIHtcbiAgICAgIC8vIEhhbmRsZSBFUzYgbW9kdWxlIHdlaXJkbmVzcyB0aGF0IGNhbiBoYXBwZW4sIGFwcGFyZW50bHk6XG4gICAgICBpZiAobmFtZSA9PT0gJ2RlZmF1bHQnICYmIGlzUGxhaW5PYmplY3Qoc2VydmljZSkpIHtcbiAgICAgICAgdGhpcy5hZGRTZXJ2aWNlcyhzZXJ2aWNlKVxuICAgICAgfSBlbHNlIHtcbiAgICAgICAgdGhpcy5hZGRTZXJ2aWNlKHNlcnZpY2UsIG5hbWUpXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgYWRkU2VydmljZShzZXJ2aWNlLCBuYW1lKSB7XG4gICAgLy8gQXV0by1pbnN0YW50aWF0ZSBjb250cm9sbGVyIGNsYXNzZXM6XG4gICAgaWYgKFNlcnZpY2UuaXNQcm90b3R5cGVPZihzZXJ2aWNlKSkge1xuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5ldy1jYXBcbiAgICAgIHNlcnZpY2UgPSBuZXcgc2VydmljZSh0aGlzLCBuYW1lKVxuICAgIH1cbiAgICBpZiAoIShzZXJ2aWNlIGluc3RhbmNlb2YgU2VydmljZSkpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgSW52YWxpZCBzZXJ2aWNlOiAke3NlcnZpY2V9YClcbiAgICB9XG4gICAgLy8gT25seSBhZnRlciB0aGUgY29uc3RydWN0b3IgaXMgY2FsbGVkLCBgc2VydmljZS5uYW1lYCBpcyBndWFyYW50ZWVkIHRvIGJlXG4gICAgLy8gc2V0IHRvIHRoZSBjb3JyZWN0IHZhbHVlLCBlLmcuIHdpdGggYW4gYWZ0ZXItY29uc3RydWN0b3IgY2xhc3MgcHJvcGVydHkuXG4gICAgKHsgbmFtZSB9ID0gc2VydmljZSlcbiAgICBjb25zdCBjb25maWcgPSB0aGlzLmNvbmZpZy5zZXJ2aWNlc1tuYW1lXVxuICAgIGlmIChjb25maWcgPT09IHVuZGVmaW5lZCkge1xuICAgICAgdGhyb3cgbmV3IEVycm9yKGBDb25maWd1cmF0aW9uIG1pc3NpbmcgZm9yIHNlcnZpY2UgJyR7bmFtZX0nYClcbiAgICB9XG4gICAgLy8gQXMgYSBjb252ZW50aW9uLCB0aGUgY29uZmlndXJhdGlvbiBvZiBhIHNlcnZpY2UgY2FuIGJlIHNldCB0byBgZmFsc2VgXG4gICAgLy8gaW4gb3JkZXIgdG8gZW50aXJlbHkgZGVhY3RpdmF0ZSB0aGUgc2VydmljZS5cbiAgICBpZiAoY29uZmlnICE9PSBmYWxzZSkge1xuICAgICAgc2VydmljZS5zZXR1cChjb25maWcpXG4gICAgICB0aGlzLnNlcnZpY2VzW25hbWVdID0gc2VydmljZVxuICAgICAgLy8gTm93IHRoYXQgdGhlIHNlcnZpY2UgaXMgc2V0IHVwLCBjYWxsIGBpbml0aWFsaXplKClgIHdoaWNoIGNhbiBiZVxuICAgICAgLy8gb3ZlcnJpZGRlbiBieSBzZXJ2aWNlcy5cbiAgICAgIHNlcnZpY2UuaW5pdGlhbGl6ZSgpXG4gICAgfVxuICB9XG5cbiAgZ2V0U2VydmljZShuYW1lKSB7XG4gICAgcmV0dXJuIHRoaXMuc2VydmljZXNbbmFtZV0gfHwgbnVsbFxuICB9XG5cbiAgZmluZFNlcnZpY2UoY2FsbGJhY2spIHtcbiAgICByZXR1cm4gT2JqZWN0LnZhbHVlcyh0aGlzLnNlcnZpY2VzKS5maW5kKGNhbGxiYWNrKVxuICB9XG5cbiAgZm9yRWFjaFNlcnZpY2UoY2FsbGJhY2spIHtcbiAgICByZXR1cm4gUHJvbWlzZS5hbGwoT2JqZWN0LnZhbHVlcyh0aGlzLnNlcnZpY2VzKS5tYXAoY2FsbGJhY2spKVxuICB9XG5cbiAgYWRkQ29udHJvbGxlcnMoY29udHJvbGxlcnMsIG5hbWVzcGFjZSkge1xuICAgIGZvciAoY29uc3QgW2tleSwgdmFsdWVdIG9mIE9iamVjdC5lbnRyaWVzKGNvbnRyb2xsZXJzKSkge1xuICAgICAgaWYgKGlzUGxhaW5PYmplY3QodmFsdWUpKSB7XG4gICAgICAgIHRoaXMuYWRkQ29udHJvbGxlcnModmFsdWUsIG5hbWVzcGFjZSA/IGAke25hbWVzcGFjZX0vJHtrZXl9YCA6IGtleSlcbiAgICAgIH0gZWxzZSB7XG4gICAgICAgIHRoaXMuYWRkQ29udHJvbGxlcih2YWx1ZSwgbmFtZXNwYWNlKVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIGFkZENvbnRyb2xsZXIoY29udHJvbGxlciwgbmFtZXNwYWNlKSB7XG4gICAgLy8gQ29udHJvbGxlcnMgcmVxdWlyZSBhZGRpdGlvbmFsIG1pZGRsZXdhcmUgdG8gYmUgaW5zdGFsbGVkIG9uY2UuXG4gICAgdGhpcy5zZXR1cENvbnRyb2xsZXJNaWRkbGV3YXJlKClcbiAgICAvLyBBdXRvLWluc3RhbnRpYXRlIGNvbnRyb2xsZXIgY2xhc3NlczpcbiAgICBpZiAoQ29udHJvbGxlci5pc1Byb3RvdHlwZU9mKGNvbnRyb2xsZXIpKSB7XG4gICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbmV3LWNhcFxuICAgICAgY29udHJvbGxlciA9IG5ldyBjb250cm9sbGVyKHRoaXMsIG5hbWVzcGFjZSlcbiAgICB9XG4gICAgaWYgKCEoY29udHJvbGxlciBpbnN0YW5jZW9mIENvbnRyb2xsZXIpKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgY29udHJvbGxlcjogJHtjb250cm9sbGVyfWApXG4gICAgfVxuICAgIC8vIEluaGVyaXRhbmNlIG9mIGFjdGlvbiBtZXRob2RzIGNhbm5vdCBoYXBwZW4gaW4gdGhlIGNvbnN0cnVjdG9yIGl0c2VsZixcbiAgICAvLyBzbyBjYWxsIHNlcGFyYXRlIGBzZXR1cCgpYCBtZXRob2QgYWZ0ZXIgaW4gb3JkZXIgdG8gdGFrZSBjYXJlIG9mIGl0LlxuICAgIGNvbnRyb2xsZXIuc2V0dXAoKVxuICAgIHRoaXMuY29udHJvbGxlcnNbY29udHJvbGxlci51cmxdID0gY29udHJvbGxlclxuICAgIC8vIE5vdyB0aGF0IHRoZSBjb250cm9sbGVyIGlzIHNldCB1cCwgY2FsbCBgaW5pdGlhbGl6ZSgpYCB3aGljaCBjYW4gYmVcbiAgICAvLyBvdmVycmlkZGVuIGJ5IGNvbnRyb2xsZXJzLlxuICAgIGNvbnRyb2xsZXIuaW5pdGlhbGl6ZSgpXG4gICAgLy8gRWFjaCBjb250cm9sbGVyIGNhbiBhbHNvIHByb3ZpZGUgZnVydGhlciBtaWRkbGV3YXJlLCBlLmcuXG4gICAgLy8gYEFkbWluQ29udHJvbGxlcmA6XG4gICAgY29uc3QgbWlkZGxld2FyZSA9IGNvbnRyb2xsZXIuY29tcG9zZSgpXG4gICAgaWYgKG1pZGRsZXdhcmUpIHtcbiAgICAgIHRoaXMudXNlKG1pZGRsZXdhcmUpXG4gICAgfVxuICB9XG5cbiAgZ2V0Q29udHJvbGxlcih1cmwpIHtcbiAgICByZXR1cm4gdGhpcy5jb250cm9sbGVyc1t1cmxdIHx8IG51bGxcbiAgfVxuXG4gIGZpbmRDb250cm9sbGVyKGNhbGxiYWNrKSB7XG4gICAgcmV0dXJuIE9iamVjdC52YWx1ZXModGhpcy5jb250cm9sbGVycykuZmluZChjYWxsYmFjaylcbiAgfVxuXG4gIGdldEFkbWluQ29udHJvbGxlcigpIHtcbiAgICByZXR1cm4gdGhpcy5maW5kQ29udHJvbGxlcihcbiAgICAgIGNvbnRyb2xsZXIgPT4gY29udHJvbGxlciBpbnN0YW5jZW9mIEFkbWluQ29udHJvbGxlclxuICAgIClcbiAgfVxuXG4gIGdldEFkbWluVnVlQ29uZmlnKCkge1xuICAgIHJldHVybiB0aGlzLmdldEFkbWluQ29udHJvbGxlcigpPy5nZXRWdWVDb25maWcoKSB8fCBudWxsXG4gIH1cblxuICBnZXRBc3NldENvbmZpZyh7XG4gICAgbW9kZWxzID0gT2JqZWN0LmtleXModGhpcy5tb2RlbHMpLFxuICAgIG5vcm1hbGl6ZURiTmFtZXMgPSB0aGlzLmNvbmZpZy5rbmV4Lm5vcm1hbGl6ZURiTmFtZXNcbiAgfSA9IHt9KSB7XG4gICAgY29uc3QgYXNzZXRDb25maWcgPSB7fVxuICAgIGZvciAoY29uc3QgbW9kZWxOYW1lIG9mIG1vZGVscykge1xuICAgICAgY29uc3QgbW9kZWxDbGFzcyA9IHRoaXMubW9kZWxzW21vZGVsTmFtZV1cbiAgICAgIGNvbnN0IHsgYXNzZXRzIH0gPSBtb2RlbENsYXNzLmRlZmluaXRpb25cbiAgICAgIGlmIChhc3NldHMpIHtcbiAgICAgICAgY29uc3Qgbm9ybWFsaXplZE1vZGVsTmFtZSA9IG5vcm1hbGl6ZURiTmFtZXNcbiAgICAgICAgICA/IHRoaXMubm9ybWFsaXplSWRlbnRpZmllcihtb2RlbE5hbWUpXG4gICAgICAgICAgOiBtb2RlbE5hbWVcbiAgICAgICAgY29uc3QgY29udmVydGVkQXNzZXRzID0ge31cbiAgICAgICAgZm9yIChjb25zdCBbYXNzZXREYXRhUGF0aCwgY29uZmlnXSBvZiBPYmplY3QuZW50cmllcyhhc3NldHMpKSB7XG4gICAgICAgICAgY29uc3Qge1xuICAgICAgICAgICAgcHJvcGVydHksXG4gICAgICAgICAgICBuZXN0ZWREYXRhUGF0aCxcbiAgICAgICAgICAgIG5hbWUsXG4gICAgICAgICAgICBpbmRleFxuICAgICAgICAgIH0gPSBtb2RlbENsYXNzLmdldFByb3BlcnR5T3JSZWxhdGlvbkF0RGF0YVBhdGgoYXNzZXREYXRhUGF0aClcbiAgICAgICAgICBpZiAocHJvcGVydHkgJiYgaW5kZXggPT09IDApIHtcbiAgICAgICAgICAgIGNvbnN0IG5vcm1hbGl6ZWROYW1lID0gbm9ybWFsaXplRGJOYW1lc1xuICAgICAgICAgICAgICA/IHRoaXMubm9ybWFsaXplSWRlbnRpZmllcihuYW1lKVxuICAgICAgICAgICAgICA6IG5hbWVcbiAgICAgICAgICAgIGNvbnN0IGRhdGFQYXRoID0gbm9ybWFsaXplRGF0YVBhdGgoW1xuICAgICAgICAgICAgICBub3JtYWxpemVkTmFtZSxcbiAgICAgICAgICAgICAgLi4ucGFyc2VEYXRhUGF0aChuZXN0ZWREYXRhUGF0aClcbiAgICAgICAgICAgIF0pXG4gICAgICAgICAgICBjb25zdCBhc3NldENvbmZpZ3MgPSBjb252ZXJ0ZWRBc3NldHNbbm9ybWFsaXplZE5hbWVdIHx8PSB7fVxuICAgICAgICAgICAgYXNzZXRDb25maWdzW2RhdGFQYXRoXSA9IGNvbmZpZ1xuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICB0aHJvdyBuZXcgRXJyb3IoJ05lc3RlZCBncmFwaCBwcm9wZXJ0aWVzIGFyZSBub3Qgc3VwcG9ydGVkIHlldCcpXG4gICAgICAgICAgfVxuICAgICAgICB9XG4gICAgICAgIGFzc2V0Q29uZmlnW25vcm1hbGl6ZWRNb2RlbE5hbWVdID0gY29udmVydGVkQXNzZXRzXG4gICAgICB9XG4gICAgfVxuICAgIHJldHVybiBhc3NldENvbmZpZ1xuICB9XG5cbiAgYWRkU3RvcmFnZXMoc3RvcmFnZXMpIHtcbiAgICBmb3IgKGNvbnN0IFtuYW1lLCBjb25maWddIG9mIE9iamVjdC5lbnRyaWVzKHN0b3JhZ2VzKSkge1xuICAgICAgdGhpcy5hZGRTdG9yYWdlKGNvbmZpZywgbmFtZSlcbiAgICB9XG4gIH1cblxuICBhZGRTdG9yYWdlKGNvbmZpZywgbmFtZSkge1xuICAgIGxldCBzdG9yYWdlID0gbnVsbFxuICAgIGlmIChpc1BsYWluT2JqZWN0KGNvbmZpZykpIHtcbiAgICAgIGNvbnN0IHN0b3JhZ2VDbGFzcyA9IFN0b3JhZ2UuZ2V0KGNvbmZpZy50eXBlKVxuICAgICAgaWYgKCFzdG9yYWdlQ2xhc3MpIHtcbiAgICAgICAgdGhyb3cgbmV3IEVycm9yKGBVbnN1cHBvcnRlZCBzdG9yYWdlOiAke2NvbmZpZ31gKVxuICAgICAgfVxuICAgICAgLy8gZXNsaW50LWRpc2FibGUtbmV4dC1saW5lIG5ldy1jYXBcbiAgICAgIHN0b3JhZ2UgPSBuZXcgc3RvcmFnZUNsYXNzKHRoaXMsIGNvbmZpZylcbiAgICB9IGVsc2UgaWYgKGNvbmZpZyBpbnN0YW5jZW9mIFN0b3JhZ2UpIHtcbiAgICAgIHN0b3JhZ2UgPSBjb25maWdcbiAgICB9XG4gICAgaWYgKHN0b3JhZ2UpIHtcbiAgICAgIGlmIChuYW1lKSB7XG4gICAgICAgIHN0b3JhZ2UubmFtZSA9IG5hbWVcbiAgICAgIH1cbiAgICAgIHRoaXMuc3RvcmFnZXNbc3RvcmFnZS5uYW1lXSA9IHN0b3JhZ2VcbiAgICB9XG4gICAgcmV0dXJuIHN0b3JhZ2VcbiAgfVxuXG4gIGdldFN0b3JhZ2UobmFtZSkge1xuICAgIHJldHVybiB0aGlzLnN0b3JhZ2VzW25hbWVdIHx8IG51bGxcbiAgfVxuXG4gIGNvbXBpbGVWYWxpZGF0b3IoanNvblNjaGVtYSwgb3B0aW9ucykge1xuICAgIHJldHVybiBqc29uU2NoZW1hXG4gICAgICA/IHRoaXMudmFsaWRhdG9yLmNvbXBpbGUoanNvblNjaGVtYSwgb3B0aW9ucylcbiAgICAgIDogbnVsbFxuICB9XG5cbiAgY29tcGlsZVBhcmFtZXRlcnNWYWxpZGF0b3IocGFyYW1ldGVycywgb3B0aW9ucyA9IHt9KSB7XG4gICAgY29uc3QgbGlzdCA9IFtdXG4gICAgY29uc3QgeyBkYXRhTmFtZSA9ICdkYXRhJyB9ID0gb3B0aW9uc1xuXG4gICAgbGV0IHByb3BlcnRpZXMgPSBudWxsXG4gICAgY29uc3QgYWRkUGFyYW1ldGVyID0gKG5hbWUsIHNjaGVtYSkgPT4ge1xuICAgICAgbGlzdC5wdXNoKHtcbiAgICAgICAgbmFtZTogbmFtZSA/PyBudWxsLFxuICAgICAgICAuLi5zY2hlbWFcbiAgICAgIH0pXG4gICAgICBpZiAoIXNjaGVtYS5tZW1iZXIpIHtcbiAgICAgICAgcHJvcGVydGllcyB8fD0ge31cbiAgICAgICAgcHJvcGVydGllc1tuYW1lIHx8IGRhdGFOYW1lXSA9IHNjaGVtYVxuICAgICAgfVxuICAgIH1cblxuICAgIC8vIFN1cHBvcnQgdHdvIGZvcm1hdHMgb2YgcGFyYW1ldGVycyBkZWZpbml0aW9uczpcbiAgICAvLyAtIEFuIGFycmF5IG9mIHBhcmFtZXRlciBzY2hlbWFzLCBuYW1lZCBieSB0aGVpciBgbmFtZWAga2V5LlxuICAgIC8vIC0gQW4gb2JqZWN0IG9mIHBhcmFtZXRlciBzY2hlbWFzLCBuYW1lZCBieSB0aGUga2V5IHVuZGVyIHdoaWNoIGVhY2hcbiAgICAvLyAgIHNjaGVtYSBpcyBzdG9yZWQgaW4gdGhlIHJvb3Qgb2JqZWN0LlxuICAgIC8vIElmIGFuIGFycmF5IGlzIHBhc3NlZCwgdGhlbiB0aGUgY29udHJvbGxlciBhY3Rpb25zIHJlY2VpdmVzIHRoZVxuICAgIC8vIHBhcmFtZXRlcnMgYXMgc2VwYXJhdGUgYXJndW1lbnRzLiBJZiBhbiBvYmplY3QgaXMgcGFzc2VkLCB0aGVuIHRoZVxuICAgIC8vIGFjdGlvbnMgcmVjZWl2ZXMgb25lIHBhcmFtZXRlciBvYmplY3Qgd2hlcmUgdW5kZXIgdGhlIHNhbWUga2V5cyB0aGVcbiAgICAvLyBzcGVjaWZpZWQgcGFyYW1ldGVyIHZhbHVlcyBhcmUgc3RvcmVkLlxuICAgIGxldCBhc09iamVjdCA9IGZhbHNlXG4gICAgaWYgKGlzQXJyYXkocGFyYW1ldGVycykpIHtcbiAgICAgIGZvciAoY29uc3QgeyBuYW1lLCAuLi5zY2hlbWEgfSBvZiBwYXJhbWV0ZXJzKSB7XG4gICAgICAgIGFkZFBhcmFtZXRlcihuYW1lLCBzY2hlbWEpXG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChpc09iamVjdChwYXJhbWV0ZXJzKSkge1xuICAgICAgYXNPYmplY3QgPSB0cnVlXG4gICAgICBmb3IgKGNvbnN0IFtuYW1lLCBzY2hlbWFdIG9mIE9iamVjdC5lbnRyaWVzKHBhcmFtZXRlcnMpKSB7XG4gICAgICAgIGlmIChzY2hlbWEpIHtcbiAgICAgICAgICBhZGRQYXJhbWV0ZXIobmFtZSwgc2NoZW1hKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgfSBlbHNlIGlmIChwYXJhbWV0ZXJzKSB7XG4gICAgICB0aHJvdyBuZXcgRXJyb3IoYEludmFsaWQgcGFyYW1ldGVycyBkZWZpbml0aW9uOiAke3BhcmFtZXRlcnN9YClcbiAgICB9XG4gICAgLy8gTk9URTogSWYgcHJvcGVydGllcyBpcyBudWxsLCBzY2hlbWEgYW5kIHZhbGlkYXRlIHdpbGwgYmVjb21lIG51bGwgdG9vLlxuICAgIC8vIE5PVEU6IElmIGl0IGlzIG5vdCBudWxsLCBpdCB3aWxsIGdldCBleHBhbmRlZCB0byBhbiBvYmplY3Qgc2NoZW1hLlxuICAgIGNvbnN0IHNjaGVtYSA9IGNvbnZlcnRTY2hlbWEocHJvcGVydGllcywgb3B0aW9ucylcbiAgICBjb25zdCB2YWxpZGF0ZSA9IHRoaXMuY29tcGlsZVZhbGlkYXRvcihzY2hlbWEsIHtcbiAgICAgIC8vIEZvciBwYXJhbWV0ZXJzLCBhbHdheXMgY29lcmNlIHR5cGVzLCBpbmNsdWRpbmcgYXJyYXlzLlxuICAgICAgY29lcmNlVHlwZXM6ICdhcnJheScsXG4gICAgICAuLi5vcHRpb25zXG4gICAgfSlcbiAgICBjb25zdCBjdHggPSB7XG4gICAgICBhcHA6IHRoaXMsXG4gICAgICB2YWxpZGF0b3I6IHRoaXMudmFsaWRhdG9yLFxuICAgICAgb3B0aW9uc1xuICAgIH1cbiAgICByZXR1cm4ge1xuICAgICAgbGlzdCxcbiAgICAgIHNjaGVtYSxcbiAgICAgIGFzT2JqZWN0LFxuICAgICAgZGF0YU5hbWUsXG4gICAgICB2YWxpZGF0ZTogdmFsaWRhdGVcbiAgICAgICAgLy8gVXNlIGBjYWxsKClgIHRvIHBhc3MgY3R4IGFzIGNvbnRleHQgdG8gQWp2LCBzZWUgcGFzc0NvbnRleHQ6XG4gICAgICAgID8gZGF0YSA9PiB2YWxpZGF0ZS5jYWxsKGN0eCwgZGF0YSlcbiAgICAgICAgOiBudWxsXG4gICAgfVxuICB9XG5cbiAgY3JlYXRlVmFsaWRhdGlvbkVycm9yKHsgdHlwZSwgbWVzc2FnZSwgZXJyb3JzLCBvcHRpb25zLCBqc29uIH0pIHtcbiAgICByZXR1cm4gbmV3IFZhbGlkYXRpb25FcnJvcih7XG4gICAgICB0eXBlLFxuICAgICAgbWVzc2FnZSxcbiAgICAgIGVycm9yczogdGhpcy52YWxpZGF0b3IucGFyc2VFcnJvcnMoZXJyb3JzLCBvcHRpb25zKSxcbiAgICAgIC8vIE9ubHkgaW5jbHVkZSB0aGUgSlNPTiBkYXRhIGluIHRoZSBlcnJvciBpZiBgbG9nLmVycm9ycy5qc29uYGlzIHNldC5cbiAgICAgIGpzb246IHRoaXMuY29uZmlnLmxvZy5lcnJvcnM/Lmpzb24gPyBqc29uIDogdW5kZWZpbmVkXG4gICAgfSlcbiAgfVxuXG4gIGNyZWF0ZURhdGFiYXNlRXJyb3IoZXJyb3IpIHtcbiAgICAvLyBSZW1vdmUga25leCBTUUwgcXVlcnkgYW5kIG1vdmUgdG8gc2VwYXJhdGUgYHNxbGAgcHJvcGVydHkuXG4gICAgLy8gVE9ETzogRml4IHRoaXMgcHJvcGVybHkgaW4gS25leCAvIE9iamVjdGlvbiBpbnN0ZWFkLCBzZWU6XG4gICAgLy8gaHR0cHM6Ly9naXR0ZXIuaW0vVmluY2l0L29iamVjdGlvbi5qcz9hdD01YTY4NzI4ZjVhOWViZTRmNzVjYTQwYjBcbiAgICBjb25zdCBbLCBzcWwsIG1lc3NhZ2VdID0gZXJyb3IubWVzc2FnZS5tYXRjaCgvXihbXFxzXFxTXSopIC0gKFtcXHNcXFNdKj8pJC8pIHx8XG4gICAgICBbbnVsbCwgbnVsbCwgZXJyb3IubWVzc2FnZV1cbiAgICByZXR1cm4gbmV3IERhdGFiYXNlRXJyb3IoZXJyb3IsIHtcbiAgICAgIG1lc3NhZ2UsXG4gICAgICAvLyBPbmx5IGluY2x1ZGUgdGhlIFNRTCBxdWVyeSBpbiB0aGUgZXJyb3IgaWYgYGxvZy5lcnJvcnMuc3FsYGlzIHNldC5cbiAgICAgIHNxbDogdGhpcy5jb25maWcubG9nLmVycm9ycz8uc3FsID8gc3FsIDogdW5kZWZpbmVkXG4gICAgfSlcbiAgfVxuXG4gIHNldHVwR2xvYmFsTWlkZGxld2FyZSgpIHtcbiAgICBjb25zdCB7IGFwcCwgbG9nIH0gPSB0aGlzLmNvbmZpZ1xuXG4gICAgdGhpcy51c2UoYXR0YWNoTG9nZ2VyKHRoaXMubG9nZ2VyKSlcblxuICAgIGlmIChhcHAucmVzcG9uc2VUaW1lICE9PSBmYWxzZSkge1xuICAgICAgdGhpcy51c2UocmVzcG9uc2VUaW1lKGdldE9wdGlvbnMoYXBwLnJlc3BvbnNlVGltZSkpKVxuICAgIH1cbiAgICBpZiAobG9nLnJlcXVlc3RzKSB7XG4gICAgICB0aGlzLnVzZShsb2dSZXF1ZXN0cygpKVxuICAgIH1cbiAgICAvLyBOZWVkcyB0byBiZSBwb3NpdGlvbmVkIGFmdGVyIHRoZSByZXF1ZXN0IGxvZ2dlciB0byBsb2cgdGhlIGNvcnJlY3RcbiAgICAvLyByZXNwb25zZSBzdGF0dXMuXG4gICAgdGhpcy51c2UoaGFuZGxlRXJyb3IoKSlcbiAgICBpZiAoYXBwLmhlbG1ldCAhPT0gZmFsc2UpIHtcbiAgICAgIHRoaXMudXNlKGhlbG1ldChnZXRPcHRpb25zKGFwcC5oZWxtZXQpKSlcbiAgICB9XG4gICAgaWYgKGFwcC5jb3JzICE9PSBmYWxzZSkge1xuICAgICAgdGhpcy51c2UoY29ycyhnZXRPcHRpb25zKGFwcC5jb3JzKSkpXG4gICAgfVxuICAgIGlmIChhcHAuY29tcHJlc3MgIT09IGZhbHNlKSB7XG4gICAgICB0aGlzLnVzZShjb21wcmVzcyhtZXJnZShcbiAgICAgICAge1xuICAgICAgICAgIC8vIFVzZSBhIHJlYXNvbmFibGUgZGVmYXVsdCBmb3IgQnJvdGxpIGNvbXByZXNzaW9uLlxuICAgICAgICAgIC8vIFNlZSBodHRwczovL2dpdGh1Yi5jb20va29hanMvY29tcHJlc3MvaXNzdWVzLzEyNlxuICAgICAgICAgIGJyOiB7XG4gICAgICAgICAgICBwYXJhbXM6IHtcbiAgICAgICAgICAgICAgW3psaWIuY29uc3RhbnRzLkJST1RMSV9QQVJBTV9RVUFMSVRZXTogNFxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSxcbiAgICAgICAgZ2V0T3B0aW9ucyhhcHAuY29tcHJlc3MpXG4gICAgICApKSlcbiAgICB9XG4gICAgaWYgKGFwcC5ldGFnICE9PSBmYWxzZSkge1xuICAgICAgdGhpcy51c2UoY29uZGl0aW9uYWwoKSlcbiAgICAgIHRoaXMudXNlKGV0YWcoKSlcbiAgICB9XG4gIH1cblxuICBzZXR1cENvbnRyb2xsZXJNaWRkbGV3YXJlKCkge1xuICAgIC8vIE5PVEU6IFRoaXMgaXMgbm90IHBhcnQgb2YgdGhlIGF1dG9tYXRpYyBgc2V0dXBHbG9iYWxNaWRkbGV3YXJlKClgIHNvIHRoYXRcbiAgICAvLyBhcHBzIGNhbiBzZXQgdXAgdGhlIHN0YXRpYyBzZXJ2aW5nIG9mIGFzc2V0cyBiZWZvcmUgaW5zdGFsbGluZyB0aGVcbiAgICAvLyBzZXNzaW9uIGFuZCBwYXNzcG9ydCBtaWRkbGV3YXJlLiBJdCBpcyBjYWxsZWQgZnJvbSBgYWRkQ29udHJvbGxlcigpYC5cbiAgICAvLyBVc2UgYSBmbGFnIHRvIG9ubHkgaW5zdGFsbCB0aGUgbWlkZGxld2FyZSBvbmNlOlxuICAgIGlmICghdGhpcy5oYXNDb250cm9sbGVyTWlkZGxld2FyZSkge1xuICAgICAgY29uc3QgeyBhcHAgfSA9IHRoaXMuY29uZmlnXG4gICAgICAvLyBTZXF1ZW5jZSBpcyBpbXBvcnRhbnQ6XG4gICAgICAvLyAxLiBib2R5IHBhcnNlclxuICAgICAgdGhpcy51c2UoYm9keVBhcnNlcihnZXRPcHRpb25zKGFwcC5ib2R5UGFyc2VyKSkpXG4gICAgICAvLyAyLiBmaW5kIHJvdXRlIGZyb20gcm91dGVzIGluc3RhbGxlZCBieSBjb250cm9sbGVycy5cbiAgICAgIHRoaXMudXNlKGZpbmRSb3V0ZSh0aGlzLnJvdXRlcikpXG4gICAgICAvLyAzLiByZXNwZWN0IHRyYW5zYWN0ZWQgc2V0dGluZ3MsIGNyZWF0ZSBhbmQgaGFuZGxlIHRyYW5zYWN0aW9ucy5cbiAgICAgIHRoaXMudXNlKGNyZWF0ZVRyYW5zYWN0aW9uKCkpXG4gICAgICAvLyA0LiBzZXNzaW9uXG4gICAgICBpZiAoYXBwLnNlc3Npb24pIHtcbiAgICAgICAgY29uc3Qge1xuICAgICAgICAgIG1vZGVsQ2xhc3MsXG4gICAgICAgICAgLi4ub3B0aW9uc1xuICAgICAgICB9ID0gZ2V0T3B0aW9ucyhhcHAuc2Vzc2lvbilcbiAgICAgICAgaWYgKG1vZGVsQ2xhc3MpIHtcbiAgICAgICAgICAvLyBDcmVhdGUgYSBDb250ZXh0U3RvcmUgdGhhdCByZXNvbHZlZCB0aGUgc3BlY2lmaWVkIG1vZGVsIGNsYXNzLFxuICAgICAgICAgIC8vIHVzZXMgaXQgdG8gcGVyc2lzdCBhbmQgcmV0cmlldmUgdGhlIHNlc3Npb24sIGFuZCBhdXRvbWF0aWNhbGx5XG4gICAgICAgICAgLy8gYmluZHMgYWxsIGRiIG9wZXJhdGlvbnMgdG8gYGN0eC50cmFuc2FjdGlvbmAsIGlmIGl0IGlzIHNldC5cbiAgICAgICAgICAvLyBlc2xpbnQtZGlzYWJsZS1uZXh0LWxpbmUgbmV3LWNhcFxuICAgICAgICAgIG9wdGlvbnMuQ29udGV4dFN0b3JlID0gU2Vzc2lvblN0b3JlKG1vZGVsQ2xhc3MpXG4gICAgICAgIH1cbiAgICAgICAgdGhpcy51c2Uoc2Vzc2lvbihvcHRpb25zLCB0aGlzKSlcbiAgICAgIH1cbiAgICAgIC8vIDUuIHBhc3Nwb3J0XG4gICAgICBpZiAoYXBwLnBhc3Nwb3J0KSB7XG4gICAgICAgIHRoaXMudXNlKHBhc3Nwb3J0LmluaXRpYWxpemUoKSlcbiAgICAgICAgaWYgKGFwcC5zZXNzaW9uKSB7XG4gICAgICAgICAgdGhpcy51c2UocGFzc3BvcnQuc2Vzc2lvbigpKVxuICAgICAgICB9XG4gICAgICAgIHRoaXMudXNlKGhhbmRsZVVzZXIoKSlcbiAgICAgIH1cblxuICAgICAgLy8gNi4gZmluYWxseSBoYW5kbGUgdGhlIGZvdW5kIHJvdXRlLCBvciBzZXQgc3RhdHVzIC8gYWxsb3cgYWNjb3JkaW5nbHkuXG4gICAgICB0aGlzLnVzZShoYW5kbGVSb3V0ZSgpKVxuICAgICAgdGhpcy5oYXNDb250cm9sbGVyTWlkZGxld2FyZSA9IHRydWVcbiAgICB9XG4gIH1cblxuICBzZXR1cExvZ2dlcigpIHtcbiAgICBjb25zdCB7IGVyciwgcmVxLCByZXMgfSA9IHBpbm8uc3RkU2VyaWFsaXplcnNcbiAgICAvLyBPbmx5IGluY2x1ZGUgYGlkYCBmcm9tIHRoZSB1c2VyLCB0byBub3QgaW5hZHZlcnRlbnRseSBsb2cgUElJLlxuICAgIGNvbnN0IHVzZXIgPSB1c2VyID0+ICh7IGlkOiB1c2VyLmlkIH0pXG4gICAgY29uc3Qgc2VyaWFsaXplcnMgPSB7IGVyciwgcmVxLCByZXMsIHVzZXIgfVxuXG4gICAgY29uc3QgbG9nZ2VyID0gcGlubyhtZXJnZShcbiAgICAgIHtcbiAgICAgICAgbGV2ZWw6ICdpbmZvJyxcbiAgICAgICAgc2VyaWFsaXplcnMsXG4gICAgICAgIHByZXR0eVByaW50OiB7XG4gICAgICAgICAgLy8gTGlzdCBvZiBrZXlzIHRvIGlnbm9yZSBpbiBwcmV0dHkgbW9kZS5cbiAgICAgICAgICBpZ25vcmU6ICdyZXEscmVzLGR1cmF0aW9uTXMsdXNlcixyZXF1ZXN0SWQnLFxuICAgICAgICAgIC8vIFNZUyB0byB1c2Ugc3lzdGVtIHRpbWUgYW5kIG5vdCBVVEMuXG4gICAgICAgICAgdHJhbnNsYXRlVGltZTogJ1NZUzpISDpNTTpzcy5sJ1xuICAgICAgICB9LFxuICAgICAgICAvLyBSZWRhY3QgY29tbW9uIHNlbnNpdGl2ZSBoZWFkZXJzLlxuICAgICAgICByZWRhY3Q6IFtcbiAgICAgICAgICAnKi5oZWFkZXJzW1wiY29va2llXCJdJyxcbiAgICAgICAgICAnKi5oZWFkZXJzW1wic2V0LWNvb2tpZVwiXScsXG4gICAgICAgICAgJyouaGVhZGVyc1tcImF1dGhvcml6YXRpb25cIl0nXG4gICAgICAgIF0sXG4gICAgICAgIGJhc2U6IG51bGwgLy8gbm8gcGlkLGhvc3RuYW1lLG5hbWVcbiAgICAgIH0sXG4gICAgICBnZXRPcHRpb25zKHRoaXMuY29uZmlnLmxvZ2dlcilcbiAgICApKVxuXG4gICAgdGhpcy5sb2dnZXIgPSBsb2dnZXIuY2hpbGQoeyBuYW1lOiAnYXBwJyB9KVxuICB9XG5cbiAgc2V0dXBLbmV4KCkge1xuICAgIGxldCB7IGtuZXgsIGxvZyB9ID0gdGhpcy5jb25maWdcbiAgICBpZiAoa25leD8uY2xpZW50KSB7XG4gICAgICBjb25zdCBzbmFrZUNhc2VPcHRpb25zID0ga25leC5ub3JtYWxpemVEYk5hbWVzID09PSB0cnVlXG4gICAgICAgID8ge31cbiAgICAgICAgOiBrbmV4Lm5vcm1hbGl6ZURiTmFtZXNcbiAgICAgIGlmIChzbmFrZUNhc2VPcHRpb25zKSB7XG4gICAgICAgIGtuZXggPSB7XG4gICAgICAgICAgLi4ua25leCxcbiAgICAgICAgICAuLi5rbmV4U25ha2VDYXNlTWFwcGVycyhzbmFrZUNhc2VPcHRpb25zKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICB0aGlzLmtuZXggPSBLbmV4KGtuZXgpXG4gICAgICAvLyBTdXBwb3J0IFBvc3RncmVTUUwgdHlwZSBwYXJzZXIgbWFwcGluZ3MgaW4gdGhlIGNvbmZpZy5cbiAgICAgIGlmIChcbiAgICAgICAga25leC5jbGllbnQgPT09ICdwb3N0Z3Jlc3FsJyAmJlxuICAgICAgICBrbmV4LnR5cGVQYXJzZXJzICYmXG4gICAgICAgIHRoaXMua25leC5jbGllbnQuZHJpdmVyXG4gICAgICApIHtcbiAgICAgICAgZm9yIChjb25zdCBbdHlwZSwgcGFyc2VyXSBvZiBPYmplY3QuZW50cmllcyhrbmV4LnR5cGVQYXJzZXJzKSkge1xuICAgICAgICAgIHRoaXMua25leC5jbGllbnQuZHJpdmVyLnR5cGVzLnNldFR5cGVQYXJzZXIodHlwZSwgcGFyc2VyKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICBpZiAobG9nLnNxbCkge1xuICAgICAgICB0aGlzLnNldHVwS25leExvZ2dpbmcoKVxuICAgICAgfVxuICAgIH1cbiAgfVxuXG4gIHNldHVwS25leExvZ2dpbmcoKSB7XG4gICAgY29uc3Qgc3RhcnRUaW1lcyA9IHt9XG4gICAgY29uc3QgbG9nZ2VyID0gdGhpcy5sb2dnZXIuY2hpbGQoeyBuYW1lOiAnc3FsJyB9KVxuICAgIGZ1bmN0aW9uIGVuZChxdWVyeSwgeyByZXNwb25zZSwgZXJyb3IgfSkge1xuICAgICAgY29uc3QgaWQgPSBxdWVyeS5fX2tuZXhRdWVyeVVpZFxuICAgICAgY29uc3QgZGlmZiA9IHByb2Nlc3MuaHJ0aW1lKHN0YXJ0VGltZXNbaWRdKVxuICAgICAgY29uc3QgZHVyYXRpb24gPSBkaWZmWzBdICogMWUzICsgZGlmZlsxXSAvIDFlNlxuICAgICAgZGVsZXRlIHN0YXJ0VGltZXNbaWRdXG4gICAgICBjb25zdCB7IHNxbCwgYmluZGluZ3MgfSA9IHF1ZXJ5XG4gICAgICByZXNwb25zZSA9IE9iamVjdC5mcm9tRW50cmllcyhcbiAgICAgICAgT2JqZWN0LmVudHJpZXMocmVzcG9uc2UpLmZpbHRlcihcbiAgICAgICAgICAoW2tleV0pID0+ICFrZXkuc3RhcnRzV2l0aCgnXycpXG4gICAgICAgIClcbiAgICAgIClcbiAgICAgIGxvZ2dlci5pbmZvKHsgZHVyYXRpb24sIGJpbmRpbmdzLCByZXNwb25zZSwgZXJyb3IgfSwgc3FsKVxuICAgIH1cblxuICAgIHRoaXMua25leFxuICAgICAgLm9uKCdxdWVyeScsIHF1ZXJ5ID0+IHtcbiAgICAgICAgc3RhcnRUaW1lc1txdWVyeS5fX2tuZXhRdWVyeVVpZF0gPSBwcm9jZXNzLmhydGltZSgpXG4gICAgICB9KVxuICAgICAgLm9uKCdxdWVyeS1yZXNwb25zZScsIChyZXNwb25zZSwgcXVlcnkpID0+IHtcbiAgICAgICAgZW5kKHF1ZXJ5LCB7IHJlc3BvbnNlIH0pXG4gICAgICB9KVxuICAgICAgLm9uKCdxdWVyeS1lcnJvcicsIChlcnJvciwgcXVlcnkpID0+IHtcbiAgICAgICAgZW5kKHF1ZXJ5LCB7IGVycm9yIH0pXG4gICAgICB9KVxuICB9XG5cbiAgbm9ybWFsaXplSWRlbnRpZmllcihpZGVudGlmaWVyKSB7XG4gICAgcmV0dXJuIHRoaXMua25leC5jbGllbnQud3JhcElkZW50aWZpZXIoaWRlbnRpZmllcikucmVwbGFjZSgvWydgXCJdL2csICcnKVxuICB9XG5cbiAgZGVub3JtYWxpemVJZGVudGlmaWVyKGlkZW50aWZpZXIpIHtcbiAgICBjb25zdCBvYmogPSB0aGlzLmtuZXguY2xpZW50LnBvc3RQcm9jZXNzUmVzcG9uc2UoeyBbaWRlbnRpZmllcl06IDEgfSlcbiAgICByZXR1cm4gT2JqZWN0LmtleXMob2JqKVswXVxuICB9XG5cbiAgbm9ybWFsaXplUGF0aChwYXRoKSB7XG4gICAgcmV0dXJuIHRoaXMuY29uZmlnLmFwcC5ub3JtYWxpemVQYXRocyA/IGh5cGhlbmF0ZShwYXRoKSA6IHBhdGhcbiAgfVxuXG4gIGZvcm1hdEVycm9yKGVycikge1xuICAgIGNvbnN0IG1lc3NhZ2UgPSBlcnIudG9KU09OXG4gICAgICA/IGZvcm1hdEpzb24oZXJyLnRvSlNPTigpKVxuICAgICAgOiBlcnIubWVzc2FnZSB8fCBlcnJcbiAgICBjb25zdCBzdHIgPSBgJHtlcnIubmFtZX06ICR7bWVzc2FnZX1gXG4gICAgcmV0dXJuIGVyci5zdGFjayAmJiB0aGlzLmNvbmZpZy5sb2cuZXJyb3JzPy5zdGFjayAhPT0gZmFsc2VcbiAgICAgID8gYCR7c3RyfVxcbiR7ZXJyLnN0YWNrLnNwbGl0KC9cXG58XFxyXFxufFxcci8pLnNsaWNlKDEpLmpvaW4ob3MuRU9MKX1gXG4gICAgICA6IHN0clxuICB9XG5cbiAgbG9nRXJyb3IoZXJyLCBjdHgpIHtcbiAgICBpZiAoIWVyci5leHBvc2UgJiYgIXRoaXMuc2lsZW50KSB7XG4gICAgICB0cnkge1xuICAgICAgICBjb25zdCB0ZXh0ID0gdGhpcy5mb3JtYXRFcnJvcihlcnIpXG4gICAgICAgIGNvbnN0IGxldmVsID1cbiAgICAgICAgICBlcnIgaW5zdGFuY2VvZiBSZXNwb25zZUVycm9yICYmIGVyci5zdGF0dXMgPCA1MDAgPyAnaW5mbycgOiAnZXJyb3InXG4gICAgICAgIGNvbnN0IGxvZ2dlciA9IGN0eD8ubG9nZ2VyIHx8IHRoaXMubG9nZ2VyXG4gICAgICAgIGxvZ2dlcltsZXZlbF0odGV4dClcbiAgICAgIH0gY2F0Y2ggKGUpIHtcbiAgICAgICAgY29uc29sZS5lcnJvcignQ291bGQgbm90IGxvZyBlcnJvcicsIGUpXG4gICAgICB9XG4gICAgfVxuICB9XG5cbiAgYXN5bmMgc3RhcnQoKSB7XG4gICAgaWYgKHRoaXMuY29uZmlnLmxvZy5lcnJvcnMgIT09IGZhbHNlKSB7XG4gICAgICB0aGlzLm9uKCdlcnJvcicsIHRoaXMubG9nRXJyb3IpXG4gICAgfVxuICAgIGF3YWl0IHRoaXMuZW1pdCgnYmVmb3JlOnN0YXJ0JylcbiAgICBhd2FpdCB0aGlzLmZvckVhY2hTZXJ2aWNlKHNlcnZpY2UgPT4gc2VydmljZS5zdGFydCgpKVxuICAgIGNvbnN0IHtcbiAgICAgIHNlcnZlcjogeyBob3N0LCBwb3J0IH0sXG4gICAgICBlbnZcbiAgICB9ID0gdGhpcy5jb25maWdcbiAgICB0aGlzLnNlcnZlciA9IGF3YWl0IG5ldyBQcm9taXNlKChyZXNvbHZlLCByZWplY3QpID0+IHtcbiAgICAgIGNvbnN0IHNlcnZlciA9IHRoaXMubGlzdGVuKHBvcnQsIGhvc3QsICgpID0+IHtcbiAgICAgICAgY29uc3QgeyBwb3J0IH0gPSBzZXJ2ZXIuYWRkcmVzcygpXG4gICAgICAgIGNvbnNvbGUuaW5mbyhcbiAgICAgICAgICBgJHtlbnZ9IHNlcnZlciBzdGFydGVkIGF0IGh0dHA6Ly8ke2hvc3R9OiR7cG9ydH1gXG4gICAgICAgIClcbiAgICAgICAgcmVzb2x2ZShzZXJ2ZXIpXG4gICAgICB9KVxuICAgICAgaWYgKCFzZXJ2ZXIpIHtcbiAgICAgICAgcmVqZWN0KG5ldyBFcnJvcihgVW5hYmxlIHRvIHN0YXJ0IHNlcnZlciBhdCBodHRwOi8vJHtob3N0fToke3BvcnR9YCkpXG4gICAgICB9XG4gICAgfSlcbiAgICBhd2FpdCB0aGlzLmVtaXQoJ2FmdGVyOnN0YXJ0JylcbiAgfVxuXG4gIGFzeW5jIHN0b3AoKSB7XG4gICAgYXdhaXQgdGhpcy5lbWl0KCdiZWZvcmU6c3RvcCcpXG4gICAgdGhpcy5zZXJ2ZXIgPSBhd2FpdCBuZXcgUHJvbWlzZSgocmVzb2x2ZSwgcmVqZWN0KSA9PiB7XG4gICAgICBjb25zdCB7IHNlcnZlciB9ID0gdGhpc1xuICAgICAgaWYgKHNlcnZlcikge1xuICAgICAgICBzZXJ2ZXIuY2xvc2UoZXJyID0+IHtcbiAgICAgICAgICBpZiAoZXJyKSB7XG4gICAgICAgICAgICByZWplY3QoZXJyKVxuICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICByZXNvbHZlKG51bGwpXG4gICAgICAgICAgfVxuICAgICAgICB9KVxuICAgICAgICAvLyBIYWNrIHRvIG1ha2Ugc3VyZSB0aGF0IHdlIGNsb3NlIHRoZSBzZXJ2ZXIsXG4gICAgICAgIC8vICBldmVuIGlmIHNvY2tldHMgYXJlIHN0aWxsIG9wZW4uXG4gICAgICAgIC8vICBUYWtlbiBmcm9tIGh0dHBzOi8vc3RhY2tvdmVyZmxvdy5jb20vYS8zNjgzMDA3Mi5cbiAgICAgICAgLy8gIEEgcHJvcGVyIHNvbHV0aW9uIHdvdWxkIGJlIHRvIHVzZSBhIGxpYnJhcnksIGV4OiBodHRwczovL2dpdGh1Yi5jb20vZ29kYWRkeS90ZXJtaW51c1xuICAgICAgICBzZXRJbW1lZGlhdGUoKCkgPT4gc2VydmVyLmVtaXQoJ2Nsb3NlJykpXG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZWplY3QobmV3IEVycm9yKCdTZXJ2ZXIgaXMgbm90IHJ1bm5pbmcnKSlcbiAgICAgIH1cbiAgICB9KVxuICAgIGF3YWl0IHRoaXMuZm9yRWFjaFNlcnZpY2Uoc2VydmljZSA9PiBzZXJ2aWNlLnN0b3AoKSlcbiAgICBhd2FpdCB0aGlzLmVtaXQoJ2FmdGVyOnN0b3AnKVxuICAgIGlmICh0aGlzLmNvbmZpZy5sb2cuZXJyb3JzICE9PSBmYWxzZSkge1xuICAgICAgdGhpcy5vZmYoJ2Vycm9yJywgdGhpcy5sb2dFcnJvcilcbiAgICB9XG4gIH1cblxuICBhc3luYyBzdGFydE9yRXhpdCgpIHtcbiAgICB0cnkge1xuICAgICAgYXdhaXQgdGhpcy5zdGFydCgpXG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICB0aGlzLmxvZ0Vycm9yKGVycilcbiAgICAgIHByb2Nlc3MuZXhpdCgtMSlcbiAgICB9XG4gIH1cblxuICAvLyBBc3NldHMgaGFuZGxpbmdcblxuICBhc3luYyBjcmVhdGVBc3NldHMoc3RvcmFnZSwgZmlsZXMsIGNvdW50ID0gMCwgdHJ4ID0gbnVsbCkge1xuICAgIGNvbnN0IEFzc2V0TW9kZWwgPSB0aGlzLmdldE1vZGVsKCdBc3NldCcpXG4gICAgaWYgKEFzc2V0TW9kZWwpIHtcbiAgICAgIGNvbnN0IGFzc2V0cyA9IGZpbGVzLm1hcChmaWxlID0+ICh7XG4gICAgICAgIGtleTogZmlsZS5rZXksXG4gICAgICAgIGZpbGUsXG4gICAgICAgIHN0b3JhZ2U6IHN0b3JhZ2UubmFtZSxcbiAgICAgICAgY291bnRcbiAgICAgIH0pKVxuICAgICAgcmV0dXJuIEFzc2V0TW9kZWxcbiAgICAgICAgLnF1ZXJ5KHRyeClcbiAgICAgICAgLmluc2VydChhc3NldHMpXG4gICAgfVxuICAgIHJldHVybiBudWxsXG4gIH1cblxuICBhc3luYyBoYW5kbGVBZGRkZWRBbmRSZW1vdmVkQXNzZXRzKFxuICAgIHN0b3JhZ2UsXG4gICAgYWRkZWRGaWxlcyxcbiAgICByZW1vdmVkRmlsZXMsXG4gICAgdHJ4ID0gbnVsbFxuICApIHtcbiAgICBjb25zdCB7XG4gICAgICBhc3NldHM6IHtcbiAgICAgICAgY2xlYW51cFRpbWVUaHJlc2hvbGQgPSAwXG4gICAgICB9ID0ge31cbiAgICB9ID0gdGhpcy5jb25maWdcbiAgICAvLyBPbmx5IHJlbW92ZSB1bnVzZWQgYXNzZXRzIHRoYXQgaGF2ZW4ndCBzZWVuIGNoYW5nZXMgZm9yIGdpdmVuIHRpbWVmcmFtZS5cbiAgICBjb25zdCB0aW1lVGhyZXNob2xkID0gaXNTdHJpbmcoY2xlYW51cFRpbWVUaHJlc2hvbGQpXG4gICAgICA/IHBhcnNlRHVyYXRpb24oY2xlYW51cFRpbWVUaHJlc2hvbGQpXG4gICAgICA6IGNsZWFudXBUaW1lVGhyZXNob2xkXG5cbiAgICBjb25zdCBpbXBvcnRlZEZpbGVzID0gW11cbiAgICBjb25zdCBBc3NldE1vZGVsID0gdGhpcy5nZXRNb2RlbCgnQXNzZXQnKVxuICAgIGlmIChBc3NldE1vZGVsKSB7XG4gICAgICBpbXBvcnRlZEZpbGVzLnB1c2goXG4gICAgICAgIC4uLmF3YWl0IHRoaXMuYWRkRm9yZWlnbkFzc2V0cyhzdG9yYWdlLCBhZGRlZEZpbGVzLCB0cngpXG4gICAgICApXG4gICAgICBpZiAoXG4gICAgICAgIGFkZGVkRmlsZXMubGVuZ3RoID4gMCB8fFxuICAgICAgICByZW1vdmVkRmlsZXMubGVuZ3RoID4gMFxuICAgICAgKSB7XG4gICAgICAgIGNvbnN0IGNoYW5nZUNvdW50ID0gKGZpbGVzLCBpbmNyZW1lbnQpID0+IChcbiAgICAgICAgICBmaWxlcy5sZW5ndGggPiAwICYmXG4gICAgICAgICAgQXNzZXRNb2RlbC5xdWVyeSh0cngpXG4gICAgICAgICAgICAud2hlcmVJbigna2V5JywgZmlsZXMubWFwKGZpbGUgPT4gZmlsZS5rZXkpKVxuICAgICAgICAgICAgLmluY3JlbWVudCgnY291bnQnLCBpbmNyZW1lbnQpXG4gICAgICAgIClcbiAgICAgICAgYXdhaXQgUHJvbWlzZS5hbGwoW1xuICAgICAgICAgIGNoYW5nZUNvdW50KGFkZGVkRmlsZXMsIDEpLFxuICAgICAgICAgIGNoYW5nZUNvdW50KHJlbW92ZWRGaWxlcywgLTEpXG4gICAgICAgIF0pXG4gICAgICAgIGlmICh0aW1lVGhyZXNob2xkID4gMCkge1xuICAgICAgICAgIHNldFRpbWVvdXQoXG4gICAgICAgICAgICAvLyBEb24ndCBwYXNzIGB0cnhgIGhlcmUsIGFzIHdlIHdhbnQgdGhpcyBkZWxheWVkIGV4ZWN1dGlvbiB0b1xuICAgICAgICAgICAgLy8gY3JlYXRlIGl0cyBvd24gdHJhbnNhY3Rpb24uXG4gICAgICAgICAgICAoKSA9PiB0aGlzLnJlbGVhc2VVbnVzZWRBc3NldHModGltZVRocmVzaG9sZCksXG4gICAgICAgICAgICB0aW1lVGhyZXNob2xkXG4gICAgICAgICAgKVxuICAgICAgICB9XG4gICAgICB9XG4gICAgICAvLyBBbHNvIGV4ZWN1dGUgcmVsZWFzZVVudXNlZEFzc2V0cygpIGltbWVkaWF0ZWx5IGluIHRoZSBzYW1lXG4gICAgICAvLyB0cmFuc2FjdGlvbiwgdG8gcG90ZW50aWFsbHkgY2xlYW4gdXAgb3RoZXIgcGVuZGluZyBhc3NldHMuXG4gICAgICBhd2FpdCB0aGlzLnJlbGVhc2VVbnVzZWRBc3NldHModGltZVRocmVzaG9sZCwgdHJ4KVxuICAgICAgcmV0dXJuIGltcG9ydGVkRmlsZXNcbiAgICB9XG4gIH1cblxuICBhc3luYyBhZGRGb3JlaWduQXNzZXRzKHN0b3JhZ2UsIGZpbGVzLCB0cnggPSBudWxsKSB7XG4gICAgY29uc3QgaW1wb3J0ZWRGaWxlcyA9IFtdXG4gICAgY29uc3QgQXNzZXRNb2RlbCA9IHRoaXMuZ2V0TW9kZWwoJ0Fzc2V0JylcbiAgICBpZiAoQXNzZXRNb2RlbCkge1xuICAgICAgLy8gRmluZCBtaXNzaW5nIGFzc2V0cyAoY29waWVkIGZyb20gYW5vdGhlciBzeXN0ZW0pLCBhbmQgYWRkIHRoZW0uXG4gICAgICBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgZmlsZXMubWFwKGFzeW5jIGZpbGUgPT4ge1xuICAgICAgICAgIGNvbnN0IGFzc2V0ID0gYXdhaXQgQXNzZXRNb2RlbC5xdWVyeSh0cngpLmZpbmRPbmUoJ2tleScsIGZpbGUua2V5KVxuICAgICAgICAgIGlmICghYXNzZXQpIHtcbiAgICAgICAgICAgIGlmIChmaWxlLmRhdGEgfHwgZmlsZS51cmwpIHtcbiAgICAgICAgICAgICAgbGV0IHsgZGF0YSB9ID0gZmlsZVxuICAgICAgICAgICAgICBpZiAoIWRhdGEpIHtcbiAgICAgICAgICAgICAgICBjb25zb2xlLmluZm8oXG4gICAgICAgICAgICAgICAgICBgJHtcbiAgICAgICAgICAgICAgICAgICAgcGljby5yZWQoJ0lORk86JylcbiAgICAgICAgICAgICAgICAgIH0gQXNzZXQgJHtcbiAgICAgICAgICAgICAgICAgICAgcGljby5ncmVlbihgJyR7ZmlsZS5uYW1lfSdgKVxuICAgICAgICAgICAgICAgICAgfSBpcyBmcm9tIGEgZm9yZWlnbiBzb3VyY2UsIGZldGNoaW5nIGZyb20gJHtcbiAgICAgICAgICAgICAgICAgICAgcGljby5ncmVlbihgJyR7ZmlsZS51cmx9J2ApXG4gICAgICAgICAgICAgICAgICB9IGFuZCBhZGRpbmcgdG8gc3RvcmFnZSAke1xuICAgICAgICAgICAgICAgICAgICBwaWNvLmdyZWVuKGAnJHtzdG9yYWdlLm5hbWV9J2ApXG4gICAgICAgICAgICAgICAgICB9Li4uYFxuICAgICAgICAgICAgICAgIClcbiAgICAgICAgICAgICAgICBjb25zdCByZXNwb25zZSA9IGF3YWl0IGF4aW9zLnJlcXVlc3Qoe1xuICAgICAgICAgICAgICAgICAgbWV0aG9kOiAnZ2V0JyxcbiAgICAgICAgICAgICAgICAgIHVybDogZmlsZS51cmwsXG4gICAgICAgICAgICAgICAgICByZXNwb25zZVR5cGU6ICdhcnJheWJ1ZmZlcidcbiAgICAgICAgICAgICAgICB9KVxuICAgICAgICAgICAgICAgIGRhdGEgPSByZXNwb25zZS5kYXRhXG4gICAgICAgICAgICAgIH1cbiAgICAgICAgICAgICAgY29uc3QgaW1wb3J0ZWRGaWxlID0gYXdhaXQgc3RvcmFnZS5hZGRGaWxlKGZpbGUsIGRhdGEpXG4gICAgICAgICAgICAgIGF3YWl0IHRoaXMuY3JlYXRlQXNzZXRzKHN0b3JhZ2UsIFtpbXBvcnRlZEZpbGVdLCAwLCB0cngpXG4gICAgICAgICAgICAgIC8vIE1lcmdlIGJhY2sgdGhlIGNoYW5nZWQgZmlsZSBwcm9wZXJ0aWVzIGludG8gdGhlIGFjdHVhbCBmaWxlc1xuICAgICAgICAgICAgICAvLyBvYmplY3QsIHNvIHRoYXQgdGhlIGRhdGEgZnJvbSB0aGUgc3RhdGljIG1vZGVsIGhvb2sgY2FuIGJlIHVzZWRcbiAgICAgICAgICAgICAgLy8gZGlyZWN0bHkgZm9yIHRoZSBhY3R1YWwgcnVubmluZyBxdWVyeS5cbiAgICAgICAgICAgICAgT2JqZWN0LmFzc2lnbihmaWxlLCBpbXBvcnRlZEZpbGUpXG4gICAgICAgICAgICAgIGltcG9ydGVkRmlsZXMucHVzaChpbXBvcnRlZEZpbGUpXG4gICAgICAgICAgICB9IGVsc2Uge1xuICAgICAgICAgICAgICB0aHJvdyBuZXcgQXNzZXRFcnJvcihcbiAgICAgICAgICAgICAgICBgVW5hYmxlIHRvIGltcG9ydCBhc3NldCBmcm9tIGZvcmVpZ24gc291cmNlOiAnJHtcbiAgICAgICAgICAgICAgICAgIGZpbGUubmFtZVxuICAgICAgICAgICAgICAgIH0nICgnJHtcbiAgICAgICAgICAgICAgICAgIGZpbGUua2V5XG4gICAgICAgICAgICAgICAgfScpYFxuICAgICAgICAgICAgICApXG4gICAgICAgICAgICB9XG4gICAgICAgICAgfSBlbHNlIHtcbiAgICAgICAgICAgIC8vIEFzc2V0IGlzIGZyb20gYSBmb3JlaWduIHNvdXJjZSwgYnV0IHdhcyBhbHJlYWR5IGltcG9ydGVkIGFuZCBjYW5cbiAgICAgICAgICAgIC8vIGJlIHJldXNlZC4gU2VlIGFib3ZlIGZvciBhbiBleHBsYW5hdGlvbiBvZiB0aGlzIG1lcmdlLlxuICAgICAgICAgICAgT2JqZWN0LmFzc2lnbihmaWxlLCBhc3NldC5maWxlKVxuICAgICAgICAgICAgLy8gTk9URTogTm8gbmVlZCB0byBhZGQgYGZpbGVgIHRvIGBpbXBvcnRlZEZpbGVzYCwgc2luY2UgaXQnc1xuICAgICAgICAgICAgLy8gYWxyZWFkeSBiZWVuIGltcG9ydGVkIHRvIHRoZSBzdG9yYWdlIGJlZm9yZS5cbiAgICAgICAgICB9XG4gICAgICAgIH0pXG4gICAgICApXG4gICAgfVxuICAgIHJldHVybiBpbXBvcnRlZEZpbGVzXG4gIH1cblxuICBhc3luYyBoYW5kbGVNb2RpZmllZEFzc2V0cyhzdG9yYWdlLCBmaWxlcywgdHJ4ID0gbnVsbCkge1xuICAgIGNvbnN0IG1vZGlmaWVkRmlsZXMgPSBbXVxuICAgIGNvbnN0IEFzc2V0TW9kZWwgPSB0aGlzLmdldE1vZGVsKCdBc3NldCcpXG4gICAgaWYgKEFzc2V0TW9kZWwpIHtcbiAgICAgIGF3YWl0IFByb21pc2UuYWxsKFxuICAgICAgICBmaWxlcy5tYXAoYXN5bmMgZmlsZSA9PiB7XG4gICAgICAgICAgaWYgKGZpbGUuZGF0YSkge1xuICAgICAgICAgICAgY29uc3QgYXNzZXQgPSBhd2FpdCBBc3NldE1vZGVsLnF1ZXJ5KHRyeCkuZmluZE9uZSgna2V5JywgZmlsZS5rZXkpXG4gICAgICAgICAgICBpZiAoYXNzZXQpIHtcbiAgICAgICAgICAgICAgY29uc3QgY2hhbmdlZEZpbGUgPSBhd2FpdCBzdG9yYWdlLmFkZEZpbGUoZmlsZSwgZmlsZS5kYXRhKVxuICAgICAgICAgICAgICAvLyBNZXJnZSBiYWNrIHRoZSBjaGFuZ2VkIGZpbGUgcHJvcGVydGllcyBpbnRvIHRoZSBhY3R1YWwgZmlsZXNcbiAgICAgICAgICAgICAgLy8gb2JqZWN0LCBzbyB0aGF0IHRoZSBkYXRhIGZyb20gdGhlIHN0YXRpYyBtb2RlbCBob29rIGNhbiBiZSB1c2VkXG4gICAgICAgICAgICAgIC8vIGRpcmVjdGx5IGZvciB0aGUgYWN0dWFsIHJ1bm5pbmcgcXVlcnkuXG4gICAgICAgICAgICAgIE9iamVjdC5hc3NpZ24oZmlsZSwgY2hhbmdlZEZpbGUpXG4gICAgICAgICAgICAgIG1vZGlmaWVkRmlsZXMucHVzaChjaGFuZ2VkRmlsZSlcbiAgICAgICAgICAgIH0gZWxzZSB7XG4gICAgICAgICAgICAgIHRocm93IG5ldyBBc3NldEVycm9yKFxuICAgICAgICAgICAgICAgIGBVbmFibGUgdG8gdXBkYXRlIG1vZGlmaWVkIGFzc2V0IGZyb20gbWVtb3J5IHNvdXJjZTogJyR7XG4gICAgICAgICAgICAgICAgICBmaWxlLm5hbWVcbiAgICAgICAgICAgICAgICB9JyAoJyR7XG4gICAgICAgICAgICAgICAgICBmaWxlLmtleVxuICAgICAgICAgICAgICAgIH0nKWBcbiAgICAgICAgICAgICAgKVxuICAgICAgICAgICAgfVxuICAgICAgICAgIH1cbiAgICAgICAgfSlcbiAgICAgIClcbiAgICB9XG4gICAgcmV0dXJuIG1vZGlmaWVkRmlsZXNcbiAgfVxuXG4gIGFzeW5jIHJlbGVhc2VVbnVzZWRBc3NldHModGltZVRocmVzaG9sZCA9IDAsIHRyeCA9IG51bGwpIHtcbiAgICBjb25zdCBBc3NldE1vZGVsID0gdGhpcy5nZXRNb2RlbCgnQXNzZXQnKVxuICAgIGlmIChBc3NldE1vZGVsKSB7XG4gICAgICByZXR1cm4gQXNzZXRNb2RlbC50cmFuc2FjdGlvbih0cngsIGFzeW5jIHRyeCA9PiB7XG4gICAgICAgIC8vIERldGVybWluZSB0aGUgdGltZSB0aHJlc2hvbGQgaW4gSlMgaW5zdGVhZCBvZiBTUUwsIGFzIHRoZXJlIGlzIG5vXG4gICAgICAgIC8vIGVhc3kgY3Jvc3MtU1FMIHdheSB0byBkbyBgbm93KCkgLSBpbnRlcnZhbCBYIGhvdXJzYDpcbiAgICAgICAgY29uc3QgZGF0ZSA9IG5ldyBEYXRlKClcbiAgICAgICAgZGF0ZS5zZXRNaWxsaXNlY29uZHMoZGF0ZS5nZXRNaWxsaXNlY29uZHMoKSAtIHRpbWVUaHJlc2hvbGQpXG4gICAgICAgIGNvbnN0IG9ycGhhbmVkQXNzZXRzID0gYXdhaXQgQXNzZXRNb2RlbFxuICAgICAgICAgIC5xdWVyeSh0cngpXG4gICAgICAgICAgLndoZXJlKCdjb3VudCcsIDApXG4gICAgICAgICAgLmFuZFdoZXJlKCd1cGRhdGVkQXQnLCAnPD0nLCBkYXRlKVxuICAgICAgICAgIC8vIFByb3RlY3QgZnJlc2hseSBjcmVhdGVkIGFzc2V0cyBmcm9tIGJlaW5nIGRlbGV0ZWQgYWdhaW4gcmlnaHQgYXdheSxcbiAgICAgICAgICAvLyAuZS5nLiB3aGVuIGBjb25maWcuYXNzZXRzLmNsZWFudXBUaW1lVGhyZXNob2xkID0gMGBcbiAgICAgICAgICAuYW5kV2hlcmUoJ3VwZGF0ZWRBdCcsICc+JywgcmVmKCdjcmVhdGVkQXQnKSlcbiAgICAgICAgaWYgKG9ycGhhbmVkQXNzZXRzLmxlbmd0aCA+IDApIHtcbiAgICAgICAgICBjb25zdCBvcnBoYW5lZEtleXMgPSBhd2FpdCBQcm9taXNlLmFsbChcbiAgICAgICAgICAgIG9ycGhhbmVkQXNzZXRzLm1hcChhc3luYyBhc3NldCA9PiB7XG4gICAgICAgICAgICAgIHRyeSB7XG4gICAgICAgICAgICAgICAgYXdhaXQgdGhpcy5nZXRTdG9yYWdlKGFzc2V0LnN0b3JhZ2UpLnJlbW92ZUZpbGUoYXNzZXQuZmlsZSlcbiAgICAgICAgICAgICAgfSBjYXRjaCAoZXJyb3IpIHtcbiAgICAgICAgICAgICAgICB0aGlzLmVtaXQoJ2Vycm9yJywgZXJyb3IpXG4gICAgICAgICAgICAgICAgYXNzZXQuZXJyb3IgPSBlcnJvclxuICAgICAgICAgICAgICB9XG4gICAgICAgICAgICAgIHJldHVybiBhc3NldC5rZXlcbiAgICAgICAgICAgIH0pXG4gICAgICAgICAgKVxuICAgICAgICAgIGF3YWl0IEFzc2V0TW9kZWxcbiAgICAgICAgICAgIC5xdWVyeSh0cngpXG4gICAgICAgICAgICAuZGVsZXRlKClcbiAgICAgICAgICAgIC53aGVyZUluKCdrZXknLCBvcnBoYW5lZEtleXMpXG4gICAgICAgIH1cbiAgICAgICAgcmV0dXJuIG9ycGhhbmVkQXNzZXRzXG4gICAgICB9KVxuICAgIH1cbiAgfVxufVxuXG4vLyBPdmVycmlkZSBLb2EncyBldmVudHMgd2l0aCBvdXIgb3duIEV2ZW50RW1pdHRlciB0aGF0IGFkZHMgc3VwcG9ydCBmb3Jcbi8vIGFzeW5jaHJvbm91cyBldmVudHMuXG5FdmVudEVtaXR0ZXIubWl4aW4oQXBwbGljYXRpb24ucHJvdG90eXBlKVxuXG5mdW5jdGlvbiBnZXRPcHRpb25zKG9wdGlvbnMpIHtcbiAgcmV0dXJuIGlzT2JqZWN0KG9wdGlvbnMpID8gb3B0aW9ucyA6IHt9XG59XG4iXX0=
|