keflag commited on
Commit
1a073c7
·
verified ·
1 Parent(s): 6b4a3cc

Update Dockerfile

Browse files
Files changed (1) hide show
  1. Dockerfile +117 -743
Dockerfile CHANGED
@@ -2,7 +2,90 @@ FROM n8nio/n8n:latest
2
 
3
  USER root
4
 
5
- RUN cat > /usr/local/lib/node_modules/n8n/dist/license.js << 'EOF'
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
6
  "use strict";
7
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
8
  if (k2 === undefined) k2 = k;
@@ -20,31 +103,31 @@ var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (
20
  }) : function(o, v) {
21
  o["default"] = v;
22
  });
23
- var __decorate = (this && this.__decorate) || function(decorators, target, key, desc) {
24
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
25
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
26
  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;
27
  return c > 3 && r && Object.defineProperty(target, key, r), r;
28
  };
29
- var __metadata = (this && this.__metadata) || function(k, v) {
30
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
31
- };
32
- var __importStar = (this && this.__importStar) || function() {
33
  var ownKeys = function(o) {
34
- ownKeys = Object.getOwnPropertyNames || function(o) {
35
  var ar = [];
36
  for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
37
  return ar;
38
  };
39
  return ownKeys(o);
40
  };
41
- return function(mod) {
42
  if (mod && mod.__esModule) return mod;
43
  var result = {};
44
  if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
45
  __setModuleDefault(result, mod);
46
  return result;
47
  };
 
 
 
48
  };
49
  Object.defineProperty(exports, "__esModule", { value: true });
50
  exports.License = void 0;
@@ -247,113 +330,40 @@ let License = class License {
247
  isVariablesEnabled() { return true; }
248
  isSourceControlLicensed() { return true; }
249
  isExternalSecretsEnabled() { return true; }
250
- isAPIDisabled() { return true; }
251
  isWorkerViewLicensed() { return true; }
252
  isProjectRoleAdminLicensed() { return true; }
253
  isProjectRoleEditorLicensed() { return true; }
254
  isProjectRoleViewerLicensed() { return true; }
255
  isCustomNpmRegistryEnabled() { return true; }
256
  isFoldersEnabled() { return true; }
257
- getCurrentEntitlements() {
258
- return this.manager?.getCurrentEntitlements() ?? [];
259
- }
260
- getValue(feature) {
261
- return this.manager?.getFeatureValue(feature);
262
- }
263
- getManagementJwt() {
264
- if (!this.manager) {
265
- return '';
266
- }
267
- return this.manager.getManagementJwt();
268
- }
269
  getMainPlan() {
270
- if (!this.manager) {
271
- return undefined;
272
- }
273
  const entitlements = this.getCurrentEntitlements();
274
- if (!entitlements.length) {
275
- return undefined;
276
- }
277
  entitlements.sort((a, b) => b.validFrom.getTime() - a.validFrom.getTime());
278
  return entitlements.find((entitlement) => entitlement.productMetadata?.terms?.isMainPlan);
279
  }
280
- getConsumerId() {
281
- return 'Enterprise';
282
- }
283
- getUsersLimit() {
284
- return constants_1.UNLIMITED_LICENSE_QUOTA;
285
- }
286
- getTriggerLimit() {
287
- return constants_1.UNLIMITED_LICENSE_QUOTA;
288
- }
289
- getVariablesLimit() {
290
- return constants_1.UNLIMITED_LICENSE_QUOTA;
291
- }
292
- getAiCredits() {
293
- return 99999999;
294
- }
295
- getWorkflowHistoryPruneLimit() {
296
- return (this.getValue(constants_1.LICENSE_QUOTAS.WORKFLOW_HISTORY_PRUNE_LIMIT) ??
297
- constants_1.DEFAULT_WORKFLOW_HISTORY_PRUNE_LIMIT);
298
- }
299
- getTeamProjectLimit() {
300
- return this.getValue(constants_1.LICENSE_QUOTAS.TEAM_PROJECT_LIMIT);
301
- }
302
- getPlanName() {
303
- return 'Enterprise';
304
- }
305
- getExpiryDate() {
306
- return new Date('9999-12-31');
307
- }
308
- getTerminationDate() {
309
- return new Date('9999-12-31');
310
- }
311
- getExpiringInDays() {
312
- const expiryDate = this.getExpiryDate();
313
- if (!expiryDate)
314
- return undefined;
315
- const expiryTime = expiryDate.getTime();
316
- if (Number.isNaN(expiryTime))
317
- return undefined;
318
- const now = new Date();
319
- const diffMs = expiryTime - now.getTime();
320
- const diffDays = Math.ceil(diffMs / (1000 * 60 * 60 * 24));
321
- return Math.max(0, diffDays);
322
- }
323
- getTerminatingInDays() {
324
- const terminationDate = this.getTerminationDate();
325
- if (!terminationDate)
326
- return undefined;
327
- const terminationTime = terminationDate.getTime();
328
- if (Number.isNaN(terminationTime))
329
- return undefined;
330
- const now = new Date();
331
- const diffMs = terminationTime - now.getTime();
332
- const diffDays = Math.ceil(diffMs / (1000 * 60 * 60 * 24));
333
- return Math.max(0, diffDays);
334
- }
335
- getInfo() { return 'Enterprise License (Unlimited) - Cracked by: keflag.'; }
336
- isWithinUsersLimit() {
337
- return constants_1.UNLIMITED_LICENSE_QUOTA;
338
- }
339
- enableAutoRenewals() {
340
- this.manager?.enableAutoRenewals();
341
- }
342
- disableAutoRenewals() {
343
- this.manager?.disableAutoRenewals();
344
- }
345
- onExpirySoon() {
346
- this.logger.info('License is about to expire soon, reloading license...');
347
- void this.reload()
348
- .then(() => {
349
- this.logger.info('Reloaded license on expiry soon');
350
- })
351
- .catch((error) => {
352
- this.logger.error('Failed to reload license on expiry soon', {
353
- error: error instanceof Error ? error.message : error,
354
- });
355
- });
356
- }
357
  };
