keflag commited on
Commit
1e32df1
·
verified ·
1 Parent(s): a5cc955

Update Dockerfile

Browse files
Files changed (1) hide show
  1. Dockerfile +7 -1095
Dockerfile CHANGED
@@ -1,1101 +1,13 @@
1
  FROM n8n/n8n:latest
2
  USER root
3
 
4
- FROM n8nio/n8n:latest
 
5
 
6
- # 1. 覆盖 license-state.js
7
- RUN cat > /usr/local/lib/node_modules/n8n/node_modules/@n8n/backend-common/dist/license-state.js <<'EOF'
8
- "use strict";
9
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
10
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
11
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
12
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
13
- return c > 3 && r && Object.defineProperty(target, key, r), r;
14
- };
15
- Object.defineProperty(exports, "__esModule", { value: true });
16
- exports.LicenseState = void 0;
17
- const constants_1 = require("@n8n/constants");
18
- const di_1 = require("@n8n/di");
19
- const n8n_workflow_1 = require("n8n-workflow");
20
- class ProviderNotSetError extends n8n_workflow_1.UnexpectedError {
21
- constructor() {
22
- super('Cannot query license state because license provider has not been set');
23
- }
24
- }
25
- let LicenseState = class LicenseState {
26
- constructor() {
27
- this.licenseProvider = null;
28
- }
29
- setLicenseProvider(provider) {
30
- this.licenseProvider = provider;
31
- }
32
- assertProvider() {
33
- if (!this.licenseProvider)
34
- throw new ProviderNotSetError();
35
- }
36
- isLicensed(feature) {
37
- return true;
38
- }
39
- getValue(feature) {
40
- this.assertProvider();
41
- return this.licenseProvider.getValue(feature);
42
- }
43
- isCustomRolesLicensed() { return true; }
44
- isDynamicCredentialsLicensed() { return true; }
45
- isPersonalSpacePolicyLicensed() { return true; }
46
- isSharingLicensed() { return true; }
47
- isLogStreamingLicensed() { return true; }
48
- isLdapLicensed() { return true; }
49
- isSamlLicensed() { return true; }
50
- isOidcLicensed() { return true; }
51
- isMFAEnforcementLicensed() { return true; }
52
- isApiKeyScopesLicensed() { return true; }
53
- isAiAssistantLicensed() { return true; }
54
- isAskAiLicensed() { return true; }
55
- isAiCreditsLicensed() { return true; }
56
- isAiGatewayLicensed() { return true; }
57
- isAdvancedExecutionFiltersLicensed() { return true; }
58
- isAdvancedPermissionsLicensed() { return true; }
59
- isDebugInEditorLicensed() { return true; }
60
- isBinaryDataS3Licensed() { return true; }
61
- isMultiMainLicensed() { return true; }
62
- isVariablesLicensed() { return true; }
63
- isSourceControlLicensed() { return true; }
64
- isExternalSecretsLicensed() { return true; }
65
- isAPIDisabled() { return false; }
66
- isWorkerViewLicensed() { return true; }
67
- isProjectRoleAdminLicensed() { return true; }
68
- isProjectRoleEditorLicensed() { return true; }
69
- isProjectRoleViewerLicensed() { return true; }
70
- isCustomNpmRegistryLicensed() { return true; }
71
- isFoldersLicensed() { return true; }
72
- isInsightsSummaryLicensed() { return true; }
73
- isInsightsDashboardLicensed() { return true; }
74
- isInsightsHourlyDataLicensed() { return true; }
75
- isWorkflowDiffsLicensed() { return true; }
76
- isDataRedactionLicensed() { return true; }
77
- isProvisioningLicensed() { return true; }
78
- getMaxUsers() {
79
- return constants_1.UNLIMITED_LICENSE_QUOTA;
80
- }
81
- getMaxActiveWorkflows() {
82
- return constants_1.UNLIMITED_LICENSE_QUOTA;
83
- }
84
- getMaxVariables() {
85
- return constants_1.UNLIMITED_LICENSE_QUOTA;
86
- }
87
- getMaxAiCredits() {
88
- return 99999999;
89
- }
90
- getWorkflowHistoryPruneQuota() {
91
- return constants_1.UNLIMITED_LICENSE_QUOTA;
92
- }
93
- getInsightsMaxHistory() {
94
- return 3650;
95
- }
96
- getInsightsRetentionMaxAge() {
97
- return 3650;
98
- }
99
- getInsightsRetentionPruneInterval() {
100
- return 24;
101
- }
102
- getMaxTeamProjects() {
103
- return -1;
104
- }
105
- getMaxWorkflowsWithEvaluations() {
106
- return -1;
107
- }
108
- };
109
- exports.LicenseState = LicenseState;
110
- exports.LicenseState = LicenseState = __decorate([
111
- (0, di_1.Service)()
112
- ], LicenseState);
113
- //# sourceMappingURL=license-state.js.map
114
- EOF
115
 
