matterbridge 2.1.6-dev.2 → 2.1.6-dev.4
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/CHANGELOG.md +6 -2
- package/dist/cli.js +148 -3
- package/dist/frontend.js +32 -106
- package/dist/matter/export.js +1 -1
- package/dist/matterbridge.js +9 -1
- package/dist/pluginManager.js +67 -56
- package/frontend/build/asset-manifest.json +3 -3
- package/frontend/build/index.html +1 -1
- package/frontend/build/matterbridge 32x32.png +0 -0
- package/frontend/build/matterbridge 64x64.png +0 -0
- package/frontend/build/matterbridge.svg +50 -0
- package/frontend/build/static/js/{main.a241d4f0.js → main.257513e8.js} +13 -13
- package/frontend/build/static/js/main.257513e8.js.map +1 -0
- package/npm-shrinkwrap.json +44 -44
- package/package.json +2 -2
- package/frontend/build/static/js/main.a241d4f0.js.map +0 -1
- /package/frontend/build/static/js/{main.a241d4f0.js.LICENSE.txt → main.257513e8.js.LICENSE.txt} +0 -0
package/dist/pluginManager.js
CHANGED
|
@@ -1,10 +1,5 @@
|
|
|
1
|
-
import { AnsiLogger, BLUE, db, er, nf, nt, rs,
|
|
2
|
-
import path from 'path';
|
|
3
|
-
import { promises as fs } from 'fs';
|
|
4
|
-
import { pathToFileURL } from 'url';
|
|
5
|
-
import { exec } from 'child_process';
|
|
1
|
+
import { AnsiLogger, UNDERLINE, UNDERLINEOFF, BLUE, db, er, nf, nt, rs, wr } from './logger/export.js';
|
|
6
2
|
import { plg, typ } from './matterbridgeTypes.js';
|
|
7
|
-
import { shelly_config, somfytahoma_config, zigbee2mqtt_config } from './defaultConfigSchema.js';
|
|
8
3
|
export class PluginManager {
|
|
9
4
|
_plugins = new Map();
|
|
10
5
|
nodeContext;
|
|
@@ -84,12 +79,14 @@ export class PluginManager {
|
|
|
84
79
|
return plugins.length;
|
|
85
80
|
}
|
|
86
81
|
async resolve(pluginPath) {
|
|
82
|
+
const { default: path } = await import('node:path');
|
|
83
|
+
const { promises } = await import('node:fs');
|
|
87
84
|
if (!pluginPath.endsWith('package.json'))
|
|
88
85
|
pluginPath = path.join(pluginPath, 'package.json');
|
|
89
86
|
let packageJsonPath = path.resolve(pluginPath);
|
|
90
87
|
this.log.debug(`Resolving plugin path ${plg}${packageJsonPath}${db}`);
|
|
91
88
|
try {
|
|
92
|
-
await
|
|
89
|
+
await promises.access(packageJsonPath);
|
|
93
90
|
}
|
|
94
91
|
catch {
|
|
95
92
|
this.log.debug(`Package.json not found at ${plg}${packageJsonPath}${db}`);
|
|
@@ -97,7 +94,7 @@ export class PluginManager {
|
|
|
97
94
|
this.log.debug(`Trying at ${plg}${packageJsonPath}${db}`);
|
|
98
95
|
}
|
|
99
96
|
try {
|
|
100
|
-
const packageJson = JSON.parse(await
|
|
97
|
+
const packageJson = JSON.parse(await promises.readFile(packageJsonPath, 'utf8'));
|
|
101
98
|
if (!packageJson.name) {
|
|
102
99
|
this.log.error(`Package.json name not found at ${packageJsonPath}`);
|
|
103
100
|
return null;
|
|
@@ -161,9 +158,10 @@ export class PluginManager {
|
|
|
161
158
|
}
|
|
162
159
|
}
|
|
163
160
|
async parse(plugin) {
|
|
164
|
-
|
|
161
|
+
const { promises } = await import('node:fs');
|
|
165
162
|
try {
|
|
166
|
-
|
|
163
|
+
this.log.debug(`Parsing package.json of plugin ${plg}${plugin.name}${db}`);
|
|
164
|
+
const packageJson = JSON.parse(await promises.readFile(plugin.path, 'utf8'));
|
|
167
165
|
if (!packageJson.name)
|
|
168
166
|
this.log.warn(`Plugin ${plg}${plugin.name}${wr} has no name in package.json`);
|
|
169
167
|
if (!packageJson.version)
|
|
@@ -235,6 +233,7 @@ export class PluginManager {
|
|
|
235
233
|
}
|
|
236
234
|
}
|
|
237
235
|
async enable(nameOrPath) {
|
|
236
|
+
const { promises } = await import('node:fs');
|
|
238
237
|
if (!nameOrPath || nameOrPath === '')
|
|
239
238
|
return null;
|
|
240
239
|
if (this._plugins.has(nameOrPath)) {
|
|
@@ -250,7 +249,7 @@ export class PluginManager {
|
|
|
250
249
|
return null;
|
|
251
250
|
}
|
|
252
251
|
try {
|
|
253
|
-
const packageJson = JSON.parse(await
|
|
252
|
+
const packageJson = JSON.parse(await promises.readFile(packageJsonPath, 'utf8'));
|
|
254
253
|
const plugin = this._plugins.get(packageJson.name);
|
|
255
254
|
if (!plugin) {
|
|
256
255
|
this.log.error(`Failed to enable plugin ${plg}${nameOrPath}${er}: plugin not registered`);
|
|
@@ -267,6 +266,7 @@ export class PluginManager {
|
|
|
267
266
|
}
|
|
268
267
|
}
|
|
269
268
|
async disable(nameOrPath) {
|
|
269
|
+
const { promises } = await import('node:fs');
|
|
270
270
|
if (!nameOrPath || nameOrPath === '')
|
|
271
271
|
return null;
|
|
272
272
|
if (this._plugins.has(nameOrPath)) {
|
|
@@ -282,7 +282,7 @@ export class PluginManager {
|
|
|
282
282
|
return null;
|
|
283
283
|
}
|
|
284
284
|
try {
|
|
285
|
-
const packageJson = JSON.parse(await
|
|
285
|
+
const packageJson = JSON.parse(await promises.readFile(packageJsonPath, 'utf8'));
|
|
286
286
|
const plugin = this._plugins.get(packageJson.name);
|
|
287
287
|
if (!plugin) {
|
|
288
288
|
this.log.error(`Failed to disable plugin ${plg}${nameOrPath}${er}: plugin not registered`);
|
|
@@ -299,6 +299,7 @@ export class PluginManager {
|
|
|
299
299
|
}
|
|
300
300
|
}
|
|
301
301
|
async remove(nameOrPath) {
|
|
302
|
+
const { promises } = await import('node:fs');
|
|
302
303
|
if (!nameOrPath || nameOrPath === '')
|
|
303
304
|
return null;
|
|
304
305
|
if (this._plugins.has(nameOrPath)) {
|
|
@@ -314,7 +315,7 @@ export class PluginManager {
|
|
|
314
315
|
return null;
|
|
315
316
|
}
|
|
316
317
|
try {
|
|
317
|
-
const packageJson = JSON.parse(await
|
|
318
|
+
const packageJson = JSON.parse(await promises.readFile(packageJsonPath, 'utf8'));
|
|
318
319
|
const plugin = this._plugins.get(packageJson.name);
|
|
319
320
|
if (!plugin) {
|
|
320
321
|
this.log.error(`Failed to remove plugin ${plg}${nameOrPath}${er}: plugin not registered`);
|
|
@@ -331,6 +332,7 @@ export class PluginManager {
|
|
|
331
332
|
}
|
|
332
333
|
}
|
|
333
334
|
async add(nameOrPath) {
|
|
335
|
+
const { promises } = await import('node:fs');
|
|
334
336
|
if (!nameOrPath || nameOrPath === '')
|
|
335
337
|
return null;
|
|
336
338
|
const packageJsonPath = await this.resolve(nameOrPath);
|
|
@@ -339,7 +341,7 @@ export class PluginManager {
|
|
|
339
341
|
return null;
|
|
340
342
|
}
|
|
341
343
|
try {
|
|
342
|
-
const packageJson = JSON.parse(await
|
|
344
|
+
const packageJson = JSON.parse(await promises.readFile(packageJsonPath, 'utf8'));
|
|
343
345
|
if (this._plugins.get(packageJson.name)) {
|
|
344
346
|
this.log.info(`Plugin ${plg}${nameOrPath}${nf} already registered`);
|
|
345
347
|
return null;
|
|
@@ -351,15 +353,16 @@ export class PluginManager {
|
|
|
351
353
|
return plugin || null;
|
|
352
354
|
}
|
|
353
355
|
catch (err) {
|
|
354
|
-
this.log.error(`Failed to parse package.json of plugin ${plg}${nameOrPath}${er}: ${err}`);
|
|
356
|
+
this.log.error(`Failed to parse package.json of plugin ${plg}${nameOrPath}${er}: ${err instanceof Error ? err.message : err}`);
|
|
355
357
|
return null;
|
|
356
358
|
}
|
|
357
359
|
}
|
|
358
360
|
async install(name) {
|
|
361
|
+
const { exec } = await import('node:child_process');
|
|
359
362
|
await this.uninstall(name);
|
|
360
363
|
this.log.info(`Installing plugin ${plg}${name}${nf}`);
|
|
361
|
-
return new Promise((resolve
|
|
362
|
-
exec(`npm install -g ${name} --omit=dev
|
|
364
|
+
return new Promise((resolve) => {
|
|
365
|
+
exec(`npm install -g ${name} --omit=dev`, (error, stdout, stderr) => {
|
|
363
366
|
if (error) {
|
|
364
367
|
this.log.error(`Failed to install plugin ${plg}${name}${er}: ${error}`);
|
|
365
368
|
this.log.debug(`Failed to install plugin ${plg}${name}${db}: ${stderr}`);
|
|
@@ -389,9 +392,10 @@ export class PluginManager {
|
|
|
389
392
|
});
|
|
390
393
|
}
|
|
391
394
|
async uninstall(name) {
|
|
395
|
+
const { exec } = await import('node:child_process');
|
|
392
396
|
this.log.info(`Uninstalling plugin ${plg}${name}${nf}`);
|
|
393
|
-
return new Promise((resolve
|
|
394
|
-
exec(`npm uninstall -g ${name}
|
|
397
|
+
return new Promise((resolve) => {
|
|
398
|
+
exec(`npm uninstall -g ${name}`, (error, stdout, stderr) => {
|
|
395
399
|
if (error) {
|
|
396
400
|
this.log.error(`Failed to uninstall plugin ${plg}${name}${er}: ${error}`);
|
|
397
401
|
this.log.debug(`Failed to uninstall plugin ${plg}${name}${db}: ${stderr}`);
|
|
@@ -406,6 +410,8 @@ export class PluginManager {
|
|
|
406
410
|
});
|
|
407
411
|
}
|
|
408
412
|
async load(plugin, start = false, message = '', configure = false) {
|
|
413
|
+
const { promises } = await import('node:fs');
|
|
414
|
+
const { default: path } = await import('node:path');
|
|
409
415
|
if (!plugin.enabled) {
|
|
410
416
|
this.log.error(`Plugin ${plg}${plugin.name}${er} not enabled`);
|
|
411
417
|
return undefined;
|
|
@@ -416,8 +422,9 @@ export class PluginManager {
|
|
|
416
422
|
}
|
|
417
423
|
this.log.info(`Loading plugin ${plg}${plugin.name}${nf} type ${typ}${plugin.type}${nf}`);
|
|
418
424
|
try {
|
|
419
|
-
const packageJson = JSON.parse(await
|
|
425
|
+
const packageJson = JSON.parse(await promises.readFile(plugin.path, 'utf8'));
|
|
420
426
|
const pluginEntry = path.resolve(path.dirname(plugin.path), packageJson.main);
|
|
427
|
+
const { pathToFileURL } = await import('node:url');
|
|
421
428
|
const pluginUrl = pathToFileURL(pluginEntry);
|
|
422
429
|
this.log.debug(`Importing plugin ${plg}${plugin.name}${db} from ${pluginUrl.href}`);
|
|
423
430
|
const pluginInstance = await import(pluginUrl.href);
|
|
@@ -463,7 +470,7 @@ export class PluginManager {
|
|
|
463
470
|
}
|
|
464
471
|
}
|
|
465
472
|
catch (err) {
|
|
466
|
-
this.log.error(`Failed to load plugin ${plg}${plugin.name}${er}: ${err}`);
|
|
473
|
+
this.log.error(`Failed to load plugin ${plg}${plugin.name}${er}: ${err instanceof Error ? err.message : err}`);
|
|
467
474
|
plugin.error = true;
|
|
468
475
|
}
|
|
469
476
|
return undefined;
|
|
@@ -493,7 +500,7 @@ export class PluginManager {
|
|
|
493
500
|
}
|
|
494
501
|
catch (err) {
|
|
495
502
|
plugin.error = true;
|
|
496
|
-
this.log.error(`Failed to start plugin ${plg}${plugin.name}${er}: ${err}`);
|
|
503
|
+
this.log.error(`Failed to start plugin ${plg}${plugin.name}${er}: ${err instanceof Error ? err.message : err}`);
|
|
497
504
|
}
|
|
498
505
|
return undefined;
|
|
499
506
|
}
|
|
@@ -543,7 +550,7 @@ export class PluginManager {
|
|
|
543
550
|
this.log.debug(`Plugin ${plg}${plugin.name}${db} not configured`);
|
|
544
551
|
}
|
|
545
552
|
if (!plugin.platform) {
|
|
546
|
-
this.log.debug(
|
|
553
|
+
this.log.debug(`Plugin ${plg}${plugin.name}${db} no platform found`);
|
|
547
554
|
return undefined;
|
|
548
555
|
}
|
|
549
556
|
this.log.info(`Shutting down plugin ${plg}${plugin.name}${nf}: ${reason}...`);
|
|
@@ -565,15 +572,18 @@ export class PluginManager {
|
|
|
565
572
|
return plugin;
|
|
566
573
|
}
|
|
567
574
|
catch (err) {
|
|
568
|
-
this.log.error(`Failed to shut down plugin ${plg}${plugin.name}${er}: ${err}`);
|
|
575
|
+
this.log.error(`Failed to shut down plugin ${plg}${plugin.name}${er}: ${err instanceof Error ? err.message : err}`);
|
|
569
576
|
}
|
|
570
577
|
return undefined;
|
|
571
578
|
}
|
|
572
579
|
async loadConfig(plugin) {
|
|
580
|
+
const { default: path } = await import('node:path');
|
|
581
|
+
const { promises } = await import('node:fs');
|
|
582
|
+
const { shelly_config, somfytahoma_config, zigbee2mqtt_config } = await import('./defaultConfigSchema.js');
|
|
573
583
|
const configFile = path.join(this.matterbridge.matterbridgeDirectory, `${plugin.name}.config.json`);
|
|
574
584
|
try {
|
|
575
|
-
await
|
|
576
|
-
const data = await
|
|
585
|
+
await promises.access(configFile);
|
|
586
|
+
const data = await promises.readFile(configFile, 'utf8');
|
|
577
587
|
const config = JSON.parse(data);
|
|
578
588
|
this.log.debug(`Loaded config file ${configFile} for plugin ${plg}${plugin.name}${db}.`);
|
|
579
589
|
config.name = plugin.name;
|
|
@@ -585,45 +595,43 @@ export class PluginManager {
|
|
|
585
595
|
return config;
|
|
586
596
|
}
|
|
587
597
|
catch (err) {
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
return config;
|
|
604
|
-
}
|
|
605
|
-
catch (err) {
|
|
606
|
-
this.log.error(`Error creating config file ${configFile} for plugin ${plg}${plugin.name}${er}: ${err}`);
|
|
607
|
-
return config;
|
|
608
|
-
}
|
|
598
|
+
const nodeErr = err;
|
|
599
|
+
if (nodeErr.code === 'ENOENT') {
|
|
600
|
+
let config;
|
|
601
|
+
if (plugin.name === 'matterbridge-zigbee2mqtt')
|
|
602
|
+
config = zigbee2mqtt_config;
|
|
603
|
+
else if (plugin.name === 'matterbridge-somfy-tahoma')
|
|
604
|
+
config = somfytahoma_config;
|
|
605
|
+
else if (plugin.name === 'matterbridge-shelly')
|
|
606
|
+
config = shelly_config;
|
|
607
|
+
else
|
|
608
|
+
config = { name: plugin.name, type: plugin.type, debug: false, unregisterOnShutdown: false };
|
|
609
|
+
try {
|
|
610
|
+
await promises.writeFile(configFile, JSON.stringify(config, null, 2), 'utf8');
|
|
611
|
+
this.log.debug(`Created config file ${configFile} for plugin ${plg}${plugin.name}${db}.`);
|
|
612
|
+
return config;
|
|
609
613
|
}
|
|
610
|
-
|
|
611
|
-
this.log.error(`Error
|
|
612
|
-
return
|
|
614
|
+
catch (err) {
|
|
615
|
+
this.log.error(`Error creating config file ${configFile} for plugin ${plg}${plugin.name}${er}: ${err instanceof Error ? err.message : err}`);
|
|
616
|
+
return config;
|
|
613
617
|
}
|
|
614
618
|
}
|
|
615
|
-
|
|
616
|
-
|
|
619
|
+
else {
|
|
620
|
+
this.log.error(`Error accessing config file ${configFile} for plugin ${plg}${plugin.name}${er}: ${err instanceof Error ? err.message : err}`);
|
|
621
|
+
return { name: plugin.name, type: plugin.type, debug: false, unregisterOnShutdown: false };
|
|
622
|
+
}
|
|
617
623
|
}
|
|
618
624
|
}
|
|
619
625
|
async saveConfigFromPlugin(plugin) {
|
|
626
|
+
const { default: path } = await import('node:path');
|
|
627
|
+
const { promises } = await import('node:fs');
|
|
620
628
|
if (!plugin.platform?.config) {
|
|
621
629
|
this.log.error(`Error saving config file for plugin ${plg}${plugin.name}${er}: config not found`);
|
|
622
630
|
return Promise.reject(new Error(`Error saving config file for plugin ${plg}${plugin.name}${er}: config not found`));
|
|
623
631
|
}
|
|
624
632
|
const configFile = path.join(this.matterbridge.matterbridgeDirectory, `${plugin.name}.config.json`);
|
|
625
633
|
try {
|
|
626
|
-
await
|
|
634
|
+
await promises.writeFile(configFile, JSON.stringify(plugin.platform.config, null, 2), 'utf8');
|
|
627
635
|
this.log.debug(`Saved config file ${configFile} for plugin ${plg}${plugin.name}${db}`);
|
|
628
636
|
return Promise.resolve();
|
|
629
637
|
}
|
|
@@ -633,13 +641,15 @@ export class PluginManager {
|
|
|
633
641
|
}
|
|
634
642
|
}
|
|
635
643
|
async saveConfigFromJson(plugin, config) {
|
|
644
|
+
const { default: path } = await import('node:path');
|
|
645
|
+
const { promises } = await import('node:fs');
|
|
636
646
|
if (!config.name || !config.type || config.name !== plugin.name) {
|
|
637
647
|
this.log.error(`Error saving config file for plugin ${plg}${plugin.name}${er}. Wrong config data content:${rs}\n`, config);
|
|
638
648
|
return;
|
|
639
649
|
}
|
|
640
650
|
const configFile = path.join(this.matterbridge.matterbridgeDirectory, `${plugin.name}.config.json`);
|
|
641
651
|
try {
|
|
642
|
-
await
|
|
652
|
+
await promises.writeFile(configFile, JSON.stringify(config, null, 2), 'utf8');
|
|
643
653
|
plugin.configJson = config;
|
|
644
654
|
this.log.debug(`Saved config file ${configFile} for plugin ${plg}${plugin.name}${db}`);
|
|
645
655
|
}
|
|
@@ -649,10 +659,11 @@ export class PluginManager {
|
|
|
649
659
|
}
|
|
650
660
|
}
|
|
651
661
|
async loadSchema(plugin) {
|
|
662
|
+
const { promises } = await import('node:fs');
|
|
652
663
|
const schemaFile = plugin.path.replace('package.json', `${plugin.name}.schema.json`);
|
|
653
664
|
try {
|
|
654
|
-
await
|
|
655
|
-
const data = await
|
|
665
|
+
await promises.access(schemaFile);
|
|
666
|
+
const data = await promises.readFile(schemaFile, 'utf8');
|
|
656
667
|
const schema = JSON.parse(data);
|
|
657
668
|
schema.title = plugin.description;
|
|
658
669
|
schema.description = plugin.name + ' v. ' + plugin.version + ' by ' + plugin.author;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"files": {
|
|
3
3
|
"main.css": "./static/css/main.cf25d33e.css",
|
|
4
|
-
"main.js": "./static/js/main.
|
|
4
|
+
"main.js": "./static/js/main.257513e8.js",
|
|
5
5
|
"static/js/453.abd36b29.chunk.js": "./static/js/453.abd36b29.chunk.js",
|
|
6
6
|
"static/media/roboto-latin-700-normal.woff2": "./static/media/roboto-latin-700-normal.4535474e1cf8598695ad.woff2",
|
|
7
7
|
"static/media/roboto-latin-500-normal.woff2": "./static/media/roboto-latin-500-normal.7077203b1982951ecf76.woff2",
|
|
@@ -61,11 +61,11 @@
|
|
|
61
61
|
"static/media/roboto-greek-ext-400-normal.woff": "./static/media/roboto-greek-ext-400-normal.16eb83b4a3b1ea994243.woff",
|
|
62
62
|
"index.html": "./index.html",
|
|
63
63
|
"main.cf25d33e.css.map": "./static/css/main.cf25d33e.css.map",
|
|
64
|
-
"main.
|
|
64
|
+
"main.257513e8.js.map": "./static/js/main.257513e8.js.map",
|
|
65
65
|
"453.abd36b29.chunk.js.map": "./static/js/453.abd36b29.chunk.js.map"
|
|
66
66
|
},
|
|
67
67
|
"entrypoints": [
|
|
68
68
|
"static/css/main.cf25d33e.css",
|
|
69
|
-
"static/js/main.
|
|
69
|
+
"static/js/main.257513e8.js"
|
|
70
70
|
]
|
|
71
71
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
<!doctype html><html lang="en"><head><meta charset="utf-8"/><base href="./"><link rel="icon" href="./matterbridge 32x32.png"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><title>Matterbridge</title><link rel="manifest" href="./manifest.json"/><script defer="defer" src="./static/js/main.
|
|
1
|
+
<!doctype html><html lang="en"><head><meta charset="utf-8"/><base href="./"><link rel="icon" href="./matterbridge 32x32.png"/><meta name="viewport" content="width=device-width,initial-scale=1"/><meta name="theme-color" content="#000000"/><title>Matterbridge</title><link rel="manifest" href="./manifest.json"/><script defer="defer" src="./static/js/main.257513e8.js"></script><link href="./static/css/main.cf25d33e.css" rel="stylesheet"></head><body><noscript>You need to enable JavaScript to run this app.</noscript><div id="root"></div></body></html>
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" viewBox="0 0 296.2 296.2">
|
|
2
|
+
<defs>
|
|
3
|
+
<linearGradient id="lg1" x1="16.6" y1="16.6" x2="279.6" y2="279.6" gradientUnits="userSpaceOnUse">
|
|
4
|
+
<stop offset="0" stop-color="#00b48d" />
|
|
5
|
+
<stop offset=".1" stop-color="#3faa77" />
|
|
6
|
+
<stop offset=".3" stop-color="#234148" />
|
|
7
|
+
<stop offset=".7" stop-color="#203b44" />
|
|
8
|
+
<stop offset=".9" stop-color="#ad2e6e" />
|
|
9
|
+
<stop offset="1" stop-color="#c81b74" />
|
|
10
|
+
</linearGradient>
|
|
11
|
+
<linearGradient id="lg2" x1="31.1" y1="31.1" x2="265.1" y2="265.1" gradientUnits="userSpaceOnUse">
|
|
12
|
+
<stop offset="0" stop-color="#00b48d" />
|
|
13
|
+
<stop offset=".2" stop-color="#285251" />
|
|
14
|
+
<stop offset=".4" stop-color="#234148" />
|
|
15
|
+
<stop offset=".8" stop-color="#203b44" />
|
|
16
|
+
<stop offset=".9" stop-color="#a8316c" />
|
|
17
|
+
<stop offset="1" stop-color="#c81b74" />
|
|
18
|
+
</linearGradient>
|
|
19
|
+
<linearGradient id="lg3" x1="116.2" y1="143.9" x2="139.8" y2="143.9"
|
|
20
|
+
gradientUnits="userSpaceOnUse">
|
|
21
|
+
<stop offset="0" stop-color="#8bc751" />
|
|
22
|
+
<stop offset="1" stop-color="#0db14b" />
|
|
23
|
+
</linearGradient>
|
|
24
|
+
<linearGradient id="lg4" x1="136.1" y1="100.8" x2="159.6" y2="100.8"
|
|
25
|
+
xlink:href="#lg3" />
|
|
26
|
+
<linearGradient id="lg5" x1="155.3" y1="143.9" x2="178.9" y2="143.9"
|
|
27
|
+
xlink:href="#lg3" />
|
|
28
|
+
<linearGradient id="lg6" x1="46.8" y1="25.7" x2="89.6" y2="74.8" gradientUnits="userSpaceOnUse">
|
|
29
|
+
<stop offset="0" stop-color="#b1d34a" />
|
|
30
|
+
<stop offset="1" stop-color="#50b848" />
|
|
31
|
+
</linearGradient>
|
|
32
|
+
</defs>
|
|
33
|
+
<rect width="296.2" height="296.2" rx="56.7" ry="56.7" style="fill:url(#lg1)" />
|
|
34
|
+
<rect x="16.3" y="16.3" width="263.6" height="263.6" rx="50.5" ry="50.5" style="fill:url(#lg2)" />
|
|
35
|
+
<circle cx="128" cy="143.9" r="11.8" style="fill:url(#lg3)" />
|
|
36
|
+
<circle cx="147.8" cy="100.8" r="11.8" style="fill:url(#lg4)" />
|
|
37
|
+
<path
|
|
38
|
+
d="m244.6 114.5.4-.5L160 33a17 17 0 0 0-24.7-.5l-86.4 83.3a15 15 0 0 0 9.2 26.9h19.3v-4.7l-13.7-12.7v-.1l83.7-80.8 84.2 81-13.9 12.8v4.5h19.5a15 15 0 0 0 7.4-28.1Z"
|
|
39
|
+
style="fill:url(#lg3)" />
|
|
40
|
+
<circle cx="167.1" cy="143.9" r="11.8" style="fill:url(#lg5)" />
|
|
41
|
+
<path fill="#fff" d="M219 89.3V35.5a10.5 10.5 0 1 0-21 0v33.7l21 20Z" />
|
|
42
|
+
<path
|
|
43
|
+
d="M91.4 73.3H83a37 37 0 0 0-14.5-28.4L65 50.2c.1 0 12.6 9 11.7 25.4-5.3-.4-11.2-1.9-16.3-5.3-11.8-7.8-16-23.7-11.9-46 8.7 1.5 34 7 43 22.8 4.1 7.3 4.1 16.1 0 26.2Z"
|
|
44
|
+
style="fill:url(#lg6)" />
|
|
45
|
+
<path
|
|
46
|
+
d="M65.9 80a49.6 49.6 0 0 0 17.8 2.2l16.6-16c1.6-8.3.5-15.7-3.3-22.4C84.6 22 47.8 17.5 46.2 17.4l-3-.4-.6 3c-3.8 18.4-5.9 50.6 23.2 60ZM48.4 24.4c8.7 1.5 34 7 43 22.8 4.1 7.3 4.1 16.1 0 26.2H83a37 37 0 0 0-14.5-28.4l-3.7 5.3c.1 0 12.6 9 11.7 25.4-5.3-.4-11.2-1.9-16.3-5.3-11.9-7.8-16-23.7-11.9-46Z"
|
|
47
|
+
fill="#1e5857" />
|
|
48
|
+
<path fill="#fff"
|
|
49
|
+
d="M250.5 90.5a17.4 17.4 0 1 1 0-34.8 17.4 17.4 0 0 1 0 34.8Zm0-22.7a5.4 5.4 0 0 0 0 10.7 5.3 5.3 0 0 0 0-10.7ZM258.8 148.2a15.9 15.9 0 0 0-9.6 28.5c-.8 4.2-5.4 4.6-5.4 4.6h-26v-43l13.6-13-1.8-2-82.2-79-81.2 78.3-2.5 2.6 13.7 13v42.9H53a21.5 21.5 0 1 0 11.7 15h12.6v18.8c0 7.8 6.4 14.1 14.1 14.1h29.3v14.8H64a10.6 10.6 0 0 0-17.7 8 10.6 10.6 0 0 0 17.6 8h157.6a16.3 16.3 0 1 0 0-16h-84.8V229h66.8c7.8 0 14.2-6.3 14.2-14.1v-19.2h27.6c14.3 0 17.8-12.8 18.5-16.6a15.9 15.9 0 0 0-5-30.9ZM43.7 210.8a10.3 10.3 0 1 1 0-20.6 10.3 10.3 0 0 1 0 20.6Zm192 36a5 5 0 1 1 0 10 5 5 0 0 1 0-10Zm-77-34.8h-22v-34h22v34Zm8.4-79.8c2.7 0 5.2 1 7.2 2.5v-10.4L188 137s2.6 1.3 4.6 1.3h6.7v68c0 3.2-2.6 5.7-5.7 5.7h-19v-34h1.4a7.5 7.5 0 0 0 0-15H120a7.5 7.5 0 0 0 0 15h.7v34h-19.3a5.7 5.7 0 0 1-5.7-5.6v-68.1h6.7c2 0 4.6-1.3 4.6-1.3l13.7-12.7v10.4a11.7 11.7 0 0 1 16 1.6v-13a14.9 14.9 0 0 0-25-10.8s-.1.2-.1.2l-.5.5-6.9 7H92.5l55-53.2 55.1 53.2h-11.8l-7-7c0-.2-.2-.3-.4-.5l-.2-.2a14.8 14.8 0 0 0-25 10.9v12.9c2.2-2.5 5.3-4.1 8.9-4.1Zm91.7 36.7a4.9 4.9 0 1 1 0-9.7 4.9 4.9 0 0 1 0 9.7Z" />
|
|
50
|
+
</svg>
|