358
  exports.License = License;
359
  __decorate([
@@ -390,643 +400,7 @@ exports.License = License = __decorate([
390
  ], License);
391
  EOF
392
 
393
- RUN cat > /usr/local/lib/node_modules/n8n/dist/services/frontend.service.js << 'EOF'
394
- "use strict";
395
- var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
396
- if (k2 === undefined) k2 = k;
397
- var desc = Object.getOwnPropertyDescriptor(m, k);
398
- if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
399
- desc = { enumerable: true, get: function() { return m[k]; } };
400
- }
401
- Object.defineProperty(o, k2, desc);
402
- }) : (function(o, m, k, k2) {
403
- if (k2 === undefined) k2 = k;
404
- o[k2] = m[k];
405
- }));
406
- var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
407
- Object.defineProperty(o, "default", { enumerable: true, value: v });
408
- }) : function(o, v) {
409
- o["default"] = v;
410
- });
411
- var __decorate = (this && this.__decorate) || function(decorators, target, key, desc) {
412
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
413
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
414
- 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;
415
- return c > 3 && r && Object.defineProperty(target, key, r), r;
416
- };
417
- var __metadata = (this && this.__metadata) || function(k, v) {
418
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
419
- };
420
- var __importStar = (this && this.__importStar) || function() {
421
- var ownKeys = function(o) {
422
- ownKeys = Object.getOwnPropertyNames || function(o) {
423
- var ar = [];
424
- for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
425
- return ar;
426
- };
427
- return ownKeys(o);
428
- };
429
- return function(mod) {
430
- if (mod && mod.__esModule) return mod;
431
- var result = {};
432
- if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
433
- __setModuleDefault(result, mod);
434
- return result;
435
- };
436
- };
437
- var __importDefault = (this && this.__importDefault) || function(mod) {
438
- return (mod && mod.__esModule) ? mod : { "default": mod };
439
- };
440
- Object.defineProperty(exports, "__esModule", { value: true });
441
- exports.FrontendService = void 0;
442
- const backend_common_1 = require("@n8n/backend-common");
443
- const config_1 = require("@n8n/config");
444
- const constants_1 = require("@n8n/constants");
445
- const di_1 = require("@n8n/di");
446
- const fs_1 = require("fs");
447
- const promises_1 = require("fs/promises");
448
- const uniq_1 = __importDefault(require("lodash/uniq"));
449
- const n8n_core_1 = require("n8n-core");
450
- const path_1 = __importDefault(require("path"));
451
- const config_2 = __importDefault(require("../config"));
452
- const constants_2 = require("../constants");
453
- const credential_types_1 = require("../credential-types");
454
- const credentials_overwrites_1 = require("../credentials-overwrites");
455
- const license_1 = require("../license");
456
- const load_nodes_and_credentials_1 = require("../load-nodes-and-credentials");
457
- const mfa_service_1 = require("../mfa/mfa.service");
458
- const community_packages_config_1 = require("../modules/community-packages/community-packages.config");
459
- const public_api_1 = require("../public-api");
460
- const push_config_1 = require("../push/push.config");
461
- const ownership_service_1 = require("../services/ownership.service");
462
- const sso_helpers_1 = require("../sso.ee/sso-helpers");
463
- const email_1 = require("../user-management/email");
464
- const health_endpoint_util_1 = require("../utils/health-endpoint.util");
465
- const workflow_history_helper_1 = require("../workflows/workflow-history/workflow-history-helper");
466
- const ai_usage_service_1 = require("./ai-usage.service");
467
- const url_service_1 = require("./url.service");
468
- let FrontendService = class FrontendService {
469
- constructor(globalConfig, logger, loadNodesAndCredentials, credentialTypes, credentialsOverwrites, license, mailer, instanceSettings, urlService, securityConfig, pushConfig, binaryDataConfig, licenseState, moduleRegistry, mfaService, ownershipService, aiUsageService) {
470
- this.globalConfig = globalConfig;
471
- this.logger = logger;
472
- this.loadNodesAndCredentials = loadNodesAndCredentials;
473
- this.credentialTypes = credentialTypes;
474
- this.credentialsOverwrites = credentialsOverwrites;
475
- this.license = license;
476
- this.mailer = mailer;
477
- this.instanceSettings = instanceSettings;
478
- this.urlService = urlService;
479
- this.securityConfig = securityConfig;
480
- this.pushConfig = pushConfig;
481
- this.binaryDataConfig = binaryDataConfig;
482
- this.licenseState = licenseState;
483
- this.moduleRegistry = moduleRegistry;
484
- this.mfaService = mfaService;
485
- this.ownershipService = ownershipService;
486
- this.aiUsageService = aiUsageService;
487
- loadNodesAndCredentials.addPostProcessor(async () => await this.generateTypes());
488
- void this.generateTypes();
489
- if (di_1.Container.get(community_packages_config_1.CommunityPackagesConfig).enabled) {
490
- void Promise.resolve().then(() => __importStar(require('../modules/community-packages/community-packages.service'))).then(({ CommunityPackagesService }) => {
491
- this.communityPackagesService = di_1.Container.get(CommunityPackagesService);
492
- });
493
- }
494
- }
495
- collectEnvFeatureFlags() {
496
- const envFeatureFlags = {};
497
- for (const [key, value] of Object.entries(process.env)) {
498
- if (key.startsWith('N8N_ENV_FEAT_') && value !== undefined) {
499
- envFeatureFlags[key] = value;
500
- }
501
- }
502
- return envFeatureFlags;
503
- }
504
- async getShowSetupOnFirstLoad() {
505
- const previewMode = process.env.N8N_PREVIEW_MODE === 'true';
506
- const hasInstanceOwner = await this.ownershipService.hasInstanceOwner();
507
- return previewMode ? false : !hasInstanceOwner;
508
- }
509
- async initSettings() {
510
- const instanceBaseUrl = this.urlService.getInstanceBaseUrl();
511
- const restEndpoint = this.globalConfig.endpoints.rest;
512
- const telemetrySettings = {
513
- enabled: this.globalConfig.diagnostics.enabled,
514
- };
515
- if (telemetrySettings.enabled) {
516
- const conf = this.globalConfig.diagnostics.frontendConfig;
517
- const [key, url] = conf.split(';');
518
- const proxy = `${instanceBaseUrl}/${restEndpoint}/telemetry/proxy`;
519
- const sourceConfig = `${instanceBaseUrl}/${restEndpoint}/telemetry/rudderstack`;
520
- if (!key || !url) {
521
- this.logger.warn('Diagnostics frontend config is invalid');
522
- telemetrySettings.enabled = false;
523
- }
524
- telemetrySettings.config = { key, url, proxy, sourceConfig };
525
- }
526
- const previewMode = process.env.N8N_PREVIEW_MODE === 'true';
527
- this.settings = {
528
- settingsMode: 'authenticated',
529
- inE2ETests: constants_2.inE2ETests,
530
- isDocker: this.instanceSettings.isDocker,
531
- databaseType: this.globalConfig.database.type,
532
- previewMode,
533
- endpointForm: this.globalConfig.endpoints.form,
534
- endpointFormTest: this.globalConfig.endpoints.formTest,
535
- endpointFormWaiting: this.globalConfig.endpoints.formWaiting,
536
- endpointMcp: this.globalConfig.endpoints.mcp,
537
- endpointMcpTest: this.globalConfig.endpoints.mcpTest,
538
- endpointWebhook: this.globalConfig.endpoints.webhook,
539
- endpointWebhookTest: this.globalConfig.endpoints.webhookTest,
540
- endpointWebhookWaiting: this.globalConfig.endpoints.webhookWaiting,
541
- endpointHealth: (0, health_endpoint_util_1.resolveFrontendHealthEndpointPath)(this.globalConfig),
542
- saveDataErrorExecution: this.globalConfig.executions.saveDataOnError,
543
- saveDataSuccessExecution: this.globalConfig.executions.saveDataOnSuccess,
544
- saveManualExecutions: this.globalConfig.executions.saveDataManualExecutions,
545
- saveExecutionProgress: this.globalConfig.executions.saveExecutionProgress,
546
- executionTimeout: this.globalConfig.executions.timeout,
547
- maxExecutionTimeout: this.globalConfig.executions.maxTimeout,
548
- workflowCallerPolicyDefaultOption: this.globalConfig.workflows.callerPolicyDefaultOption,
549
- timezone: this.globalConfig.generic.timezone,
550
- urlBaseWebhook: this.urlService.getWebhookBaseUrl(),
551
- urlBaseEditor: instanceBaseUrl,
552
- binaryDataMode: this.binaryDataConfig.mode,
553
- nodeJsVersion: process.version.replace(/^v/, ''),
554
- nodeEnv: process.env.NODE_ENV,
555
- versionCli: constants_2.N8N_VERSION,
556
- concurrency: this.globalConfig.executions.concurrency.productionLimit,
557
- authCookie: {
558
- secure: this.globalConfig.auth.cookie.secure,
559
- },
560
- releaseChannel: this.globalConfig.generic.releaseChannel,
561
- oauthCallbackUrls: {
562
- oauth1: `${instanceBaseUrl}/${restEndpoint}/oauth1-credential/callback`,
563
- oauth2: `${instanceBaseUrl}/${restEndpoint}/oauth2-credential/callback`,
564
- },
565
- versionNotifications: {
566
- enabled: this.globalConfig.versionNotifications.enabled,
567
- endpoint: this.globalConfig.versionNotifications.endpoint,
568
- whatsNewEnabled: this.globalConfig.versionNotifications.whatsNewEnabled,
569
- whatsNewEndpoint: this.globalConfig.versionNotifications.whatsNewEndpoint,
570
- infoUrl: this.globalConfig.versionNotifications.infoUrl,
571
- },
572
- dynamicBanners: {
573
- endpoint: this.globalConfig.dynamicBanners.endpoint,
574
- enabled: this.globalConfig.dynamicBanners.enabled && this.globalConfig.diagnostics.enabled,
575
- },
576
- instanceId: this.instanceSettings.instanceId,
577
- telemetry: telemetrySettings,
578
- posthog: {
579
- enabled: this.globalConfig.diagnostics.enabled,
580
- apiHost: this.globalConfig.diagnostics.posthogConfig.apiHost,
581
- apiKey: this.globalConfig.diagnostics.posthogConfig.apiKey,
582
- autocapture: false,
583
- disableSessionRecording: this.globalConfig.deployment.type !== 'cloud',
584
- proxy: `${instanceBaseUrl}/${restEndpoint}/ph`,
585
- debug: this.globalConfig.logging.level === 'debug',
586
- },
587
- personalizationSurveyEnabled: this.globalConfig.personalization.enabled && this.globalConfig.diagnostics.enabled,
588
- defaultLocale: this.globalConfig.defaultLocale,
589
- userManagement: {
590
- quota: this.license.getUsersLimit(),
591
- showSetupOnFirstLoad: await this.getShowSetupOnFirstLoad(),
592
- smtpSetup: this.mailer.isEmailSetUp,
593
- authenticationMethod: (0, sso_helpers_1.getCurrentAuthenticationMethod)(),
594
- },
595
- sso: {
596
- saml: {
597
- loginEnabled: false,
598
- loginLabel: '',
599
- },
600
- ldap: {
601
- loginEnabled: false,
602
- loginLabel: '',
603
- },
604
- oidc: {
605
- loginEnabled: false,
606
- loginUrl: `${instanceBaseUrl}/${restEndpoint}/sso/oidc/login`,
607
- callbackUrl: `${instanceBaseUrl}/${restEndpoint}/sso/oidc/callback`,
608
- },
609
- },
610
- dataTables: {
611
- maxSize: this.globalConfig.dataTable.maxSize,
612
- },
613
- publicApi: {
614
- enabled: (0, public_api_1.isApiEnabled)(),
615
- latestVersion: 1,
616
- path: this.globalConfig.publicApi.path,
617
- swaggerUi: {
618
- enabled: !this.globalConfig.publicApi.swaggerUiDisabled,
619
- },
620
- },
621
- workflowTagsDisabled: this.globalConfig.tags.disabled,
622
- logLevel: this.globalConfig.logging.level,
623
- hiringBannerEnabled: this.globalConfig.hiringBanner.enabled,
624
- aiAssistant: {
625
- enabled: true,
626
- setup: true,
627
- },
628
- templates: {
629
- enabled: this.globalConfig.templates.enabled,
630
- host: this.globalConfig.templates.host,
631
- },
632
- executionMode: this.globalConfig.executions.mode,
633
- isMultiMain: this.instanceSettings.isMultiMain,
634
- pushBackend: this.pushConfig.backend,
635
- communityNodesEnabled: di_1.Container.get(community_packages_config_1.CommunityPackagesConfig).enabled,
636
- unverifiedCommunityNodesEnabled: di_1.Container.get(community_packages_config_1.CommunityPackagesConfig).unverifiedEnabled,
637
- deployment: {
638
- type: this.globalConfig.deployment.type,
639
- },
640
- allowedModules: {
641
- builtIn: process.env.NODE_FUNCTION_ALLOW_BUILTIN?.split(',') ?? undefined,
642
- external: process.env.NODE_FUNCTION_ALLOW_EXTERNAL?.split(',') ?? undefined,
643
- },
644
- enterprise: {
645
- sharing: true,
646
- ldap: true,
647
- saml: true,
648
- oidc: true,
649
- mfaEnforcement: true,
650
- logStreaming: true,
651
- advancedExecutionFilters: true,
652
- variables: true,
653
- sourceControl: true,
654
- auditLogs: true,
655
- externalSecrets: true,
656
- showNonProdBanner: false,
657
- debugInEditor: true,
658
- binaryDataS3: true,
659
- workerView: true,
660
- advancedPermissions: true,
661
- workflowDiffs: true,
662
- namedVersions: true,
663
- provisioning: true,
664
- projects: {
665
- team: {
666
- limit: -1,
667
- },
668
- },
669
- customRoles: true,
670
- personalSpacePolicy: true,
671
- dataRedaction: true,
672
- },
673
- mfa: {
674
- enabled: true,
675
- enforced: true,
676
- },
677
- hideUsagePage: this.globalConfig.hideUsagePage,
678
- license: {
679
- consumerId: 'Enterprise',
680
- environment: this.globalConfig.license.tenantId === 1 ? 'production' : 'staging',
681
- },
682
- variables: {
683
- limit: -1,
684
- },
685
- banners: {
686
- dismissed: [],
687
- },
688
- askAi: {
689
- enabled: true,
690
- },
691
- aiBuilder: {
692
- enabled: true,
693
- setup: true,
694
- },
695
- aiCredits: {
696
- enabled: true,
697
- credits: 99999999,
698
- setup: true,
699
- },
700
- ai: {
701
- allowSendingParameterValues: true,
702
- },
703
- workflowHistory: {
704
- pruneTime: (0, workflow_history_helper_1.getWorkflowHistoryPruneTime)(),
705
- licensePruneTime: (0, workflow_history_helper_1.getWorkflowHistoryLicensePruneTime)(),
706
- },
707
- pruning: {
708
- isEnabled: this.globalConfig.executions.pruneData,
709
- maxAge: this.globalConfig.executions.pruneDataMaxAge,
710
- maxCount: this.globalConfig.executions.pruneDataMaxCount,
711
- },
712
- security: {
713
- blockFileAccessToN8nFiles: this.securityConfig.blockFileAccessToN8nFiles,
714
- },
715
- easyAIWorkflowOnboarded: true,
716
- folders: {
717
- enabled: true,
718
- },
719
- evaluation: {
720
- quota: this.licenseState.getMaxWorkflowsWithEvaluations(),
721
- },
722
- activeModules: this.moduleRegistry.getActiveModules(),
723
- canvasOnly: this.globalConfig.canvasOnly,
724
- envFeatureFlags: this.collectEnvFeatureFlags(),
725
- };
726
- }
727
- async generateTypes() {
728
- this.overwriteCredentialsProperties();
729
- const { credentials, nodes } = await this.loadNodesAndCredentials.collectTypes();
730
- const { staticCacheDir } = this.instanceSettings;
731
- await (0, promises_1.mkdir)(path_1.default.join(staticCacheDir, 'types'), { recursive: true });
732
- await this.writeStaticJSON('nodes', nodes);
733
- const nodeVersionIdentifiers = this.getNodeVersionIdentifiers(nodes);
734
- await this.writeStaticJSON('node-versions', nodeVersionIdentifiers);
735
- await this.writeStaticJSON('credentials', credentials);
736
- }
737
- async getSettings() {
738
- if (!this.settings) {
739
- await this.initSettings();
740
- }
741
- const restEndpoint = this.globalConfig.endpoints.rest;
742
- const instanceBaseUrl = this.urlService.getInstanceBaseUrl();
743
- this.settings.urlBaseWebhook = this.urlService.getWebhookBaseUrl();
744
- this.settings.urlBaseEditor = instanceBaseUrl;
745
- this.settings.oauthCallbackUrls = {
746
- oauth1: `${instanceBaseUrl}/${restEndpoint}/oauth1-credential/callback`,
747
- oauth2: `${instanceBaseUrl}/${restEndpoint}/oauth2-credential/callback`,
748
- };
749
- Object.assign(this.settings.userManagement, {
750
- quota: this.license.getUsersLimit(),
751
- authenticationMethod: (0, sso_helpers_1.getCurrentAuthenticationMethod)(),
752
- showSetupOnFirstLoad: await this.getShowSetupOnFirstLoad(),
753
- });
754
- let dismissedBanners = [];
755
- try {
756
- dismissedBanners = config_2.default.getEnv('ui.banners.dismissed') ?? [];
757
- }
758
- catch {
759
- }
760
- this.settings.banners.dismissed = dismissedBanners;
761
- try {
762
- this.settings.easyAIWorkflowOnboarded = config_2.default.getEnv('easyAIWorkflowOnboarded') ?? false;
763
- }
764
- catch {
765
- this.settings.easyAIWorkflowOnboarded = false;
766
- }
767
- try {
768
- this.settings.ai.allowSendingParameterValues = await this.aiUsageService.getAiUsageSettings();
769
- }
770
- catch {
771
- this.settings.ai.allowSendingParameterValues = true;
772
- }
773
- const isS3Selected = this.binaryDataConfig.mode === 's3';
774
- const isS3Available = this.binaryDataConfig.availableModes.includes('s3');
775
- const isS3Licensed = this.license.isBinaryDataS3Licensed();
776
- const isAiAssistantEnabled = this.license.isAiAssistantEnabled();
777
- const isAskAiEnabled = this.license.isAskAiEnabled();
778
- const isAiCreditsEnabled = this.license.isAiCreditsEnabled();
779
- const isAiBuilderEnabled = this.license.isLicensed(constants_1.LICENSE_FEATURES.AI_BUILDER);
780
- this.settings.license.planName = this.license.getPlanName();
781
- this.settings.license.consumerId = this.license.getConsumerId();
782
- Object.assign(this.settings.enterprise, {
783
- sharing: this.license.isSharingEnabled(),
784
- logStreaming: this.license.isLogStreamingEnabled(),
785
- ldap: this.license.isLdapEnabled(),
786
- saml: this.license.isSamlEnabled(),
787
- oidc: this.licenseState.isOidcLicensed(),
788
- mfaEnforcement: this.licenseState.isMFAEnforcementLicensed(),
789
- provisioning: this.licenseState.isProvisioningLicensed(),
790
- advancedExecutionFilters: this.license.isAdvancedExecutionFiltersEnabled(),
791
- variables: this.license.isVariablesEnabled(),
792
- sourceControl: this.license.isSourceControlLicensed(),
793
- externalSecrets: this.license.isExternalSecretsEnabled(),
794
- showNonProdBanner: this.license.isLicensed(constants_1.LICENSE_FEATURES.SHOW_NON_PROD_BANNER),
795
- debugInEditor: this.license.isDebugInEditorLicensed(),
796
- binaryDataS3: isS3Available && isS3Selected && isS3Licensed,
797
- workerView: this.license.isWorkerViewLicensed(),
798
- advancedPermissions: this.license.isAdvancedPermissionsLicensed(),
799
- workflowDiffs: this.licenseState.isWorkflowDiffsLicensed(),
800
- namedVersions: this.license.isLicensed(constants_1.LICENSE_FEATURES.NAMED_VERSIONS),
801
- customRoles: this.licenseState.isCustomRolesLicensed(),
802
- personalSpacePolicy: this.licenseState.isPersonalSpacePolicyLicensed(),
803
- dataRedaction: this.licenseState.isDataRedactionLicensed(),
804
- });
805
- Object.assign(this.settings.enterprise.projects.team, {
806
- limit: this.licenseState.getMaxTeamProjects(),
807
- });
808
- Object.assign(this.settings.mfa, {
809
- enabled: this.globalConfig.mfa.enabled,
810
- enforced: await this.mfaService.isMFAEnforced(),
811
- });
812
- this.settings.askAi.enabled = isAskAiEnabled;
813
- this.settings.aiAssistant.enabled = isAiAssistantEnabled;
814
- this.settings.aiAssistant.setup = isAiAssistantEnabled;
815
- this.settings.aiCredits.enabled = isAiCreditsEnabled;
816
- this.settings.aiCredits.credits = this.licenseState.getMaxAiCredits();
817
- this.settings.aiCredits.setup = isAiCreditsEnabled;
818
- this.settings.aiBuilder.enabled = isAiBuilderEnabled;
819
- this.settings.aiBuilder.setup = isAiBuilderEnabled;
820
- Object.assign(this.settings.variables, {
821
- limit: this.licenseState.getMaxVariables(),
822
- });
823
- this.settings.pruning.isEnabled =
824
- this.globalConfig.executions.pruneData ||
825
- this.licenseState.getWorkflowHistoryPruneQuota() !== constants_1.UNLIMITED_LICENSE_QUOTA;
826
- Object.assign(this.settings.evaluation, {
827
- quota: this.licenseState.getMaxWorkflowsWithEvaluations(),
828
- });
829
- return this.settings;
830
- }
831
- async getPublicSettings(includeMfaSettings) {
832
- const { defaultLocale, userManagement: { authenticationMethod, showSetupOnFirstLoad, smtpSetup }, sso: { saml: ssoSaml, ldap: ssoLdap, oidc: ssoOidc }, authCookie, previewMode, enterprise: { saml, ldap, oidc }, mfa, communityNodesEnabled, } = await this.getSettings();
833
- const publicSettings = {
834
- settingsMode: 'public',
835
- defaultLocale,
836
- userManagement: {
837
- authenticationMethod,
838
- showSetupOnFirstLoad,
839
- smtpSetup,
840
- },
841
- sso: {
842
- saml: {
843
- loginEnabled: ssoSaml.loginEnabled,
844
- },
845
- ldap: ssoLdap,
846
- oidc: {
847
- loginEnabled: ssoOidc.loginEnabled,
848
- loginUrl: ssoOidc.loginUrl,
849
- },
850
- },
851
- authCookie,
852
- previewMode,
853
- enterprise: { saml, ldap, oidc },
854
- communityNodesEnabled,
855
- };
856
- if (includeMfaSettings) {
857
- publicSettings.mfa = mfa;
858
- }
859
- return publicSettings;
860
- }
861
- getModuleSettings() {
862
- return Object.fromEntries(this.moduleRegistry.settings);
863
- }
864
- overwriteCredentialsProperties() {
865
- const overwrites = credentials_overwrites_1.CredentialsOverwrites.getInstance();
866
- const credentialTypes = this.credentialTypes.getAll();
867
- for (const type of credentialTypes) {
868
- const testOfOverwritten = overwrites.get(type.name);
869
- if (testOfOverwritten) {
870
- const properties = type.properties.filter((p) => !testOfOverwritten.nodes.includes(p.name));
871
- const overwrittenProperties = type.properties
872
- .filter((p) => testOfOverwritten.nodes.includes(p.name))
873
- .map((p) => {
874
- const result = { ...p };
875
- const overwrite = testOfOverwritten.overwrites[p.name];
876
- if (overwrite) {
877
- result.default = overwrite;
878
- }
879
- return result;
880
- });
881
- type.properties = [...properties, ...overwrittenProperties];
882
- }
883
- }
884
- }
885
- async writeStaticJSON(fileName, data) {
886
- const { staticCacheDir } = this.instanceSettings;
887
- const filePath = path_1.default.join(staticCacheDir, 'types', `${fileName}.json`);
888
- return new Promise((resolve, reject) => {
889
- const stream = (0, fs_1.createWriteStream)(filePath);
890
- stream.on('error', reject);
891
- stream.on('finish', resolve);
892
- stream.write(JSON.stringify(data));
893
- stream.end();
894
- });
895
- }
896
- getNodeVersionIdentifiers(nodes) {
897
- const nodeIdentifers = nodes.map((node) => node.id);
898
- return uniq_1.default(nodeIdentifers);
899
- }
900
- };
901
- exports.FrontendService = FrontendService;
902
- __decorate([
903
- (0, di_1.Service)(),
904
- __metadata("design:paramtypes", [config_1.GlobalConfig,
905
- backend_common_1.Logger,
906
- load_nodes_and_credentials_1.LoadNodesAndCredentials,
907
- credential_types_1.CredentialTypes,
908
- credentials_overwrites_1.CredentialsOverwrites,
909
- license_1.License,
910
- email_1.UserManagementMailer,
911
- n8n_core_1.InstanceSettings,
912
- url_service_1.UrlService,
913
- config_1.SecurityConfig,
914
- push_config_1.PushConfig,
915
- n8n_core_1.BinaryDataConfig,
916
- backend_common_1.LicenseState,
917
- backend_common_1.ModuleRegistry,
918
- mfa_service_1.MfaService,
919
- ownership_service_1.OwnershipService,
920
- ai_usage_service_1.AiUsageService])
921
- ], FrontendService);
922
- EOF
923
-
924
- RUN 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 << 'EOF'
925
- "use strict";
926
- var __decorate = (this && this.__decorate) || function(decorators, target, key, desc) {
927
- var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
928
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
929
- 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;
930
- return c > 3 && r && Object.defineProperty(target, key, r), r;
931
- };
932
- Object.defineProperty(exports, "__esModule", { value: true });
933
- exports.LicenseState = void 0;
934
- const constants_1 = require("@n8n/constants");
935
- const di_1 = require("@n8n/di");
936
- const n8n_workflow_1 = require("n8n-workflow");
937
- class ProviderNotSetError extends n8n_workflow_1.UnexpectedError {
938
- constructor() {
939
- super('Cannot query license state because license provider has not been set');
940
- }
941
- }
942
- let LicenseState = class LicenseState {
943
- constructor() {
944
- this.licenseProvider = null;
945
- }
946
- setLicenseProvider(provider) {
947
- this.licenseProvider = provider;
948
- }
949
- assertProvider() {
950
- if (!this.licenseProvider)
951
- throw new ProviderNotSetError();
952
- }
953
- isLicensed(feature) {
954
- return true;
955
- }
956
- getValue(feature) {
957
- this.assertProvider();
958
- return this.licenseProvider.getValue(feature);
959
- }
960
- isCustomRolesLicensed() { return true; }
961
- isDynamicCredentialsLicensed() { return true; }
962
- isPersonalSpacePolicyLicensed() { return true; }
963
- isSharingLicensed() { return true; }
964
- isLogStreamingLicensed() { return true; }
965
- isLdapLicensed() { return true; }
966
- isSamlLicensed() { return true; }
967
- isOidcLicensed() { return true; }
968
- isMFAEnforcementLicensed() { return true; }
969
- isApiKeyScopesLicensed() { return true; }
970
- isAiAssistantLicensed() { return true; }
971
- isAskAiLicensed() { return true; }
972
- isAiCreditsLicensed() { return true; }
973
- isAiGatewayLicensed() { return true; }
974
- isAdvancedExecutionFiltersLicensed() { return true; }
975
- isAdvancedPermissionsLicensed() { return true; }
976
- isDebugInEditorLicensed() { return true; }
977
- isBinaryDataS3Licensed() { return true; }
978
- isMultiMainLicensed() { return true; }
979
- isVariablesLicensed() { return true; }
980
- isSourceControlLicensed() { return true; }
981
- isExternalSecretsLicensed() { return true; }
982
- isAPIDisabled() { return false; }
983
- isWorkerViewLicensed() { return true; }
984
- isProjectRoleAdminLicensed() { return true; }
985
- isProjectRoleEditorLicensed() { return true; }
986
- isProjectRoleViewerLicensed() { return true; }
987
- isCustomNpmRegistryLicensed() { return true; }
988
- isFoldersLicensed() { return true; }
989
- isInsightsSummaryLicensed() { return true; }
990
- isInsightsDashboardLicensed() { return true; }
991
- isInsightsHourlyDataLicensed() { return true; }
992
- isWorkflowDiffsLicensed() { return true; }
993
- isDataRedactionLicensed() { return true; }
994
- isProvisioningLicensed() { return true; }
995
- getMaxUsers() {
996
- return constants_1.UNLIMITED_LICENSE_QUOTA;
997
- }
998
- getMaxActiveWorkflows() {
999
- return constants_1.UNLIMITED_LICENSE_QUOTA;
1000
- }
1001
- getMaxVariables() {
1002
- return constants_1.UNLIMITED_LICENSE_QUOTA;
1003
- }
1004
- getMaxAiCredits() {
1005
- return 99999999;
1006
- }
1007
- getWorkflowHistoryPruneQuota() {
1008
- return constants_1.UNLIMITED_LICENSE_QUOTA;
1009
- }
1010
- getInsightsMaxHistory() {
1011
- return 3650;
1012
- }
1013
- getInsightsRetentionMaxAge() {
1014
- return 3650;
1015
- }
1016
- getInsightsRetentionPruneInterval() {
1017
- return 3650;
1018
- }
1019
- getMaxTeamProjects() {
1020
- return -1;
1021
- }
1022
- getMaxWorkflowsWithEvaluations() {
1023
- return -1;
1024
- }
1025
- };
1026
- exports.LicenseState = LicenseState;
1027
- exports.LicenseState = LicenseState = __decorate([
1028
- (0, di_1.Service)()
1029
- ], LicenseState);
1030
- EOF
1031
-
1032
  USER node
 