116
- # 2. 覆盖 license.js
117
- RUN cat > /usr/local/lib/node_modules/n8n/dist/license.js <<'EOF'
118
- "use strict";
119
- var __createBinding = (this && this.__createBinding) || (function(o, m, k, k2) {
120
- if (k2 === undefined) k2 = k;
121
- var desc = Object.getOwnPropertyDescriptor(m, k);
122
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
123
- desc = { enumerable: true, get: function() { return m[k]; } };
124
- }
125
- Object.defineProperty(o, k2, desc);
126
- }) : (function(o, m, k, k2) {
127
- if (k2 === undefined) k2 = k;
128
- o[k2] = m[k];
129
- });
130
- var __setModuleDefault = (this && this.__setModuleDefault) || (function(o, v) {
131
- Object.defineProperty(o, "default", { enumerable: true, value: v });
132
- }) : function(o, v) {
133
- o["default"] = v;
134
- };
135
- var __decorate = (this && this.__decorate) || function(decorators, target, key, desc) {
136
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
137
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
138
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
139
- return c > 3 && r && Object.defineProperty(target, key, r), r;
140
- };
141
- var __importStar = (this && this.__importStar) || function() {
142
- var ownKeys = function(o) {
143
- ownKeys = Object.getOwnPropertyNames || function(o) {
144
- var ar = [];
145
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
146
- return ar;
147
- };
148
- return ownKeys(o);
149
- };
150
- return function(mod) {
151
- if (mod && mod.__esModule) return mod;
152
- var result = {};
153
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
154
- __setModuleDefault(result, mod);
155
- return result;
156
- };
157
- });
158
- var __metadata = (this && this.__metadata) || function(k, v) {
159
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
160
- };
161
- Object.defineProperty(exports, "__esModule", { value: true });
162
- exports.License = void 0;
163
- const backend_common_1 = require("@n8n/backend-common");
164
- const config_1 = require("@n8n/config");
165
- const constants_1 = require("@n8n/constants");
166
- const db_1 = require("@n8n/db");
167
- const decorators_1 = require("@n8n/decorators");
168
- const di_1 = require("@n8n/di");
169
- const license_sdk_1 = require("@n8n_io/license-sdk");
170
- const n8n_core_1 = require("n8n-core");
171
- const license_metrics_service_1 = require("./metrics/license-metrics.service");
172
- const constants_2 = require("./constants");
173
- const LICENSE_RENEWAL_DISABLED_WARNING = 'Automatic license renewal is disabled. The license will not renew automatically, and access to licensed features may be lost!';
174
- let License = class License {
175
- constructor(logger, instanceSettings, settingsRepository, licenseMetricsService, globalConfig) {
176
- this.logger = logger;
177
- this.instanceSettings = instanceSettings;
178
- this.settingsRepository = settingsRepository;
179
- this.licenseMetricsService = licenseMetricsService;
180
- this.globalConfig = globalConfig;
181
- this.isShuttingDown = false;
182
- this.refreshCallbacks = [];
183
- this.logger = this.logger.scoped('license');
184
- }
185
- async init({ forceRecreate = false, isCli = false, } = {}) {
186
- if (this.manager && !forceRecreate) {
187
- this.logger.warn('License manager already initialized or shutting down');
188
- return;
189
- }
190
- if (this.isShuttingDown) {
191
- this.logger.warn('License manager already shutting down');
192
- return;
193
- }
194
- const { instanceType } = this.instanceSettings;
195
- const isMainInstance = instanceType === 'main';
196
- const server = this.globalConfig.license.serverUrl;
197
- const offlineMode = !isMainInstance;
198
- const autoRenewOffset = 72 * constants_1.Time.hours.toSeconds;
199
- const saveCertStr = isMainInstance
200
- ? async (value) => await this.saveCertStr(value)
201
- : async () => { };
202
- const onFeatureChange = isMainInstance
203
- ? async () => await this.onFeatureChange()
204
- : async () => { };
205
- const onLicenseRenewed = isMainInstance
206
- ? async () => await this.onLicenseRenewed()
207
- : async () => { };
208
- const collectUsageMetrics = isMainInstance
209
- ? async () => await this.licenseMetricsService.collectUsageMetrics()
210
- : async () => [];
211
- const collectPassthroughData = isMainInstance
212
- ? async () => await this.licenseMetricsService.collectPassthroughData()
213
- : async () => ({});
214
- const onExpirySoon = !this.instanceSettings.isLeader ? () => this.onExpirySoon() : undefined;
215
- const expirySoonOffsetMins = !this.instanceSettings.isLeader ? 120 : undefined;
216
- const { isLeader } = this.instanceSettings;
217
- const { autoRenewalEnabled } = this.globalConfig.license;
218
- const eligibleToRenew = isCli || isLeader;
219
- const shouldRenew = eligibleToRenew && autoRenewalEnabled;
220
- if (eligibleToRenew && !autoRenewalEnabled) {
221
- this.logger.warn(LICENSE_RENEWAL_DISABLED_WARNING);
222
- }
223
- try {
224
- this.manager = new license_sdk_1.LicenseManager({
225
- server,
226
- tenantId: this.globalConfig.license.tenantId,
227
- productIdentifier: `n8n-${constants_2.N8N_VERSION}`,
228
- autoRenewEnabled: shouldRenew,
229
- renewOnInit: shouldRenew,
230
- autoRenewOffset,
231
- detachFloatingOnShutdown: this.globalConfig.license.detachFloatingOnShutdown,
232
- offlineMode,
233
- logger: this.logger,
234
- loadCertStr: async () => await this.loadCertStr(),
235
- saveCertStr,
236
- deviceFingerprint: () => this.instanceSettings.instanceId,
237
- collectUsageMetrics,
238
- collectPassthroughData,
239
- onFeatureChange,
240
- onLicenseRenewed,
241
- onExpirySoon,
242
- expirySoonOffsetMins,
243
- });
244
- await this.manager.initialize();
245
- this.logger.debug('License initialized');
246
- }
247
- catch (error) {
248
- if (error instanceof Error) {
249
- this.logger.error('Could not initialize license manager sdk', { error });
250
- }
251
- }
252
- }
253
- async loadCertStr() {
254
- const ephemeralLicense = this.globalConfig.license.cert;
255
- if (ephemeralLicense) {
256
- return ephemeralLicense;
257
- }
258
- const databaseSettings = await this.settingsRepository.findOne({
259
- where: {
260
- key: constants_2.SETTINGS_LICENSE_CERT_KEY,
261
- },
262
- });
263
- return databaseSettings?.value ?? '';
264
- }
265
- async onFeatureChange() {
266
- void this.broadcastReloadLicenseCommand();
267
- await this.notifyRefreshCallbacks();
268
- }
269
- async onLicenseRenewed() {
270
- void this.broadcastReloadLicenseCommand();
271
- await this.notifyRefreshCallbacks();
272
- }
273
- async broadcastReloadLicenseCommand() {
274
- if (this.globalConfig.executions.mode === 'queue' && this.instanceSettings.isLeader) {
275
- const { Publisher } = await Promise.resolve().then(() => __importStar(require('./scaling/pubsub/publisher.service')));
276
- await di_1.Container.get(Publisher).publishCommand({ command: 'reload-license' });
277
- }
278
- }
279
- async saveCertStr(value) {
280
- if (this.globalConfig.license.cert)
281
- return;
282
- await this.settingsRepository.upsert({
283
- key: constants_2.SETTINGS_LICENSE_CERT_KEY,
284
- value,
285
- loadOnStartup: false,
286
- }, ['key']);
287
- }
288
- onCertRefresh(refreshCallback) {
289
- this.refreshCallbacks.push(refreshCallback);
290
- return () => {
291
- const index = this.refreshCallbacks.indexOf(refreshCallback);
292
- if (index > -1) {
293
- this.refreshCallbacks.splice(index, 1);
294
- }
295
- };
296
- }
297
- async notifyRefreshCallbacks() {
298
- const cert = await this.loadCertStr();
299
- for (const refreshCallback of this.refreshCallbacks) {
300
- try {
301
- refreshCallback(cert);
302
- }
303
- catch (error) {
304
- this.logger.error('Error in license refresh callback', { error });
305
- }
306
- }
307
- }
308
- async activate(activationKey, eulaUri, userEmail) {
309
- if (!this.manager) {
310
- return;
311
- }
312
- await this.manager.activate(activationKey, { eulaUri, email: userEmail });
313
- this.logger.debug('License activated');
314
- }
315
- async reload() {
316
- if (!this.manager) {
317
- return;
318
- }
319
- await this.manager.reload();
320
- await this.notifyRefreshCallbacks();
321
- this.logger.debug('License reloaded');
322
- }
323
- async renew() {
324
- if (!this.manager) {
325
- return;
326
- }
327
- await this.manager.renew();
328
- this.logger.debug('License renewed');
329
- }
330
- async clear() {
331
- if (!this.manager) {
332
- return;
333
- }
334
- await this.manager.clear();
335
- this.logger.info('License cleared');
336
- }
337
- async shutdown() {
338
- this.isShuttingDown = true;
339
- if (!this.manager) {
340
- return;
341
- }
342
- await this.manager.shutdown();
343
- this.logger.debug('License shut down');
344
- }
345
- isLicensed(feature) {
346
- return true;
347
- }
348
- isDynamicCredentialsEnabled() {
349
- return true;
350
- }
351
- isSharingEnabled() {
352
- return true;
353
- }
354
- isLogStreamingEnabled() {
355
- return true;
356
- }
357
- isLdapEnabled() {
358
- return true;
359
- }
360
- isSamlEnabled() {
361
- return true;
362
- }
363
- isAiAssistantEnabled() {
364
- return true;
365
- }
366
- isAskAiEnabled() {
367
- return true;
368
- }
369
- isAiCreditsEnabled() {
370
- return true;
371
- }
372
- isAdvancedExecutionFiltersEnabled() {
373
- return true;
374
- }
375
- isAdvancedPermissionsLicensed() {
376
- return true;
377
- }
378
- isDebugInEditorLicensed() {
379
- return true;
380
- }
381
- isBinaryDataS3Licensed() {
382
- return true;
383
- }
384
- isMultiMainLicensed() {
385
- return true;
386
- }
387
- isVariablesEnabled() {
388
- return true;
389
- }
390
- isSourceControlLicensed() {
391
- return true;
392
- }
393
- isExternalSecretsEnabled() {
394
- return true;
395
- }
396
- isAPIDisabled() {
397
- return false;
398
- }
399
- isWorkerViewLicensed() {
400
- return true;
401
- }
402
- isProjectRoleAdminLicensed() {
403
- return true;
404
- }
405
- isProjectRoleEditorLicensed() {
406
- return true;
407
- }
408
- isProjectRoleViewerLicensed() {
409
- return true;
410
- }
411
- isCustomNpmRegistryEnabled() {
412
- return true;
413
- }
414
- isFoldersEnabled() {
415
- return true;
416
- }
417
- getCurrentEntitlements() {
418
- return [];
419
- }
420
- getValue(feature) {
421
- if (feature === 'planName') return 'Enterprise';
422
- return constants_1.UNLIMITED_LICENSE_QUOTA;
423
- }
424
- getManagementJwt() {
425
- return '';
426
- }
427
- getMainPlan() {
428
- return undefined;
429
- }
430
- getConsumerId() {
431
- return 'Enterprise';
432
- }
433
- getUsersLimit() {
434
- return constants_1.UNLIMITED_LICENSE_QUOTA;
435
- }
436
- getTriggerLimit() {
437
- return constants_1.UNLIMITED_LICENSE_QUOTA;
438
- }
439
- getVariablesLimit() {
440
- return constants_1.UNLIMITED_LICENSE_QUOTA;
441
- }
442
- getAiCredits() {
443
- return constants_1.UNLIMITED_LICENSE_QUOTA;
444
- }
445
- getWorkflowHistoryPruneLimit() {
446
- return constants_1.DEFAULT_WORKFLOW_HISTORY_PRUNE_LIMIT;
447
- }
448
- getTeamProjectLimit() {
449
- return constants_1.UNLIMITED_LICENSE_QUOTA;
450
- }
451
- getPlanName() {
452
- return 'Enterprise';
453
- }
454
- getExpiryDate() {
455
- return new Date('9999-12-31');
456
- }
457
- getTerminationDate() {
458
- return new Date('9999-12-31');
459
- }
460
- getExpiringInDays() {
461
- return 36500;
462
- }
463
- getTerminatingInDays() {
464
- return 36500;
465
- }
466
- getInfo() {
467
- return 'Enterprise License (Unlimited) - Cracked by: keflag.';
468
- }
469
- isWithinUsersLimit() {
470
- return true;
471
- }
472
- enableAutoRenewals() {
473
- }
474
- disableAutoRenewals() {
475
- }
476
- onExpirySoon() {
477
- }
478
- };
479
- exports.License = License;
480
- __decorate([
481
- (0, decorators_1.OnPubSubEvent)('reload-license'),
482
- __metadata("design:type", Function),
483
- __metadata("design:paramtypes", []),
484
- __metadata("design:returntype", Promise)
485
- ], License.prototype, "reload", null);
486
- __decorate([
487
- (0, decorators_1.OnShutdown)(),
488
- __metadata("design:type", Function),
489
- __metadata("design:paramtypes", []),
490
- __metadata("design:returntype", Promise)
491
- ], License.prototype, "shutdown", null);
492
- __decorate([
493
- (0, decorators_1.OnLeaderTakeover)(),
494
- __metadata("design:type", Function),
495
- __metadata("design:paramtypes", []),
496
- __metadata("design:returntype", void 0)
497
- ], License.prototype, "enableAutoRenewals", null);
498
- __decorate([
499
- (0, decorators_1.OnLeaderStepdown)(),
500
- __metadata("design:type", Function),
501
- __metadata("design:paramtypes", []),
502
- __metadata("design:returntype", void 0)
503
- ], License.prototype, "disableAutoRenewals", null);
504
- exports.License = License = __decorate([
505
- (0, di_1.Service)(),
506
- __metadata("design:paramtypes", [backend_common_1.Logger,
507
- n8n_core_1.InstanceSettings,
508
- db_1.SettingsRepository,
509
- license_metrics_service_1.LicenseMetricsService,
510
- config_1.GlobalConfig])
511
- ], License);
512
- //# sourceMappingURL=license.js.map
513
- EOF
514
 
515
- # 3. 覆盖 frontend.service.js
516
- RUN cat > /usr/local/lib/node_modules/n8n/dist/services/frontend.service.js << 'EOF'
517
- "use strict";
518
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
519
- if (k2 === undefined) k2 = k;
520
- var desc = Object.getOwnPropertyDescriptor(m, k);
521
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
522
- desc = { enumerable: true, get: function() { return m[k]; } };
523
- }
524
- Object.defineProperty(o, k2, desc);
525
- }) : (function(o, m, k, k2) {
526
- if (k2 === undefined) k2 = k;
527
- o[k2] = m[k];
528
- }));
529
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
530
- Object.defineProperty(o, "default", { enumerable: true, value: v });
531
- }) : function(o, v) {
532
- o["default"] = v;
533
- });
534
- var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
535
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
536
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
537
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
538
- return c > 3 && r && Object.defineProperty(target, key, r), r;
539
- };
540
- var __importStar = (this && this.__importStar) || (function () {
541
- var ownKeys = function(o) {
542
- ownKeys = Object.getOwnPropertyNames || function (o) {
543
- var ar = [];
544
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
545
- return ar;
546
- };
547
- return ownKeys(o);
548
- };
549
- return function (mod) {
550
- if (mod && mod.__esModule) return mod;
551
- var result = {};
552
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
553
- __setModuleDefault(result, mod);
554
- return result;
555
- };
556
- })();
557
- var __metadata = (this && this.__metadata) || function (k, v) {
558
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
559
- };
560
- var __importDefault = (this && this.__importDefault) || function (mod) {
561
- return (mod && mod.__esModule) ? mod : { "default": mod };
562
- };
563
- Object.defineProperty(exports, "__esModule", { value: true });
564
- exports.FrontendService = void 0;
565
- const backend_common_1 = require("@n8n/backend-common");
566
- const config_1 = require("@n8n/config");
567
- const constants_1 = require("@n8n/constants");
568
- const di_1 = require("@n8n/di");
569
- const fs_1 = require("fs");
570
- const promises_1 = require("fs/promises");
571
- const uniq_1 = __importDefault(require("lodash/uniq"));
572
- const n8n_core_1 = require("n8n-core");
573
- const path_1 = __importDefault(require("path"));
574
- const config_2 = __importDefault(require("../config"));
575
- const constants_2 = require("../constants");
576
- const credential_types_1 = require("../credential-types");
577
- const credentials_overwrites_1 = require("../credentials-overwrites");
578
- const license_1 = require("../license");
579
- const load_nodes_and_credentials_1 = require("../load-nodes-and-credentials");
580
- const mfa_service_1 = require("../mfa/mfa.service");
581
- const community_packages_config_1 = require("../modules/community-packages/community-packages.config");
582
- const public_api_1 = require("../public-api");
583
- const push_config_1 = require("../push/push.config");
584
- const ownership_service_1 = require("../services/ownership.service");
585
- const sso_helpers_1 = require("../sso.ee/sso-helpers");
586
- const email_1 = require("../user-management/email");
587
- const health_endpoint_util_1 = require("../utils/health-endpoint.util");
588
- const workflow_history_helper_1 = require("../workflows/workflow-history/workflow-history-helper");
589
- const ai_usage_service_1 = require("./ai-usage.service");
590
- const url_service_1 = require("./url.service");
591
- let FrontendService = class FrontendService {
592
- constructor(globalConfig, logger, loadNodesAndCredentials, credentialTypes, credentialsOverwrites, license, mailer, instanceSettings, urlService, securityConfig, pushConfig, binaryDataConfig, licenseState, moduleRegistry, mfaService, ownershipService, aiUsageService) {
593
- this.globalConfig = globalConfig;
594
- this.logger = logger;
595
- this.loadNodesAndCredentials = loadNodesAndCredentials;
596
- this.credentialTypes = credentialTypes;
597
- this.credentialsOverwrites = credentialsOverwrites;
598
- this.license = license;
599
- this.mailer = mailer;
600
- this.instanceSettings = instanceSettings;
601
- this.urlService = urlService;
602
- this.securityConfig = securityConfig;
603
- this.pushConfig = pushConfig;
604
- this.binaryDataConfig = binaryDataConfig;
605
- this.licenseState = licenseState;
606
- this.moduleRegistry = moduleRegistry;
607
- this.mfaService = mfaService;
608
- this.ownershipService = ownershipService;
609
- this.aiUsageService = aiUsageService;
610
- loadNodesAndCredentials.addPostProcessor(async () => await this.generateTypes());
611
- void this.generateTypes();
612
- if (di_1.Container.get(community_packages_config_1.CommunityPackagesConfig).enabled) {
613
- void Promise.resolve().then(() => __importStar(require('../modules/community-packages/community-packages.service'))).then(({ CommunityPackagesService }) => {
614
- this.communityPackagesService = di_1.Container.get(CommunityPackagesService);
615
- });
616
- }
617
- }
618
- collectEnvFeatureFlags() {
619
- const envFeatureFlags = {};
620
- for (const [key, value] of Object.entries(process.env)) {
621
- if (key.startsWith('N8N_ENV_FEAT_') && value !== undefined) {
622
- envFeatureFlags[key] = value;
623
- }
624
- }
625
- return envFeatureFlags;
626
- }
627
- async getShowSetupOnFirstLoad() {
628
- const previewMode = process.env.N8N_PREVIEW_MODE === 'true';
629
- const hasInstanceOwner = await this.ownershipService.hasInstanceOwner();
630
- return previewMode ? false : !hasInstanceOwner;
631
- }
632
- async initSettings() {
633
- const instanceBaseUrl = this.urlService.getInstanceBaseUrl();
634
- const restEndpoint = this.globalConfig.endpoints.rest;
635
- const telemetrySettings = {
636
- enabled: this.globalConfig.diagnostics.enabled,
637
- };
638
- if (telemetrySettings.enabled) {
639
- const conf = this.globalConfig.diagnostics.frontendConfig;
640
- const [key, url] = conf.split(';');
641
- const proxy = `${instanceBaseUrl}/${restEndpoint}/telemetry/proxy`;
642
- const sourceConfig = `${instanceBaseUrl}/${restEndpoint}/telemetry/rudderstack`;
643
- if (!key || !url) {
644
- this.logger.warn('Diagnostics frontend config is invalid');
645
- telemetrySettings.enabled = false;
646
- }
647
- telemetrySettings.config = { key, url, proxy, sourceConfig };
648
- }
649
- const previewMode = process.env.N8N_PREVIEW_MODE === 'true';
650
- this.settings = {
651
- settingsMode: 'authenticated',
652
- inE2ETests: constants_2.inE2ETests,
653
- isDocker: this.instanceSettings.isDocker,
654
- databaseType: this.globalConfig.database.type,
655
- previewMode,
656
- endpointForm: this.globalConfig.endpoints.form,
657
- endpointFormTest: this.globalConfig.endpoints.formTest,
658
- endpointFormWaiting: this.globalConfig.endpoints.formWaiting,
659
- endpointMcp: this.globalConfig.endpoints.mcp,
660
- endpointMcpTest: this.globalConfig.endpoints.mcpTest,
661
- endpointWebhook: this.globalConfig.endpoints.webhook,
662
- endpointWebhookTest: this.globalConfig.endpoints.webhookTest,
663
- endpointWebhookWaiting: this.globalConfig.endpoints.webhookWaiting,
664
- endpointHealth: (0, health_endpoint_util_1.resolveFrontendHealthEndpointPath)(this.globalConfig),
665
- saveDataErrorExecution: this.globalConfig.executions.saveDataOnError,
666
- saveDataSuccessExecution: this.globalConfig.executions.saveDataOnSuccess,
667
- saveManualExecutions: this.globalConfig.executions.saveDataManualExecutions,
668
- saveExecutionProgress: this.globalConfig.executions.saveExecutionProgress,
669
- executionTimeout: this.globalConfig.executions.timeout,
670
- maxExecutionTimeout: this.globalConfig.executions.maxTimeout,
671
- workflowCallerPolicyDefaultOption: this.globalConfig.workflows.callerPolicyDefaultOption,
672
- timezone: this.globalConfig.generic.timezone,
673
- urlBaseWebhook: this.urlService.getWebhookBaseUrl(),
674
- urlBaseEditor: instanceBaseUrl,
675
- binaryDataMode: this.binaryDataConfig.mode,
676
- nodeJsVersion: process.version.replace(/^v/, ''),
677
- nodeEnv: process.env.NODE_ENV,
678
- versionCli: constants_2.N8N_VERSION,
679
- concurrency: this.globalConfig.executions.concurrency.productionLimit,
680
- authCookie: {
681
- secure: this.globalConfig.auth.cookie.secure,
682
- },
683
- releaseChannel: this.globalConfig.generic.releaseChannel,
684
- oauthCallbackUrls: {
685
- oauth1: `${instanceBaseUrl}/${restEndpoint}/oauth1-credential/callback`,
686
- oauth2: `${instanceBaseUrl}/${restEndpoint}/oauth2-credential/callback`,
687
- },
688
- versionNotifications: {
689
- enabled: this.globalConfig.versionNotifications.enabled,
690
- endpoint: this.globalConfig.versionNotifications.endpoint,
691
- whatsNewEnabled: this.globalConfig.versionNotifications.whatsNewEnabled,
692
- whatsNewEndpoint: this.globalConfig.versionNotifications.whatsNewEndpoint,
693
- infoUrl: this.globalConfig.versionNotifications.infoUrl,
694
- },
695
- dynamicBanners: {
696
- endpoint: this.globalConfig.dynamicBanners.endpoint,
697
- enabled: this.globalConfig.dynamicBanners.enabled && this.globalConfig.diagnostics.enabled,
698
- },
699
- instanceId: this.instanceSettings.instanceId,
700
- telemetry: telemetrySettings,
701
- posthog: {
702
- enabled: this.globalConfig.diagnostics.enabled,
703
- apiHost: this.globalConfig.diagnostics.posthogConfig.apiHost,
704
- apiKey: this.globalConfig.diagnostics.posthogConfig.apiKey,
705
- autocapture: false,
706
- disableSessionRecording: this.globalConfig.deployment.type !== 'cloud',
707
- proxy: `${instanceBaseUrl}/${restEndpoint}/ph`,
708
- debug: this.globalConfig.logging.level === 'debug',
709
- },
710
- personalizationSurveyEnabled: this.globalConfig.personalization.enabled && this.globalConfig.diagnostics.enabled,
711
- defaultLocale: this.globalConfig.defaultLocale,
712
- userManagement: {
713
- quota: this.license.getUsersLimit(),
714
- showSetupOnFirstLoad: await this.getShowSetupOnFirstLoad(),
715
- smtpSetup: this.mailer.isEmailSetUp,
716
- authenticationMethod: (0, sso_helpers_1.getCurrentAuthenticationMethod)(),
717
- },
718
- sso: {
719
- managedByEnv: this.globalConfig.instanceSettingsLoader.ssoManagedByEnv,
720
- saml: {
721
- loginEnabled: false,
722
- loginLabel: '',
723
- },
724
- ldap: {
725
- loginEnabled: false,
726
- loginLabel: '',
727
- },
728
- oidc: {
729
- loginEnabled: false,
730
- loginUrl: `${instanceBaseUrl}/${restEndpoint}/sso/oidc/login`,
731
- callbackUrl: `${instanceBaseUrl}/${restEndpoint}/sso/oidc/callback`,
732
- },
733
- },
734
- dataTables: {
735
- maxSize: this.globalConfig.dataTable.maxSize,
736
- },
737
- publicApi: {
738
- enabled: (0, public_api_1.isApiEnabled)(),
739
- latestVersion: 1,
740
- path: this.globalConfig.publicApi.path,
741
- swaggerUi: {
742
- enabled: !this.globalConfig.publicApi.swaggerUiDisabled,
743
- },
744
- },
745
- workflowTagsDisabled: this.globalConfig.tags.disabled,
746
- logLevel: this.globalConfig.logging.level,
747
- hiringBannerEnabled: this.globalConfig.hiringBanner.enabled,
748
- aiAssistant: {
749
- enabled: false,
750
- setup: false,
751
- },
752
- templates: {
753
- enabled: this.globalConfig.templates.enabled,
754
- host: this.globalConfig.templates.host,
755
- },
756
- executionMode: this.globalConfig.executions.mode,
757
- isMultiMain: this.instanceSettings.isMultiMain,
758
- pushBackend: this.pushConfig.backend,
759
- communityNodesEnabled: di_1.Container.get(community_packages_config_1.CommunityPackagesConfig).enabled,
760
- unverifiedCommunityNodesEnabled: di_1.Container.get(community_packages_config_1.CommunityPackagesConfig).unverifiedEnabled,
761
- deployment: {
762
- type: this.globalConfig.deployment.type,
763
- },
764
- allowedModules: {
765
- builtIn: process.env.NODE_FUNCTION_ALLOW_BUILTIN?.split(',') ?? undefined,
766
- external: process.env.NODE_FUNCTION_ALLOW_EXTERNAL?.split(',') ?? undefined,
767
- },
768
- enterprise: {
769
- sharing: false,
770
- ldap: false,
771
- saml: false,
772
- oidc: false,
773
- mfaEnforcement: false,
774
- logStreaming: false,
775
- advancedExecutionFilters: false,
776
- variables: false,
777
- sourceControl: false,
778
- auditLogs: false,
779
- externalSecrets: false,
780
- showNonProdBanner: false,
781
- debugInEditor: false,
782
- binaryDataS3: false,
783
- workerView: false,
784
- advancedPermissions: false,
785
- workflowDiffs: false,
786
- namedVersions: false,
787
- provisioning: false,
788
- projects: {
789
- team: {
790
- limit: 0,
791
- },
792
- },
793
- customRoles: false,
794
- personalSpacePolicy: false,
795
- dataRedaction: false,
796
- },
797
- mfa: {
798
- enabled: false,
799
- enforced: false,
800
- },
801
- hideUsagePage: this.globalConfig.hideUsagePage,
802
- license: {
803
- consumerId: 'unknown',
804
- environment: this.globalConfig.license.tenantId === 1 ? 'production' : 'staging',
805
- },
806
- variables: {
807
- limit: 0,
808
- },
809
- banners: {
810
- dismissed: [],
811
- },
812
- askAi: {
813
- enabled: false,
814
- },
815
- aiBuilder: {
816
- enabled: false,
817
- setup: false,
818
- },
819
- aiCredits: {
820
- enabled: false,
821
- credits: 0,
822
- setup: false,
823
- },
824
- ai: {
825
- allowSendingParameterValues: true,
826
- },
827
- workflowHistory: {
828
- pruneTime: (0, workflow_history_helper_1.getWorkflowHistoryPruneTime)(),
829
- licensePruneTime: (0, workflow_history_helper_1.getWorkflowHistoryLicensePruneTime)(),
830
- },
831
- pruning: {
832
- isEnabled: this.globalConfig.executions.pruneData,
833
- maxAge: this.globalConfig.executions.pruneDataMaxAge,
834
- maxCount: this.globalConfig.executions.pruneDataMaxCount,
835
- },
836
- security: {
837
- blockFileAccessToN8nFiles: this.securityConfig.blockFileAccessToN8nFiles,
838
- },
839
- easyAIWorkflowOnboarded: false,
840
- folders: {
841
- enabled: false,
842
- },
843
- evaluation: {
844
- quota: this.licenseState.getMaxWorkflowsWithEvaluations()
845
- },
846
- activeModules: this.moduleRegistry.getActiveModules(),
847
- canvasOnly: this.globalConfig.canvasOnly,
848
- envFeatureFlags: this.collectEnvFeatureFlags(),
849
- };
850
- }
851
- async generateTypes() {
852
- this.overwriteCredentialsProperties();
853
- const { credentials, nodes } = await this.loadNodesAndCredentials.collectTypes();
854
- const { staticCacheDir } = this.instanceSettings;
855
- await (0, promises_1.mkdir)(path_1.default.join(staticCacheDir, 'types'), { recursive: true });
856
- await this.writeStaticJSON('nodes', nodes);
857
- const nodeVersionIdentifiers = this.getNodeVersionIdentifiers(nodes);
858
- await this.writeStaticJSON('node-versions', nodeVersionIdentifiers);
859
- await this.writeStaticJSON('credentials', credentials);
860
- }
861
- async getSettings() {
862
- if (!this.settings) {
863
- await this.initSettings();
864
- }
865
- const restEndpoint = this.globalConfig.endpoints.rest;
866
- const instanceBaseUrl = this.urlService.getInstanceBaseUrl();
867
- this.settings.urlBaseWebhook = this.urlService.getWebhookBaseUrl();
868
- this.settings.urlBaseEditor = instanceBaseUrl;
869
- this.settings.oauthCallbackUrls = {
870
- oauth1: `${instanceBaseUrl}/${restEndpoint}/oauth1-credential/callback`,
871
- oauth2: `${instanceBaseUrl}/${restEndpoint}/oauth2-credential/callback`,
872
- };
873
- Object.assign(this.settings.userManagement, {
874
- quota: this.license.getUsersLimit(),
875
- authenticationMethod: (0, sso_helpers_1.getCurrentAuthenticationMethod)(),
876
- showSetupOnFirstLoad: await this.getShowSetupOnFirstLoad(),
877
- });
878
- let dismissedBanners = [];
879
- try {
880
- dismissedBanners = config_2.default.getEnv('ui.banners.dismissed') ?? [];
881
- }
882
- catch {
883
- }
884
- this.settings.banners.dismissed = dismissedBanners;
885
- try {
886
- this.settings.easyAIWorkflowOnboarded = config_2.default.getEnv('easyAIWorkflowOnboarded') ?? false;
887
- }
888
- catch {
889
- this.settings.easyAIWorkflowOnboarded = false;
890
- }
891
- try {
892
- this.settings.ai.allowSendingParameterValues = await this.aiUsageService.getAiUsageSettings();
893
- }
894
- catch {
895
- this.settings.ai.allowSendingParameterValues = true;
896
- }
897
-
898
- const isS3Selected = this.binaryDataConfig.mode === 's3';
899
- const isS3Available = this.binaryDataConfig.availableModes.includes('s3');
900
- const isS3Licensed = true;
901
- const isAiAssistantEnabled = true;
902
- const isAskAiEnabled = true;
903
- const isAiCreditsEnabled = true;
904
- const isAiBuilderEnabled = true;
905
-
906
- this.settings.license.planName = "Enterprise";
907
- this.settings.license.consumerId = "Enterprise";
908
-
909
- Object.assign(this.settings.enterprise, {
910
- sharing: true,
911
- logStreaming: true,
912
- ldap: true,
913
- saml: true,
914
- oidc: true,
915
- mfaEnforcement: true,
916
- provisioning: false,
917
- advancedExecutionFilters: true,
918
- variables: true,
919
- sourceControl: true,
920
- externalSecrets: true,
921
- showNonProdBanner: false,
922
- debugInEditor: true,
923
- binaryDataS3: isS3Available && isS3Selected && isS3Licensed,
924
- workerView: true,
925
- advancedPermissions: true,
926
- workflowDiffs: true,
927
- namedVersions: true,
928
- customRoles: true,
929
- personalSpacePolicy: true,
930
- dataRedaction: true,
931
- });
932
-
933
- if (true) {
934
- Object.assign(this.settings.sso.ldap, {
935
- loginLabel: this.globalConfig.sso.ldap.loginLabel,
936
- loginEnabled: this.globalConfig.sso.ldap.loginEnabled,
937
- });
938
- }
939
- if (true) {
940
- Object.assign(this.settings.sso.saml, {
941
- loginLabel: (0, sso_helpers_1.getSamlLoginLabel)(),
942
- loginEnabled: this.globalConfig.sso.saml.loginEnabled,
943
- });
944
- }
945
- if (true) {
946
- Object.assign(this.settings.sso.oidc, {
947
- loginEnabled: this.globalConfig.sso.oidc.loginEnabled,
948
- });
949
- }
950
- if (true) {
951
- this.settings.variables.limit = constants_1.UNLIMITED_LICENSE_QUOTA;
952
- }
953
- if (this.communityPackagesService) {
954
- this.settings.missingPackages = this.communityPackagesService.hasMissingPackages;
955
- }
956
- if (isAiAssistantEnabled) {
957
- this.settings.aiAssistant.enabled = true;
958
- this.settings.aiAssistant.setup = true;
959
- }
960
- if (isAskAiEnabled) {
961
- this.settings.askAi.enabled = true;
962
- }
963
- if (isAiCreditsEnabled) {
964
- this.settings.aiCredits.enabled = true;
965
- this.settings.aiCredits.credits = constants_1.UNLIMITED_LICENSE_QUOTA;
966
- this.settings.aiCredits.setup = true;
967
- }
968
- if (isAiBuilderEnabled) {
969
- this.settings.aiBuilder.enabled = true;
970
- this.settings.aiBuilder.setup = true;
971
- }
972
-
973
- this.settings.mfa.enabled = this.globalConfig.mfa.enabled;
974
- this.settings.mfa.enforced = true;
975
- this.settings.executionMode = this.globalConfig.executions.mode;
976
- this.settings.binaryDataMode = this.binaryDataConfig.mode;
977
- this.settings.enterprise.projects.team.limit = constants_1.UNLIMITED_LICENSE_QUOTA;
978
- this.settings.folders.enabled = true;
979
- this.settings.evaluation.quota = 99999;
980
- this.settings.envFeatureFlags = this.collectEnvFeatureFlags();
981
- return this.settings;
982
- }
983
- async getPublicSettings(includeMfaSettings) {
984
- const { defaultLocale, userManagement: { authenticationMethod, showSetupOnFirstLoad, smtpSetup }, sso: { saml: ssoSaml, ldap: ssoLdap, oidc: ssoOidc }, authCookie, previewMode, enterprise: { saml, ldap, oidc }, mfa, communityNodesEnabled, } = await this.getSettings();
985
- const publicSettings = {
986
- settingsMode: 'public',
987
- defaultLocale,
988
- userManagement: {
989
- authenticationMethod,
990
- showSetupOnFirstLoad,
991
- smtpSetup,
992
- },
993
- sso: {
994
- saml: {
995
- loginEnabled: ssoSaml.loginEnabled,
996
- },
997
- ldap: ssoLdap,
998
- oidc: {
999
- loginEnabled: ssoOidc.loginEnabled,
1000
- loginUrl: ssoOidc.loginUrl,
1001
- },
1002
- },
1003
- authCookie,
1004
- previewMode,
1005
- enterprise: { saml: true, ldap: true, oidc: true },
1006
- communityNodesEnabled,
1007
- };
1008
- if (includeMfaSettings) {
1009
- publicSettings.mfa = mfa;
1010
- }
1011
- return publicSettings;
1012
- }
1013
- getModuleSettings() {
1014
- return Object.fromEntries(this.moduleRegistry.settings);
1015
- }
1016
- getNodeVersionIdentifiers(nodes) {
1017
- const identifiers = new Set();
1018
- for (const node of nodes) {
1019
- if (!node?.name || node.version === undefined)
1020
- continue;
1021
- const versions = Array.isArray(node.version) ? node.version : [node.version];
1022
- for (const version of versions) {
1023
- if (version === undefined)
1024
- continue;
1025
- identifiers.add(`${node.name}@${String(version)}`);
1026
- }
1027
- }
1028
- return Array.from(identifiers);
1029
- }
1030
- async writeStaticJSON(name, data) {
1031
- const { staticCacheDir } = this.instanceSettings;
1032
- const filePath = path_1.default.join(staticCacheDir, `types/${name}.json`);
1033
- const stream = (0, fs_1.createWriteStream)(filePath, 'utf-8');
1034
- return await new Promise((resolve, reject) => {
1035
- stream.on('error', reject);
1036
- stream.on('finish', resolve);
1037
- stream.write('[\n');
1038
- data.forEach((entry, index) => {
1039
- stream.write(JSON.stringify(entry));
1040
- if (index !== data.length - 1)
1041
- stream.write(',');
1042
- stream.write('\n');
1043
- });
1044
- stream.write(']\n');
1045
- stream.end();
1046
- });
1047
- }
1048
- overwriteCredentialsProperties() {
1049
- const { credentials } = this.loadNodesAndCredentials.types;
1050
- const credentialsOverwrites = this.credentialsOverwrites.getAll();
1051
- const { skipTypes } = this.globalConfig.credentials.overwrite;
1052
- for (const credential of credentials) {
1053
- delete credential.__overwrittenProperties;
1054
- delete credential.__skipManagedCreation;
1055
- const overwrittenProperties = [];
1056
- this.credentialTypes
1057
- .getParentTypes(credential.name)
1058
- .reverse()
1059
- .map((name) => credentialsOverwrites[name])
1060
- .forEach((overwrite) => {
1061
- if (overwrite)
1062
- overwrittenProperties.push(...Object.keys(overwrite));
1063
- });
1064
- if (credential.name in credentialsOverwrites) {
1065
- overwrittenProperties.push(...Object.keys(credentialsOverwrites[credential.name]));
1066
- }
1067
- if (overwrittenProperties.length) {
1068
- credential.__overwrittenProperties = (0, uniq_1.default)(overwrittenProperties);
1069
- }
1070
- if (skipTypes.includes(credential.name)) {
1071
- credential.__skipManagedCreation = true;
1072
- }
1073
- }
1074
- }
1075
- };
1076
- exports.FrontendService = FrontendService;
1077
- exports.FrontendService = FrontendService = __decorate([
1078
- (0, di_1.Service)(),
1079
- __metadata("design:paramtypes", [config_1.GlobalConfig,
1080
- backend_common_1.Logger,
1081
- load_nodes_and_credentials_1.LoadNodesAndCredentials,
1082
- credential_types_1.CredentialTypes,
1083
- credentials_overwrites_1.CredentialsOverwrites,
1084
- license_1.License,
1085
- email_1.UserManagementMailer,
1086
- n8n_core_1.InstanceSettings,
1087
- url_service_1.UrlService,
1088
- config_1.SecurityConfig,
1089
- push_config_1.PushConfig,
1090
- n8n_core_1.BinaryDataConfig,
1091
- backend_common_1.LicenseState,
1092
- backend_common_1.ModuleRegistry,
1093
- mfa_service_1.MfaService,
1094
- ownership_service_1.OwnershipService,
1095
- ai_usage_service_1.AiUsageService])
1096
- ], FrontendService);
1097
- //# sourceMappingURL=frontend.service.js.map
1098
- EOF
1099
-
1100
- # ==============================
1101
- # 启动 n8n
 
1
  FROM n8n/n8n:latest
2
  USER root
3
 
4
+ # 输出 license.js 内容
5
+ RUN echo "====== 1. license.js ======" && cat /usr/local/lib/node_modules/n8n/dist/license.js 2>/dev/null || true
6
 
7
+ # 输出 frontend.service.js 内容
8
+ RUN echo -e "\n====== 2. frontend.service.js ======" && cat /usr/local/lib/node_modules/n8n/dist/services/frontend.service.js 2>/dev/null || true
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
9
 
10
+ # 输出 license-state.js 内容
11
+ RUN echo -e "\n====== 3. license-state.js ======" && cat /usr/local/lib/node_modules/n8n/node_modules/.pnpm/@n8n+backend-common@file+packages+@n8n+backend-common/node_modules/@n8n/backend-common/dist/license-state.js 2>/dev/null || true
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
 
13
+ USER node