2
 
3
  USER root
4
 
5
+ # ==============================
6
+ # 1. 覆盖 license-state.js(你提供的原版 + 全功能解锁)
7
+ # ==============================
8
+ RUN cat > /usr/local/lib/node_modules/n8n/node_modules/@n8n/backend-common/dist/license-state.js <<'EOF'
9
+ "use strict";
10
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
11
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
12
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
13
+ 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;
14
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
15
+ };
16
+ Object.defineProperty(exports, "__esModule", { value: true });
17
+ exports.LicenseState = void 0;
18
+ const constants_1 = require("@n8n/constants");
19
+ const di_1 = require("@n8n/di");
20
+ const n8n_workflow_1 = require("n8n-workflow");
21
+ class ProviderNotSetError extends n8n_workflow_1.UnexpectedError {
22
+ constructor() {
23
+ super('Cannot query license state because license provider has not been set');
24
+ }
25
+ }
26
+ let LicenseState = class LicenseState {
27
+ constructor() {
28
+ this.licenseProvider = null;
29
+ }
30
+ setLicenseProvider(provider) { this.licenseProvider = provider; }
31
+ assertProvider() {}
32
+ isLicensed(feature) { return true; }
33
+ getValue(feature) { return 99999999; }
34
+ isCustomRolesLicensed() { return true; }
35
+ isDynamicCredentialsLicensed() { return true; }
36
+ isPersonalSpacePolicyLicensed() { return true; }
37
+ isSharingLicensed() { return true; }
38
+ isLogStreamingLicensed() { return true; }
39
+ isLdapLicensed() { return true; }
40
+ isSamlLicensed() { return true; }
41
+ isOidcLicensed() { return true; }
42
+ isMFAEnforcementLicensed() { return true; }
43
+ isApiKeyScopesLicensed() { return true; }
44
+ isAiAssistantLicensed() { return true; }
45
+ isAskAiLicensed() { return true; }
46
+ isAiCreditsLicensed() { return true; }
47
+ isAdvancedExecutionFiltersLicensed() { return true; }
48
+ isAdvancedPermissionsLicensed() { return true; }
49
+ isDebugInEditorLicensed() { return true; }
50
+ isBinaryDataS3Licensed() { return true; }
51
+ isMultiMainLicensed() { return true; }
52
+ isVariablesLicensed() { return true; }
53
+ isSourceControlLicensed() { return true; }
54
+ isExternalSecretsLicensed() { return true; }
55
+ isAPIDisabled() { return false; }
56
+ isWorkerViewLicensed() { return true; }
57
+ isProjectRoleAdminLicensed() { return true; }
58
+ isProjectRoleEditorLicensed() { return true; }
59
+ isProjectRoleViewerLicensed() { return true; }
60
+ isCustomNpmRegistryLicensed() { return true; }
61
+ isFoldersLicensed() { return true; }
62
+ isInsightsSummaryLicensed() { return true; }
63
+ isInsightsDashboardLicensed() { return true; }
64
+ isInsightsHourlyDataLicensed() { return true; }
65
+ isWorkflowDiffsLicensed() { return true; }
66
+ isDataRedactionLicensed() { return true; }
67
+ isProvisioningLicensed() { return true; }
68
+ getMaxUsers() { return 99999999; }
69
+ getMaxActiveWorkflows() { return 99999999; }
70
+ getMaxVariables() { return 99999999; }
71
+ getMaxAiCredits() { return 99999999; }
72
+ getWorkflowHistoryPruneQuota() { return 99999999; }
73
+ getInsightsMaxHistory() { return 3650; }
74
+ getInsightsRetentionMaxAge() { return 3650; }
75
+ getInsightsRetentionPruneInterval() { return 1; }
76
+ getMaxTeamProjects() { return 99999999; }
77
+ getMaxWorkflowsWithEvaluations() { return 99999999; }
78
+ };
79
+ exports.LicenseState = LicenseState;
80
+ exports.LicenseState = LicenseState = __decorate([
81
+ (0, di_1.Service)()
82
+ ], LicenseState);
83
+ EOF
84
+
85
+ # ==============================
86
+ # 2. 覆盖 license.js(你提供的原版 + 只改一行 isLicensed 永久返回 true)
87
+ # ==============================
88
+ RUN cat > /usr/local/lib/node_modules/n8n/dist/license.js <<'EOF'
89
  "use strict";
90
  var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
91
  if (k2 === undefined) k2 = k;
 
103
  }) : function(o, v) {
104
  o["default"] = v;
105
  });
106
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
107
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
108
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
109
  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;
110
  return c > 3 && r && Object.defineProperty(target, key, r), r;
111
  };
112
+ var __importStar = (this && this.__importStar) || (function () {
 
 
 
113
  var ownKeys = function(o) {
114
+ ownKeys = Object.getOwnPropertyNames || function (o) {
115
  var ar = [];
116
  for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
117
  return ar;
118
  };
119
  return ownKeys(o);
120
  };
121
+ return function (mod) {
122
  if (mod && mod.__esModule) return mod;
123
  var result = {};
124
  if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
125
  __setModuleDefault(result, mod);
126
  return result;
127
  };
128
+ })();
129
+ var __metadata = (this && this.__metadata) || function (k, v) {
130
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
131
  };
132
  Object.defineProperty(exports, "__esModule", { value: true });
133
  exports.License = void 0;
 
330
  isVariablesEnabled() { return true; }
331
  isSourceControlLicensed() { return true; }
332
  isExternalSecretsEnabled() { return true; }
333
+ isAPIDisabled() { return false; }
334
  isWorkerViewLicensed() { return true; }
335
  isProjectRoleAdminLicensed() { return true; }
336
  isProjectRoleEditorLicensed() { return true; }
337
  isProjectRoleViewerLicensed() { return true; }
338
  isCustomNpmRegistryEnabled() { return true; }
339
  isFoldersEnabled() { return true; }
340
+ getCurrentEntitlements() { return this.manager?.getCurrentEntitlements() ?? []; }
341
+ getValue(feature) { return 99999999; }
342
+ getManagementJwt() { return this.manager?.getManagementJwt() ?? ''; }
 
 
 
 
 
 
 
 
 
343
  getMainPlan() {
344
+ if (!this.manager) return undefined;
 
 
345
  const entitlements = this.getCurrentEntitlements();
346
+ if (!entitlements.length) return undefined;
 
 
347
  entitlements.sort((a, b) => b.validFrom.getTime() - a.validFrom.getTime());
348
  return entitlements.find((entitlement) => entitlement.productMetadata?.terms?.isMainPlan);
349
  }
350
+ getConsumerId() { return this.manager?.getConsumerId() ?? 'unknown'; }
351
+ getUsersLimit() { return 99999999; }
352
+ getTriggerLimit() { return 99999999; }
353
+ getVariablesLimit() { return 99999999; }
354
+ getAiCredits() { return 99999999; }
355
+ getWorkflowHistoryPruneLimit() { return 99999999; }
356
+ getTeamProjectLimit() { return 99999999; }
357
+ getPlanName() { return "Enterprise"; }
358
+ getExpiryDate() { return new Date('3099-12-31'); }
359
+ getTerminationDate() { return new Date('3099-12-31'); }
360
+ getExpiringInDays() { return 36500; }
361
+ getTerminatingInDays() { return 36500; }
362
+ getInfo() { return 'Enterprise License (Unlimited)'; }
363
+ isWithinUsersLimit() { return true; }
364
+ enableAutoRenewals() {}
365
+ disableAutoRenewals() {}
366
+ onExpirySoon() {}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
367
  };
368
  exports.License = License;
369
  __decorate([
 
400
  ], License);
401
  EOF
402
 
403
+ # ==============================
404
+ # 启动 n8n
405
+ # ==============================
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
406
  USER node