From f3d3d40c75f27b335beb884c7902dd50dbdc1bd2 Mon Sep 17 00:00:00 2001 From: per1234 Date: Mon, 27 Feb 2023 08:19:19 -0800 Subject: [PATCH 01/32] Bump version metadata post release On every startup, Arduino IDE checks for new versions of the IDE. If a newer version is available, a notification/dialog is shown offering an update. "Newer" is determined by comparing the version of the user's IDE to the latest available version on the update channel. This comparison is done according to the Semantic Versioning Specification ("SemVer"). In order to facilitate beta testing, builds are generated of the Arduino IDE at the current stage in development. These builds are given an identifying version of the following form: - -snapshot- - builds generated for every push and pull request that modifies relevant files - -nightly- - daily builds of the tip of the default branch In order to cause these builds to be correctly considered "newer" than the release version, the version metadata must be bumped immediately following each release. This will also serve as the metadata bump for the next release in the event that release is a minor release. In case it is instead a minor or major release, the version metadata will need to be updated once more before the release tag is created. --- arduino-ide-extension/package.json | 2 +- electron-app/package.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arduino-ide-extension/package.json b/arduino-ide-extension/package.json index dd2959470..ad52691c0 100644 --- a/arduino-ide-extension/package.json +++ b/arduino-ide-extension/package.json @@ -1,6 +1,6 @@ { "name": "arduino-ide-extension", - "version": "2.0.4", + "version": "2.0.5", "description": "An extension for Theia building the Arduino IDE", "license": "AGPL-3.0-or-later", "scripts": { diff --git a/electron-app/package.json b/electron-app/package.json index 0c210263f..1ffc8860b 100644 --- a/electron-app/package.json +++ b/electron-app/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "electron-app", - "version": "2.0.4", + "version": "2.0.5", "license": "AGPL-3.0-or-later", "main": "src-gen/frontend/electron-main.js", "dependencies": { @@ -21,7 +21,7 @@ "@theia/process": "1.31.1", "@theia/terminal": "1.31.1", "@theia/workspace": "1.31.1", - "arduino-ide-extension": "2.0.4" + "arduino-ide-extension": "2.0.5" }, "devDependencies": { "@theia/cli": "1.31.1", diff --git a/package.json b/package.json index 760e2a72d..8267afa70 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "arduino-ide", - "version": "2.0.4", + "version": "2.0.5", "description": "Arduino IDE", "repository": "https://github.com/arduino/arduino-ide.git", "author": "Arduino SA", From bfec85c352a9a889f29dcc6af7beb6cfbd35353b Mon Sep 17 00:00:00 2001 From: Akos Kitta Date: Mon, 27 Feb 2023 14:26:46 +0100 Subject: [PATCH 02/32] fix: no unnecessary tree update on mouse over/out Closes #1766 Signed-off-by: Akos Kitta --- .../src/browser/widgets/sketchbook/sketchbook-tree-widget.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-tree-widget.tsx b/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-tree-widget.tsx index 1c3323227..ece7a1a20 100644 --- a/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-tree-widget.tsx +++ b/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-tree-widget.tsx @@ -116,7 +116,6 @@ export class SketchbookTreeWidget extends FileTreeWidget { protected hoveredNodeId: string | undefined; protected setHoverNodeId(id: string | undefined): void { this.hoveredNodeId = id; - this.update(); } protected override createNodeAttributes( From 77213507fbdd9467439e28daf790e41aa953b53f Mon Sep 17 00:00:00 2001 From: Akos Kitta Date: Wed, 22 Feb 2023 16:11:09 +0100 Subject: [PATCH 03/32] fix: encoding when reading a cloud sketch Closes #449 Closes #634 Signed-off-by: Akos Kitta --- .../src/browser/create/create-api.ts | 48 ++----------------- .../src/browser/create/create-fs-provider.ts | 3 +- arduino-ide-extension/src/common/utils.ts | 11 +++++ 3 files changed, 16 insertions(+), 46 deletions(-) diff --git a/arduino-ide-extension/src/browser/create/create-api.ts b/arduino-ide-extension/src/browser/create/create-api.ts index 536e7f4bc..4c988f5df 100644 --- a/arduino-ide-extension/src/browser/create/create-api.ts +++ b/arduino-ide-extension/src/browser/create/create-api.ts @@ -2,6 +2,7 @@ import { MaybePromise } from '@theia/core/lib/common/types'; import { inject, injectable } from '@theia/core/shared/inversify'; import { fetch } from 'cross-fetch'; import { SketchesService } from '../../common/protocol'; +import { unit8ArrayToString } from '../../common/utils'; import { ArduinoPreferences } from '../arduino-preferences'; import { AuthenticationClientService } from '../auth/authentication-client-service'; import { SketchCache } from '../widgets/cloud-sketchbook/cloud-sketch-cache'; @@ -19,49 +20,6 @@ export namespace ResponseResultProvider { export const JSON: ResponseResultProvider = (response) => response.json(); } -// TODO: check if this is still needed: https://github.com/electron/electron/issues/18733 -// The original issue was reported for Electron 5.x and 6.x. Theia uses 15.x -export function Utf8ArrayToStr(array: Uint8Array): string { - let out, i, c; - let char2, char3; - - out = ''; - const len = array.length; - i = 0; - while (i < len) { - c = array[i++]; - switch (c >> 4) { - case 0: - case 1: - case 2: - case 3: - case 4: - case 5: - case 6: - case 7: - // 0xxxxxxx - out += String.fromCharCode(c); - break; - case 12: - case 13: - // 110x xxxx 10xx xxxx - char2 = array[i++]; - out += String.fromCharCode(((c & 0x1f) << 6) | (char2 & 0x3f)); - break; - case 14: - // 1110 xxxx 10xx xxxx 10xx xxxx - char2 = array[i++]; - char3 = array[i++]; - out += String.fromCharCode( - ((c & 0x0f) << 12) | ((char2 & 0x3f) << 6) | ((char3 & 0x3f) << 0) - ); - break; - } - } - - return out; -} - type ResourceType = 'f' | 'd'; @injectable() @@ -333,7 +291,7 @@ export class CreateApi { // parse the secret file const secrets = ( - typeof content === 'string' ? content : Utf8ArrayToStr(content) + typeof content === 'string' ? content : unit8ArrayToString(content) ) .split(/\r?\n/) .reduce((prev, curr) => { @@ -397,7 +355,7 @@ export class CreateApi { const headers = await this.headers(); let data: string = - typeof content === 'string' ? content : Utf8ArrayToStr(content); + typeof content === 'string' ? content : unit8ArrayToString(content); data = await this.toggleSecretsInclude(posixPath, data, 'remove'); const payload = { data: btoa(data) }; diff --git a/arduino-ide-extension/src/browser/create/create-fs-provider.ts b/arduino-ide-extension/src/browser/create/create-fs-provider.ts index 41ef5ab04..7908d0556 100644 --- a/arduino-ide-extension/src/browser/create/create-fs-provider.ts +++ b/arduino-ide-extension/src/browser/create/create-fs-provider.ts @@ -29,6 +29,7 @@ import { CreateUri } from './create-uri'; import { SketchesService } from '../../common/protocol'; import { ArduinoPreferences } from '../arduino-preferences'; import { Create } from './typings'; +import { stringToUint8Array } from '../../common/utils'; @injectable() export class CreateFsProvider @@ -154,7 +155,7 @@ export class CreateFsProvider async readFile(uri: URI): Promise { const content = await this.getCreateApi.readFile(uri.path.toString()); - return new TextEncoder().encode(content); + return stringToUint8Array(content); } async writeFile( diff --git a/arduino-ide-extension/src/common/utils.ts b/arduino-ide-extension/src/common/utils.ts index 3fbf98be9..994e02ec0 100644 --- a/arduino-ide-extension/src/common/utils.ts +++ b/arduino-ide-extension/src/common/utils.ts @@ -20,3 +20,14 @@ export function startsWithUpperCase(what: string): boolean { export function isNullOrUndefined(what: unknown): what is undefined | null { return what === undefined || what === null; } + +// Text encoder can crash in electron browser: https://github.com/arduino/arduino-ide/issues/634#issuecomment-1440039171 +export function unit8ArrayToString(uint8Array: Uint8Array): string { + return uint8Array.reduce( + (text, byte) => text + String.fromCharCode(byte), + '' + ); +} +export function stringToUint8Array(text: string): Uint8Array { + return Uint8Array.from(text, (char) => char.charCodeAt(0)); +} From fa9777e529b36c82a3a8bb9456782cb431c60f23 Mon Sep 17 00:00:00 2001 From: Akos Kitta Date: Fri, 3 Mar 2023 08:41:05 +0100 Subject: [PATCH 04/32] fix: scroll to the bottom after the state update Closes #1736 Signed-off-by: Akos Kitta --- .../serial/monitor/serial-monitor-send-output.tsx | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/arduino-ide-extension/src/browser/serial/monitor/serial-monitor-send-output.tsx b/arduino-ide-extension/src/browser/serial/monitor/serial-monitor-send-output.tsx index 136180202..12142f654 100644 --- a/arduino-ide-extension/src/browser/serial/monitor/serial-monitor-send-output.tsx +++ b/arduino-ide-extension/src/browser/serial/monitor/serial-monitor-send-output.tsx @@ -65,11 +65,13 @@ export class SerialMonitorOutput extends React.Component< this.state.charCount ); const [lines, charCount] = truncateLines(newLines, totalCharCount); - this.setState({ - lines, - charCount, - }); - this.scrollToBottom(); + this.setState( + { + lines, + charCount, + }, + () => this.scrollToBottom() + ); }), this.props.clearConsoleEvent(() => this.setState({ lines: [], charCount: 0 }) From 24dc0bbc88bcfd083e03b0c8601cffb08e8d5728 Mon Sep 17 00:00:00 2001 From: Akos Kitta Date: Fri, 3 Mar 2023 09:17:16 +0100 Subject: [PATCH 05/32] fix: update monitor output after widget show Closes #1724 Signed-off-by: Akos Kitta --- .../browser/serial/monitor/monitor-widget.tsx | 5 +++++ .../monitor/serial-monitor-send-output.tsx | 16 +++++++--------- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/arduino-ide-extension/src/browser/serial/monitor/monitor-widget.tsx b/arduino-ide-extension/src/browser/serial/monitor/monitor-widget.tsx index a5a25230c..ec83f5a0a 100644 --- a/arduino-ide-extension/src/browser/serial/monitor/monitor-widget.tsx +++ b/arduino-ide-extension/src/browser/serial/monitor/monitor-widget.tsx @@ -117,6 +117,11 @@ export class MonitorWidget extends ReactWidget { (this.focusNode || this.node).focus(); } + protected override onAfterShow(msg: Message): void { + super.onAfterShow(msg); + this.update(); + } + protected onFocusResolved = (element: HTMLElement | undefined) => { if (this.closing || !this.isAttached) { return; diff --git a/arduino-ide-extension/src/browser/serial/monitor/serial-monitor-send-output.tsx b/arduino-ide-extension/src/browser/serial/monitor/serial-monitor-send-output.tsx index 12142f654..2ddd2c565 100644 --- a/arduino-ide-extension/src/browser/serial/monitor/serial-monitor-send-output.tsx +++ b/arduino-ide-extension/src/browser/serial/monitor/serial-monitor-send-output.tsx @@ -17,7 +17,7 @@ export class SerialMonitorOutput extends React.Component< * Do not touch it. It is used to be able to "follow" the serial monitor log. */ protected toDisposeBeforeUnmount = new DisposableCollection(); - private listRef: React.RefObject; + private listRef: React.RefObject; constructor(props: Readonly) { super(props); @@ -34,12 +34,10 @@ export class SerialMonitorOutput extends React.Component< { + private readonly scrollToBottom = () => { if (this.listRef.current && this.props.monitorModel.autoscroll) { this.listRef.current.scrollToItem(this.state.lines.length, 'end'); } - }).bind(this); + }; } const _Row = ({ From fb10de1446c7d3ed93a7bb30a0404ffbdc01f4a3 Mon Sep 17 00:00:00 2001 From: Akos Kitta Date: Fri, 10 Mar 2023 13:55:34 +0100 Subject: [PATCH 06/32] fix: jsonc parsing in the IDE2 backend Occurred when `settings.json` contained comments or a trailing comma. Closes #1945 Signed-off-by: Akos Kitta --- arduino-ide-extension/package.json | 1 + .../src/node/arduino-daemon-impl.ts | 38 ++++--------- .../src/node/arduino-ide-backend-module.ts | 3 ++ .../src/node/settings-reader.ts | 53 +++++++++++++++++++ .../src/node/sketches-service-impl.ts | 33 ++---------- .../src/test/node/settings.reader.test.ts | 45 ++++++++++++++++ .../src/test/node/test-bindings.ts | 2 + 7 files changed, 118 insertions(+), 57 deletions(-) create mode 100644 arduino-ide-extension/src/node/settings-reader.ts create mode 100644 arduino-ide-extension/src/test/node/settings.reader.test.ts diff --git a/arduino-ide-extension/package.json b/arduino-ide-extension/package.json index ad52691c0..11a8a6a3f 100644 --- a/arduino-ide-extension/package.json +++ b/arduino-ide-extension/package.json @@ -78,6 +78,7 @@ "google-protobuf": "^3.20.1", "hash.js": "^1.1.7", "js-yaml": "^3.13.1", + "jsonc-parser": "^2.2.0", "just-diff": "^5.1.1", "jwt-decode": "^3.1.2", "keytar": "7.2.0", diff --git a/arduino-ide-extension/src/node/arduino-daemon-impl.ts b/arduino-ide-extension/src/node/arduino-daemon-impl.ts index 3f2480d07..ec0e0cc31 100644 --- a/arduino-ide-extension/src/node/arduino-daemon-impl.ts +++ b/arduino-ide-extension/src/node/arduino-daemon-impl.ts @@ -1,5 +1,4 @@ import { join } from 'path'; -import { promises as fs } from 'fs'; import { inject, injectable, named } from '@theia/core/shared/inversify'; import { spawn, ChildProcess } from 'child_process'; import { FileUri } from '@theia/core/lib/node/file-uri'; @@ -16,7 +15,7 @@ import { BackendApplicationContribution } from '@theia/core/lib/node/backend-app import { ArduinoDaemon, NotificationServiceServer } from '../common/protocol'; import { CLI_CONFIG } from './cli-config'; import { getExecPath } from './exec-util'; -import { ErrnoException } from './utils/errors'; +import { SettingsReader } from './settings-reader'; @injectable() export class ArduinoDaemonImpl @@ -32,6 +31,9 @@ export class ArduinoDaemonImpl @inject(NotificationServiceServer) private readonly notificationService: NotificationServiceServer; + @inject(SettingsReader) + private readonly settingsReader: SettingsReader; + private readonly toDispose = new DisposableCollection(); private readonly onDaemonStartedEmitter = new Emitter(); private readonly onDaemonStoppedEmitter = new Emitter(); @@ -149,34 +151,12 @@ export class ArduinoDaemonImpl } private async debugDaemon(): Promise { - // Poor man's preferences on the backend. (https://github.com/arduino/arduino-ide/issues/1056#issuecomment-1153975064) - const configDirUri = await this.envVariablesServer.getConfigDirUri(); - const configDirPath = FileUri.fsPath(configDirUri); - try { - const raw = await fs.readFile(join(configDirPath, 'settings.json'), { - encoding: 'utf8', - }); - const json = this.tryParse(raw); - if (json) { - const value = json['arduino.cli.daemon.debug']; - return typeof value === 'boolean' && !!value; - } - return false; - } catch (error) { - if (ErrnoException.isENOENT(error)) { - return false; - } - throw error; - } - } - - // eslint-disable-next-line @typescript-eslint/no-explicit-any - private tryParse(raw: string): any | undefined { - try { - return JSON.parse(raw); - } catch { - return undefined; + const settings = await this.settingsReader.read(); + if (settings) { + const value = settings['arduino.cli.daemon.debug']; + return value === true; } + return false; } protected async spawnDaemonProcess(): Promise<{ diff --git a/arduino-ide-extension/src/node/arduino-ide-backend-module.ts b/arduino-ide-extension/src/node/arduino-ide-backend-module.ts index 812761f77..5cd81f7c3 100644 --- a/arduino-ide-extension/src/node/arduino-ide-backend-module.ts +++ b/arduino-ide-extension/src/node/arduino-ide-backend-module.ts @@ -118,6 +118,7 @@ import { LocalDirectoryPluginDeployerResolverWithFallback, PluginDeployer_GH_12064, } from './theia/plugin-ext/plugin-deployer'; +import { SettingsReader } from './settings-reader'; export default new ContainerModule((bind, unbind, isBound, rebind) => { bind(BackendApplication).toSelf().inSingletonScope(); @@ -403,6 +404,8 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => { .toSelf() .inSingletonScope(); rebind(PluginDeployer).to(PluginDeployer_GH_12064).inSingletonScope(); + + bind(SettingsReader).toSelf().inSingletonScope(); }); function bindChildLogger(bind: interfaces.Bind, name: string): void { diff --git a/arduino-ide-extension/src/node/settings-reader.ts b/arduino-ide-extension/src/node/settings-reader.ts new file mode 100644 index 000000000..d6ab15811 --- /dev/null +++ b/arduino-ide-extension/src/node/settings-reader.ts @@ -0,0 +1,53 @@ +import { EnvVariablesServer } from '@theia/core/lib/common/env-variables'; +import { FileUri } from '@theia/core/lib/node/file-uri'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { promises as fs } from 'fs'; +import { + parse as parseJsonc, + ParseError, + printParseErrorCode, +} from 'jsonc-parser'; +import { join } from 'path'; +import { ErrnoException } from './utils/errors'; + +// Poor man's preferences on the backend. (https://github.com/arduino/arduino-ide/issues/1056#issuecomment-1153975064) +@injectable() +export class SettingsReader { + @inject(EnvVariablesServer) + private readonly envVariableServer: EnvVariablesServer; + + async read(): Promise | undefined> { + const configDirUri = await this.envVariableServer.getConfigDirUri(); + const configDirPath = FileUri.fsPath(configDirUri); + const settingsPath = join(configDirPath, 'settings.json'); + try { + const raw = await fs.readFile(settingsPath, { encoding: 'utf8' }); + return parse(raw); + } catch (err) { + if (ErrnoException.isENOENT(err)) { + return undefined; + } + } + } +} + +export function parse(raw: string): Record | undefined { + const errors: ParseError[] = []; + const settings = + parseJsonc(raw, errors, { + allowEmptyContent: true, + allowTrailingComma: true, + disallowComments: false, + }) ?? {}; + if (errors.length) { + console.error('Detected JSONC parser errors:'); + console.error('----- CONTENT START -----'); + console.error(raw); + console.error('----- CONTENT END -----'); + errors.forEach(({ error, offset }) => + console.error(` - ${printParseErrorCode(error)} at ${offset}`) + ); + return undefined; + } + return typeof settings === 'object' ? settings : undefined; +} diff --git a/arduino-ide-extension/src/node/sketches-service-impl.ts b/arduino-ide-extension/src/node/sketches-service-impl.ts index 42ca3e9a3..f4ff29db2 100644 --- a/arduino-ide-extension/src/node/sketches-service-impl.ts +++ b/arduino-ide-extension/src/node/sketches-service-impl.ts @@ -43,6 +43,7 @@ import { firstToUpperCase, startsWithUpperCase, } from '../common/utils'; +import { SettingsReader } from './settings-reader'; const RecentSketches = 'recent-sketches.json'; const DefaultIno = `void setup() { @@ -86,6 +87,9 @@ export class SketchesServiceImpl @inject(IsTempSketch) private readonly isTempSketch: IsTempSketch; + @inject(SettingsReader) + private readonly settingsReader: SettingsReader; + async getSketches({ uri }: { uri?: string }): Promise { const root = await this.root(uri); if (!root) { @@ -631,38 +635,11 @@ export class SketchesServiceImpl return crypto.createHash('md5').update(path).digest('hex').toUpperCase(); } - // Returns the default.ino from the settings or from default folder. - private async readSettings(): Promise | undefined> { - const configDirUri = await this.envVariableServer.getConfigDirUri(); - const configDirPath = FileUri.fsPath(configDirUri); - - try { - const raw = await fs.readFile(join(configDirPath, 'settings.json'), { - encoding: 'utf8', - }); - - return this.tryParse(raw); - } catch (err) { - if (ErrnoException.isENOENT(err)) { - return undefined; - } - throw err; - } - } - - private tryParse(raw: string): Record | undefined { - try { - return JSON.parse(raw); - } catch { - return undefined; - } - } - // Returns the default.ino from the settings or from default folder. private async loadInoContent(): Promise { if (!this.inoContent) { this.inoContent = new Deferred(); - const settings = await this.readSettings(); + const settings = await this.settingsReader.read(); if (settings) { const inoBlueprintPath = settings['arduino.sketch.inoBlueprint']; if (inoBlueprintPath && typeof inoBlueprintPath === 'string') { diff --git a/arduino-ide-extension/src/test/node/settings.reader.test.ts b/arduino-ide-extension/src/test/node/settings.reader.test.ts new file mode 100644 index 000000000..65e6b7a7e --- /dev/null +++ b/arduino-ide-extension/src/test/node/settings.reader.test.ts @@ -0,0 +1,45 @@ +import { expect } from 'chai'; +import { parse } from '../../node/settings-reader'; + +describe('settings-reader', () => { + describe('parse', () => { + it('should handle comments', () => { + const actual = parse(` +{ + "alma": "korte", + // comment + "szilva": false +}`); + expect(actual).to.be.deep.equal({ + alma: 'korte', + szilva: false, + }); + }); + + it('should handle trailing comma', () => { + const actual = parse(` +{ + "alma": "korte", + "szilva": 123, +}`); + expect(actual).to.be.deep.equal({ + alma: 'korte', + szilva: 123, + }); + }); + + it('should parse empty', () => { + const actual = parse(''); + expect(actual).to.be.deep.equal({}); + }); + + it('should parse to undefined when parse has failed', () => { + const actual = parse(` +{ + alma:: 'korte' + trash +}`); + expect(actual).to.be.undefined; + }); + }); +}); diff --git a/arduino-ide-extension/src/test/node/test-bindings.ts b/arduino-ide-extension/src/test/node/test-bindings.ts index 1aef2ff72..19b99f3a3 100644 --- a/arduino-ide-extension/src/test/node/test-bindings.ts +++ b/arduino-ide-extension/src/test/node/test-bindings.ts @@ -51,6 +51,7 @@ import { MonitorServiceFactory, MonitorServiceFactoryOptions, } from '../../node/monitor-service-factory'; +import { SettingsReader } from '../../node/settings-reader'; import { SketchesServiceImpl } from '../../node/sketches-service-impl'; import { EnvVariablesServer } from '../../node/theia/env-variables/env-variables-server'; @@ -277,6 +278,7 @@ export function createBaseContainer( bind(IsTempSketch).toSelf().inSingletonScope(); bind(SketchesServiceImpl).toSelf().inSingletonScope(); bind(SketchesService).toService(SketchesServiceImpl); + bind(SettingsReader).toSelf().inSingletonScope(); if (containerCustomizations) { containerCustomizations(bind, rebind); } From d398ed13455428c5f1bbd12bdb98151572014831 Mon Sep 17 00:00:00 2001 From: per1234 Date: Sun, 12 Mar 2023 17:40:36 -0700 Subject: [PATCH 07/32] Add bundled tools version check step to release procedure The Arduino IDE release includes several tool dependencies. Unstable versions of these tools may be pinned provisionally for use with the development version of Arduino IDE, but production releases of Arduino IDE must use production releases of the tool dependencies. The release manager should check the tool versions before making a release, but previously this step was not mentioned in the release procedure documentation. --- docs/internal/release-procedure.md | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/docs/internal/release-procedure.md b/docs/internal/release-procedure.md index 12afe0e26..fa043bf28 100644 --- a/docs/internal/release-procedure.md +++ b/docs/internal/release-procedure.md @@ -14,7 +14,15 @@ It will be shown in these search results: https://github.com/arduino/arduino-ide/pulls/app%2Fgithub-actions -### 2. 👀 Check version of packages +### 2. 🛠️ Check bundled tool versions + +The Arduino IDE release includes several tool dependencies. Unstable versions of these tools may be pinned provisionally for use with the development version of Arduino IDE, but production releases of Arduino IDE must use production releases of the tool dependencies. + +The tool versions are defined in the `arduino` object of [`arduino-ide-extension/package.json`](../../arduino-ide-extension/package.json). + +If any of the tools are pinned to a development version, ensure a suitable production release of the tool is available and then submit a PR to update the version in `arduino-ide-extension/package.json`. + +### 3. 👀 Check version of packages The [`version` field](https://docs.npmjs.com/cli/v8/configuring-npm/package-json#version) of the project's `package.json` metadata files received a patch version bump (e.g., `2.0.1` -> `2.0.2`) at the time of the previous release. @@ -31,7 +39,7 @@ If the version number of the previous release was `2.0.1`: - If this is considered a minor release (non-breaking changes to the "API"), the `version` values must be changed to `2.1.0`. - If this is considered a major release (breaking changes to the "API"), the `version` values must be changed to `3.0.0`. -### 3. 🚢 Create the release on GitHub +### 4. 🚢 Create the release on GitHub Then, you need to **create and push the new tag** and wait for the release to appear on [the "**Releases**" page](https://github.com/arduino/arduino-ide/releases). @@ -46,13 +54,13 @@ git push origin Pushing a tag will trigger a **GitHub Actions** workflow on the `main` branch. Check the "**Arduino IDE**" workflow and see that everything goes right. If the workflow succeeds, a new release will be created automatically and you should see it on the ["**Releases**"](https://github.com/arduino/arduino-ide/releases) page. -### 4. ⬆️ Bump version metadata of packages +### 5. ⬆️ Bump version metadata of packages In order for the version number of the tester and nightly builds to have correct precedence compared to the release version, the `version` field of the project's `package.json` files must be given a patch version bump (e.g., `2.0.1` -> `2.0.2`) **after** the creation of the release tag. Follow the instructions for updating the version metadata [**here**](#update-version-metadata). -### 5. 📄 Create the changelog +### 6. 📄 Create the changelog **Create GitHub issues for the known issues** that we haven't solved in the current release: @@ -71,7 +79,7 @@ Add a list of mentions of GitHub users who contributed to the release in any of Add a "**Known Issues**" section at the bottom of the changelog. -### 6. ✎ Update the "**Software**" Page +### 7. ✎ Update the "**Software**" Page Open a PR on the [bcmi-labs/wiki-content](https://github.com/bcmi-labs/wiki-content) repository to update the links and texts. @@ -88,7 +96,7 @@ When the deploy workflow is done, check if links on the "**Software**" page are https://www.arduino.cc/en/software#future-version-of-the-arduino-ide -### 7. 😎 Brag about it +### 8. 😎 Brag about it - Ask in the `#product_releases` **Slack** channel to write a post for the social media and, if needed, a blog post. - Post a message on the forum (ask @per1234).
From ec24b6813da2fcdd252ae4b05e31335d009e3094 Mon Sep 17 00:00:00 2001 From: Akos Kitta Date: Fri, 10 Mar 2023 13:07:25 +0100 Subject: [PATCH 08/32] fix: use text `--format` for the CLI `Can't write debug log: available only in text format` error is thrown by the CLI if the `--debug` flag is present. Ref: arduino/arduino-cli#2003 Closes #1942 Signed-off-by: Akos Kitta --- arduino-ide-extension/package.json | 6 +- .../src/node/arduino-daemon-impl.ts | 41 ++-- .../cli/commands/v1/commands_grpc_pb.js | 2 - .../arduino/cli/commands/v1/commands_pb.d.ts | 32 +++ .../cc/arduino/cli/commands/v1/commands_pb.js | 193 ++++++++++++++++++ .../cc/arduino/cli/commands/v1/core_pb.d.ts | 17 ++ .../cc/arduino/cli/commands/v1/core_pb.js | 123 +++++++++++ 7 files changed, 389 insertions(+), 25 deletions(-) diff --git a/arduino-ide-extension/package.json b/arduino-ide-extension/package.json index 11a8a6a3f..393eb1380 100644 --- a/arduino-ide-extension/package.json +++ b/arduino-ide-extension/package.json @@ -164,7 +164,11 @@ ], "arduino": { "cli": { - "version": "0.31.0" + "version": { + "owner": "arduino", + "repo": "arduino-cli", + "commitish": "6992de7" + } }, "fwuploader": { "version": "2.2.2" diff --git a/arduino-ide-extension/src/node/arduino-daemon-impl.ts b/arduino-ide-extension/src/node/arduino-daemon-impl.ts index ec0e0cc31..327544555 100644 --- a/arduino-ide-extension/src/node/arduino-daemon-impl.ts +++ b/arduino-ide-extension/src/node/arduino-daemon-impl.ts @@ -136,8 +136,6 @@ export class ArduinoDaemonImpl const cliConfigPath = join(FileUri.fsPath(configDirUri), CLI_CONFIG); const args = [ 'daemon', - '--format', - 'jsonmini', '--port', '0', '--config-file', @@ -177,26 +175,6 @@ export class ArduinoDaemonImpl daemon.stdout.on('data', (data) => { const message = data.toString(); - - let port = ''; - let address = ''; - message - .split('\n') - .filter((line: string) => line.length) - .forEach((line: string) => { - try { - const parsedLine = JSON.parse(line); - if ('Port' in parsedLine) { - port = parsedLine.Port; - } - if ('IP' in parsedLine) { - address = parsedLine.IP; - } - } catch (err) { - // ignore - } - }); - this.onData(message); if (!grpcServerIsReady) { const error = DaemonError.parse(message); @@ -205,6 +183,25 @@ export class ArduinoDaemonImpl return; } + let port = ''; + let address = ''; + message + .split('\n') + .filter((line: string) => line.length) + .forEach((line: string) => { + try { + const parsedLine = JSON.parse(line); + if ('Port' in parsedLine) { + port = parsedLine.Port; + } + if ('IP' in parsedLine) { + address = parsedLine.IP; + } + } catch (err) { + // ignore + } + }); + if (port.length && address.length) { grpcServerIsReady = true; ready.resolve({ daemon, port }); diff --git a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/commands_grpc_pb.js b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/commands_grpc_pb.js index 887ef6b04..49ec3d019 100644 --- a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/commands_grpc_pb.js +++ b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/commands_grpc_pb.js @@ -1333,5 +1333,3 @@ enumerateMonitorPortSettings: { }, }; -// BOOTSTRAP COMMANDS -// ------------------- diff --git a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/commands_pb.d.ts b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/commands_pb.d.ts index ecfeeb4ff..fc1c8b525 100644 --- a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/commands_pb.d.ts +++ b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/commands_pb.d.ts @@ -172,6 +172,31 @@ export namespace InitResponse { } +export class FailedInstanceInitError extends jspb.Message { + getReason(): FailedInstanceInitReason; + setReason(value: FailedInstanceInitReason): FailedInstanceInitError; + + getMessage(): string; + setMessage(value: string): FailedInstanceInitError; + + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): FailedInstanceInitError.AsObject; + static toObject(includeInstance: boolean, msg: FailedInstanceInitError): FailedInstanceInitError.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: FailedInstanceInitError, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): FailedInstanceInitError; + static deserializeBinaryFromReader(message: FailedInstanceInitError, reader: jspb.BinaryReader): FailedInstanceInitError; +} + +export namespace FailedInstanceInitError { + export type AsObject = { + reason: FailedInstanceInitReason, + message: string, + } +} + export class DestroyRequest extends jspb.Message { hasInstance(): boolean; @@ -528,3 +553,10 @@ export namespace ArchiveSketchResponse { export type AsObject = { } } + +export enum FailedInstanceInitReason { + FAILED_INSTANCE_INIT_REASON_UNSPECIFIED = 0, + FAILED_INSTANCE_INIT_REASON_INVALID_INDEX_URL = 1, + FAILED_INSTANCE_INIT_REASON_INDEX_LOAD_ERROR = 2, + FAILED_INSTANCE_INIT_REASON_TOOL_LOAD_ERROR = 3, +} diff --git a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/commands_pb.js b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/commands_pb.js index 9d688b4f4..62c15ec81 100644 --- a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/commands_pb.js +++ b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/commands_pb.js @@ -37,6 +37,8 @@ goog.exportSymbol('proto.cc.arduino.cli.commands.v1.CreateRequest', null, global goog.exportSymbol('proto.cc.arduino.cli.commands.v1.CreateResponse', null, global); goog.exportSymbol('proto.cc.arduino.cli.commands.v1.DestroyRequest', null, global); goog.exportSymbol('proto.cc.arduino.cli.commands.v1.DestroyResponse', null, global); +goog.exportSymbol('proto.cc.arduino.cli.commands.v1.FailedInstanceInitError', null, global); +goog.exportSymbol('proto.cc.arduino.cli.commands.v1.FailedInstanceInitReason', null, global); goog.exportSymbol('proto.cc.arduino.cli.commands.v1.InitRequest', null, global); goog.exportSymbol('proto.cc.arduino.cli.commands.v1.InitResponse', null, global); goog.exportSymbol('proto.cc.arduino.cli.commands.v1.InitResponse.MessageCase', null, global); @@ -156,6 +158,27 @@ if (goog.DEBUG && !COMPILED) { */ proto.cc.arduino.cli.commands.v1.InitResponse.Progress.displayName = 'proto.cc.arduino.cli.commands.v1.InitResponse.Progress'; } +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.cc.arduino.cli.commands.v1.FailedInstanceInitError = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.cc.arduino.cli.commands.v1.FailedInstanceInitError, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.cc.arduino.cli.commands.v1.FailedInstanceInitError.displayName = 'proto.cc.arduino.cli.commands.v1.FailedInstanceInitError'; +} /** * Generated by JsPbCodeGenerator. * @param {Array=} opt_data Optional initial data array, typically from a @@ -1398,6 +1421,166 @@ proto.cc.arduino.cli.commands.v1.InitResponse.prototype.hasProfile = function() +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.cc.arduino.cli.commands.v1.FailedInstanceInitError.prototype.toObject = function(opt_includeInstance) { + return proto.cc.arduino.cli.commands.v1.FailedInstanceInitError.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.cc.arduino.cli.commands.v1.FailedInstanceInitError} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.cc.arduino.cli.commands.v1.FailedInstanceInitError.toObject = function(includeInstance, msg) { + var f, obj = { + reason: jspb.Message.getFieldWithDefault(msg, 1, 0), + message: jspb.Message.getFieldWithDefault(msg, 2, "") + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.cc.arduino.cli.commands.v1.FailedInstanceInitError} + */ +proto.cc.arduino.cli.commands.v1.FailedInstanceInitError.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.cc.arduino.cli.commands.v1.FailedInstanceInitError; + return proto.cc.arduino.cli.commands.v1.FailedInstanceInitError.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.cc.arduino.cli.commands.v1.FailedInstanceInitError} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.cc.arduino.cli.commands.v1.FailedInstanceInitError} + */ +proto.cc.arduino.cli.commands.v1.FailedInstanceInitError.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + case 1: + var value = /** @type {!proto.cc.arduino.cli.commands.v1.FailedInstanceInitReason} */ (reader.readEnum()); + msg.setReason(value); + break; + case 2: + var value = /** @type {string} */ (reader.readString()); + msg.setMessage(value); + break; + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.cc.arduino.cli.commands.v1.FailedInstanceInitError.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.cc.arduino.cli.commands.v1.FailedInstanceInitError.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.cc.arduino.cli.commands.v1.FailedInstanceInitError} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.cc.arduino.cli.commands.v1.FailedInstanceInitError.serializeBinaryToWriter = function(message, writer) { + var f = undefined; + f = message.getReason(); + if (f !== 0.0) { + writer.writeEnum( + 1, + f + ); + } + f = message.getMessage(); + if (f.length > 0) { + writer.writeString( + 2, + f + ); + } +}; + + +/** + * optional FailedInstanceInitReason reason = 1; + * @return {!proto.cc.arduino.cli.commands.v1.FailedInstanceInitReason} + */ +proto.cc.arduino.cli.commands.v1.FailedInstanceInitError.prototype.getReason = function() { + return /** @type {!proto.cc.arduino.cli.commands.v1.FailedInstanceInitReason} */ (jspb.Message.getFieldWithDefault(this, 1, 0)); +}; + + +/** + * @param {!proto.cc.arduino.cli.commands.v1.FailedInstanceInitReason} value + * @return {!proto.cc.arduino.cli.commands.v1.FailedInstanceInitError} returns this + */ +proto.cc.arduino.cli.commands.v1.FailedInstanceInitError.prototype.setReason = function(value) { + return jspb.Message.setProto3EnumField(this, 1, value); +}; + + +/** + * optional string message = 2; + * @return {string} + */ +proto.cc.arduino.cli.commands.v1.FailedInstanceInitError.prototype.getMessage = function() { + return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 2, "")); +}; + + +/** + * @param {string} value + * @return {!proto.cc.arduino.cli.commands.v1.FailedInstanceInitError} returns this + */ +proto.cc.arduino.cli.commands.v1.FailedInstanceInitError.prototype.setMessage = function(value) { + return jspb.Message.setProto3StringField(this, 2, value); +}; + + + + + if (jspb.Message.GENERATE_TO_OBJECT) { /** * Creates an object representation of this proto. @@ -3699,4 +3882,14 @@ proto.cc.arduino.cli.commands.v1.ArchiveSketchResponse.serializeBinaryToWriter = }; +/** + * @enum {number} + */ +proto.cc.arduino.cli.commands.v1.FailedInstanceInitReason = { + FAILED_INSTANCE_INIT_REASON_UNSPECIFIED: 0, + FAILED_INSTANCE_INIT_REASON_INVALID_INDEX_URL: 1, + FAILED_INSTANCE_INIT_REASON_INDEX_LOAD_ERROR: 2, + FAILED_INSTANCE_INIT_REASON_TOOL_LOAD_ERROR: 3 +}; + goog.object.extend(exports, proto.cc.arduino.cli.commands.v1); diff --git a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/core_pb.d.ts b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/core_pb.d.ts index 30792fd12..dc8d8b97c 100644 --- a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/core_pb.d.ts +++ b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/core_pb.d.ts @@ -82,6 +82,23 @@ export namespace PlatformInstallResponse { } } +export class PlatformLoadingError extends jspb.Message { + + serializeBinary(): Uint8Array; + toObject(includeInstance?: boolean): PlatformLoadingError.AsObject; + static toObject(includeInstance: boolean, msg: PlatformLoadingError): PlatformLoadingError.AsObject; + static extensions: {[key: number]: jspb.ExtensionFieldInfo}; + static extensionsBinary: {[key: number]: jspb.ExtensionFieldBinaryInfo}; + static serializeBinaryToWriter(message: PlatformLoadingError, writer: jspb.BinaryWriter): void; + static deserializeBinary(bytes: Uint8Array): PlatformLoadingError; + static deserializeBinaryFromReader(message: PlatformLoadingError, reader: jspb.BinaryReader): PlatformLoadingError; +} + +export namespace PlatformLoadingError { + export type AsObject = { + } +} + export class PlatformDownloadRequest extends jspb.Message { hasInstance(): boolean; diff --git a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/core_pb.js b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/core_pb.js index 093656172..f1f3b7793 100644 --- a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/core_pb.js +++ b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/core_pb.js @@ -24,6 +24,7 @@ goog.exportSymbol('proto.cc.arduino.cli.commands.v1.PlatformInstallRequest', nul goog.exportSymbol('proto.cc.arduino.cli.commands.v1.PlatformInstallResponse', null, global); goog.exportSymbol('proto.cc.arduino.cli.commands.v1.PlatformListRequest', null, global); goog.exportSymbol('proto.cc.arduino.cli.commands.v1.PlatformListResponse', null, global); +goog.exportSymbol('proto.cc.arduino.cli.commands.v1.PlatformLoadingError', null, global); goog.exportSymbol('proto.cc.arduino.cli.commands.v1.PlatformSearchRequest', null, global); goog.exportSymbol('proto.cc.arduino.cli.commands.v1.PlatformSearchResponse', null, global); goog.exportSymbol('proto.cc.arduino.cli.commands.v1.PlatformUninstallRequest', null, global); @@ -72,6 +73,27 @@ if (goog.DEBUG && !COMPILED) { */ proto.cc.arduino.cli.commands.v1.PlatformInstallResponse.displayName = 'proto.cc.arduino.cli.commands.v1.PlatformInstallResponse'; } +/** + * Generated by JsPbCodeGenerator. + * @param {Array=} opt_data Optional initial data array, typically from a + * server response, or constructed directly in Javascript. The array is used + * in place and becomes part of the constructed object. It is not cloned. + * If no data is provided, the constructed object will be empty, but still + * valid. + * @extends {jspb.Message} + * @constructor + */ +proto.cc.arduino.cli.commands.v1.PlatformLoadingError = function(opt_data) { + jspb.Message.initialize(this, opt_data, 0, -1, null, null); +}; +goog.inherits(proto.cc.arduino.cli.commands.v1.PlatformLoadingError, jspb.Message); +if (goog.DEBUG && !COMPILED) { + /** + * @public + * @override + */ + proto.cc.arduino.cli.commands.v1.PlatformLoadingError.displayName = 'proto.cc.arduino.cli.commands.v1.PlatformLoadingError'; +} /** * Generated by JsPbCodeGenerator. * @param {Array=} opt_data Optional initial data array, typically from a @@ -809,6 +831,107 @@ proto.cc.arduino.cli.commands.v1.PlatformInstallResponse.prototype.hasTaskProgre +if (jspb.Message.GENERATE_TO_OBJECT) { +/** + * Creates an object representation of this proto. + * Field names that are reserved in JavaScript and will be renamed to pb_name. + * Optional fields that are not set will be set to undefined. + * To access a reserved field use, foo.pb_, eg, foo.pb_default. + * For the list of reserved names please see: + * net/proto2/compiler/js/internal/generator.cc#kKeyword. + * @param {boolean=} opt_includeInstance Deprecated. whether to include the + * JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @return {!Object} + */ +proto.cc.arduino.cli.commands.v1.PlatformLoadingError.prototype.toObject = function(opt_includeInstance) { + return proto.cc.arduino.cli.commands.v1.PlatformLoadingError.toObject(opt_includeInstance, this); +}; + + +/** + * Static version of the {@see toObject} method. + * @param {boolean|undefined} includeInstance Deprecated. Whether to include + * the JSPB instance for transitional soy proto support: + * http://goto/soy-param-migration + * @param {!proto.cc.arduino.cli.commands.v1.PlatformLoadingError} msg The msg instance to transform. + * @return {!Object} + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.cc.arduino.cli.commands.v1.PlatformLoadingError.toObject = function(includeInstance, msg) { + var f, obj = { + + }; + + if (includeInstance) { + obj.$jspbMessageInstance = msg; + } + return obj; +}; +} + + +/** + * Deserializes binary data (in protobuf wire format). + * @param {jspb.ByteSource} bytes The bytes to deserialize. + * @return {!proto.cc.arduino.cli.commands.v1.PlatformLoadingError} + */ +proto.cc.arduino.cli.commands.v1.PlatformLoadingError.deserializeBinary = function(bytes) { + var reader = new jspb.BinaryReader(bytes); + var msg = new proto.cc.arduino.cli.commands.v1.PlatformLoadingError; + return proto.cc.arduino.cli.commands.v1.PlatformLoadingError.deserializeBinaryFromReader(msg, reader); +}; + + +/** + * Deserializes binary data (in protobuf wire format) from the + * given reader into the given message object. + * @param {!proto.cc.arduino.cli.commands.v1.PlatformLoadingError} msg The message object to deserialize into. + * @param {!jspb.BinaryReader} reader The BinaryReader to use. + * @return {!proto.cc.arduino.cli.commands.v1.PlatformLoadingError} + */ +proto.cc.arduino.cli.commands.v1.PlatformLoadingError.deserializeBinaryFromReader = function(msg, reader) { + while (reader.nextField()) { + if (reader.isEndGroup()) { + break; + } + var field = reader.getFieldNumber(); + switch (field) { + default: + reader.skipField(); + break; + } + } + return msg; +}; + + +/** + * Serializes the message to binary data (in protobuf wire format). + * @return {!Uint8Array} + */ +proto.cc.arduino.cli.commands.v1.PlatformLoadingError.prototype.serializeBinary = function() { + var writer = new jspb.BinaryWriter(); + proto.cc.arduino.cli.commands.v1.PlatformLoadingError.serializeBinaryToWriter(this, writer); + return writer.getResultBuffer(); +}; + + +/** + * Serializes the given message to binary data (in protobuf wire + * format), writing to the given BinaryWriter. + * @param {!proto.cc.arduino.cli.commands.v1.PlatformLoadingError} message + * @param {!jspb.BinaryWriter} writer + * @suppress {unusedLocalVariables} f is only used for nested messages + */ +proto.cc.arduino.cli.commands.v1.PlatformLoadingError.serializeBinaryToWriter = function(message, writer) { + var f = undefined; +}; + + + + + if (jspb.Message.GENERATE_TO_OBJECT) { /** * Creates an object representation of this proto. From 58aac236bf51532313db1855298294348c0abeb0 Mon Sep 17 00:00:00 2001 From: per1234 Date: Sun, 12 Mar 2023 20:48:47 -0700 Subject: [PATCH 09/32] Allow leading underscore in sketch filenames The Arduino Sketch Specification defines the allowed format of sketch folder names and sketch code filenames. Arduino IDE enforces compliance with the specification in order to ensure sketches created with Arduino IDE can be used with any other Arduino development tool. The Arduino Sketch Specification has been changed to allow a leading underscore in sketch folder names and sketch code filenames so IDE's sketch name validation must be updated accordingly. --- .../src/common/protocol/sketches-service.ts | 20 ++++-------- .../test/browser/workspace-commands.test.ts | 10 +++--- .../src/test/common/sketches-service.test.ts | 32 ++++++++----------- i18n/en.json | 4 +-- 4 files changed, 27 insertions(+), 39 deletions(-) diff --git a/arduino-ide-extension/src/common/protocol/sketches-service.ts b/arduino-ide-extension/src/common/protocol/sketches-service.ts index df25a34f3..7953be720 100644 --- a/arduino-ide-extension/src/common/protocol/sketches-service.ts +++ b/arduino-ide-extension/src/common/protocol/sketches-service.ts @@ -157,8 +157,6 @@ export namespace Sketch { // (non-API) exported for the tests export const defaultSketchFolderName = 'sketch'; // (non-API) exported for the tests - export const defaultFallbackFirstChar = '0'; - // (non-API) exported for the tests export const defaultFallbackChar = '_'; // (non-API) exported for the tests export function reservedFilename(name: string): string { @@ -176,11 +174,11 @@ export namespace Sketch { // (non-API) exported for the tests export const invalidSketchFolderNameMessage = nls.localize( 'arduino/sketch/invalidSketchName', - 'The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.' + 'The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.' ); const invalidCloudSketchFolderNameMessage = nls.localize( 'arduino/sketch/invalidCloudSketchName', - 'The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.' + 'The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.' ); /** * `undefined` if the candidate sketch folder name is valid. Otherwise, the validation error message. @@ -193,7 +191,7 @@ export namespace Sketch { if (validFilenameError) { return validFilenameError; } - return /^[0-9a-zA-Z]{1}[0-9a-zA-Z_\.-]{0,62}$/.test(candidate) + return /^[0-9a-zA-Z_]{1}[0-9a-zA-Z_\.-]{0,62}$/.test(candidate) ? undefined : invalidSketchFolderNameMessage; } @@ -208,7 +206,7 @@ export namespace Sketch { if (validFilenameError) { return validFilenameError; } - return /^[0-9a-zA-Z]{1}[0-9a-zA-Z_\.-]{0,35}$/.test(candidate) + return /^[0-9a-zA-Z_]{1}[0-9a-zA-Z_\.-]{0,35}$/.test(candidate) ? undefined : invalidCloudSketchFolderNameMessage; } @@ -252,10 +250,7 @@ export namespace Sketch { return defaultSketchFolderName; } const validName = candidate - ? candidate - .replace(/^[^0-9a-zA-Z]{1}/g, defaultFallbackFirstChar) - .replace(/[^0-9a-zA-Z_]/g, defaultFallbackChar) - .slice(0, 63) + ? candidate.replace(/[^0-9a-zA-Z_]/g, defaultFallbackChar).slice(0, 63) : defaultSketchFolderName; if (appendTimestampSuffix) { return `${validName.slice(0, 63 - timestampSuffixLength)}${ @@ -283,10 +278,7 @@ export namespace Sketch { return defaultSketchFolderName; } return candidate - ? candidate - .replace(/^[^0-9a-zA-Z]{1}/g, defaultFallbackFirstChar) - .replace(/[^0-9a-zA-Z_]/g, defaultFallbackChar) - .slice(0, 36) + ? candidate.replace(/[^0-9a-zA-Z_]/g, defaultFallbackChar).slice(0, 36) : defaultSketchFolderName; } diff --git a/arduino-ide-extension/src/test/browser/workspace-commands.test.ts b/arduino-ide-extension/src/test/browser/workspace-commands.test.ts index 234515e76..0676ed77a 100644 --- a/arduino-ide-extension/src/test/browser/workspace-commands.test.ts +++ b/arduino-ide-extension/src/test/browser/workspace-commands.test.ts @@ -171,22 +171,22 @@ describe('workspace-commands', () => { }); it('code files cannot start with number (no extension)', async () => { - const actual = await testMe('_invalid'); + const actual = await testMe('-invalid'); expect(actual).to.be.equal(Sketch.invalidSketchFolderNameMessage); }); it('code files cannot start with number (trailing dot)', async () => { - const actual = await testMe('_invalid.'); + const actual = await testMe('-invalid.'); expect(actual).to.be.equal(Sketch.invalidSketchFolderNameMessage); }); it('code files cannot start with number (trailing dot)', async () => { - const actual = await testMe('_invalid.cpp'); + const actual = await testMe('-invalid.cpp'); expect(actual).to.be.equal(Sketch.invalidSketchFolderNameMessage); }); it('should warn about invalid extension first', async () => { - const actual = await testMe('_invalid.xxx'); + const actual = await testMe('-invalid.xxx'); expect(actual).to.be.equal(invalidExtensionMessage('.xxx')); }); @@ -196,7 +196,7 @@ describe('workspace-commands', () => { }); it('should ignore non-code filename validation from the spec', async () => { - const actual = await testMe('_invalid.json'); + const actual = await testMe('-invalid.json'); expect(actual).to.be.empty; }); diff --git a/arduino-ide-extension/src/test/common/sketches-service.test.ts b/arduino-ide-extension/src/test/common/sketches-service.test.ts index 917155e58..ae9f2481c 100644 --- a/arduino-ide-extension/src/test/common/sketches-service.test.ts +++ b/arduino-ide-extension/src/test/common/sketches-service.test.ts @@ -43,7 +43,7 @@ describe('sketch', () => { ['trailing.dots...', false], ['no.trailing.dots.._', true], ['No Spaces', false], - ['_invalidToStartWithUnderscore', false], + ['_validToStartWithUnderscore', true], ['Invalid+Char.ino', false], ['', false], ['/', false], @@ -81,7 +81,7 @@ describe('sketch', () => { ['can.contain.dots', true], ['-cannot-start-with-dash', false], ['.cannot.start.with.dash', false], - ['_cannot_start_with_underscore', false], + ['_can_start_with_underscore', true], ['No Spaces', false], ['Invalid+Char.ino', false], ['', false], @@ -108,14 +108,14 @@ describe('sketch', () => { describe('toValidSketchFolderName', () => { [ ['', Sketch.defaultSketchFolderName], - [' ', Sketch.defaultFallbackFirstChar], - [' ', Sketch.defaultFallbackFirstChar + Sketch.defaultFallbackChar], + [' ', Sketch.defaultFallbackChar], + [' ', Sketch.defaultFallbackChar + Sketch.defaultFallbackChar], [ '0123456789012345678901234567890123456789012345678901234567890123', '012345678901234567890123456789012345678901234567890123456789012', ], ['foo bar', 'foo_bar'], - ['_foobar', '0foobar'], + ['-foobar', '_foobar'], ['vAlid', 'vAlid'], ['COM1', Sketch.defaultSketchFolderName], ['COM1.', 'COM1_'], @@ -130,20 +130,18 @@ describe('sketch', () => { const epochSuffix = Sketch.timestampSuffix(epoch); [ ['', Sketch.defaultSketchFolderName + epochSuffix], - [' ', Sketch.defaultFallbackFirstChar + epochSuffix], + [' ', Sketch.defaultFallbackChar + epochSuffix], [ ' ', - Sketch.defaultFallbackFirstChar + - Sketch.defaultFallbackChar + - epochSuffix, + Sketch.defaultFallbackChar + Sketch.defaultFallbackChar + epochSuffix, ], [ '0123456789012345678901234567890123456789012345678901234567890123', '0123456789012345678901234567890123456789012' + epochSuffix, ], ['foo bar', 'foo_bar' + epochSuffix], - ['.foobar', '0foobar' + epochSuffix], - ['-fooBar', '0fooBar' + epochSuffix], + ['.foobar', '_foobar' + epochSuffix], + ['-fooBar', '_fooBar' + epochSuffix], ['foobar.', 'foobar_' + epochSuffix], ['fooBar-', 'fooBar_' + epochSuffix], ['fooBar+', 'fooBar_' + epochSuffix], @@ -164,19 +162,17 @@ describe('sketch', () => { ['only_underscore-is+ok.ino', 'only_underscore_is_ok_ino'], ['regex++', 'regex__'], ['dots...', 'dots___'], - ['.dots...', '0dots___'], - ['-dashes---', '0dashes___'], - ['_underscore___', '0underscore___'], + ['.dots...', '_dots___'], + ['-dashes---', '_dashes___'], ['No Spaces', 'No_Spaces'], - ['_startsWithUnderscore', '0startsWithUnderscore'], ['Invalid+Char.ino', 'Invalid_Char_ino'], ['', 'sketch'], - ['/', '0'], + ['/', '_'], [ '/-1////////////////////+//////////////-/', - '0_1_________________________________', + '__1_________________________________', ], - ['//trash/', '0_trash_'], + ['//trash/', '__trash_'], [ '63Length_012345678901234567890123456789012345678901234567890123', '63Length_012345678901234567890123456', diff --git a/i18n/en.json b/i18n/en.json index e02f7eeb4..b24a89cd4 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -419,11 +419,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "Export Compiled Binary", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "Moving", "movingMsg": "The file \"{0}\" needs to be inside a sketch folder named \"{1}\".\nCreate this folder, move the file, and continue?", "new": "New Sketch", From 2aad0e3b163f27c51b15b58a6f35aab757a643fb Mon Sep 17 00:00:00 2001 From: Akos Kitta Date: Wed, 1 Mar 2023 18:02:45 +0100 Subject: [PATCH 10/32] feat: new UX for the boards/library manager widgets Closes #19 Closes #781 Closes #1591 Closes #1607 Closes #1697 Closes #1707 Closes #1924 Closes #1941 Signed-off-by: Akos Kitta --- arduino-ide-extension/package.json | 2 - .../browser/arduino-ide-frontend-module.ts | 7 +- .../browser/boards/boards-auto-installer.ts | 2 +- .../src/browser/contributions/examples.ts | 130 ++- .../browser/library/library-list-widget.ts | 22 +- .../src/browser/menu/arduino-menus.ts | 16 +- .../browser/style/boards-config-dialog.css | 2 +- .../src/browser/style/dialogs.css | 6 +- .../src/browser/style/fonts.css | 5 + .../src/browser/style/ide-updater-dialog.css | 4 +- .../src/browser/style/index.css | 18 +- .../src/browser/style/list-widget.css | 166 +++- .../src/browser/style/main.css | 8 +- .../component-list/component-list-item.tsx | 90 +- .../widgets/component-list/component-list.tsx | 154 +--- .../filterable-list-container.tsx | 52 +- .../component-list/list-item-renderer.tsx | 858 +++++++++++++++--- .../widgets/component-list/list-widget.tsx | 43 +- .../src/common/protocol/arduino-component.ts | 33 +- .../src/common/protocol/examples-service.ts | 4 + .../src/common/protocol/installable.ts | 40 + .../src/common/protocol/library-service.ts | 14 +- .../src/node/examples-service-impl.ts | 10 + .../src/node/library-service-impl.ts | 10 +- .../src/test/browser/fixtures/boards.ts | 1 - .../src/test/common/installable.test.ts | 99 ++ i18n/en.json | 10 +- package.json | 4 - yarn.lock | 55 +- 29 files changed, 1385 insertions(+), 480 deletions(-) diff --git a/arduino-ide-extension/package.json b/arduino-ide-extension/package.json index 393eb1380..3cf6e2c6e 100644 --- a/arduino-ide-extension/package.json +++ b/arduino-ide-extension/package.json @@ -58,7 +58,6 @@ "@types/p-queue": "^2.3.1", "@types/ps-tree": "^1.1.0", "@types/react-tabs": "^2.3.2", - "@types/react-virtualized": "^9.21.21", "@types/temp": "^0.8.34", "@types/which": "^1.3.1", "@vscode/debugprotocol": "^1.51.0", @@ -96,7 +95,6 @@ "react-perfect-scrollbar": "^1.5.8", "react-select": "^5.6.0", "react-tabs": "^3.1.2", - "react-virtualized": "^9.22.3", "react-window": "^1.8.6", "semver": "^7.3.2", "string-natural-compare": "^2.0.3", diff --git a/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts b/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts index 7dd6fc1b9..73ed052e9 100644 --- a/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts +++ b/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts @@ -79,7 +79,10 @@ import { ProblemManager as TheiaProblemManager } from '@theia/markers/lib/browse import { ProblemManager } from './theia/markers/problem-manager'; import { BoardsAutoInstaller } from './boards/boards-auto-installer'; import { ShellLayoutRestorer } from './theia/core/shell-layout-restorer'; -import { ListItemRenderer } from './widgets/component-list/list-item-renderer'; +import { + ArduinoComponentContextMenuRenderer, + ListItemRenderer, +} from './widgets/component-list/list-item-renderer'; import { ColorContribution } from '@theia/core/lib/browser/color-application-contribution'; import { @@ -1021,4 +1024,6 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => { bind(SidebarBottomMenuWidget).toSelf(); rebind(TheiaSidebarBottomMenuWidget).toService(SidebarBottomMenuWidget); + + bind(ArduinoComponentContextMenuRenderer).toSelf().inSingletonScope(); }); diff --git a/arduino-ide-extension/src/browser/boards/boards-auto-installer.ts b/arduino-ide-extension/src/browser/boards/boards-auto-installer.ts index f516258f6..6d95ea661 100644 --- a/arduino-ide-extension/src/browser/boards/boards-auto-installer.ts +++ b/arduino-ide-extension/src/browser/boards/boards-auto-installer.ts @@ -174,7 +174,7 @@ export class BoardsAutoInstaller implements FrontendApplicationContribution { // CLI returns the packages already sorted with the deprecated ones at the end of the list // in order to ensure the new ones are preferred const candidates = packagesForBoard.filter( - ({ installable, installedVersion }) => installable && !installedVersion + ({ installedVersion }) => !installedVersion ); return candidates[0]; diff --git a/arduino-ide-extension/src/browser/contributions/examples.ts b/arduino-ide-extension/src/browser/contributions/examples.ts index a87c58860..02c19694d 100644 --- a/arduino-ide-extension/src/browser/contributions/examples.ts +++ b/arduino-ide-extension/src/browser/contributions/examples.ts @@ -1,6 +1,6 @@ import * as PQueue from 'p-queue'; import { inject, injectable } from '@theia/core/shared/inversify'; -import { CommandHandler } from '@theia/core/lib/common/command'; +import { CommandHandler, CommandService } from '@theia/core/lib/common/command'; import { MenuPath, CompositeMenuNode, @@ -11,7 +11,11 @@ import { DisposableCollection, } from '@theia/core/lib/common/disposable'; import { OpenSketch } from './open-sketch'; -import { ArduinoMenus, PlaceholderMenuNode } from '../menu/arduino-menus'; +import { + ArduinoMenus, + examplesLabel, + PlaceholderMenuNode, +} from '../menu/arduino-menus'; import { BoardsServiceProvider } from '../boards/boards-service-provider'; import { ExamplesService } from '../../common/protocol/examples-service'; import { @@ -25,11 +29,73 @@ import { SketchRef, SketchContainer, SketchesError, - Sketch, CoreService, + SketchesService, + Sketch, } from '../../common/protocol'; -import { nls } from '@theia/core/lib/common'; +import { nls } from '@theia/core/lib/common/nls'; import { unregisterSubmenu } from '../menu/arduino-menus'; +import { MaybePromise } from '@theia/core/lib/common/types'; +import { ApplicationError } from '@theia/core/lib/common/application-error'; + +/** + * Creates a cloned copy of the example sketch and opens it in a new window. + */ +export async function openClonedExample( + uri: string, + services: { + sketchesService: SketchesService; + commandService: CommandService; + }, + onError: { + onDidFailClone?: ( + err: ApplicationError< + number, + { + uri: string; + } + >, + uri: string + ) => MaybePromise; + onDidFailOpen?: ( + err: ApplicationError< + number, + { + uri: string; + } + >, + sketch: Sketch + ) => MaybePromise; + } = {} +): Promise { + const { sketchesService, commandService } = services; + const { onDidFailClone, onDidFailOpen } = onError; + try { + const sketch = await sketchesService.cloneExample(uri); + try { + await commandService.executeCommand( + OpenSketch.Commands.OPEN_SKETCH.id, + sketch + ); + } catch (openError) { + if (SketchesError.NotFound.is(openError)) { + if (onDidFailOpen) { + await onDidFailOpen(openError, sketch); + return; + } + } + throw openError; + } + } catch (cloneError) { + if (SketchesError.NotFound.is(cloneError)) { + if (onDidFailClone) { + await onDidFailClone(cloneError, uri); + return; + } + } + throw cloneError; + } +} @injectable() export abstract class Examples extends SketchContribution { @@ -94,7 +160,7 @@ export abstract class Examples extends SketchContribution { // TODO: unregister submenu? https://github.com/eclipse-theia/theia/issues/7300 registry.registerSubmenu( ArduinoMenus.FILE__EXAMPLES_SUBMENU, - nls.localize('arduino/examples/menu', 'Examples'), + examplesLabel, { order: '4', } @@ -174,47 +240,33 @@ export abstract class Examples extends SketchContribution { } protected createHandler(uri: string): CommandHandler { + const forceUpdate = () => + this.update({ + board: this.boardsServiceClient.boardsConfig.selectedBoard, + forceRefresh: true, + }); return { execute: async () => { - const sketch = await this.clone(uri); - if (sketch) { - try { - return this.commandService.executeCommand( - OpenSketch.Commands.OPEN_SKETCH.id, - sketch - ); - } catch (err) { - if (SketchesError.NotFound.is(err)) { + await openClonedExample( + uri, + { + sketchesService: this.sketchesService, + commandService: this.commandRegistry, + }, + { + onDidFailClone: () => { // Do not toast the error message. It's handled by the `Open Sketch` command. - this.update({ - board: this.boardsServiceClient.boardsConfig.selectedBoard, - forceRefresh: true, - }); - } else { - throw err; - } + forceUpdate(); + }, + onDidFailOpen: (err) => { + this.messageService.error(err.message); + forceUpdate(); + }, } - } + ); }, }; } - - private async clone(uri: string): Promise { - try { - const sketch = await this.sketchesService.cloneExample(uri); - return sketch; - } catch (err) { - if (SketchesError.NotFound.is(err)) { - this.messageService.error(err.message); - this.update({ - board: this.boardsServiceClient.boardsConfig.selectedBoard, - forceRefresh: true, - }); - } else { - throw err; - } - } - } } @injectable() diff --git a/arduino-ide-extension/src/browser/library/library-list-widget.ts b/arduino-ide-extension/src/browser/library/library-list-widget.ts index 4a0318d26..050783816 100644 --- a/arduino-ide-extension/src/browser/library/library-list-widget.ts +++ b/arduino-ide-extension/src/browser/library/library-list-widget.ts @@ -12,7 +12,10 @@ import { LibrarySearch, LibraryService, } from '../../common/protocol/library-service'; -import { ListWidget } from '../widgets/component-list/list-widget'; +import { + ListWidget, + UserAbortError, +} from '../widgets/component-list/list-widget'; import { Installable } from '../../common/protocol'; import { ListItemRenderer } from '../widgets/component-list/list-item-renderer'; import { nls } from '@theia/core/lib/common'; @@ -141,6 +144,8 @@ export class LibraryListWidget extends ListWidget< // All installDependencies = true; } + } else { + throw new UserAbortError(); } } else { // The lib does not have any dependencies. @@ -235,6 +240,21 @@ class MessageBoxDialog extends AbstractDialog { this.response = 0; super.handleEnter(event); } + + protected override onAfterAttach(message: Message): void { + super.onAfterAttach(message); + let buttonToFocus: HTMLButtonElement | undefined = undefined; + for (const child of Array.from(this.controlPanel.children)) { + if (child instanceof HTMLButtonElement) { + if (child.classList.contains('main')) { + buttonToFocus = child; + break; + } + buttonToFocus = child; + } + } + buttonToFocus?.focus(); + } } export namespace MessageBoxDialog { export interface Options extends DialogProps { diff --git a/arduino-ide-extension/src/browser/menu/arduino-menus.ts b/arduino-ide-extension/src/browser/menu/arduino-menus.ts index 18b52b32c..9ecfec550 100644 --- a/arduino-ide-extension/src/browser/menu/arduino-menus.ts +++ b/arduino-ide-extension/src/browser/menu/arduino-menus.ts @@ -1,4 +1,3 @@ -import { isOSX } from '@theia/core/lib/common/os'; import { CommonMenus } from '@theia/core/lib/browser/common-frontend-contribution'; import { MAIN_MENU_BAR, @@ -7,6 +6,8 @@ import { MenuPath, SubMenuOptions, } from '@theia/core/lib/common/menu'; +import { nls } from '@theia/core/lib/common/nls'; +import { isOSX } from '@theia/core/lib/common/os'; export namespace ArduinoMenus { // Main menu @@ -173,6 +174,17 @@ export namespace ArduinoMenus { '3_sign_out', ]; + // Context menu from the library and boards manager widget + export const ARDUINO_COMPONENT__CONTEXT = ['arduino-component--context']; + export const ARDUINO_COMPONENT__CONTEXT__INFO_GROUP = [ + ...ARDUINO_COMPONENT__CONTEXT, + '0_info', + ]; + export const ARDUINO_COMPONENT__CONTEXT__ACTION_GROUP = [ + ...ARDUINO_COMPONENT__CONTEXT, + '1_action', + ]; + // -- ROOT SSL CERTIFICATES export const ROOT_CERTIFICATES__CONTEXT = [ 'arduino-root-certificates--context', @@ -230,3 +242,5 @@ export class PlaceholderMenuNode implements MenuNode { return [...this.menuPath, 'placeholder'].join('-'); } } + +export const examplesLabel = nls.localize('arduino/examples/menu', 'Examples'); diff --git a/arduino-ide-extension/src/browser/style/boards-config-dialog.css b/arduino-ide-extension/src/browser/style/boards-config-dialog.css index 59633efb4..a7c474e8d 100644 --- a/arduino-ide-extension/src/browser/style/boards-config-dialog.css +++ b/arduino-ide-extension/src/browser/style/boards-config-dialog.css @@ -165,7 +165,7 @@ div#select-board-dialog .selectBoardContainer .list .item.selected i { border: 1px solid var(--theia-arduino-toolbar-dropdown-border); display: flex; gap: 10px; - height: 28px; + height: var(--arduino-button-height); margin: 0 4px; overflow: hidden; padding: 0 10px; diff --git a/arduino-ide-extension/src/browser/style/dialogs.css b/arduino-ide-extension/src/browser/style/dialogs.css index f48e7e25b..cb73abd60 100644 --- a/arduino-ide-extension/src/browser/style/dialogs.css +++ b/arduino-ide-extension/src/browser/style/dialogs.css @@ -12,7 +12,7 @@ min-width: 424px; max-height: 560px; - padding: 0 28px; + padding: 0 var(--arduino-button-height); } .p-Widget.dialogOverlay .dialogBlock .dialogTitle { @@ -35,7 +35,7 @@ } .p-Widget.dialogOverlay .dialogBlock .dialogContent > input { - margin-bottom: 28px; + margin-bottom: var(--arduino-button-height); } .p-Widget.dialogOverlay .dialogBlock .dialogContent > div { @@ -43,7 +43,7 @@ } .p-Widget.dialogOverlay .dialogBlock .dialogContent .dialogSection { - margin-top: 28px; + margin-top: var(--arduino-button-height); } .p-Widget.dialogOverlay .dialogBlock .dialogContent .dialogSection:first-child { margin-top: 0; diff --git a/arduino-ide-extension/src/browser/style/fonts.css b/arduino-ide-extension/src/browser/style/fonts.css index 2e243103e..65ab9f337 100644 --- a/arduino-ide-extension/src/browser/style/fonts.css +++ b/arduino-ide-extension/src/browser/style/fonts.css @@ -1,5 +1,10 @@ @font-face { font-family: 'Open Sans'; + src: url('fonts/OpenSans-Regular-webfont.woff') format('woff'); +} + +@font-face { + font-family: 'Open Sans Bold'; src: url('fonts/OpenSans-Bold-webfont.woff') format('woff'); } diff --git a/arduino-ide-extension/src/browser/style/ide-updater-dialog.css b/arduino-ide-extension/src/browser/style/ide-updater-dialog.css index abdf2eec6..5bd5fac44 100644 --- a/arduino-ide-extension/src/browser/style/ide-updater-dialog.css +++ b/arduino-ide-extension/src/browser/style/ide-updater-dialog.css @@ -15,7 +15,7 @@ } .ide-updater-dialog--logo-container { - margin-right: 28px; + margin-right: var(--arduino-button-height); } .ide-updater-dialog--logo { @@ -76,7 +76,7 @@ .ide-updater-dialog .buttons-container { display: flex; justify-content: flex-end; - margin-top: 28px; + margin-top: var(--arduino-button-height); } .ide-updater-dialog .buttons-container a.theia-button { diff --git a/arduino-ide-extension/src/browser/style/index.css b/arduino-ide-extension/src/browser/style/index.css index 6aa967304..d0ac1e45e 100644 --- a/arduino-ide-extension/src/browser/style/index.css +++ b/arduino-ide-extension/src/browser/style/index.css @@ -20,6 +20,10 @@ @import './progress-bar.css'; @import './settings-step-input.css'; +:root { + --arduino-button-height: 28px; +} + /* Revive of the `--theia-icon-loading`. The variable has been removed from Theia while IDE2 still uses is. */ /* The SVG icons are still part of Theia (1.31.1) */ /* https://github.com/arduino/arduino-ide/pull/1662#issuecomment-1324997134 */ @@ -64,9 +68,9 @@ body.theia-dark { /* Makes the sidepanel a bit wider when opening the widget */ .p-DockPanel-widget { - min-width: 200px; + min-width: 220px; min-height: 20px; - height: 200px; + height: 220px; } /* Overrule the default Theia CSS button styles. */ @@ -74,9 +78,9 @@ button.theia-button, .theia-button { align-items: center; display: flex; - font-family: 'Open Sans',sans-serif; + font-family: 'Open Sans Bold',sans-serif; font-style: normal; - font-weight: 700; + font-weight: 700; font-size: 14px; justify-content: center; cursor: pointer; @@ -95,7 +99,7 @@ button.theia-button, } button.theia-button { - height: 28px; + height: var(--arduino-button-height); max-width: none; } @@ -154,10 +158,6 @@ button.theia-button.message-box-dialog-button { font-size: 14px; } -.uppercase { - text-transform: uppercase; -} - /* High Contrast Theme rules */ /* TODO: Remove it when the Theia version is upgraded to 1.27.0 and use Theia APIs to implement it*/ .hc-black.hc-theia.theia-hc button.theia-button:hover, diff --git a/arduino-ide-extension/src/browser/style/list-widget.css b/arduino-ide-extension/src/browser/style/list-widget.css index c77820d6f..0ce86919c 100644 --- a/arduino-ide-extension/src/browser/style/list-widget.css +++ b/arduino-ide-extension/src/browser/style/list-widget.css @@ -44,102 +44,152 @@ height: 100%; /* This has top be 100% down to the `scrollContainer`. */ } -.filterable-list-container .items-container > div > div:nth-child(odd) { - background-color: var(--theia-sideBar-background); - filter: contrast(105%); +.component-list-item { + padding: 20px 15px 25px; } -.filterable-list-container .items-container > div > div:nth-child(even) { - background-color: var(--theia-sideBar-background); - filter: contrast(95%); +.component-list-item .header { + padding-bottom: 2px; + min-height: var(--theia-statusBar-height); } -.filterable-list-container .items-container > div > div:hover { - background-color: var(--theia-sideBar-background); - filter: contrast(90%); +.component-list-item .header > div { + display: flex; } -.component-list-item { - padding: 10px 10px 10px 15px; - font-size: var(--theia-ui-font-size1); +.component-list-item .header > div .p-TabBar-toolbar { + align-self: start; + padding: unset; + margin-right: unset; } -.component-list-item:hover { - cursor: pointer; +.component-list-item:hover .header > div .p-TabBar-toolbar > div { + visibility: visible; } -.component-list-item .header { - padding-bottom: 2px; - display: flex; - flex-direction: column; +.component-list-item .header > div .p-TabBar-toolbar > div { + visibility: hidden; +} + +.component-list-item .header .title { + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 2; + white-space: normal; + overflow: hidden; + text-overflow: ellipsis; + flex: 1 1 auto; } -.component-list-item .header .version-info { +.component-list-item .header .title .name { + font-family: 'Open Sans Bold'; + font-style: normal; + font-weight: 700; + font-size: 14px; +} + +.component-list-item .header .version { display: flex; justify-content: space-between; align-items: center; } -.component-list-item .header .name { - font-weight: bold; -} - .component-list-item .header .author { - font-weight: bold; color: var(--theia-panelTitle-inactiveForeground); } -.component-list-item:hover .header .author { - color: var(--theia-foreground); -} - .component-list-item .header .version { color: var(--theia-panelTitle-inactiveForeground); + padding-top: 4px; } .component-list-item .footer .theia-button.install { height: auto; /* resets the default Theia button height in the filterable list widget */ } -.component-list-item .header .installed:before { - margin-left: 4px; +.component-list-item .header .installed-version:before { + min-width: 79px; display: inline-block; justify-self: end; - background-color: var(--theia-button-background); + text-align: center; + background-color: var(--theia-arduino-toolbar-dropdown-option-backgroundHover); padding: 2px 4px 2px 4px; - font-size: 10px; - font-weight: bold; + font-size: 12px; max-height: calc(1em + 4px); - color: var(--theia-button-foreground); - content: attr(install); + color: var(--theia-button-background); + content: attr(version); + cursor: pointer; + border-radius: 4px; } -.component-list-item .header .installed:hover:before { - background-color: var(--theia-button-foreground); - color: var(--theia-button-background); - content: attr(uninstall); +.component-list-item .header .installed-version:hover:before { + content: attr(remove); + text-transform: uppercase; } -.component-list-item[min-width~="170px"] .footer { - padding: 5px 5px 0px 0px; - min-height: 35px; +.component-list-item .content { display: flex; - flex-direction: row-reverse; + flex-direction: column; + padding-top: 4px; + font-family: 'Open Sans'; + font-style: normal; + font-weight: 400; + font-size: 12px; +} + +.component-list-item .content > p { + margin-block-start: unset; + margin-block-end: unset; + + display: -webkit-box; + -webkit-box-orient: vertical; + -webkit-line-clamp: 3; + white-space: normal; + overflow: hidden; + text-overflow: ellipsis; +} + +.component-list-item .content > .info { + white-space: nowrap; } .component-list-item .footer { flex-direction: column-reverse; + padding-top: 8px; } .component-list-item .footer > * { display: inline-block; - margin: 5px 0px 0px 10px; +} + +.filterable-list-container .separator { + display: flex; + flex-direction: row; +} + +.filterable-list-container .separator :last-child, +.filterable-list-container .separator :first-child { + min-height: 8px; + max-height: 8px; + min-width: 8px; + max-width: 8px; +} + +div.filterable-list-container > div > div > div > div:nth-child(1) > div.separator :first-child, +div.filterable-list-container > div > div > div > div:nth-child(1) > div.separator :last-child { + display: none; +} + +.filterable-list-container .separator .line { + max-height: 1px; + height: 1px; + background-color: var(--theia-activityBar-inactiveForeground); + flex: 1 1 auto; } .component-list-item:hover .footer > label { display: inline-block; align-self: center; - margin: 5px 0px 0px 10px; } .component-list-item .info a { @@ -151,13 +201,33 @@ text-decoration: underline; } +.component-list-item .theia-button.secondary.no-border { + border: 2px solid var(--theia-button-foreground) +} + +.component-list-item .theia-button.secondary.no-border:hover { + border: 2px solid var(--theia-secondaryButton-foreground) +} + +.component-list-item .theia-button { + margin-left: 12px; +} + +.component-list-item .theia-select { + height: var(--arduino-button-height); + min-height: var(--arduino-button-height); + width: 65px; + min-width: 65px; +} + /* High Contrast Theme rules */ /* TODO: Remove it when the Theia version is upgraded to 1.27.0 and use Theia APIs to implement it*/ -.hc-black.hc-theia.theia-hc .component-list-item .header .installed:hover:before { +.hc-black.hc-theia.theia-hc .component-list-item .header .installed-version:hover:before { background-color: transparent; - outline: 1px dashed var(--theia-focusBorder); + outline: 1px dashed var(--theia-focusBorder); } -.hc-black.hc-theia.theia-hc .component-list-item .header .installed:before { +.hc-black.hc-theia.theia-hc .component-list-item .header .installed-version:before { + color: var(--theia-button-background); border: 1px solid var(--theia-button-border); } diff --git a/arduino-ide-extension/src/browser/style/main.css b/arduino-ide-extension/src/browser/style/main.css index 438277dee..fa98d63f3 100644 --- a/arduino-ide-extension/src/browser/style/main.css +++ b/arduino-ide-extension/src/browser/style/main.css @@ -28,8 +28,8 @@ display: flex; justify-content: center; align-items: center; - height: 28px; - width: 28px; + height: var(--arduino-button-height); + width: var(--arduino-button-height); } .p-TabBar-toolbar .item.arduino-tool-item .arduino-upload-sketch--toolbar, @@ -66,8 +66,8 @@ } .arduino-tool-icon { - height: 28px; - width: 28px; + height: var(--arduino-button-height); + width: var(--arduino-button-height); } .arduino-verify-sketch--toolbar-icon { diff --git a/arduino-ide-extension/src/browser/widgets/component-list/component-list-item.tsx b/arduino-ide-extension/src/browser/widgets/component-list/component-list-item.tsx index 121c01e03..83b0dea71 100644 --- a/arduino-ide-extension/src/browser/widgets/component-list/component-list-item.tsx +++ b/arduino-ide-extension/src/browser/widgets/component-list/component-list-item.tsx @@ -1,60 +1,76 @@ import * as React from '@theia/core/shared/react'; +import type { ArduinoComponent } from '../../../common/protocol/arduino-component'; import { Installable } from '../../../common/protocol/installable'; -import { ArduinoComponent } from '../../../common/protocol/arduino-component'; -import { ListItemRenderer } from './list-item-renderer'; +import type { ListItemRenderer } from './list-item-renderer'; +import { UserAbortError } from './list-widget'; export class ComponentListItem< T extends ArduinoComponent > extends React.Component, ComponentListItem.State> { constructor(props: ComponentListItem.Props) { super(props); - if (props.item.installable) { - const version = props.item.availableVersions.filter( - (version) => version !== props.item.installedVersion - )[0]; - this.state = { - selectedVersion: version, - }; - } + this.state = {}; } override render(): React.ReactNode { const { item, itemRenderer } = this.props; + const selectedVersion = + this.props.edited?.item.name === item.name + ? this.props.edited.selectedVersion + : this.latestVersion; return ( <> - {itemRenderer.renderItem( - Object.assign(this.state, { item }), - this.install.bind(this), - this.uninstall.bind(this), - this.onVersionChange.bind(this) - )} + {itemRenderer.renderItem({ + item, + selectedVersion, + inProgress: this.state.inProgress, + install: (item) => this.install(item), + uninstall: (item) => this.uninstall(item), + onVersionChange: (version) => this.onVersionChange(version), + })} ); } private async install(item: T): Promise { - const toInstall = this.state.selectedVersion; - const version = this.props.item.availableVersions.filter( - (version) => version !== this.state.selectedVersion - )[0]; - this.setState({ - selectedVersion: version, - }); - try { - await this.props.install(item, toInstall); - } catch { - this.setState({ - selectedVersion: toInstall, - }); - } + await this.withState('installing', () => + this.props.install( + item, + this.props.edited?.item.name === item.name + ? this.props.edited.selectedVersion + : Installable.latest(this.props.item.availableVersions) + ) + ); } private async uninstall(item: T): Promise { - await this.props.uninstall(item); + await this.withState('uninstalling', () => this.props.uninstall(item)); + } + + private async withState( + inProgress: 'installing' | 'uninstalling', + task: () => Promise + ): Promise { + this.setState({ inProgress }); + try { + await task(); + } catch (err) { + if (err instanceof UserAbortError) { + // No state update when user cancels the task + return; + } + throw err; + } finally { + this.setState({ inProgress: undefined }); + } } private onVersionChange(version: Installable.Version): void { - this.setState({ selectedVersion: version }); + this.props.onItemEdit(this.props.item, version); + } + + private get latestVersion(): Installable.Version | undefined { + return Installable.latest(this.props.item.availableVersions); } } @@ -63,10 +79,18 @@ export namespace ComponentListItem { readonly item: T; readonly install: (item: T, version?: Installable.Version) => Promise; readonly uninstall: (item: T) => Promise; + readonly edited?: { + item: T; + selectedVersion: Installable.Version; + }; + readonly onItemEdit: ( + item: T, + selectedVersion: Installable.Version + ) => void; readonly itemRenderer: ListItemRenderer; } export interface State { - selectedVersion?: Installable.Version; + inProgress?: 'installing' | 'uninstalling' | undefined; } } diff --git a/arduino-ide-extension/src/browser/widgets/component-list/component-list.tsx b/arduino-ide-extension/src/browser/widgets/component-list/component-list.tsx index 0f0dc9430..86f4d3df7 100644 --- a/arduino-ide-extension/src/browser/widgets/component-list/component-list.tsx +++ b/arduino-ide-extension/src/browser/widgets/component-list/component-list.tsx @@ -1,148 +1,32 @@ -import 'react-virtualized/styles.css'; import * as React from '@theia/core/shared/react'; -import AutoSizer from 'react-virtualized/dist/commonjs/AutoSizer'; -import { - CellMeasurer, - CellMeasurerCache, -} from 'react-virtualized/dist/commonjs/CellMeasurer'; -import type { - ListRowProps, - ListRowRenderer, -} from 'react-virtualized/dist/commonjs/List'; -import List from 'react-virtualized/dist/commonjs/List'; +import { Virtuoso } from '@theia/core/shared/react-virtuoso'; import { ArduinoComponent } from '../../../common/protocol/arduino-component'; import { Installable } from '../../../common/protocol/installable'; import { ComponentListItem } from './component-list-item'; import { ListItemRenderer } from './list-item-renderer'; -function sameAs( - left: T[], - right: T[], - ...compareProps: (keyof T)[] -): boolean { - if (left === right) { - return true; - } - const leftLength = left.length; - if (leftLength !== right.length) { - return false; - } - for (let i = 0; i < leftLength; i++) { - for (const prop of compareProps) { - const leftValue = left[i][prop]; - const rightValue = right[i][prop]; - if (leftValue !== rightValue) { - return false; - } - } - } - return true; -} - export class ComponentList extends React.Component< ComponentList.Props > { - private readonly cache: CellMeasurerCache; - private resizeAllFlag: boolean; - private list: List | undefined; - private mostRecentWidth: number | undefined; - - constructor(props: ComponentList.Props) { - super(props); - this.cache = new CellMeasurerCache({ - defaultHeight: 140, - fixedWidth: true, - }); - } - override render(): React.ReactNode { return ( - - {({ width, height }) => { - if (this.mostRecentWidth && this.mostRecentWidth !== width) { - this.resizeAllFlag = true; - setTimeout(() => this.clearAll(), 0); - } - this.mostRecentWidth = width; - return ( - ` won't be visible even if the mouse cursor is over the `
`. - // See https://github.com/bvaughn/react-virtualized/blob/005be24a608add0344284053dae7633be86053b2/source/Grid/Grid.js#L38-L42 - scrollingResetTimeInterval={0} - /> - ); - }} - - ); - } - - override componentDidUpdate(prevProps: ComponentList.Props): void { - if ( - this.resizeAllFlag || - !sameAs(this.props.items, prevProps.items, 'name', 'installedVersion') - ) { - this.clearAll(true); - } - } - - private readonly setListRef = (ref: List | null): void => { - this.list = ref || undefined; - }; - - private clearAll(scrollToTop = false): void { - this.resizeAllFlag = false; - this.cache.clearAll(); - if (this.list) { - this.list.recomputeRowHeights(); - if (scrollToTop) { - this.list.scrollToPosition(0); - } - } - } - - private readonly createItem: ListRowRenderer = ({ - index, - parent, - key, - style, - }: ListRowProps): React.ReactNode => { - const item = this.props.items[index]; - return ( - - {({ registerChild }) => ( - // eslint-disable-next-line @typescript-eslint/ban-ts-comment - // @ts-ignore -
- - key={this.props.itemLabel(item)} - item={item} - itemRenderer={this.props.itemRenderer} - install={this.props.install} - uninstall={this.props.uninstall} - /> -
+ ( + + key={this.props.itemLabel(item)} + item={item} + itemRenderer={this.props.itemRenderer} + install={this.props.install} + uninstall={this.props.uninstall} + edited={this.props.edited} + onItemEdit={this.props.onItemEdit} + /> )} -
+ /> ); - }; + } } - export namespace ComponentList { export interface Props { readonly items: T[]; @@ -150,5 +34,13 @@ export namespace ComponentList { readonly itemRenderer: ListItemRenderer; readonly install: (item: T, version?: Installable.Version) => Promise; readonly uninstall: (item: T) => Promise; + readonly edited?: { + item: T; + selectedVersion: Installable.Version; + }; + readonly onItemEdit: ( + item: T, + selectedVersion: Installable.Version + ) => void; } } diff --git a/arduino-ide-extension/src/browser/widgets/component-list/filterable-list-container.tsx b/arduino-ide-extension/src/browser/widgets/component-list/filterable-list-container.tsx index 07a1379ef..05e0e95be 100644 --- a/arduino-ide-extension/src/browser/widgets/component-list/filterable-list-container.tsx +++ b/arduino-ide-extension/src/browser/widgets/component-list/filterable-list-container.tsx @@ -15,6 +15,7 @@ import { ListItemRenderer } from './list-item-renderer'; import { ResponseServiceClient } from '../../../common/protocol'; import { nls } from '@theia/core/lib/common'; import { FilterRenderer } from './filter-renderer'; +import { DisposableCollection } from '@theia/core/lib/common/disposable'; export class FilterableListContainer< T extends ArduinoComponent, @@ -23,21 +24,30 @@ export class FilterableListContainer< FilterableListContainer.Props, FilterableListContainer.State > { + private readonly toDispose: DisposableCollection; + constructor(props: Readonly>) { super(props); this.state = { searchOptions: props.defaultSearchOptions, items: [], }; + this.toDispose = new DisposableCollection(); } override componentDidMount(): void { this.search = debounce(this.search, 500, { trailing: true }); this.search(this.state.searchOptions); - this.props.searchOptionsDidChange((newSearchOptions) => { - const { searchOptions } = this.state; - this.setSearchOptionsAndUpdate({ ...searchOptions, ...newSearchOptions }); - }); + this.toDispose.pushAll([ + this.props.searchOptionsDidChange((newSearchOptions) => { + const { searchOptions } = this.state; + this.setSearchOptionsAndUpdate({ + ...searchOptions, + ...newSearchOptions, + }); + }), + this.props.onDidShow(() => this.setState({ edited: undefined })), + ]); } override componentDidUpdate(): void { @@ -46,6 +56,10 @@ export class FilterableListContainer< this.props.container.updateScrollBar(); } + override componentWillUnmount(): void { + this.toDispose.dispose(); + } + override render(): React.ReactNode { return (
@@ -90,11 +104,13 @@ export class FilterableListContainer< itemRenderer={itemRenderer} install={this.install.bind(this)} uninstall={this.uninstall.bind(this)} + edited={this.state.edited} + onItemEdit={this.onItemEdit.bind(this)} /> ); } - protected handlePropChange = (prop: keyof S, value: S[keyof S]): void => { + private handlePropChange = (prop: keyof S, value: S[keyof S]): void => { const searchOptions = { ...this.state.searchOptions, [prop]: value, @@ -106,15 +122,14 @@ export class FilterableListContainer< this.setState({ searchOptions }, () => this.search(searchOptions)); } - protected search(searchOptions: S): void { + private search(searchOptions: S): void { const { searchable } = this.props; - searchable.search(searchOptions).then((items) => this.setState({ items })); + searchable + .search(searchOptions) + .then((items) => this.setState({ items, edited: undefined })); } - protected async install( - item: T, - version: Installable.Version - ): Promise { + private async install(item: T, version: Installable.Version): Promise { const { install, searchable } = this.props; await ExecuteWithProgress.doWithProgress({ ...this.props, @@ -124,10 +139,10 @@ export class FilterableListContainer< run: ({ progressId }) => install({ item, progressId, version }), }); const items = await searchable.search(this.state.searchOptions); - this.setState({ items }); + this.setState({ items, edited: undefined }); } - protected async uninstall(item: T): Promise { + private async uninstall(item: T): Promise { const ok = await new ConfirmDialog({ title: nls.localize('arduino/component/uninstall', 'Uninstall'), msg: nls.localize( @@ -152,7 +167,11 @@ export class FilterableListContainer< run: ({ progressId }) => uninstall({ item, progressId }), }); const items = await searchable.search(this.state.searchOptions); - this.setState({ items }); + this.setState({ items, edited: undefined }); + } + + private onItemEdit(item: T, selectedVersion: Installable.Version): void { + this.setState({ edited: { item, selectedVersion } }); } } @@ -171,6 +190,7 @@ export namespace FilterableListContainer { readonly searchOptionsDidChange: Event | undefined>; readonly messageService: MessageService; readonly responseService: ResponseServiceClient; + readonly onDidShow: Event; readonly install: ({ item, progressId, @@ -193,5 +213,9 @@ export namespace FilterableListContainer { export interface State { searchOptions: S; items: T[]; + edited?: { + item: T; + selectedVersion: Installable.Version; + }; } } diff --git a/arduino-ide-extension/src/browser/widgets/component-list/list-item-renderer.tsx b/arduino-ide-extension/src/browser/widgets/component-list/list-item-renderer.tsx index 4e6d56364..945b563dc 100644 --- a/arduino-ide-extension/src/browser/widgets/component-list/list-item-renderer.tsx +++ b/arduino-ide-extension/src/browser/widgets/component-list/list-item-renderer.tsx @@ -1,137 +1,783 @@ -import * as React from '@theia/core/shared/react'; -import { inject, injectable } from '@theia/core/shared/inversify'; +import { ApplicationError } from '@theia/core'; +import { + Anchor, + ContextMenuRenderer, +} from '@theia/core/lib/browser/context-menu-renderer'; +import { TabBarToolbar } from '@theia/core/lib/browser/shell/tab-bar-toolbar'; +import { codicon } from '@theia/core/lib/browser/widgets/widget'; import { WindowService } from '@theia/core/lib/browser/window/window-service'; -import { Installable } from '../../../common/protocol/installable'; -import { ArduinoComponent } from '../../../common/protocol/arduino-component'; -import { ComponentListItem } from './component-list-item'; -import { nls } from '@theia/core/lib/common'; +import { + CommandHandler, + CommandRegistry, + CommandService, +} from '@theia/core/lib/common/command'; +import { + Disposable, + DisposableCollection, +} from '@theia/core/lib/common/disposable'; +import { + MenuModelRegistry, + MenuPath, + SubMenuOptions, +} from '@theia/core/lib/common/menu'; +import { MessageService } from '@theia/core/lib/common/message-service'; +import { nls } from '@theia/core/lib/common/nls'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import * as React from '@theia/core/shared/react'; import { Unknown } from '../../../common/nls'; +import { + CoreService, + ExamplesService, + LibraryPackage, + Sketch, + SketchContainer, + SketchesService, + SketchRef, +} from '../../../common/protocol'; +import type { ArduinoComponent } from '../../../common/protocol/arduino-component'; +import { Installable } from '../../../common/protocol/installable'; +import { openClonedExample } from '../../contributions/examples'; +import { + ArduinoMenus, + examplesLabel, + unregisterSubmenu, +} from '../../menu/arduino-menus'; + +const moreInfoLabel = nls.localize('arduino/component/moreInfo', 'More info'); +const otherVersionsLabel = nls.localize( + 'arduino/component/otherVersions', + 'Other Versions' +); +const installLabel = nls.localize('arduino/component/install', 'Install'); +const installLatestLabel = nls.localize( + 'arduino/component/installLatest', + 'Install Latest' +); +function installVersionLabel(selectedVersion: string) { + return nls.localize( + 'arduino/component/installVersion', + 'Install {0}', + selectedVersion + ); +} +const updateLabel = nls.localize('arduino/component/update', 'Update'); +const removeLabel = nls.localize('arduino/component/remove', 'Remove'); +const byLabel = nls.localize('arduino/component/by', 'by'); +function nameAuthorLabel(name: string, author: string) { + return nls.localize('arduino/component/title', '{0} by {1}', name, author); +} +function installedLabel(installedVersion: string) { + return nls.localize( + 'arduino/component/installed', + '{0} installed', + installedVersion + ); +} +function clickToOpenInBrowserLabel(href: string): string | undefined { + return nls.localize( + 'arduino/component/clickToOpen', + 'Click to open in browser: {0}', + href + ); +} + +interface MenuTemplate { + readonly menuLabel: string; +} +interface MenuActionTemplate extends MenuTemplate { + readonly menuPath: MenuPath; + readonly handler: CommandHandler; + /** + * If not defined the insertion oder will be the order string. + */ + readonly order?: string; +} +interface SubmenuTemplate extends MenuTemplate { + readonly menuLabel: string; + readonly submenuPath: MenuPath; + readonly options?: SubMenuOptions; +} +function isMenuTemplate(arg: unknown): arg is MenuTemplate { + return ( + typeof arg === 'object' && + (arg as MenuTemplate).menuLabel !== undefined && + typeof (arg as MenuTemplate).menuLabel === 'string' + ); +} +function isMenuActionTemplate(arg: MenuTemplate): arg is MenuActionTemplate { + return ( + isMenuTemplate(arg) && + (arg as MenuActionTemplate).handler !== undefined && + typeof (arg as MenuActionTemplate).handler === 'object' && + (arg as MenuActionTemplate).menuPath !== undefined && + Array.isArray((arg as MenuActionTemplate).menuPath) + ); +} + +@injectable() +export class ArduinoComponentContextMenuRenderer { + @inject(CommandRegistry) + private readonly commandRegistry: CommandRegistry; + @inject(MenuModelRegistry) + private readonly menuRegistry: MenuModelRegistry; + @inject(ContextMenuRenderer) + private readonly contextMenuRenderer: ContextMenuRenderer; + + private readonly toDisposeBeforeRender = new DisposableCollection(); + private menuIndexCounter = 0; + + async render( + anchor: Anchor, + ...templates: (MenuActionTemplate | SubmenuTemplate)[] + ): Promise { + this.toDisposeBeforeRender.dispose(); + this.toDisposeBeforeRender.pushAll([ + Disposable.create(() => (this.menuIndexCounter = 0)), + ...templates.map((template) => this.registerMenu(template)), + ]); + const options = { + menuPath: ArduinoMenus.ARDUINO_COMPONENT__CONTEXT, + anchor, + showDisabled: true, + }; + this.contextMenuRenderer.render(options); + } + + private registerMenu( + template: MenuActionTemplate | SubmenuTemplate + ): Disposable { + if (isMenuActionTemplate(template)) { + const { menuLabel, menuPath, handler, order } = template; + const id = this.generateCommandId(menuLabel, menuPath); + const index = this.menuIndexCounter++; + return new DisposableCollection( + this.commandRegistry.registerCommand({ id }, handler), + this.menuRegistry.registerMenuAction(menuPath, { + commandId: id, + label: menuLabel, + order: typeof order === 'string' ? order : String(index).padStart(4), + }) + ); + } else { + const { menuLabel, submenuPath, options } = template; + return new DisposableCollection( + this.menuRegistry.registerSubmenu(submenuPath, menuLabel, options), + Disposable.create(() => + unregisterSubmenu(submenuPath, this.menuRegistry) + ) + ); + } + } + + private generateCommandId(menuLabel: string, menuPath: MenuPath): string { + return `arduino--component-context-${menuPath.join('-')}-${menuLabel}`; + } +} + +interface ListItemRendererParams { + readonly item: T; + readonly selectedVersion: Installable.Version | undefined; + readonly inProgress?: 'installing' | 'uninstalling' | undefined; + readonly install: (item: T) => Promise; + readonly uninstall: (item: T) => Promise; + readonly onVersionChange: (version: Installable.Version) => void; +} + +interface ListItemRendererServices { + readonly windowService: WindowService; + readonly messagesService: MessageService; + readonly commandService: CommandService; + readonly coreService: CoreService; + readonly examplesService: ExamplesService; + readonly sketchesService: SketchesService; + readonly contextMenuRenderer: ArduinoComponentContextMenuRenderer; +} @injectable() export class ListItemRenderer { @inject(WindowService) - protected windowService: WindowService; + private readonly windowService: WindowService; + @inject(MessageService) + private readonly messageService: MessageService; + @inject(CommandService) + private readonly commandService: CommandService; + @inject(CoreService) + private readonly coreService: CoreService; + @inject(ExamplesService) + private readonly examplesService: ExamplesService; + @inject(SketchesService) + private readonly sketchesService: SketchesService; + @inject(ArduinoComponentContextMenuRenderer) + private readonly contextMenuRenderer: ArduinoComponentContextMenuRenderer; - protected onMoreInfoClick = ( - event: React.SyntheticEvent - ): void => { - const { target } = event.nativeEvent; - if (target instanceof HTMLAnchorElement) { - this.windowService.openNewWindow(target.href, { external: true }); - event.nativeEvent.preventDefault(); + private readonly onMoreInfo = (href: string | undefined): void => { + if (href) { + this.windowService.openNewWindow(href, { external: true }); } }; - renderItem( - input: ComponentListItem.State & { item: T }, - install: (item: T) => Promise, - uninstall: (item: T) => Promise, - onVersionChange: (version: Installable.Version) => void - ): React.ReactNode { - const { item } = input; - let nameAndAuthor: JSX.Element; - if (item.name && item.author) { - const name = {item.name}; - const author = {item.author}; - nameAndAuthor = ( - - {name} {nls.localize('arduino/component/by', 'by')} {author} - + renderItem(params: ListItemRendererParams): React.ReactNode { + const action = this.action(params); + return ( + <> + +
+
+ +
+
+ + ); + } + + private action(params: ListItemRendererParams): Installable.Action { + const { + item: { installedVersion, availableVersions }, + selectedVersion, + } = params; + return Installable.action({ + installed: installedVersion, + available: availableVersions, + selected: selectedVersion, + }); + } + + private get services(): ListItemRendererServices { + return { + windowService: this.windowService, + messagesService: this.messageService, + commandService: this.commandService, + coreService: this.coreService, + sketchesService: this.sketchesService, + examplesService: this.examplesService, + contextMenuRenderer: this.contextMenuRenderer, + }; + } +} + +class Separator extends React.Component { + override render(): React.ReactNode { + return ( +
+
+
+
+
+ ); + } +} + +class Header extends React.Component< + Readonly<{ + params: ListItemRendererParams; + action: Installable.Action; + services: ListItemRendererServices; + onMoreInfo: (href: string | undefined) => void; + }> +> { + override render(): React.ReactNode { + return ( +
+
+ + <Toolbar {...this.props} /> + </div> + <InstalledVersion {...this.props} /> + </div> + ); + } +} + +class Toolbar<T extends ArduinoComponent> extends React.Component< + Readonly<{ + params: ListItemRendererParams<T>; + action: Installable.Action; + services: ListItemRendererServices; + onMoreInfo: (href: string | undefined) => void; + }> +> { + private readonly onClick = (event: React.MouseEvent): void => { + event.stopPropagation(); + event.preventDefault(); + const anchor = this.toAnchor(event); + this.showContextMenu(anchor); + }; + + override render(): React.ReactNode { + return ( + <div className={TabBarToolbar.Styles.TAB_BAR_TOOLBAR}> + <div className={`${TabBarToolbar.Styles.TAB_BAR_TOOLBAR_ITEM} enabled`}> + <div + id="__more__" + className={codicon('ellipsis', true)} + title={nls.localizeByDefault('More Actions...')} + onClick={this.onClick} + /> + </div> + </div> + ); + } + + private toAnchor(event: React.MouseEvent): Anchor { + const itemBox = event.currentTarget + .closest('.' + TabBarToolbar.Styles.TAB_BAR_TOOLBAR_ITEM) + ?.getBoundingClientRect(); + return itemBox + ? { + y: itemBox.bottom + itemBox.height / 2, + x: itemBox.left, + } + : event.nativeEvent; + } + + private async showContextMenu(anchor: Anchor): Promise<void> { + this.props.services.contextMenuRenderer.render( + anchor, + this.moreInfo, + ...(await this.examples), + ...this.otherVersions, + ...this.actions + ); + } + + private get moreInfo(): MenuActionTemplate { + const { + params: { + item: { moreInfoLink }, + }, + } = this.props; + return { + menuLabel: moreInfoLabel, + menuPath: ArduinoMenus.ARDUINO_COMPONENT__CONTEXT, + handler: { + execute: () => this.props.onMoreInfo(moreInfoLink), + isEnabled: () => Boolean(moreInfoLink), + }, + }; + } + + private get examples(): Promise<(MenuActionTemplate | SubmenuTemplate)[]> { + const { + params: { + item, + item: { installedVersion, name }, + }, + services: { examplesService }, + } = this.props; + // TODO: `LibraryPackage.is` should not be here but it saves one extra `lib list` + // gRPC equivalent call with the name of a platform which will result an empty array. + if (!LibraryPackage.is(item) || !installedVersion) { + return Promise.resolve([]); + } + const submenuPath = [ + ...ArduinoMenus.ARDUINO_COMPONENT__CONTEXT, + 'examples', + ]; + return examplesService.find({ libraryName: name }).then((containers) => [ + { + submenuPath, + menuLabel: examplesLabel, + options: { order: String(0) }, + }, + ...containers + .map((container) => this.flattenContainers(container, submenuPath)) + .reduce((acc, curr) => acc.concat(curr), []), + ]); + } + + private flattenContainers( + container: SketchContainer, + menuPath: MenuPath, + depth = 0 + ): (MenuActionTemplate | SubmenuTemplate)[] { + const templates: (MenuActionTemplate | SubmenuTemplate)[] = []; + const { label } = container; + if (depth > 0) { + menuPath = [...menuPath, label]; + templates.push({ + submenuPath: menuPath, + menuLabel: label, + options: { order: label.toLocaleLowerCase() }, + }); + } + return templates + .concat( + ...container.sketches.map((sketch) => + this.sketchToMenuTemplate(sketch, menuPath) + ) + ) + .concat( + container.children + .map((childContainer) => + this.flattenContainers(childContainer, menuPath, ++depth) + ) + .reduce((acc, curr) => acc.concat(curr), []) ); - } else if (item.name) { - nameAndAuthor = <span className="name">{item.name}</span>; - } else if ((item as any).id) { - nameAndAuthor = <span className="name">{(item as any).id}</span>; - } else { - nameAndAuthor = <span className="name">{Unknown}</span>; + } + + private sketchToMenuTemplate( + sketch: SketchRef, + menuPath: MenuPath + ): MenuActionTemplate { + const { name, uri } = sketch; + const { sketchesService, commandService } = this.props.services; + return { + menuLabel: name, + menuPath, + handler: { + execute: () => + openClonedExample( + uri, + { sketchesService, commandService }, + this.onExampleOpenError + ), + }, + order: name.toLocaleLowerCase(), + }; + } + + private get onExampleOpenError(): { + onDidFailClone: ( + err: ApplicationError<number, unknown>, + uri: string + ) => unknown; + onDidFailOpen: ( + err: ApplicationError<number, unknown>, + sketch: Sketch + ) => unknown; + } { + const { + services: { messagesService, coreService }, + } = this.props; + const handle = async (err: ApplicationError<number, unknown>) => { + messagesService.error(err.message); + return coreService.refresh(); + }; + return { + onDidFailClone: handle, + onDidFailOpen: handle, + }; + } + + private get otherVersions(): (MenuActionTemplate | SubmenuTemplate)[] { + const { + params: { + item: { availableVersions }, + selectedVersion, + onVersionChange, + }, + } = this.props; + const submenuPath = [ + ...ArduinoMenus.ARDUINO_COMPONENT__CONTEXT, + 'other-versions', + ]; + return [ + { + submenuPath, + menuLabel: otherVersionsLabel, + options: { order: String(1) }, + }, + ...availableVersions + .filter((version) => version !== selectedVersion) + .map((version) => ({ + menuPath: submenuPath, + menuLabel: version, + handler: { + execute: () => onVersionChange(version), + }, + })), + ]; + } + + private get actions(): MenuActionTemplate[] { + const { + action, + params: { + item, + item: { availableVersions, installedVersion }, + install, + uninstall, + selectedVersion, + }, + } = this.props; + const removeAction = { + menuLabel: removeLabel, + menuPath: ArduinoMenus.ARDUINO_COMPONENT__CONTEXT__ACTION_GROUP, + handler: { + execute: () => uninstall(item), + }, + }; + const installAction = { + menuLabel: installVersionLabel( + selectedVersion ?? Installable.latest(availableVersions) ?? '' + ), + menuPath: ArduinoMenus.ARDUINO_COMPONENT__CONTEXT__ACTION_GROUP, + handler: { + execute: () => install(item), + }, + }; + const installLatestAction = { + menuLabel: installLatestLabel, + menuPath: ArduinoMenus.ARDUINO_COMPONENT__CONTEXT__ACTION_GROUP, + handler: { + execute: () => install(item), + }, + }; + const updateAction = { + menuLabel: updateLabel, + menuPath: ArduinoMenus.ARDUINO_COMPONENT__CONTEXT__ACTION_GROUP, + handler: { + execute: () => install(item), + }, + }; + switch (action) { + case 'unknown': + return []; + case 'remove': { + return [removeAction]; + } + case 'update': { + return [removeAction, updateAction]; + } + case 'installLatest': + return [ + ...(Boolean(installedVersion) ? [removeAction] : []), + installLatestAction, + ]; + case 'installSelected': { + return [ + ...(Boolean(installedVersion) ? [removeAction] : []), + installAction, + ]; + } } - const onClickUninstall = () => uninstall(item); - const installedVersion = !!item.installedVersion && ( - <div className="version-info"> - <span className="version"> - {nls.localize( - 'arduino/component/version', - 'Version {0}', - item.installedVersion - )} - </span> - <span - className="installed uppercase" - onClick={onClickUninstall} - {...{ - install: nls.localize('arduino/component/installed', 'Installed'), - uninstall: nls.localize('arduino/component/uninstall', 'Uninstall'), - }} - /> + } +} + +class Title<T extends ArduinoComponent> extends React.Component< + Readonly<{ + params: ListItemRendererParams<T>; + }> +> { + override render(): React.ReactNode { + const { name, author } = this.props.params.item; + const title = + name && author ? nameAuthorLabel(name, author) : name ? name : Unknown; + return ( + <div className="title" title={title}> + {name && author ? ( + <> + {<span className="name">{name}</span>}{' '} + {<span className="author">{`${byLabel} ${author}`}</span>} + </> + ) : name ? ( + <span className="name">{name}</span> + ) : ( + <span className="name">{Unknown}</span> + )} </div> ); + } +} - const summary = <div className="summary">{item.summary}</div>; - const description = <div className="summary">{item.description}</div>; +class InstalledVersion<T extends ArduinoComponent> extends React.Component< + Readonly<{ + params: ListItemRendererParams<T>; + }> +> { + private readonly onClick = (): void => { + this.props.params.uninstall(this.props.params.item); + }; - const moreInfo = !!item.moreInfoLink && ( - <a href={item.moreInfoLink} onClick={this.onMoreInfoClick}> - {nls.localize('arduino/component/moreInfo', 'More info')} - </a> + override render(): React.ReactNode { + const { installedVersion } = this.props.params.item; + return ( + installedVersion && ( + <div className="version"> + <span + className="installed-version" + onClick={this.onClick} + {...{ + version: installedLabel(installedVersion), + remove: removeLabel, + }} + /> + </div> + ) ); - const onClickInstall = () => install(item); - const installButton = item.installable && ( - <button - className="theia-button secondary install uppercase" - onClick={onClickInstall} - > - {nls.localize('arduino/component/install', 'Install')} - </button> + } +} + +class Content<T extends ArduinoComponent> extends React.Component< + Readonly<{ + params: ListItemRendererParams<T>; + onMoreInfo: (href: string | undefined) => void; + }> +> { + override render(): React.ReactNode { + const { + params: { + item: { summary, description }, + }, + } = this.props; + const content = [summary, description].filter(Boolean).join(' '); + return ( + <div className="content" title={content}> + <p>{content}</p> + <MoreInfo {...this.props} /> + </div> ); + } +} - const onSelectChange = (event: React.ChangeEvent<HTMLSelectElement>) => { - const version = event.target.value; - if (version) { - onVersionChange(version); - } - }; +class MoreInfo<T extends ArduinoComponent> extends React.Component< + Readonly<{ + params: ListItemRendererParams<T>; + onMoreInfo: (href: string | undefined) => void; + }> +> { + private readonly onClick = ( + event: React.SyntheticEvent<HTMLAnchorElement, Event> + ): void => { + const { target } = event.nativeEvent; + if (target instanceof HTMLAnchorElement) { + this.props.onMoreInfo(target.href); + event.nativeEvent.preventDefault(); + } + }; - const versions = (() => { - const { availableVersions } = item; - if (availableVersions.length === 0) { - return undefined; - } else if (availableVersions.length === 1) { - return <label>{availableVersions[0]}</label>; - } else { + override render(): React.ReactNode { + const { + params: { + item: { moreInfoLink: href }, + }, + } = this.props; + return ( + href && ( + <div className="info" title={clickToOpenInBrowserLabel(href)}> + <a href={href} onClick={this.onClick}> + {moreInfoLabel} + </a> + </div> + ) + ); + } +} + +class Footer<T extends ArduinoComponent> extends React.Component< + Readonly<{ + params: ListItemRendererParams<T>; + action: Installable.Action; + }> +> { + override render(): React.ReactNode { + return ( + <div className="footer"> + <SelectVersion {...this.props} /> + <Button {...this.props} /> + </div> + ); + } +} + +class SelectVersion<T extends ArduinoComponent> extends React.Component< + Readonly<{ + params: ListItemRendererParams<T>; + action: Installable.Action; + }> +> { + private readonly onChange = ( + event: React.ChangeEvent<HTMLSelectElement> + ): void => { + const version = event.target.value; + if (version) { + this.props.params.onVersionChange(version); + } + }; + + override render(): React.ReactNode { + const { + selectedVersion, + item: { availableVersions }, + } = this.props.params; + switch (this.props.action) { + case 'installLatest': // fall-through + case 'installSelected': // fall-through + case 'update': // fall-through + case 'remove': return ( <select className="theia-select" - value={input.selectedVersion} - onChange={onSelectChange} + value={selectedVersion} + onChange={this.onChange} > - {item.availableVersions - .filter((version) => version !== item.installedVersion) // Filter the version that is currently installed. - .map((version) => ( - <option value={version} key={version}> - {version} - </option> - ))} + {availableVersions.map((version) => ( + <option value={version} key={version}> + {version} + </option> + ))} </select> ); - } - })(); + case 'unknown': + return undefined; + } + } +} +class Button<T extends ArduinoComponent> extends React.Component< + Readonly<{ + params: ListItemRendererParams<T>; + action: Installable.Action; + }> +> { + override render(): React.ReactNode { + const { + params: { item, install, uninstall, inProgress: state }, + } = this.props; + const classNames = ['theia-button install uppercase']; + let onClick; + let label; + switch (this.props.action) { + case 'unknown': + return undefined; + case 'installLatest': { + classNames.push('primary'); + label = installLabel; + onClick = () => install(item); + break; + } + case 'installSelected': { + classNames.push('secondary'); + label = installLabel; + onClick = () => install(item); + break; + } + case 'update': { + classNames.push('secondary'); + label = updateLabel; + onClick = () => install(item); + break; + } + case 'remove': { + classNames.push('secondary', 'no-border'); + label = removeLabel; + onClick = () => uninstall(item); + break; + } + } return ( - <div className="component-list-item noselect"> - <div className="header"> - {nameAndAuthor} - {installedVersion} - </div> - <div className="content"> - {summary} - {description} - </div> - <div className="info">{moreInfo}</div> - <div className="footer"> - {versions} - {installButton} - </div> - </div> + <button + className={classNames.join(' ')} + onClick={onClick} + disabled={Boolean(state)} + > + {label} + </button> ); } } diff --git a/arduino-ide-extension/src/browser/widgets/component-list/list-widget.tsx b/arduino-ide-extension/src/browser/widgets/component-list/list-widget.tsx index a6cf5ffbf..ca340a01f 100644 --- a/arduino-ide-extension/src/browser/widgets/component-list/list-widget.tsx +++ b/arduino-ide-extension/src/browser/widgets/component-list/list-widget.tsx @@ -29,29 +29,27 @@ export abstract class ListWidget< > extends ReactWidget { @inject(MessageService) protected readonly messageService: MessageService; - - @inject(CommandService) - protected readonly commandService: CommandService; - - @inject(ResponseServiceClient) - protected readonly responseService: ResponseServiceClient; - @inject(NotificationCenter) protected readonly notificationCenter: NotificationCenter; + @inject(CommandService) + private readonly commandService: CommandService; + @inject(ResponseServiceClient) + private readonly responseService: ResponseServiceClient; /** * Do not touch or use it. It is for setting the focus on the `input` after the widget activation. */ - protected focusNode: HTMLElement | undefined; + private focusNode: HTMLElement | undefined; private readonly didReceiveFirstFocus = new Deferred(); - protected readonly searchOptionsChangeEmitter = new Emitter< + private readonly searchOptionsChangeEmitter = new Emitter< Partial<S> | undefined >(); + private readonly onDidShowEmitter = new Emitter<void>(); /** * Instead of running an `update` from the `postConstruct` `init` method, * we use this variable to track first activate, then run. */ - protected firstActivate = true; + private firstUpdate = true; constructor(protected options: ListWidget.Options<T, S>) { super(); @@ -64,7 +62,10 @@ export abstract class ListWidget< this.addClass('arduino-list-widget'); this.node.tabIndex = 0; // To be able to set the focus on the widget. this.scrollOptions = undefined; - this.toDispose.push(this.searchOptionsChangeEmitter); + this.toDispose.pushAll([ + this.searchOptionsChangeEmitter, + this.onDidShowEmitter, + ]); } @postConstruct() @@ -81,12 +82,14 @@ export abstract class ListWidget< protected override onAfterShow(message: Message): void { this.maybeUpdateOnFirstRender(); super.onAfterShow(message); + this.onDidShowEmitter.fire(); } private maybeUpdateOnFirstRender() { - if (this.firstActivate) { - this.firstActivate = false; + if (this.firstUpdate) { + this.firstUpdate = false; this.update(); + this.didReceiveFirstFocus.promise.then(() => this.focusNode?.focus()); } } @@ -106,7 +109,9 @@ export abstract class ListWidget< this.updateScrollBar(); } - protected onFocusResolved = (element: HTMLElement | undefined): void => { + private readonly onFocusResolved = ( + element: HTMLElement | undefined + ): void => { this.focusNode = element; this.didReceiveFirstFocus.resolve(); }; @@ -133,7 +138,7 @@ export abstract class ListWidget< return this.options.installable.uninstall({ item, progressId }); } - render(): React.ReactNode { + override render(): React.ReactNode { return ( <FilterableListContainer<T, S> defaultSearchOptions={this.options.defaultSearchOptions} @@ -149,6 +154,7 @@ export abstract class ListWidget< messageService={this.messageService} commandService={this.commandService} responseService={this.responseService} + onDidShow={this.onDidShowEmitter.event} /> ); } @@ -186,3 +192,10 @@ export namespace ListWidget { readonly defaultSearchOptions: S; } } + +export class UserAbortError extends Error { + constructor(message = 'User abort') { + super(message); + Object.setPrototypeOf(this, UserAbortError.prototype); + } +} diff --git a/arduino-ide-extension/src/common/protocol/arduino-component.ts b/arduino-ide-extension/src/common/protocol/arduino-component.ts index 20d49f9be..298708e12 100644 --- a/arduino-ide-extension/src/common/protocol/arduino-component.ts +++ b/arduino-ide-extension/src/common/protocol/arduino-component.ts @@ -1,34 +1,35 @@ -import { Installable } from './installable'; +import type { Installable } from './installable'; export interface ArduinoComponent { readonly name: string; - readonly deprecated?: boolean; readonly author: string; readonly summary: string; readonly description: string; - readonly moreInfoLink?: string; readonly availableVersions: Installable.Version[]; - readonly installable: boolean; readonly installedVersion?: Installable.Version; /** * This is the `Type` in IDE (1.x) UI. */ readonly types: string[]; + readonly deprecated?: boolean; + readonly moreInfoLink?: string; } export namespace ArduinoComponent { - export function is(arg: any): arg is ArduinoComponent { + export function is(arg: unknown): arg is ArduinoComponent { return ( - !!arg && - 'name' in arg && - typeof arg['name'] === 'string' && - 'author' in arg && - typeof arg['author'] === 'string' && - 'summary' in arg && - typeof arg['summary'] === 'string' && - 'description' in arg && - typeof arg['description'] === 'string' && - 'installable' in arg && - typeof arg['installable'] === 'boolean' + typeof arg === 'object' && + (<ArduinoComponent>arg).name !== undefined && + typeof (<ArduinoComponent>arg).name === 'string' && + (<ArduinoComponent>arg).author !== undefined && + typeof (<ArduinoComponent>arg).author === 'string' && + (<ArduinoComponent>arg).summary !== undefined && + typeof (<ArduinoComponent>arg).summary === 'string' && + (<ArduinoComponent>arg).description !== undefined && + typeof (<ArduinoComponent>arg).description === 'string' && + (<ArduinoComponent>arg).availableVersions !== undefined && + Array.isArray((<ArduinoComponent>arg).availableVersions) && + (<ArduinoComponent>arg).types !== undefined && + Array.isArray((<ArduinoComponent>arg).types) ); } } diff --git a/arduino-ide-extension/src/common/protocol/examples-service.ts b/arduino-ide-extension/src/common/protocol/examples-service.ts index 8194e57e4..db16a66f0 100644 --- a/arduino-ide-extension/src/common/protocol/examples-service.ts +++ b/arduino-ide-extension/src/common/protocol/examples-service.ts @@ -9,4 +9,8 @@ export interface ExamplesService { current: SketchContainer[]; any: SketchContainer[]; }>; + /** + * Finds example sketch containers for the installed library. + */ + find(options: { libraryName: string }): Promise<SketchContainer[]>; } diff --git a/arduino-ide-extension/src/common/protocol/installable.ts b/arduino-ide-extension/src/common/protocol/installable.ts index f311f8202..962f52aec 100644 --- a/arduino-ide-extension/src/common/protocol/installable.ts +++ b/arduino-ide-extension/src/common/protocol/installable.ts @@ -51,6 +51,46 @@ export namespace Installable { }; } + export const ActionLiterals = [ + 'installLatest', + 'installSelected', + 'update', + 'remove', + 'unknown', + ] as const; + export type Action = typeof ActionLiterals[number]; + + export function action(params: { + installed?: Version | undefined; + available: Version[]; + selected?: Version; + }): Action { + const { installed, available } = params; + const latest = Installable.latest(available); + if (!latest || (installed && !available.includes(installed))) { + return 'unknown'; + } + const selected = params.selected ?? latest; + if (installed === selected) { + return 'remove'; + } + if (installed) { + return selected === latest && installed !== latest + ? 'update' + : 'installSelected'; + } else { + return selected === latest ? 'installLatest' : 'installSelected'; + } + } + + export function latest(versions: Version[]): Version | undefined { + if (!versions.length) { + return undefined; + } + const ordered = versions.slice().sort(Installable.Version.COMPARATOR); + return ordered[ordered.length - 1]; + } + export const Installed = <T extends ArduinoComponent>({ installedVersion, }: T): boolean => { diff --git a/arduino-ide-extension/src/common/protocol/library-service.ts b/arduino-ide-extension/src/common/protocol/library-service.ts index 4a20aae21..e8a32d901 100644 --- a/arduino-ide-extension/src/common/protocol/library-service.ts +++ b/arduino-ide-extension/src/common/protocol/library-service.ts @@ -198,6 +198,10 @@ export namespace LibraryService { export namespace List { export interface Options { readonly fqbn?: string | undefined; + /** + * The name of the library to filter to. + */ + readonly libraryName?: string | undefined; } } } @@ -241,11 +245,15 @@ export interface LibraryPackage extends ArduinoComponent { readonly category: string; } export namespace LibraryPackage { - export function is(arg: any): arg is LibraryPackage { + export function is(arg: unknown): arg is LibraryPackage { return ( ArduinoComponent.is(arg) && - 'includes' in arg && - Array.isArray(arg['includes']) + (<LibraryPackage>arg).includes !== undefined && + Array.isArray((<LibraryPackage>arg).includes) && + (<LibraryPackage>arg).exampleUris !== undefined && + Array.isArray((<LibraryPackage>arg).exampleUris) && + (<LibraryPackage>arg).location !== undefined && + typeof (<LibraryPackage>arg).location === 'number' ); } diff --git a/arduino-ide-extension/src/node/examples-service-impl.ts b/arduino-ide-extension/src/node/examples-service-impl.ts index 63860c555..83cca1e1a 100644 --- a/arduino-ide-extension/src/node/examples-service-impl.ts +++ b/arduino-ide-extension/src/node/examples-service-impl.ts @@ -118,6 +118,16 @@ export class ExamplesServiceImpl implements ExamplesService { return { user, current, any }; } + async find(options: { libraryName: string }): Promise<SketchContainer[]> { + const { libraryName } = options; + const packages = await this.libraryService.list({ libraryName }); + return Promise.all( + packages + .filter(({ location }) => location === LibraryLocation.USER) + .map((pkg) => this.tryGroupExamples(pkg)) + ); + } + /** * The CLI provides direct FS paths to the examples so that menus and menu groups cannot be built for the UI by traversing the * folder hierarchy. This method tries to workaround it by falling back to the `installDirUri` and manually creating the diff --git a/arduino-ide-extension/src/node/library-service-impl.ts b/arduino-ide-extension/src/node/library-service-impl.ts index 9d345b2d6..bd5eb8cb1 100644 --- a/arduino-ide-extension/src/node/library-service-impl.ts +++ b/arduino-ide-extension/src/node/library-service-impl.ts @@ -103,7 +103,6 @@ export class LibraryServiceImpl return toLibrary( { name: item.getName(), - installable: true, installedVersion, }, item.getLatest()!, @@ -154,8 +153,10 @@ export class LibraryServiceImpl async list({ fqbn, + libraryName, }: { fqbn?: string | undefined; + libraryName?: string | undefined; }): Promise<LibraryPackage[]> { const coreClient = await this.coreClient; const { client, instance } = coreClient; @@ -166,6 +167,9 @@ export class LibraryServiceImpl req.setAll(true); // https://github.com/arduino/arduino-ide/pull/303#issuecomment-815556447 req.setFqbn(fqbn); } + if (libraryName) { + req.setName(libraryName); + } const resp = await new Promise<LibraryListResponse | undefined>( (resolve, reject) => { @@ -219,7 +223,6 @@ export class LibraryServiceImpl { name: library.getName(), installedVersion, - installable: true, description: library.getSentence(), summary: library.getParagraph(), moreInfoLink: library.getWebsite(), @@ -455,8 +458,7 @@ function toLibrary( return { name: '', exampleUris: [], - installable: false, - location: 0, + location: LibraryLocation.BUILTIN, ...pkg, author: lib.getAuthor(), diff --git a/arduino-ide-extension/src/test/browser/fixtures/boards.ts b/arduino-ide-extension/src/test/browser/fixtures/boards.ts index 0cedb5b77..16256f3ab 100644 --- a/arduino-ide-extension/src/test/browser/fixtures/boards.ts +++ b/arduino-ide-extension/src/test/browser/fixtures/boards.ts @@ -49,7 +49,6 @@ export const aPackage: BoardsPackage = { deprecated: false, description: 'Some Arduino Board, Some Other Arduino Board', id: 'some:arduinoCoreId', - installable: true, moreInfoLink: 'http://www.some-url.lol/', name: 'Some Arduino Package', summary: 'Boards included in this package:', diff --git a/arduino-ide-extension/src/test/common/installable.test.ts b/arduino-ide-extension/src/test/common/installable.test.ts index 4047f37f1..ed89e799a 100644 --- a/arduino-ide-extension/src/test/common/installable.test.ts +++ b/arduino-ide-extension/src/test/common/installable.test.ts @@ -2,6 +2,16 @@ import { expect } from 'chai'; import { Installable } from '../../common/protocol/installable'; describe('installable', () => { + const latest = '2.0.0'; + // shuffled versions + const available: Installable.Version[] = [ + '1.4.1', + '1.0.0', + latest, + '2.0.0-beta.1', + '1.5', + ]; + describe('compare', () => { const testMe = Installable.Version.COMPARATOR; @@ -39,4 +49,93 @@ describe('installable', () => { }); }); }); + + describe('latest', () => { + it('should get the latest version from a shuffled array', () => { + const copy = available.slice(); + expect(Installable.latest(copy)).to.be.equal(latest); + expect(available).to.be.deep.equal(copy); + }); + }); + + describe('action', () => { + const installLatest: Installable.Action = 'installLatest'; + const installSelected: Installable.Action = 'installSelected'; + const update: Installable.Action = 'update'; + const remove: Installable.Action = 'remove'; + const unknown: Installable.Action = 'unknown'; + const notAvailable = '0.0.0'; + + it("should result 'unknown' if available is empty", () => { + expect(Installable.action({ available: [] })).to.be.equal(unknown); + }); + it("should result 'unknown' if installed is not in available", () => { + expect( + Installable.action({ available, installed: notAvailable }) + ).to.be.equal(unknown); + }); + + it("should result 'installLatest' if not installed and not selected", () => { + expect(Installable.action({ available })).to.be.equal(installLatest); + }); + it("should result 'installLatest' if not installed and latest is selected", () => { + expect(Installable.action({ available, selected: latest })).to.be.equal( + installLatest + ); + }); + + it("should result 'installSelected' if not installed and not latest is selected", () => { + available + .filter((version) => version !== latest) + .forEach((selected) => + expect( + Installable.action({ + available, + selected, + }) + ).to.be.equal(installSelected) + ); + }); + it("should result 'installSelected' if installed and the selected is neither the latest nor the installed", () => { + available.forEach((installed) => + available + .filter((selected) => selected !== latest && selected !== installed) + .forEach((selected) => + expect( + Installable.action({ + installed, + available, + selected, + }) + ).to.be.equal(installSelected) + ) + ); + }); + + it("should result 'update' if the installed version is not the latest and the latest is selected", () => { + available + .filter((installed) => installed !== latest) + .forEach((installed) => + expect( + Installable.action({ + installed, + available, + selected: latest, + }) + ).to.be.equal(update) + ); + }); + + it("should result 'remove' if the selected version equals the installed version", () => { + available.forEach((version) => + expect( + Installable.action({ + installed: version, + available, + selected: version, + }) + ).to.be.equal(remove) + ); + }); + }); }); diff --git a/i18n/en.json b/i18n/en.json index b24a89cd4..b6e67e855 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -160,13 +160,19 @@ "component": { "boardsIncluded": "Boards included in this package:", "by": "by", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "Filter your search...", "install": "Install", - "installed": "Installed", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "More info", + "otherVersions": "Other Versions", + "remove": "Remove", + "title": "{0} by {1}", "uninstall": "Uninstall", "uninstallMsg": "Do you want to uninstall {0}?", - "version": "Version {0}" + "update": "Update" }, "configuration": { "cli": { diff --git a/package.json b/package.json index 8267afa70..266f0feac 100644 --- a/package.json +++ b/package.json @@ -36,10 +36,6 @@ "typescript": "~4.5.5", "xhr2": "^0.2.1" }, - "resolutions": { - "@types/react": "18.0.0", - "@types/react-dom": "18.0.0" - }, "scripts": { "prepare": "lerna run prepare && yarn download:plugins", "cleanup": "npx rimraf ./**/node_modules && rm -rf ./node_modules ./.browser_modules ./arduino-ide-extension/build ./arduino-ide-extension/downloads ./arduino-ide-extension/Examples ./arduino-ide-extension/lib ./electron-app/lib ./electron-app/src-gen ./electron-app/gen-webpack.config.js", diff --git a/yarn.lock b/yarn.lock index e77dd480d..3ed199799 100644 --- a/yarn.lock +++ b/yarn.lock @@ -898,13 +898,6 @@ dependencies: regenerator-runtime "^0.13.10" -"@babel/runtime@^7.7.2": - version "7.20.1" - resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.20.1.tgz#1148bb33ab252b165a06698fde7576092a78b4a9" - integrity sha512-mrzLkl6U9YLF8qpqI7TB82PESyEGjm/0Ly91jG575eVxMMlb8fYfOXFZIJ8XfLrJZQbm7dlKry2bJmXBUEkdFg== - dependencies: - regenerator-runtime "^0.13.10" - "@babel/template@^7.18.6": version "7.18.6" resolved "https://registry.yarnpkg.com/@babel/template/-/template-7.18.6.tgz#1283f4993e00b929d6e2d3c72fdc9168a2977a31" @@ -3535,10 +3528,10 @@ resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.4.tgz#cd667bcfdd025213aafb7ca5915a932590acdcdc" integrity sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw== -"@types/react-dom@18.0.0", "@types/react-dom@^18.0.6": - version "18.0.0" - resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.0.tgz#b13f8d098e4b0c45df4f1ed123833143b0c71141" - integrity sha512-49897Y0UiCGmxZqpC8Blrf6meL8QUla6eb+BBhn69dTXlmuOlzkfr7HHY/O8J25e1lTUMs+YYxSlVDAaGHCOLg== +"@types/react-dom@^18.0.6": + version "18.0.11" + resolved "https://registry.yarnpkg.com/@types/react-dom/-/react-dom-18.0.11.tgz#321351c1459bc9ca3d216aefc8a167beec334e33" + integrity sha512-O38bPbI2CWtgw/OoQoY+BRelw7uysmXbWvw3nLWO21H1HSh+GOlqPuXshJfjmpNlKiiSDG9cc1JZAaMmVdcTlw== dependencies: "@types/react" "*" @@ -3556,14 +3549,6 @@ dependencies: "@types/react" "*" -"@types/react-virtualized@^9.21.21": - version "9.21.21" - resolved "https://registry.yarnpkg.com/@types/react-virtualized/-/react-virtualized-9.21.21.tgz#65c96f25314f0fb3d40536929dc78112753b49e1" - integrity sha512-Exx6I7p4Qn+BBA1SRyj/UwQlZ0I0Pq7g7uhAp0QQ4JWzZunqEqNBGTmCmMmS/3N9wFgAGWuBD16ap7k8Y14VPA== - dependencies: - "@types/prop-types" "*" - "@types/react" "^17" - "@types/react-window@^1.8.5": version "1.8.5" resolved "https://registry.yarnpkg.com/@types/react-window/-/react-window-1.8.5.tgz#285fcc5cea703eef78d90f499e1457e9b5c02fc1" @@ -3571,7 +3556,7 @@ dependencies: "@types/react" "*" -"@types/react@*", "@types/react@18.0.0", "@types/react@^17", "@types/react@^18.0.15": +"@types/react@*": version "18.0.0" resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.0.tgz#4be8aa3a2d04afc3ac2cc1ca43d39b0bd412890c" integrity sha512-7+K7zEQYu7NzOwQGLR91KwWXXDzmTFODRVizJyIALf6RfLv2GDpqpknX64pvRVILXCpXi7O/pua8NGk44dLvJw== @@ -3580,6 +3565,15 @@ "@types/scheduler" "*" csstype "^3.0.2" +"@types/react@^18.0.15": + version "18.0.28" + resolved "https://registry.yarnpkg.com/@types/react/-/react-18.0.28.tgz#accaeb8b86f4908057ad629a26635fe641480065" + integrity sha512-RD0ivG1kEztNBdoAK7lekI9M+azSnitIn85h4iOiaLjaTrMjzslhaqCGaI4IyCJ1RljWiLCEu4jyrLLgqxBTew== + dependencies: + "@types/prop-types" "*" + "@types/scheduler" "*" + csstype "^3.0.2" + "@types/request@^2.0.3": version "2.48.8" resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.8.tgz#0b90fde3b655ab50976cb8c5ac00faca22f5a82c" @@ -5542,7 +5536,7 @@ cloneable-readable@^1.0.0: process-nextick-args "^2.0.0" readable-stream "^2.3.5" -clsx@^1.0.4, clsx@^1.1.0: +clsx@^1.1.0: version "1.2.1" resolved "https://registry.yarnpkg.com/clsx/-/clsx-1.2.1.tgz#0ddc4a20a549b59c93a4116bb26f5294ca17dc12" integrity sha512-EcR6r5a8bj6pu3ycsa/E/cKVGuTgZJZdsyUYHOksG/UHIiKfjxzRxYJpyVBwYaQeOvghal9fcc4PidlgzugAQg== @@ -6436,7 +6430,7 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -dom-helpers@^5.0.1, dom-helpers@^5.1.3: +dom-helpers@^5.0.1: version "5.2.1" resolved "https://registry.yarnpkg.com/dom-helpers/-/dom-helpers-5.2.1.tgz#d9400536b2bf8225ad98fe052e029451ac40e902" integrity sha512-nRCa7CK3VTrM2NmGkIy4cbK7IZlgBE/PYMn55rrXefr5xXDP0LdtfPnblFDoVdcAfslJ7or6iqAUnx0CCGIWQA== @@ -12322,11 +12316,6 @@ react-is@^18.0.0: resolved "https://registry.yarnpkg.com/react-is/-/react-is-18.2.0.tgz#199431eeaaa2e09f86427efbb4f1473edb47609b" integrity sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w== -react-lifecycles-compat@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/react-lifecycles-compat/-/react-lifecycles-compat-3.0.4.tgz#4f1a273afdfc8f3488a8c516bfda78f872352362" - integrity sha512-fBASbA6LnOU9dOU2eW7aQ8xmYBSXUIWr+UmF9b1efZBazGNO+rcXT/icdKnYm2pTwcRylVUYwW7H1PHfLekVzA== - react-markdown@^8.0.0: version "8.0.3" resolved "https://registry.yarnpkg.com/react-markdown/-/react-markdown-8.0.3.tgz#e8aba0d2f5a1b2124d476ee1fff9448a2f57e4b3" @@ -12397,18 +12386,6 @@ react-transition-group@^4.3.0: loose-envify "^1.4.0" prop-types "^15.6.2" -react-virtualized@^9.22.3: - version "9.22.3" - resolved "https://registry.yarnpkg.com/react-virtualized/-/react-virtualized-9.22.3.tgz#f430f16beb0a42db420dbd4d340403c0de334421" - integrity sha512-MKovKMxWTcwPSxE1kK1HcheQTWfuCxAuBoSTf2gwyMM21NdX/PXUhnoP8Uc5dRKd+nKm8v41R36OellhdCpkrw== - dependencies: - "@babel/runtime" "^7.7.2" - clsx "^1.0.4" - dom-helpers "^5.1.3" - loose-envify "^1.4.0" - prop-types "^15.7.2" - react-lifecycles-compat "^3.0.4" - react-virtuoso@^2.17.0: version "2.19.1" resolved "https://registry.yarnpkg.com/react-virtuoso/-/react-virtuoso-2.19.1.tgz#a660a5c3cafcc7a84b59dfc356e1916e632c1e3a" From b09ae485361b29db47374b497227bdeecb563592 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 15 Mar 2023 20:02:34 +0000 Subject: [PATCH 11/32] build(deps): Bump actions/setup-go from 3 to 4 Bumps [actions/setup-go](https://github.com/actions/setup-go) from 3 to 4. - [Release notes](https://github.com/actions/setup-go/releases) - [Commits](https://github.com/actions/setup-go/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/setup-go dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> --- .github/workflows/build.yml | 2 +- .github/workflows/check-i18n-task.yml | 2 +- .github/workflows/i18n-nightly-push.yml | 2 +- .github/workflows/i18n-weekly-pull.yml | 2 +- .github/workflows/themes-weekly-pull.yml | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 52af464a6..d26c26def 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -69,7 +69,7 @@ jobs: python-version: '3.x' - name: Install Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: ${{ env.GO_VERSION }} diff --git a/.github/workflows/check-i18n-task.yml b/.github/workflows/check-i18n-task.yml index 9e65dbdb3..d4bb68bb6 100644 --- a/.github/workflows/check-i18n-task.yml +++ b/.github/workflows/check-i18n-task.yml @@ -36,7 +36,7 @@ jobs: registry-url: 'https://registry.npmjs.org' - name: Install Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: ${{ env.GO_VERSION }} diff --git a/.github/workflows/i18n-nightly-push.yml b/.github/workflows/i18n-nightly-push.yml index 708262c7f..a2c649593 100644 --- a/.github/workflows/i18n-nightly-push.yml +++ b/.github/workflows/i18n-nightly-push.yml @@ -23,7 +23,7 @@ jobs: registry-url: 'https://registry.npmjs.org' - name: Install Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: ${{ env.GO_VERSION }} diff --git a/.github/workflows/i18n-weekly-pull.yml b/.github/workflows/i18n-weekly-pull.yml index 5b7337cf1..435d1e572 100644 --- a/.github/workflows/i18n-weekly-pull.yml +++ b/.github/workflows/i18n-weekly-pull.yml @@ -23,7 +23,7 @@ jobs: registry-url: 'https://registry.npmjs.org' - name: Install Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: ${{ env.GO_VERSION }} diff --git a/.github/workflows/themes-weekly-pull.yml b/.github/workflows/themes-weekly-pull.yml index 8c735d938..a236db537 100644 --- a/.github/workflows/themes-weekly-pull.yml +++ b/.github/workflows/themes-weekly-pull.yml @@ -25,7 +25,7 @@ jobs: registry-url: 'https://registry.npmjs.org' - name: Install Go - uses: actions/setup-go@v3 + uses: actions/setup-go@v4 with: go-version: ${{ env.GO_VERSION }} From 0ab28266dfe1859eb4e1c88502452f419b667099 Mon Sep 17 00:00:00 2001 From: Akos Kitta <a.kitta@arduino.cc> Date: Wed, 15 Feb 2023 18:03:37 +0100 Subject: [PATCH 12/32] feat: introduced cloud state in sketchbook view Closes #1879 Closes #1876 Closes #1899 Closes #1878 Signed-off-by: Akos Kitta <a.kitta@arduino.cc> --- arduino-ide-extension/arduino-icons.json | 2 +- arduino-ide-extension/package.json | 5 +- .../browser/arduino-ide-frontend-module.ts | 12 +- .../src/browser/contributions/account.ts | 18 +- .../contributions/cloud-contribution.ts | 2 +- .../src/browser/contributions/contribution.ts | 5 +- .../contributions/create-cloud-copy.ts | 118 ++++++ .../browser/contributions/new-cloud-sketch.ts | 59 ++- .../contributions/rename-cloud-sketch.ts | 2 +- .../browser/contributions/save-as-sketch.ts | 108 +++--- .../src/browser/create/create-api.ts | 11 +- .../src/browser/create/create-features.ts | 55 ++- .../arduino-cloud-download.svg} | 0 .../icons/arduino-cloud-filled-offline.svg | 4 + .../browser/icons/arduino-cloud-filled.svg | 3 + .../browser/icons/arduino-cloud-offline.svg | 4 + .../arduino-cloud-upload.svg} | 0 .../src/browser/icons/arduino-cloud.svg | 3 + .../src/browser/style/account-icon.svg | 1 - .../src/browser/style/cloud-sketchbook.css | 34 +- .../src/browser/style/fonts.css | 24 +- .../src/browser/style/fonts/FontAwesome.svg | 6 + .../src/browser/style/fonts/FontAwesome.ttf | Bin 43180 -> 45416 bytes .../src/browser/style/fonts/FontAwesome.woff | Bin 43256 -> 45492 bytes .../src/browser/style/main.css | 6 +- .../src/browser/style/sketch-folder-icon.svg | 4 - .../src/browser/style/sketchbook.css | 7 - .../theia/core/connection-status-service.ts | 342 ++++++++++++++--- .../theia/core/sidebar-bottom-menu-widget.tsx | 20 +- .../theia/core/window-title-updater.ts | 74 +++- .../theia/messages/notifications-manager.ts | 8 - .../cloud-sketchbook-commands.ts | 88 +++++ .../cloud-sketchbook-composite-widget.tsx | 7 +- .../cloud-sketchbook-contributions.ts | 362 +++++++++++------- .../cloud-sketchbook-tree-model.ts | 14 +- .../cloud-sketchbook-tree-widget.tsx | 29 +- .../cloud-sketchbook/cloud-sketchbook-tree.ts | 216 +++++++---- ...cloud-user-status.tsx => cloud-status.tsx} | 58 +-- .../widgets/sketchbook/sketchbook-commands.ts | 3 - .../sketchbook/sketchbook-tree-widget.tsx | 27 +- .../widgets/sketchbook/sketchbook-tree.ts | 18 +- .../sketchbook-widget-contribution.ts | 18 +- .../src/common/protocol/sketches-service.ts | 13 +- arduino-ide-extension/src/common/utils.ts | 9 +- .../src/node/sketches-service-impl.ts | 178 ++++----- .../browser/connection-status-service.test.ts | 46 +++ .../node/boards-service-impl.slow-test.ts | 20 +- .../test/node/core-service-impl.slow-test.ts | 18 +- .../node/library-service-impl.slow-test.ts | 18 +- .../node/sketches-service-impl.slow-test.ts | 262 +++++++++++++ .../src/test/node/test-bindings.ts | 16 +- i18n/en.json | 12 +- yarn.lock | 245 +++++++++++- 53 files changed, 1963 insertions(+), 651 deletions(-) create mode 100644 arduino-ide-extension/src/browser/contributions/create-cloud-copy.ts rename arduino-ide-extension/src/browser/{style/pull-sketch-icon.svg => icons/arduino-cloud-download.svg} (100%) create mode 100644 arduino-ide-extension/src/browser/icons/arduino-cloud-filled-offline.svg create mode 100644 arduino-ide-extension/src/browser/icons/arduino-cloud-filled.svg create mode 100644 arduino-ide-extension/src/browser/icons/arduino-cloud-offline.svg rename arduino-ide-extension/src/browser/{style/push-sketch-icon.svg => icons/arduino-cloud-upload.svg} (100%) create mode 100644 arduino-ide-extension/src/browser/icons/arduino-cloud.svg delete mode 100644 arduino-ide-extension/src/browser/style/account-icon.svg delete mode 100644 arduino-ide-extension/src/browser/style/sketch-folder-icon.svg create mode 100644 arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-commands.ts rename arduino-ide-extension/src/browser/widgets/cloud-sketchbook/{cloud-user-status.tsx => cloud-status.tsx} (62%) create mode 100644 arduino-ide-extension/src/test/browser/connection-status-service.test.ts create mode 100644 arduino-ide-extension/src/test/node/sketches-service-impl.slow-test.ts diff --git a/arduino-ide-extension/arduino-icons.json b/arduino-ide-extension/arduino-icons.json index d109db94f..7c510e9cf 100644 --- a/arduino-ide-extension/arduino-icons.json +++ b/arduino-ide-extension/arduino-icons.json @@ -1 +1 @@ -{"IcoMoonType":"selection","icons":[{"icon":{"paths":["M558.545 1024c-23.818 0-47.637-9.095-65.819-27.276l-465.454-465.453c-36.363-36.363-36.363-95.273 0-131.636s95.273-36.363 131.637 0l399.636 399.636 772.003-772c36.361-36.363 95.269-36.363 131.631 0s36.361 95.273 0 131.637l-837.815 837.815c-18.182 18.181-42 27.276-65.818 27.276z"],"attrs":[{}],"width":1489,"isMulticolor":false,"isMulticolor2":false,"grid":14,"tags":["arduino-verify"]},"attrs":[{}],"properties":{"order":12,"id":192,"name":"arduino-verify","prevSize":28,"code":59659},"setIdx":0,"setId":1,"iconIdx":0},{"icon":{"paths":["M1072.469 526.509l-409.603 409.598c-13.65 12.971-30.717 19.804-48.467 19.804s-34.817-6.833-48.467-19.804c-26.625-26.617-26.625-70.315 0-96.932l293.551-292.866h-791.217c-37.55 0-68.267-30.717-68.267-68.267s30.717-68.267 68.267-68.267h791.217l-293.551-292.866c-26.625-26.616-26.625-70.317 0-96.934 26.616-26.634 70.317-26.634 96.933 0l409.603 409.6c26.624 26.616 26.624 70.317 0 96.934v0z"],"attrs":[{}],"width":1161,"isMulticolor":false,"isMulticolor2":false,"grid":14,"tags":["arduino-upload"]},"attrs":[{}],"properties":{"order":11,"id":191,"name":"arduino-upload","prevSize":28,"code":59660},"setIdx":0,"setId":1,"iconIdx":1},{"icon":{"paths":["M651.891 890.88c-92.835 0-179.095-28.493-250.5-77.197l-129.659 129.658c-22.494 22.496-58.964 22.496-81.458 0s-22.494-58.963 0-81.459l124.954-124.954c-67.75-78.157-108.777-180.090-108.777-291.489 0-245.759 199.68-445.439 445.44-445.439s445.44 199.679 445.44 445.439c0 245.761-199.68 445.441-445.44 445.441zM651.891 153.6c-161.28 0-291.84 130.559-291.84 291.839s130.56 291.841 291.84 291.841c160.512 0 291.84-130.561 291.84-291.841 0-160.511-130.56-291.839-291.84-291.839zM1149.562 478.091c0 35.423 28.717 64.138 64.141 64.138s64.134-28.716 64.134-64.138c0-35.423-28.71-64.139-64.134-64.139s-64.141 28.716-64.141 64.139zM64.064 542.237c-35.382 0-64.064-28.682-64.064-64.063s28.682-64.064 64.064-64.064c35.381 0 64.064 28.682 64.064 64.064s-28.683 64.063-64.064 64.063zM1458.707 542.229c-35.418 0-64.134-28.716-64.134-64.138s28.717-64.139 64.134-64.139c35.424 0 64.141 28.716 64.141 64.139s-28.717 64.138-64.141 64.138zM652.659 526.847c-44.961 0-81.408-36.447-81.408-81.407s36.447-81.408 81.408-81.408c44.96 0 81.408 36.447 81.408 81.408s-36.448 81.407-81.408 81.407z"],"attrs":[{}],"width":1536,"isMulticolor":false,"isMulticolor2":false,"grid":14,"tags":["arduino-monitor"]},"attrs":[{}],"properties":{"order":10,"id":190,"name":"arduino-monitor","prevSize":28,"code":59661},"setIdx":0,"setId":1,"iconIdx":2},{"icon":{"paths":["M511.998 603.432c50.495 0 91.432-40.936 91.432-91.432s-40.936-91.432-91.432-91.432c-50.495 0-91.432 40.936-91.432 91.432s40.936 91.432 91.432 91.432z","M923.433 603.432c50.494 0 91.432-40.936 91.432-91.432s-40.937-91.432-91.432-91.432c-50.494 0-91.432 40.936-91.432 91.432s40.937 91.432 91.432 91.432z","M100.565 603.432c50.495 0 91.432-40.936 91.432-91.432s-40.936-91.432-91.432-91.432c-50.495 0-91.432 40.936-91.432 91.432s40.936 91.432 91.432 91.432z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"grid":14,"tags":["arduino-sketch-tabs-menu"]},"attrs":[{},{},{}],"properties":{"order":9,"id":189,"name":"arduino-sketch-tabs-menu","prevSize":28,"code":59662},"setIdx":0,"setId":1,"iconIdx":3},{"icon":{"paths":["M323.368 970.208c-20.263 0-39-11.42-48.21-29.788l-146.789-293.581h-74.474c-29.789 0-53.895-24.107-53.895-53.895s24.105-53.895 53.895-53.895h107.789c20.421 0 39.053 11.528 48.21 29.788l96.527 193.056 180.263-720.949c5.842-23.579 26.737-40.263 51-40.842 23.947-1.579 45.893 15.158 52.894 38.421l150.162 500.526h67.681c29.788 0 53.895 24.107 53.895 53.895s-24.107 53.895-53.895 53.895h-107.789c-23.789 0-44.787-15.629-51.631-38.422l-105.316-351.104-168.052 672.053c-5.474 21.897-23.948 38.055-46.368 40.529-2 0.21-3.947 0.313-5.895 0.313h-0.001z"],"attrs":[{}],"width":862,"isMulticolor":false,"isMulticolor2":false,"grid":14,"tags":["arduino-plotter"]},"attrs":[{}],"properties":{"order":8,"id":188,"name":"arduino-plotter","prevSize":28,"code":59663},"setIdx":0,"setId":1,"iconIdx":4},{"icon":{"paths":["M416.006 800c-4.211 0.026-8.386-0.787-12.285-2.374-3.899-1.594-7.445-3.942-10.435-6.906l-224-224.002c-6.026-6.026-9.411-14.198-9.411-22.72s3.385-16.694 9.411-22.72c6.026-6.026 14.198-9.411 22.72-9.411s16.694 3.386 22.72 9.411l201.28 201.602 425.281-425.602c6.022-6.026 14.195-9.411 22.72-9.411 8.518 0 16.691 3.386 22.72 9.411 6.022 6.026 9.408 14.198 9.408 22.72s-3.386 16.694-9.408 22.72l-448.001 448.002c-2.99 2.963-6.536 5.312-10.435 6.906-3.899 1.587-8.074 2.4-12.285 2.374z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["fa-check"],"grid":14},"attrs":[{}],"properties":{"order":722,"id":0,"name":"fa-check","prevSize":28,"code":59658},"setIdx":0,"setId":1,"iconIdx":5},{"icon":{"paths":["M864 128h-576c-8.484 0.062-16.618 3.385-22.72 9.28l-128 128c-5.969 6.052-9.305 14.219-9.28 22.72v576c0.024 8.48 3.404 16.602 9.4 22.598s14.121 9.376 22.6 9.402h576c8.486-0.038 16.634-3.36 22.72-9.28l128-128c5.894-6.099 9.216-14.234 9.28-22.72v-576c-0.026-8.479-3.405-16.605-9.402-22.6s-14.118-9.375-22.598-9.4zM704 832h-512v-512h512v512zM722.56 256h-485.12l63.68-64h485.44l-64 64zM832 722.88l-64 63.68v-485.12l64-64v485.44z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["technology-3dimensionscube"],"grid":14},"attrs":[{}],"properties":{"order":717,"id":1,"name":"arduino-technology-3dimensionscube","prevSize":28,"code":59654},"setIdx":0,"setId":1,"iconIdx":6},{"icon":{"paths":["M848 224v96c0 8.487-3.373 16.627-9.37 22.627-6.003 6.001-14.144 9.373-22.63 9.373h-16v96c-0.019 5.909-1.67 11.699-4.781 16.725-3.104 5.027-7.539 9.096-12.819 11.755l-238.4 119.36v242.88c16.845 7.354 30.644 20.282 39.079 36.608 8.435 16.333 10.989 35.066 7.233 53.056s-13.59 34.144-27.852 45.734c-14.262 11.597-32.081 17.92-50.46 17.92s-36.198-6.323-50.46-17.92c-14.262-11.59-24.097-27.744-27.852-45.734s-1.201-36.723 7.233-53.056c8.435-16.326 22.234-29.254 39.079-36.608v-82.88l-238.4-119.36c-5.277-2.659-9.715-6.728-12.822-11.755s-4.76-10.816-4.778-16.725v-102.72c-16.845-7.352-30.644-20.279-39.079-36.609s-10.988-35.066-7.233-53.057c3.755-17.992 13.59-34.141 27.852-45.734s32.081-17.921 50.46-17.921c18.38 0 36.198 6.328 50.46 17.921s24.097 27.743 27.852 45.734c3.756 17.992 1.201 36.727-7.233 53.057s-22.234 29.257-39.079 36.609v82.88l192 96v-524.16h-32c-6.372 0.032-12.609-1.839-17.91-5.374s-9.428-8.572-11.85-14.466c-2.41-5.858-3.028-12.3-1.775-18.509s4.321-11.907 8.815-16.371l64-64c2.975-2.999 6.514-5.38 10.413-7.005s8.083-2.461 12.307-2.461c4.225 0 8.407 0.836 12.307 2.461s7.439 4.005 10.413 7.005l64 64c4.44 4.5 7.448 10.214 8.644 16.422s0.526 12.63-1.924 18.458c-2.401 5.844-6.477 10.846-11.716 14.377s-11.406 5.432-17.724 5.463h-32v364.16l192-96v-76.16h-16c-8.486 0-16.627-3.372-22.63-9.373-5.997-6.001-9.37-14.14-9.37-22.627v-96c0-8.487 3.373-16.627 9.37-22.627 6.003-6.001 14.144-9.373 22.63-9.373h96c8.486 0 16.627 3.372 22.63 9.373 5.997 6.001 9.37 14.14 9.37 22.627z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["technology-usb"],"grid":14},"attrs":[{}],"properties":{"order":715,"id":2,"name":"arduino-technology-usb","prevSize":28,"code":59655},"setIdx":0,"setId":1,"iconIdx":7},{"icon":{"paths":["M512 832c35.346 0 64-28.653 64-64s-28.654-64-64-64c-35.346 0-64 28.653-64 64s28.654 64 64 64z","M647.699 664.32c-8.442-0.122-16.493-3.571-22.401-9.6-14.863-14.9-32.519-26.721-51.957-34.787s-40.277-12.218-61.323-12.218c-21.046 0-41.884 4.152-61.323 12.218s-37.094 19.887-51.957 34.787c-5.996 5.958-14.106 9.306-22.56 9.306s-16.564-3.347-22.56-9.306c-5.96-5.997-9.306-14.106-9.306-22.559s3.345-16.564 9.306-22.56c20.801-20.803 45.495-37.304 72.673-48.563s56.308-17.053 85.727-17.053c29.418 0 58.548 5.795 85.726 17.053s51.875 27.761 72.675 48.563c4.512 4.476 7.59 10.194 8.838 16.426 1.254 6.232 0.614 12.695-1.818 18.562-2.438 5.875-6.573 10.886-11.866 14.4-5.299 3.514-11.52 5.37-17.875 5.331z","M919.373 392.639c-4.269 0.195-8.538-0.47-12.55-1.954s-7.686-3.757-10.81-6.686c-101.965-101.613-240.045-158.669-383.997-158.669-143.951 0-282.035 57.056-384 158.669-6.026 5.983-14.181 9.328-22.673 9.298s-16.623-3.432-22.607-9.458c-5.983-6.026-9.327-14.181-9.298-22.673s3.432-16.623 9.458-22.607c114.009-113.924 268.588-177.918 429.76-177.918 161.175 0 315.754 63.994 429.757 177.918 3.002 2.975 5.382 6.514 7.008 10.413s2.458 8.083 2.458 12.307c0 4.225-0.832 8.407-2.458 12.307s-4.006 7.439-7.008 10.413c-3.078 2.89-6.701 5.14-10.656 6.623-3.949 1.483-8.16 2.168-12.384 2.017z","M783.706 528.316c-4.211 0.024-8.384-0.783-12.288-2.375-3.898-1.592-7.443-3.939-10.432-6.905-32.691-32.703-71.501-58.646-114.221-76.346-42.715-17.7-88.501-26.81-134.74-26.81s-92.025 9.11-134.742 26.81c-42.717 17.7-81.529 43.643-114.218 76.346-6.122 5.242-13.996 7.982-22.049 7.671s-15.693-3.65-21.393-9.349c-5.699-5.699-9.037-13.338-9.348-21.392s2.428-15.928 7.67-22.050c78.009-77.968 183.788-121.767 294.080-121.767s216.072 43.799 294.081 121.767c5.958 5.996 9.306 14.106 9.306 22.56s-3.347 16.564-9.306 22.56c-5.958 5.912-14.003 9.245-22.4 9.28z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["technology-connection"],"grid":14},"attrs":[{},{},{},{}],"properties":{"order":714,"id":3,"name":"arduino-technology-connection","prevSize":28,"code":59656},"setIdx":0,"setId":1,"iconIdx":8},{"icon":{"paths":["M512.006 991.994c-4.198 0.109-8.362-0.768-12.16-2.56-5.844-2.4-10.846-6.477-14.377-11.712-3.53-5.242-5.431-11.405-5.463-17.728v-370.877l-169.28 169.597c-2.984 2.989-6.525 5.35-10.424 6.97-3.898 1.613-8.077 2.445-12.296 2.445s-8.397-0.832-12.296-2.445c-3.898-1.619-7.441-3.981-10.424-6.97-2.984-2.982-5.35-6.522-6.965-10.419s-2.445-8.077-2.445-12.301c0-4.218 0.831-8.397 2.445-12.294s3.981-7.437 6.965-10.426l201.6-201.277-201.6-201.28c-6.026-6.026-9.411-14.198-9.411-22.72s3.385-16.694 9.411-22.72c6.026-6.026 14.198-9.411 22.72-9.411s16.694 3.386 22.72 9.411l169.28 169.6v-370.88c0.032-6.318 1.933-12.485 5.463-17.724s8.533-9.316 14.377-11.716c5.828-2.451 12.25-3.12 18.458-1.924s11.922 4.204 16.422 8.644l224.001 224c3.002 2.975 5.382 6.514 7.002 10.413 1.626 3.9 2.464 8.082 2.464 12.307s-0.838 8.407-2.464 12.307c-1.619 3.9-4 7.439-7.002 10.413l-201.601 201.28 201.601 201.277c3.002 2.976 5.382 6.515 7.002 10.419 1.626 3.898 2.464 8.077 2.464 12.301 0 4.23-0.838 8.41-2.464 12.307-1.619 3.904-4 7.443-7.002 10.413l-224.001 224c-2.99 2.97-6.536 5.318-10.435 6.906-3.899 1.594-8.074 2.4-12.285 2.374zM544.006 589.117v293.757l146.881-146.88-146.881-146.877zM544.006 141.117v293.76l146.881-146.88-146.881-146.88z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["technology-bluetooth"],"grid":14},"attrs":[{}],"properties":{"order":713,"id":4,"name":"arduino-technology-bluetooth","prevSize":28,"code":59657},"setIdx":0,"setId":1,"iconIdx":9},{"icon":{"paths":["M613.86 663.104c-8.983 0.005-17.72-2.956-24.841-8.429-7.126-5.474-12.241-13.144-14.55-21.825s-1.685-17.883 1.778-26.173c3.463-8.29 9.57-15.202 17.366-19.661l304.621-173.965-488.052-278.887v296.386c0 10.801-4.291 21.16-11.929 28.799-7.638 7.636-17.997 11.927-28.799 11.927s-21.16-4.291-28.799-11.927c-7.638-7.638-11.929-17.997-11.929-28.799v-366.545c-0.004-7.135 1.867-14.146 5.426-20.33s8.681-11.324 14.852-14.905c6.171-3.581 13.175-5.477 20.31-5.499s14.15 1.832 20.343 5.376l610.91 349.045c6.232 3.561 11.413 8.707 15.020 14.917 3.603 6.21 5.502 13.261 5.502 20.441s-1.899 14.232-5.502 20.441c-3.607 6.21-8.788 11.356-15.020 14.917l-366.545 209.324c-6.135 3.528-13.089 5.381-20.163 5.371z","M491.636 797.094c10.803 0 21.16-4.291 28.798-11.93s11.93-17.994 11.93-28.798c0-10.803-4.291-21.16-11.93-28.798s-17.994-11.93-28.798-11.93h-43.173c-1.991-17.389-5.534-34.56-10.589-51.316l41.949-41.951c3.798-3.793 6.81-8.304 8.867-13.265 2.053-4.962 3.109-10.277 3.109-15.649s-1.057-10.687-3.109-15.649c-2.057-4.962-5.069-9.467-8.867-13.265s-8.304-6.81-13.265-8.867c-4.961-2.053-10.279-3.114-15.649-3.114s-10.688 1.061-15.649 3.114c-4.961 2.057-9.47 5.069-13.267 8.867l-21.585 21.583c-14.553-22.109-34.216-40.387-57.327-53.285-23.11-12.902-48.988-20.052-75.444-20.838-26.456 0.787-52.334 7.936-75.444 20.838s-42.774 31.181-57.327 53.29l-21.585-21.588c-7.669-7.671-18.070-11.976-28.915-11.976s-21.247 4.305-28.916 11.976c-7.669 7.666-11.978 18.069-11.978 28.914s4.308 21.248 11.977 28.914l41.949 41.951c-5.055 16.756-8.599 33.927-10.589 51.316h-43.171c-10.802 0-21.161 4.291-28.799 11.93s-11.929 17.994-11.929 28.798c0 10.803 4.291 21.16 11.929 28.798s17.997 11.93 28.799 11.93h43.173c1.991 17.389 5.534 34.56 10.589 51.316l-1.222 1.224-40.727 40.727c-7.631 7.685-11.913 18.078-11.913 28.914 0 10.831 4.282 21.225 11.913 28.914 7.72 7.568 18.102 11.813 28.915 11.813s21.194-4.245 28.915-11.813l21.585-21.588c14.553 22.109 34.216 40.387 57.327 53.29s48.989 20.052 75.445 20.838c26.456-0.787 52.334-7.936 75.444-20.838s42.774-31.181 57.327-53.29l21.585 21.588c7.72 7.573 18.102 11.813 28.915 11.813s21.194-4.24 28.916-11.813c7.629-7.689 11.911-18.083 11.911-28.914 0-10.836-4.282-21.229-11.911-28.914l-41.95-41.951c5.055-16.756 8.599-33.927 10.589-51.316h43.174zM267.636 593.458c37.058 0 69.644 32.991 87.564 81.455h-175.127c17.92-48.463 50.506-81.455 87.564-81.455zM267.636 919.276c-55.389 0-101.818-74.533-101.818-162.909h203.636c0 88.376-46.429 162.909-101.818 162.909z"],"attrs":[{},{}],"tags":["arduino-debugger"],"grid":14,"isMulticolor":false,"isMulticolor2":false},"attrs":[{},{}],"properties":{"order":696,"id":5,"name":"arduino-debugger","prevSize":28,"code":59653},"setIdx":0,"setId":1,"iconIdx":10},{"icon":{"paths":["M1011.905 953.837l-286.249-286.249c66.349-81.248 98.942-184.882 91.034-289.478-7.903-104.597-55.702-202.157-133.511-272.506-77.804-70.35-179.671-108.111-284.533-105.473s-204.701 45.47-278.874 119.643c-74.172 74.172-117.006 174.012-119.643 278.874s35.123 206.729 105.473 284.537c70.35 77.804 167.91 125.604 272.506 133.506 104.597 7.907 208.231-24.685 289.479-91.034l286.249 286.249c3.8 3.832 8.323 6.874 13.305 8.95s10.328 3.145 15.727 3.145c5.398 0 10.745-1.071 15.727-3.145 4.986-2.075 9.506-5.117 13.31-8.95 3.832-3.804 6.874-8.323 8.95-13.31 2.075-4.982 3.145-10.328 3.145-15.727s-1.071-10.739-3.145-15.727c-2.075-4.982-5.117-9.506-8.95-13.305v0zM410.372 737.512c-64.702 0-127.952-19.184-181.75-55.132-53.798-35.944-95.728-87.038-120.49-146.816s-31.239-125.554-18.616-189.013c12.623-63.459 43.78-121.751 89.532-167.502s104.043-76.909 167.502-89.532c63.459-12.623 129.235-6.145 189.013 18.616s110.868 66.691 146.816 120.489c35.948 53.798 55.132 117.048 55.132 181.75 0 86.766-34.467 169.972-95.815 231.325-61.353 61.349-144.564 95.815-231.326 95.815v0z"],"attrs":[{}],"tags":["arduino-search"],"grid":14,"isMulticolor":false,"isMulticolor2":false},"attrs":[{}],"properties":{"order":689,"id":6,"name":"arduino-search","prevSize":28,"code":59649},"setIdx":0,"setId":1,"iconIdx":11},{"icon":{"paths":["M997.684 728.889c0 11.506-4.572 22.538-12.707 30.67s-19.165 12.707-30.67 12.707h-433.777c-11.506 0-22.538-4.572-30.673-12.707s-12.705-19.165-12.705-30.67 4.571-22.538 12.705-30.67c8.136-8.134 19.166-12.707 30.673-12.707h433.777c11.506 0 22.538 4.572 30.67 12.707s12.707 19.165 12.707 30.67z","M1201.991 351.068l-74.173-73.742v-199.104c0-11.503-4.572-22.539-12.707-30.673s-19.165-12.705-30.67-12.705h-910.933c-11.503 0-22.539 4.571-30.673 12.705s-12.705 19.168-12.705 30.673v130.133h-86.756c-11.504 0-22.539 4.571-30.673 12.705s-12.705 19.168-12.705 30.673v216.89c0 11.503 4.571 22.539 12.705 30.673s19.168 12.705 30.673 12.705h86.756v433.777c0 11.506 4.571 22.538 12.705 30.67s19.168 12.707 30.673 12.707h910.933c5.71 0.034 11.368-1.062 16.653-3.216 5.285-2.161 10.092-5.342 14.143-9.365l86.756-86.756c4.020-4.052 7.203-8.859 9.365-14.143 2.157-5.285 3.253-10.94 3.216-16.653v-477.156c0.034-5.708-1.062-11.369-3.216-16.654-2.161-5.285-5.342-10.092-9.365-14.145zM86.751 425.243v-130.133h216.89v130.133h-216.89zM1127.818 841.24l-61.159 61.159h-849.774v-390.4h130.133c11.503 0 22.539-4.571 30.673-12.705s12.705-19.168 12.705-30.673v-216.89c0-11.503-4.571-22.539-12.705-30.673s-19.168-12.705-30.673-12.705h-130.133v-86.756h824.177v173.51c-0.034 5.708 1.062 11.369 3.216 16.654 2.161 5.285 5.342 10.092 9.365 14.145l74.173 73.742v441.589z"],"width":1214.5714285714287,"attrs":[{},{}],"tags":["arduino-boards"],"grid":14,"isMulticolor":false,"isMulticolor2":false},"attrs":[{},{}],"properties":{"order":7,"id":7,"name":"arduino-boards","prevSize":28,"code":59650},"setIdx":0,"setId":1,"iconIdx":12},{"icon":{"paths":["M1021.954 918.445l-171.299-652.491c-2.901-9.738-9.491-17.956-18.363-22.903-8.876-4.946-19.333-6.228-29.138-3.571l-141.319 35.427v-230.085c0-10.325-4.102-20.227-11.403-27.529s-17.201-11.403-27.528-11.403h-155.725c-10.327 0-20.226 4.101-27.529 11.403-7.301 7.302-11.403 17.203-11.403 27.529v116.794h-155.725v-77.863c0-10.325-4.101-20.227-11.403-27.529s-17.203-11.403-27.529-11.403h-194.658c-10.325 0-20.227 4.101-27.529 11.403s-11.403 17.203-11.403 27.529v895.424c0 10.327 4.101 20.226 11.403 27.528s17.203 11.403 27.529 11.403h583.972c10.327 0 20.226-4.102 27.528-11.403s11.403-17.201 11.403-27.528v-454.332l119.909 456.668c2.207 8.565 7.265 16.124 14.34 21.433 7.079 5.308 15.751 8.044 24.591 7.764 3.364 0.379 6.758 0.379 10.123 0l164.678-43.212c9.975-2.589 18.518-9.032 23.75-17.908 2.581-4.721 4.156-9.926 4.627-15.288 0.467-5.361-0.178-10.759-1.9-15.857v0zM194.659 940.247h-116.794v-817.56h116.794v817.56zM428.248 940.247h-155.725v-700.766h155.725v700.766zM583.973 940.247h-77.863v-856.491h77.863v856.491zM847.15 923.896l-151.442-576.964 89.543-23.748 151.442 578.132-89.543 22.58z"],"attrs":[{}],"tags":["arduino-library"],"grid":14,"isMulticolor":false,"isMulticolor2":false},"attrs":[{}],"properties":{"order":691,"id":8,"name":"arduino-library","prevSize":28,"code":59651},"setIdx":0,"setId":1,"iconIdx":13},{"icon":{"paths":["M1189.198 204.801h-542.21l-189.437-189.951c-4.784-4.746-10.457-8.499-16.696-11.048s-12.918-3.84-19.656-3.801h-358.398c-13.579 0-26.602 5.394-36.204 14.997s-14.997 22.624-14.997 36.204v921.597c0 13.581 5.394 26.601 14.997 36.203s22.624 14.998 36.204 14.998h1126.397c13.581 0 26.601-5.395 36.203-14.998s14.998-22.621 14.998-36.203v-716.798c0-13.579-5.395-26.602-14.998-36.204s-22.621-14.997-36.203-14.997zM114.001 102.4h286.208l102.4 102.4h-388.606v-102.4zM1137.998 921.598h-1023.998v-614.398h1023.998v614.398z"],"width":1252,"attrs":[{}],"tags":["arduino-folder"],"grid":14,"isMulticolor":false,"isMulticolor2":false},"attrs":[{}],"properties":{"order":692,"id":9,"name":"arduino-folder","prevSize":28,"code":59652},"setIdx":0,"setId":1,"iconIdx":14},{"icon":{"paths":["M512.083 959.936c118.817 0 232.769-47.2 316.781-131.213 84.019-84.019 131.219-197.969 131.219-316.785 0-8.487-3.373-16.627-9.376-22.628-5.997-6.001-14.138-9.373-22.624-9.373s-16.627 3.372-22.63 9.373c-5.997 6.001-9.37 14.141-9.37 22.627-0.019 87.81-30.131 172.959-85.318 241.26s-132.115 115.622-217.962 134.086c-85.848 18.458-175.428 6.931-253.811-32.646-78.383-39.584-140.833-104.832-176.941-184.87-36.108-80.045-43.693-170.045-21.49-255.001s72.852-159.737 143.505-211.878c70.653-52.141 157.042-78.492 244.768-74.662s171.487 37.612 237.33 95.712h-158.081c-8.487 0-16.626 3.372-22.627 9.373s-9.373 14.141-9.373 22.627c0 8.487 3.372 16.627 9.373 22.628s14.14 9.372 22.627 9.372h224.001c8.486 0 16.627-3.371 22.624-9.372 6.003-6.001 9.376-14.141 9.376-22.628v-224c0-8.487-3.373-16.626-9.376-22.627-5.997-6.001-14.138-9.373-22.624-9.373s-16.627 3.371-22.63 9.373c-5.997 6.001-9.37 14.14-9.37 22.627v136.96c-55.162-46.332-120.678-78.68-191.002-94.301s-143.375-14.052-212.963 4.571c-69.588 18.623-133.659 53.753-186.78 102.41s-93.725 109.405-118.369 177.096c-24.644 67.69-32.602 140.324-23.199 211.745 9.404 71.419 35.891 139.521 77.216 198.523 41.325 59.008 96.27 107.174 160.174 140.422s134.885 50.598 206.922 50.573v0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[{}]},"tags":["reload"],"grid":14},"attrs":[{}],"properties":{"order":681,"id":10,"name":"reload","prevSize":28,"code":59648},"setIdx":0,"setId":1,"iconIdx":15},{"icon":{"paths":["M846.857 600c34.857 20 46.857 65.143 26.857 100l-36.571 62.857c-20 34.857-65.143 46.857-100 26.857l-152-87.429v175.429c0 40-33.143 73.143-73.143 73.143h-73.143c-40 0-73.143-33.143-73.143-73.143v-175.429l-152 87.429c-34.857 20-80 8-100-26.857l-36.571-62.857c-20-34.857-8-80 26.857-100l152-88-152-88c-34.857-20-46.857-65.143-26.857-100l36.571-62.857c20-34.857 65.143-46.857 100-26.857l152 87.429v-175.429c0-40 33.143-73.143 73.143-73.143h73.143c40 0 73.143 33.143 73.143 73.143v175.429l152-87.429c34.857-20 80-8 100 26.857l36.571 62.857c20 34.857 8 80-26.857 100l-152 88z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["asterisk"],"defaultCode":61545,"grid":14},"attrs":[],"properties":{"name":"asterisk","id":11,"order":679,"prevSize":28,"code":61545},"setIdx":0,"setId":1,"iconIdx":16},{"icon":{"paths":["M804.571 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-237.714v237.714c0 30.286-24.571 54.857-54.857 54.857h-109.714c-30.286 0-54.857-24.571-54.857-54.857v-237.714h-237.714c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h237.714v-237.714c0-30.286 24.571-54.857 54.857-54.857h109.714c30.286 0 54.857 24.571 54.857 54.857v237.714h237.714c30.286 0 54.857 24.571 54.857 54.857z"],"width":804.5714285714286,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["plus"],"defaultCode":61543,"grid":14},"attrs":[],"properties":{"name":"plus","id":12,"order":3,"prevSize":28,"code":61543},"setIdx":0,"setId":1,"iconIdx":17},{"icon":{"paths":["M402.286 717.714v137.143c0 12.571-10.286 22.857-22.857 22.857h-137.143c-12.571 0-22.857-10.286-22.857-22.857v-137.143c0-12.571 10.286-22.857 22.857-22.857h137.143c12.571 0 22.857 10.286 22.857 22.857zM582.857 374.857c0 108.571-73.714 150.286-128 180.571-33.714 19.429-54.857 58.857-54.857 75.429v0c0 12.571-9.714 27.429-22.857 27.429h-137.143c-12.571 0-20.571-19.429-20.571-32v-25.714c0-69.143 68.571-128.571 118.857-151.429 44-20 62.286-38.857 62.286-75.429 0-32-41.714-60.571-88-60.571-25.714 0-49.143 8-61.714 16.571-13.714 9.714-27.429 23.429-61.143 65.714-4.571 5.714-11.429 9.143-17.714 9.143-5.143 0-9.714-1.714-14.286-4.571l-93.714-71.429c-9.714-7.429-12-20-5.714-30.286 61.714-102.286 148.571-152 265.143-152 122.286 0 259.429 97.714 259.429 228.571z"],"width":634.88,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["question"],"defaultCode":61736,"grid":14},"attrs":[],"properties":{"name":"question","id":13,"order":4,"prevSize":28,"code":61736},"setIdx":0,"setId":1,"iconIdx":18},{"icon":{"paths":["M804.571 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-694.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h694.857c30.286 0 54.857 24.571 54.857 54.857z"],"width":804.5714285714286,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["minus"],"defaultCode":61544,"grid":14},"attrs":[],"properties":{"name":"minus","id":14,"order":5,"prevSize":28,"code":61544},"setIdx":0,"setId":1,"iconIdx":19},{"icon":{"paths":["M877.714 128v640c0 80.571-120.571 109.714-182.857 109.714s-182.857-29.143-182.857-109.714 120.571-109.714 182.857-109.714c37.714 0 75.429 6.857 109.714 22.286v-306.857l-438.857 135.429v405.143c0 80.571-120.571 109.714-182.857 109.714s-182.857-29.143-182.857-109.714 120.571-109.714 182.857-109.714c37.714 0 75.429 6.857 109.714 22.286v-552.571c0-24 16-45.143 38.857-52.571l475.429-146.286c5.143-1.714 10.286-2.286 16-2.286 30.286 0 54.857 24.571 54.857 54.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["music"],"defaultCode":61441,"grid":14},"attrs":[],"properties":{"name":"music","id":15,"order":7,"prevSize":28,"code":61441},"setIdx":0,"setId":1,"iconIdx":20},{"icon":{"paths":["M658.286 475.429c0-141.143-114.857-256-256-256s-256 114.857-256 256 114.857 256 256 256 256-114.857 256-256zM950.857 950.857c0 40-33.143 73.143-73.143 73.143-19.429 0-38.286-8-51.429-21.714l-196-195.429c-66.857 46.286-146.857 70.857-228 70.857-222.286 0-402.286-180-402.286-402.286s180-402.286 402.286-402.286 402.286 180 402.286 402.286c0 81.143-24.571 161.143-70.857 228l196 196c13.143 13.143 21.143 32 21.143 51.429z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["search"],"defaultCode":61442,"grid":14},"attrs":[],"properties":{"name":"search","id":16,"order":8,"prevSize":28,"code":61442},"setIdx":0,"setId":1,"iconIdx":21},{"icon":{"paths":["M950.857 859.429v-438.857c-12 13.714-25.143 26.286-39.429 37.714-81.714 62.857-164 126.857-243.429 193.143-42.857 36-96 80-155.429 80h-1.143c-59.429 0-112.571-44-155.429-80-79.429-66.286-161.714-130.286-243.429-193.143-14.286-11.429-27.429-24-39.429-37.714v438.857c0 9.714 8.571 18.286 18.286 18.286h841.143c9.714 0 18.286-8.571 18.286-18.286zM950.857 258.857c0-14.286 3.429-39.429-18.286-39.429h-841.143c-9.714 0-18.286 8.571-18.286 18.286 0 65.143 32.571 121.714 84 162.286 76.571 60 153.143 120.571 229.143 181.143 30.286 24.571 85.143 77.143 125.143 77.143h1.143c40 0 94.857-52.571 125.143-77.143 76-60.571 152.571-121.143 229.143-181.143 37.143-29.143 84-92.571 84-141.143zM1024 237.714v621.714c0 50.286-41.143 91.429-91.429 91.429h-841.143c-50.286 0-91.429-41.143-91.429-91.429v-621.714c0-50.286 41.143-91.429 91.429-91.429h841.143c50.286 0 91.429 41.143 91.429 91.429z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["envelope-o"],"defaultCode":61443,"grid":14},"attrs":[],"properties":{"name":"envelope-o","id":17,"order":9,"prevSize":28,"code":61443},"setIdx":0,"setId":1,"iconIdx":22},{"icon":{"paths":["M512 950.857c-9.143 0-18.286-3.429-25.143-10.286l-356.571-344c-4.571-4-130.286-118.857-130.286-256 0-167.429 102.286-267.429 273.143-267.429 100 0 193.714 78.857 238.857 123.429 45.143-44.571 138.857-123.429 238.857-123.429 170.857 0 273.143 100 273.143 267.429 0 137.143-125.714 252-130.857 257.143l-356 342.857c-6.857 6.857-16 10.286-25.143 10.286z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["heart"],"defaultCode":61444,"grid":14},"attrs":[],"properties":{"name":"heart","id":18,"order":10,"prevSize":28,"code":61444},"setIdx":0,"setId":1,"iconIdx":23},{"icon":{"paths":["M950.857 369.714c0 10.286-7.429 20-14.857 27.429l-207.429 202.286 49.143 285.714c0.571 4 0.571 7.429 0.571 11.429 0 14.857-6.857 28.571-23.429 28.571-8 0-16-2.857-22.857-6.857l-256.571-134.857-256.571 134.857c-7.429 4-14.857 6.857-22.857 6.857-16.571 0-24-13.714-24-28.571 0-4 0.571-7.429 1.143-11.429l49.143-285.714-208-202.286c-6.857-7.429-14.286-17.143-14.286-27.429 0-17.143 17.714-24 32-26.286l286.857-41.714 128.571-260c5.143-10.857 14.857-23.429 28-23.429s22.857 12.571 28 23.429l128.571 260 286.857 41.714c13.714 2.286 32 9.143 32 26.286z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["star"],"defaultCode":61445,"grid":14},"attrs":[],"properties":{"name":"star","id":19,"order":11,"prevSize":28,"code":61445},"setIdx":0,"setId":1,"iconIdx":24},{"icon":{"paths":["M649.714 573.714l174.857-169.714-241.143-35.429-108-218.286-108 218.286-241.143 35.429 174.857 169.714-41.714 240.571 216-113.714 215.429 113.714zM950.857 369.714c0 10.286-7.429 20-14.857 27.429l-207.429 202.286 49.143 285.714c0.571 4 0.571 7.429 0.571 11.429 0 15.429-6.857 28.571-23.429 28.571-8 0-16-2.857-22.857-6.857l-256.571-134.857-256.571 134.857c-7.429 4-14.857 6.857-22.857 6.857-16.571 0-24-13.714-24-28.571 0-4 0.571-7.429 1.143-11.429l49.143-285.714-208-202.286c-6.857-7.429-14.286-17.143-14.286-27.429 0-17.143 17.714-24 32-26.286l286.857-41.714 128.571-260c5.143-10.857 14.857-23.429 28-23.429s22.857 12.571 28 23.429l128.571 260 286.857 41.714c13.714 2.286 32 9.143 32 26.286z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["star-o"],"defaultCode":61446,"grid":14},"attrs":[],"properties":{"name":"star-o","id":20,"order":12,"prevSize":28,"code":61446},"setIdx":0,"setId":1,"iconIdx":25},{"icon":{"paths":["M731.429 799.429c0 83.429-54.857 151.429-121.714 151.429h-488c-66.857 0-121.714-68-121.714-151.429 0-150.286 37.143-324 186.857-324 46.286 45.143 109.143 73.143 178.857 73.143s132.571-28 178.857-73.143c149.714 0 186.857 173.714 186.857 324zM585.143 292.571c0 121.143-98.286 219.429-219.429 219.429s-219.429-98.286-219.429-219.429 98.286-219.429 219.429-219.429 219.429 98.286 219.429 219.429z"],"width":731.4285714285713,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["user"],"defaultCode":61447,"grid":14},"attrs":[],"properties":{"name":"user","id":21,"order":13,"prevSize":28,"code":61447},"setIdx":0,"setId":1,"iconIdx":26},{"icon":{"paths":["M219.429 914.286v-73.143c0-20-16.571-36.571-36.571-36.571h-73.143c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h73.143c20 0 36.571-16.571 36.571-36.571zM219.429 694.857v-73.143c0-20-16.571-36.571-36.571-36.571h-73.143c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h73.143c20 0 36.571-16.571 36.571-36.571zM219.429 475.429v-73.143c0-20-16.571-36.571-36.571-36.571h-73.143c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h73.143c20 0 36.571-16.571 36.571-36.571zM804.571 914.286v-292.571c0-20-16.571-36.571-36.571-36.571h-438.857c-20 0-36.571 16.571-36.571 36.571v292.571c0 20 16.571 36.571 36.571 36.571h438.857c20 0 36.571-16.571 36.571-36.571zM219.429 256v-73.143c0-20-16.571-36.571-36.571-36.571h-73.143c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h73.143c20 0 36.571-16.571 36.571-36.571zM1024 914.286v-73.143c0-20-16.571-36.571-36.571-36.571h-73.143c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h73.143c20 0 36.571-16.571 36.571-36.571zM804.571 475.429v-292.571c0-20-16.571-36.571-36.571-36.571h-438.857c-20 0-36.571 16.571-36.571 36.571v292.571c0 20 16.571 36.571 36.571 36.571h438.857c20 0 36.571-16.571 36.571-36.571zM1024 694.857v-73.143c0-20-16.571-36.571-36.571-36.571h-73.143c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h73.143c20 0 36.571-16.571 36.571-36.571zM1024 475.429v-73.143c0-20-16.571-36.571-36.571-36.571h-73.143c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h73.143c20 0 36.571-16.571 36.571-36.571zM1024 256v-73.143c0-20-16.571-36.571-36.571-36.571h-73.143c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h73.143c20 0 36.571-16.571 36.571-36.571zM1097.143 164.571v768c0 50.286-41.143 91.429-91.429 91.429h-914.286c-50.286 0-91.429-41.143-91.429-91.429v-768c0-50.286 41.143-91.429 91.429-91.429h914.286c50.286 0 91.429 41.143 91.429 91.429z"],"width":1097.142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["film"],"defaultCode":61448,"grid":14},"attrs":[],"properties":{"name":"film","id":22,"order":14,"prevSize":28,"code":61448},"setIdx":0,"setId":1,"iconIdx":27},{"icon":{"paths":["M438.857 585.143v219.429c0 40-33.143 73.143-73.143 73.143h-292.571c-40 0-73.143-33.143-73.143-73.143v-219.429c0-40 33.143-73.143 73.143-73.143h292.571c40 0 73.143 33.143 73.143 73.143zM438.857 146.286v219.429c0 40-33.143 73.143-73.143 73.143h-292.571c-40 0-73.143-33.143-73.143-73.143v-219.429c0-40 33.143-73.143 73.143-73.143h292.571c40 0 73.143 33.143 73.143 73.143zM950.857 585.143v219.429c0 40-33.143 73.143-73.143 73.143h-292.571c-40 0-73.143-33.143-73.143-73.143v-219.429c0-40 33.143-73.143 73.143-73.143h292.571c40 0 73.143 33.143 73.143 73.143zM950.857 146.286v219.429c0 40-33.143 73.143-73.143 73.143h-292.571c-40 0-73.143-33.143-73.143-73.143v-219.429c0-40 33.143-73.143 73.143-73.143h292.571c40 0 73.143 33.143 73.143 73.143z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["th-large"],"defaultCode":61449,"grid":14},"attrs":[],"properties":{"name":"th-large","id":23,"order":15,"prevSize":28,"code":61449},"setIdx":0,"setId":1,"iconIdx":28},{"icon":{"paths":["M292.571 713.143v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM292.571 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM658.286 713.143v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM292.571 128v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM658.286 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM1024 713.143v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM658.286 128v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM1024 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM1024 128v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["th"],"defaultCode":61450,"grid":14},"attrs":[],"properties":{"name":"th","id":24,"order":16,"prevSize":28,"code":61450},"setIdx":0,"setId":1,"iconIdx":29},{"icon":{"paths":["M292.571 713.143v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM292.571 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM1024 713.143v109.714c0 30.286-24.571 54.857-54.857 54.857h-548.571c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h548.571c30.286 0 54.857 24.571 54.857 54.857zM292.571 128v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM1024 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-548.571c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h548.571c30.286 0 54.857 24.571 54.857 54.857zM1024 128v109.714c0 30.286-24.571 54.857-54.857 54.857h-548.571c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h548.571c30.286 0 54.857 24.571 54.857 54.857z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["th-list"],"defaultCode":61451,"grid":14},"attrs":[],"properties":{"name":"th-list","id":25,"order":17,"prevSize":28,"code":61451},"setIdx":0,"setId":1,"iconIdx":30},{"icon":{"paths":["M725.322 782.343c3.477 3.448 6.237 7.547 8.118 12.069 1.885 4.515 2.853 9.364 2.853 14.259s-0.967 9.744-2.853 14.266c-1.881 4.515-4.641 8.623-8.118 12.069-3.448 3.472-7.547 6.232-12.069 8.118-4.515 1.881-9.364 2.848-14.259 2.848s-9.744-0.967-14.266-2.848c-4.522-1.885-8.623-4.646-12.069-8.118l-270.371-270.375-270.372 270.375c-3.448 3.472-7.549 6.232-12.069 8.118-4.519 1.881-9.366 2.848-14.263 2.848s-9.744-0.967-14.263-2.848c-4.519-1.885-8.622-4.646-12.069-8.118-3.474-3.448-6.235-7.555-8.118-12.069-1.884-4.522-2.853-9.37-2.853-14.266s0.97-9.744 2.853-14.259c1.884-4.522 4.643-8.623 8.118-12.069l270.372-270.375-270.372-270.372c-3.456-3.456-6.201-7.565-8.072-12.082s-2.835-9.36-2.835-14.25c0-4.891 0.964-9.732 2.835-14.25s4.617-8.626 8.072-12.081c3.456-3.456 7.564-6.201 12.081-8.072s9.361-2.835 14.25-2.835c4.891 0 9.732 0.964 14.25 2.835s8.626 4.617 12.081 8.072l270.372 270.372 270.371-270.372c6.984-6.983 16.455-10.909 26.335-10.909 9.875 0 19.347 3.923 26.33 10.909s10.909 16.456 10.909 26.333c0 9.877-3.923 19.348-10.909 26.333l-270.371 270.372 270.371 270.375z"],"width":804.5714285714286,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[{}]},"tags":["close","remove","times"],"defaultCode":61453,"grid":14},"attrs":[{}],"properties":{"name":"close, remove, times","id":26,"order":19,"prevSize":28,"code":61453},"setIdx":0,"setId":1,"iconIdx":31},{"icon":{"paths":["M585.143 457.143v36.571c0 9.714-8.571 18.286-18.286 18.286h-128v128c0 9.714-8.571 18.286-18.286 18.286h-36.571c-9.714 0-18.286-8.571-18.286-18.286v-128h-128c-9.714 0-18.286-8.571-18.286-18.286v-36.571c0-9.714 8.571-18.286 18.286-18.286h128v-128c0-9.714 8.571-18.286 18.286-18.286h36.571c9.714 0 18.286 8.571 18.286 18.286v128h128c9.714 0 18.286 8.571 18.286 18.286zM658.286 475.429c0-141.143-114.857-256-256-256s-256 114.857-256 256 114.857 256 256 256 256-114.857 256-256zM950.857 950.857c0 40.571-32.571 73.143-73.143 73.143-19.429 0-38.286-8-51.429-21.714l-196-195.429c-66.857 46.286-146.857 70.857-228 70.857-222.286 0-402.286-180-402.286-402.286s180-402.286 402.286-402.286 402.286 180 402.286 402.286c0 81.143-24.571 161.143-70.857 228l196 196c13.143 13.143 21.143 32 21.143 51.429z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["search-plus"],"defaultCode":61454,"grid":14},"attrs":[],"properties":{"name":"search-plus","id":27,"order":20,"prevSize":28,"code":61454},"setIdx":0,"setId":1,"iconIdx":32},{"icon":{"paths":["M585.143 457.143v36.571c0 9.714-8.571 18.286-18.286 18.286h-329.143c-9.714 0-18.286-8.571-18.286-18.286v-36.571c0-9.714 8.571-18.286 18.286-18.286h329.143c9.714 0 18.286 8.571 18.286 18.286zM658.286 475.429c0-141.143-114.857-256-256-256s-256 114.857-256 256 114.857 256 256 256 256-114.857 256-256zM950.857 950.857c0 40.571-32.571 73.143-73.143 73.143-19.429 0-38.286-8-51.429-21.714l-196-195.429c-66.857 46.286-146.857 70.857-228 70.857-222.286 0-402.286-180-402.286-402.286s180-402.286 402.286-402.286 402.286 180 402.286 402.286c0 81.143-24.571 161.143-70.857 228l196 196c13.143 13.143 21.143 32 21.143 51.429z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["search-minus"],"defaultCode":61456,"grid":14},"attrs":[],"properties":{"name":"search-minus","id":28,"order":21,"prevSize":28,"code":61456},"setIdx":0,"setId":1,"iconIdx":33},{"icon":{"paths":["M877.714 512c0 241.714-197.143 438.857-438.857 438.857s-438.857-197.143-438.857-438.857c0-138.857 64-266.857 175.429-350.286 32.571-24.571 78.286-18.286 102.286 14.286 24.571 32 17.714 78.286-14.286 102.286-74.286 56-117.143 141.143-117.143 233.714 0 161.143 131.429 292.571 292.571 292.571s292.571-131.429 292.571-292.571c0-92.571-42.857-177.714-117.143-233.714-32-24-38.857-70.286-14.286-102.286 24-32.571 70.286-38.857 102.286-14.286 111.429 83.429 175.429 211.429 175.429 350.286zM512 73.143v365.714c0 40-33.143 73.143-73.143 73.143s-73.143-33.143-73.143-73.143v-365.714c0-40 33.143-73.143 73.143-73.143s73.143 33.143 73.143 73.143z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["power-off"],"defaultCode":61457,"grid":14},"attrs":[],"properties":{"name":"power-off","id":29,"order":22,"prevSize":28,"code":61457},"setIdx":0,"setId":1,"iconIdx":34},{"icon":{"paths":["M146.286 822.857v109.714c0 10.286-8 18.286-18.286 18.286h-109.714c-10.286 0-18.286-8-18.286-18.286v-109.714c0-10.286 8-18.286 18.286-18.286h109.714c10.286 0 18.286 8 18.286 18.286zM365.714 749.714v182.857c0 10.286-8 18.286-18.286 18.286h-109.714c-10.286 0-18.286-8-18.286-18.286v-182.857c0-10.286 8-18.286 18.286-18.286h109.714c10.286 0 18.286 8 18.286 18.286zM585.143 603.429v329.143c0 10.286-8 18.286-18.286 18.286h-109.714c-10.286 0-18.286-8-18.286-18.286v-329.143c0-10.286 8-18.286 18.286-18.286h109.714c10.286 0 18.286 8 18.286 18.286zM804.571 384v548.571c0 10.286-8 18.286-18.286 18.286h-109.714c-10.286 0-18.286-8-18.286-18.286v-548.571c0-10.286 8-18.286 18.286-18.286h109.714c10.286 0 18.286 8 18.286 18.286zM1024 91.429v841.143c0 10.286-8 18.286-18.286 18.286h-109.714c-10.286 0-18.286-8-18.286-18.286v-841.143c0-10.286 8-18.286 18.286-18.286h109.714c10.286 0 18.286 8 18.286 18.286z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["signal"],"defaultCode":61458,"grid":14},"attrs":[],"properties":{"name":"signal","id":30,"order":23,"prevSize":28,"code":61458},"setIdx":0,"setId":1,"iconIdx":35},{"icon":{"paths":["M585.143 512c0-80.571-65.714-146.286-146.286-146.286s-146.286 65.714-146.286 146.286 65.714 146.286 146.286 146.286 146.286-65.714 146.286-146.286zM877.714 449.714v126.857c0 8.571-6.857 18.857-16 20.571l-105.714 16c-6.286 18.286-13.143 35.429-22.286 52 19.429 28 40 53.143 61.143 78.857 3.429 4 5.714 9.143 5.714 14.286s-1.714 9.143-5.143 13.143c-13.714 18.286-90.857 102.286-110.286 102.286-5.143 0-10.286-2.286-14.857-5.143l-78.857-61.714c-16.571 8.571-34.286 16-52 21.714-4 34.857-7.429 72-16.571 106.286-2.286 9.143-10.286 16-20.571 16h-126.857c-10.286 0-19.429-7.429-20.571-17.143l-16-105.143c-17.714-5.714-34.857-12.571-51.429-21.143l-80.571 61.143c-4 3.429-9.143 5.143-14.286 5.143s-10.286-2.286-14.286-6.286c-30.286-27.429-70.286-62.857-94.286-96-2.857-4-4-8.571-4-13.143 0-5.143 1.714-9.143 4.571-13.143 19.429-26.286 40.571-51.429 60-78.286-9.714-18.286-17.714-37.143-23.429-56.571l-104.571-15.429c-9.714-1.714-16.571-10.857-16.571-20.571v-126.857c0-8.571 6.857-18.857 15.429-20.571l106.286-16c5.714-18.286 13.143-35.429 22.286-52.571-19.429-27.429-40-53.143-61.143-78.857-3.429-4-5.714-8.571-5.714-13.714s2.286-9.143 5.143-13.143c13.714-18.857 90.857-102.286 110.286-102.286 5.143 0 10.286 2.286 14.857 5.714l78.857 61.143c16.571-8.571 34.286-16 52-21.714 4-34.857 7.429-72 16.571-106.286 2.286-9.143 10.286-16 20.571-16h126.857c10.286 0 19.429 7.429 20.571 17.143l16 105.143c17.714 5.714 34.857 12.571 51.429 21.143l81.143-61.143c3.429-3.429 8.571-5.143 13.714-5.143s10.286 2.286 14.286 5.714c30.286 28 70.286 63.429 94.286 97.143 2.857 3.429 4 8 4 12.571 0 5.143-1.714 9.143-4.571 13.143-19.429 26.286-40.571 51.429-60 78.286 9.714 18.286 17.714 37.143 23.429 56l104.571 16c9.714 1.714 16.571 10.857 16.571 20.571z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["cog","gear"],"defaultCode":61459,"grid":14},"attrs":[],"properties":{"name":"cog, gear","id":31,"order":24,"prevSize":28,"code":61459},"setIdx":0,"setId":1,"iconIdx":36},{"icon":{"paths":["M292.571 420.571v329.143c0 10.286-8 18.286-18.286 18.286h-36.571c-10.286 0-18.286-8-18.286-18.286v-329.143c0-10.286 8-18.286 18.286-18.286h36.571c10.286 0 18.286 8 18.286 18.286zM438.857 420.571v329.143c0 10.286-8 18.286-18.286 18.286h-36.571c-10.286 0-18.286-8-18.286-18.286v-329.143c0-10.286 8-18.286 18.286-18.286h36.571c10.286 0 18.286 8 18.286 18.286zM585.143 420.571v329.143c0 10.286-8 18.286-18.286 18.286h-36.571c-10.286 0-18.286-8-18.286-18.286v-329.143c0-10.286 8-18.286 18.286-18.286h36.571c10.286 0 18.286 8 18.286 18.286zM658.286 834.286v-541.714h-512v541.714c0 27.429 15.429 43.429 18.286 43.429h475.429c2.857 0 18.286-16 18.286-43.429zM274.286 219.429h256l-27.429-66.857c-1.714-2.286-6.857-5.714-9.714-6.286h-181.143c-3.429 0.571-8 4-9.714 6.286zM804.571 237.714v36.571c0 10.286-8 18.286-18.286 18.286h-54.857v541.714c0 62.857-41.143 116.571-91.429 116.571h-475.429c-50.286 0-91.429-51.429-91.429-114.286v-544h-54.857c-10.286 0-18.286-8-18.286-18.286v-36.571c0-10.286 8-18.286 18.286-18.286h176.571l40-95.429c11.429-28 45.714-50.857 76-50.857h182.857c30.286 0 64.571 22.857 76 50.857l40 95.429h176.571c10.286 0 18.286 8 18.286 18.286z"],"width":804.5714285714286,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["trash-o"],"defaultCode":61460,"grid":14},"attrs":[],"properties":{"name":"trash-o","id":32,"order":25,"prevSize":28,"code":61460},"setIdx":0,"setId":1,"iconIdx":37},{"icon":{"paths":["M804.571 566.857v274.286c0 20-16.571 36.571-36.571 36.571h-219.429v-219.429h-146.286v219.429h-219.429c-20 0-36.571-16.571-36.571-36.571v-274.286c0-1.143 0.571-2.286 0.571-3.429l328.571-270.857 328.571 270.857c0.571 1.143 0.571 2.286 0.571 3.429zM932 527.429l-35.429 42.286c-2.857 3.429-7.429 5.714-12 6.286h-1.714c-4.571 0-8.571-1.143-12-4l-395.429-329.714-395.429 329.714c-4 2.857-8.571 4.571-13.714 4-4.571-0.571-9.143-2.857-12-6.286l-35.429-42.286c-6.286-7.429-5.143-19.429 2.286-25.714l410.857-342.286c24-20 62.857-20 86.857 0l139.429 116.571v-111.429c0-10.286 8-18.286 18.286-18.286h109.714c10.286 0 18.286 8 18.286 18.286v233.143l125.143 104c7.429 6.286 8.571 18.286 2.286 25.714z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["home"],"defaultCode":61461,"grid":14},"attrs":[],"properties":{"name":"home","id":33,"order":26,"prevSize":28,"code":61461},"setIdx":0,"setId":1,"iconIdx":38},{"icon":{"paths":["M838.857 217.143c21.143 21.143 38.857 63.429 38.857 93.714v658.286c0 30.286-24.571 54.857-54.857 54.857h-768c-30.286 0-54.857-24.571-54.857-54.857v-914.286c0-30.286 24.571-54.857 54.857-54.857h512c30.286 0 72.571 17.714 93.714 38.857zM585.143 77.714v214.857h214.857c-3.429-9.714-8.571-19.429-12.571-23.429l-178.857-178.857c-4-4-13.714-9.143-23.429-12.571zM804.571 950.857v-585.143h-237.714c-30.286 0-54.857-24.571-54.857-54.857v-237.714h-438.857v877.714h731.429z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["file-o"],"defaultCode":61462,"grid":14},"attrs":[],"properties":{"name":"file-o","id":34,"order":27,"prevSize":28,"code":61462},"setIdx":0,"setId":1,"iconIdx":39},{"icon":{"paths":["M512 310.857v256c0 10.286-8 18.286-18.286 18.286h-182.857c-10.286 0-18.286-8-18.286-18.286v-36.571c0-10.286 8-18.286 18.286-18.286h128v-201.143c0-10.286 8-18.286 18.286-18.286h36.571c10.286 0 18.286 8 18.286 18.286zM749.714 512c0-171.429-139.429-310.857-310.857-310.857s-310.857 139.429-310.857 310.857 139.429 310.857 310.857 310.857 310.857-139.429 310.857-310.857zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["clock-o"],"defaultCode":61463,"grid":14},"attrs":[],"properties":{"name":"clock-o","id":35,"order":28,"prevSize":28,"code":61463},"setIdx":0,"setId":1,"iconIdx":40},{"icon":{"paths":["M731.429 768c0-20-16.571-36.571-36.571-36.571s-36.571 16.571-36.571 36.571 16.571 36.571 36.571 36.571 36.571-16.571 36.571-36.571zM877.714 768c0-20-16.571-36.571-36.571-36.571s-36.571 16.571-36.571 36.571 16.571 36.571 36.571 36.571 36.571-16.571 36.571-36.571zM950.857 640v182.857c0 30.286-24.571 54.857-54.857 54.857h-841.143c-30.286 0-54.857-24.571-54.857-54.857v-182.857c0-30.286 24.571-54.857 54.857-54.857h265.714l77.143 77.714c21.143 20.571 48.571 32 77.714 32s56.571-11.429 77.714-32l77.714-77.714h265.143c30.286 0 54.857 24.571 54.857 54.857zM765.143 314.857c5.714 13.714 2.857 29.714-8 40l-256 256c-6.857 7.429-16.571 10.857-25.714 10.857s-18.857-3.429-25.714-10.857l-256-256c-10.857-10.286-13.714-26.286-8-40 5.714-13.143 18.857-22.286 33.714-22.286h146.286v-256c0-20 16.571-36.571 36.571-36.571h146.286c20 0 36.571 16.571 36.571 36.571v256h146.286c14.857 0 28 9.143 33.714 22.286z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["download"],"defaultCode":61465,"grid":14},"attrs":[],"properties":{"name":"download","id":36,"order":30,"prevSize":28,"code":61465},"setIdx":0,"setId":1,"iconIdx":41},{"icon":{"paths":["M640 530.286c0 5.143-2.286 9.714-5.714 13.714l-182.286 182.286c-4 3.429-8.571 5.143-13.143 5.143s-9.143-1.714-13.143-5.143l-182.857-182.857c-5.143-5.714-6.857-13.143-4-20s9.714-11.429 17.143-11.429h109.714v-201.143c0-10.286 8-18.286 18.286-18.286h109.714c10.286 0 18.286 8 18.286 18.286v201.143h109.714c10.286 0 18.286 8 18.286 18.286zM438.857 201.143c-171.429 0-310.857 139.429-310.857 310.857s139.429 310.857 310.857 310.857 310.857-139.429 310.857-310.857-139.429-310.857-310.857-310.857zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857v0c242.286 0 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["arrow-circle-o-down"],"defaultCode":61466,"grid":14},"attrs":[],"properties":{"name":"arrow-circle-o-down","id":37,"order":31,"prevSize":28,"code":61466},"setIdx":0,"setId":1,"iconIdx":42},{"icon":{"paths":["M638.857 500.571c-2.857 6.857-9.714 11.429-17.143 11.429h-109.714v201.143c0 10.286-8 18.286-18.286 18.286h-109.714c-10.286 0-18.286-8-18.286-18.286v-201.143h-109.714c-10.286 0-18.286-8-18.286-18.286 0-5.143 2.286-9.714 5.714-13.714l182.286-182.286c4-3.429 8.571-5.143 13.143-5.143s9.143 1.714 13.143 5.143l182.857 182.857c5.143 5.714 6.857 13.143 4 20zM438.857 201.143c-171.429 0-310.857 139.429-310.857 310.857s139.429 310.857 310.857 310.857 310.857-139.429 310.857-310.857-139.429-310.857-310.857-310.857zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857v0c242.286 0 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["arrow-circle-o-up"],"defaultCode":61467,"grid":14},"attrs":[],"properties":{"name":"arrow-circle-o-up","id":38,"order":32,"prevSize":28,"code":61467},"setIdx":0,"setId":1,"iconIdx":43},{"icon":{"paths":["M584.571 548.571h180.571c-1.143-2.857-1.714-6.286-2.857-9.143l-121.143-283.429h-404.571l-121.143 283.429c-1.143 2.857-1.714 6.286-2.857 9.143h180.571l54.286 109.714h182.857zM877.714 565.714v275.429c0 20-16.571 36.571-36.571 36.571h-804.571c-20 0-36.571-16.571-36.571-36.571v-275.429c0-20.571 6.286-50.857 14.286-70.286l136-315.429c8-18.857 30.857-33.714 50.857-33.714h475.429c20 0 42.857 14.857 50.857 33.714l136 315.429c8 19.429 14.286 49.714 14.286 70.286z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["inbox"],"defaultCode":61468,"grid":14},"attrs":[],"properties":{"name":"inbox","id":39,"order":33,"prevSize":28,"code":61468},"setIdx":0,"setId":1,"iconIdx":44},{"icon":{"paths":["M676.571 512c0 13.143-6.857 25.143-18.286 31.429l-310.857 182.857c-5.714 3.429-12 5.143-18.286 5.143s-12.571-1.714-18.286-4.571c-11.429-6.857-18.286-18.857-18.286-32v-365.714c0-13.143 6.857-25.143 18.286-32 11.429-6.286 25.714-6.286 36.571 0.571l310.857 182.857c11.429 6.286 18.286 18.286 18.286 31.429zM749.714 512c0-171.429-139.429-310.857-310.857-310.857s-310.857 139.429-310.857 310.857 139.429 310.857 310.857 310.857 310.857-139.429 310.857-310.857zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["play-circle-o"],"defaultCode":61469,"grid":14},"attrs":[],"properties":{"name":"play-circle-o","id":40,"order":34,"prevSize":28,"code":61469},"setIdx":0,"setId":1,"iconIdx":45},{"icon":{"paths":["M877.714 146.286v256c0 20-16.571 36.571-36.571 36.571h-256c-14.857 0-28-9.143-33.714-22.857-5.714-13.143-2.857-29.143 8-39.429l78.857-78.857c-53.714-49.714-124.571-78.286-199.429-78.286-161.143 0-292.571 131.429-292.571 292.571s131.429 292.571 292.571 292.571c90.857 0 174.857-41.143 230.857-113.714 2.857-4 8-6.286 13.143-6.857 5.143 0 10.286 1.714 14.286 5.143l78.286 78.857c6.857 6.286 6.857 17.143 1.143 24.571-83.429 100.571-206.857 158.286-337.714 158.286-241.714 0-438.857-197.143-438.857-438.857s197.143-438.857 438.857-438.857c112.571 0 221.714 45.143 302.286 121.143l74.286-73.714c10.286-10.857 26.286-13.714 40-8 13.143 5.714 22.286 18.857 22.286 33.714z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["repeat","rotate-right"],"defaultCode":61470,"grid":14},"attrs":[],"properties":{"name":"repeat, rotate-right","id":41,"order":35,"prevSize":28,"code":61470},"setIdx":0,"setId":1,"iconIdx":46},{"icon":{"paths":["M863.429 603.429c0 1.143 0 2.857-0.571 4-48.571 202.286-215.429 343.429-426.286 343.429-111.429 0-219.429-44-300.571-121.143l-73.714 73.714c-6.857 6.857-16 10.857-25.714 10.857-20 0-36.571-16.571-36.571-36.571v-256c0-20 16.571-36.571 36.571-36.571h256c20 0 36.571 16.571 36.571 36.571 0 9.714-4 18.857-10.857 25.714l-78.286 78.286c53.714 50.286 125.143 78.857 198.857 78.857 101.714 0 196-52.571 249.143-139.429 13.714-22.286 20.571-44 30.286-66.857 2.857-8 8.571-13.143 17.143-13.143h109.714c10.286 0 18.286 8.571 18.286 18.286zM877.714 146.286v256c0 20-16.571 36.571-36.571 36.571h-256c-20 0-36.571-16.571-36.571-36.571 0-9.714 4-18.857 10.857-25.714l78.857-78.857c-54.286-50.286-125.714-78.286-199.429-78.286-101.714 0-196 52.571-249.143 139.429-13.714 22.286-20.571 44-30.286 66.857-2.857 8-8.571 13.143-17.143 13.143h-113.714c-10.286 0-18.286-8.571-18.286-18.286v-4c49.143-202.857 217.714-343.429 428.571-343.429 112 0 221.143 44.571 302.286 121.143l74.286-73.714c6.857-6.857 16-10.857 25.714-10.857 20 0 36.571 16.571 36.571 36.571z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["refresh"],"defaultCode":61473,"grid":14},"attrs":[],"properties":{"name":"refresh","id":42,"order":36,"prevSize":28,"code":61473},"setIdx":0,"setId":1,"iconIdx":47},{"icon":{"paths":["M219.429 676.571v36.571c0 9.714-8.571 18.286-18.286 18.286h-36.571c-9.714 0-18.286-8.571-18.286-18.286v-36.571c0-9.714 8.571-18.286 18.286-18.286h36.571c9.714 0 18.286 8.571 18.286 18.286zM219.429 530.286v36.571c0 9.714-8.571 18.286-18.286 18.286h-36.571c-9.714 0-18.286-8.571-18.286-18.286v-36.571c0-9.714 8.571-18.286 18.286-18.286h36.571c9.714 0 18.286 8.571 18.286 18.286zM219.429 384v36.571c0 9.714-8.571 18.286-18.286 18.286h-36.571c-9.714 0-18.286-8.571-18.286-18.286v-36.571c0-9.714 8.571-18.286 18.286-18.286h36.571c9.714 0 18.286 8.571 18.286 18.286zM877.714 676.571v36.571c0 9.714-8.571 18.286-18.286 18.286h-548.571c-9.714 0-18.286-8.571-18.286-18.286v-36.571c0-9.714 8.571-18.286 18.286-18.286h548.571c9.714 0 18.286 8.571 18.286 18.286zM877.714 530.286v36.571c0 9.714-8.571 18.286-18.286 18.286h-548.571c-9.714 0-18.286-8.571-18.286-18.286v-36.571c0-9.714 8.571-18.286 18.286-18.286h548.571c9.714 0 18.286 8.571 18.286 18.286zM877.714 384v36.571c0 9.714-8.571 18.286-18.286 18.286h-548.571c-9.714 0-18.286-8.571-18.286-18.286v-36.571c0-9.714 8.571-18.286 18.286-18.286h548.571c9.714 0 18.286 8.571 18.286 18.286zM950.857 786.286v-475.429c0-9.714-8.571-18.286-18.286-18.286h-841.143c-9.714 0-18.286 8.571-18.286 18.286v475.429c0 9.714 8.571 18.286 18.286 18.286h841.143c9.714 0 18.286-8.571 18.286-18.286zM1024 164.571v621.714c0 50.286-41.143 91.429-91.429 91.429h-841.143c-50.286 0-91.429-41.143-91.429-91.429v-621.714c0-50.286 41.143-91.429 91.429-91.429h841.143c50.286 0 91.429 41.143 91.429 91.429z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["list-alt"],"defaultCode":61474,"grid":14},"attrs":[],"properties":{"name":"list-alt","id":43,"order":37,"prevSize":28,"code":61474},"setIdx":0,"setId":1,"iconIdx":48},{"icon":{"paths":["M182.857 438.857h292.571v-109.714c0-80.571-65.714-146.286-146.286-146.286s-146.286 65.714-146.286 146.286v109.714zM658.286 493.714v329.143c0 30.286-24.571 54.857-54.857 54.857h-548.571c-30.286 0-54.857-24.571-54.857-54.857v-329.143c0-30.286 24.571-54.857 54.857-54.857h18.286v-109.714c0-140.571 115.429-256 256-256s256 115.429 256 256v109.714h18.286c30.286 0 54.857 24.571 54.857 54.857z"],"width":658.2857142857142,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["lock"],"defaultCode":61475,"grid":14},"attrs":[],"properties":{"name":"lock","id":44,"order":38,"prevSize":28,"code":61475},"setIdx":0,"setId":1,"iconIdx":49},{"icon":{"paths":["M438.857 201.143v621.714c0 20-16.571 36.571-36.571 36.571-9.714 0-18.857-4-25.714-10.857l-190.286-190.286h-149.714c-20 0-36.571-16.571-36.571-36.571v-219.429c0-20 16.571-36.571 36.571-36.571h149.714l190.286-190.286c6.857-6.857 16-10.857 25.714-10.857 20 0 36.571 16.571 36.571 36.571z"],"width":438.85714285714283,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["volume-off"],"defaultCode":61478,"grid":14},"attrs":[],"properties":{"name":"volume-off","id":45,"order":41,"prevSize":28,"code":61478},"setIdx":0,"setId":1,"iconIdx":50},{"icon":{"paths":["M438.857 201.143v621.714c0 20-16.571 36.571-36.571 36.571-9.714 0-18.857-4-25.714-10.857l-190.286-190.286h-149.714c-20 0-36.571-16.571-36.571-36.571v-219.429c0-20 16.571-36.571 36.571-36.571h149.714l190.286-190.286c6.857-6.857 16-10.857 25.714-10.857 20 0 36.571 16.571 36.571 36.571zM658.286 512c0 57.143-34.857 112.571-88.571 134.286-4.571 2.286-9.714 2.857-14.286 2.857-20 0-36.571-16-36.571-36.571 0-43.429 66.286-31.429 66.286-100.571s-66.286-57.143-66.286-100.571c0-20.571 16.571-36.571 36.571-36.571 4.571 0 9.714 0.571 14.286 2.857 53.714 21.143 88.571 77.143 88.571 134.286z"],"width":658.2857142857142,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["volume-down"],"defaultCode":61479,"grid":14},"attrs":[],"properties":{"name":"volume-down","id":46,"order":42,"prevSize":28,"code":61479},"setIdx":0,"setId":1,"iconIdx":51},{"icon":{"paths":["M438.857 201.143v621.714c0 20-16.571 36.571-36.571 36.571-9.714 0-18.857-4-25.714-10.857l-190.286-190.286h-149.714c-20 0-36.571-16.571-36.571-36.571v-219.429c0-20 16.571-36.571 36.571-36.571h149.714l190.286-190.286c6.857-6.857 16-10.857 25.714-10.857 20 0 36.571 16.571 36.571 36.571zM658.286 512c0 57.143-34.857 112.571-88.571 134.286-4.571 2.286-9.714 2.857-14.286 2.857-20 0-36.571-16-36.571-36.571 0-43.429 66.286-31.429 66.286-100.571s-66.286-57.143-66.286-100.571c0-20.571 16.571-36.571 36.571-36.571 4.571 0 9.714 0.571 14.286 2.857 53.714 21.143 88.571 77.143 88.571 134.286zM804.571 512c0 116-69.714 224-177.143 269.143-4.571 1.714-9.714 2.857-14.286 2.857-20.571 0-37.143-16.571-37.143-36.571 0-16 9.143-26.857 22.286-33.714 15.429-8 29.714-14.857 43.429-25.143 56.571-41.143 89.714-106.857 89.714-176.571s-33.143-135.429-89.714-176.571c-13.714-10.286-28-17.143-43.429-25.143-13.143-6.857-22.286-17.714-22.286-33.714 0-20 16.571-36.571 36.571-36.571 5.143 0 10.286 1.143 14.857 2.857 107.429 45.143 177.143 153.143 177.143 269.143zM950.857 512c0 175.429-104.571 334.286-265.714 403.429-4.571 1.714-9.714 2.857-14.857 2.857-20 0-36.571-16.571-36.571-36.571 0-16.571 8.571-25.714 22.286-33.714 8-4.571 17.143-7.429 25.714-12 16-8.571 32-18.286 46.857-29.143 93.714-69.143 149.143-178.286 149.143-294.857s-55.429-225.714-149.143-294.857c-14.857-10.857-30.857-20.571-46.857-29.143-8.571-4.571-17.714-7.429-25.714-12-13.714-8-22.286-17.143-22.286-33.714 0-20 16.571-36.571 36.571-36.571 5.143 0 10.286 1.143 14.857 2.857 161.143 69.143 265.714 228 265.714 403.429z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["volume-up"],"defaultCode":61480,"grid":14},"attrs":[],"properties":{"name":"volume-up","id":47,"order":43,"prevSize":28,"code":61480},"setIdx":0,"setId":1,"iconIdx":52},{"icon":{"paths":["M219.429 658.286v73.143h-73.143v-73.143h73.143zM219.429 219.429v73.143h-73.143v-73.143h73.143zM658.286 219.429v73.143h-73.143v-73.143h73.143zM73.143 804h219.429v-218.857h-219.429v218.857zM73.143 365.714h219.429v-219.429h-219.429v219.429zM512 365.714h219.429v-219.429h-219.429v219.429zM365.714 512v365.714h-365.714v-365.714h365.714zM658.286 804.571v73.143h-73.143v-73.143h73.143zM804.571 804.571v73.143h-73.143v-73.143h73.143zM804.571 512v219.429h-219.429v-73.143h-73.143v219.429h-73.143v-365.714h219.429v73.143h73.143v-73.143h73.143zM365.714 73.143v365.714h-365.714v-365.714h365.714zM804.571 73.143v365.714h-365.714v-365.714h365.714z"],"width":804.5714285714286,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["qrcode"],"defaultCode":61481,"grid":14},"attrs":[],"properties":{"name":"qrcode","id":48,"order":44,"prevSize":28,"code":61481},"setIdx":0,"setId":1,"iconIdx":53},{"icon":{"paths":["M256 256c0-40.571-32.571-73.143-73.143-73.143s-73.143 32.571-73.143 73.143 32.571 73.143 73.143 73.143 73.143-32.571 73.143-73.143zM865.714 585.143c0 19.429-8 38.286-21.143 51.429l-280.571 281.143c-13.714 13.143-32.571 21.143-52 21.143s-38.286-8-51.429-21.143l-408.571-409.143c-29.143-28.571-52-84-52-124.571v-237.714c0-40 33.143-73.143 73.143-73.143h237.714c40.571 0 96 22.857 125.143 52l408.571 408c13.143 13.714 21.143 32.571 21.143 52z"],"width":865.7188571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["tag"],"defaultCode":61483,"grid":14},"attrs":[],"properties":{"name":"tag","id":49,"order":46,"prevSize":28,"code":61483},"setIdx":0,"setId":1,"iconIdx":54},{"icon":{"paths":["M256 256c0-40.571-32.571-73.143-73.143-73.143s-73.143 32.571-73.143 73.143 32.571 73.143 73.143 73.143 73.143-32.571 73.143-73.143zM865.714 585.143c0 19.429-8 38.286-21.143 51.429l-280.571 281.143c-13.714 13.143-32.571 21.143-52 21.143s-38.286-8-51.429-21.143l-408.571-409.143c-29.143-28.571-52-84-52-124.571v-237.714c0-40 33.143-73.143 73.143-73.143h237.714c40.571 0 96 22.857 125.143 52l408.571 408c13.143 13.714 21.143 32.571 21.143 52zM1085.143 585.143c0 19.429-8 38.286-21.143 51.429l-280.571 281.143c-13.714 13.143-32.571 21.143-52 21.143-29.714 0-44.571-13.714-64-33.714l268.571-268.571c13.143-13.143 21.143-32 21.143-51.429s-8-38.286-21.143-52l-408.571-408c-29.143-29.143-84.571-52-125.143-52h128c40.571 0 96 22.857 125.143 52l408.571 408c13.143 13.714 21.143 32.571 21.143 52z"],"width":1085.1474285714285,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["tags"],"defaultCode":61484,"grid":14},"attrs":[],"properties":{"name":"tags","id":50,"order":47,"prevSize":28,"code":61484},"setIdx":0,"setId":1,"iconIdx":55},{"icon":{"paths":["M936.571 273.143c14.286 20.571 18.286 47.429 10.286 73.714l-157.143 517.714c-14.286 48.571-64.571 86.286-113.714 86.286h-527.429c-58.286 0-120.571-46.286-141.714-105.714-9.143-25.714-9.143-50.857-1.143-72.571 1.143-11.429 3.429-22.857 4-36.571 0.571-9.143-4.571-16.571-3.429-23.429 2.286-13.714 14.286-23.429 23.429-38.857 17.143-28.571 36.571-74.857 42.857-104.571 2.857-10.857-2.857-23.429 0-33.143 2.857-10.857 13.714-18.857 19.429-29.143 15.429-26.286 35.429-77.143 38.286-104 1.143-12-4.571-25.143-1.143-34.286 4-13.143 16.571-18.857 25.143-30.286 13.714-18.857 36.571-73.143 40-103.429 1.143-9.714-4.571-19.429-2.857-29.714 2.286-10.857 16-22.286 25.143-35.429 24-35.429 28.571-113.714 101.143-93.143l-0.571 1.714c9.714-2.286 19.429-5.143 29.143-5.143h434.857c26.857 0 50.857 12 65.143 32 14.857 20.571 18.286 47.429 10.286 74.286l-156.571 517.714c-26.857 88-41.714 107.429-114.286 107.429h-496.571c-7.429 0-16.571 1.714-21.714 8.571-4.571 6.857-5.143 12-0.571 24.571 11.429 33.143 50.857 40 82.286 40h527.429c21.143 0 45.714-12 52-32.571l171.429-564c3.429-10.857 3.429-22.286 2.857-32.571 13.143 5.143 25.143 13.143 33.714 24.571zM328.571 274.286c-3.429 10.286 2.286 18.286 12.571 18.286h347.429c9.714 0 20.571-8 24-18.286l12-36.571c3.429-10.286-2.286-18.286-12.571-18.286h-347.429c-9.714 0-20.571 8-24 18.286zM281.143 420.571c-3.429 10.286 2.286 18.286 12.571 18.286h347.429c9.714 0 20.571-8 24-18.286l12-36.571c3.429-10.286-2.286-18.286-12.571-18.286h-347.429c-9.714 0-20.571 8-24 18.286z"],"width":952.5394285714285,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["book"],"defaultCode":61485,"grid":14},"attrs":[],"properties":{"name":"book","id":51,"order":48,"prevSize":28,"code":61485},"setIdx":0,"setId":1,"iconIdx":56},{"icon":{"paths":["M219.429 877.714h512v-146.286h-512v146.286zM219.429 512h512v-219.429h-91.429c-30.286 0-54.857-24.571-54.857-54.857v-91.429h-365.714v365.714zM877.714 548.571c0-20-16.571-36.571-36.571-36.571s-36.571 16.571-36.571 36.571 16.571 36.571 36.571 36.571 36.571-16.571 36.571-36.571zM950.857 548.571v237.714c0 9.714-8.571 18.286-18.286 18.286h-128v91.429c0 30.286-24.571 54.857-54.857 54.857h-548.571c-30.286 0-54.857-24.571-54.857-54.857v-91.429h-128c-9.714 0-18.286-8.571-18.286-18.286v-237.714c0-60 49.714-109.714 109.714-109.714h36.571v-310.857c0-30.286 24.571-54.857 54.857-54.857h384c30.286 0 72 17.143 93.714 38.857l86.857 86.857c21.714 21.714 38.857 63.429 38.857 93.714v146.286h36.571c60 0 109.714 49.714 109.714 109.714z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["print"],"defaultCode":61487,"grid":14},"attrs":[],"properties":{"name":"print","id":52,"order":50,"prevSize":28,"code":61487},"setIdx":0,"setId":1,"iconIdx":57},{"icon":{"paths":["M996.571 804.571c25.143 0 33.143 16 17.714 36l-72 92.571c-15.429 20-40.571 20-56 0l-72-92.571c-15.429-20-7.429-36 17.714-36h45.714v-585.143h-45.714c-25.143 0-33.143-16-17.714-36l72-92.571c15.429-20 40.571-20 56 0l72 92.571c15.429 20 7.429 36-17.714 36h-45.714v585.143h45.714zM46.286 73.714l30.857 15.429c4 1.714 108.571 2.857 120.571 2.857 50.286 0 100.571-2.286 150.857-2.286 41.143 0 81.714 0.571 122.857 0.571h167.429c22.857 0 36 5.143 51.429-16.571l24-0.571c5.143 0 10.857 0.571 16 0.571 1.143 64 1.143 128 1.143 192 0 20 0.571 42.286-2.857 62.286-12.571 4.571-25.714 8.571-38.857 10.286-13.143-22.857-22.286-48-30.857-73.143-4-11.429-17.714-88.571-18.857-89.714-12-14.857-25.143-12-42.857-12-52 0-106.286-2.286-157.714 4-2.857 25.143-5.143 52-4.571 77.714 0.571 160.571 2.286 321.143 2.286 481.714 0 44-6.857 90.286 5.714 132.571 43.429 22.286 94.857 25.714 139.429 45.714 1.143 9.143 2.857 18.857 2.857 28.571 0 5.143-0.571 10.857-1.714 16.571l-19.429 0.571c-81.143 2.286-161.143-10.286-242.857-10.286-57.714 0-115.429 10.286-173.143 10.286-0.571-9.714-1.714-20-1.714-29.714v-5.143c21.714-34.857 100-35.429 136-56.571 12.571-28 10.857-182.857 10.857-218.857 0-115.429-3.429-230.857-3.429-346.286v-66.857c0-10.286 2.286-51.429-4.571-59.429-8-8.571-82.857-6.857-92.571-6.857-21.143 0-82.286 9.714-98.857 21.714-27.429 18.857-27.429 133.143-61.714 135.429-10.286-6.286-24.571-15.429-32-25.143v-218.857z"],"width":1029.7051428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["text-height"],"defaultCode":61492,"grid":14},"attrs":[],"properties":{"name":"text-height","id":53,"order":694,"prevSize":28,"code":61492},"setIdx":0,"setId":1,"iconIdx":58},{"icon":{"paths":["M46.286 73.714l30.857 15.429c4 1.714 108.571 2.857 120.571 2.857 50.286 0 100.571-2.286 150.857-2.286 151.429 0 304.571-3.429 456 1.714 12.571 0.571 24.571-7.429 32-17.714l24-0.571c5.143 0 10.857 0.571 16 0.571 1.143 64 1.143 128 1.143 192 0 20.571 0.571 42.286-2.857 62.286-12.571 4.571-25.714 8.571-38.857 10.286-13.143-22.857-22.286-48-30.857-73.143-4-11.429-18.286-88.571-18.857-89.714-4-5.143-9.143-8.571-15.429-10.857-4.571-1.714-32-1.143-37.714-1.143-70.286 0-151.429-4-220.571 4-2.857 25.143-5.143 52-4.571 77.714l0.571 86.857v-29.714c0.571 93.143 1.714 185.714 1.714 278.286 0 44-6.857 90.286 5.714 132.571 43.429 22.286 94.857 25.714 139.429 45.714 1.143 9.143 2.857 18.857 2.857 28.571 0 5.143-0.571 10.857-1.714 16.571l-19.429 0.571c-81.143 2.286-161.143-10.286-242.857-10.286-57.714 0-115.429 10.286-173.143 10.286-0.571-9.714-1.714-20-1.714-29.714v-5.143c21.714-34.857 100-35.429 136-56.571 14.286-32 10.286-302.286 10.286-352.571 0-8-2.857-16.571-2.857-25.143 0-23.429 4-157.714-4.571-167.429-8-8.571-82.857-6.857-92.571-6.857-24 0-158.286 12.571-172 21.714-26.857 17.714-27.429 132.571-61.714 135.429-10.286-6.286-24.571-15.429-32-25.143v-218.857zM748.571 806.286c20 0 96 68 111.429 80 8.571 6.857 14.857 16.571 14.857 28s-6.286 21.143-14.857 28c-15.429 12-91.429 80-111.429 80-26.286 0-17.143-61.143-17.143-71.429h-585.143c0 10.286 9.143 71.429-17.143 71.429-20 0-96-68-111.429-80-8.571-6.857-14.857-16.571-14.857-28s6.286-21.143 14.857-28c15.429-12 91.429-80 111.429-80 26.286 0 17.143 61.143 17.143 71.429h585.143c0-10.286-9.143-71.429 17.143-71.429z"],"width":878.2994285714285,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["text-width"],"defaultCode":61493,"grid":14},"attrs":[],"properties":{"name":"text-width","id":54,"order":695,"prevSize":28,"code":61493},"setIdx":0,"setId":1,"iconIdx":59},{"icon":{"paths":["M1024 768v73.143c0 20-16.571 36.571-36.571 36.571h-950.857c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h950.857c20 0 36.571 16.571 36.571 36.571zM804.571 548.571v73.143c0 20-16.571 36.571-36.571 36.571h-731.429c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h731.429c20 0 36.571 16.571 36.571 36.571zM950.857 329.143v73.143c0 20-16.571 36.571-36.571 36.571h-877.714c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h877.714c20 0 36.571 16.571 36.571 36.571zM731.429 109.714v73.143c0 20-16.571 36.571-36.571 36.571h-658.286c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h658.286c20 0 36.571 16.571 36.571 36.571z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["align-left"],"defaultCode":61494,"grid":14},"attrs":[],"properties":{"name":"align-left","id":55,"order":57,"prevSize":28,"code":61494},"setIdx":0,"setId":1,"iconIdx":60},{"icon":{"paths":["M1024 768v73.143c0 20-16.571 36.571-36.571 36.571h-950.857c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h950.857c20 0 36.571 16.571 36.571 36.571zM804.571 548.571v73.143c0 20-16.571 36.571-36.571 36.571h-512c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h512c20 0 36.571 16.571 36.571 36.571zM950.857 329.143v73.143c0 20-16.571 36.571-36.571 36.571h-804.571c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h804.571c20 0 36.571 16.571 36.571 36.571zM731.429 109.714v73.143c0 20-16.571 36.571-36.571 36.571h-365.714c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h365.714c20 0 36.571 16.571 36.571 36.571z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["align-center"],"defaultCode":61495,"grid":14},"attrs":[],"properties":{"name":"align-center","id":56,"order":58,"prevSize":28,"code":61495},"setIdx":0,"setId":1,"iconIdx":61},{"icon":{"paths":["M1024 768v73.143c0 20-16.571 36.571-36.571 36.571h-950.857c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h950.857c20 0 36.571 16.571 36.571 36.571zM1024 548.571v73.143c0 20-16.571 36.571-36.571 36.571h-731.429c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h731.429c20 0 36.571 16.571 36.571 36.571zM1024 329.143v73.143c0 20-16.571 36.571-36.571 36.571h-877.714c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h877.714c20 0 36.571 16.571 36.571 36.571zM1024 109.714v73.143c0 20-16.571 36.571-36.571 36.571h-658.286c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h658.286c20 0 36.571 16.571 36.571 36.571z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["align-right"],"defaultCode":61496,"grid":14},"attrs":[],"properties":{"name":"align-right","id":57,"order":59,"prevSize":28,"code":61496},"setIdx":0,"setId":1,"iconIdx":62},{"icon":{"paths":["M1024 768v73.143c0 20-16.571 36.571-36.571 36.571h-950.857c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h950.857c20 0 36.571 16.571 36.571 36.571zM1024 548.571v73.143c0 20-16.571 36.571-36.571 36.571h-950.857c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h950.857c20 0 36.571 16.571 36.571 36.571zM1024 329.143v73.143c0 20-16.571 36.571-36.571 36.571h-950.857c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h950.857c20 0 36.571 16.571 36.571 36.571zM1024 109.714v73.143c0 20-16.571 36.571-36.571 36.571h-950.857c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h950.857c20 0 36.571 16.571 36.571 36.571z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["align-justify"],"defaultCode":61497,"grid":14},"attrs":[],"properties":{"name":"align-justify","id":58,"order":60,"prevSize":28,"code":61497},"setIdx":0,"setId":1,"iconIdx":63},{"icon":{"paths":["M146.286 749.714v109.714c0 9.714-8.571 18.286-18.286 18.286h-109.714c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h109.714c9.714 0 18.286 8.571 18.286 18.286zM146.286 530.286v109.714c0 9.714-8.571 18.286-18.286 18.286h-109.714c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h109.714c9.714 0 18.286 8.571 18.286 18.286zM146.286 310.857v109.714c0 9.714-8.571 18.286-18.286 18.286h-109.714c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h109.714c9.714 0 18.286 8.571 18.286 18.286zM1024 749.714v109.714c0 9.714-8.571 18.286-18.286 18.286h-768c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h768c9.714 0 18.286 8.571 18.286 18.286zM146.286 91.429v109.714c0 9.714-8.571 18.286-18.286 18.286h-109.714c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h109.714c9.714 0 18.286 8.571 18.286 18.286zM1024 530.286v109.714c0 9.714-8.571 18.286-18.286 18.286h-768c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h768c9.714 0 18.286 8.571 18.286 18.286zM1024 310.857v109.714c0 9.714-8.571 18.286-18.286 18.286h-768c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h768c9.714 0 18.286 8.571 18.286 18.286zM1024 91.429v109.714c0 9.714-8.571 18.286-18.286 18.286h-768c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h768c9.714 0 18.286 8.571 18.286 18.286z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["list"],"defaultCode":61498,"grid":14},"attrs":[],"properties":{"name":"list","id":59,"order":61,"prevSize":28,"code":61498},"setIdx":0,"setId":1,"iconIdx":64},{"icon":{"paths":["M219.429 310.857v329.143c0 9.714-8.571 18.286-18.286 18.286-4.571 0-9.714-1.714-13.143-5.143l-164.571-164.571c-3.429-3.429-5.143-8.571-5.143-13.143s1.714-9.714 5.143-13.143l164.571-164.571c3.429-3.429 8.571-5.143 13.143-5.143 9.714 0 18.286 8.571 18.286 18.286zM1024 749.714v109.714c0 9.714-8.571 18.286-18.286 18.286h-987.429c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h987.429c9.714 0 18.286 8.571 18.286 18.286zM1024 530.286v109.714c0 9.714-8.571 18.286-18.286 18.286h-621.714c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h621.714c9.714 0 18.286 8.571 18.286 18.286zM1024 310.857v109.714c0 9.714-8.571 18.286-18.286 18.286h-621.714c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h621.714c9.714 0 18.286 8.571 18.286 18.286zM1024 91.429v109.714c0 9.714-8.571 18.286-18.286 18.286h-987.429c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h987.429c9.714 0 18.286 8.571 18.286 18.286z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["dedent","outdent"],"defaultCode":61499,"grid":14},"attrs":[],"properties":{"name":"dedent, outdent","id":60,"order":62,"prevSize":28,"code":61499},"setIdx":0,"setId":1,"iconIdx":65},{"icon":{"paths":["M201.143 475.429c0 4.571-1.714 9.714-5.143 13.143l-164.571 164.571c-3.429 3.429-8.571 5.143-13.143 5.143-9.714 0-18.286-8.571-18.286-18.286v-329.143c0-9.714 8.571-18.286 18.286-18.286 4.571 0 9.714 1.714 13.143 5.143l164.571 164.571c3.429 3.429 5.143 8.571 5.143 13.143zM1024 749.714v109.714c0 9.714-8.571 18.286-18.286 18.286h-987.429c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h987.429c9.714 0 18.286 8.571 18.286 18.286zM1024 530.286v109.714c0 9.714-8.571 18.286-18.286 18.286h-621.714c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h621.714c9.714 0 18.286 8.571 18.286 18.286zM1024 310.857v109.714c0 9.714-8.571 18.286-18.286 18.286h-621.714c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h621.714c9.714 0 18.286 8.571 18.286 18.286zM1024 91.429v109.714c0 9.714-8.571 18.286-18.286 18.286h-987.429c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h987.429c9.714 0 18.286 8.571 18.286 18.286z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["indent"],"defaultCode":61500,"grid":14},"attrs":[],"properties":{"name":"indent","id":61,"order":63,"prevSize":28,"code":61500},"setIdx":0,"setId":1,"iconIdx":66},{"icon":{"paths":["M207.429 877.714l52-52-134.286-134.286-52 52v61.143h73.143v73.143h61.143zM506.286 347.429c0-7.429-5.143-12.571-12.571-12.571-3.429 0-6.857 1.143-9.714 4l-309.714 309.714c-2.857 2.857-4 6.286-4 9.714 0 7.429 5.143 12.571 12.571 12.571 3.429 0 6.857-1.143 9.714-4l309.714-309.714c2.857-2.857 4-6.286 4-9.714zM475.429 237.714l237.714 237.714-475.429 475.429h-237.714v-237.714zM865.714 292.571c0 19.429-8 38.286-21.143 51.429l-94.857 94.857-237.714-237.714 94.857-94.286c13.143-13.714 32-21.714 51.429-21.714s38.286 8 52 21.714l134.286 133.714c13.143 13.714 21.143 32.571 21.143 52z"],"width":865.7188571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["pencil"],"defaultCode":61504,"grid":14},"attrs":[],"properties":{"name":"pencil","id":62,"order":66,"prevSize":28,"code":61504},"setIdx":0,"setId":1,"iconIdx":67},{"icon":{"paths":["M438.857 822.857v-621.714c-171.429 0-310.857 139.429-310.857 310.857s139.429 310.857 310.857 310.857zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["adjust"],"defaultCode":61506,"grid":14},"attrs":[],"properties":{"name":"adjust","id":63,"order":68,"prevSize":28,"code":61506},"setIdx":0,"setId":1,"iconIdx":68},{"icon":{"paths":["M507.429 676.571l66.286-66.286-86.857-86.857-66.286 66.286v32h54.857v54.857h32zM758.857 265.143c-5.143-5.143-13.714-4.571-18.857 0.571l-200 200c-5.143 5.143-5.714 13.714-0.571 18.857s13.714 4.571 18.857-0.571l200-200c5.143-5.143 5.714-13.714 0.571-18.857zM804.571 604.571v108.571c0 90.857-73.714 164.571-164.571 164.571h-475.429c-90.857 0-164.571-73.714-164.571-164.571v-475.429c0-90.857 73.714-164.571 164.571-164.571h475.429c22.857 0 45.714 4.571 66.857 14.286 5.143 2.286 9.143 7.429 10.286 13.143 1.143 6.286-0.571 12-5.143 16.571l-28 28c-5.143 5.143-12 6.857-18.286 4.571-8.571-2.286-17.143-3.429-25.714-3.429h-475.429c-50.286 0-91.429 41.143-91.429 91.429v475.429c0 50.286 41.143 91.429 91.429 91.429h475.429c50.286 0 91.429-41.143 91.429-91.429v-72c0-4.571 1.714-9.143 5.143-12.571l36.571-36.571c5.714-5.714 13.143-6.857 20-4s11.429 9.143 11.429 16.571zM749.714 182.857l164.571 164.571-384 384h-164.571v-164.571zM1003.429 258.286l-52.571 52.571-164.571-164.571 52.571-52.571c21.143-21.143 56.571-21.143 77.714 0l86.857 86.857c21.143 21.143 21.143 56.571 0 77.714z"],"width":1024.5851428571427,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["edit","pencil-square-o"],"defaultCode":61508,"grid":14},"attrs":[],"properties":{"name":"edit, pencil-square-o","id":64,"order":70,"prevSize":28,"code":61508},"setIdx":0,"setId":1,"iconIdx":69},{"icon":{"paths":["M804.571 565.143v148c0 90.857-73.714 164.571-164.571 164.571h-475.429c-90.857 0-164.571-73.714-164.571-164.571v-475.429c0-90.857 73.714-164.571 164.571-164.571h145.714c9.714 0 18.286 8 18.286 18.286 0 9.143-6.286 16.571-14.857 18.286-28.571 9.714-54.286 21.143-76 34.286-2.857 1.143-5.714 2.286-9.143 2.286h-64c-50.286 0-91.429 41.143-91.429 91.429v475.429c0 50.286 41.143 91.429 91.429 91.429h475.429c50.286 0 91.429-41.143 91.429-91.429v-122.286c0-6.857 4-13.143 10.286-16.571 11.429-5.143 21.714-12.571 30.857-21.143 5.143-5.143 13.143-7.429 20-4.571s12 9.143 12 16.571zM940 281.714l-219.429 219.429c-6.857 7.429-16 10.857-25.714 10.857-4.571 0-9.714-1.143-14.286-2.857-13.143-5.714-22.286-18.857-22.286-33.714v-109.714h-91.429c-125.714 0-205.714 24-250.286 74.857-46.286 53.143-60 138.857-42.286 270.286 1.143 8-4 16-11.429 19.429-2.286 0.571-4.571 1.143-6.857 1.143-5.714 0-11.429-2.857-14.857-7.429-4-5.714-94.857-134.286-94.857-248.571 0-153.143 48-329.143 420.571-329.143h91.429v-109.714c0-14.857 9.143-28 22.286-33.714 4.571-1.714 9.714-2.857 14.286-2.857 9.714 0 18.857 4 25.714 10.857l219.429 219.429c14.286 14.286 14.286 37.143 0 51.429z"],"width":954.2948571428572,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["share-square-o"],"defaultCode":61509,"grid":14},"attrs":[],"properties":{"name":"share-square-o","id":65,"order":71,"prevSize":28,"code":61509},"setIdx":0,"setId":1,"iconIdx":70},{"icon":{"paths":["M804.571 531.429v181.714c0 90.857-73.714 164.571-164.571 164.571h-475.429c-90.857 0-164.571-73.714-164.571-164.571v-475.429c0-90.857 73.714-164.571 164.571-164.571h475.429c22.857 0 45.714 4.571 66.857 14.286 5.143 2.286 9.143 7.429 10.286 13.143 1.143 6.286-0.571 12-5.143 16.571l-28 28c-3.429 3.429-8.571 5.714-13.143 5.714-1.714 0-3.429-0.571-5.143-1.143-8.571-2.286-17.143-3.429-25.714-3.429h-475.429c-50.286 0-91.429 41.143-91.429 91.429v475.429c0 50.286 41.143 91.429 91.429 91.429h475.429c50.286 0 91.429-41.143 91.429-91.429v-145.143c0-4.571 1.714-9.143 5.143-12.571l36.571-36.571c4-4 8.571-5.714 13.143-5.714 2.286 0 4.571 0.571 6.857 1.714 6.857 2.857 11.429 9.143 11.429 16.571zM936.571 252l-465.143 465.143c-18.286 18.286-46.857 18.286-65.143 0l-245.714-245.714c-18.286-18.286-18.286-46.857 0-65.143l62.857-62.857c18.286-18.286 46.857-18.286 65.143 0l150.286 150.286 369.714-369.714c18.286-18.286 46.857-18.286 65.143 0l62.857 62.857c18.286 18.286 18.286 46.857 0 65.143z"],"width":954.8799999999999,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["check-square-o"],"defaultCode":61510,"grid":14},"attrs":[],"properties":{"name":"check-square-o","id":66,"order":719,"prevSize":28,"code":61510},"setIdx":0,"setId":1,"iconIdx":71},{"icon":{"paths":["M1024 512c0 9.714-4 18.857-10.857 25.714l-146.286 146.286c-6.857 6.857-16 10.857-25.714 10.857-20 0-36.571-16.571-36.571-36.571v-73.143h-219.429v219.429h73.143c20 0 36.571 16.571 36.571 36.571 0 9.714-4 18.857-10.857 25.714l-146.286 146.286c-6.857 6.857-16 10.857-25.714 10.857s-18.857-4-25.714-10.857l-146.286-146.286c-6.857-6.857-10.857-16-10.857-25.714 0-20 16.571-36.571 36.571-36.571h73.143v-219.429h-219.429v73.143c0 20-16.571 36.571-36.571 36.571-9.714 0-18.857-4-25.714-10.857l-146.286-146.286c-6.857-6.857-10.857-16-10.857-25.714s4-18.857 10.857-25.714l146.286-146.286c6.857-6.857 16-10.857 25.714-10.857 20 0 36.571 16.571 36.571 36.571v73.143h219.429v-219.429h-73.143c-20 0-36.571-16.571-36.571-36.571 0-9.714 4-18.857 10.857-25.714l146.286-146.286c6.857-6.857 16-10.857 25.714-10.857s18.857 4 25.714 10.857l146.286 146.286c6.857 6.857 10.857 16 10.857 25.714 0 20-16.571 36.571-36.571 36.571h-73.143v219.429h219.429v-73.143c0-20 16.571-36.571 36.571-36.571 9.714 0 18.857 4 25.714 10.857l146.286 146.286c6.857 6.857 10.857 16 10.857 25.714z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["arrows"],"defaultCode":61511,"grid":14},"attrs":[],"properties":{"name":"arrows","id":67,"order":73,"prevSize":28,"code":61511},"setIdx":0,"setId":1,"iconIdx":72},{"icon":{"paths":["M559.429 80.571c14.286-14.286 25.714-9.143 25.714 10.857v841.143c0 20-11.429 25.143-25.714 10.857l-405.714-405.714c-3.429-3.429-5.714-6.857-7.429-10.857v387.429c0 20-16.571 36.571-36.571 36.571h-73.143c-20 0-36.571-16.571-36.571-36.571v-804.571c0-20 16.571-36.571 36.571-36.571h73.143c20 0 36.571 16.571 36.571 36.571v387.429c1.714-4 4-7.429 7.429-10.857z"],"width":585.1428571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["step-backward"],"defaultCode":61512,"grid":14},"attrs":[],"properties":{"name":"step-backward","id":68,"order":74,"prevSize":28,"code":61512},"setIdx":0,"setId":1,"iconIdx":73},{"icon":{"paths":["M998.286 80.571c14.286-14.286 25.714-9.143 25.714 10.857v841.143c0 20-11.429 25.143-25.714 10.857l-405.714-405.714c-3.429-3.429-5.714-6.857-7.429-10.857v405.714c0 20-11.429 25.143-25.714 10.857l-405.714-405.714c-3.429-3.429-5.714-6.857-7.429-10.857v387.429c0 20-16.571 36.571-36.571 36.571h-73.143c-20 0-36.571-16.571-36.571-36.571v-804.571c0-20 16.571-36.571 36.571-36.571h73.143c20 0 36.571 16.571 36.571 36.571v387.429c1.714-4 4-7.429 7.429-10.857l405.714-405.714c14.286-14.286 25.714-9.143 25.714 10.857v405.714c1.714-4 4-7.429 7.429-10.857z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["fast-backward"],"defaultCode":61513,"grid":14},"attrs":[],"properties":{"name":"fast-backward","id":69,"order":75,"prevSize":28,"code":61513},"setIdx":0,"setId":1,"iconIdx":74},{"icon":{"paths":["M925.143 80.571c14.286-14.286 25.714-9.143 25.714 10.857v841.143c0 20-11.429 25.143-25.714 10.857l-405.714-405.714c-3.429-3.429-5.714-6.857-7.429-10.857v405.714c0 20-11.429 25.143-25.714 10.857l-405.714-405.714c-14.286-14.286-14.286-37.143 0-51.429l405.714-405.714c14.286-14.286 25.714-9.143 25.714 10.857v405.714c1.714-4 4-7.429 7.429-10.857z"],"width":1017.1245714285715,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["backward"],"defaultCode":61514,"grid":14},"attrs":[],"properties":{"name":"backward","id":70,"order":76,"prevSize":28,"code":61514},"setIdx":0,"setId":1,"iconIdx":75},{"icon":{"paths":["M790.857 529.714l-758.857 421.714c-17.714 9.714-32 1.143-32-18.857v-841.143c0-20 14.286-28.571 32-18.857l758.857 421.714c17.714 9.714 17.714 25.714 0 35.429z"],"width":808.5942857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["play"],"defaultCode":61515,"grid":14},"attrs":[],"properties":{"name":"play","id":71,"order":77,"prevSize":28,"code":61515},"setIdx":0,"setId":1,"iconIdx":76},{"icon":{"paths":["M877.714 109.714v804.571c0 20-16.571 36.571-36.571 36.571h-292.571c-20 0-36.571-16.571-36.571-36.571v-804.571c0-20 16.571-36.571 36.571-36.571h292.571c20 0 36.571 16.571 36.571 36.571zM365.714 109.714v804.571c0 20-16.571 36.571-36.571 36.571h-292.571c-20 0-36.571-16.571-36.571-36.571v-804.571c0-20 16.571-36.571 36.571-36.571h292.571c20 0 36.571 16.571 36.571 36.571z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["pause"],"defaultCode":61516,"grid":14},"attrs":[],"properties":{"name":"pause","id":72,"order":78,"prevSize":28,"code":61516},"setIdx":0,"setId":1,"iconIdx":77},{"icon":{"paths":["M877.714 109.714v804.571c0 20-16.571 36.571-36.571 36.571h-804.571c-20 0-36.571-16.571-36.571-36.571v-804.571c0-20 16.571-36.571 36.571-36.571h804.571c20 0 36.571 16.571 36.571 36.571z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["stop"],"defaultCode":61517,"grid":14},"attrs":[],"properties":{"name":"stop","id":73,"order":79,"prevSize":28,"code":61517},"setIdx":0,"setId":1,"iconIdx":78},{"icon":{"paths":["M25.714 943.429c-14.286 14.286-25.714 9.143-25.714-10.857v-841.143c0-20 11.429-25.143 25.714-10.857l405.714 405.714c3.429 3.429 5.714 6.857 7.429 10.857v-405.714c0-20 11.429-25.143 25.714-10.857l405.714 405.714c14.286 14.286 14.286 37.143 0 51.429l-405.714 405.714c-14.286 14.286-25.714 9.143-25.714-10.857v-405.714c-1.714 4-4 7.429-7.429 10.857z"],"width":884.5897142857142,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["forward"],"defaultCode":61518,"grid":14},"attrs":[],"properties":{"name":"forward","id":74,"order":80,"prevSize":28,"code":61518},"setIdx":0,"setId":1,"iconIdx":79},{"icon":{"paths":["M25.714 943.429c-14.286 14.286-25.714 9.143-25.714-10.857v-841.143c0-20 11.429-25.143 25.714-10.857l405.714 405.714c3.429 3.429 5.714 6.857 7.429 10.857v-405.714c0-20 11.429-25.143 25.714-10.857l405.714 405.714c3.429 3.429 5.714 6.857 7.429 10.857v-387.429c0-20 16.571-36.571 36.571-36.571h73.143c20 0 36.571 16.571 36.571 36.571v804.571c0 20-16.571 36.571-36.571 36.571h-73.143c-20 0-36.571-16.571-36.571-36.571v-387.429c-1.714 4-4 7.429-7.429 10.857l-405.714 405.714c-14.286 14.286-25.714 9.143-25.714-10.857v-405.714c-1.714 4-4 7.429-7.429 10.857z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["fast-forward"],"defaultCode":61520,"grid":14},"attrs":[],"properties":{"name":"fast-forward","id":75,"order":81,"prevSize":28,"code":61520},"setIdx":0,"setId":1,"iconIdx":80},{"icon":{"paths":["M25.714 943.429c-14.286 14.286-25.714 9.143-25.714-10.857v-841.143c0-20 11.429-25.143 25.714-10.857l405.714 405.714c3.429 3.429 5.714 6.857 7.429 10.857v-387.429c0-20 16.571-36.571 36.571-36.571h73.143c20 0 36.571 16.571 36.571 36.571v804.571c0 20-16.571 36.571-36.571 36.571h-73.143c-20 0-36.571-16.571-36.571-36.571v-387.429c-1.714 4-4 7.429-7.429 10.857z"],"width":585.1428571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["step-forward"],"defaultCode":61521,"grid":14},"attrs":[],"properties":{"name":"step-forward","id":76,"order":82,"prevSize":28,"code":61521},"setIdx":0,"setId":1,"iconIdx":81},{"icon":{"paths":["M8 559.429l405.714-405.714c14.286-14.286 37.143-14.286 51.429 0l405.714 405.714c14.286 14.286 9.143 25.714-10.857 25.714h-841.143c-20 0-25.143-11.429-10.857-25.714zM841.714 877.714h-804.571c-20 0-36.571-16.571-36.571-36.571v-146.286c0-20 16.571-36.571 36.571-36.571h804.571c20 0 36.571 16.571 36.571 36.571v146.286c0 20-16.571 36.571-36.571 36.571z"],"width":878.8845714285713,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["eject"],"defaultCode":61522,"grid":14},"attrs":[],"properties":{"name":"eject","id":77,"order":83,"prevSize":28,"code":61522},"setIdx":0,"setId":1,"iconIdx":82},{"icon":{"paths":["M669.143 172l-303.429 303.429 303.429 303.429c14.286 14.286 14.286 37.143 0 51.429l-94.857 94.857c-14.286 14.286-37.143 14.286-51.429 0l-424-424c-14.286-14.286-14.286-37.143 0-51.429l424-424c14.286-14.286 37.143-14.286 51.429 0l94.857 94.857c14.286 14.286 14.286 37.143 0 51.429z"],"width":768,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["chevron-left"],"defaultCode":61523,"grid":14},"attrs":[],"properties":{"name":"chevron-left","id":78,"order":84,"prevSize":28,"code":61523},"setIdx":0,"setId":1,"iconIdx":83},{"icon":{"paths":["M632.571 501.143l-424 424c-14.286 14.286-37.143 14.286-51.429 0l-94.857-94.857c-14.286-14.286-14.286-37.143 0-51.429l303.429-303.429-303.429-303.429c-14.286-14.286-14.286-37.143 0-51.429l94.857-94.857c14.286-14.286 37.143-14.286 51.429 0l424 424c14.286 14.286 14.286 37.143 0 51.429z"],"width":694.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["chevron-right"],"defaultCode":61524,"grid":14},"attrs":[],"properties":{"name":"chevron-right","id":79,"order":85,"prevSize":28,"code":61524},"setIdx":0,"setId":1,"iconIdx":84},{"icon":{"paths":["M694.857 548.571v-73.143c0-20-16.571-36.571-36.571-36.571h-146.286v-146.286c0-20-16.571-36.571-36.571-36.571h-73.143c-20 0-36.571 16.571-36.571 36.571v146.286h-146.286c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h146.286v146.286c0 20 16.571 36.571 36.571 36.571h73.143c20 0 36.571-16.571 36.571-36.571v-146.286h146.286c20 0 36.571-16.571 36.571-36.571zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["plus-circle"],"defaultCode":61525,"grid":14},"attrs":[],"properties":{"name":"plus-circle","id":80,"order":86,"prevSize":28,"code":61525},"setIdx":0,"setId":1,"iconIdx":85},{"icon":{"paths":["M694.857 548.571v-73.143c0-20-16.571-36.571-36.571-36.571h-438.857c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h438.857c20 0 36.571-16.571 36.571-36.571zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["minus-circle"],"defaultCode":61526,"grid":14},"attrs":[],"properties":{"name":"minus-circle","id":81,"order":87,"prevSize":28,"code":61526},"setIdx":0,"setId":1,"iconIdx":86},{"icon":{"paths":["M656.571 641.143c0-9.714-4-18.857-10.857-25.714l-103.429-103.429 103.429-103.429c6.857-6.857 10.857-16 10.857-25.714s-4-19.429-10.857-26.286l-51.429-51.429c-6.857-6.857-16.571-10.857-26.286-10.857s-18.857 4-25.714 10.857l-103.429 103.429-103.429-103.429c-6.857-6.857-16-10.857-25.714-10.857s-19.429 4-26.286 10.857l-51.429 51.429c-6.857 6.857-10.857 16.571-10.857 26.286s4 18.857 10.857 25.714l103.429 103.429-103.429 103.429c-6.857 6.857-10.857 16-10.857 25.714s4 19.429 10.857 26.286l51.429 51.429c6.857 6.857 16.571 10.857 26.286 10.857s18.857-4 25.714-10.857l103.429-103.429 103.429 103.429c6.857 6.857 16 10.857 25.714 10.857s19.429-4 26.286-10.857l51.429-51.429c6.857-6.857 10.857-16.571 10.857-26.286zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["times-circle"],"defaultCode":61527,"grid":14},"attrs":[],"properties":{"name":"times-circle","id":82,"order":88,"prevSize":28,"code":61527},"setIdx":0,"setId":1,"iconIdx":87},{"icon":{"paths":["M733.714 419.429c0-9.714-3.429-19.429-10.286-26.286l-52-51.429c-6.857-6.857-16-10.857-25.714-10.857s-18.857 4-25.714 10.857l-233.143 232.571-129.143-129.143c-6.857-6.857-16-10.857-25.714-10.857s-18.857 4-25.714 10.857l-52 51.429c-6.857 6.857-10.286 16.571-10.286 26.286s3.429 18.857 10.286 25.714l206.857 206.857c6.857 6.857 16.571 10.857 25.714 10.857 9.714 0 19.429-4 26.286-10.857l310.286-310.286c6.857-6.857 10.286-16 10.286-25.714zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["check-circle"],"defaultCode":61528,"grid":14},"attrs":[],"properties":{"name":"check-circle","id":83,"order":89,"prevSize":28,"code":61528},"setIdx":0,"setId":1,"iconIdx":88},{"icon":{"paths":["M512 786.286v-109.714c0-10.286-8-18.286-18.286-18.286h-109.714c-10.286 0-18.286 8-18.286 18.286v109.714c0 10.286 8 18.286 18.286 18.286h109.714c10.286 0 18.286-8 18.286-18.286zM658.286 402.286c0-104.571-109.714-182.857-208-182.857-93.143 0-162.857 40-212 121.714-5.143 8-2.857 18.286 4.571 24l75.429 57.143c2.857 2.286 6.857 3.429 10.857 3.429 5.143 0 10.857-2.286 14.286-6.857 26.857-34.286 38.286-44.571 49.143-52.571 9.714-6.857 28.571-13.714 49.143-13.714 36.571 0 70.286 23.429 70.286 48.571 0 29.714-15.429 44.571-50.286 60.571-40.571 18.286-96 65.714-96 121.143v20.571c0 10.286 8 18.286 18.286 18.286h109.714c10.286 0 18.286-8 18.286-18.286v0c0-13.143 16.571-41.143 43.429-56.571 43.429-24.571 102.857-57.714 102.857-144.571zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["question-circle"],"defaultCode":61529,"grid":14},"attrs":[],"properties":{"name":"question-circle","id":84,"order":90,"prevSize":28,"code":61529},"setIdx":0,"setId":1,"iconIdx":89},{"icon":{"paths":["M585.143 786.286v-91.429c0-10.286-8-18.286-18.286-18.286h-54.857v-292.571c0-10.286-8-18.286-18.286-18.286h-182.857c-10.286 0-18.286 8-18.286 18.286v91.429c0 10.286 8 18.286 18.286 18.286h54.857v182.857h-54.857c-10.286 0-18.286 8-18.286 18.286v91.429c0 10.286 8 18.286 18.286 18.286h256c10.286 0 18.286-8 18.286-18.286zM512 274.286v-91.429c0-10.286-8-18.286-18.286-18.286h-109.714c-10.286 0-18.286 8-18.286 18.286v91.429c0 10.286 8 18.286 18.286 18.286h109.714c10.286 0 18.286-8 18.286-18.286zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["info-circle"],"defaultCode":61530,"grid":14},"attrs":[],"properties":{"name":"info-circle","id":85,"order":91,"prevSize":28,"code":61530},"setIdx":0,"setId":1,"iconIdx":90},{"icon":{"paths":["M684 585.143h-62.286c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h62.286c-24.571-82.286-89.714-147.429-172-172v62.286c0 20-16.571 36.571-36.571 36.571h-73.143c-20 0-36.571-16.571-36.571-36.571v-62.286c-82.286 24.571-147.429 89.714-172 172h62.286c20 0 36.571 16.571 36.571 36.571v73.143c0 20-16.571 36.571-36.571 36.571h-62.286c24.571 82.286 89.714 147.429 172 172v-62.286c0-20 16.571-36.571 36.571-36.571h73.143c20 0 36.571 16.571 36.571 36.571v62.286c82.286-24.571 147.429-89.714 172-172zM877.714 475.429v73.143c0 20-16.571 36.571-36.571 36.571h-81.714c-28 122.857-124.571 219.429-247.429 247.429v81.714c0 20-16.571 36.571-36.571 36.571h-73.143c-20 0-36.571-16.571-36.571-36.571v-81.714c-122.857-28-219.429-124.571-247.429-247.429h-81.714c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h81.714c28-122.857 124.571-219.429 247.429-247.429v-81.714c0-20 16.571-36.571 36.571-36.571h73.143c20 0 36.571 16.571 36.571 36.571v81.714c122.857 28 219.429 124.571 247.429 247.429h81.714c20 0 36.571 16.571 36.571 36.571z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["crosshairs"],"defaultCode":61531,"grid":14},"attrs":[],"properties":{"name":"crosshairs","id":86,"order":92,"prevSize":28,"code":61531},"setIdx":0,"setId":1,"iconIdx":91},{"icon":{"paths":["M626.857 616.571l-83.429 83.429c-7.429 7.429-18.857 7.429-26.286 0l-78.286-78.286-78.286 78.286c-7.429 7.429-18.857 7.429-26.286 0l-83.429-83.429c-7.429-7.429-7.429-18.857 0-26.286l78.286-78.286-78.286-78.286c-7.429-7.429-7.429-18.857 0-26.286l83.429-83.429c7.429-7.429 18.857-7.429 26.286 0l78.286 78.286 78.286-78.286c7.429-7.429 18.857-7.429 26.286 0l83.429 83.429c7.429 7.429 7.429 18.857 0 26.286l-78.286 78.286 78.286 78.286c7.429 7.429 7.429 18.857 0 26.286zM749.714 512c0-171.429-139.429-310.857-310.857-310.857s-310.857 139.429-310.857 310.857 139.429 310.857 310.857 310.857 310.857-139.429 310.857-310.857zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["times-circle-o"],"defaultCode":61532,"grid":14},"attrs":[],"properties":{"name":"times-circle-o","id":87,"order":93,"prevSize":28,"code":61532},"setIdx":0,"setId":1,"iconIdx":92},{"icon":{"paths":["M669.143 464.571l-241.143 241.143c-14.286 14.286-37.143 14.286-51.429 0l-168-168c-14.286-14.286-14.286-37.143 0-51.429l58.286-58.286c14.286-14.286 37.143-14.286 51.429 0l84 84 157.143-157.143c14.286-14.286 37.143-14.286 51.429 0l58.286 58.286c14.286 14.286 14.286 37.143 0 51.429zM749.714 512c0-171.429-139.429-310.857-310.857-310.857s-310.857 139.429-310.857 310.857 139.429 310.857 310.857 310.857 310.857-139.429 310.857-310.857zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["check-circle-o"],"defaultCode":61533,"grid":14},"attrs":[],"properties":{"name":"check-circle-o","id":88,"order":94,"prevSize":28,"code":61533},"setIdx":0,"setId":1,"iconIdx":93},{"icon":{"paths":["M749.714 510.286c0-62.286-18.286-120-49.714-168.571l-430.857 430.286c49.143 32 107.429 50.857 169.714 50.857 171.429 0 310.857-140 310.857-312.571zM178.857 681.143l431.429-430.857c-49.143-33.143-108-52-171.429-52-171.429 0-310.857 140-310.857 312 0 63.429 18.857 121.714 50.857 170.857zM877.714 510.286c0 243.429-196.571 440.571-438.857 440.571s-438.857-197.143-438.857-440.571c0-242.857 196.571-440 438.857-440s438.857 197.143 438.857 440z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["ban"],"defaultCode":61534,"grid":14},"attrs":[],"properties":{"name":"ban","id":89,"order":95,"prevSize":28,"code":61534},"setIdx":0,"setId":1,"iconIdx":94},{"icon":{"paths":["M877.714 512v73.143c0 38.857-25.714 73.143-66.857 73.143h-402.286l167.429 168c13.714 13.143 21.714 32 21.714 51.429s-8 38.286-21.714 51.429l-42.857 43.429c-13.143 13.143-32 21.143-51.429 21.143s-38.286-8-52-21.143l-372-372.571c-13.143-13.143-21.143-32-21.143-51.429s8-38.286 21.143-52l372-371.429c13.714-13.714 32.571-21.714 52-21.714s37.714 8 51.429 21.714l42.857 42.286c13.714 13.714 21.714 32.571 21.714 52s-8 38.286-21.714 52l-167.429 167.429h402.286c41.143 0 66.857 34.286 66.857 73.143z"],"width":914.2857142857142,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["arrow-left"],"defaultCode":61536,"grid":14},"attrs":[],"properties":{"name":"arrow-left","id":90,"order":96,"prevSize":28,"code":61536},"setIdx":0,"setId":1,"iconIdx":95},{"icon":{"paths":["M841.143 548.571c0 19.429-7.429 38.286-21.143 52l-372 372c-13.714 13.143-32.571 21.143-52 21.143s-37.714-8-51.429-21.143l-42.857-42.857c-13.714-13.714-21.714-32.571-21.714-52s8-38.286 21.714-52l167.429-167.429h-402.286c-41.143 0-66.857-34.286-66.857-73.143v-73.143c0-38.857 25.714-73.143 66.857-73.143h402.286l-167.429-168c-13.714-13.143-21.714-32-21.714-51.429s8-38.286 21.714-51.429l42.857-42.857c13.714-13.714 32-21.714 51.429-21.714s38.286 8 52 21.714l372 372c13.714 13.143 21.143 32 21.143 51.429z"],"width":841.1428571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["arrow-right"],"defaultCode":61537,"grid":14},"attrs":[],"properties":{"name":"arrow-right","id":91,"order":97,"prevSize":28,"code":61537},"setIdx":0,"setId":1,"iconIdx":96},{"icon":{"paths":["M920.571 554.857c0 19.429-8 37.714-21.143 51.429l-42.857 42.857c-13.714 13.714-32.571 21.714-52 21.714s-38.286-8-51.429-21.714l-168-167.429v402.286c0 41.143-34.286 66.857-73.143 66.857h-73.143c-38.857 0-73.143-25.714-73.143-66.857v-402.286l-168 167.429c-13.143 13.714-32 21.714-51.429 21.714s-38.286-8-51.429-21.714l-42.857-42.857c-13.714-13.714-21.714-32-21.714-51.429s8-38.286 21.714-52l372-372c13.143-13.714 32-21.143 51.429-21.143s38.286 7.429 52 21.143l372 372c13.143 13.714 21.143 32.571 21.143 52z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["arrow-up"],"defaultCode":61538,"grid":14},"attrs":[],"properties":{"name":"arrow-up","id":92,"order":98,"prevSize":28,"code":61538},"setIdx":0,"setId":1,"iconIdx":97},{"icon":{"paths":["M920.571 475.429c0 19.429-8 38.286-21.143 51.429l-372 372.571c-13.714 13.143-32.571 21.143-52 21.143s-38.286-8-51.429-21.143l-372-372.571c-13.714-13.143-21.714-32-21.714-51.429s8-38.286 21.714-52l42.286-42.857c13.714-13.143 32.571-21.143 52-21.143s38.286 8 51.429 21.143l168 168v-402.286c0-40 33.143-73.143 73.143-73.143h73.143c40 0 73.143 33.143 73.143 73.143v402.286l168-168c13.143-13.143 32-21.143 51.429-21.143s38.286 8 52 21.143l42.857 42.857c13.143 13.714 21.143 32.571 21.143 52z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["arrow-down"],"defaultCode":61539,"grid":14},"attrs":[],"properties":{"name":"arrow-down","id":93,"order":99,"prevSize":28,"code":61539},"setIdx":0,"setId":1,"iconIdx":98},{"icon":{"paths":["M1024 365.714c0 9.714-4 18.857-10.857 25.714l-292.571 292.571c-6.857 6.857-16 10.857-25.714 10.857-20 0-36.571-16.571-36.571-36.571v-146.286h-128c-246.286 0-408 47.429-408 320 0 23.429 1.143 46.857 2.857 70.286 0.571 9.143 2.857 19.429 2.857 28.571 0 10.857-6.857 20-18.286 20-8 0-12-4-16-9.714-8.571-12-14.857-30.286-21.143-43.429-32.571-73.143-72.571-177.714-72.571-257.714 0-64 6.286-129.714 30.286-190.286 79.429-197.143 312.571-230.286 500-230.286h128v-146.286c0-20 16.571-36.571 36.571-36.571 9.714 0 18.857 4 25.714 10.857l292.571 292.571c6.857 6.857 10.857 16 10.857 25.714z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["mail-forward","share"],"defaultCode":61540,"grid":14},"attrs":[],"properties":{"name":"mail-forward, share","id":94,"order":100,"prevSize":28,"code":61540},"setIdx":0,"setId":1,"iconIdx":99},{"icon":{"paths":["M431.429 603.429c0 4.571-2.286 9.714-5.714 13.143l-189.714 189.714 82.286 82.286c6.857 6.857 10.857 16 10.857 25.714 0 20-16.571 36.571-36.571 36.571h-256c-20 0-36.571-16.571-36.571-36.571v-256c0-20 16.571-36.571 36.571-36.571 9.714 0 18.857 4 25.714 10.857l82.286 82.286 189.714-189.714c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l65.143 65.143c3.429 3.429 5.714 8.571 5.714 13.143zM877.714 109.714v256c0 20-16.571 36.571-36.571 36.571-9.714 0-18.857-4-25.714-10.857l-82.286-82.286-189.714 189.714c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-65.143-65.143c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l189.714-189.714-82.286-82.286c-6.857-6.857-10.857-16-10.857-25.714 0-20 16.571-36.571 36.571-36.571h256c20 0 36.571 16.571 36.571 36.571z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["expand"],"defaultCode":61541,"grid":14},"attrs":[],"properties":{"name":"expand","id":95,"order":101,"prevSize":28,"code":61541},"setIdx":0,"setId":1,"iconIdx":100},{"icon":{"paths":["M438.857 548.571v256c0 20-16.571 36.571-36.571 36.571-9.714 0-18.857-4-25.714-10.857l-82.286-82.286-189.714 189.714c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-65.143-65.143c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l189.714-189.714-82.286-82.286c-6.857-6.857-10.857-16-10.857-25.714 0-20 16.571-36.571 36.571-36.571h256c20 0 36.571 16.571 36.571 36.571zM870.286 164.571c0 4.571-2.286 9.714-5.714 13.143l-189.714 189.714 82.286 82.286c6.857 6.857 10.857 16 10.857 25.714 0 20-16.571 36.571-36.571 36.571h-256c-20 0-36.571-16.571-36.571-36.571v-256c0-20 16.571-36.571 36.571-36.571 9.714 0 18.857 4 25.714 10.857l82.286 82.286 189.714-189.714c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l65.143 65.143c3.429 3.429 5.714 8.571 5.714 13.143z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["compress"],"defaultCode":61542,"grid":14},"attrs":[],"properties":{"name":"compress","id":96,"order":102,"prevSize":28,"code":61542},"setIdx":0,"setId":1,"iconIdx":101},{"icon":{"paths":["M438.857 73.143c242.286 0 438.857 196.571 438.857 438.857s-196.571 438.857-438.857 438.857-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857zM512 785.714v-108.571c0-10.286-8-18.857-17.714-18.857h-109.714c-10.286 0-18.857 8.571-18.857 18.857v108.571c0 10.286 8.571 18.857 18.857 18.857h109.714c9.714 0 17.714-8.571 17.714-18.857zM510.857 589.143l10.286-354.857c0-4-1.714-8-5.714-10.286-3.429-2.857-8.571-4.571-13.714-4.571h-125.714c-5.143 0-10.286 1.714-13.714 4.571-4 2.286-5.714 6.286-5.714 10.286l9.714 354.857c0 8 8.571 14.286 19.429 14.286h105.714c10.286 0 18.857-6.286 19.429-14.286z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["exclamation-circle"],"defaultCode":61546,"grid":14},"attrs":[],"properties":{"name":"exclamation-circle","id":97,"order":103,"prevSize":28,"code":61546},"setIdx":0,"setId":1,"iconIdx":102},{"icon":{"paths":["M950.857 548.571c-54.286-84-128.571-156-217.714-201.714 22.857 38.857 34.857 83.429 34.857 128.571 0 141.143-114.857 256-256 256s-256-114.857-256-256c0-45.143 12-89.714 34.857-128.571-89.143 45.714-163.429 117.714-217.714 201.714 97.714 150.857 255.429 256 438.857 256s341.143-105.143 438.857-256zM539.429 329.143c0-14.857-12.571-27.429-27.429-27.429-95.429 0-173.714 78.286-173.714 173.714 0 14.857 12.571 27.429 27.429 27.429s27.429-12.571 27.429-27.429c0-65.143 53.714-118.857 118.857-118.857 14.857 0 27.429-12.571 27.429-27.429zM1024 548.571c0 14.286-4.571 27.429-11.429 39.429-105.143 173.143-297.714 289.714-500.571 289.714s-395.429-117.143-500.571-289.714c-6.857-12-11.429-25.143-11.429-39.429s4.571-27.429 11.429-39.429c105.143-172.571 297.714-289.714 500.571-289.714s395.429 117.143 500.571 289.714c6.857 12 11.429 25.143 11.429 39.429z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["eye"],"defaultCode":61550,"grid":14},"attrs":[],"properties":{"name":"eye","id":98,"order":107,"prevSize":28,"code":61550},"setIdx":0,"setId":1,"iconIdx":103},{"icon":{"paths":["M317.143 762.857l44.571-80.571c-66.286-48-105.714-125.143-105.714-206.857 0-45.143 12-89.714 34.857-128.571-89.143 45.714-163.429 117.714-217.714 201.714 59.429 92 143.429 169.143 244 214.286zM539.429 329.143c0-14.857-12.571-27.429-27.429-27.429-95.429 0-173.714 78.286-173.714 173.714 0 14.857 12.571 27.429 27.429 27.429s27.429-12.571 27.429-27.429c0-65.714 53.714-118.857 118.857-118.857 14.857 0 27.429-12.571 27.429-27.429zM746.857 220c0 1.143 0 4-0.571 5.143-120.571 215.429-240 432-360.571 647.429l-28 50.857c-3.429 5.714-9.714 9.143-16 9.143-10.286 0-64.571-33.143-76.571-40-5.714-3.429-9.143-9.143-9.143-16 0-9.143 19.429-40 25.143-49.714-110.857-50.286-204-136-269.714-238.857-7.429-11.429-11.429-25.143-11.429-39.429 0-13.714 4-28 11.429-39.429 113.143-173.714 289.714-289.714 500.571-289.714 34.286 0 69.143 3.429 102.857 9.714l30.857-55.429c3.429-5.714 9.143-9.143 16-9.143 10.286 0 64 33.143 76 40 5.714 3.429 9.143 9.143 9.143 15.429zM768 475.429c0 106.286-65.714 201.143-164.571 238.857l160-286.857c2.857 16 4.571 32 4.571 48zM1024 548.571c0 14.857-4 26.857-11.429 39.429-17.714 29.143-40 57.143-62.286 82.857-112 128.571-266.286 206.857-438.286 206.857l42.286-75.429c166.286-14.286 307.429-115.429 396.571-253.714-42.286-65.714-96.571-123.429-161.143-168l36-64c70.857 47.429 142.286 118.857 186.857 192.571 7.429 12.571 11.429 24.571 11.429 39.429z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["eye-slash"],"defaultCode":61552,"grid":14},"attrs":[],"properties":{"name":"eye-slash","id":99,"order":108,"prevSize":28,"code":61552},"setIdx":0,"setId":1,"iconIdx":104},{"icon":{"paths":["M585.143 785.714v-108.571c0-10.286-8-18.857-18.286-18.857h-109.714c-10.286 0-18.286 8.571-18.286 18.857v108.571c0 10.286 8 18.857 18.286 18.857h109.714c10.286 0 18.286-8.571 18.286-18.857zM584 572l10.286-262.286c0-3.429-1.714-8-5.714-10.857-3.429-2.857-8.571-6.286-13.714-6.286h-125.714c-5.143 0-10.286 3.429-13.714 6.286-4 2.857-5.714 8.571-5.714 12l9.714 261.143c0 7.429 8.571 13.143 19.429 13.143h105.714c10.286 0 18.857-5.714 19.429-13.143zM576 38.286l438.857 804.571c12.571 22.286 12 49.714-1.143 72s-37.143 36-62.857 36h-877.714c-25.714 0-49.714-13.714-62.857-36s-13.714-49.714-1.143-72l438.857-804.571c12.571-23.429 37.143-38.286 64-38.286s51.429 14.857 64 38.286z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["exclamation-triangle","warning"],"defaultCode":61553,"grid":14},"attrs":[],"properties":{"name":"exclamation-triangle, warning","id":100,"order":109,"prevSize":28,"code":61553},"setIdx":0,"setId":1,"iconIdx":105},{"icon":{"paths":["M73.143 950.857h164.571v-164.571h-164.571v164.571zM274.286 950.857h182.857v-164.571h-182.857v164.571zM73.143 749.714h164.571v-182.857h-164.571v182.857zM274.286 749.714h182.857v-182.857h-182.857v182.857zM73.143 530.286h164.571v-164.571h-164.571v164.571zM493.714 950.857h182.857v-164.571h-182.857v164.571zM274.286 530.286h182.857v-164.571h-182.857v164.571zM713.143 950.857h164.571v-164.571h-164.571v164.571zM493.714 749.714h182.857v-182.857h-182.857v182.857zM292.571 256v-164.571c0-9.714-8.571-18.286-18.286-18.286h-36.571c-9.714 0-18.286 8.571-18.286 18.286v164.571c0 9.714 8.571 18.286 18.286 18.286h36.571c9.714 0 18.286-8.571 18.286-18.286zM713.143 749.714h164.571v-182.857h-164.571v182.857zM493.714 530.286h182.857v-164.571h-182.857v164.571zM713.143 530.286h164.571v-164.571h-164.571v164.571zM731.429 256v-164.571c0-9.714-8.571-18.286-18.286-18.286h-36.571c-9.714 0-18.286 8.571-18.286 18.286v164.571c0 9.714 8.571 18.286 18.286 18.286h36.571c9.714 0 18.286-8.571 18.286-18.286zM950.857 219.429v731.429c0 40-33.143 73.143-73.143 73.143h-804.571c-40 0-73.143-33.143-73.143-73.143v-731.429c0-40 33.143-73.143 73.143-73.143h73.143v-54.857c0-50.286 41.143-91.429 91.429-91.429h36.571c50.286 0 91.429 41.143 91.429 91.429v54.857h219.429v-54.857c0-50.286 41.143-91.429 91.429-91.429h36.571c50.286 0 91.429 41.143 91.429 91.429v54.857h73.143c40 0 73.143 33.143 73.143 73.143z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["calendar"],"defaultCode":61555,"grid":14},"attrs":[],"properties":{"name":"calendar","id":101,"order":111,"prevSize":28,"code":61555},"setIdx":0,"setId":1,"iconIdx":106},{"icon":{"paths":["M380.571 274.857c-32 49.143-55.429 102.286-78.286 156-33.143-69.143-69.714-138.286-156-138.286h-128c-10.286 0-18.286-8-18.286-18.286v-109.714c0-10.286 8-18.286 18.286-18.286h128c101.714 0 176.571 47.429 234.286 128.571zM1024 731.429c0 4.571-1.714 9.714-5.143 13.143l-182.857 182.857c-3.429 3.429-8.571 5.143-13.143 5.143-9.714 0-18.286-8.571-18.286-18.286v-109.714c-169.714 0-274.286 20-380-128.571 31.429-49.143 54.857-102.286 77.714-156 33.143 69.143 69.714 138.286 156 138.286h146.286v-109.714c0-10.286 8-18.286 18.286-18.286 5.143 0 9.714 2.286 13.714 5.714l182.286 182.286c3.429 3.429 5.143 8.571 5.143 13.143zM1024 219.429c0 4.571-1.714 9.714-5.143 13.143l-182.857 182.857c-3.429 3.429-8.571 5.143-13.143 5.143-9.714 0-18.286-8-18.286-18.286v-109.714h-146.286c-76 0-112 52-144 113.714-16.571 32-30.857 65.143-44.571 97.714-63.429 147.429-137.714 300.571-323.429 300.571h-128c-10.286 0-18.286-8-18.286-18.286v-109.714c0-10.286 8-18.286 18.286-18.286h128c76 0 112-52 144-113.714 16.571-32 30.857-65.143 44.571-97.714 63.429-147.429 137.714-300.571 323.429-300.571h146.286v-109.714c0-10.286 8-18.286 18.286-18.286 5.143 0 9.714 2.286 13.714 5.714l182.286 182.286c3.429 3.429 5.143 8.571 5.143 13.143z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["random"],"defaultCode":61556,"grid":14},"attrs":[],"properties":{"name":"random","id":102,"order":112,"prevSize":28,"code":61556},"setIdx":0,"setId":1,"iconIdx":107},{"icon":{"paths":["M1024 512c0 202.286-229.143 365.714-512 365.714-28 0-56-1.714-82.857-4.571-74.857 66.286-164 113.143-262.857 138.286-20.571 5.714-42.857 9.714-65.143 12.571-12.571 1.143-24.571-8-27.429-21.714v-0.571c-2.857-14.286 6.857-22.857 15.429-33.143 36-40.571 77.143-74.857 104-170.286-117.714-66.857-193.143-170.286-193.143-286.286 0-201.714 229.143-365.714 512-365.714s512 163.429 512 365.714z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["comment"],"defaultCode":61557,"grid":14},"attrs":[],"properties":{"name":"comment","id":103,"order":113,"prevSize":28,"code":61557},"setIdx":0,"setId":1,"iconIdx":108},{"icon":{"paths":["M961.714 760.571l-94.857 94.286c-14.286 14.286-37.143 14.286-51.429 0l-303.429-303.429-303.429 303.429c-14.286 14.286-37.143 14.286-51.429 0l-94.857-94.286c-14.286-14.286-14.286-37.714 0-52l424-423.429c14.286-14.286 37.143-14.286 51.429 0l424 423.429c14.286 14.286 14.286 37.714 0 52z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["chevron-up"],"defaultCode":61559,"grid":14},"attrs":[],"properties":{"name":"chevron-up","id":104,"order":115,"prevSize":28,"code":61559},"setIdx":0,"setId":1,"iconIdx":109},{"icon":{"paths":["M961.714 461.714l-424 423.429c-14.286 14.286-37.143 14.286-51.429 0l-424-423.429c-14.286-14.286-14.286-37.714 0-52l94.857-94.286c14.286-14.286 37.143-14.286 51.429 0l303.429 303.429 303.429-303.429c14.286-14.286 37.143-14.286 51.429 0l94.857 94.286c14.286 14.286 14.286 37.714 0 52z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["chevron-down"],"defaultCode":61560,"grid":14},"attrs":[],"properties":{"name":"chevron-down","id":105,"order":116,"prevSize":28,"code":61560},"setIdx":0,"setId":1,"iconIdx":110},{"icon":{"paths":["M731.429 859.429c0 9.714-8.571 18.286-18.286 18.286h-548.571c-21.143 0-18.286-22.286-18.286-36.571v-329.143h-109.714c-20 0-36.571-16.571-36.571-36.571 0-8.571 2.857-17.143 8.571-23.429l182.857-219.429c6.857-8 17.143-12.571 28-12.571s21.143 4.571 28 12.571l182.857 219.429c5.714 6.286 8.571 14.857 8.571 23.429 0 20-16.571 36.571-36.571 36.571h-109.714v219.429h329.143c5.143 0 10.857 2.286 14.286 6.286l91.429 109.714c2.286 3.429 4 8 4 12zM1097.143 621.714c0 8.571-2.857 17.143-8.571 23.429l-182.857 219.429c-6.857 8-17.143 13.143-28 13.143s-21.143-5.143-28-13.143l-182.857-219.429c-5.714-6.286-8.571-14.857-8.571-23.429 0-20 16.571-36.571 36.571-36.571h109.714v-219.429h-329.143c-5.143 0-10.857-2.286-14.286-6.857l-91.429-109.714c-2.286-2.857-4-7.429-4-11.429 0-9.714 8.571-18.286 18.286-18.286h548.571c21.143 0 18.286 22.286 18.286 36.571v329.143h109.714c20 0 36.571 16.571 36.571 36.571z"],"width":1097.142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["retweet"],"defaultCode":61561,"grid":14},"attrs":[],"properties":{"name":"retweet","id":106,"order":117,"prevSize":28,"code":61561},"setIdx":0,"setId":1,"iconIdx":111},{"icon":{"paths":["M950.857 347.429v402.286c0 70.286-57.714 128-128 128h-694.857c-70.286 0-128-57.714-128-128v-548.571c0-70.286 57.714-128 128-128h182.857c70.286 0 128 57.714 128 128v18.286h384c70.286 0 128 57.714 128 128z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["folder"],"defaultCode":61563,"grid":14},"attrs":[],"properties":{"name":"folder","id":107,"order":119,"prevSize":28,"code":61563},"setIdx":0,"setId":1,"iconIdx":112},{"icon":{"paths":["M1073.714 544c0 13.714-8.571 27.429-17.714 37.714l-192 226.286c-33.143 38.857-100.571 69.714-150.857 69.714h-621.714c-20.571 0-49.714-6.286-49.714-32 0-13.714 8.571-27.429 17.714-37.714l192-226.286c33.143-38.857 100.571-69.714 150.857-69.714h621.714c20.571 0 49.714 6.286 49.714 32zM877.714 347.429v91.429h-475.429c-71.429 0-160 40.571-206.286 95.429l-195.429 229.714c0-4.571-0.571-9.714-0.571-14.286v-548.571c0-70.286 57.714-128 128-128h182.857c70.286 0 128 57.714 128 128v18.286h310.857c70.286 0 128 57.714 128 128z"],"width":1073.7371428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["folder-open"],"defaultCode":61564,"grid":14},"attrs":[],"properties":{"name":"folder-open","id":108,"order":120,"prevSize":28,"code":61564},"setIdx":0,"setId":1,"iconIdx":113},{"icon":{"paths":["M402.286 182.857c0 20-16.571 36.571-36.571 36.571h-73.143v585.143h73.143c20 0 36.571 16.571 36.571 36.571 0 9.714-4 18.857-10.857 25.714l-146.286 146.286c-6.857 6.857-16 10.857-25.714 10.857s-18.857-4-25.714-10.857l-146.286-146.286c-6.857-6.857-10.857-16-10.857-25.714 0-20 16.571-36.571 36.571-36.571h73.143v-585.143h-73.143c-20 0-36.571-16.571-36.571-36.571 0-9.714 4-18.857 10.857-25.714l146.286-146.286c6.857-6.857 16-10.857 25.714-10.857s18.857 4 25.714 10.857l146.286 146.286c6.857 6.857 10.857 16 10.857 25.714z"],"width":438.85714285714283,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["arrows-v"],"defaultCode":61565,"grid":14},"attrs":[],"properties":{"name":"arrows-v","id":109,"order":121,"prevSize":28,"code":61565},"setIdx":0,"setId":1,"iconIdx":114},{"icon":{"paths":["M1024 512c0 9.714-4 18.857-10.857 25.714l-146.286 146.286c-6.857 6.857-16 10.857-25.714 10.857-20 0-36.571-16.571-36.571-36.571v-73.143h-585.143v73.143c0 20-16.571 36.571-36.571 36.571-9.714 0-18.857-4-25.714-10.857l-146.286-146.286c-6.857-6.857-10.857-16-10.857-25.714s4-18.857 10.857-25.714l146.286-146.286c6.857-6.857 16-10.857 25.714-10.857 20 0 36.571 16.571 36.571 36.571v73.143h585.143v-73.143c0-20 16.571-36.571 36.571-36.571 9.714 0 18.857 4 25.714 10.857l146.286 146.286c6.857 6.857 10.857 16 10.857 25.714z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["arrows-h"],"defaultCode":61566,"grid":14},"attrs":[],"properties":{"name":"arrows-h","id":110,"order":122,"prevSize":28,"code":61566},"setIdx":0,"setId":1,"iconIdx":115},{"icon":{"paths":["M512 512c0-80.571-65.714-146.286-146.286-146.286s-146.286 65.714-146.286 146.286 65.714 146.286 146.286 146.286 146.286-65.714 146.286-146.286zM950.857 804.571c0-40-33.143-73.143-73.143-73.143s-73.143 33.143-73.143 73.143c0 40.571 33.143 73.143 73.143 73.143 40.571 0 73.143-33.143 73.143-73.143zM950.857 219.429c0-40-33.143-73.143-73.143-73.143s-73.143 33.143-73.143 73.143c0 40.571 33.143 73.143 73.143 73.143 40.571 0 73.143-33.143 73.143-73.143zM731.429 460v105.714c0 7.429-5.714 16-13.143 17.143l-88.571 13.714c-4.571 14.857-10.857 29.143-18.286 43.429 16 22.857 33.143 44 51.429 65.714 2.286 3.429 4 6.857 4 11.429 0 4-1.143 8-4 10.857-11.429 15.429-75.429 85.143-92 85.143-4.571 0-8.571-1.714-12-4l-65.714-51.429c-14.286 7.429-28.571 13.143-44 17.714-2.857 29.143-5.714 60.571-13.143 88.571-2.286 8-9.143 13.714-17.143 13.714h-106.286c-8 0-16-6.286-17.143-14.286l-13.143-87.429c-14.857-4.571-29.143-10.857-42.857-17.714l-67.429 50.857c-2.857 2.857-7.429 4-11.429 4-4.571 0-8.571-1.714-12-4.571-14.857-13.714-82.286-74.857-82.286-91.429 0-4 1.714-7.429 4-10.857 16.571-21.714 33.714-42.857 50.286-65.143-8-15.429-14.857-30.857-20-46.857l-86.857-13.714c-8-1.143-13.714-8.571-13.714-16.571v-105.714c0-7.429 5.714-16 13.143-17.143l88.571-13.714c4.571-14.857 10.857-29.143 18.286-43.429-16-22.857-33.143-44-51.429-65.714-2.286-3.429-4-7.429-4-11.429s1.143-8 4-11.429c11.429-15.429 75.429-84.571 92-84.571 4.571 0 8.571 1.714 12 4l65.714 51.429c14.286-7.429 28.571-13.143 44-18.286 2.857-28.571 5.714-60 13.143-88 2.286-8 9.143-13.714 17.143-13.714h106.286c8 0 16 6.286 17.143 14.286l13.143 87.429c14.857 4.571 29.143 10.857 42.857 17.714l67.429-50.857c3.429-2.857 7.429-4 11.429-4 4.571 0 8.571 1.714 12 4.571 14.857 13.714 82.286 75.429 82.286 91.429 0 4-1.714 7.429-4 10.857-16.571 22.286-33.714 42.857-49.714 65.143 7.429 15.429 14.286 30.857 19.429 46.857l86.857 13.143c8 1.714 13.714 9.143 13.714 17.143zM1097.143 764.571v80c0 8.571-73.714 16.571-85.143 17.714-4.571 10.857-10.286 20.571-17.143 29.714 5.143 11.429 29.143 68.571 29.143 78.857 0 1.714-0.571 2.857-2.286 4-6.857 4-68 40.571-70.857 40.571-7.429 0-50.286-57.143-56-65.714-5.714 0.571-11.429 1.143-17.143 1.143s-11.429-0.571-17.143-1.143c-5.714 8.571-48.571 65.714-56 65.714-2.857 0-64-36.571-70.857-40.571-1.714-1.143-2.286-2.857-2.286-4 0-9.714 24-67.429 29.143-78.857-6.857-9.143-12.571-18.857-17.143-29.714-11.429-1.143-85.143-9.143-85.143-17.714v-80c0-8.571 73.714-16.571 85.143-17.714 4.571-10.286 10.286-20.571 17.143-29.714-5.143-11.429-29.143-69.143-29.143-78.857 0-1.143 0.571-2.857 2.286-4 6.857-3.429 68-40 70.857-40 7.429 0 50.286 56.571 56 65.143 5.714-0.571 11.429-1.143 17.143-1.143s11.429 0.571 17.143 1.143c16-22.286 33.143-44.571 52.571-64l3.429-1.143c2.857 0 64 36 70.857 40 1.714 1.143 2.286 2.857 2.286 4 0 10.286-24 67.429-29.143 78.857 6.857 9.143 12.571 19.429 17.143 29.714 11.429 1.143 85.143 9.143 85.143 17.714zM1097.143 179.429v80c0 8.571-73.714 16.571-85.143 17.714-4.571 10.857-10.286 20.571-17.143 29.714 5.143 11.429 29.143 68.571 29.143 78.857 0 1.714-0.571 2.857-2.286 4-6.857 4-68 40.571-70.857 40.571-7.429 0-50.286-57.143-56-65.714-5.714 0.571-11.429 1.143-17.143 1.143s-11.429-0.571-17.143-1.143c-5.714 8.571-48.571 65.714-56 65.714-2.857 0-64-36.571-70.857-40.571-1.714-1.143-2.286-2.857-2.286-4 0-9.714 24-67.429 29.143-78.857-6.857-9.143-12.571-18.857-17.143-29.714-11.429-1.143-85.143-9.143-85.143-17.714v-80c0-8.571 73.714-16.571 85.143-17.714 4.571-10.286 10.286-20.571 17.143-29.714-5.143-11.429-29.143-69.143-29.143-78.857 0-1.143 0.571-2.857 2.286-4 6.857-3.429 68-40 70.857-40 7.429 0 50.286 56.571 56 65.143 5.714-0.571 11.429-1.143 17.143-1.143s11.429 0.571 17.143 1.143c16-22.286 33.143-44.571 52.571-64l3.429-1.143c2.857 0 64 36 70.857 40 1.714 1.143 2.286 2.857 2.286 4 0 10.286-24 67.429-29.143 78.857 6.857 9.143 12.571 19.429 17.143 29.714 11.429 1.143 85.143 9.143 85.143 17.714z"],"width":1097.142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["cogs","gears"],"defaultCode":61573,"grid":14},"attrs":[],"properties":{"name":"cogs, gears","id":111,"order":128,"prevSize":28,"code":61573},"setIdx":0,"setId":1,"iconIdx":116},{"icon":{"paths":["M475.429 18.286v765.143l-256.571 134.857c-7.429 4-14.857 6.857-22.857 6.857-16.571 0-24-13.714-24-28.571 0-4 0.571-7.429 1.143-11.429l49.143-285.714-208-202.286c-6.857-7.429-14.286-17.143-14.286-27.429 0-17.143 17.714-24 32-26.286l286.857-41.714 128.571-260c5.143-10.857 14.857-23.429 28-23.429v0z"],"width":475.4285714285714,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["star-half"],"defaultCode":61577,"grid":14},"attrs":[],"properties":{"name":"star-half","id":112,"order":132,"prevSize":28,"code":61577},"setIdx":0,"setId":1,"iconIdx":117},{"icon":{"paths":["M950.857 340.571c0-160.571-108.571-194.286-200-194.286-85.143 0-181.143 92-210.857 127.429-13.714 16.571-42.286 16.571-56 0-29.714-35.429-125.714-127.429-210.857-127.429-91.429 0-200 33.714-200 194.286 0 104.571 105.714 201.714 106.857 202.857l332 320 331.429-319.429c1.714-1.714 107.429-98.857 107.429-203.429zM1024 340.571c0 137.143-125.714 252-130.857 257.143l-356 342.857c-6.857 6.857-16 10.286-25.143 10.286s-18.286-3.429-25.143-10.286l-356.571-344c-4.571-4-130.286-118.857-130.286-256 0-167.429 102.286-267.429 273.143-267.429 100 0 193.714 78.857 238.857 123.429 45.143-44.571 138.857-123.429 238.857-123.429 170.857 0 273.143 100 273.143 267.429z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["heart-o"],"defaultCode":61578,"grid":14},"attrs":[],"properties":{"name":"heart-o","id":113,"order":133,"prevSize":28,"code":61578},"setIdx":0,"setId":1,"iconIdx":118},{"icon":{"paths":["M365.714 822.857c0 16 7.429 54.857-18.286 54.857h-182.857c-90.857 0-164.571-73.714-164.571-164.571v-402.286c0-90.857 73.714-164.571 164.571-164.571h182.857c9.714 0 18.286 8.571 18.286 18.286 0 16 7.429 54.857-18.286 54.857h-182.857c-50.286 0-91.429 41.143-91.429 91.429v402.286c0 50.286 41.143 91.429 91.429 91.429h164.571c14.286 0 36.571-2.857 36.571 18.286zM896 512c0 9.714-4 18.857-10.857 25.714l-310.857 310.857c-6.857 6.857-16 10.857-25.714 10.857-20 0-36.571-16.571-36.571-36.571v-164.571h-256c-20 0-36.571-16.571-36.571-36.571v-219.429c0-20 16.571-36.571 36.571-36.571h256v-164.571c0-20 16.571-36.571 36.571-36.571 9.714 0 18.857 4 25.714 10.857l310.857 310.857c6.857 6.857 10.857 16 10.857 25.714z"],"width":896,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["sign-out"],"defaultCode":61579,"grid":14},"attrs":[],"properties":{"name":"sign-out","id":114,"order":134,"prevSize":28,"code":61579},"setIdx":0,"setId":1,"iconIdx":119},{"icon":{"paths":["M274.286 493.714v-256c0-10.286-8-18.286-18.286-18.286s-18.286 8-18.286 18.286v256c0 10.286 8 18.286 18.286 18.286s18.286-8 18.286-18.286zM658.286 694.857c0 20-16.571 36.571-36.571 36.571h-245.143l-29.143 276c-1.143 9.143-8.571 16.571-17.714 16.571h-0.571c-9.143 0-16.571-6.286-18.286-15.429l-43.429-277.143h-230.857c-20 0-36.571-16.571-36.571-36.571 0-93.714 70.857-182.857 146.286-182.857v-292.571c-40 0-73.143-33.143-73.143-73.143s33.143-73.143 73.143-73.143h365.714c40 0 73.143 33.143 73.143 73.143s-33.143 73.143-73.143 73.143v292.571c75.429 0 146.286 89.143 146.286 182.857z"],"width":658.2857142857142,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["thumb-tack"],"defaultCode":61581,"grid":14},"attrs":[],"properties":{"name":"thumb-tack","id":115,"order":136,"prevSize":28,"code":61581},"setIdx":0,"setId":1,"iconIdx":120},{"icon":{"paths":["M804.571 530.286v182.857c0 90.857-73.714 164.571-164.571 164.571h-475.429c-90.857 0-164.571-73.714-164.571-164.571v-475.429c0-90.857 73.714-164.571 164.571-164.571h402.286c10.286 0 18.286 8 18.286 18.286v36.571c0 10.286-8 18.286-18.286 18.286h-402.286c-50.286 0-91.429 41.143-91.429 91.429v475.429c0 50.286 41.143 91.429 91.429 91.429h475.429c50.286 0 91.429-41.143 91.429-91.429v-182.857c0-10.286 8-18.286 18.286-18.286h36.571c10.286 0 18.286 8 18.286 18.286zM1024 36.571v292.571c0 20-16.571 36.571-36.571 36.571-9.714 0-18.857-4-25.714-10.857l-100.571-100.571-372.571 372.571c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-65.143-65.143c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l372.571-372.571-100.571-100.571c-6.857-6.857-10.857-16-10.857-25.714 0-20 16.571-36.571 36.571-36.571h292.571c20 0 36.571 16.571 36.571 36.571z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["external-link"],"defaultCode":61582,"grid":14},"attrs":[],"properties":{"name":"external-link","id":116,"order":137,"prevSize":28,"code":61582},"setIdx":0,"setId":1,"iconIdx":121},{"icon":{"paths":["M676.571 512c0 9.714-4 18.857-10.857 25.714l-310.857 310.857c-6.857 6.857-16 10.857-25.714 10.857-20 0-36.571-16.571-36.571-36.571v-164.571h-256c-20 0-36.571-16.571-36.571-36.571v-219.429c0-20 16.571-36.571 36.571-36.571h256v-164.571c0-20 16.571-36.571 36.571-36.571 9.714 0 18.857 4 25.714 10.857l310.857 310.857c6.857 6.857 10.857 16 10.857 25.714zM877.714 310.857v402.286c0 90.857-73.714 164.571-164.571 164.571h-182.857c-9.714 0-18.286-8.571-18.286-18.286 0-16-7.429-54.857 18.286-54.857h182.857c50.286 0 91.429-41.143 91.429-91.429v-402.286c0-50.286-41.143-91.429-91.429-91.429h-164.571c-14.286 0-36.571 2.857-36.571-18.286 0-16-7.429-54.857 18.286-54.857h182.857c90.857 0 164.571 73.714 164.571 164.571z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["sign-in"],"defaultCode":61584,"grid":14},"attrs":[],"properties":{"name":"sign-in","id":117,"order":138,"prevSize":28,"code":61584},"setIdx":0,"setId":1,"iconIdx":122},{"icon":{"paths":["M731.429 841.143c0-20-16.571-36.571-36.571-36.571s-36.571 16.571-36.571 36.571 16.571 36.571 36.571 36.571 36.571-16.571 36.571-36.571zM877.714 841.143c0-20-16.571-36.571-36.571-36.571s-36.571 16.571-36.571 36.571 16.571 36.571 36.571 36.571 36.571-16.571 36.571-36.571zM950.857 713.143v182.857c0 30.286-24.571 54.857-54.857 54.857h-841.143c-30.286 0-54.857-24.571-54.857-54.857v-182.857c0-30.286 24.571-54.857 54.857-54.857h244c15.429 42.286 56 73.143 103.429 73.143h146.286c47.429 0 88-30.857 103.429-73.143h244c30.286 0 54.857 24.571 54.857 54.857zM765.143 342.857c-5.714 13.714-18.857 22.857-33.714 22.857h-146.286v256c0 20-16.571 36.571-36.571 36.571h-146.286c-20 0-36.571-16.571-36.571-36.571v-256h-146.286c-14.857 0-28-9.143-33.714-22.857-5.714-13.143-2.857-29.143 8-39.429l256-256c6.857-7.429 16.571-10.857 25.714-10.857s18.857 3.429 25.714 10.857l256 256c10.857 10.286 13.714 26.286 8 39.429z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["upload"],"defaultCode":61587,"grid":14},"attrs":[],"properties":{"name":"upload","id":118,"order":141,"prevSize":28,"code":61587},"setIdx":0,"setId":1,"iconIdx":123},{"icon":{"paths":["M640 146.286h-475.429c-50.286 0-91.429 41.143-91.429 91.429v475.429c0 50.286 41.143 91.429 91.429 91.429h475.429c50.286 0 91.429-41.143 91.429-91.429v-475.429c0-50.286-41.143-91.429-91.429-91.429zM804.571 237.714v475.429c0 90.857-73.714 164.571-164.571 164.571h-475.429c-90.857 0-164.571-73.714-164.571-164.571v-475.429c0-90.857 73.714-164.571 164.571-164.571h475.429c90.857 0 164.571 73.714 164.571 164.571z"],"width":804.5714285714286,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["square-o"],"defaultCode":61590,"grid":14},"attrs":[],"properties":{"name":"square-o","id":119,"order":144,"prevSize":28,"code":61590},"setIdx":0,"setId":1,"iconIdx":124},{"icon":{"paths":["M658.286 146.286h-585.143v709.714l292.571-280.571 50.857 48.571 241.714 232v-709.714zM665.143 73.143c8.571 0 17.143 1.714 25.143 5.143 25.143 9.714 41.143 33.143 41.143 58.857v736.571c0 25.714-16 49.143-41.143 58.857-8 3.429-16.571 4.571-25.143 4.571-17.714 0-34.286-6.286-47.429-18.286l-252-242.286-252 242.286c-13.143 12-29.714 18.857-47.429 18.857-8.571 0-17.143-1.714-25.143-5.143-25.143-9.714-41.143-33.143-41.143-58.857v-736.571c0-25.714 16-49.143 41.143-58.857 8-3.429 16.571-5.143 25.143-5.143h598.857z"],"width":731.4285714285713,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["bookmark-o"],"defaultCode":61591,"grid":14},"attrs":[],"properties":{"name":"bookmark-o","id":120,"order":145,"prevSize":28,"code":61591},"setIdx":0,"setId":1,"iconIdx":125},{"icon":{"paths":["M594.286 694.857c0 25.143-20.571 45.714-45.714 45.714s-45.714-20.571-45.714-45.714 20.571-45.714 45.714-45.714 45.714 20.571 45.714 45.714zM740.571 694.857c0 25.143-20.571 45.714-45.714 45.714s-45.714-20.571-45.714-45.714 20.571-45.714 45.714-45.714 45.714 20.571 45.714 45.714zM804.571 786.286v-182.857c0-9.714-8.571-18.286-18.286-18.286h-694.857c-9.714 0-18.286 8.571-18.286 18.286v182.857c0 9.714 8.571 18.286 18.286 18.286h694.857c9.714 0 18.286-8.571 18.286-18.286zM101.714 512h674.286l-89.714-275.429c-2.857-9.714-13.714-17.143-24-17.143h-446.857c-10.286 0-21.143 7.429-24 17.143zM877.714 603.429v182.857c0 50.286-41.143 91.429-91.429 91.429h-694.857c-50.286 0-91.429-41.143-91.429-91.429v-182.857c0-15.429 4.571-28.571 9.143-42.857l112.571-346.286c13.143-40 51.429-68 93.714-68h446.857c42.286 0 80.571 28 93.714 68l112.571 346.286c4.571 14.286 9.143 27.429 9.143 42.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["hdd-o"],"defaultCode":61600,"grid":14},"attrs":[],"properties":{"name":"hdd-o","id":121,"order":153,"prevSize":28,"code":61600},"setIdx":0,"setId":1,"iconIdx":126},{"icon":{"paths":["M521.143 969.143c0-5.143-4-9.143-9.143-9.143-45.143 0-82.286-37.143-82.286-82.286 0-5.143-4-9.143-9.143-9.143s-9.143 4-9.143 9.143c0 55.429 45.143 100.571 100.571 100.571 5.143 0 9.143-4 9.143-9.143zM140.571 804.571h742.857c-102.286-115.429-152-272-152-475.429 0-73.714-69.714-182.857-219.429-182.857s-219.429 109.143-219.429 182.857c0 203.429-49.714 360-152 475.429zM987.429 804.571c0 40-33.143 73.143-73.143 73.143h-256c0 80.571-65.714 146.286-146.286 146.286s-146.286-65.714-146.286-146.286h-256c-40 0-73.143-33.143-73.143-73.143 84.571-71.429 182.857-199.429 182.857-475.429 0-109.714 90.857-229.714 242.286-252-2.857-6.857-4.571-14.286-4.571-22.286 0-30.286 24.571-54.857 54.857-54.857s54.857 24.571 54.857 54.857c0 8-1.714 15.429-4.571 22.286 151.429 22.286 242.286 142.286 242.286 252 0 276 98.286 404 182.857 475.429z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["bell-o"],"defaultCode":61602,"grid":14},"attrs":[],"properties":{"name":"bell-o","id":122,"order":686,"prevSize":28,"code":61602},"setIdx":0,"setId":1,"iconIdx":127},{"icon":{"paths":["M786.286 512l78.857 77.143c10.857 10.286 14.857 25.714 11.429 40-4 14.286-15.429 25.714-29.714 29.143l-107.429 27.429 30.286 106.286c4 14.286 0 29.714-10.857 40-10.286 10.857-25.714 14.857-40 10.857l-106.286-30.286-27.429 107.429c-3.429 14.286-14.857 25.714-29.143 29.714-3.429 0.571-7.429 1.143-10.857 1.143-10.857 0-21.714-4.571-29.143-12.571l-77.143-78.857-77.143 78.857c-10.286 10.857-25.714 14.857-40 11.429-14.857-4-25.714-15.429-29.143-29.714l-27.429-107.429-106.286 30.286c-14.286 4-29.714 0-40-10.857-10.857-10.286-14.857-25.714-10.857-40l30.286-106.286-107.429-27.429c-14.286-3.429-25.714-14.857-29.714-29.143-3.429-14.286 0.571-29.714 11.429-40l78.857-77.143-78.857-77.143c-10.857-10.286-14.857-25.714-11.429-40 4-14.286 15.429-25.714 29.714-29.143l107.429-27.429-30.286-106.286c-4-14.286 0-29.714 10.857-40 10.286-10.857 25.714-14.857 40-10.857l106.286 30.286 27.429-107.429c3.429-14.286 14.857-25.714 29.143-29.143 14.286-4 29.714 0 40 10.857l77.143 79.429 77.143-79.429c10.286-10.857 25.143-14.857 40-10.857 14.286 3.429 25.714 14.857 29.143 29.143l27.429 107.429 106.286-30.286c14.286-4 29.714 0 40 10.857 10.857 10.286 14.857 25.714 10.857 40l-30.286 106.286 107.429 27.429c14.286 3.429 25.714 14.857 29.714 29.143 3.429 14.286-0.571 29.714-11.429 40z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["certificate"],"defaultCode":61603,"grid":14},"attrs":[],"properties":{"name":"certificate","id":123,"order":687,"prevSize":28,"code":61603},"setIdx":0,"setId":1,"iconIdx":128},{"icon":{"paths":["M731.429 548.571v-73.143c0-20-16.571-36.571-36.571-36.571h-286.857l108-108c6.857-6.857 10.857-16 10.857-25.714s-4-18.857-10.857-25.714l-52-52c-6.857-6.857-16-10.286-25.714-10.286s-18.857 3.429-25.714 10.286l-258.857 258.857c-6.857 6.857-10.286 16-10.286 25.714s3.429 18.857 10.286 25.714l258.857 258.857c6.857 6.857 16 10.286 25.714 10.286s18.857-3.429 25.714-10.286l52-52c6.857-6.857 10.286-16 10.286-25.714s-3.429-18.857-10.286-25.714l-108-108h286.857c20 0 36.571-16.571 36.571-36.571zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["arrow-circle-left"],"defaultCode":61608,"grid":14},"attrs":[],"properties":{"name":"arrow-circle-left","id":124,"order":161,"prevSize":28,"code":61608},"setIdx":0,"setId":1,"iconIdx":129},{"icon":{"paths":["M734.286 512c0-9.714-3.429-18.857-10.286-25.714l-258.857-258.857c-6.857-6.857-16-10.286-25.714-10.286s-18.857 3.429-25.714 10.286l-52 52c-6.857 6.857-10.286 16-10.286 25.714s3.429 18.857 10.286 25.714l108 108h-286.857c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h286.857l-108 108c-6.857 6.857-10.857 16-10.857 25.714s4 18.857 10.857 25.714l52 52c6.857 6.857 16 10.286 25.714 10.286s18.857-3.429 25.714-10.286l258.857-258.857c6.857-6.857 10.286-16 10.286-25.714zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["arrow-circle-right"],"defaultCode":61609,"grid":14},"attrs":[],"properties":{"name":"arrow-circle-right","id":125,"order":162,"prevSize":28,"code":61609},"setIdx":0,"setId":1,"iconIdx":130},{"icon":{"paths":["M733.714 511.429c0-9.714-3.429-18.857-10.286-25.714l-258.857-258.857c-6.857-6.857-16-10.286-25.714-10.286s-18.857 3.429-25.714 10.286l-258.857 258.857c-6.857 6.857-10.286 16-10.286 25.714s3.429 18.857 10.286 25.714l52 52c6.857 6.857 16 10.286 25.714 10.286s18.857-3.429 25.714-10.286l108-108v286.857c0 20 16.571 36.571 36.571 36.571h73.143c20 0 36.571-16.571 36.571-36.571v-286.857l108 108c6.857 6.857 16 10.857 25.714 10.857s18.857-4 25.714-10.857l52-52c6.857-6.857 10.286-16 10.286-25.714zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["arrow-circle-up"],"defaultCode":61610,"grid":14},"attrs":[],"properties":{"name":"arrow-circle-up","id":126,"order":163,"prevSize":28,"code":61610},"setIdx":0,"setId":1,"iconIdx":131},{"icon":{"paths":["M733.714 512.571c0-9.714-3.429-18.857-10.286-25.714l-52-52c-6.857-6.857-16-10.286-25.714-10.286s-18.857 3.429-25.714 10.286l-108 108v-286.857c0-20-16.571-36.571-36.571-36.571h-73.143c-20 0-36.571 16.571-36.571 36.571v286.857l-108-108c-6.857-6.857-16-10.857-25.714-10.857s-18.857 4-25.714 10.857l-52 52c-6.857 6.857-10.286 16-10.286 25.714s3.429 18.857 10.286 25.714l258.857 258.857c6.857 6.857 16 10.286 25.714 10.286s18.857-3.429 25.714-10.286l258.857-258.857c6.857-6.857 10.286-16 10.286-25.714zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["arrow-circle-down"],"defaultCode":61611,"grid":14},"attrs":[],"properties":{"name":"arrow-circle-down","id":127,"order":164,"prevSize":28,"code":61611},"setIdx":0,"setId":1,"iconIdx":132},{"icon":{"paths":["M219.429 841.143c0-20-16.571-36.571-36.571-36.571s-36.571 16.571-36.571 36.571 16.571 36.571 36.571 36.571 36.571-16.571 36.571-36.571zM587.429 601.143l-389.714 389.714c-13.143 13.143-32 21.143-51.429 21.143s-38.286-8-52-21.143l-60.571-61.714c-13.714-13.143-21.714-32-21.714-51.429s8-38.286 21.714-52l389.143-389.143c29.714 74.857 89.714 134.857 164.571 164.571zM949.714 352.571c0 18.857-6.857 42.286-13.143 60.571-36 101.714-133.714 172-241.714 172-141.143 0-256-114.857-256-256s114.857-256 256-256c41.714 0 96 12.571 130.857 36 5.714 4 9.143 9.143 9.143 16 0 6.286-4 12.571-9.143 16l-167.429 96.571v128l110.286 61.143c18.857-10.857 151.429-94.286 162.857-94.286s18.286 8.571 18.286 20z"],"width":961.6822857142856,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["wrench"],"defaultCode":61613,"grid":14},"attrs":[],"properties":{"name":"wrench","id":128,"order":166,"prevSize":28,"code":61613},"setIdx":0,"setId":1,"iconIdx":133},{"icon":{"paths":["M585.143 804.571h365.714v-73.143h-365.714v73.143zM365.714 512h585.143v-73.143h-585.143v73.143zM731.429 219.429h219.429v-73.143h-219.429v73.143zM1024 694.857v146.286c0 20-16.571 36.571-36.571 36.571h-950.857c-20 0-36.571-16.571-36.571-36.571v-146.286c0-20 16.571-36.571 36.571-36.571h950.857c20 0 36.571 16.571 36.571 36.571zM1024 402.286v146.286c0 20-16.571 36.571-36.571 36.571h-950.857c-20 0-36.571-16.571-36.571-36.571v-146.286c0-20 16.571-36.571 36.571-36.571h950.857c20 0 36.571 16.571 36.571 36.571zM1024 109.714v146.286c0 20-16.571 36.571-36.571 36.571h-950.857c-20 0-36.571-16.571-36.571-36.571v-146.286c0-20 16.571-36.571 36.571-36.571h950.857c20 0 36.571 16.571 36.571 36.571z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["tasks"],"defaultCode":61614,"grid":14},"attrs":[],"properties":{"name":"tasks","id":129,"order":167,"prevSize":28,"code":61614},"setIdx":0,"setId":1,"iconIdx":134},{"icon":{"paths":["M801.714 168.571c5.714 13.714 2.857 29.714-8 40l-281.714 281.714v424c0 14.857-9.143 28-22.286 33.714-4.571 1.714-9.714 2.857-14.286 2.857-9.714 0-18.857-3.429-25.714-10.857l-146.286-146.286c-6.857-6.857-10.857-16-10.857-25.714v-277.714l-281.714-281.714c-10.857-10.286-13.714-26.286-8-40 5.714-13.143 18.857-22.286 33.714-22.286h731.429c14.857 0 28 9.143 33.714 22.286z"],"width":804.5714285714286,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["filter"],"defaultCode":61616,"grid":14},"attrs":[],"properties":{"name":"filter","id":130,"order":168,"prevSize":28,"code":61616},"setIdx":0,"setId":1,"iconIdx":135},{"icon":{"paths":["M365.714 146.286h292.571v-73.143h-292.571v73.143zM1024 512v274.286c0 50.286-41.143 91.429-91.429 91.429h-841.143c-50.286 0-91.429-41.143-91.429-91.429v-274.286h384v91.429c0 20 16.571 36.571 36.571 36.571h182.857c20 0 36.571-16.571 36.571-36.571v-91.429h384zM585.143 512v73.143h-146.286v-73.143h146.286zM1024 237.714v219.429h-1024v-219.429c0-50.286 41.143-91.429 91.429-91.429h201.143v-91.429c0-30.286 24.571-54.857 54.857-54.857h329.143c30.286 0 54.857 24.571 54.857 54.857v91.429h201.143c50.286 0 91.429 41.143 91.429 91.429z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["briefcase"],"defaultCode":61617,"grid":14},"attrs":[],"properties":{"name":"briefcase","id":131,"order":169,"prevSize":28,"code":61617},"setIdx":0,"setId":1,"iconIdx":136},{"icon":{"paths":["M733.143 309.143l-202.857 202.857 202.857 202.857 82.286-82.286c10.286-10.857 26.286-13.714 40-8 13.143 5.714 22.286 18.857 22.286 33.714v256c0 20-16.571 36.571-36.571 36.571h-256c-14.857 0-28-9.143-33.714-22.857-5.714-13.143-2.857-29.143 8-39.429l82.286-82.286-202.857-202.857-202.857 202.857 82.286 82.286c10.857 10.286 13.714 26.286 8 39.429-5.714 13.714-18.857 22.857-33.714 22.857h-256c-20 0-36.571-16.571-36.571-36.571v-256c0-14.857 9.143-28 22.857-33.714 13.143-5.714 29.143-2.857 39.429 8l82.286 82.286 202.857-202.857-202.857-202.857-82.286 82.286c-6.857 6.857-16 10.857-25.714 10.857-4.571 0-9.714-1.143-13.714-2.857-13.714-5.714-22.857-18.857-22.857-33.714v-256c0-20 16.571-36.571 36.571-36.571h256c14.857 0 28 9.143 33.714 22.857 5.714 13.143 2.857 29.143-8 39.429l-82.286 82.286 202.857 202.857 202.857-202.857-82.286-82.286c-10.857-10.286-13.714-26.286-8-39.429 5.714-13.714 18.857-22.857 33.714-22.857h256c20 0 36.571 16.571 36.571 36.571v256c0 14.857-9.143 28-22.286 33.714-4.571 1.714-9.714 2.857-14.286 2.857-9.714 0-18.857-4-25.714-10.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["arrows-alt"],"defaultCode":61618,"grid":14},"attrs":[],"properties":{"name":"arrows-alt","id":132,"order":170,"prevSize":28,"code":61618},"setIdx":0,"setId":1,"iconIdx":137},{"icon":{"paths":["M1097.143 658.286c0 121.143-98.286 219.429-219.429 219.429h-621.714c-141.143 0-256-114.857-256-256 0-102.286 60.571-190.857 147.429-231.429-0.571-8-1.143-16.571-1.143-24.571 0-161.714 130.857-292.571 292.571-292.571 122.286 0 226.857 74.857 270.857 181.714 25.143-22.286 58.286-35.429 94.857-35.429 80.571 0 146.286 65.714 146.286 146.286 0 29.143-8.571 56-23.429 78.857 97.143 22.857 169.714 109.714 169.714 213.714z"],"width":1097.142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["cloud"],"defaultCode":61634,"grid":14},"attrs":[],"properties":{"name":"cloud","id":133,"order":173,"prevSize":28,"code":61634},"setIdx":0,"setId":1,"iconIdx":138},{"icon":{"paths":["M969.143 219.429c30.286 0 54.857 24.571 54.857 54.857v694.857c0 30.286-24.571 54.857-54.857 54.857h-548.571c-30.286 0-54.857-24.571-54.857-54.857v-164.571h-310.857c-30.286 0-54.857-24.571-54.857-54.857v-384c0-30.286 17.714-72.571 38.857-93.714l233.143-233.143c21.143-21.143 63.429-38.857 93.714-38.857h237.714c30.286 0 54.857 24.571 54.857 54.857v187.429c22.286-13.143 50.857-22.857 73.143-22.857h237.714zM658.286 341.143l-170.857 170.857h170.857v-170.857zM292.571 121.714l-170.857 170.857h170.857v-170.857zM404.571 491.429l180.571-180.571v-237.714h-219.429v237.714c0 30.286-24.571 54.857-54.857 54.857h-237.714v365.714h292.571v-146.286c0-30.286 17.714-72.571 38.857-93.714zM950.857 950.857v-658.286h-219.429v237.714c0 30.286-24.571 54.857-54.857 54.857h-237.714v365.714h512z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["copy","files-o"],"defaultCode":61637,"grid":14},"attrs":[],"properties":{"name":"copy, files-o","id":134,"order":176,"prevSize":28,"code":61637},"setIdx":0,"setId":1,"iconIdx":139},{"icon":{"paths":["M219.429 877.714h438.857v-219.429h-438.857v219.429zM731.429 877.714h73.143v-512c0-10.857-9.714-34.286-17.143-41.714l-160.571-160.571c-8-8-30.286-17.143-41.714-17.143v237.714c0 30.286-24.571 54.857-54.857 54.857h-329.143c-30.286 0-54.857-24.571-54.857-54.857v-237.714h-73.143v731.429h73.143v-237.714c0-30.286 24.571-54.857 54.857-54.857h475.429c30.286 0 54.857 24.571 54.857 54.857v237.714zM512 347.429v-182.857c0-9.714-8.571-18.286-18.286-18.286h-109.714c-9.714 0-18.286 8.571-18.286 18.286v182.857c0 9.714 8.571 18.286 18.286 18.286h109.714c9.714 0 18.286-8.571 18.286-18.286zM877.714 365.714v530.286c0 30.286-24.571 54.857-54.857 54.857h-768c-30.286 0-54.857-24.571-54.857-54.857v-768c0-30.286 24.571-54.857 54.857-54.857h530.286c30.286 0 72 17.143 93.714 38.857l160 160c21.714 21.714 38.857 63.429 38.857 93.714z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["floppy-o","save"],"defaultCode":61639,"grid":14},"attrs":[],"properties":{"name":"floppy-o, save","id":135,"order":178,"prevSize":28,"code":61639},"setIdx":0,"setId":1,"iconIdx":140},{"icon":{"paths":["M877.714 237.714v548.571c0 90.857-73.714 164.571-164.571 164.571h-548.571c-90.857 0-164.571-73.714-164.571-164.571v-548.571c0-90.857 73.714-164.571 164.571-164.571h548.571c90.857 0 164.571 73.714 164.571 164.571z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["square"],"defaultCode":61640,"grid":14},"attrs":[],"properties":{"name":"square","id":136,"order":179,"prevSize":28,"code":61640},"setIdx":0,"setId":1,"iconIdx":141},{"icon":{"paths":["M877.714 768v73.143c0 20-16.571 36.571-36.571 36.571h-804.571c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h804.571c20 0 36.571 16.571 36.571 36.571zM877.714 475.429v73.143c0 20-16.571 36.571-36.571 36.571h-804.571c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h804.571c20 0 36.571 16.571 36.571 36.571zM877.714 182.857v73.143c0 20-16.571 36.571-36.571 36.571h-804.571c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h804.571c20 0 36.571 16.571 36.571 36.571z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["bars","navicon","reorder"],"defaultCode":61641,"grid":14},"attrs":[],"properties":{"name":"bars, navicon, reorder","id":137,"order":180,"prevSize":28,"code":61641},"setIdx":0,"setId":1,"iconIdx":142},{"icon":{"paths":["M219.429 804.571c0 60.571-49.143 109.714-109.714 109.714s-109.714-49.143-109.714-109.714 49.143-109.714 109.714-109.714 109.714 49.143 109.714 109.714zM219.429 512c0 60.571-49.143 109.714-109.714 109.714s-109.714-49.143-109.714-109.714 49.143-109.714 109.714-109.714 109.714 49.143 109.714 109.714zM1024 749.714v109.714c0 9.714-8.571 18.286-18.286 18.286h-694.857c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h694.857c9.714 0 18.286 8.571 18.286 18.286zM219.429 219.429c0 60.571-49.143 109.714-109.714 109.714s-109.714-49.143-109.714-109.714 49.143-109.714 109.714-109.714 109.714 49.143 109.714 109.714zM1024 457.143v109.714c0 9.714-8.571 18.286-18.286 18.286h-694.857c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h694.857c9.714 0 18.286 8.571 18.286 18.286zM1024 164.571v109.714c0 9.714-8.571 18.286-18.286 18.286h-694.857c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h694.857c9.714 0 18.286 8.571 18.286 18.286z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["list-ul"],"defaultCode":61642,"grid":14},"attrs":[],"properties":{"name":"list-ul","id":138,"order":181,"prevSize":28,"code":61642},"setIdx":0,"setId":1,"iconIdx":143},{"icon":{"paths":["M217.714 925.714c0 62.857-49.143 98.286-108.571 98.286-36 0-72.571-12-98.286-37.714l32.571-50.286c15.429 14.286 38.857 25.714 60.571 25.714 20 0 41.143-9.714 41.143-32.571 0-32-36.571-33.714-60-32l-14.857-32c20.571-26.286 39.429-55.429 64-77.714v-0.571c-18.286 0-37.143 1.143-55.429 1.143v30.286h-60.571v-86.857h190.286v50.286l-54.286 65.714c38.286 9.143 63.429 38.857 63.429 78.286zM218.857 567.429v90.857h-206.857c-1.714-10.286-3.429-20.571-3.429-30.857 0-105.714 129.143-121.714 129.143-169.714 0-19.429-12-29.714-30.857-29.714-20 0-36.571 17.143-46.286 33.143l-48.571-33.714c18.857-39.429 57.714-61.714 101.143-61.714 53.143 0 98.857 31.429 98.857 88 0 84.571-124 103.429-125.714 148h72.571v-34.286h60zM1024 749.714v109.714c0 9.714-8.571 18.286-18.286 18.286h-694.857c-10.286 0-18.286-8.571-18.286-18.286v-109.714c0-10.286 8-18.286 18.286-18.286h694.857c9.714 0 18.286 8 18.286 18.286zM219.429 236v56.571h-191.429v-56.571h61.143c0-46.286 0.571-92.571 0.571-138.857v-6.857h-1.143c-6.286 12.571-17.714 21.143-28.571 30.857l-40.571-43.429 77.714-72.571h60.571v230.857h61.714zM1024 457.143v109.714c0 9.714-8.571 18.286-18.286 18.286h-694.857c-10.286 0-18.286-8.571-18.286-18.286v-109.714c0-10.286 8-18.286 18.286-18.286h694.857c9.714 0 18.286 8 18.286 18.286zM1024 164.571v109.714c0 9.714-8.571 18.286-18.286 18.286h-694.857c-10.286 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8-18.286 18.286-18.286h694.857c9.714 0 18.286 8.571 18.286 18.286z"],"width":1032.5577142857144,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["list-ol"],"defaultCode":61643,"grid":14},"attrs":[],"properties":{"name":"list-ol","id":139,"order":182,"prevSize":28,"code":61643},"setIdx":0,"setId":1,"iconIdx":144},{"icon":{"paths":["M292.571 786.286v-109.714c0-10.286-8-18.286-18.286-18.286h-182.857c-10.286 0-18.286 8-18.286 18.286v109.714c0 10.286 8 18.286 18.286 18.286h182.857c10.286 0 18.286-8 18.286-18.286zM292.571 566.857v-109.714c0-10.286-8-18.286-18.286-18.286h-182.857c-10.286 0-18.286 8-18.286 18.286v109.714c0 10.286 8 18.286 18.286 18.286h182.857c10.286 0 18.286-8 18.286-18.286zM585.143 786.286v-109.714c0-10.286-8-18.286-18.286-18.286h-182.857c-10.286 0-18.286 8-18.286 18.286v109.714c0 10.286 8 18.286 18.286 18.286h182.857c10.286 0 18.286-8 18.286-18.286zM292.571 347.429v-109.714c0-10.286-8-18.286-18.286-18.286h-182.857c-10.286 0-18.286 8-18.286 18.286v109.714c0 10.286 8 18.286 18.286 18.286h182.857c10.286 0 18.286-8 18.286-18.286zM585.143 566.857v-109.714c0-10.286-8-18.286-18.286-18.286h-182.857c-10.286 0-18.286 8-18.286 18.286v109.714c0 10.286 8 18.286 18.286 18.286h182.857c10.286 0 18.286-8 18.286-18.286zM877.714 786.286v-109.714c0-10.286-8-18.286-18.286-18.286h-182.857c-10.286 0-18.286 8-18.286 18.286v109.714c0 10.286 8 18.286 18.286 18.286h182.857c10.286 0 18.286-8 18.286-18.286zM585.143 347.429v-109.714c0-10.286-8-18.286-18.286-18.286h-182.857c-10.286 0-18.286 8-18.286 18.286v109.714c0 10.286 8 18.286 18.286 18.286h182.857c10.286 0 18.286-8 18.286-18.286zM877.714 566.857v-109.714c0-10.286-8-18.286-18.286-18.286h-182.857c-10.286 0-18.286 8-18.286 18.286v109.714c0 10.286 8 18.286 18.286 18.286h182.857c10.286 0 18.286-8 18.286-18.286zM877.714 347.429v-109.714c0-10.286-8-18.286-18.286-18.286h-182.857c-10.286 0-18.286 8-18.286 18.286v109.714c0 10.286 8 18.286 18.286 18.286h182.857c10.286 0 18.286-8 18.286-18.286zM950.857 164.571v621.714c0 50.286-41.143 91.429-91.429 91.429h-768c-50.286 0-91.429-41.143-91.429-91.429v-621.714c0-50.286 41.143-91.429 91.429-91.429h768c50.286 0 91.429 41.143 91.429 91.429z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["table"],"defaultCode":61646,"grid":14},"attrs":[],"properties":{"name":"table","id":140,"order":185,"prevSize":28,"code":61646},"setIdx":0,"setId":1,"iconIdx":145},{"icon":{"paths":["M585.143 402.286c0 9.714-4 18.857-10.857 25.714l-256 256c-6.857 6.857-16 10.857-25.714 10.857s-18.857-4-25.714-10.857l-256-256c-6.857-6.857-10.857-16-10.857-25.714 0-20 16.571-36.571 36.571-36.571h512c20 0 36.571 16.571 36.571 36.571z"],"width":585.1428571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["caret-down"],"defaultCode":61655,"grid":14},"attrs":[],"properties":{"name":"caret-down","id":141,"order":193,"prevSize":28,"code":61655},"setIdx":0,"setId":1,"iconIdx":146},{"icon":{"paths":["M585.143 694.857c0 20-16.571 36.571-36.571 36.571h-512c-20 0-36.571-16.571-36.571-36.571 0-9.714 4-18.857 10.857-25.714l256-256c6.857-6.857 16-10.857 25.714-10.857s18.857 4 25.714 10.857l256 256c6.857 6.857 10.857 16 10.857 25.714z"],"width":585.1428571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["caret-up"],"defaultCode":61656,"grid":14},"attrs":[],"properties":{"name":"caret-up","id":142,"order":194,"prevSize":28,"code":61656},"setIdx":0,"setId":1,"iconIdx":147},{"icon":{"paths":["M365.714 256v512c0 20-16.571 36.571-36.571 36.571-9.714 0-18.857-4-25.714-10.857l-256-256c-6.857-6.857-10.857-16-10.857-25.714s4-18.857 10.857-25.714l256-256c6.857-6.857 16-10.857 25.714-10.857 20 0 36.571 16.571 36.571 36.571z"],"width":402.2857142857143,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["caret-left"],"defaultCode":61657,"grid":14},"attrs":[],"properties":{"name":"caret-left","id":143,"order":195,"prevSize":28,"code":61657},"setIdx":0,"setId":1,"iconIdx":148},{"icon":{"paths":["M329.143 512c0 9.714-4 18.857-10.857 25.714l-256 256c-6.857 6.857-16 10.857-25.714 10.857-20 0-36.571-16.571-36.571-36.571v-512c0-20 16.571-36.571 36.571-36.571 9.714 0 18.857 4 25.714 10.857l256 256c6.857 6.857 10.857 16 10.857 25.714z"],"width":329.1428571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["caret-right"],"defaultCode":61658,"grid":14},"attrs":[],"properties":{"name":"caret-right","id":144,"order":196,"prevSize":28,"code":61658},"setIdx":0,"setId":1,"iconIdx":149},{"icon":{"paths":["M91.429 877.714h347.429v-658.286h-365.714v640c0 9.714 8.571 18.286 18.286 18.286zM877.714 859.429v-640h-365.714v658.286h347.429c9.714 0 18.286-8.571 18.286-18.286zM950.857 164.571v694.857c0 50.286-41.143 91.429-91.429 91.429h-768c-50.286 0-91.429-41.143-91.429-91.429v-694.857c0-50.286 41.143-91.429 91.429-91.429h768c50.286 0 91.429 41.143 91.429 91.429z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["columns"],"defaultCode":61659,"grid":14},"attrs":[],"properties":{"name":"columns","id":145,"order":197,"prevSize":28,"code":61659},"setIdx":0,"setId":1,"iconIdx":150},{"icon":{"paths":["M585.143 621.714c0 9.714-4 18.857-10.857 25.714l-256 256c-6.857 6.857-16 10.857-25.714 10.857s-18.857-4-25.714-10.857l-256-256c-6.857-6.857-10.857-16-10.857-25.714 0-20 16.571-36.571 36.571-36.571h512c20 0 36.571 16.571 36.571 36.571zM585.143 402.286c0 20-16.571 36.571-36.571 36.571h-512c-20 0-36.571-16.571-36.571-36.571 0-9.714 4-18.857 10.857-25.714l256-256c6.857-6.857 16-10.857 25.714-10.857s18.857 4 25.714 10.857l256 256c6.857 6.857 10.857 16 10.857 25.714z"],"width":585.1428571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["sort","unsorted"],"defaultCode":61660,"grid":14},"attrs":[],"properties":{"name":"sort, unsorted","id":146,"order":198,"prevSize":28,"code":61660},"setIdx":0,"setId":1,"iconIdx":151},{"icon":{"paths":["M585.143 621.714c0 9.714-4 18.857-10.857 25.714l-256 256c-6.857 6.857-16 10.857-25.714 10.857s-18.857-4-25.714-10.857l-256-256c-6.857-6.857-10.857-16-10.857-25.714 0-20 16.571-36.571 36.571-36.571h512c20 0 36.571 16.571 36.571 36.571z"],"width":585.1428571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["sort-desc","sort-down"],"defaultCode":61661,"grid":14},"attrs":[],"properties":{"name":"sort-desc, sort-down","id":147,"order":199,"prevSize":28,"code":61661},"setIdx":0,"setId":1,"iconIdx":152},{"icon":{"paths":["M585.143 402.286c0 20-16.571 36.571-36.571 36.571h-512c-20 0-36.571-16.571-36.571-36.571 0-9.714 4-18.857 10.857-25.714l256-256c6.857-6.857 16-10.857 25.714-10.857s18.857 4 25.714 10.857l256 256c6.857 6.857 10.857 16 10.857 25.714z"],"width":585.1428571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["sort-asc","sort-up"],"defaultCode":61662,"grid":14},"attrs":[],"properties":{"name":"sort-asc, sort-up","id":148,"order":200,"prevSize":28,"code":61662},"setIdx":0,"setId":1,"iconIdx":153},{"icon":{"paths":["M877.714 512c0 241.714-197.143 438.857-438.857 438.857-130.857 0-254.286-57.714-337.714-158.286-5.714-7.429-5.143-18.286 1.143-24.571l78.286-78.857c4-3.429 9.143-5.143 14.286-5.143 5.143 0.571 10.286 2.857 13.143 6.857 56 72.571 140 113.714 230.857 113.714 161.143 0 292.571-131.429 292.571-292.571s-131.429-292.571-292.571-292.571c-74.857 0-145.714 28.571-198.857 78.286l78.286 78.857c10.857 10.286 13.714 26.286 8 39.429-5.714 13.714-18.857 22.857-33.714 22.857h-256c-20 0-36.571-16.571-36.571-36.571v-256c0-14.857 9.143-28 22.857-33.714 13.143-5.714 29.143-2.857 39.429 8l74.286 73.714c80.571-76 189.714-121.143 302.286-121.143 241.714 0 438.857 197.143 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["rotate-left","undo"],"defaultCode":61666,"grid":14},"attrs":[],"properties":{"name":"rotate-left, undo","id":149,"order":203,"prevSize":28,"code":61666},"setIdx":0,"setId":1,"iconIdx":154},{"icon":{"paths":["M838.857 217.143c21.143 21.143 38.857 63.429 38.857 93.714v658.286c0 30.286-24.571 54.857-54.857 54.857h-768c-30.286 0-54.857-24.571-54.857-54.857v-914.286c0-30.286 24.571-54.857 54.857-54.857h512c30.286 0 72.571 17.714 93.714 38.857zM585.143 77.714v214.857h214.857c-3.429-9.714-8.571-19.429-12.571-23.429l-178.857-178.857c-4-4-13.714-9.143-23.429-12.571zM804.571 950.857v-585.143h-237.714c-30.286 0-54.857-24.571-54.857-54.857v-237.714h-438.857v877.714h731.429zM219.429 457.143c0-10.286 8-18.286 18.286-18.286h402.286c10.286 0 18.286 8 18.286 18.286v36.571c0 10.286-8 18.286-18.286 18.286h-402.286c-10.286 0-18.286-8-18.286-18.286v-36.571zM640 585.143c10.286 0 18.286 8 18.286 18.286v36.571c0 10.286-8 18.286-18.286 18.286h-402.286c-10.286 0-18.286-8-18.286-18.286v-36.571c0-10.286 8-18.286 18.286-18.286h402.286zM640 731.429c10.286 0 18.286 8 18.286 18.286v36.571c0 10.286-8 18.286-18.286 18.286h-402.286c-10.286 0-18.286-8-18.286-18.286v-36.571c0-10.286 8-18.286 18.286-18.286h402.286z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["file-text-o"],"defaultCode":61686,"grid":14},"attrs":[],"properties":{"name":"file-text-o","id":150,"order":222,"prevSize":28,"code":61686},"setIdx":0,"setId":1,"iconIdx":155},{"icon":{"paths":["M731.429 548.571v-73.143c0-20-16.571-36.571-36.571-36.571h-182.857v-182.857c0-20-16.571-36.571-36.571-36.571h-73.143c-20 0-36.571 16.571-36.571 36.571v182.857h-182.857c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h182.857v182.857c0 20 16.571 36.571 36.571 36.571h73.143c20 0 36.571-16.571 36.571-36.571v-182.857h182.857c20 0 36.571-16.571 36.571-36.571zM877.714 237.714v548.571c0 90.857-73.714 164.571-164.571 164.571h-548.571c-90.857 0-164.571-73.714-164.571-164.571v-548.571c0-90.857 73.714-164.571 164.571-164.571h548.571c90.857 0 164.571 73.714 164.571 164.571z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["plus-square"],"defaultCode":61694,"grid":14},"attrs":[],"properties":{"name":"plus-square","id":151,"order":230,"prevSize":28,"code":61694},"setIdx":0,"setId":1,"iconIdx":156},{"icon":{"paths":["M358.286 786.286c0 4.571-2.286 9.714-5.714 13.143l-28.571 28.571c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-266.286-266.286c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l266.286-266.286c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l28.571 28.571c3.429 3.429 5.714 8.571 5.714 13.143s-2.286 9.714-5.714 13.143l-224.571 224.571 224.571 224.571c3.429 3.429 5.714 8.571 5.714 13.143zM577.714 786.286c0 4.571-2.286 9.714-5.714 13.143l-28.571 28.571c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-266.286-266.286c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l266.286-266.286c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l28.571 28.571c3.429 3.429 5.714 8.571 5.714 13.143s-2.286 9.714-5.714 13.143l-224.571 224.571 224.571 224.571c3.429 3.429 5.714 8.571 5.714 13.143z"],"width":603.4285714285714,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["angle-double-left"],"defaultCode":61696,"grid":14},"attrs":[],"properties":{"name":"angle-double-left","id":152,"order":231,"prevSize":28,"code":61696},"setIdx":0,"setId":1,"iconIdx":157},{"icon":{"paths":["M340 548.571c0 4.571-2.286 9.714-5.714 13.143l-266.286 266.286c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-28.571-28.571c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l224.571-224.571-224.571-224.571c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l28.571-28.571c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l266.286 266.286c3.429 3.429 5.714 8.571 5.714 13.143zM559.429 548.571c0 4.571-2.286 9.714-5.714 13.143l-266.286 266.286c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-28.571-28.571c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l224.571-224.571-224.571-224.571c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l28.571-28.571c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l266.286 266.286c3.429 3.429 5.714 8.571 5.714 13.143z"],"width":566.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["angle-double-right"],"defaultCode":61697,"grid":14},"attrs":[],"properties":{"name":"angle-double-right","id":153,"order":232,"prevSize":28,"code":61697},"setIdx":0,"setId":1,"iconIdx":158},{"icon":{"paths":["M614.286 749.714c0 4.571-2.286 9.714-5.714 13.143l-28.571 28.571c-3.429 3.429-8 5.714-13.143 5.714-4.571 0-9.714-2.286-13.143-5.714l-224.571-224.571-224.571 224.571c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-28.571-28.571c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l266.286-266.286c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l266.286 266.286c3.429 3.429 5.714 8.571 5.714 13.143zM614.286 530.286c0 4.571-2.286 9.714-5.714 13.143l-28.571 28.571c-3.429 3.429-8 5.714-13.143 5.714-4.571 0-9.714-2.286-13.143-5.714l-224.571-224.571-224.571 224.571c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-28.571-28.571c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l266.286-266.286c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l266.286 266.286c3.429 3.429 5.714 8.571 5.714 13.143z"],"width":658.2857142857142,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["angle-double-up"],"defaultCode":61698,"grid":14},"attrs":[],"properties":{"name":"angle-double-up","id":154,"order":233,"prevSize":28,"code":61698},"setIdx":0,"setId":1,"iconIdx":159},{"icon":{"paths":["M614.286 493.714c0 4.571-2.286 9.714-5.714 13.143l-266.286 266.286c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-266.286-266.286c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l28.571-28.571c3.429-3.429 8-5.714 13.143-5.714 4.571 0 9.714 2.286 13.143 5.714l224.571 224.571 224.571-224.571c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l28.571 28.571c3.429 3.429 5.714 8.571 5.714 13.143zM614.286 274.286c0 4.571-2.286 9.714-5.714 13.143l-266.286 266.286c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-266.286-266.286c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l28.571-28.571c3.429-3.429 8-5.714 13.143-5.714 4.571 0 9.714 2.286 13.143 5.714l224.571 224.571 224.571-224.571c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l28.571 28.571c3.429 3.429 5.714 8.571 5.714 13.143z"],"width":658.2857142857142,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["angle-double-down"],"defaultCode":61699,"grid":14},"attrs":[],"properties":{"name":"angle-double-down","id":155,"order":234,"prevSize":28,"code":61699},"setIdx":0,"setId":1,"iconIdx":160},{"icon":{"paths":["M358.286 310.857c0 4.571-2.286 9.714-5.714 13.143l-224.571 224.571 224.571 224.571c3.429 3.429 5.714 8.571 5.714 13.143s-2.286 9.714-5.714 13.143l-28.571 28.571c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-266.286-266.286c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l266.286-266.286c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l28.571 28.571c3.429 3.429 5.714 8 5.714 13.143z"],"width":384,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["angle-left"],"defaultCode":61700,"grid":14},"attrs":[],"properties":{"name":"angle-left","id":156,"order":235,"prevSize":28,"code":61700},"setIdx":0,"setId":1,"iconIdx":161},{"icon":{"paths":["M340 548.571c0 4.571-2.286 9.714-5.714 13.143l-266.286 266.286c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-28.571-28.571c-3.429-3.429-5.714-8-5.714-13.143 0-4.571 2.286-9.714 5.714-13.143l224.571-224.571-224.571-224.571c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l28.571-28.571c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l266.286 266.286c3.429 3.429 5.714 8.571 5.714 13.143z"],"width":347.4285714285714,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["angle-right"],"defaultCode":61701,"grid":14},"attrs":[],"properties":{"name":"angle-right","id":157,"order":236,"prevSize":28,"code":61701},"setIdx":0,"setId":1,"iconIdx":162},{"icon":{"paths":["M614.286 676.571c0 4.571-2.286 9.714-5.714 13.143l-28.571 28.571c-3.429 3.429-8 5.714-13.143 5.714-4.571 0-9.714-2.286-13.143-5.714l-224.571-224.571-224.571 224.571c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-28.571-28.571c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l266.286-266.286c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l266.286 266.286c3.429 3.429 5.714 8.571 5.714 13.143z"],"width":658.2857142857142,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["angle-up"],"defaultCode":61702,"grid":14},"attrs":[],"properties":{"name":"angle-up","id":158,"order":237,"prevSize":28,"code":61702},"setIdx":0,"setId":1,"iconIdx":163},{"icon":{"paths":["M614.286 420.571c0 4.571-2.286 9.714-5.714 13.143l-266.286 266.286c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-266.286-266.286c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l28.571-28.571c3.429-3.429 8-5.714 13.143-5.714 4.571 0 9.714 2.286 13.143 5.714l224.571 224.571 224.571-224.571c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l28.571 28.571c3.429 3.429 5.714 8.571 5.714 13.143z"],"width":658.2857142857142,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["angle-down"],"defaultCode":61703,"grid":14},"attrs":[],"properties":{"name":"angle-down","id":159,"order":238,"prevSize":28,"code":61703},"setIdx":0,"setId":1,"iconIdx":164},{"icon":{"paths":["M438.857 201.143c-171.429 0-310.857 139.429-310.857 310.857s139.429 310.857 310.857 310.857 310.857-139.429 310.857-310.857-139.429-310.857-310.857-310.857zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857v0c242.286 0 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["circle-o"],"defaultCode":61708,"grid":14},"attrs":[],"properties":{"name":"circle-o","id":160,"order":243,"prevSize":28,"code":61708},"setIdx":0,"setId":1,"iconIdx":165},{"icon":{"paths":["M300.571 796.571c0 40-32.571 73.143-73.143 73.143-40 0-73.143-33.143-73.143-73.143 0-40.571 33.143-73.143 73.143-73.143 40.571 0 73.143 32.571 73.143 73.143zM585.143 914.286c0 40.571-32.571 73.143-73.143 73.143s-73.143-32.571-73.143-73.143 32.571-73.143 73.143-73.143 73.143 32.571 73.143 73.143zM182.857 512c0 40.571-32.571 73.143-73.143 73.143s-73.143-32.571-73.143-73.143 32.571-73.143 73.143-73.143 73.143 32.571 73.143 73.143zM869.714 796.571c0 40-33.143 73.143-73.143 73.143-40.571 0-73.143-33.143-73.143-73.143 0-40.571 32.571-73.143 73.143-73.143 40 0 73.143 32.571 73.143 73.143zM318.857 227.429c0 50.286-41.143 91.429-91.429 91.429s-91.429-41.143-91.429-91.429 41.143-91.429 91.429-91.429 91.429 41.143 91.429 91.429zM987.429 512c0 40.571-32.571 73.143-73.143 73.143s-73.143-32.571-73.143-73.143 32.571-73.143 73.143-73.143 73.143 32.571 73.143 73.143zM621.714 109.714c0 60.571-49.143 109.714-109.714 109.714s-109.714-49.143-109.714-109.714 49.143-109.714 109.714-109.714 109.714 49.143 109.714 109.714zM924.571 227.429c0 70.857-57.714 128-128 128-70.857 0-128-57.143-128-128 0-70.286 57.143-128 128-128 70.286 0 128 57.714 128 128z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["spinner"],"defaultCode":61712,"grid":14},"attrs":[],"properties":{"name":"spinner","id":161,"order":246,"prevSize":28,"code":61712},"setIdx":0,"setId":1,"iconIdx":166},{"icon":{"paths":["M877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["circle"],"defaultCode":61713,"grid":14},"attrs":[],"properties":{"name":"circle","id":162,"order":247,"prevSize":28,"code":61713},"setIdx":0,"setId":1,"iconIdx":167},{"icon":{"paths":["M1024 640c0 80-40 184.571-72.571 257.714-6.286 13.143-12.571 31.429-21.143 43.429-4 5.714-8 9.714-16 9.714-11.429 0-18.286-9.143-18.286-20 0-9.143 2.286-19.429 2.857-28.571 1.714-23.429 2.857-46.857 2.857-70.286 0-272.571-161.714-320-408-320h-128v146.286c0 20-16.571 36.571-36.571 36.571-9.714 0-18.857-4-25.714-10.857l-292.571-292.571c-6.857-6.857-10.857-16-10.857-25.714s4-18.857 10.857-25.714l292.571-292.571c6.857-6.857 16-10.857 25.714-10.857 20 0 36.571 16.571 36.571 36.571v146.286h128c187.429 0 420.571 33.143 500 230.286 24 60.571 30.286 126.286 30.286 190.286z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["mail-reply","reply"],"defaultCode":61714,"grid":14},"attrs":[],"properties":{"name":"mail-reply, reply","id":163,"order":248,"prevSize":28,"code":61714},"setIdx":0,"setId":1,"iconIdx":168},{"icon":{"paths":["M877.714 749.714v-402.286c0-30.286-24.571-54.857-54.857-54.857h-402.286c-30.286 0-54.857-24.571-54.857-54.857v-36.571c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v548.571c0 30.286 24.571 54.857 54.857 54.857h694.857c30.286 0 54.857-24.571 54.857-54.857zM950.857 347.429v402.286c0 70.286-57.714 128-128 128h-694.857c-70.286 0-128-57.714-128-128v-548.571c0-70.286 57.714-128 128-128h182.857c70.286 0 128 57.714 128 128v18.286h384c70.286 0 128 57.714 128 128z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["folder-o"],"defaultCode":61716,"grid":14},"attrs":[],"properties":{"name":"folder-o","id":164,"order":250,"prevSize":28,"code":61716},"setIdx":0,"setId":1,"iconIdx":169},{"icon":{"paths":["M1017.714 532c0-16-17.714-20-30.286-20h-621.714c-30.286 0-70.286 18.857-89.714 42.286l-168 207.429c-5.143 6.857-10.286 14.286-10.286 22.857 0 16 17.714 20 30.286 20h621.714c30.286 0 70.286-18.857 89.714-42.857l168-207.429c5.143-6.286 10.286-13.714 10.286-22.286zM365.714 438.857h438.857v-91.429c0-30.286-24.571-54.857-54.857-54.857h-329.143c-30.286 0-54.857-24.571-54.857-54.857v-36.571c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v487.429l146.286-180c33.143-40.571 94.286-69.714 146.286-69.714zM1090.857 532c0 25.143-10.857 49.143-26.286 68.571l-168.571 207.429c-32.571 40-94.857 69.714-146.286 69.714h-621.714c-70.286 0-128-57.714-128-128v-548.571c0-70.286 57.714-128 128-128h182.857c70.286 0 128 57.714 128 128v18.286h310.857c70.286 0 128 57.714 128 128v91.429h109.714c38.857 0 77.714 17.714 94.857 54.286 5.714 12 8.571 25.143 8.571 38.857z"],"width":1090.8525714285713,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["folder-open-o"],"defaultCode":61717,"grid":14},"attrs":[],"properties":{"name":"folder-open-o","id":165,"order":251,"prevSize":28,"code":61717},"setIdx":0,"setId":1,"iconIdx":170},{"icon":{"paths":["M219.429 667.429v54.857c0 5.143-4 9.143-9.143 9.143h-54.857c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h54.857c5.143 0 9.143 4 9.143 9.143zM292.571 521.143v54.857c0 5.143-4 9.143-9.143 9.143h-128c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h128c5.143 0 9.143 4 9.143 9.143zM219.429 374.857v54.857c0 5.143-4 9.143-9.143 9.143h-54.857c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h54.857c5.143 0 9.143 4 9.143 9.143zM804.571 667.429v54.857c0 5.143-4 9.143-9.143 9.143h-493.714c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h493.714c5.143 0 9.143 4 9.143 9.143zM438.857 521.143v54.857c0 5.143-4 9.143-9.143 9.143h-54.857c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h54.857c5.143 0 9.143 4 9.143 9.143zM365.714 374.857v54.857c0 5.143-4 9.143-9.143 9.143h-54.857c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h54.857c5.143 0 9.143 4 9.143 9.143zM585.143 521.143v54.857c0 5.143-4 9.143-9.143 9.143h-54.857c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h54.857c5.143 0 9.143 4 9.143 9.143zM512 374.857v54.857c0 5.143-4 9.143-9.143 9.143h-54.857c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h54.857c5.143 0 9.143 4 9.143 9.143zM731.429 521.143v54.857c0 5.143-4 9.143-9.143 9.143h-54.857c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h54.857c5.143 0 9.143 4 9.143 9.143zM950.857 667.429v54.857c0 5.143-4 9.143-9.143 9.143h-54.857c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h54.857c5.143 0 9.143 4 9.143 9.143zM658.286 374.857v54.857c0 5.143-4 9.143-9.143 9.143h-54.857c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h54.857c5.143 0 9.143 4 9.143 9.143zM804.571 374.857v54.857c0 5.143-4 9.143-9.143 9.143h-54.857c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h54.857c5.143 0 9.143 4 9.143 9.143zM950.857 374.857v201.143c0 5.143-4 9.143-9.143 9.143h-128c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h64v-137.143c0-5.143 4-9.143 9.143-9.143h54.857c5.143 0 9.143 4 9.143 9.143zM1024 804.571v-512h-950.857v512h950.857zM1097.143 292.571v512c0 40.571-32.571 73.143-73.143 73.143h-950.857c-40.571 0-73.143-32.571-73.143-73.143v-512c0-40.571 32.571-73.143 73.143-73.143h950.857c40.571 0 73.143 32.571 73.143 73.143z"],"width":1097.142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["keyboard-o"],"defaultCode":61724,"grid":14},"attrs":[],"properties":{"name":"keyboard-o","id":166,"order":256,"prevSize":28,"code":61724},"setIdx":0,"setId":1,"iconIdx":171},{"icon":{"paths":["M334.286 561.714l-266.286 266.286c-7.429 7.429-18.857 7.429-26.286 0l-28.571-28.571c-7.429-7.429-7.429-18.857 0-26.286l224.571-224.571-224.571-224.571c-7.429-7.429-7.429-18.857 0-26.286l28.571-28.571c7.429-7.429 18.857-7.429 26.286 0l266.286 266.286c7.429 7.429 7.429 18.857 0 26.286zM950.857 822.857v36.571c0 10.286-8 18.286-18.286 18.286h-548.571c-10.286 0-18.286-8-18.286-18.286v-36.571c0-10.286 8-18.286 18.286-18.286h548.571c10.286 0 18.286 8 18.286 18.286z"],"width":956.5622857142856,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["terminal"],"defaultCode":61728,"grid":14},"attrs":[],"properties":{"name":"terminal","id":167,"order":259,"prevSize":28,"code":61728},"setIdx":0,"setId":1,"iconIdx":172},{"icon":{"paths":["M352.571 799.429l-28.571 28.571c-7.429 7.429-18.857 7.429-26.286 0l-266.286-266.286c-7.429-7.429-7.429-18.857 0-26.286l266.286-266.286c7.429-7.429 18.857-7.429 26.286 0l28.571 28.571c7.429 7.429 7.429 18.857 0 26.286l-224.571 224.571 224.571 224.571c7.429 7.429 7.429 18.857 0 26.286zM690.286 189.714l-213.143 737.714c-2.857 9.714-13.143 15.429-22.286 12.571l-35.429-9.714c-9.714-2.857-15.429-13.143-12.571-22.857l213.143-737.714c2.857-9.714 13.143-15.429 22.286-12.571l35.429 9.714c9.714 2.857 15.429 13.143 12.571 22.857zM1065.714 561.714l-266.286 266.286c-7.429 7.429-18.857 7.429-26.286 0l-28.571-28.571c-7.429-7.429-7.429-18.857 0-26.286l224.571-224.571-224.571-224.571c-7.429-7.429-7.429-18.857 0-26.286l28.571-28.571c7.429-7.429 18.857-7.429 26.286 0l266.286 266.286c7.429 7.429 7.429 18.857 0 26.286z"],"width":1097.142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["code"],"defaultCode":61729,"grid":14},"attrs":[],"properties":{"name":"code","id":168,"order":684,"prevSize":28,"code":61729},"setIdx":0,"setId":1,"iconIdx":173},{"icon":{"paths":["M365.714 618.286v40c0 14.857-9.143 28-22.286 33.714-4.571 1.714-9.714 2.857-14.286 2.857-9.714 0-18.857-3.429-25.714-10.857l-292.571-292.571c-14.286-14.286-14.286-37.143 0-51.429l292.571-292.571c10.286-10.857 26.286-13.714 40-8 13.143 5.714 22.286 18.857 22.286 33.714v39.429l-226.857 227.429c-14.286 14.286-14.286 37.143 0 51.429zM1024 640c0 118.857-89.714 293.714-93.714 301.143-2.857 6.286-9.143 9.714-16 9.714-1.714 0-3.429 0-5.143-0.571-8.571-2.857-13.714-10.857-13.143-19.429 16.571-156-2.857-258.857-60.571-322.857-48.571-54.286-127.429-83.429-250.286-93.143v143.429c0 14.857-9.143 28-22.286 33.714-4.571 1.714-9.714 2.857-14.286 2.857-9.714 0-18.857-3.429-25.714-10.857l-292.571-292.571c-14.286-14.286-14.286-37.143 0-51.429l292.571-292.571c10.286-10.857 26.286-13.714 40-8 13.143 5.714 22.286 18.857 22.286 33.714v149.714c157.714 10.857 270.286 52.571 342.286 126.286 86.286 88.571 96.571 208.571 96.571 290.857z"],"width":1020.5622857142856,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["mail-reply-all","reply-all"],"defaultCode":61730,"grid":14},"attrs":[],"properties":{"name":"mail-reply-all, reply-all","id":169,"order":685,"prevSize":28,"code":61730},"setIdx":0,"setId":1,"iconIdx":174},{"icon":{"paths":["M677.714 546.857l146.857-142.857-241.143-35.429-17.143-34.286-90.857-184v550.286l33.714 17.714 181.714 96-34.286-202.857-6.857-37.714zM936 397.143l-207.429 202.286 49.143 285.714c4 25.143-5.143 40-22.857 40-6.286 0-14.286-2.286-22.857-6.857l-256.571-134.857-256.571 134.857c-8.571 4.571-16.571 6.857-22.857 6.857-17.714 0-26.857-14.857-22.857-40l49.143-285.714-208-202.286c-24.571-24.571-16.571-48.571 17.714-53.714l286.857-41.714 128.571-260c7.429-15.429 17.714-23.429 28-23.429v0c10.286 0 20 8 28 23.429l128.571 260 286.857 41.714c34.286 5.143 42.286 29.143 17.143 53.714z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["star-half-empty","star-half-full","star-half-o"],"defaultCode":61731,"grid":14},"attrs":[],"properties":{"name":"star-half-empty, star-half-full, star-half-o","id":170,"order":262,"prevSize":28,"code":61731},"setIdx":0,"setId":1,"iconIdx":175},{"icon":{"paths":["M318.286 731.429h340v-340zM292.571 705.714l340-340h-340v340zM950.857 749.714v109.714c0 10.286-8 18.286-18.286 18.286h-128v128c0 10.286-8 18.286-18.286 18.286h-109.714c-10.286 0-18.286-8-18.286-18.286v-128h-493.714c-10.286 0-18.286-8-18.286-18.286v-493.714h-128c-10.286 0-18.286-8-18.286-18.286v-109.714c0-10.286 8-18.286 18.286-18.286h128v-128c0-10.286 8-18.286 18.286-18.286h109.714c10.286 0 18.286 8 18.286 18.286v128h486.286l140.571-141.143c7.429-6.857 18.857-6.857 26.286 0 6.857 7.429 6.857 18.857 0 26.286l-141.143 140.571v486.286h128c10.286 0 18.286 8 18.286 18.286z"],"width":952.5394285714285,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["crop"],"defaultCode":61733,"grid":14},"attrs":[],"properties":{"name":"crop","id":171,"order":264,"prevSize":28,"code":61733},"setIdx":0,"setId":1,"iconIdx":176},{"icon":{"paths":["M164.571 841.143c0-30.286-24.571-54.857-54.857-54.857s-54.857 24.571-54.857 54.857 24.571 54.857 54.857 54.857 54.857-24.571 54.857-54.857zM164.571 182.857c0-30.286-24.571-54.857-54.857-54.857s-54.857 24.571-54.857 54.857 24.571 54.857 54.857 54.857 54.857-24.571 54.857-54.857zM530.286 256c0-30.286-24.571-54.857-54.857-54.857s-54.857 24.571-54.857 54.857 24.571 54.857 54.857 54.857 54.857-24.571 54.857-54.857zM585.143 256c0 40.571-22.286 76-54.857 94.857-1.714 206.286-148 252-245.143 282.857-90.857 28.571-120.571 42.286-120.571 97.714v14.857c32.571 18.857 54.857 54.286 54.857 94.857 0 60.571-49.143 109.714-109.714 109.714s-109.714-49.143-109.714-109.714c0-40.571 22.286-76 54.857-94.857v-468.571c-32.571-18.857-54.857-54.286-54.857-94.857 0-60.571 49.143-109.714 109.714-109.714s109.714 49.143 109.714 109.714c0 40.571-22.286 76-54.857 94.857v284c29.143-14.286 60-24 88-32.571 106.286-33.714 166.857-58.857 168-178.286-32.571-18.857-54.857-54.286-54.857-94.857 0-60.571 49.143-109.714 109.714-109.714s109.714 49.143 109.714 109.714z"],"width":585.1428571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["code-fork"],"defaultCode":61734,"grid":14},"attrs":[],"properties":{"name":"code-fork","id":172,"order":265,"prevSize":28,"code":61734},"setIdx":0,"setId":1,"iconIdx":177},{"icon":{"paths":["M250.857 726.286l-146.286 146.286c-4 3.429-8.571 5.143-13.143 5.143s-9.143-1.714-13.143-5.143c-6.857-7.429-6.857-18.857 0-26.286l146.286-146.286c7.429-6.857 18.857-6.857 26.286 0 6.857 7.429 6.857 18.857 0 26.286zM347.429 749.714v182.857c0 10.286-8 18.286-18.286 18.286s-18.286-8-18.286-18.286v-182.857c0-10.286 8-18.286 18.286-18.286s18.286 8 18.286 18.286zM219.429 621.714c0 10.286-8 18.286-18.286 18.286h-182.857c-10.286 0-18.286-8-18.286-18.286s8-18.286 18.286-18.286h182.857c10.286 0 18.286 8 18.286 18.286zM941.714 694.857c0 44-17.143 85.143-48.571 116l-84 83.429c-30.857 30.857-72 47.429-116 47.429s-85.714-17.143-116.571-48.571l-190.857-191.429c-9.714-9.714-17.143-20.571-24-32l136.571-10.286 156 156.571c20.571 20.571 57.143 21.143 77.714 0.571l84-83.429c10.286-10.286 16-24 16-38.286 0-14.857-5.714-28.571-16-38.857l-156.571-157.143 10.286-136.571c11.429 6.857 22.286 14.286 32 24l192 192c30.857 31.429 48 72.571 48 116.571zM589.143 281.143l-136.571 10.286-156-156.571c-10.286-10.286-24-16-38.857-16s-28.571 5.714-38.857 15.429l-84 83.429c-10.286 10.286-16 24-16 38.286 0 14.857 5.714 28.571 16 38.857l156.571 156.571-10.286 137.143c-11.429-6.857-22.286-14.286-32-24l-192-192c-30.857-31.429-48-72.571-48-116.571s17.143-85.143 48.571-116l84-83.429c30.857-30.857 72-47.429 116-47.429s85.714 17.143 116.571 48.571l190.857 191.429c9.714 9.714 17.143 20.571 24 32zM950.857 329.143c0 10.286-8 18.286-18.286 18.286h-182.857c-10.286 0-18.286-8-18.286-18.286s8-18.286 18.286-18.286h182.857c10.286 0 18.286 8 18.286 18.286zM640 18.286v182.857c0 10.286-8 18.286-18.286 18.286s-18.286-8-18.286-18.286v-182.857c0-10.286 8-18.286 18.286-18.286s18.286 8 18.286 18.286zM872.571 104.571l-146.286 146.286c-4 3.429-8.571 5.143-13.143 5.143s-9.143-1.714-13.143-5.143c-6.857-7.429-6.857-18.857 0-26.286l146.286-146.286c7.429-6.857 18.857-6.857 26.286 0 6.857 7.429 6.857 18.857 0 26.286z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["chain-broken","unlink"],"defaultCode":61735,"grid":14},"attrs":[],"properties":{"name":"chain-broken, unlink","id":173,"order":266,"prevSize":28,"code":61735},"setIdx":0,"setId":1,"iconIdx":178},{"icon":{"paths":["M511.999 960c-88.606 0-175.222-26.276-248.895-75.5-73.673-49.229-131.095-119.199-165.002-201.057-33.908-81.864-42.78-171.94-25.494-258.844s59.954-166.729 122.608-229.383c62.654-62.654 142.48-105.322 229.383-122.608s176.98-8.414 258.844 25.494c81.859 33.908 151.828 91.329 201.057 165.002 49.224 73.673 75.5 160.29 75.5 248.895 0 118.815-47.201 232.765-131.215 316.785-84.019 84.014-197.97 131.215-316.785 131.215zM511.999 128c-75.948 0-150.19 22.521-213.339 64.716s-112.367 102.167-141.431 172.334c-29.064 70.167-36.668 147.375-21.852 221.866 14.817 74.486 51.389 142.909 105.093 196.613s122.126 90.276 196.615 105.093c74.488 14.817 151.699 7.214 221.863-21.852 70.17-29.066 130.14-78.285 172.334-141.43 42.194-63.15 64.717-137.39 64.717-213.34 0-101.843-40.458-199.515-112.471-271.529s-169.687-112.471-271.529-112.471z","M495.999 352c26.511 0 48-21.49 48-48s-21.489-48-48-48c-26.51 0-48 21.49-48 48s21.49 48 48 48z","M671.999 704c0 8.489-3.369 16.625-9.375 22.625-6.001 6.006-14.136 9.375-22.625 9.375h-256c-8.487 0-16.626-3.369-22.627-9.375-6.001-6.001-9.373-14.136-9.373-22.625s3.372-16.625 9.373-22.625c6.001-6.006 14.14-9.375 22.627-9.375h96v-192h-64c-8.487 0-16.626-3.372-22.627-9.373s-9.373-14.14-9.373-22.627c0-8.487 3.372-16.626 9.373-22.627s14.14-9.373 22.627-9.373h96c8.489 0 16.625 3.372 22.625 9.373 6.006 6.001 9.375 14.14 9.375 22.627v224h96c8.489 0 16.625 3.369 22.625 9.375 6.006 6.001 9.375 14.136 9.375 22.625z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["info"],"defaultCode":61737,"grid":14},"attrs":[],"properties":{"name":"info","id":174,"order":678,"prevSize":28,"code":61737},"setIdx":0,"setId":1,"iconIdx":179},{"icon":{"paths":["M917.119 944.34h-812.798c-5.469-0.020-10.84-1.444-15.602-4.137-4.762-2.688-8.755-6.554-11.598-11.223-2.809-4.864-4.287-10.383-4.287-16s1.479-11.136 4.287-16l406.4-799.999c2.685-5.242 6.765-9.64 11.79-12.712s10.8-4.697 16.688-4.697c5.893 0 11.668 1.625 16.691 4.697 5.028 3.072 9.103 7.471 11.791 12.712l406.4 799.999c2.806 4.864 4.285 10.383 4.285 16s-1.48 11.136-4.285 16c-3.057 5.059-7.46 9.175-12.713 11.884-5.253 2.714-11.151 3.917-17.050 3.476zM156.481 880.34h708.481l-354.243-697.279-354.238 697.279z","M510.709 816.34c26.511 0 48-21.489 48-48s-21.489-48-48-48c-26.51 0-48 21.489-48 48s21.49 48 48 48z","M510.709 656.34c-8.487 0-16.626-3.369-22.627-9.375-6.001-6.001-9.373-14.136-9.373-22.625v-224c0-8.487 3.372-16.626 9.373-22.627s14.14-9.373 22.627-9.373c8.489 0 16.625 3.372 22.625 9.373 6.006 6.001 9.375 14.14 9.375 22.627v224c0 8.489-3.369 16.625-9.375 22.625-6.001 6.006-14.136 9.375-22.625 9.375z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["exclamation"],"defaultCode":61738,"grid":14},"attrs":[],"properties":{"name":"exclamation","id":175,"order":268,"prevSize":28,"code":61738},"setIdx":0,"setId":1,"iconIdx":180},{"icon":{"paths":["M822.857 256c0-30.286-24.571-54.857-54.857-54.857s-54.857 24.571-54.857 54.857 24.571 54.857 54.857 54.857 54.857-24.571 54.857-54.857zM950.857 91.429c0 189.714-52.571 316-188 452-33.143 32.571-70.857 66.286-111.429 100.571l-11.429 216.571c-0.571 5.714-4 11.429-9.143 14.857l-219.429 128c-2.857 1.714-5.714 2.286-9.143 2.286-4.571 0-9.143-1.714-13.143-5.143l-36.571-36.571c-4.571-5.143-6.286-12-4.571-18.286l48.571-157.714-160.571-160.571-157.714 48.571c-1.714 0.571-3.429 0.571-5.143 0.571-4.571 0-9.714-1.714-13.143-5.143l-36.571-36.571c-5.714-6.286-6.857-15.429-2.857-22.286l128-219.429c3.429-5.143 9.143-8.571 14.857-9.143l216.571-11.429c34.286-40.571 68-78.286 100.571-111.429 142.857-142.286 252-188 450.857-188 10.286 0 19.429 8 19.429 18.286z"],"width":967.4605714285714,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["rocket"],"defaultCode":61749,"grid":14},"attrs":[],"properties":{"name":"rocket","id":176,"order":682,"prevSize":28,"code":61749},"setIdx":0,"setId":1,"iconIdx":181},{"icon":{"paths":["M997.143 441.714l-93.714 436h-190.857l101.714-475.429c4.571-20 1.714-38.286-8.571-50.286-9.714-12-26.857-18.857-47.429-18.857h-96.571l-116.571 544.571h-190.857l116.571-544.571h-163.429l-116.571 544.571h-190.857l116.571-544.571-87.429-186.857h729.143c77.143 0 147.429 32 192.571 88 45.714 56 62.286 132 46.286 207.429z"],"width":1013.1748571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["maxcdn"],"defaultCode":61750,"grid":14},"attrs":[],"properties":{"name":"maxcdn","id":177,"order":683,"prevSize":28,"code":61750},"setIdx":0,"setId":1,"iconIdx":182},{"icon":{"paths":["M519.429 797.143l58.286-58.286c14.286-14.286 14.286-37.143 0-51.429l-175.429-175.429 175.429-175.429c14.286-14.286 14.286-37.143 0-51.429l-58.286-58.286c-14.286-14.286-37.143-14.286-51.429 0l-259.429 259.429c-14.286 14.286-14.286 37.143 0 51.429l259.429 259.429c14.286 14.286 37.143 14.286 51.429 0zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["chevron-circle-left"],"defaultCode":61751,"grid":14},"attrs":[],"properties":{"name":"chevron-circle-left","id":178,"order":280,"prevSize":28,"code":61751},"setIdx":0,"setId":1,"iconIdx":183},{"icon":{"paths":["M409.714 797.143l259.429-259.429c14.286-14.286 14.286-37.143 0-51.429l-259.429-259.429c-14.286-14.286-37.143-14.286-51.429 0l-58.286 58.286c-14.286 14.286-14.286 37.143 0 51.429l175.429 175.429-175.429 175.429c-14.286 14.286-14.286 37.143 0 51.429l58.286 58.286c14.286 14.286 37.143 14.286 51.429 0zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["chevron-circle-right"],"defaultCode":61752,"grid":14},"attrs":[],"properties":{"name":"chevron-circle-right","id":179,"order":281,"prevSize":28,"code":61752},"setIdx":0,"setId":1,"iconIdx":184},{"icon":{"paths":["M665.714 650.857l58.286-58.286c14.286-14.286 14.286-37.143 0-51.429l-259.429-259.429c-14.286-14.286-37.143-14.286-51.429 0l-259.429 259.429c-14.286 14.286-14.286 37.143 0 51.429l58.286 58.286c14.286 14.286 37.143 14.286 51.429 0l175.429-175.429 175.429 175.429c14.286 14.286 37.143 14.286 51.429 0zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["chevron-circle-up"],"defaultCode":61753,"grid":14},"attrs":[],"properties":{"name":"chevron-circle-up","id":180,"order":282,"prevSize":28,"code":61753},"setIdx":0,"setId":1,"iconIdx":185},{"icon":{"paths":["M464.571 742.286l259.429-259.429c14.286-14.286 14.286-37.143 0-51.429l-58.286-58.286c-14.286-14.286-37.143-14.286-51.429 0l-175.429 175.429-175.429-175.429c-14.286-14.286-37.143-14.286-51.429 0l-58.286 58.286c-14.286 14.286-14.286 37.143 0 51.429l259.429 259.429c14.286 14.286 37.143 14.286 51.429 0zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["chevron-circle-down"],"defaultCode":61754,"grid":14},"attrs":[],"properties":{"name":"chevron-circle-down","id":181,"order":283,"prevSize":28,"code":61754},"setIdx":0,"setId":1,"iconIdx":186},{"icon":{"paths":["M219.429 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-109.714c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h109.714c30.286 0 54.857 24.571 54.857 54.857zM512 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-109.714c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h109.714c30.286 0 54.857 24.571 54.857 54.857zM804.571 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-109.714c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h109.714c30.286 0 54.857 24.571 54.857 54.857z"],"width":804.5714285714286,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["ellipsis-h"],"defaultCode":61761,"grid":14},"attrs":[],"properties":{"name":"ellipsis-h","id":182,"order":289,"prevSize":28,"code":61761},"setIdx":0,"setId":1,"iconIdx":187},{"icon":{"paths":["M437.143 742.286c2.857 6.857 1.714 14.286-2.857 20l-200 219.429c-3.429 3.429-8 5.714-13.143 5.714v0c-5.143 0-10.286-2.286-13.714-5.714l-202.857-219.429c-4.571-5.714-5.714-13.143-2.857-20 2.857-6.286 9.143-10.857 16.571-10.857h128v-713.143c0-10.286 8-18.286 18.286-18.286h109.714c10.286 0 18.286 8 18.286 18.286v713.143h128c7.429 0 13.714 4 16.571 10.857z"],"width":438.85714285714283,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["long-arrow-down"],"defaultCode":61813,"grid":14},"attrs":[],"properties":{"name":"long-arrow-down","id":183,"order":338,"prevSize":28,"code":61813},"setIdx":0,"setId":1,"iconIdx":188},{"icon":{"paths":["M437.143 281.714c-2.857 6.286-9.143 10.857-16.571 10.857h-128v713.143c0 10.286-8 18.286-18.286 18.286h-109.714c-10.286 0-18.286-8-18.286-18.286v-713.143h-128c-7.429 0-13.714-4-16.571-10.857s-1.714-14.286 2.857-20l200-219.429c3.429-3.429 8-5.714 13.143-5.714v0c5.143 0 10.286 2.286 13.714 5.714l202.857 219.429c4.571 5.714 5.714 13.143 2.857 20z"],"width":438.85714285714283,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["long-arrow-up"],"defaultCode":61814,"grid":14},"attrs":[],"properties":{"name":"long-arrow-up","id":184,"order":339,"prevSize":28,"code":61814},"setIdx":0,"setId":1,"iconIdx":189},{"icon":{"paths":["M1024 457.143v109.714c0 10.286-8 18.286-18.286 18.286h-713.143v128c0 7.429-4 13.714-10.857 16.571s-14.286 1.714-20-2.857l-219.429-200c-3.429-3.429-5.714-8-5.714-13.143v0c0-5.143 2.286-10.286 5.714-13.714l219.429-202.286c5.714-5.143 13.143-6.286 20-3.429 6.286 2.857 10.857 9.143 10.857 16.571v128h713.143c10.286 0 18.286 8 18.286 18.286z"],"width":1060.5714285714284,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["long-arrow-left"],"defaultCode":61815,"grid":14},"attrs":[],"properties":{"name":"long-arrow-left","id":185,"order":340,"prevSize":28,"code":61815},"setIdx":0,"setId":1,"iconIdx":190},{"icon":{"paths":["M987.429 510.286c0 5.143-2.286 10.286-5.714 13.714l-219.429 202.286c-5.714 5.143-13.143 6.286-20 3.429-6.286-2.857-10.857-9.143-10.857-16.571v-128h-713.143c-10.286 0-18.286-8-18.286-18.286v-109.714c0-10.286 8-18.286 18.286-18.286h713.143v-128c0-7.429 4-13.714 10.857-16.571s14.286-1.714 20 2.857l219.429 200c3.429 3.429 5.714 8 5.714 13.143v0z"],"width":987.4285714285713,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["long-arrow-right"],"defaultCode":61816,"grid":14},"attrs":[],"properties":{"name":"long-arrow-right","id":186,"order":341,"prevSize":28,"code":61816},"setIdx":0,"setId":1,"iconIdx":191},{"icon":{"paths":["M109.714 731.429v73.143h-64c-5.143 0-9.143-4-9.143-9.143v-9.143h-27.429c-5.143 0-9.143-4-9.143-9.143v-18.286c0-5.143 4-9.143 9.143-9.143h27.429v-9.143c0-5.143 4-9.143 9.143-9.143h64zM109.714 585.143v73.143h-64c-5.143 0-9.143-4-9.143-9.143v-9.143h-27.429c-5.143 0-9.143-4-9.143-9.143v-18.286c0-5.143 4-9.143 9.143-9.143h27.429v-9.143c0-5.143 4-9.143 9.143-9.143h64zM109.714 438.857v73.143h-64c-5.143 0-9.143-4-9.143-9.143v-9.143h-27.429c-5.143 0-9.143-4-9.143-9.143v-18.286c0-5.143 4-9.143 9.143-9.143h27.429v-9.143c0-5.143 4-9.143 9.143-9.143h64zM109.714 292.571v73.143h-64c-5.143 0-9.143-4-9.143-9.143v-9.143h-27.429c-5.143 0-9.143-4-9.143-9.143v-18.286c0-5.143 4-9.143 9.143-9.143h27.429v-9.143c0-5.143 4-9.143 9.143-9.143h64zM109.714 146.286v73.143h-64c-5.143 0-9.143-4-9.143-9.143v-9.143h-27.429c-5.143 0-9.143-4-9.143-9.143v-18.286c0-5.143 4-9.143 9.143-9.143h27.429v-9.143c0-5.143 4-9.143 9.143-9.143h64zM731.429 54.857v841.143c0 30.286-24.571 54.857-54.857 54.857h-475.429c-30.286 0-54.857-24.571-54.857-54.857v-841.143c0-30.286 24.571-54.857 54.857-54.857h475.429c30.286 0 54.857 24.571 54.857 54.857zM877.714 758.857v18.286c0 5.143-4 9.143-9.143 9.143h-27.429v9.143c0 5.143-4 9.143-9.143 9.143h-64v-73.143h64c5.143 0 9.143 4 9.143 9.143v9.143h27.429c5.143 0 9.143 4 9.143 9.143zM877.714 612.571v18.286c0 5.143-4 9.143-9.143 9.143h-27.429v9.143c0 5.143-4 9.143-9.143 9.143h-64v-73.143h64c5.143 0 9.143 4 9.143 9.143v9.143h27.429c5.143 0 9.143 4 9.143 9.143zM877.714 466.286v18.286c0 5.143-4 9.143-9.143 9.143h-27.429v9.143c0 5.143-4 9.143-9.143 9.143h-64v-73.143h64c5.143 0 9.143 4 9.143 9.143v9.143h27.429c5.143 0 9.143 4 9.143 9.143zM877.714 320v18.286c0 5.143-4 9.143-9.143 9.143h-27.429v9.143c0 5.143-4 9.143-9.143 9.143h-64v-73.143h64c5.143 0 9.143 4 9.143 9.143v9.143h27.429c5.143 0 9.143 4 9.143 9.143zM877.714 173.714v18.286c0 5.143-4 9.143-9.143 9.143h-27.429v9.143c0 5.143-4 9.143-9.143 9.143h-64v-73.143h64c5.143 0 9.143 4 9.143 9.143v9.143h27.429c5.143 0 9.143 4 9.143 9.143z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[]},"tags":["microchip"],"defaultCode":62171,"grid":14},"attrs":[],"properties":{"name":"microchip","id":187,"order":693,"prevSize":28,"code":62171},"setIdx":0,"setId":1,"iconIdx":192}],"height":1024,"metadata":{"name":"FontAwesome"},"preferences":{"showGlyphs":true,"showQuickUse":true,"showQuickUse2":true,"showSVGs":true,"fontPref":{"prefix":"fa-","metadata":{"fontFamily":"FontAwesome","majorVersion":1,"minorVersion":0},"metrics":{"emSize":1024,"baseline":6.25,"whitespace":50},"embed":false,"noie8":true,"ie7":false,"showSelector":false,"selector":"i","showMetrics":false,"showMetadata":false,"showVersion":false},"imagePref":{"prefix":"icon-","png":true,"useClassSelector":true,"color":0,"bgColor":16777215,"classSelector":".icon","name":"icomoon"},"historySize":50,"showCodes":true,"gridSize":16}} \ No newline at end of file +{"IcoMoonType":"selection","icons":[{"icon":{"paths":["M684.256 793.966l-146.286 146.286c-6.932 6.802-16.255 10.606-25.964 10.606s-19.032-3.803-25.964-10.606l-146.286-146.286c-3.41-3.41-6.115-7.458-7.96-11.913s-2.796-9.23-2.796-14.052c-0.001-9.738 3.868-19.079 10.754-25.965s16.226-10.756 25.964-10.756c4.822 0 9.597 0.949 14.052 2.795s8.504 4.549 11.914 7.959l83.749 84.107v-423.856c0-9.699 3.853-19.002 10.712-25.86s16.16-10.712 25.86-10.712c9.699 0 19.001 3.853 25.86 10.712s10.712 16.16 10.712 25.86v423.856l83.749-84.107c6.886-6.886 16.227-10.756 25.966-10.756s19.079 3.869 25.966 10.756c6.886 6.886 10.755 16.227 10.755 25.966s-3.869 19.079-10.755 25.966z","M786.286 658.285h-128c-9.699 0-19.001-3.852-25.86-10.711s-10.712-16.161-10.712-25.86c0-9.699 3.853-19.001 10.712-25.86s16.16-10.712 25.86-10.712h128c32.768-0.031 64.285-12.618 88.057-35.172 23.779-22.554 38.005-53.361 39.76-86.085s-9.092-64.877-30.318-89.846c-21.219-24.97-51.207-40.858-83.785-44.396-8.316-0.882-16.084-4.59-21.994-10.505-5.917-5.914-9.626-13.678-10.503-21.996-3.35-31.449-18.235-60.542-41.784-81.652-23.551-21.11-54.092-32.737-85.719-32.634-23.597-0.154-46.754 6.384-66.785 18.857-6.953 4.363-15.168 6.269-23.332 5.414s-15.805-4.42-21.704-10.128c-33.699-32.745-78.905-50.956-125.893-50.714-44.461 0.011-87.395 16.221-120.77 45.598s-54.9 69.908-60.551 114.009c-0.856 6.825-3.618 13.27-7.971 18.595s-10.119 9.315-16.636 11.512c-28.688 9.795-52.969 29.455-68.519 55.477s-21.361 56.718-16.396 86.623c4.964 29.905 20.381 57.078 43.504 76.68s52.454 30.362 82.768 30.363h128c9.699 0 19.002 3.853 25.86 10.712s10.711 16.16 10.711 25.86c0 9.699-3.853 19.002-10.711 25.86s-16.161 10.711-25.86 10.711h-128c-45.726-0.010-90.084-15.596-125.767-44.191s-60.559-68.491-70.532-113.116c-9.973-44.625-4.447-91.317 15.667-132.381s53.618-74.052 94.989-93.527c12.401-57.159 43.982-108.357 89.498-145.089s102.228-56.789 160.717-56.839c56.689-0.21 111.801 18.659 156.464 53.571 26.825-11.769 55.891-17.556 85.178-16.958s58.092 7.565 84.415 20.419c26.323 12.854 49.532 31.284 68.007 54.012 18.483 22.728 31.795 49.208 39.007 77.598 47.587 12.004 89.154 40.98 116.875 81.479 27.728 40.499 39.702 89.732 33.675 138.44-6.034 48.708-29.645 93.536-66.406 126.054s-84.136 50.488-133.215 50.527z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"grid":14,"tags":["arduino-cloud-download"],"colorPermutations":{"12714014111291321":[]}},"attrs":[],"properties":{"order":723,"id":198,"name":"arduino-cloud-download","prevSize":28,"code":59664},"setIdx":0,"setId":1,"iconIdx":0},{"icon":{"paths":["M854.72 246.726l-671.997 672.001c-6.066 5.946-14.223 9.28-22.719 9.28s-16.653-3.334-22.719-9.28c-5.996-6.042-9.361-14.208-9.361-22.72s3.365-16.678 9.361-22.72l107.52-107.52c-37.22-5.818-71.592-23.424-98.059-50.234s-43.632-61.402-48.97-98.694c-5.338-37.292 1.432-75.312 19.315-108.469s45.935-59.7 80.029-75.724c7.995-36.965 25.219-71.304 50.068-99.816s56.512-50.267 92.038-63.237c35.526-12.971 73.758-16.735 111.132-10.941s72.672 20.956 102.604 44.074c23.899-10.368 49.78-15.369 75.821-14.651 26.038 0.718 51.606 7.138 74.896 18.807l105.6-105.596c6.029-6.026 14.202-9.411 22.72-9.411 8.525 0 16.698 3.385 22.72 9.411 6.029 6.026 9.414 14.198 9.414 22.72s-3.386 16.694-9.414 22.72v0z","M928 592.030c-0.083 46.653-18.65 91.375-51.642 124.36-32.986 32.986-77.702 51.558-124.358 51.642h-322.563l361.283-361.282c1.6 4.797 2.88 9.6 4.166 14.398 38.093 9.509 71.904 31.506 96.032 62.48s37.184 69.139 37.082 108.402v0z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"grid":14,"tags":["arduino-cloud-filled-offline"],"colorPermutations":{"12714014111291321":[]}},"attrs":[],"properties":{"order":724,"id":197,"name":"arduino-cloud-filled-offline","prevSize":28,"code":59665},"setIdx":0,"setId":1,"iconIdx":1},{"icon":{"paths":["M928 591.998c-0.083 46.653-18.65 91.375-51.635 124.36-32.992 32.992-77.709 51.558-124.365 51.642h-479.998c-40.017-0.013-78.836-13.658-110.060-38.688-31.224-25.024-52.989-59.942-61.71-98.999-8.721-39.055-3.876-79.916 13.736-115.849s46.94-64.794 83.151-81.826c7.995-36.965 25.22-71.304 50.068-99.816s56.513-50.266 92.038-63.237c35.526-12.971 73.759-16.735 111.132-10.941s72.672 20.956 102.604 44.074c22.414-9.744 46.599-14.755 71.040-14.72 39.262-0.102 77.425 12.954 108.401 37.083s52.973 57.94 62.483 96.035c38.093 9.508 71.904 31.506 96.032 62.48s37.184 69.14 37.082 108.403z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"grid":14,"tags":["arduino-cloud-filled"],"colorPermutations":{"12714014111291321":[]}},"attrs":[],"properties":{"order":725,"id":196,"name":"arduino-cloud-filled","prevSize":28,"code":59666},"setIdx":0,"setId":1,"iconIdx":2},{"icon":{"paths":["M794.88 421.148c-1.28-4.797-2.56-9.601-4.16-14.398l-53.12 53.125c2.080 5.548 5.67 10.404 10.362 14.022 4.698 3.618 10.304 5.853 16.198 6.454 28.493 3.153 54.701 17.094 73.235 38.963 18.541 21.868 28 50.003 26.445 78.628s-14.016 55.569-34.81 75.3c-20.8 19.725-48.365 30.746-77.030 30.79h-258.563l-64 64h322.563c42.944-0.026 84.403-15.744 116.57-44.198s52.832-67.68 58.099-110.301c5.267-42.621-5.216-85.699-29.491-121.13-24.269-35.43-60.646-60.771-102.298-71.254v0z","M854.72 201.3c-6.042-5.997-14.208-9.363-22.72-9.363s-16.678 3.366-22.714 9.363l-105.606 105.595c-23.29-11.669-48.858-18.089-74.898-18.806s-51.923 4.284-75.821 14.652c-29.932-23.118-65.23-38.28-102.604-44.074s-75.606-2.029-111.132 10.941c-35.526 12.971-67.19 34.726-92.039 63.237s-42.073 62.851-50.068 99.816c-34.093 16.024-62.145 42.566-80.028 75.723s-24.653 71.177-19.315 108.468c5.338 37.292 22.502 71.884 48.968 98.693s60.837 44.416 98.057 50.234l-107.52 107.52c-5.996 6.042-9.361 14.208-9.361 22.72s3.364 16.678 9.361 22.72c6.065 5.946 14.223 9.28 22.719 9.28s16.653-3.334 22.719-9.28l672.001-672.001c5.997-6.040 9.357-14.207 9.363-22.718 0-8.511-3.366-16.678-9.363-22.719v0zM306.564 704.019h-34.563c-26.523 0.013-52.188-9.395-72.423-26.541s-33.725-40.92-38.067-67.085c-4.342-26.165 0.747-53.022 14.36-75.785s34.865-39.954 59.97-48.51c5.716-1.953 10.763-5.483 14.557-10.184s6.18-10.379 6.883-16.379c5.021-38.555 23.892-73.968 53.095-99.638s66.744-39.843 105.625-39.878c41.119-0.243 80.673 15.741 110.078 44.484 5.176 4.951 11.848 8.045 18.97 8.797s14.294-0.88 20.39-4.641c17.553-10.974 37.86-16.744 58.562-16.641 10.271 0.061 20.492 1.458 30.399 4.156l-347.836 347.843z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"grid":14,"tags":["arduino-cloud-offline"],"colorPermutations":{"12714014111291321":[]}},"attrs":[],"properties":{"order":726,"id":195,"name":"arduino-cloud-offline","prevSize":28,"code":59667},"setIdx":0,"setId":1,"iconIdx":3},{"icon":{"paths":["M684.258 537.965c-6.932 6.799-16.255 10.607-25.964 10.607s-19.032-3.809-25.964-10.607l-83.751-84.118v423.867c0 9.699-3.853 19.003-10.711 25.856-6.859 6.861-16.161 10.715-25.86 10.715s-19.001-3.855-25.86-10.715c-6.859-6.853-10.712-16.157-10.712-25.856v-423.867l-83.749 84.118c-6.886 6.886-16.227 10.756-25.966 10.756s-19.079-3.869-25.966-10.756c-6.886-6.886-10.755-16.227-10.755-25.966s3.869-19.079 10.755-25.966l146.286-146.286c6.903-6.854 16.236-10.701 25.964-10.701s19.062 3.847 25.964 10.701l146.286 146.286c6.853 6.904 10.7 16.237 10.701 25.965s-3.845 19.062-10.698 25.966z","M786.286 694.856h-128c-9.699 0-19.001-3.852-25.86-10.711s-10.712-16.161-10.712-25.86c0-9.699 3.853-19.001 10.712-25.86s16.16-10.712 25.86-10.712h128c32.768-0.031 64.285-12.618 88.057-35.172 23.779-22.554 38.005-53.361 39.76-86.085s-9.092-64.877-30.318-89.846c-21.219-24.97-51.207-40.858-83.785-44.396-8.316-0.882-16.084-4.59-21.994-10.505-5.917-5.914-9.626-13.678-10.503-21.996-3.35-31.449-18.235-60.542-41.784-81.652-23.551-21.11-54.092-32.737-85.719-32.634-23.597-0.154-46.754 6.384-66.785 18.857-6.954 4.362-15.168 6.268-23.331 5.413s-15.805-4.419-21.705-10.127c-33.699-32.745-78.905-50.956-125.893-50.714-44.461 0.011-87.395 16.221-120.77 45.598s-54.9 69.908-60.551 114.009c-0.856 6.825-3.618 13.27-7.971 18.595s-10.119 9.315-16.636 11.512c-28.688 9.795-52.969 29.455-68.519 55.477s-21.361 56.718-16.396 86.623c4.964 29.905 20.381 57.078 43.504 76.68s52.454 30.362 82.768 30.363h128c9.699 0 19.002 3.853 25.86 10.712s10.711 16.16 10.711 25.86c0 9.699-3.853 19.002-10.711 25.86s-16.161 10.711-25.86 10.711h-128c-45.726-0.010-90.084-15.596-125.767-44.191s-60.559-68.491-70.532-113.116c-9.973-44.625-4.447-91.317 15.667-132.381s53.618-74.052 94.989-93.527c12.401-57.159 43.982-108.357 89.498-145.089s102.228-56.789 160.717-56.839c56.689-0.21 111.801 18.659 156.464 53.571 26.825-11.769 55.891-17.556 85.178-16.958s58.092 7.565 84.415 20.419c26.323 12.854 49.532 31.284 68.007 54.012 18.483 22.728 31.795 49.208 39.007 77.598 47.587 12.004 89.154 40.98 116.875 81.479 27.728 40.499 39.702 89.732 33.675 138.44-6.034 48.708-29.645 93.536-66.406 126.054s-84.136 50.488-133.215 50.527z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"grid":14,"tags":["arduino-cloud-upload"],"colorPermutations":{"12714014111291321":[]}},"attrs":[],"properties":{"order":727,"id":194,"name":"arduino-cloud-upload","prevSize":28,"code":59668},"setIdx":0,"setId":1,"iconIdx":4},{"icon":{"paths":["M752 768h-480c-40.010-0.006-78.824-13.645-110.046-38.662-31.222-25.024-52.989-59.93-61.716-98.98-8.726-39.047-3.891-79.902 13.709-115.833s46.915-64.796 83.115-81.836c10.851-50.014 38.484-94.812 78.31-126.953s89.45-49.69 140.627-49.734c49.603-0.184 97.826 16.327 136.906 46.875 23.472-10.298 48.904-15.361 74.531-14.838s50.829 6.62 73.862 17.866c23.034 11.247 43.341 27.374 59.507 47.261 16.173 19.887 27.821 43.056 34.131 67.898 41.638 10.504 78.010 35.857 102.266 71.294 24.262 35.437 34.739 78.515 29.466 121.135-5.28 42.623-25.939 81.842-58.106 110.296s-73.619 44.179-116.563 44.211zM416 320.001c-38.904 0.010-76.471 14.193-105.674 39.899s-48.038 61.169-52.982 99.757c-0.749 5.972-3.166 11.611-6.975 16.271s-8.853 8.151-14.556 10.073c-25.102 8.571-46.348 25.773-59.954 48.542s-18.691 49.628-14.347 75.795c4.344 26.167 17.833 49.943 38.066 67.095s45.897 26.566 72.422 26.566h480c28.672-0.026 56.25-11.040 77.050-30.778 20.806-19.731 33.254-46.688 34.79-75.321s-7.955-56.767-26.528-78.616c-18.566-21.848-44.806-35.75-73.312-38.847-7.277-0.772-14.074-4.016-19.245-9.191-5.178-5.176-8.422-11.969-9.19-19.247-2.931-27.518-15.955-52.974-36.563-71.445-20.602-18.471-47.328-28.645-75.002-28.555-20.647-0.135-40.909 5.587-58.437 16.5-6.084 3.816-13.272 5.484-20.415 4.737s-13.83-3.868-18.992-8.861c-29.487-28.652-69.042-44.586-110.156-44.375v0z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"grid":14,"tags":["arduino-cloud"],"colorPermutations":{"12714014111291321":[]}},"attrs":[],"properties":{"order":728,"id":193,"name":"arduino-cloud","prevSize":28,"code":59669},"setIdx":0,"setId":1,"iconIdx":5},{"icon":{"paths":["M558.545 1024c-23.818 0-47.637-9.095-65.819-27.276l-465.454-465.453c-36.363-36.363-36.363-95.273 0-131.636s95.273-36.363 131.637 0l399.636 399.636 772.003-772c36.361-36.363 95.269-36.363 131.631 0s36.361 95.273 0 131.637l-837.815 837.815c-18.182 18.181-42 27.276-65.818 27.276z"],"attrs":[{}],"width":1489,"isMulticolor":false,"isMulticolor2":false,"grid":14,"tags":["arduino-verify"],"colorPermutations":{"12714014111291321":[{}]}},"attrs":[{}],"properties":{"order":12,"id":192,"name":"arduino-verify","prevSize":28,"code":59659},"setIdx":0,"setId":1,"iconIdx":6},{"icon":{"paths":["M1072.469 526.509l-409.603 409.598c-13.65 12.971-30.717 19.804-48.467 19.804s-34.817-6.833-48.467-19.804c-26.625-26.617-26.625-70.315 0-96.932l293.551-292.866h-791.217c-37.55 0-68.267-30.717-68.267-68.267s30.717-68.267 68.267-68.267h791.217l-293.551-292.866c-26.625-26.616-26.625-70.317 0-96.934 26.616-26.634 70.317-26.634 96.933 0l409.603 409.6c26.624 26.616 26.624 70.317 0 96.934v0z"],"attrs":[{}],"width":1161,"isMulticolor":false,"isMulticolor2":false,"grid":14,"tags":["arduino-upload"],"colorPermutations":{"12714014111291321":[{}]}},"attrs":[{}],"properties":{"order":11,"id":191,"name":"arduino-upload","prevSize":28,"code":59660},"setIdx":0,"setId":1,"iconIdx":7},{"icon":{"paths":["M651.891 890.88c-92.835 0-179.095-28.493-250.5-77.197l-129.659 129.658c-22.494 22.496-58.964 22.496-81.458 0s-22.494-58.963 0-81.459l124.954-124.954c-67.75-78.157-108.777-180.090-108.777-291.489 0-245.759 199.68-445.439 445.44-445.439s445.44 199.679 445.44 445.439c0 245.761-199.68 445.441-445.44 445.441zM651.891 153.6c-161.28 0-291.84 130.559-291.84 291.839s130.56 291.841 291.84 291.841c160.512 0 291.84-130.561 291.84-291.841 0-160.511-130.56-291.839-291.84-291.839zM1149.562 478.091c0 35.423 28.717 64.138 64.141 64.138s64.134-28.716 64.134-64.138c0-35.423-28.71-64.139-64.134-64.139s-64.141 28.716-64.141 64.139zM64.064 542.237c-35.382 0-64.064-28.682-64.064-64.063s28.682-64.064 64.064-64.064c35.381 0 64.064 28.682 64.064 64.064s-28.683 64.063-64.064 64.063zM1458.707 542.229c-35.418 0-64.134-28.716-64.134-64.138s28.717-64.139 64.134-64.139c35.424 0 64.141 28.716 64.141 64.139s-28.717 64.138-64.141 64.138zM652.659 526.847c-44.961 0-81.408-36.447-81.408-81.407s36.447-81.408 81.408-81.408c44.96 0 81.408 36.447 81.408 81.408s-36.448 81.407-81.408 81.407z"],"attrs":[{}],"width":1536,"isMulticolor":false,"isMulticolor2":false,"grid":14,"tags":["arduino-monitor"],"colorPermutations":{"12714014111291321":[{}]}},"attrs":[{}],"properties":{"order":10,"id":190,"name":"arduino-monitor","prevSize":28,"code":59661},"setIdx":0,"setId":1,"iconIdx":8},{"icon":{"paths":["M511.998 603.432c50.495 0 91.432-40.936 91.432-91.432s-40.936-91.432-91.432-91.432c-50.495 0-91.432 40.936-91.432 91.432s40.936 91.432 91.432 91.432z","M923.433 603.432c50.494 0 91.432-40.936 91.432-91.432s-40.937-91.432-91.432-91.432c-50.494 0-91.432 40.936-91.432 91.432s40.937 91.432 91.432 91.432z","M100.565 603.432c50.495 0 91.432-40.936 91.432-91.432s-40.936-91.432-91.432-91.432c-50.495 0-91.432 40.936-91.432 91.432s40.936 91.432 91.432 91.432z"],"attrs":[{},{},{}],"isMulticolor":false,"isMulticolor2":false,"grid":14,"tags":["arduino-sketch-tabs-menu"],"colorPermutations":{"12714014111291321":[{},{},{}]}},"attrs":[{},{},{}],"properties":{"order":9,"id":189,"name":"arduino-sketch-tabs-menu","prevSize":28,"code":59662},"setIdx":0,"setId":1,"iconIdx":9},{"icon":{"paths":["M323.368 970.208c-20.263 0-39-11.42-48.21-29.788l-146.789-293.581h-74.474c-29.789 0-53.895-24.107-53.895-53.895s24.105-53.895 53.895-53.895h107.789c20.421 0 39.053 11.528 48.21 29.788l96.527 193.056 180.263-720.949c5.842-23.579 26.737-40.263 51-40.842 23.947-1.579 45.893 15.158 52.894 38.421l150.162 500.526h67.681c29.788 0 53.895 24.107 53.895 53.895s-24.107 53.895-53.895 53.895h-107.789c-23.789 0-44.787-15.629-51.631-38.422l-105.316-351.104-168.052 672.053c-5.474 21.897-23.948 38.055-46.368 40.529-2 0.21-3.947 0.313-5.895 0.313h-0.001z"],"attrs":[{}],"width":862,"isMulticolor":false,"isMulticolor2":false,"grid":14,"tags":["arduino-plotter"],"colorPermutations":{"12714014111291321":[{}]}},"attrs":[{}],"properties":{"order":8,"id":188,"name":"arduino-plotter","prevSize":28,"code":59663},"setIdx":0,"setId":1,"iconIdx":10},{"icon":{"paths":["M416.006 800c-4.211 0.026-8.386-0.787-12.285-2.374-3.899-1.594-7.445-3.942-10.435-6.906l-224-224.002c-6.026-6.026-9.411-14.198-9.411-22.72s3.385-16.694 9.411-22.72c6.026-6.026 14.198-9.411 22.72-9.411s16.694 3.386 22.72 9.411l201.28 201.602 425.281-425.602c6.022-6.026 14.195-9.411 22.72-9.411 8.518 0 16.691 3.386 22.72 9.411 6.022 6.026 9.408 14.198 9.408 22.72s-3.386 16.694-9.408 22.72l-448.001 448.002c-2.99 2.963-6.536 5.312-10.435 6.906-3.899 1.587-8.074 2.4-12.285 2.374z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["fa-check"],"grid":14,"colorPermutations":{"12714014111291321":[{}]}},"attrs":[{}],"properties":{"order":722,"id":0,"name":"fa-check","prevSize":28,"code":59658},"setIdx":0,"setId":1,"iconIdx":11},{"icon":{"paths":["M864 128h-576c-8.484 0.062-16.618 3.385-22.72 9.28l-128 128c-5.969 6.052-9.305 14.219-9.28 22.72v576c0.024 8.48 3.404 16.602 9.4 22.598s14.121 9.376 22.6 9.402h576c8.486-0.038 16.634-3.36 22.72-9.28l128-128c5.894-6.099 9.216-14.234 9.28-22.72v-576c-0.026-8.479-3.405-16.605-9.402-22.6s-14.118-9.375-22.598-9.4zM704 832h-512v-512h512v512zM722.56 256h-485.12l63.68-64h485.44l-64 64zM832 722.88l-64 63.68v-485.12l64-64v485.44z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["technology-3dimensionscube"],"grid":14,"colorPermutations":{"12714014111291321":[{}]}},"attrs":[{}],"properties":{"order":717,"id":1,"name":"arduino-technology-3dimensionscube","prevSize":28,"code":59654},"setIdx":0,"setId":1,"iconIdx":12},{"icon":{"paths":["M848 224v96c0 8.487-3.373 16.627-9.37 22.627-6.003 6.001-14.144 9.373-22.63 9.373h-16v96c-0.019 5.909-1.67 11.699-4.781 16.725-3.104 5.027-7.539 9.096-12.819 11.755l-238.4 119.36v242.88c16.845 7.354 30.644 20.282 39.079 36.608 8.435 16.333 10.989 35.066 7.233 53.056s-13.59 34.144-27.852 45.734c-14.262 11.597-32.081 17.92-50.46 17.92s-36.198-6.323-50.46-17.92c-14.262-11.59-24.097-27.744-27.852-45.734s-1.201-36.723 7.233-53.056c8.435-16.326 22.234-29.254 39.079-36.608v-82.88l-238.4-119.36c-5.277-2.659-9.715-6.728-12.822-11.755s-4.76-10.816-4.778-16.725v-102.72c-16.845-7.352-30.644-20.279-39.079-36.609s-10.988-35.066-7.233-53.057c3.755-17.992 13.59-34.141 27.852-45.734s32.081-17.921 50.46-17.921c18.38 0 36.198 6.328 50.46 17.921s24.097 27.743 27.852 45.734c3.756 17.992 1.201 36.727-7.233 53.057s-22.234 29.257-39.079 36.609v82.88l192 96v-524.16h-32c-6.372 0.032-12.609-1.839-17.91-5.374s-9.428-8.572-11.85-14.466c-2.41-5.858-3.028-12.3-1.775-18.509s4.321-11.907 8.815-16.371l64-64c2.975-2.999 6.514-5.38 10.413-7.005s8.083-2.461 12.307-2.461c4.225 0 8.407 0.836 12.307 2.461s7.439 4.005 10.413 7.005l64 64c4.44 4.5 7.448 10.214 8.644 16.422s0.526 12.63-1.924 18.458c-2.401 5.844-6.477 10.846-11.716 14.377s-11.406 5.432-17.724 5.463h-32v364.16l192-96v-76.16h-16c-8.486 0-16.627-3.372-22.63-9.373-5.997-6.001-9.37-14.14-9.37-22.627v-96c0-8.487 3.373-16.627 9.37-22.627 6.003-6.001 14.144-9.373 22.63-9.373h96c8.486 0 16.627 3.372 22.63 9.373 5.997 6.001 9.37 14.14 9.37 22.627z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["technology-usb"],"grid":14,"colorPermutations":{"12714014111291321":[{}]}},"attrs":[{}],"properties":{"order":715,"id":2,"name":"arduino-technology-usb","prevSize":28,"code":59655},"setIdx":0,"setId":1,"iconIdx":13},{"icon":{"paths":["M512 832c35.346 0 64-28.653 64-64s-28.654-64-64-64c-35.346 0-64 28.653-64 64s28.654 64 64 64z","M647.699 664.32c-8.442-0.122-16.493-3.571-22.401-9.6-14.863-14.9-32.519-26.721-51.957-34.787s-40.277-12.218-61.323-12.218c-21.046 0-41.884 4.152-61.323 12.218s-37.094 19.887-51.957 34.787c-5.996 5.958-14.106 9.306-22.56 9.306s-16.564-3.347-22.56-9.306c-5.96-5.997-9.306-14.106-9.306-22.559s3.345-16.564 9.306-22.56c20.801-20.803 45.495-37.304 72.673-48.563s56.308-17.053 85.727-17.053c29.418 0 58.548 5.795 85.726 17.053s51.875 27.761 72.675 48.563c4.512 4.476 7.59 10.194 8.838 16.426 1.254 6.232 0.614 12.695-1.818 18.562-2.438 5.875-6.573 10.886-11.866 14.4-5.299 3.514-11.52 5.37-17.875 5.331z","M919.373 392.639c-4.269 0.195-8.538-0.47-12.55-1.954s-7.686-3.757-10.81-6.686c-101.965-101.613-240.045-158.669-383.997-158.669-143.951 0-282.035 57.056-384 158.669-6.026 5.983-14.181 9.328-22.673 9.298s-16.623-3.432-22.607-9.458c-5.983-6.026-9.327-14.181-9.298-22.673s3.432-16.623 9.458-22.607c114.009-113.924 268.588-177.918 429.76-177.918 161.175 0 315.754 63.994 429.757 177.918 3.002 2.975 5.382 6.514 7.008 10.413s2.458 8.083 2.458 12.307c0 4.225-0.832 8.407-2.458 12.307s-4.006 7.439-7.008 10.413c-3.078 2.89-6.701 5.14-10.656 6.623-3.949 1.483-8.16 2.168-12.384 2.017z","M783.706 528.316c-4.211 0.024-8.384-0.783-12.288-2.375-3.898-1.592-7.443-3.939-10.432-6.905-32.691-32.703-71.501-58.646-114.221-76.346-42.715-17.7-88.501-26.81-134.74-26.81s-92.025 9.11-134.742 26.81c-42.717 17.7-81.529 43.643-114.218 76.346-6.122 5.242-13.996 7.982-22.049 7.671s-15.693-3.65-21.393-9.349c-5.699-5.699-9.037-13.338-9.348-21.392s2.428-15.928 7.67-22.050c78.009-77.968 183.788-121.767 294.080-121.767s216.072 43.799 294.081 121.767c5.958 5.996 9.306 14.106 9.306 22.56s-3.347 16.564-9.306 22.56c-5.958 5.912-14.003 9.245-22.4 9.28z"],"attrs":[{},{},{},{}],"isMulticolor":false,"isMulticolor2":false,"tags":["technology-connection"],"grid":14,"colorPermutations":{"12714014111291321":[{},{},{},{}]}},"attrs":[{},{},{},{}],"properties":{"order":714,"id":3,"name":"arduino-technology-connection","prevSize":28,"code":59656},"setIdx":0,"setId":1,"iconIdx":14},{"icon":{"paths":["M512.006 991.994c-4.198 0.109-8.362-0.768-12.16-2.56-5.844-2.4-10.846-6.477-14.377-11.712-3.53-5.242-5.431-11.405-5.463-17.728v-370.877l-169.28 169.597c-2.984 2.989-6.525 5.35-10.424 6.97-3.898 1.613-8.077 2.445-12.296 2.445s-8.397-0.832-12.296-2.445c-3.898-1.619-7.441-3.981-10.424-6.97-2.984-2.982-5.35-6.522-6.965-10.419s-2.445-8.077-2.445-12.301c0-4.218 0.831-8.397 2.445-12.294s3.981-7.437 6.965-10.426l201.6-201.277-201.6-201.28c-6.026-6.026-9.411-14.198-9.411-22.72s3.385-16.694 9.411-22.72c6.026-6.026 14.198-9.411 22.72-9.411s16.694 3.386 22.72 9.411l169.28 169.6v-370.88c0.032-6.318 1.933-12.485 5.463-17.724s8.533-9.316 14.377-11.716c5.828-2.451 12.25-3.12 18.458-1.924s11.922 4.204 16.422 8.644l224.001 224c3.002 2.975 5.382 6.514 7.002 10.413 1.626 3.9 2.464 8.082 2.464 12.307s-0.838 8.407-2.464 12.307c-1.619 3.9-4 7.439-7.002 10.413l-201.601 201.28 201.601 201.277c3.002 2.976 5.382 6.515 7.002 10.419 1.626 3.898 2.464 8.077 2.464 12.301 0 4.23-0.838 8.41-2.464 12.307-1.619 3.904-4 7.443-7.002 10.413l-224.001 224c-2.99 2.97-6.536 5.318-10.435 6.906-3.899 1.594-8.074 2.4-12.285 2.374zM544.006 589.117v293.757l146.881-146.88-146.881-146.877zM544.006 141.117v293.76l146.881-146.88-146.881-146.88z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"tags":["technology-bluetooth"],"grid":14,"colorPermutations":{"12714014111291321":[{}]}},"attrs":[{}],"properties":{"order":713,"id":4,"name":"arduino-technology-bluetooth","prevSize":28,"code":59657},"setIdx":0,"setId":1,"iconIdx":15},{"icon":{"paths":["M613.86 663.104c-8.983 0.005-17.72-2.956-24.841-8.429-7.126-5.474-12.241-13.144-14.55-21.825s-1.685-17.883 1.778-26.173c3.463-8.29 9.57-15.202 17.366-19.661l304.621-173.965-488.052-278.887v296.386c0 10.801-4.291 21.16-11.929 28.799-7.638 7.636-17.997 11.927-28.799 11.927s-21.16-4.291-28.799-11.927c-7.638-7.638-11.929-17.997-11.929-28.799v-366.545c-0.004-7.135 1.867-14.146 5.426-20.33s8.681-11.324 14.852-14.905c6.171-3.581 13.175-5.477 20.31-5.499s14.15 1.832 20.343 5.376l610.91 349.045c6.232 3.561 11.413 8.707 15.020 14.917 3.603 6.21 5.502 13.261 5.502 20.441s-1.899 14.232-5.502 20.441c-3.607 6.21-8.788 11.356-15.020 14.917l-366.545 209.324c-6.135 3.528-13.089 5.381-20.163 5.371z","M491.636 797.094c10.803 0 21.16-4.291 28.798-11.93s11.93-17.994 11.93-28.798c0-10.803-4.291-21.16-11.93-28.798s-17.994-11.93-28.798-11.93h-43.173c-1.991-17.389-5.534-34.56-10.589-51.316l41.949-41.951c3.798-3.793 6.81-8.304 8.867-13.265 2.053-4.962 3.109-10.277 3.109-15.649s-1.057-10.687-3.109-15.649c-2.057-4.962-5.069-9.467-8.867-13.265s-8.304-6.81-13.265-8.867c-4.961-2.053-10.279-3.114-15.649-3.114s-10.688 1.061-15.649 3.114c-4.961 2.057-9.47 5.069-13.267 8.867l-21.585 21.583c-14.553-22.109-34.216-40.387-57.327-53.285-23.11-12.902-48.988-20.052-75.444-20.838-26.456 0.787-52.334 7.936-75.444 20.838s-42.774 31.181-57.327 53.29l-21.585-21.588c-7.669-7.671-18.070-11.976-28.915-11.976s-21.247 4.305-28.916 11.976c-7.669 7.666-11.978 18.069-11.978 28.914s4.308 21.248 11.977 28.914l41.949 41.951c-5.055 16.756-8.599 33.927-10.589 51.316h-43.171c-10.802 0-21.161 4.291-28.799 11.93s-11.929 17.994-11.929 28.798c0 10.803 4.291 21.16 11.929 28.798s17.997 11.93 28.799 11.93h43.173c1.991 17.389 5.534 34.56 10.589 51.316l-1.222 1.224-40.727 40.727c-7.631 7.685-11.913 18.078-11.913 28.914 0 10.831 4.282 21.225 11.913 28.914 7.72 7.568 18.102 11.813 28.915 11.813s21.194-4.245 28.915-11.813l21.585-21.588c14.553 22.109 34.216 40.387 57.327 53.29s48.989 20.052 75.445 20.838c26.456-0.787 52.334-7.936 75.444-20.838s42.774-31.181 57.327-53.29l21.585 21.588c7.72 7.573 18.102 11.813 28.915 11.813s21.194-4.24 28.916-11.813c7.629-7.689 11.911-18.083 11.911-28.914 0-10.836-4.282-21.229-11.911-28.914l-41.95-41.951c5.055-16.756 8.599-33.927 10.589-51.316h43.174zM267.636 593.458c37.058 0 69.644 32.991 87.564 81.455h-175.127c17.92-48.463 50.506-81.455 87.564-81.455zM267.636 919.276c-55.389 0-101.818-74.533-101.818-162.909h203.636c0 88.376-46.429 162.909-101.818 162.909z"],"attrs":[{},{}],"tags":["arduino-debugger"],"grid":14,"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"12714014111291321":[{},{}]}},"attrs":[{},{}],"properties":{"order":696,"id":5,"name":"arduino-debugger","prevSize":28,"code":59653},"setIdx":0,"setId":1,"iconIdx":16},{"icon":{"paths":["M1011.905 953.837l-286.249-286.249c66.349-81.248 98.942-184.882 91.034-289.478-7.903-104.597-55.702-202.157-133.511-272.506-77.804-70.35-179.671-108.111-284.533-105.473s-204.701 45.47-278.874 119.643c-74.172 74.172-117.006 174.012-119.643 278.874s35.123 206.729 105.473 284.537c70.35 77.804 167.91 125.604 272.506 133.506 104.597 7.907 208.231-24.685 289.479-91.034l286.249 286.249c3.8 3.832 8.323 6.874 13.305 8.95s10.328 3.145 15.727 3.145c5.398 0 10.745-1.071 15.727-3.145 4.986-2.075 9.506-5.117 13.31-8.95 3.832-3.804 6.874-8.323 8.95-13.31 2.075-4.982 3.145-10.328 3.145-15.727s-1.071-10.739-3.145-15.727c-2.075-4.982-5.117-9.506-8.95-13.305v0zM410.372 737.512c-64.702 0-127.952-19.184-181.75-55.132-53.798-35.944-95.728-87.038-120.49-146.816s-31.239-125.554-18.616-189.013c12.623-63.459 43.78-121.751 89.532-167.502s104.043-76.909 167.502-89.532c63.459-12.623 129.235-6.145 189.013 18.616s110.868 66.691 146.816 120.489c35.948 53.798 55.132 117.048 55.132 181.75 0 86.766-34.467 169.972-95.815 231.325-61.353 61.349-144.564 95.815-231.326 95.815v0z"],"attrs":[{}],"tags":["arduino-search"],"grid":14,"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"12714014111291321":[{}]}},"attrs":[{}],"properties":{"order":689,"id":6,"name":"arduino-search","prevSize":28,"code":59649},"setIdx":0,"setId":1,"iconIdx":17},{"icon":{"paths":["M997.684 728.889c0 11.506-4.572 22.538-12.707 30.67s-19.165 12.707-30.67 12.707h-433.777c-11.506 0-22.538-4.572-30.673-12.707s-12.705-19.165-12.705-30.67 4.571-22.538 12.705-30.67c8.136-8.134 19.166-12.707 30.673-12.707h433.777c11.506 0 22.538 4.572 30.67 12.707s12.707 19.165 12.707 30.67z","M1201.991 351.068l-74.173-73.742v-199.104c0-11.503-4.572-22.539-12.707-30.673s-19.165-12.705-30.67-12.705h-910.933c-11.503 0-22.539 4.571-30.673 12.705s-12.705 19.168-12.705 30.673v130.133h-86.756c-11.504 0-22.539 4.571-30.673 12.705s-12.705 19.168-12.705 30.673v216.89c0 11.503 4.571 22.539 12.705 30.673s19.168 12.705 30.673 12.705h86.756v433.777c0 11.506 4.571 22.538 12.705 30.67s19.168 12.707 30.673 12.707h910.933c5.71 0.034 11.368-1.062 16.653-3.216 5.285-2.161 10.092-5.342 14.143-9.365l86.756-86.756c4.020-4.052 7.203-8.859 9.365-14.143 2.157-5.285 3.253-10.94 3.216-16.653v-477.156c0.034-5.708-1.062-11.369-3.216-16.654-2.161-5.285-5.342-10.092-9.365-14.145zM86.751 425.243v-130.133h216.89v130.133h-216.89zM1127.818 841.24l-61.159 61.159h-849.774v-390.4h130.133c11.503 0 22.539-4.571 30.673-12.705s12.705-19.168 12.705-30.673v-216.89c0-11.503-4.571-22.539-12.705-30.673s-19.168-12.705-30.673-12.705h-130.133v-86.756h824.177v173.51c-0.034 5.708 1.062 11.369 3.216 16.654 2.161 5.285 5.342 10.092 9.365 14.145l74.173 73.742v441.589z"],"width":1214.5714285714287,"attrs":[{},{}],"tags":["arduino-boards"],"grid":14,"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"12714014111291321":[{},{}]}},"attrs":[{},{}],"properties":{"order":7,"id":7,"name":"arduino-boards","prevSize":28,"code":59650},"setIdx":0,"setId":1,"iconIdx":18},{"icon":{"paths":["M1021.954 918.445l-171.299-652.491c-2.901-9.738-9.491-17.956-18.363-22.903-8.876-4.946-19.333-6.228-29.138-3.571l-141.319 35.427v-230.085c0-10.325-4.102-20.227-11.403-27.529s-17.201-11.403-27.528-11.403h-155.725c-10.327 0-20.226 4.101-27.529 11.403-7.301 7.302-11.403 17.203-11.403 27.529v116.794h-155.725v-77.863c0-10.325-4.101-20.227-11.403-27.529s-17.203-11.403-27.529-11.403h-194.658c-10.325 0-20.227 4.101-27.529 11.403s-11.403 17.203-11.403 27.529v895.424c0 10.327 4.101 20.226 11.403 27.528s17.203 11.403 27.529 11.403h583.972c10.327 0 20.226-4.102 27.528-11.403s11.403-17.201 11.403-27.528v-454.332l119.909 456.668c2.207 8.565 7.265 16.124 14.34 21.433 7.079 5.308 15.751 8.044 24.591 7.764 3.364 0.379 6.758 0.379 10.123 0l164.678-43.212c9.975-2.589 18.518-9.032 23.75-17.908 2.581-4.721 4.156-9.926 4.627-15.288 0.467-5.361-0.178-10.759-1.9-15.857v0zM194.659 940.247h-116.794v-817.56h116.794v817.56zM428.248 940.247h-155.725v-700.766h155.725v700.766zM583.973 940.247h-77.863v-856.491h77.863v856.491zM847.15 923.896l-151.442-576.964 89.543-23.748 151.442 578.132-89.543 22.58z"],"attrs":[{}],"tags":["arduino-library"],"grid":14,"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"12714014111291321":[{}]}},"attrs":[{}],"properties":{"order":691,"id":8,"name":"arduino-library","prevSize":28,"code":59651},"setIdx":0,"setId":1,"iconIdx":19},{"icon":{"paths":["M1189.198 204.801h-542.21l-189.437-189.951c-4.784-4.746-10.457-8.499-16.696-11.048s-12.918-3.84-19.656-3.801h-358.398c-13.579 0-26.602 5.394-36.204 14.997s-14.997 22.624-14.997 36.204v921.597c0 13.581 5.394 26.601 14.997 36.203s22.624 14.998 36.204 14.998h1126.397c13.581 0 26.601-5.395 36.203-14.998s14.998-22.621 14.998-36.203v-716.798c0-13.579-5.395-26.602-14.998-36.204s-22.621-14.997-36.203-14.997zM114.001 102.4h286.208l102.4 102.4h-388.606v-102.4zM1137.998 921.598h-1023.998v-614.398h1023.998v614.398z"],"width":1252,"attrs":[{}],"tags":["arduino-folder"],"grid":14,"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"12714014111291321":[{}]}},"attrs":[{}],"properties":{"order":692,"id":9,"name":"arduino-folder","prevSize":28,"code":59652},"setIdx":0,"setId":1,"iconIdx":20},{"icon":{"paths":["M512.083 959.936c118.817 0 232.769-47.2 316.781-131.213 84.019-84.019 131.219-197.969 131.219-316.785 0-8.487-3.373-16.627-9.376-22.628-5.997-6.001-14.138-9.373-22.624-9.373s-16.627 3.372-22.63 9.373c-5.997 6.001-9.37 14.141-9.37 22.627-0.019 87.81-30.131 172.959-85.318 241.26s-132.115 115.622-217.962 134.086c-85.848 18.458-175.428 6.931-253.811-32.646-78.383-39.584-140.833-104.832-176.941-184.87-36.108-80.045-43.693-170.045-21.49-255.001s72.852-159.737 143.505-211.878c70.653-52.141 157.042-78.492 244.768-74.662s171.487 37.612 237.33 95.712h-158.081c-8.487 0-16.626 3.372-22.627 9.373s-9.373 14.141-9.373 22.627c0 8.487 3.372 16.627 9.373 22.628s14.14 9.372 22.627 9.372h224.001c8.486 0 16.627-3.371 22.624-9.372 6.003-6.001 9.376-14.141 9.376-22.628v-224c0-8.487-3.373-16.626-9.376-22.627-5.997-6.001-14.138-9.373-22.624-9.373s-16.627 3.371-22.63 9.373c-5.997 6.001-9.37 14.14-9.37 22.627v136.96c-55.162-46.332-120.678-78.68-191.002-94.301s-143.375-14.052-212.963 4.571c-69.588 18.623-133.659 53.753-186.78 102.41s-93.725 109.405-118.369 177.096c-24.644 67.69-32.602 140.324-23.199 211.745 9.404 71.419 35.891 139.521 77.216 198.523 41.325 59.008 96.27 107.174 160.174 140.422s134.885 50.598 206.922 50.573v0z"],"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[{}],"12714014111291321":[{}]},"tags":["reload"],"grid":14},"attrs":[{}],"properties":{"order":681,"id":10,"name":"reload","prevSize":28,"code":59648},"setIdx":0,"setId":1,"iconIdx":21},{"icon":{"paths":["M846.857 600c34.857 20 46.857 65.143 26.857 100l-36.571 62.857c-20 34.857-65.143 46.857-100 26.857l-152-87.429v175.429c0 40-33.143 73.143-73.143 73.143h-73.143c-40 0-73.143-33.143-73.143-73.143v-175.429l-152 87.429c-34.857 20-80 8-100-26.857l-36.571-62.857c-20-34.857-8-80 26.857-100l152-88-152-88c-34.857-20-46.857-65.143-26.857-100l36.571-62.857c20-34.857 65.143-46.857 100-26.857l152 87.429v-175.429c0-40 33.143-73.143 73.143-73.143h73.143c40 0 73.143 33.143 73.143 73.143v175.429l152-87.429c34.857-20 80-8 100 26.857l36.571 62.857c20 34.857 8 80-26.857 100l-152 88z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["asterisk"],"defaultCode":61545,"grid":14},"attrs":[],"properties":{"name":"asterisk","id":11,"order":679,"prevSize":28,"code":61545},"setIdx":0,"setId":1,"iconIdx":22},{"icon":{"paths":["M804.571 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-237.714v237.714c0 30.286-24.571 54.857-54.857 54.857h-109.714c-30.286 0-54.857-24.571-54.857-54.857v-237.714h-237.714c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h237.714v-237.714c0-30.286 24.571-54.857 54.857-54.857h109.714c30.286 0 54.857 24.571 54.857 54.857v237.714h237.714c30.286 0 54.857 24.571 54.857 54.857z"],"width":804.5714285714286,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["plus"],"defaultCode":61543,"grid":14},"attrs":[],"properties":{"name":"plus","id":12,"order":3,"prevSize":28,"code":61543},"setIdx":0,"setId":1,"iconIdx":23},{"icon":{"paths":["M402.286 717.714v137.143c0 12.571-10.286 22.857-22.857 22.857h-137.143c-12.571 0-22.857-10.286-22.857-22.857v-137.143c0-12.571 10.286-22.857 22.857-22.857h137.143c12.571 0 22.857 10.286 22.857 22.857zM582.857 374.857c0 108.571-73.714 150.286-128 180.571-33.714 19.429-54.857 58.857-54.857 75.429v0c0 12.571-9.714 27.429-22.857 27.429h-137.143c-12.571 0-20.571-19.429-20.571-32v-25.714c0-69.143 68.571-128.571 118.857-151.429 44-20 62.286-38.857 62.286-75.429 0-32-41.714-60.571-88-60.571-25.714 0-49.143 8-61.714 16.571-13.714 9.714-27.429 23.429-61.143 65.714-4.571 5.714-11.429 9.143-17.714 9.143-5.143 0-9.714-1.714-14.286-4.571l-93.714-71.429c-9.714-7.429-12-20-5.714-30.286 61.714-102.286 148.571-152 265.143-152 122.286 0 259.429 97.714 259.429 228.571z"],"width":634.88,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["question"],"defaultCode":61736,"grid":14},"attrs":[],"properties":{"name":"question","id":13,"order":4,"prevSize":28,"code":61736},"setIdx":0,"setId":1,"iconIdx":24},{"icon":{"paths":["M804.571 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-694.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h694.857c30.286 0 54.857 24.571 54.857 54.857z"],"width":804.5714285714286,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["minus"],"defaultCode":61544,"grid":14},"attrs":[],"properties":{"name":"minus","id":14,"order":5,"prevSize":28,"code":61544},"setIdx":0,"setId":1,"iconIdx":25},{"icon":{"paths":["M877.714 128v640c0 80.571-120.571 109.714-182.857 109.714s-182.857-29.143-182.857-109.714 120.571-109.714 182.857-109.714c37.714 0 75.429 6.857 109.714 22.286v-306.857l-438.857 135.429v405.143c0 80.571-120.571 109.714-182.857 109.714s-182.857-29.143-182.857-109.714 120.571-109.714 182.857-109.714c37.714 0 75.429 6.857 109.714 22.286v-552.571c0-24 16-45.143 38.857-52.571l475.429-146.286c5.143-1.714 10.286-2.286 16-2.286 30.286 0 54.857 24.571 54.857 54.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["music"],"defaultCode":61441,"grid":14},"attrs":[],"properties":{"name":"music","id":15,"order":7,"prevSize":28,"code":61441},"setIdx":0,"setId":1,"iconIdx":26},{"icon":{"paths":["M658.286 475.429c0-141.143-114.857-256-256-256s-256 114.857-256 256 114.857 256 256 256 256-114.857 256-256zM950.857 950.857c0 40-33.143 73.143-73.143 73.143-19.429 0-38.286-8-51.429-21.714l-196-195.429c-66.857 46.286-146.857 70.857-228 70.857-222.286 0-402.286-180-402.286-402.286s180-402.286 402.286-402.286 402.286 180 402.286 402.286c0 81.143-24.571 161.143-70.857 228l196 196c13.143 13.143 21.143 32 21.143 51.429z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["search"],"defaultCode":61442,"grid":14},"attrs":[],"properties":{"name":"search","id":16,"order":8,"prevSize":28,"code":61442},"setIdx":0,"setId":1,"iconIdx":27},{"icon":{"paths":["M950.857 859.429v-438.857c-12 13.714-25.143 26.286-39.429 37.714-81.714 62.857-164 126.857-243.429 193.143-42.857 36-96 80-155.429 80h-1.143c-59.429 0-112.571-44-155.429-80-79.429-66.286-161.714-130.286-243.429-193.143-14.286-11.429-27.429-24-39.429-37.714v438.857c0 9.714 8.571 18.286 18.286 18.286h841.143c9.714 0 18.286-8.571 18.286-18.286zM950.857 258.857c0-14.286 3.429-39.429-18.286-39.429h-841.143c-9.714 0-18.286 8.571-18.286 18.286 0 65.143 32.571 121.714 84 162.286 76.571 60 153.143 120.571 229.143 181.143 30.286 24.571 85.143 77.143 125.143 77.143h1.143c40 0 94.857-52.571 125.143-77.143 76-60.571 152.571-121.143 229.143-181.143 37.143-29.143 84-92.571 84-141.143zM1024 237.714v621.714c0 50.286-41.143 91.429-91.429 91.429h-841.143c-50.286 0-91.429-41.143-91.429-91.429v-621.714c0-50.286 41.143-91.429 91.429-91.429h841.143c50.286 0 91.429 41.143 91.429 91.429z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["envelope-o"],"defaultCode":61443,"grid":14},"attrs":[],"properties":{"name":"envelope-o","id":17,"order":9,"prevSize":28,"code":61443},"setIdx":0,"setId":1,"iconIdx":28},{"icon":{"paths":["M512 950.857c-9.143 0-18.286-3.429-25.143-10.286l-356.571-344c-4.571-4-130.286-118.857-130.286-256 0-167.429 102.286-267.429 273.143-267.429 100 0 193.714 78.857 238.857 123.429 45.143-44.571 138.857-123.429 238.857-123.429 170.857 0 273.143 100 273.143 267.429 0 137.143-125.714 252-130.857 257.143l-356 342.857c-6.857 6.857-16 10.286-25.143 10.286z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["heart"],"defaultCode":61444,"grid":14},"attrs":[],"properties":{"name":"heart","id":18,"order":10,"prevSize":28,"code":61444},"setIdx":0,"setId":1,"iconIdx":29},{"icon":{"paths":["M950.857 369.714c0 10.286-7.429 20-14.857 27.429l-207.429 202.286 49.143 285.714c0.571 4 0.571 7.429 0.571 11.429 0 14.857-6.857 28.571-23.429 28.571-8 0-16-2.857-22.857-6.857l-256.571-134.857-256.571 134.857c-7.429 4-14.857 6.857-22.857 6.857-16.571 0-24-13.714-24-28.571 0-4 0.571-7.429 1.143-11.429l49.143-285.714-208-202.286c-6.857-7.429-14.286-17.143-14.286-27.429 0-17.143 17.714-24 32-26.286l286.857-41.714 128.571-260c5.143-10.857 14.857-23.429 28-23.429s22.857 12.571 28 23.429l128.571 260 286.857 41.714c13.714 2.286 32 9.143 32 26.286z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["star"],"defaultCode":61445,"grid":14},"attrs":[],"properties":{"name":"star","id":19,"order":11,"prevSize":28,"code":61445},"setIdx":0,"setId":1,"iconIdx":30},{"icon":{"paths":["M649.714 573.714l174.857-169.714-241.143-35.429-108-218.286-108 218.286-241.143 35.429 174.857 169.714-41.714 240.571 216-113.714 215.429 113.714zM950.857 369.714c0 10.286-7.429 20-14.857 27.429l-207.429 202.286 49.143 285.714c0.571 4 0.571 7.429 0.571 11.429 0 15.429-6.857 28.571-23.429 28.571-8 0-16-2.857-22.857-6.857l-256.571-134.857-256.571 134.857c-7.429 4-14.857 6.857-22.857 6.857-16.571 0-24-13.714-24-28.571 0-4 0.571-7.429 1.143-11.429l49.143-285.714-208-202.286c-6.857-7.429-14.286-17.143-14.286-27.429 0-17.143 17.714-24 32-26.286l286.857-41.714 128.571-260c5.143-10.857 14.857-23.429 28-23.429s22.857 12.571 28 23.429l128.571 260 286.857 41.714c13.714 2.286 32 9.143 32 26.286z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["star-o"],"defaultCode":61446,"grid":14},"attrs":[],"properties":{"name":"star-o","id":20,"order":12,"prevSize":28,"code":61446},"setIdx":0,"setId":1,"iconIdx":31},{"icon":{"paths":["M731.429 799.429c0 83.429-54.857 151.429-121.714 151.429h-488c-66.857 0-121.714-68-121.714-151.429 0-150.286 37.143-324 186.857-324 46.286 45.143 109.143 73.143 178.857 73.143s132.571-28 178.857-73.143c149.714 0 186.857 173.714 186.857 324zM585.143 292.571c0 121.143-98.286 219.429-219.429 219.429s-219.429-98.286-219.429-219.429 98.286-219.429 219.429-219.429 219.429 98.286 219.429 219.429z"],"width":731.4285714285713,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["user"],"defaultCode":61447,"grid":14},"attrs":[],"properties":{"name":"user","id":21,"order":13,"prevSize":28,"code":61447},"setIdx":0,"setId":1,"iconIdx":32},{"icon":{"paths":["M219.429 914.286v-73.143c0-20-16.571-36.571-36.571-36.571h-73.143c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h73.143c20 0 36.571-16.571 36.571-36.571zM219.429 694.857v-73.143c0-20-16.571-36.571-36.571-36.571h-73.143c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h73.143c20 0 36.571-16.571 36.571-36.571zM219.429 475.429v-73.143c0-20-16.571-36.571-36.571-36.571h-73.143c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h73.143c20 0 36.571-16.571 36.571-36.571zM804.571 914.286v-292.571c0-20-16.571-36.571-36.571-36.571h-438.857c-20 0-36.571 16.571-36.571 36.571v292.571c0 20 16.571 36.571 36.571 36.571h438.857c20 0 36.571-16.571 36.571-36.571zM219.429 256v-73.143c0-20-16.571-36.571-36.571-36.571h-73.143c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h73.143c20 0 36.571-16.571 36.571-36.571zM1024 914.286v-73.143c0-20-16.571-36.571-36.571-36.571h-73.143c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h73.143c20 0 36.571-16.571 36.571-36.571zM804.571 475.429v-292.571c0-20-16.571-36.571-36.571-36.571h-438.857c-20 0-36.571 16.571-36.571 36.571v292.571c0 20 16.571 36.571 36.571 36.571h438.857c20 0 36.571-16.571 36.571-36.571zM1024 694.857v-73.143c0-20-16.571-36.571-36.571-36.571h-73.143c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h73.143c20 0 36.571-16.571 36.571-36.571zM1024 475.429v-73.143c0-20-16.571-36.571-36.571-36.571h-73.143c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h73.143c20 0 36.571-16.571 36.571-36.571zM1024 256v-73.143c0-20-16.571-36.571-36.571-36.571h-73.143c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h73.143c20 0 36.571-16.571 36.571-36.571zM1097.143 164.571v768c0 50.286-41.143 91.429-91.429 91.429h-914.286c-50.286 0-91.429-41.143-91.429-91.429v-768c0-50.286 41.143-91.429 91.429-91.429h914.286c50.286 0 91.429 41.143 91.429 91.429z"],"width":1097.142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["film"],"defaultCode":61448,"grid":14},"attrs":[],"properties":{"name":"film","id":22,"order":14,"prevSize":28,"code":61448},"setIdx":0,"setId":1,"iconIdx":33},{"icon":{"paths":["M438.857 585.143v219.429c0 40-33.143 73.143-73.143 73.143h-292.571c-40 0-73.143-33.143-73.143-73.143v-219.429c0-40 33.143-73.143 73.143-73.143h292.571c40 0 73.143 33.143 73.143 73.143zM438.857 146.286v219.429c0 40-33.143 73.143-73.143 73.143h-292.571c-40 0-73.143-33.143-73.143-73.143v-219.429c0-40 33.143-73.143 73.143-73.143h292.571c40 0 73.143 33.143 73.143 73.143zM950.857 585.143v219.429c0 40-33.143 73.143-73.143 73.143h-292.571c-40 0-73.143-33.143-73.143-73.143v-219.429c0-40 33.143-73.143 73.143-73.143h292.571c40 0 73.143 33.143 73.143 73.143zM950.857 146.286v219.429c0 40-33.143 73.143-73.143 73.143h-292.571c-40 0-73.143-33.143-73.143-73.143v-219.429c0-40 33.143-73.143 73.143-73.143h292.571c40 0 73.143 33.143 73.143 73.143z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["th-large"],"defaultCode":61449,"grid":14},"attrs":[],"properties":{"name":"th-large","id":23,"order":15,"prevSize":28,"code":61449},"setIdx":0,"setId":1,"iconIdx":34},{"icon":{"paths":["M292.571 713.143v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM292.571 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM658.286 713.143v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM292.571 128v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM658.286 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM1024 713.143v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM658.286 128v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM1024 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM1024 128v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["th"],"defaultCode":61450,"grid":14},"attrs":[],"properties":{"name":"th","id":24,"order":16,"prevSize":28,"code":61450},"setIdx":0,"setId":1,"iconIdx":35},{"icon":{"paths":["M292.571 713.143v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM292.571 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM1024 713.143v109.714c0 30.286-24.571 54.857-54.857 54.857h-548.571c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h548.571c30.286 0 54.857 24.571 54.857 54.857zM292.571 128v109.714c0 30.286-24.571 54.857-54.857 54.857h-182.857c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h182.857c30.286 0 54.857 24.571 54.857 54.857zM1024 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-548.571c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h548.571c30.286 0 54.857 24.571 54.857 54.857zM1024 128v109.714c0 30.286-24.571 54.857-54.857 54.857h-548.571c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h548.571c30.286 0 54.857 24.571 54.857 54.857z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["th-list"],"defaultCode":61451,"grid":14},"attrs":[],"properties":{"name":"th-list","id":25,"order":17,"prevSize":28,"code":61451},"setIdx":0,"setId":1,"iconIdx":36},{"icon":{"paths":["M725.322 782.343c3.477 3.448 6.237 7.547 8.118 12.069 1.885 4.515 2.853 9.364 2.853 14.259s-0.967 9.744-2.853 14.266c-1.881 4.515-4.641 8.623-8.118 12.069-3.448 3.472-7.547 6.232-12.069 8.118-4.515 1.881-9.364 2.848-14.259 2.848s-9.744-0.967-14.266-2.848c-4.522-1.885-8.623-4.646-12.069-8.118l-270.371-270.375-270.372 270.375c-3.448 3.472-7.549 6.232-12.069 8.118-4.519 1.881-9.366 2.848-14.263 2.848s-9.744-0.967-14.263-2.848c-4.519-1.885-8.622-4.646-12.069-8.118-3.474-3.448-6.235-7.555-8.118-12.069-1.884-4.522-2.853-9.37-2.853-14.266s0.97-9.744 2.853-14.259c1.884-4.522 4.643-8.623 8.118-12.069l270.372-270.375-270.372-270.372c-3.456-3.456-6.201-7.565-8.072-12.082s-2.835-9.36-2.835-14.25c0-4.891 0.964-9.732 2.835-14.25s4.617-8.626 8.072-12.081c3.456-3.456 7.564-6.201 12.081-8.072s9.361-2.835 14.25-2.835c4.891 0 9.732 0.964 14.25 2.835s8.626 4.617 12.081 8.072l270.372 270.372 270.371-270.372c6.984-6.983 16.455-10.909 26.335-10.909 9.875 0 19.347 3.923 26.33 10.909s10.909 16.456 10.909 26.333c0 9.877-3.923 19.348-10.909 26.333l-270.371 270.372 270.371 270.375z"],"width":804.5714285714286,"attrs":[{}],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[{}],"12714014111291321":[{}]},"tags":["close","remove","times"],"defaultCode":61453,"grid":14},"attrs":[{}],"properties":{"name":"close, remove, times","id":26,"order":19,"prevSize":28,"code":61453},"setIdx":0,"setId":1,"iconIdx":37},{"icon":{"paths":["M585.143 457.143v36.571c0 9.714-8.571 18.286-18.286 18.286h-128v128c0 9.714-8.571 18.286-18.286 18.286h-36.571c-9.714 0-18.286-8.571-18.286-18.286v-128h-128c-9.714 0-18.286-8.571-18.286-18.286v-36.571c0-9.714 8.571-18.286 18.286-18.286h128v-128c0-9.714 8.571-18.286 18.286-18.286h36.571c9.714 0 18.286 8.571 18.286 18.286v128h128c9.714 0 18.286 8.571 18.286 18.286zM658.286 475.429c0-141.143-114.857-256-256-256s-256 114.857-256 256 114.857 256 256 256 256-114.857 256-256zM950.857 950.857c0 40.571-32.571 73.143-73.143 73.143-19.429 0-38.286-8-51.429-21.714l-196-195.429c-66.857 46.286-146.857 70.857-228 70.857-222.286 0-402.286-180-402.286-402.286s180-402.286 402.286-402.286 402.286 180 402.286 402.286c0 81.143-24.571 161.143-70.857 228l196 196c13.143 13.143 21.143 32 21.143 51.429z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["search-plus"],"defaultCode":61454,"grid":14},"attrs":[],"properties":{"name":"search-plus","id":27,"order":20,"prevSize":28,"code":61454},"setIdx":0,"setId":1,"iconIdx":38},{"icon":{"paths":["M585.143 457.143v36.571c0 9.714-8.571 18.286-18.286 18.286h-329.143c-9.714 0-18.286-8.571-18.286-18.286v-36.571c0-9.714 8.571-18.286 18.286-18.286h329.143c9.714 0 18.286 8.571 18.286 18.286zM658.286 475.429c0-141.143-114.857-256-256-256s-256 114.857-256 256 114.857 256 256 256 256-114.857 256-256zM950.857 950.857c0 40.571-32.571 73.143-73.143 73.143-19.429 0-38.286-8-51.429-21.714l-196-195.429c-66.857 46.286-146.857 70.857-228 70.857-222.286 0-402.286-180-402.286-402.286s180-402.286 402.286-402.286 402.286 180 402.286 402.286c0 81.143-24.571 161.143-70.857 228l196 196c13.143 13.143 21.143 32 21.143 51.429z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["search-minus"],"defaultCode":61456,"grid":14},"attrs":[],"properties":{"name":"search-minus","id":28,"order":21,"prevSize":28,"code":61456},"setIdx":0,"setId":1,"iconIdx":39},{"icon":{"paths":["M877.714 512c0 241.714-197.143 438.857-438.857 438.857s-438.857-197.143-438.857-438.857c0-138.857 64-266.857 175.429-350.286 32.571-24.571 78.286-18.286 102.286 14.286 24.571 32 17.714 78.286-14.286 102.286-74.286 56-117.143 141.143-117.143 233.714 0 161.143 131.429 292.571 292.571 292.571s292.571-131.429 292.571-292.571c0-92.571-42.857-177.714-117.143-233.714-32-24-38.857-70.286-14.286-102.286 24-32.571 70.286-38.857 102.286-14.286 111.429 83.429 175.429 211.429 175.429 350.286zM512 73.143v365.714c0 40-33.143 73.143-73.143 73.143s-73.143-33.143-73.143-73.143v-365.714c0-40 33.143-73.143 73.143-73.143s73.143 33.143 73.143 73.143z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["power-off"],"defaultCode":61457,"grid":14},"attrs":[],"properties":{"name":"power-off","id":29,"order":22,"prevSize":28,"code":61457},"setIdx":0,"setId":1,"iconIdx":40},{"icon":{"paths":["M146.286 822.857v109.714c0 10.286-8 18.286-18.286 18.286h-109.714c-10.286 0-18.286-8-18.286-18.286v-109.714c0-10.286 8-18.286 18.286-18.286h109.714c10.286 0 18.286 8 18.286 18.286zM365.714 749.714v182.857c0 10.286-8 18.286-18.286 18.286h-109.714c-10.286 0-18.286-8-18.286-18.286v-182.857c0-10.286 8-18.286 18.286-18.286h109.714c10.286 0 18.286 8 18.286 18.286zM585.143 603.429v329.143c0 10.286-8 18.286-18.286 18.286h-109.714c-10.286 0-18.286-8-18.286-18.286v-329.143c0-10.286 8-18.286 18.286-18.286h109.714c10.286 0 18.286 8 18.286 18.286zM804.571 384v548.571c0 10.286-8 18.286-18.286 18.286h-109.714c-10.286 0-18.286-8-18.286-18.286v-548.571c0-10.286 8-18.286 18.286-18.286h109.714c10.286 0 18.286 8 18.286 18.286zM1024 91.429v841.143c0 10.286-8 18.286-18.286 18.286h-109.714c-10.286 0-18.286-8-18.286-18.286v-841.143c0-10.286 8-18.286 18.286-18.286h109.714c10.286 0 18.286 8 18.286 18.286z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["signal"],"defaultCode":61458,"grid":14},"attrs":[],"properties":{"name":"signal","id":30,"order":23,"prevSize":28,"code":61458},"setIdx":0,"setId":1,"iconIdx":41},{"icon":{"paths":["M585.143 512c0-80.571-65.714-146.286-146.286-146.286s-146.286 65.714-146.286 146.286 65.714 146.286 146.286 146.286 146.286-65.714 146.286-146.286zM877.714 449.714v126.857c0 8.571-6.857 18.857-16 20.571l-105.714 16c-6.286 18.286-13.143 35.429-22.286 52 19.429 28 40 53.143 61.143 78.857 3.429 4 5.714 9.143 5.714 14.286s-1.714 9.143-5.143 13.143c-13.714 18.286-90.857 102.286-110.286 102.286-5.143 0-10.286-2.286-14.857-5.143l-78.857-61.714c-16.571 8.571-34.286 16-52 21.714-4 34.857-7.429 72-16.571 106.286-2.286 9.143-10.286 16-20.571 16h-126.857c-10.286 0-19.429-7.429-20.571-17.143l-16-105.143c-17.714-5.714-34.857-12.571-51.429-21.143l-80.571 61.143c-4 3.429-9.143 5.143-14.286 5.143s-10.286-2.286-14.286-6.286c-30.286-27.429-70.286-62.857-94.286-96-2.857-4-4-8.571-4-13.143 0-5.143 1.714-9.143 4.571-13.143 19.429-26.286 40.571-51.429 60-78.286-9.714-18.286-17.714-37.143-23.429-56.571l-104.571-15.429c-9.714-1.714-16.571-10.857-16.571-20.571v-126.857c0-8.571 6.857-18.857 15.429-20.571l106.286-16c5.714-18.286 13.143-35.429 22.286-52.571-19.429-27.429-40-53.143-61.143-78.857-3.429-4-5.714-8.571-5.714-13.714s2.286-9.143 5.143-13.143c13.714-18.857 90.857-102.286 110.286-102.286 5.143 0 10.286 2.286 14.857 5.714l78.857 61.143c16.571-8.571 34.286-16 52-21.714 4-34.857 7.429-72 16.571-106.286 2.286-9.143 10.286-16 20.571-16h126.857c10.286 0 19.429 7.429 20.571 17.143l16 105.143c17.714 5.714 34.857 12.571 51.429 21.143l81.143-61.143c3.429-3.429 8.571-5.143 13.714-5.143s10.286 2.286 14.286 5.714c30.286 28 70.286 63.429 94.286 97.143 2.857 3.429 4 8 4 12.571 0 5.143-1.714 9.143-4.571 13.143-19.429 26.286-40.571 51.429-60 78.286 9.714 18.286 17.714 37.143 23.429 56l104.571 16c9.714 1.714 16.571 10.857 16.571 20.571z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["cog","gear"],"defaultCode":61459,"grid":14},"attrs":[],"properties":{"name":"cog, gear","id":31,"order":24,"prevSize":28,"code":61459},"setIdx":0,"setId":1,"iconIdx":42},{"icon":{"paths":["M292.571 420.571v329.143c0 10.286-8 18.286-18.286 18.286h-36.571c-10.286 0-18.286-8-18.286-18.286v-329.143c0-10.286 8-18.286 18.286-18.286h36.571c10.286 0 18.286 8 18.286 18.286zM438.857 420.571v329.143c0 10.286-8 18.286-18.286 18.286h-36.571c-10.286 0-18.286-8-18.286-18.286v-329.143c0-10.286 8-18.286 18.286-18.286h36.571c10.286 0 18.286 8 18.286 18.286zM585.143 420.571v329.143c0 10.286-8 18.286-18.286 18.286h-36.571c-10.286 0-18.286-8-18.286-18.286v-329.143c0-10.286 8-18.286 18.286-18.286h36.571c10.286 0 18.286 8 18.286 18.286zM658.286 834.286v-541.714h-512v541.714c0 27.429 15.429 43.429 18.286 43.429h475.429c2.857 0 18.286-16 18.286-43.429zM274.286 219.429h256l-27.429-66.857c-1.714-2.286-6.857-5.714-9.714-6.286h-181.143c-3.429 0.571-8 4-9.714 6.286zM804.571 237.714v36.571c0 10.286-8 18.286-18.286 18.286h-54.857v541.714c0 62.857-41.143 116.571-91.429 116.571h-475.429c-50.286 0-91.429-51.429-91.429-114.286v-544h-54.857c-10.286 0-18.286-8-18.286-18.286v-36.571c0-10.286 8-18.286 18.286-18.286h176.571l40-95.429c11.429-28 45.714-50.857 76-50.857h182.857c30.286 0 64.571 22.857 76 50.857l40 95.429h176.571c10.286 0 18.286 8 18.286 18.286z"],"width":804.5714285714286,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["trash-o"],"defaultCode":61460,"grid":14},"attrs":[],"properties":{"name":"trash-o","id":32,"order":25,"prevSize":28,"code":61460},"setIdx":0,"setId":1,"iconIdx":43},{"icon":{"paths":["M804.571 566.857v274.286c0 20-16.571 36.571-36.571 36.571h-219.429v-219.429h-146.286v219.429h-219.429c-20 0-36.571-16.571-36.571-36.571v-274.286c0-1.143 0.571-2.286 0.571-3.429l328.571-270.857 328.571 270.857c0.571 1.143 0.571 2.286 0.571 3.429zM932 527.429l-35.429 42.286c-2.857 3.429-7.429 5.714-12 6.286h-1.714c-4.571 0-8.571-1.143-12-4l-395.429-329.714-395.429 329.714c-4 2.857-8.571 4.571-13.714 4-4.571-0.571-9.143-2.857-12-6.286l-35.429-42.286c-6.286-7.429-5.143-19.429 2.286-25.714l410.857-342.286c24-20 62.857-20 86.857 0l139.429 116.571v-111.429c0-10.286 8-18.286 18.286-18.286h109.714c10.286 0 18.286 8 18.286 18.286v233.143l125.143 104c7.429 6.286 8.571 18.286 2.286 25.714z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["home"],"defaultCode":61461,"grid":14},"attrs":[],"properties":{"name":"home","id":33,"order":26,"prevSize":28,"code":61461},"setIdx":0,"setId":1,"iconIdx":44},{"icon":{"paths":["M838.857 217.143c21.143 21.143 38.857 63.429 38.857 93.714v658.286c0 30.286-24.571 54.857-54.857 54.857h-768c-30.286 0-54.857-24.571-54.857-54.857v-914.286c0-30.286 24.571-54.857 54.857-54.857h512c30.286 0 72.571 17.714 93.714 38.857zM585.143 77.714v214.857h214.857c-3.429-9.714-8.571-19.429-12.571-23.429l-178.857-178.857c-4-4-13.714-9.143-23.429-12.571zM804.571 950.857v-585.143h-237.714c-30.286 0-54.857-24.571-54.857-54.857v-237.714h-438.857v877.714h731.429z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["file-o"],"defaultCode":61462,"grid":14},"attrs":[],"properties":{"name":"file-o","id":34,"order":27,"prevSize":28,"code":61462},"setIdx":0,"setId":1,"iconIdx":45},{"icon":{"paths":["M512 310.857v256c0 10.286-8 18.286-18.286 18.286h-182.857c-10.286 0-18.286-8-18.286-18.286v-36.571c0-10.286 8-18.286 18.286-18.286h128v-201.143c0-10.286 8-18.286 18.286-18.286h36.571c10.286 0 18.286 8 18.286 18.286zM749.714 512c0-171.429-139.429-310.857-310.857-310.857s-310.857 139.429-310.857 310.857 139.429 310.857 310.857 310.857 310.857-139.429 310.857-310.857zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["clock-o"],"defaultCode":61463,"grid":14},"attrs":[],"properties":{"name":"clock-o","id":35,"order":28,"prevSize":28,"code":61463},"setIdx":0,"setId":1,"iconIdx":46},{"icon":{"paths":["M731.429 768c0-20-16.571-36.571-36.571-36.571s-36.571 16.571-36.571 36.571 16.571 36.571 36.571 36.571 36.571-16.571 36.571-36.571zM877.714 768c0-20-16.571-36.571-36.571-36.571s-36.571 16.571-36.571 36.571 16.571 36.571 36.571 36.571 36.571-16.571 36.571-36.571zM950.857 640v182.857c0 30.286-24.571 54.857-54.857 54.857h-841.143c-30.286 0-54.857-24.571-54.857-54.857v-182.857c0-30.286 24.571-54.857 54.857-54.857h265.714l77.143 77.714c21.143 20.571 48.571 32 77.714 32s56.571-11.429 77.714-32l77.714-77.714h265.143c30.286 0 54.857 24.571 54.857 54.857zM765.143 314.857c5.714 13.714 2.857 29.714-8 40l-256 256c-6.857 7.429-16.571 10.857-25.714 10.857s-18.857-3.429-25.714-10.857l-256-256c-10.857-10.286-13.714-26.286-8-40 5.714-13.143 18.857-22.286 33.714-22.286h146.286v-256c0-20 16.571-36.571 36.571-36.571h146.286c20 0 36.571 16.571 36.571 36.571v256h146.286c14.857 0 28 9.143 33.714 22.286z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["download"],"defaultCode":61465,"grid":14},"attrs":[],"properties":{"name":"download","id":36,"order":30,"prevSize":28,"code":61465},"setIdx":0,"setId":1,"iconIdx":47},{"icon":{"paths":["M640 530.286c0 5.143-2.286 9.714-5.714 13.714l-182.286 182.286c-4 3.429-8.571 5.143-13.143 5.143s-9.143-1.714-13.143-5.143l-182.857-182.857c-5.143-5.714-6.857-13.143-4-20s9.714-11.429 17.143-11.429h109.714v-201.143c0-10.286 8-18.286 18.286-18.286h109.714c10.286 0 18.286 8 18.286 18.286v201.143h109.714c10.286 0 18.286 8 18.286 18.286zM438.857 201.143c-171.429 0-310.857 139.429-310.857 310.857s139.429 310.857 310.857 310.857 310.857-139.429 310.857-310.857-139.429-310.857-310.857-310.857zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857v0c242.286 0 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["arrow-circle-o-down"],"defaultCode":61466,"grid":14},"attrs":[],"properties":{"name":"arrow-circle-o-down","id":37,"order":31,"prevSize":28,"code":61466},"setIdx":0,"setId":1,"iconIdx":48},{"icon":{"paths":["M638.857 500.571c-2.857 6.857-9.714 11.429-17.143 11.429h-109.714v201.143c0 10.286-8 18.286-18.286 18.286h-109.714c-10.286 0-18.286-8-18.286-18.286v-201.143h-109.714c-10.286 0-18.286-8-18.286-18.286 0-5.143 2.286-9.714 5.714-13.714l182.286-182.286c4-3.429 8.571-5.143 13.143-5.143s9.143 1.714 13.143 5.143l182.857 182.857c5.143 5.714 6.857 13.143 4 20zM438.857 201.143c-171.429 0-310.857 139.429-310.857 310.857s139.429 310.857 310.857 310.857 310.857-139.429 310.857-310.857-139.429-310.857-310.857-310.857zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857v0c242.286 0 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["arrow-circle-o-up"],"defaultCode":61467,"grid":14},"attrs":[],"properties":{"name":"arrow-circle-o-up","id":38,"order":32,"prevSize":28,"code":61467},"setIdx":0,"setId":1,"iconIdx":49},{"icon":{"paths":["M584.571 548.571h180.571c-1.143-2.857-1.714-6.286-2.857-9.143l-121.143-283.429h-404.571l-121.143 283.429c-1.143 2.857-1.714 6.286-2.857 9.143h180.571l54.286 109.714h182.857zM877.714 565.714v275.429c0 20-16.571 36.571-36.571 36.571h-804.571c-20 0-36.571-16.571-36.571-36.571v-275.429c0-20.571 6.286-50.857 14.286-70.286l136-315.429c8-18.857 30.857-33.714 50.857-33.714h475.429c20 0 42.857 14.857 50.857 33.714l136 315.429c8 19.429 14.286 49.714 14.286 70.286z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["inbox"],"defaultCode":61468,"grid":14},"attrs":[],"properties":{"name":"inbox","id":39,"order":33,"prevSize":28,"code":61468},"setIdx":0,"setId":1,"iconIdx":50},{"icon":{"paths":["M676.571 512c0 13.143-6.857 25.143-18.286 31.429l-310.857 182.857c-5.714 3.429-12 5.143-18.286 5.143s-12.571-1.714-18.286-4.571c-11.429-6.857-18.286-18.857-18.286-32v-365.714c0-13.143 6.857-25.143 18.286-32 11.429-6.286 25.714-6.286 36.571 0.571l310.857 182.857c11.429 6.286 18.286 18.286 18.286 31.429zM749.714 512c0-171.429-139.429-310.857-310.857-310.857s-310.857 139.429-310.857 310.857 139.429 310.857 310.857 310.857 310.857-139.429 310.857-310.857zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["play-circle-o"],"defaultCode":61469,"grid":14},"attrs":[],"properties":{"name":"play-circle-o","id":40,"order":34,"prevSize":28,"code":61469},"setIdx":0,"setId":1,"iconIdx":51},{"icon":{"paths":["M877.714 146.286v256c0 20-16.571 36.571-36.571 36.571h-256c-14.857 0-28-9.143-33.714-22.857-5.714-13.143-2.857-29.143 8-39.429l78.857-78.857c-53.714-49.714-124.571-78.286-199.429-78.286-161.143 0-292.571 131.429-292.571 292.571s131.429 292.571 292.571 292.571c90.857 0 174.857-41.143 230.857-113.714 2.857-4 8-6.286 13.143-6.857 5.143 0 10.286 1.714 14.286 5.143l78.286 78.857c6.857 6.286 6.857 17.143 1.143 24.571-83.429 100.571-206.857 158.286-337.714 158.286-241.714 0-438.857-197.143-438.857-438.857s197.143-438.857 438.857-438.857c112.571 0 221.714 45.143 302.286 121.143l74.286-73.714c10.286-10.857 26.286-13.714 40-8 13.143 5.714 22.286 18.857 22.286 33.714z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["repeat","rotate-right"],"defaultCode":61470,"grid":14},"attrs":[],"properties":{"name":"repeat, rotate-right","id":41,"order":35,"prevSize":28,"code":61470},"setIdx":0,"setId":1,"iconIdx":52},{"icon":{"paths":["M863.429 603.429c0 1.143 0 2.857-0.571 4-48.571 202.286-215.429 343.429-426.286 343.429-111.429 0-219.429-44-300.571-121.143l-73.714 73.714c-6.857 6.857-16 10.857-25.714 10.857-20 0-36.571-16.571-36.571-36.571v-256c0-20 16.571-36.571 36.571-36.571h256c20 0 36.571 16.571 36.571 36.571 0 9.714-4 18.857-10.857 25.714l-78.286 78.286c53.714 50.286 125.143 78.857 198.857 78.857 101.714 0 196-52.571 249.143-139.429 13.714-22.286 20.571-44 30.286-66.857 2.857-8 8.571-13.143 17.143-13.143h109.714c10.286 0 18.286 8.571 18.286 18.286zM877.714 146.286v256c0 20-16.571 36.571-36.571 36.571h-256c-20 0-36.571-16.571-36.571-36.571 0-9.714 4-18.857 10.857-25.714l78.857-78.857c-54.286-50.286-125.714-78.286-199.429-78.286-101.714 0-196 52.571-249.143 139.429-13.714 22.286-20.571 44-30.286 66.857-2.857 8-8.571 13.143-17.143 13.143h-113.714c-10.286 0-18.286-8.571-18.286-18.286v-4c49.143-202.857 217.714-343.429 428.571-343.429 112 0 221.143 44.571 302.286 121.143l74.286-73.714c6.857-6.857 16-10.857 25.714-10.857 20 0 36.571 16.571 36.571 36.571z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["refresh"],"defaultCode":61473,"grid":14},"attrs":[],"properties":{"name":"refresh","id":42,"order":36,"prevSize":28,"code":61473},"setIdx":0,"setId":1,"iconIdx":53},{"icon":{"paths":["M219.429 676.571v36.571c0 9.714-8.571 18.286-18.286 18.286h-36.571c-9.714 0-18.286-8.571-18.286-18.286v-36.571c0-9.714 8.571-18.286 18.286-18.286h36.571c9.714 0 18.286 8.571 18.286 18.286zM219.429 530.286v36.571c0 9.714-8.571 18.286-18.286 18.286h-36.571c-9.714 0-18.286-8.571-18.286-18.286v-36.571c0-9.714 8.571-18.286 18.286-18.286h36.571c9.714 0 18.286 8.571 18.286 18.286zM219.429 384v36.571c0 9.714-8.571 18.286-18.286 18.286h-36.571c-9.714 0-18.286-8.571-18.286-18.286v-36.571c0-9.714 8.571-18.286 18.286-18.286h36.571c9.714 0 18.286 8.571 18.286 18.286zM877.714 676.571v36.571c0 9.714-8.571 18.286-18.286 18.286h-548.571c-9.714 0-18.286-8.571-18.286-18.286v-36.571c0-9.714 8.571-18.286 18.286-18.286h548.571c9.714 0 18.286 8.571 18.286 18.286zM877.714 530.286v36.571c0 9.714-8.571 18.286-18.286 18.286h-548.571c-9.714 0-18.286-8.571-18.286-18.286v-36.571c0-9.714 8.571-18.286 18.286-18.286h548.571c9.714 0 18.286 8.571 18.286 18.286zM877.714 384v36.571c0 9.714-8.571 18.286-18.286 18.286h-548.571c-9.714 0-18.286-8.571-18.286-18.286v-36.571c0-9.714 8.571-18.286 18.286-18.286h548.571c9.714 0 18.286 8.571 18.286 18.286zM950.857 786.286v-475.429c0-9.714-8.571-18.286-18.286-18.286h-841.143c-9.714 0-18.286 8.571-18.286 18.286v475.429c0 9.714 8.571 18.286 18.286 18.286h841.143c9.714 0 18.286-8.571 18.286-18.286zM1024 164.571v621.714c0 50.286-41.143 91.429-91.429 91.429h-841.143c-50.286 0-91.429-41.143-91.429-91.429v-621.714c0-50.286 41.143-91.429 91.429-91.429h841.143c50.286 0 91.429 41.143 91.429 91.429z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["list-alt"],"defaultCode":61474,"grid":14},"attrs":[],"properties":{"name":"list-alt","id":43,"order":37,"prevSize":28,"code":61474},"setIdx":0,"setId":1,"iconIdx":54},{"icon":{"paths":["M182.857 438.857h292.571v-109.714c0-80.571-65.714-146.286-146.286-146.286s-146.286 65.714-146.286 146.286v109.714zM658.286 493.714v329.143c0 30.286-24.571 54.857-54.857 54.857h-548.571c-30.286 0-54.857-24.571-54.857-54.857v-329.143c0-30.286 24.571-54.857 54.857-54.857h18.286v-109.714c0-140.571 115.429-256 256-256s256 115.429 256 256v109.714h18.286c30.286 0 54.857 24.571 54.857 54.857z"],"width":658.2857142857142,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["lock"],"defaultCode":61475,"grid":14},"attrs":[],"properties":{"name":"lock","id":44,"order":38,"prevSize":28,"code":61475},"setIdx":0,"setId":1,"iconIdx":55},{"icon":{"paths":["M438.857 201.143v621.714c0 20-16.571 36.571-36.571 36.571-9.714 0-18.857-4-25.714-10.857l-190.286-190.286h-149.714c-20 0-36.571-16.571-36.571-36.571v-219.429c0-20 16.571-36.571 36.571-36.571h149.714l190.286-190.286c6.857-6.857 16-10.857 25.714-10.857 20 0 36.571 16.571 36.571 36.571z"],"width":438.85714285714283,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["volume-off"],"defaultCode":61478,"grid":14},"attrs":[],"properties":{"name":"volume-off","id":45,"order":41,"prevSize":28,"code":61478},"setIdx":0,"setId":1,"iconIdx":56},{"icon":{"paths":["M438.857 201.143v621.714c0 20-16.571 36.571-36.571 36.571-9.714 0-18.857-4-25.714-10.857l-190.286-190.286h-149.714c-20 0-36.571-16.571-36.571-36.571v-219.429c0-20 16.571-36.571 36.571-36.571h149.714l190.286-190.286c6.857-6.857 16-10.857 25.714-10.857 20 0 36.571 16.571 36.571 36.571zM658.286 512c0 57.143-34.857 112.571-88.571 134.286-4.571 2.286-9.714 2.857-14.286 2.857-20 0-36.571-16-36.571-36.571 0-43.429 66.286-31.429 66.286-100.571s-66.286-57.143-66.286-100.571c0-20.571 16.571-36.571 36.571-36.571 4.571 0 9.714 0.571 14.286 2.857 53.714 21.143 88.571 77.143 88.571 134.286z"],"width":658.2857142857142,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["volume-down"],"defaultCode":61479,"grid":14},"attrs":[],"properties":{"name":"volume-down","id":46,"order":42,"prevSize":28,"code":61479},"setIdx":0,"setId":1,"iconIdx":57},{"icon":{"paths":["M438.857 201.143v621.714c0 20-16.571 36.571-36.571 36.571-9.714 0-18.857-4-25.714-10.857l-190.286-190.286h-149.714c-20 0-36.571-16.571-36.571-36.571v-219.429c0-20 16.571-36.571 36.571-36.571h149.714l190.286-190.286c6.857-6.857 16-10.857 25.714-10.857 20 0 36.571 16.571 36.571 36.571zM658.286 512c0 57.143-34.857 112.571-88.571 134.286-4.571 2.286-9.714 2.857-14.286 2.857-20 0-36.571-16-36.571-36.571 0-43.429 66.286-31.429 66.286-100.571s-66.286-57.143-66.286-100.571c0-20.571 16.571-36.571 36.571-36.571 4.571 0 9.714 0.571 14.286 2.857 53.714 21.143 88.571 77.143 88.571 134.286zM804.571 512c0 116-69.714 224-177.143 269.143-4.571 1.714-9.714 2.857-14.286 2.857-20.571 0-37.143-16.571-37.143-36.571 0-16 9.143-26.857 22.286-33.714 15.429-8 29.714-14.857 43.429-25.143 56.571-41.143 89.714-106.857 89.714-176.571s-33.143-135.429-89.714-176.571c-13.714-10.286-28-17.143-43.429-25.143-13.143-6.857-22.286-17.714-22.286-33.714 0-20 16.571-36.571 36.571-36.571 5.143 0 10.286 1.143 14.857 2.857 107.429 45.143 177.143 153.143 177.143 269.143zM950.857 512c0 175.429-104.571 334.286-265.714 403.429-4.571 1.714-9.714 2.857-14.857 2.857-20 0-36.571-16.571-36.571-36.571 0-16.571 8.571-25.714 22.286-33.714 8-4.571 17.143-7.429 25.714-12 16-8.571 32-18.286 46.857-29.143 93.714-69.143 149.143-178.286 149.143-294.857s-55.429-225.714-149.143-294.857c-14.857-10.857-30.857-20.571-46.857-29.143-8.571-4.571-17.714-7.429-25.714-12-13.714-8-22.286-17.143-22.286-33.714 0-20 16.571-36.571 36.571-36.571 5.143 0 10.286 1.143 14.857 2.857 161.143 69.143 265.714 228 265.714 403.429z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["volume-up"],"defaultCode":61480,"grid":14},"attrs":[],"properties":{"name":"volume-up","id":47,"order":43,"prevSize":28,"code":61480},"setIdx":0,"setId":1,"iconIdx":58},{"icon":{"paths":["M219.429 658.286v73.143h-73.143v-73.143h73.143zM219.429 219.429v73.143h-73.143v-73.143h73.143zM658.286 219.429v73.143h-73.143v-73.143h73.143zM73.143 804h219.429v-218.857h-219.429v218.857zM73.143 365.714h219.429v-219.429h-219.429v219.429zM512 365.714h219.429v-219.429h-219.429v219.429zM365.714 512v365.714h-365.714v-365.714h365.714zM658.286 804.571v73.143h-73.143v-73.143h73.143zM804.571 804.571v73.143h-73.143v-73.143h73.143zM804.571 512v219.429h-219.429v-73.143h-73.143v219.429h-73.143v-365.714h219.429v73.143h73.143v-73.143h73.143zM365.714 73.143v365.714h-365.714v-365.714h365.714zM804.571 73.143v365.714h-365.714v-365.714h365.714z"],"width":804.5714285714286,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["qrcode"],"defaultCode":61481,"grid":14},"attrs":[],"properties":{"name":"qrcode","id":48,"order":44,"prevSize":28,"code":61481},"setIdx":0,"setId":1,"iconIdx":59},{"icon":{"paths":["M256 256c0-40.571-32.571-73.143-73.143-73.143s-73.143 32.571-73.143 73.143 32.571 73.143 73.143 73.143 73.143-32.571 73.143-73.143zM865.714 585.143c0 19.429-8 38.286-21.143 51.429l-280.571 281.143c-13.714 13.143-32.571 21.143-52 21.143s-38.286-8-51.429-21.143l-408.571-409.143c-29.143-28.571-52-84-52-124.571v-237.714c0-40 33.143-73.143 73.143-73.143h237.714c40.571 0 96 22.857 125.143 52l408.571 408c13.143 13.714 21.143 32.571 21.143 52z"],"width":865.7188571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["tag"],"defaultCode":61483,"grid":14},"attrs":[],"properties":{"name":"tag","id":49,"order":46,"prevSize":28,"code":61483},"setIdx":0,"setId":1,"iconIdx":60},{"icon":{"paths":["M256 256c0-40.571-32.571-73.143-73.143-73.143s-73.143 32.571-73.143 73.143 32.571 73.143 73.143 73.143 73.143-32.571 73.143-73.143zM865.714 585.143c0 19.429-8 38.286-21.143 51.429l-280.571 281.143c-13.714 13.143-32.571 21.143-52 21.143s-38.286-8-51.429-21.143l-408.571-409.143c-29.143-28.571-52-84-52-124.571v-237.714c0-40 33.143-73.143 73.143-73.143h237.714c40.571 0 96 22.857 125.143 52l408.571 408c13.143 13.714 21.143 32.571 21.143 52zM1085.143 585.143c0 19.429-8 38.286-21.143 51.429l-280.571 281.143c-13.714 13.143-32.571 21.143-52 21.143-29.714 0-44.571-13.714-64-33.714l268.571-268.571c13.143-13.143 21.143-32 21.143-51.429s-8-38.286-21.143-52l-408.571-408c-29.143-29.143-84.571-52-125.143-52h128c40.571 0 96 22.857 125.143 52l408.571 408c13.143 13.714 21.143 32.571 21.143 52z"],"width":1085.1474285714285,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["tags"],"defaultCode":61484,"grid":14},"attrs":[],"properties":{"name":"tags","id":50,"order":47,"prevSize":28,"code":61484},"setIdx":0,"setId":1,"iconIdx":61},{"icon":{"paths":["M936.571 273.143c14.286 20.571 18.286 47.429 10.286 73.714l-157.143 517.714c-14.286 48.571-64.571 86.286-113.714 86.286h-527.429c-58.286 0-120.571-46.286-141.714-105.714-9.143-25.714-9.143-50.857-1.143-72.571 1.143-11.429 3.429-22.857 4-36.571 0.571-9.143-4.571-16.571-3.429-23.429 2.286-13.714 14.286-23.429 23.429-38.857 17.143-28.571 36.571-74.857 42.857-104.571 2.857-10.857-2.857-23.429 0-33.143 2.857-10.857 13.714-18.857 19.429-29.143 15.429-26.286 35.429-77.143 38.286-104 1.143-12-4.571-25.143-1.143-34.286 4-13.143 16.571-18.857 25.143-30.286 13.714-18.857 36.571-73.143 40-103.429 1.143-9.714-4.571-19.429-2.857-29.714 2.286-10.857 16-22.286 25.143-35.429 24-35.429 28.571-113.714 101.143-93.143l-0.571 1.714c9.714-2.286 19.429-5.143 29.143-5.143h434.857c26.857 0 50.857 12 65.143 32 14.857 20.571 18.286 47.429 10.286 74.286l-156.571 517.714c-26.857 88-41.714 107.429-114.286 107.429h-496.571c-7.429 0-16.571 1.714-21.714 8.571-4.571 6.857-5.143 12-0.571 24.571 11.429 33.143 50.857 40 82.286 40h527.429c21.143 0 45.714-12 52-32.571l171.429-564c3.429-10.857 3.429-22.286 2.857-32.571 13.143 5.143 25.143 13.143 33.714 24.571zM328.571 274.286c-3.429 10.286 2.286 18.286 12.571 18.286h347.429c9.714 0 20.571-8 24-18.286l12-36.571c3.429-10.286-2.286-18.286-12.571-18.286h-347.429c-9.714 0-20.571 8-24 18.286zM281.143 420.571c-3.429 10.286 2.286 18.286 12.571 18.286h347.429c9.714 0 20.571-8 24-18.286l12-36.571c3.429-10.286-2.286-18.286-12.571-18.286h-347.429c-9.714 0-20.571 8-24 18.286z"],"width":952.5394285714285,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["book"],"defaultCode":61485,"grid":14},"attrs":[],"properties":{"name":"book","id":51,"order":48,"prevSize":28,"code":61485},"setIdx":0,"setId":1,"iconIdx":62},{"icon":{"paths":["M219.429 877.714h512v-146.286h-512v146.286zM219.429 512h512v-219.429h-91.429c-30.286 0-54.857-24.571-54.857-54.857v-91.429h-365.714v365.714zM877.714 548.571c0-20-16.571-36.571-36.571-36.571s-36.571 16.571-36.571 36.571 16.571 36.571 36.571 36.571 36.571-16.571 36.571-36.571zM950.857 548.571v237.714c0 9.714-8.571 18.286-18.286 18.286h-128v91.429c0 30.286-24.571 54.857-54.857 54.857h-548.571c-30.286 0-54.857-24.571-54.857-54.857v-91.429h-128c-9.714 0-18.286-8.571-18.286-18.286v-237.714c0-60 49.714-109.714 109.714-109.714h36.571v-310.857c0-30.286 24.571-54.857 54.857-54.857h384c30.286 0 72 17.143 93.714 38.857l86.857 86.857c21.714 21.714 38.857 63.429 38.857 93.714v146.286h36.571c60 0 109.714 49.714 109.714 109.714z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["print"],"defaultCode":61487,"grid":14},"attrs":[],"properties":{"name":"print","id":52,"order":50,"prevSize":28,"code":61487},"setIdx":0,"setId":1,"iconIdx":63},{"icon":{"paths":["M996.571 804.571c25.143 0 33.143 16 17.714 36l-72 92.571c-15.429 20-40.571 20-56 0l-72-92.571c-15.429-20-7.429-36 17.714-36h45.714v-585.143h-45.714c-25.143 0-33.143-16-17.714-36l72-92.571c15.429-20 40.571-20 56 0l72 92.571c15.429 20 7.429 36-17.714 36h-45.714v585.143h45.714zM46.286 73.714l30.857 15.429c4 1.714 108.571 2.857 120.571 2.857 50.286 0 100.571-2.286 150.857-2.286 41.143 0 81.714 0.571 122.857 0.571h167.429c22.857 0 36 5.143 51.429-16.571l24-0.571c5.143 0 10.857 0.571 16 0.571 1.143 64 1.143 128 1.143 192 0 20 0.571 42.286-2.857 62.286-12.571 4.571-25.714 8.571-38.857 10.286-13.143-22.857-22.286-48-30.857-73.143-4-11.429-17.714-88.571-18.857-89.714-12-14.857-25.143-12-42.857-12-52 0-106.286-2.286-157.714 4-2.857 25.143-5.143 52-4.571 77.714 0.571 160.571 2.286 321.143 2.286 481.714 0 44-6.857 90.286 5.714 132.571 43.429 22.286 94.857 25.714 139.429 45.714 1.143 9.143 2.857 18.857 2.857 28.571 0 5.143-0.571 10.857-1.714 16.571l-19.429 0.571c-81.143 2.286-161.143-10.286-242.857-10.286-57.714 0-115.429 10.286-173.143 10.286-0.571-9.714-1.714-20-1.714-29.714v-5.143c21.714-34.857 100-35.429 136-56.571 12.571-28 10.857-182.857 10.857-218.857 0-115.429-3.429-230.857-3.429-346.286v-66.857c0-10.286 2.286-51.429-4.571-59.429-8-8.571-82.857-6.857-92.571-6.857-21.143 0-82.286 9.714-98.857 21.714-27.429 18.857-27.429 133.143-61.714 135.429-10.286-6.286-24.571-15.429-32-25.143v-218.857z"],"width":1029.7051428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["text-height"],"defaultCode":61492,"grid":14},"attrs":[],"properties":{"name":"text-height","id":53,"order":694,"prevSize":28,"code":61492},"setIdx":0,"setId":1,"iconIdx":64},{"icon":{"paths":["M46.286 73.714l30.857 15.429c4 1.714 108.571 2.857 120.571 2.857 50.286 0 100.571-2.286 150.857-2.286 151.429 0 304.571-3.429 456 1.714 12.571 0.571 24.571-7.429 32-17.714l24-0.571c5.143 0 10.857 0.571 16 0.571 1.143 64 1.143 128 1.143 192 0 20.571 0.571 42.286-2.857 62.286-12.571 4.571-25.714 8.571-38.857 10.286-13.143-22.857-22.286-48-30.857-73.143-4-11.429-18.286-88.571-18.857-89.714-4-5.143-9.143-8.571-15.429-10.857-4.571-1.714-32-1.143-37.714-1.143-70.286 0-151.429-4-220.571 4-2.857 25.143-5.143 52-4.571 77.714l0.571 86.857v-29.714c0.571 93.143 1.714 185.714 1.714 278.286 0 44-6.857 90.286 5.714 132.571 43.429 22.286 94.857 25.714 139.429 45.714 1.143 9.143 2.857 18.857 2.857 28.571 0 5.143-0.571 10.857-1.714 16.571l-19.429 0.571c-81.143 2.286-161.143-10.286-242.857-10.286-57.714 0-115.429 10.286-173.143 10.286-0.571-9.714-1.714-20-1.714-29.714v-5.143c21.714-34.857 100-35.429 136-56.571 14.286-32 10.286-302.286 10.286-352.571 0-8-2.857-16.571-2.857-25.143 0-23.429 4-157.714-4.571-167.429-8-8.571-82.857-6.857-92.571-6.857-24 0-158.286 12.571-172 21.714-26.857 17.714-27.429 132.571-61.714 135.429-10.286-6.286-24.571-15.429-32-25.143v-218.857zM748.571 806.286c20 0 96 68 111.429 80 8.571 6.857 14.857 16.571 14.857 28s-6.286 21.143-14.857 28c-15.429 12-91.429 80-111.429 80-26.286 0-17.143-61.143-17.143-71.429h-585.143c0 10.286 9.143 71.429-17.143 71.429-20 0-96-68-111.429-80-8.571-6.857-14.857-16.571-14.857-28s6.286-21.143 14.857-28c15.429-12 91.429-80 111.429-80 26.286 0 17.143 61.143 17.143 71.429h585.143c0-10.286-9.143-71.429 17.143-71.429z"],"width":878.2994285714285,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["text-width"],"defaultCode":61493,"grid":14},"attrs":[],"properties":{"name":"text-width","id":54,"order":695,"prevSize":28,"code":61493},"setIdx":0,"setId":1,"iconIdx":65},{"icon":{"paths":["M1024 768v73.143c0 20-16.571 36.571-36.571 36.571h-950.857c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h950.857c20 0 36.571 16.571 36.571 36.571zM804.571 548.571v73.143c0 20-16.571 36.571-36.571 36.571h-731.429c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h731.429c20 0 36.571 16.571 36.571 36.571zM950.857 329.143v73.143c0 20-16.571 36.571-36.571 36.571h-877.714c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h877.714c20 0 36.571 16.571 36.571 36.571zM731.429 109.714v73.143c0 20-16.571 36.571-36.571 36.571h-658.286c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h658.286c20 0 36.571 16.571 36.571 36.571z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["align-left"],"defaultCode":61494,"grid":14},"attrs":[],"properties":{"name":"align-left","id":55,"order":57,"prevSize":28,"code":61494},"setIdx":0,"setId":1,"iconIdx":66},{"icon":{"paths":["M1024 768v73.143c0 20-16.571 36.571-36.571 36.571h-950.857c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h950.857c20 0 36.571 16.571 36.571 36.571zM804.571 548.571v73.143c0 20-16.571 36.571-36.571 36.571h-512c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h512c20 0 36.571 16.571 36.571 36.571zM950.857 329.143v73.143c0 20-16.571 36.571-36.571 36.571h-804.571c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h804.571c20 0 36.571 16.571 36.571 36.571zM731.429 109.714v73.143c0 20-16.571 36.571-36.571 36.571h-365.714c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h365.714c20 0 36.571 16.571 36.571 36.571z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["align-center"],"defaultCode":61495,"grid":14},"attrs":[],"properties":{"name":"align-center","id":56,"order":58,"prevSize":28,"code":61495},"setIdx":0,"setId":1,"iconIdx":67},{"icon":{"paths":["M1024 768v73.143c0 20-16.571 36.571-36.571 36.571h-950.857c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h950.857c20 0 36.571 16.571 36.571 36.571zM1024 548.571v73.143c0 20-16.571 36.571-36.571 36.571h-731.429c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h731.429c20 0 36.571 16.571 36.571 36.571zM1024 329.143v73.143c0 20-16.571 36.571-36.571 36.571h-877.714c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h877.714c20 0 36.571 16.571 36.571 36.571zM1024 109.714v73.143c0 20-16.571 36.571-36.571 36.571h-658.286c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h658.286c20 0 36.571 16.571 36.571 36.571z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["align-right"],"defaultCode":61496,"grid":14},"attrs":[],"properties":{"name":"align-right","id":57,"order":59,"prevSize":28,"code":61496},"setIdx":0,"setId":1,"iconIdx":68},{"icon":{"paths":["M1024 768v73.143c0 20-16.571 36.571-36.571 36.571h-950.857c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h950.857c20 0 36.571 16.571 36.571 36.571zM1024 548.571v73.143c0 20-16.571 36.571-36.571 36.571h-950.857c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h950.857c20 0 36.571 16.571 36.571 36.571zM1024 329.143v73.143c0 20-16.571 36.571-36.571 36.571h-950.857c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h950.857c20 0 36.571 16.571 36.571 36.571zM1024 109.714v73.143c0 20-16.571 36.571-36.571 36.571h-950.857c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h950.857c20 0 36.571 16.571 36.571 36.571z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["align-justify"],"defaultCode":61497,"grid":14},"attrs":[],"properties":{"name":"align-justify","id":58,"order":60,"prevSize":28,"code":61497},"setIdx":0,"setId":1,"iconIdx":69},{"icon":{"paths":["M146.286 749.714v109.714c0 9.714-8.571 18.286-18.286 18.286h-109.714c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h109.714c9.714 0 18.286 8.571 18.286 18.286zM146.286 530.286v109.714c0 9.714-8.571 18.286-18.286 18.286h-109.714c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h109.714c9.714 0 18.286 8.571 18.286 18.286zM146.286 310.857v109.714c0 9.714-8.571 18.286-18.286 18.286h-109.714c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h109.714c9.714 0 18.286 8.571 18.286 18.286zM1024 749.714v109.714c0 9.714-8.571 18.286-18.286 18.286h-768c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h768c9.714 0 18.286 8.571 18.286 18.286zM146.286 91.429v109.714c0 9.714-8.571 18.286-18.286 18.286h-109.714c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h109.714c9.714 0 18.286 8.571 18.286 18.286zM1024 530.286v109.714c0 9.714-8.571 18.286-18.286 18.286h-768c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h768c9.714 0 18.286 8.571 18.286 18.286zM1024 310.857v109.714c0 9.714-8.571 18.286-18.286 18.286h-768c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h768c9.714 0 18.286 8.571 18.286 18.286zM1024 91.429v109.714c0 9.714-8.571 18.286-18.286 18.286h-768c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h768c9.714 0 18.286 8.571 18.286 18.286z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["list"],"defaultCode":61498,"grid":14},"attrs":[],"properties":{"name":"list","id":59,"order":61,"prevSize":28,"code":61498},"setIdx":0,"setId":1,"iconIdx":70},{"icon":{"paths":["M219.429 310.857v329.143c0 9.714-8.571 18.286-18.286 18.286-4.571 0-9.714-1.714-13.143-5.143l-164.571-164.571c-3.429-3.429-5.143-8.571-5.143-13.143s1.714-9.714 5.143-13.143l164.571-164.571c3.429-3.429 8.571-5.143 13.143-5.143 9.714 0 18.286 8.571 18.286 18.286zM1024 749.714v109.714c0 9.714-8.571 18.286-18.286 18.286h-987.429c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h987.429c9.714 0 18.286 8.571 18.286 18.286zM1024 530.286v109.714c0 9.714-8.571 18.286-18.286 18.286h-621.714c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h621.714c9.714 0 18.286 8.571 18.286 18.286zM1024 310.857v109.714c0 9.714-8.571 18.286-18.286 18.286h-621.714c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h621.714c9.714 0 18.286 8.571 18.286 18.286zM1024 91.429v109.714c0 9.714-8.571 18.286-18.286 18.286h-987.429c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h987.429c9.714 0 18.286 8.571 18.286 18.286z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["dedent","outdent"],"defaultCode":61499,"grid":14},"attrs":[],"properties":{"name":"dedent, outdent","id":60,"order":62,"prevSize":28,"code":61499},"setIdx":0,"setId":1,"iconIdx":71},{"icon":{"paths":["M201.143 475.429c0 4.571-1.714 9.714-5.143 13.143l-164.571 164.571c-3.429 3.429-8.571 5.143-13.143 5.143-9.714 0-18.286-8.571-18.286-18.286v-329.143c0-9.714 8.571-18.286 18.286-18.286 4.571 0 9.714 1.714 13.143 5.143l164.571 164.571c3.429 3.429 5.143 8.571 5.143 13.143zM1024 749.714v109.714c0 9.714-8.571 18.286-18.286 18.286h-987.429c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h987.429c9.714 0 18.286 8.571 18.286 18.286zM1024 530.286v109.714c0 9.714-8.571 18.286-18.286 18.286h-621.714c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h621.714c9.714 0 18.286 8.571 18.286 18.286zM1024 310.857v109.714c0 9.714-8.571 18.286-18.286 18.286h-621.714c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h621.714c9.714 0 18.286 8.571 18.286 18.286zM1024 91.429v109.714c0 9.714-8.571 18.286-18.286 18.286h-987.429c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h987.429c9.714 0 18.286 8.571 18.286 18.286z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["indent"],"defaultCode":61500,"grid":14},"attrs":[],"properties":{"name":"indent","id":61,"order":63,"prevSize":28,"code":61500},"setIdx":0,"setId":1,"iconIdx":72},{"icon":{"paths":["M207.429 877.714l52-52-134.286-134.286-52 52v61.143h73.143v73.143h61.143zM506.286 347.429c0-7.429-5.143-12.571-12.571-12.571-3.429 0-6.857 1.143-9.714 4l-309.714 309.714c-2.857 2.857-4 6.286-4 9.714 0 7.429 5.143 12.571 12.571 12.571 3.429 0 6.857-1.143 9.714-4l309.714-309.714c2.857-2.857 4-6.286 4-9.714zM475.429 237.714l237.714 237.714-475.429 475.429h-237.714v-237.714zM865.714 292.571c0 19.429-8 38.286-21.143 51.429l-94.857 94.857-237.714-237.714 94.857-94.286c13.143-13.714 32-21.714 51.429-21.714s38.286 8 52 21.714l134.286 133.714c13.143 13.714 21.143 32.571 21.143 52z"],"width":865.7188571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["pencil"],"defaultCode":61504,"grid":14},"attrs":[],"properties":{"name":"pencil","id":62,"order":66,"prevSize":28,"code":61504},"setIdx":0,"setId":1,"iconIdx":73},{"icon":{"paths":["M438.857 822.857v-621.714c-171.429 0-310.857 139.429-310.857 310.857s139.429 310.857 310.857 310.857zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["adjust"],"defaultCode":61506,"grid":14},"attrs":[],"properties":{"name":"adjust","id":63,"order":68,"prevSize":28,"code":61506},"setIdx":0,"setId":1,"iconIdx":74},{"icon":{"paths":["M507.429 676.571l66.286-66.286-86.857-86.857-66.286 66.286v32h54.857v54.857h32zM758.857 265.143c-5.143-5.143-13.714-4.571-18.857 0.571l-200 200c-5.143 5.143-5.714 13.714-0.571 18.857s13.714 4.571 18.857-0.571l200-200c5.143-5.143 5.714-13.714 0.571-18.857zM804.571 604.571v108.571c0 90.857-73.714 164.571-164.571 164.571h-475.429c-90.857 0-164.571-73.714-164.571-164.571v-475.429c0-90.857 73.714-164.571 164.571-164.571h475.429c22.857 0 45.714 4.571 66.857 14.286 5.143 2.286 9.143 7.429 10.286 13.143 1.143 6.286-0.571 12-5.143 16.571l-28 28c-5.143 5.143-12 6.857-18.286 4.571-8.571-2.286-17.143-3.429-25.714-3.429h-475.429c-50.286 0-91.429 41.143-91.429 91.429v475.429c0 50.286 41.143 91.429 91.429 91.429h475.429c50.286 0 91.429-41.143 91.429-91.429v-72c0-4.571 1.714-9.143 5.143-12.571l36.571-36.571c5.714-5.714 13.143-6.857 20-4s11.429 9.143 11.429 16.571zM749.714 182.857l164.571 164.571-384 384h-164.571v-164.571zM1003.429 258.286l-52.571 52.571-164.571-164.571 52.571-52.571c21.143-21.143 56.571-21.143 77.714 0l86.857 86.857c21.143 21.143 21.143 56.571 0 77.714z"],"width":1024.5851428571427,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["edit","pencil-square-o"],"defaultCode":61508,"grid":14},"attrs":[],"properties":{"name":"edit, pencil-square-o","id":64,"order":70,"prevSize":28,"code":61508},"setIdx":0,"setId":1,"iconIdx":75},{"icon":{"paths":["M804.571 565.143v148c0 90.857-73.714 164.571-164.571 164.571h-475.429c-90.857 0-164.571-73.714-164.571-164.571v-475.429c0-90.857 73.714-164.571 164.571-164.571h145.714c9.714 0 18.286 8 18.286 18.286 0 9.143-6.286 16.571-14.857 18.286-28.571 9.714-54.286 21.143-76 34.286-2.857 1.143-5.714 2.286-9.143 2.286h-64c-50.286 0-91.429 41.143-91.429 91.429v475.429c0 50.286 41.143 91.429 91.429 91.429h475.429c50.286 0 91.429-41.143 91.429-91.429v-122.286c0-6.857 4-13.143 10.286-16.571 11.429-5.143 21.714-12.571 30.857-21.143 5.143-5.143 13.143-7.429 20-4.571s12 9.143 12 16.571zM940 281.714l-219.429 219.429c-6.857 7.429-16 10.857-25.714 10.857-4.571 0-9.714-1.143-14.286-2.857-13.143-5.714-22.286-18.857-22.286-33.714v-109.714h-91.429c-125.714 0-205.714 24-250.286 74.857-46.286 53.143-60 138.857-42.286 270.286 1.143 8-4 16-11.429 19.429-2.286 0.571-4.571 1.143-6.857 1.143-5.714 0-11.429-2.857-14.857-7.429-4-5.714-94.857-134.286-94.857-248.571 0-153.143 48-329.143 420.571-329.143h91.429v-109.714c0-14.857 9.143-28 22.286-33.714 4.571-1.714 9.714-2.857 14.286-2.857 9.714 0 18.857 4 25.714 10.857l219.429 219.429c14.286 14.286 14.286 37.143 0 51.429z"],"width":954.2948571428572,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["share-square-o"],"defaultCode":61509,"grid":14},"attrs":[],"properties":{"name":"share-square-o","id":65,"order":71,"prevSize":28,"code":61509},"setIdx":0,"setId":1,"iconIdx":76},{"icon":{"paths":["M804.571 531.429v181.714c0 90.857-73.714 164.571-164.571 164.571h-475.429c-90.857 0-164.571-73.714-164.571-164.571v-475.429c0-90.857 73.714-164.571 164.571-164.571h475.429c22.857 0 45.714 4.571 66.857 14.286 5.143 2.286 9.143 7.429 10.286 13.143 1.143 6.286-0.571 12-5.143 16.571l-28 28c-3.429 3.429-8.571 5.714-13.143 5.714-1.714 0-3.429-0.571-5.143-1.143-8.571-2.286-17.143-3.429-25.714-3.429h-475.429c-50.286 0-91.429 41.143-91.429 91.429v475.429c0 50.286 41.143 91.429 91.429 91.429h475.429c50.286 0 91.429-41.143 91.429-91.429v-145.143c0-4.571 1.714-9.143 5.143-12.571l36.571-36.571c4-4 8.571-5.714 13.143-5.714 2.286 0 4.571 0.571 6.857 1.714 6.857 2.857 11.429 9.143 11.429 16.571zM936.571 252l-465.143 465.143c-18.286 18.286-46.857 18.286-65.143 0l-245.714-245.714c-18.286-18.286-18.286-46.857 0-65.143l62.857-62.857c18.286-18.286 46.857-18.286 65.143 0l150.286 150.286 369.714-369.714c18.286-18.286 46.857-18.286 65.143 0l62.857 62.857c18.286 18.286 18.286 46.857 0 65.143z"],"width":954.8799999999999,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["check-square-o"],"defaultCode":61510,"grid":14},"attrs":[],"properties":{"name":"check-square-o","id":66,"order":719,"prevSize":28,"code":61510},"setIdx":0,"setId":1,"iconIdx":77},{"icon":{"paths":["M1024 512c0 9.714-4 18.857-10.857 25.714l-146.286 146.286c-6.857 6.857-16 10.857-25.714 10.857-20 0-36.571-16.571-36.571-36.571v-73.143h-219.429v219.429h73.143c20 0 36.571 16.571 36.571 36.571 0 9.714-4 18.857-10.857 25.714l-146.286 146.286c-6.857 6.857-16 10.857-25.714 10.857s-18.857-4-25.714-10.857l-146.286-146.286c-6.857-6.857-10.857-16-10.857-25.714 0-20 16.571-36.571 36.571-36.571h73.143v-219.429h-219.429v73.143c0 20-16.571 36.571-36.571 36.571-9.714 0-18.857-4-25.714-10.857l-146.286-146.286c-6.857-6.857-10.857-16-10.857-25.714s4-18.857 10.857-25.714l146.286-146.286c6.857-6.857 16-10.857 25.714-10.857 20 0 36.571 16.571 36.571 36.571v73.143h219.429v-219.429h-73.143c-20 0-36.571-16.571-36.571-36.571 0-9.714 4-18.857 10.857-25.714l146.286-146.286c6.857-6.857 16-10.857 25.714-10.857s18.857 4 25.714 10.857l146.286 146.286c6.857 6.857 10.857 16 10.857 25.714 0 20-16.571 36.571-36.571 36.571h-73.143v219.429h219.429v-73.143c0-20 16.571-36.571 36.571-36.571 9.714 0 18.857 4 25.714 10.857l146.286 146.286c6.857 6.857 10.857 16 10.857 25.714z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["arrows"],"defaultCode":61511,"grid":14},"attrs":[],"properties":{"name":"arrows","id":67,"order":73,"prevSize":28,"code":61511},"setIdx":0,"setId":1,"iconIdx":78},{"icon":{"paths":["M559.429 80.571c14.286-14.286 25.714-9.143 25.714 10.857v841.143c0 20-11.429 25.143-25.714 10.857l-405.714-405.714c-3.429-3.429-5.714-6.857-7.429-10.857v387.429c0 20-16.571 36.571-36.571 36.571h-73.143c-20 0-36.571-16.571-36.571-36.571v-804.571c0-20 16.571-36.571 36.571-36.571h73.143c20 0 36.571 16.571 36.571 36.571v387.429c1.714-4 4-7.429 7.429-10.857z"],"width":585.1428571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["step-backward"],"defaultCode":61512,"grid":14},"attrs":[],"properties":{"name":"step-backward","id":68,"order":74,"prevSize":28,"code":61512},"setIdx":0,"setId":1,"iconIdx":79},{"icon":{"paths":["M998.286 80.571c14.286-14.286 25.714-9.143 25.714 10.857v841.143c0 20-11.429 25.143-25.714 10.857l-405.714-405.714c-3.429-3.429-5.714-6.857-7.429-10.857v405.714c0 20-11.429 25.143-25.714 10.857l-405.714-405.714c-3.429-3.429-5.714-6.857-7.429-10.857v387.429c0 20-16.571 36.571-36.571 36.571h-73.143c-20 0-36.571-16.571-36.571-36.571v-804.571c0-20 16.571-36.571 36.571-36.571h73.143c20 0 36.571 16.571 36.571 36.571v387.429c1.714-4 4-7.429 7.429-10.857l405.714-405.714c14.286-14.286 25.714-9.143 25.714 10.857v405.714c1.714-4 4-7.429 7.429-10.857z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["fast-backward"],"defaultCode":61513,"grid":14},"attrs":[],"properties":{"name":"fast-backward","id":69,"order":75,"prevSize":28,"code":61513},"setIdx":0,"setId":1,"iconIdx":80},{"icon":{"paths":["M925.143 80.571c14.286-14.286 25.714-9.143 25.714 10.857v841.143c0 20-11.429 25.143-25.714 10.857l-405.714-405.714c-3.429-3.429-5.714-6.857-7.429-10.857v405.714c0 20-11.429 25.143-25.714 10.857l-405.714-405.714c-14.286-14.286-14.286-37.143 0-51.429l405.714-405.714c14.286-14.286 25.714-9.143 25.714 10.857v405.714c1.714-4 4-7.429 7.429-10.857z"],"width":1017.1245714285715,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["backward"],"defaultCode":61514,"grid":14},"attrs":[],"properties":{"name":"backward","id":70,"order":76,"prevSize":28,"code":61514},"setIdx":0,"setId":1,"iconIdx":81},{"icon":{"paths":["M790.857 529.714l-758.857 421.714c-17.714 9.714-32 1.143-32-18.857v-841.143c0-20 14.286-28.571 32-18.857l758.857 421.714c17.714 9.714 17.714 25.714 0 35.429z"],"width":808.5942857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["play"],"defaultCode":61515,"grid":14},"attrs":[],"properties":{"name":"play","id":71,"order":77,"prevSize":28,"code":61515},"setIdx":0,"setId":1,"iconIdx":82},{"icon":{"paths":["M877.714 109.714v804.571c0 20-16.571 36.571-36.571 36.571h-292.571c-20 0-36.571-16.571-36.571-36.571v-804.571c0-20 16.571-36.571 36.571-36.571h292.571c20 0 36.571 16.571 36.571 36.571zM365.714 109.714v804.571c0 20-16.571 36.571-36.571 36.571h-292.571c-20 0-36.571-16.571-36.571-36.571v-804.571c0-20 16.571-36.571 36.571-36.571h292.571c20 0 36.571 16.571 36.571 36.571z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["pause"],"defaultCode":61516,"grid":14},"attrs":[],"properties":{"name":"pause","id":72,"order":78,"prevSize":28,"code":61516},"setIdx":0,"setId":1,"iconIdx":83},{"icon":{"paths":["M877.714 109.714v804.571c0 20-16.571 36.571-36.571 36.571h-804.571c-20 0-36.571-16.571-36.571-36.571v-804.571c0-20 16.571-36.571 36.571-36.571h804.571c20 0 36.571 16.571 36.571 36.571z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["stop"],"defaultCode":61517,"grid":14},"attrs":[],"properties":{"name":"stop","id":73,"order":79,"prevSize":28,"code":61517},"setIdx":0,"setId":1,"iconIdx":84},{"icon":{"paths":["M25.714 943.429c-14.286 14.286-25.714 9.143-25.714-10.857v-841.143c0-20 11.429-25.143 25.714-10.857l405.714 405.714c3.429 3.429 5.714 6.857 7.429 10.857v-405.714c0-20 11.429-25.143 25.714-10.857l405.714 405.714c14.286 14.286 14.286 37.143 0 51.429l-405.714 405.714c-14.286 14.286-25.714 9.143-25.714-10.857v-405.714c-1.714 4-4 7.429-7.429 10.857z"],"width":884.5897142857142,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["forward"],"defaultCode":61518,"grid":14},"attrs":[],"properties":{"name":"forward","id":74,"order":80,"prevSize":28,"code":61518},"setIdx":0,"setId":1,"iconIdx":85},{"icon":{"paths":["M25.714 943.429c-14.286 14.286-25.714 9.143-25.714-10.857v-841.143c0-20 11.429-25.143 25.714-10.857l405.714 405.714c3.429 3.429 5.714 6.857 7.429 10.857v-405.714c0-20 11.429-25.143 25.714-10.857l405.714 405.714c3.429 3.429 5.714 6.857 7.429 10.857v-387.429c0-20 16.571-36.571 36.571-36.571h73.143c20 0 36.571 16.571 36.571 36.571v804.571c0 20-16.571 36.571-36.571 36.571h-73.143c-20 0-36.571-16.571-36.571-36.571v-387.429c-1.714 4-4 7.429-7.429 10.857l-405.714 405.714c-14.286 14.286-25.714 9.143-25.714-10.857v-405.714c-1.714 4-4 7.429-7.429 10.857z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["fast-forward"],"defaultCode":61520,"grid":14},"attrs":[],"properties":{"name":"fast-forward","id":75,"order":81,"prevSize":28,"code":61520},"setIdx":0,"setId":1,"iconIdx":86},{"icon":{"paths":["M25.714 943.429c-14.286 14.286-25.714 9.143-25.714-10.857v-841.143c0-20 11.429-25.143 25.714-10.857l405.714 405.714c3.429 3.429 5.714 6.857 7.429 10.857v-387.429c0-20 16.571-36.571 36.571-36.571h73.143c20 0 36.571 16.571 36.571 36.571v804.571c0 20-16.571 36.571-36.571 36.571h-73.143c-20 0-36.571-16.571-36.571-36.571v-387.429c-1.714 4-4 7.429-7.429 10.857z"],"width":585.1428571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["step-forward"],"defaultCode":61521,"grid":14},"attrs":[],"properties":{"name":"step-forward","id":76,"order":82,"prevSize":28,"code":61521},"setIdx":0,"setId":1,"iconIdx":87},{"icon":{"paths":["M8 559.429l405.714-405.714c14.286-14.286 37.143-14.286 51.429 0l405.714 405.714c14.286 14.286 9.143 25.714-10.857 25.714h-841.143c-20 0-25.143-11.429-10.857-25.714zM841.714 877.714h-804.571c-20 0-36.571-16.571-36.571-36.571v-146.286c0-20 16.571-36.571 36.571-36.571h804.571c20 0 36.571 16.571 36.571 36.571v146.286c0 20-16.571 36.571-36.571 36.571z"],"width":878.8845714285713,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["eject"],"defaultCode":61522,"grid":14},"attrs":[],"properties":{"name":"eject","id":77,"order":83,"prevSize":28,"code":61522},"setIdx":0,"setId":1,"iconIdx":88},{"icon":{"paths":["M669.143 172l-303.429 303.429 303.429 303.429c14.286 14.286 14.286 37.143 0 51.429l-94.857 94.857c-14.286 14.286-37.143 14.286-51.429 0l-424-424c-14.286-14.286-14.286-37.143 0-51.429l424-424c14.286-14.286 37.143-14.286 51.429 0l94.857 94.857c14.286 14.286 14.286 37.143 0 51.429z"],"width":768,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["chevron-left"],"defaultCode":61523,"grid":14},"attrs":[],"properties":{"name":"chevron-left","id":78,"order":84,"prevSize":28,"code":61523},"setIdx":0,"setId":1,"iconIdx":89},{"icon":{"paths":["M632.571 501.143l-424 424c-14.286 14.286-37.143 14.286-51.429 0l-94.857-94.857c-14.286-14.286-14.286-37.143 0-51.429l303.429-303.429-303.429-303.429c-14.286-14.286-14.286-37.143 0-51.429l94.857-94.857c14.286-14.286 37.143-14.286 51.429 0l424 424c14.286 14.286 14.286 37.143 0 51.429z"],"width":694.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["chevron-right"],"defaultCode":61524,"grid":14},"attrs":[],"properties":{"name":"chevron-right","id":79,"order":85,"prevSize":28,"code":61524},"setIdx":0,"setId":1,"iconIdx":90},{"icon":{"paths":["M694.857 548.571v-73.143c0-20-16.571-36.571-36.571-36.571h-146.286v-146.286c0-20-16.571-36.571-36.571-36.571h-73.143c-20 0-36.571 16.571-36.571 36.571v146.286h-146.286c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h146.286v146.286c0 20 16.571 36.571 36.571 36.571h73.143c20 0 36.571-16.571 36.571-36.571v-146.286h146.286c20 0 36.571-16.571 36.571-36.571zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["plus-circle"],"defaultCode":61525,"grid":14},"attrs":[],"properties":{"name":"plus-circle","id":80,"order":86,"prevSize":28,"code":61525},"setIdx":0,"setId":1,"iconIdx":91},{"icon":{"paths":["M694.857 548.571v-73.143c0-20-16.571-36.571-36.571-36.571h-438.857c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h438.857c20 0 36.571-16.571 36.571-36.571zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["minus-circle"],"defaultCode":61526,"grid":14},"attrs":[],"properties":{"name":"minus-circle","id":81,"order":87,"prevSize":28,"code":61526},"setIdx":0,"setId":1,"iconIdx":92},{"icon":{"paths":["M656.571 641.143c0-9.714-4-18.857-10.857-25.714l-103.429-103.429 103.429-103.429c6.857-6.857 10.857-16 10.857-25.714s-4-19.429-10.857-26.286l-51.429-51.429c-6.857-6.857-16.571-10.857-26.286-10.857s-18.857 4-25.714 10.857l-103.429 103.429-103.429-103.429c-6.857-6.857-16-10.857-25.714-10.857s-19.429 4-26.286 10.857l-51.429 51.429c-6.857 6.857-10.857 16.571-10.857 26.286s4 18.857 10.857 25.714l103.429 103.429-103.429 103.429c-6.857 6.857-10.857 16-10.857 25.714s4 19.429 10.857 26.286l51.429 51.429c6.857 6.857 16.571 10.857 26.286 10.857s18.857-4 25.714-10.857l103.429-103.429 103.429 103.429c6.857 6.857 16 10.857 25.714 10.857s19.429-4 26.286-10.857l51.429-51.429c6.857-6.857 10.857-16.571 10.857-26.286zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["times-circle"],"defaultCode":61527,"grid":14},"attrs":[],"properties":{"name":"times-circle","id":82,"order":88,"prevSize":28,"code":61527},"setIdx":0,"setId":1,"iconIdx":93},{"icon":{"paths":["M733.714 419.429c0-9.714-3.429-19.429-10.286-26.286l-52-51.429c-6.857-6.857-16-10.857-25.714-10.857s-18.857 4-25.714 10.857l-233.143 232.571-129.143-129.143c-6.857-6.857-16-10.857-25.714-10.857s-18.857 4-25.714 10.857l-52 51.429c-6.857 6.857-10.286 16.571-10.286 26.286s3.429 18.857 10.286 25.714l206.857 206.857c6.857 6.857 16.571 10.857 25.714 10.857 9.714 0 19.429-4 26.286-10.857l310.286-310.286c6.857-6.857 10.286-16 10.286-25.714zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["check-circle"],"defaultCode":61528,"grid":14},"attrs":[],"properties":{"name":"check-circle","id":83,"order":89,"prevSize":28,"code":61528},"setIdx":0,"setId":1,"iconIdx":94},{"icon":{"paths":["M512 786.286v-109.714c0-10.286-8-18.286-18.286-18.286h-109.714c-10.286 0-18.286 8-18.286 18.286v109.714c0 10.286 8 18.286 18.286 18.286h109.714c10.286 0 18.286-8 18.286-18.286zM658.286 402.286c0-104.571-109.714-182.857-208-182.857-93.143 0-162.857 40-212 121.714-5.143 8-2.857 18.286 4.571 24l75.429 57.143c2.857 2.286 6.857 3.429 10.857 3.429 5.143 0 10.857-2.286 14.286-6.857 26.857-34.286 38.286-44.571 49.143-52.571 9.714-6.857 28.571-13.714 49.143-13.714 36.571 0 70.286 23.429 70.286 48.571 0 29.714-15.429 44.571-50.286 60.571-40.571 18.286-96 65.714-96 121.143v20.571c0 10.286 8 18.286 18.286 18.286h109.714c10.286 0 18.286-8 18.286-18.286v0c0-13.143 16.571-41.143 43.429-56.571 43.429-24.571 102.857-57.714 102.857-144.571zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["question-circle"],"defaultCode":61529,"grid":14},"attrs":[],"properties":{"name":"question-circle","id":84,"order":90,"prevSize":28,"code":61529},"setIdx":0,"setId":1,"iconIdx":95},{"icon":{"paths":["M585.143 786.286v-91.429c0-10.286-8-18.286-18.286-18.286h-54.857v-292.571c0-10.286-8-18.286-18.286-18.286h-182.857c-10.286 0-18.286 8-18.286 18.286v91.429c0 10.286 8 18.286 18.286 18.286h54.857v182.857h-54.857c-10.286 0-18.286 8-18.286 18.286v91.429c0 10.286 8 18.286 18.286 18.286h256c10.286 0 18.286-8 18.286-18.286zM512 274.286v-91.429c0-10.286-8-18.286-18.286-18.286h-109.714c-10.286 0-18.286 8-18.286 18.286v91.429c0 10.286 8 18.286 18.286 18.286h109.714c10.286 0 18.286-8 18.286-18.286zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["info-circle"],"defaultCode":61530,"grid":14},"attrs":[],"properties":{"name":"info-circle","id":85,"order":91,"prevSize":28,"code":61530},"setIdx":0,"setId":1,"iconIdx":96},{"icon":{"paths":["M684 585.143h-62.286c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h62.286c-24.571-82.286-89.714-147.429-172-172v62.286c0 20-16.571 36.571-36.571 36.571h-73.143c-20 0-36.571-16.571-36.571-36.571v-62.286c-82.286 24.571-147.429 89.714-172 172h62.286c20 0 36.571 16.571 36.571 36.571v73.143c0 20-16.571 36.571-36.571 36.571h-62.286c24.571 82.286 89.714 147.429 172 172v-62.286c0-20 16.571-36.571 36.571-36.571h73.143c20 0 36.571 16.571 36.571 36.571v62.286c82.286-24.571 147.429-89.714 172-172zM877.714 475.429v73.143c0 20-16.571 36.571-36.571 36.571h-81.714c-28 122.857-124.571 219.429-247.429 247.429v81.714c0 20-16.571 36.571-36.571 36.571h-73.143c-20 0-36.571-16.571-36.571-36.571v-81.714c-122.857-28-219.429-124.571-247.429-247.429h-81.714c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h81.714c28-122.857 124.571-219.429 247.429-247.429v-81.714c0-20 16.571-36.571 36.571-36.571h73.143c20 0 36.571 16.571 36.571 36.571v81.714c122.857 28 219.429 124.571 247.429 247.429h81.714c20 0 36.571 16.571 36.571 36.571z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["crosshairs"],"defaultCode":61531,"grid":14},"attrs":[],"properties":{"name":"crosshairs","id":86,"order":92,"prevSize":28,"code":61531},"setIdx":0,"setId":1,"iconIdx":97},{"icon":{"paths":["M626.857 616.571l-83.429 83.429c-7.429 7.429-18.857 7.429-26.286 0l-78.286-78.286-78.286 78.286c-7.429 7.429-18.857 7.429-26.286 0l-83.429-83.429c-7.429-7.429-7.429-18.857 0-26.286l78.286-78.286-78.286-78.286c-7.429-7.429-7.429-18.857 0-26.286l83.429-83.429c7.429-7.429 18.857-7.429 26.286 0l78.286 78.286 78.286-78.286c7.429-7.429 18.857-7.429 26.286 0l83.429 83.429c7.429 7.429 7.429 18.857 0 26.286l-78.286 78.286 78.286 78.286c7.429 7.429 7.429 18.857 0 26.286zM749.714 512c0-171.429-139.429-310.857-310.857-310.857s-310.857 139.429-310.857 310.857 139.429 310.857 310.857 310.857 310.857-139.429 310.857-310.857zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["times-circle-o"],"defaultCode":61532,"grid":14},"attrs":[],"properties":{"name":"times-circle-o","id":87,"order":93,"prevSize":28,"code":61532},"setIdx":0,"setId":1,"iconIdx":98},{"icon":{"paths":["M669.143 464.571l-241.143 241.143c-14.286 14.286-37.143 14.286-51.429 0l-168-168c-14.286-14.286-14.286-37.143 0-51.429l58.286-58.286c14.286-14.286 37.143-14.286 51.429 0l84 84 157.143-157.143c14.286-14.286 37.143-14.286 51.429 0l58.286 58.286c14.286 14.286 14.286 37.143 0 51.429zM749.714 512c0-171.429-139.429-310.857-310.857-310.857s-310.857 139.429-310.857 310.857 139.429 310.857 310.857 310.857 310.857-139.429 310.857-310.857zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["check-circle-o"],"defaultCode":61533,"grid":14},"attrs":[],"properties":{"name":"check-circle-o","id":88,"order":94,"prevSize":28,"code":61533},"setIdx":0,"setId":1,"iconIdx":99},{"icon":{"paths":["M749.714 510.286c0-62.286-18.286-120-49.714-168.571l-430.857 430.286c49.143 32 107.429 50.857 169.714 50.857 171.429 0 310.857-140 310.857-312.571zM178.857 681.143l431.429-430.857c-49.143-33.143-108-52-171.429-52-171.429 0-310.857 140-310.857 312 0 63.429 18.857 121.714 50.857 170.857zM877.714 510.286c0 243.429-196.571 440.571-438.857 440.571s-438.857-197.143-438.857-440.571c0-242.857 196.571-440 438.857-440s438.857 197.143 438.857 440z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["ban"],"defaultCode":61534,"grid":14},"attrs":[],"properties":{"name":"ban","id":89,"order":95,"prevSize":28,"code":61534},"setIdx":0,"setId":1,"iconIdx":100},{"icon":{"paths":["M877.714 512v73.143c0 38.857-25.714 73.143-66.857 73.143h-402.286l167.429 168c13.714 13.143 21.714 32 21.714 51.429s-8 38.286-21.714 51.429l-42.857 43.429c-13.143 13.143-32 21.143-51.429 21.143s-38.286-8-52-21.143l-372-372.571c-13.143-13.143-21.143-32-21.143-51.429s8-38.286 21.143-52l372-371.429c13.714-13.714 32.571-21.714 52-21.714s37.714 8 51.429 21.714l42.857 42.286c13.714 13.714 21.714 32.571 21.714 52s-8 38.286-21.714 52l-167.429 167.429h402.286c41.143 0 66.857 34.286 66.857 73.143z"],"width":914.2857142857142,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["arrow-left"],"defaultCode":61536,"grid":14},"attrs":[],"properties":{"name":"arrow-left","id":90,"order":96,"prevSize":28,"code":61536},"setIdx":0,"setId":1,"iconIdx":101},{"icon":{"paths":["M841.143 548.571c0 19.429-7.429 38.286-21.143 52l-372 372c-13.714 13.143-32.571 21.143-52 21.143s-37.714-8-51.429-21.143l-42.857-42.857c-13.714-13.714-21.714-32.571-21.714-52s8-38.286 21.714-52l167.429-167.429h-402.286c-41.143 0-66.857-34.286-66.857-73.143v-73.143c0-38.857 25.714-73.143 66.857-73.143h402.286l-167.429-168c-13.714-13.143-21.714-32-21.714-51.429s8-38.286 21.714-51.429l42.857-42.857c13.714-13.714 32-21.714 51.429-21.714s38.286 8 52 21.714l372 372c13.714 13.143 21.143 32 21.143 51.429z"],"width":841.1428571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["arrow-right"],"defaultCode":61537,"grid":14},"attrs":[],"properties":{"name":"arrow-right","id":91,"order":97,"prevSize":28,"code":61537},"setIdx":0,"setId":1,"iconIdx":102},{"icon":{"paths":["M920.571 554.857c0 19.429-8 37.714-21.143 51.429l-42.857 42.857c-13.714 13.714-32.571 21.714-52 21.714s-38.286-8-51.429-21.714l-168-167.429v402.286c0 41.143-34.286 66.857-73.143 66.857h-73.143c-38.857 0-73.143-25.714-73.143-66.857v-402.286l-168 167.429c-13.143 13.714-32 21.714-51.429 21.714s-38.286-8-51.429-21.714l-42.857-42.857c-13.714-13.714-21.714-32-21.714-51.429s8-38.286 21.714-52l372-372c13.143-13.714 32-21.143 51.429-21.143s38.286 7.429 52 21.143l372 372c13.143 13.714 21.143 32.571 21.143 52z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["arrow-up"],"defaultCode":61538,"grid":14},"attrs":[],"properties":{"name":"arrow-up","id":92,"order":98,"prevSize":28,"code":61538},"setIdx":0,"setId":1,"iconIdx":103},{"icon":{"paths":["M920.571 475.429c0 19.429-8 38.286-21.143 51.429l-372 372.571c-13.714 13.143-32.571 21.143-52 21.143s-38.286-8-51.429-21.143l-372-372.571c-13.714-13.143-21.714-32-21.714-51.429s8-38.286 21.714-52l42.286-42.857c13.714-13.143 32.571-21.143 52-21.143s38.286 8 51.429 21.143l168 168v-402.286c0-40 33.143-73.143 73.143-73.143h73.143c40 0 73.143 33.143 73.143 73.143v402.286l168-168c13.143-13.143 32-21.143 51.429-21.143s38.286 8 52 21.143l42.857 42.857c13.143 13.714 21.143 32.571 21.143 52z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["arrow-down"],"defaultCode":61539,"grid":14},"attrs":[],"properties":{"name":"arrow-down","id":93,"order":99,"prevSize":28,"code":61539},"setIdx":0,"setId":1,"iconIdx":104},{"icon":{"paths":["M1024 365.714c0 9.714-4 18.857-10.857 25.714l-292.571 292.571c-6.857 6.857-16 10.857-25.714 10.857-20 0-36.571-16.571-36.571-36.571v-146.286h-128c-246.286 0-408 47.429-408 320 0 23.429 1.143 46.857 2.857 70.286 0.571 9.143 2.857 19.429 2.857 28.571 0 10.857-6.857 20-18.286 20-8 0-12-4-16-9.714-8.571-12-14.857-30.286-21.143-43.429-32.571-73.143-72.571-177.714-72.571-257.714 0-64 6.286-129.714 30.286-190.286 79.429-197.143 312.571-230.286 500-230.286h128v-146.286c0-20 16.571-36.571 36.571-36.571 9.714 0 18.857 4 25.714 10.857l292.571 292.571c6.857 6.857 10.857 16 10.857 25.714z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["mail-forward","share"],"defaultCode":61540,"grid":14},"attrs":[],"properties":{"name":"mail-forward, share","id":94,"order":100,"prevSize":28,"code":61540},"setIdx":0,"setId":1,"iconIdx":105},{"icon":{"paths":["M431.429 603.429c0 4.571-2.286 9.714-5.714 13.143l-189.714 189.714 82.286 82.286c6.857 6.857 10.857 16 10.857 25.714 0 20-16.571 36.571-36.571 36.571h-256c-20 0-36.571-16.571-36.571-36.571v-256c0-20 16.571-36.571 36.571-36.571 9.714 0 18.857 4 25.714 10.857l82.286 82.286 189.714-189.714c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l65.143 65.143c3.429 3.429 5.714 8.571 5.714 13.143zM877.714 109.714v256c0 20-16.571 36.571-36.571 36.571-9.714 0-18.857-4-25.714-10.857l-82.286-82.286-189.714 189.714c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-65.143-65.143c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l189.714-189.714-82.286-82.286c-6.857-6.857-10.857-16-10.857-25.714 0-20 16.571-36.571 36.571-36.571h256c20 0 36.571 16.571 36.571 36.571z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["expand"],"defaultCode":61541,"grid":14},"attrs":[],"properties":{"name":"expand","id":95,"order":101,"prevSize":28,"code":61541},"setIdx":0,"setId":1,"iconIdx":106},{"icon":{"paths":["M438.857 548.571v256c0 20-16.571 36.571-36.571 36.571-9.714 0-18.857-4-25.714-10.857l-82.286-82.286-189.714 189.714c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-65.143-65.143c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l189.714-189.714-82.286-82.286c-6.857-6.857-10.857-16-10.857-25.714 0-20 16.571-36.571 36.571-36.571h256c20 0 36.571 16.571 36.571 36.571zM870.286 164.571c0 4.571-2.286 9.714-5.714 13.143l-189.714 189.714 82.286 82.286c6.857 6.857 10.857 16 10.857 25.714 0 20-16.571 36.571-36.571 36.571h-256c-20 0-36.571-16.571-36.571-36.571v-256c0-20 16.571-36.571 36.571-36.571 9.714 0 18.857 4 25.714 10.857l82.286 82.286 189.714-189.714c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l65.143 65.143c3.429 3.429 5.714 8.571 5.714 13.143z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["compress"],"defaultCode":61542,"grid":14},"attrs":[],"properties":{"name":"compress","id":96,"order":102,"prevSize":28,"code":61542},"setIdx":0,"setId":1,"iconIdx":107},{"icon":{"paths":["M438.857 73.143c242.286 0 438.857 196.571 438.857 438.857s-196.571 438.857-438.857 438.857-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857zM512 785.714v-108.571c0-10.286-8-18.857-17.714-18.857h-109.714c-10.286 0-18.857 8.571-18.857 18.857v108.571c0 10.286 8.571 18.857 18.857 18.857h109.714c9.714 0 17.714-8.571 17.714-18.857zM510.857 589.143l10.286-354.857c0-4-1.714-8-5.714-10.286-3.429-2.857-8.571-4.571-13.714-4.571h-125.714c-5.143 0-10.286 1.714-13.714 4.571-4 2.286-5.714 6.286-5.714 10.286l9.714 354.857c0 8 8.571 14.286 19.429 14.286h105.714c10.286 0 18.857-6.286 19.429-14.286z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["exclamation-circle"],"defaultCode":61546,"grid":14},"attrs":[],"properties":{"name":"exclamation-circle","id":97,"order":103,"prevSize":28,"code":61546},"setIdx":0,"setId":1,"iconIdx":108},{"icon":{"paths":["M950.857 548.571c-54.286-84-128.571-156-217.714-201.714 22.857 38.857 34.857 83.429 34.857 128.571 0 141.143-114.857 256-256 256s-256-114.857-256-256c0-45.143 12-89.714 34.857-128.571-89.143 45.714-163.429 117.714-217.714 201.714 97.714 150.857 255.429 256 438.857 256s341.143-105.143 438.857-256zM539.429 329.143c0-14.857-12.571-27.429-27.429-27.429-95.429 0-173.714 78.286-173.714 173.714 0 14.857 12.571 27.429 27.429 27.429s27.429-12.571 27.429-27.429c0-65.143 53.714-118.857 118.857-118.857 14.857 0 27.429-12.571 27.429-27.429zM1024 548.571c0 14.286-4.571 27.429-11.429 39.429-105.143 173.143-297.714 289.714-500.571 289.714s-395.429-117.143-500.571-289.714c-6.857-12-11.429-25.143-11.429-39.429s4.571-27.429 11.429-39.429c105.143-172.571 297.714-289.714 500.571-289.714s395.429 117.143 500.571 289.714c6.857 12 11.429 25.143 11.429 39.429z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["eye"],"defaultCode":61550,"grid":14},"attrs":[],"properties":{"name":"eye","id":98,"order":107,"prevSize":28,"code":61550},"setIdx":0,"setId":1,"iconIdx":109},{"icon":{"paths":["M317.143 762.857l44.571-80.571c-66.286-48-105.714-125.143-105.714-206.857 0-45.143 12-89.714 34.857-128.571-89.143 45.714-163.429 117.714-217.714 201.714 59.429 92 143.429 169.143 244 214.286zM539.429 329.143c0-14.857-12.571-27.429-27.429-27.429-95.429 0-173.714 78.286-173.714 173.714 0 14.857 12.571 27.429 27.429 27.429s27.429-12.571 27.429-27.429c0-65.714 53.714-118.857 118.857-118.857 14.857 0 27.429-12.571 27.429-27.429zM746.857 220c0 1.143 0 4-0.571 5.143-120.571 215.429-240 432-360.571 647.429l-28 50.857c-3.429 5.714-9.714 9.143-16 9.143-10.286 0-64.571-33.143-76.571-40-5.714-3.429-9.143-9.143-9.143-16 0-9.143 19.429-40 25.143-49.714-110.857-50.286-204-136-269.714-238.857-7.429-11.429-11.429-25.143-11.429-39.429 0-13.714 4-28 11.429-39.429 113.143-173.714 289.714-289.714 500.571-289.714 34.286 0 69.143 3.429 102.857 9.714l30.857-55.429c3.429-5.714 9.143-9.143 16-9.143 10.286 0 64 33.143 76 40 5.714 3.429 9.143 9.143 9.143 15.429zM768 475.429c0 106.286-65.714 201.143-164.571 238.857l160-286.857c2.857 16 4.571 32 4.571 48zM1024 548.571c0 14.857-4 26.857-11.429 39.429-17.714 29.143-40 57.143-62.286 82.857-112 128.571-266.286 206.857-438.286 206.857l42.286-75.429c166.286-14.286 307.429-115.429 396.571-253.714-42.286-65.714-96.571-123.429-161.143-168l36-64c70.857 47.429 142.286 118.857 186.857 192.571 7.429 12.571 11.429 24.571 11.429 39.429z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["eye-slash"],"defaultCode":61552,"grid":14},"attrs":[],"properties":{"name":"eye-slash","id":99,"order":108,"prevSize":28,"code":61552},"setIdx":0,"setId":1,"iconIdx":110},{"icon":{"paths":["M585.143 785.714v-108.571c0-10.286-8-18.857-18.286-18.857h-109.714c-10.286 0-18.286 8.571-18.286 18.857v108.571c0 10.286 8 18.857 18.286 18.857h109.714c10.286 0 18.286-8.571 18.286-18.857zM584 572l10.286-262.286c0-3.429-1.714-8-5.714-10.857-3.429-2.857-8.571-6.286-13.714-6.286h-125.714c-5.143 0-10.286 3.429-13.714 6.286-4 2.857-5.714 8.571-5.714 12l9.714 261.143c0 7.429 8.571 13.143 19.429 13.143h105.714c10.286 0 18.857-5.714 19.429-13.143zM576 38.286l438.857 804.571c12.571 22.286 12 49.714-1.143 72s-37.143 36-62.857 36h-877.714c-25.714 0-49.714-13.714-62.857-36s-13.714-49.714-1.143-72l438.857-804.571c12.571-23.429 37.143-38.286 64-38.286s51.429 14.857 64 38.286z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["exclamation-triangle","warning"],"defaultCode":61553,"grid":14},"attrs":[],"properties":{"name":"exclamation-triangle, warning","id":100,"order":109,"prevSize":28,"code":61553},"setIdx":0,"setId":1,"iconIdx":111},{"icon":{"paths":["M73.143 950.857h164.571v-164.571h-164.571v164.571zM274.286 950.857h182.857v-164.571h-182.857v164.571zM73.143 749.714h164.571v-182.857h-164.571v182.857zM274.286 749.714h182.857v-182.857h-182.857v182.857zM73.143 530.286h164.571v-164.571h-164.571v164.571zM493.714 950.857h182.857v-164.571h-182.857v164.571zM274.286 530.286h182.857v-164.571h-182.857v164.571zM713.143 950.857h164.571v-164.571h-164.571v164.571zM493.714 749.714h182.857v-182.857h-182.857v182.857zM292.571 256v-164.571c0-9.714-8.571-18.286-18.286-18.286h-36.571c-9.714 0-18.286 8.571-18.286 18.286v164.571c0 9.714 8.571 18.286 18.286 18.286h36.571c9.714 0 18.286-8.571 18.286-18.286zM713.143 749.714h164.571v-182.857h-164.571v182.857zM493.714 530.286h182.857v-164.571h-182.857v164.571zM713.143 530.286h164.571v-164.571h-164.571v164.571zM731.429 256v-164.571c0-9.714-8.571-18.286-18.286-18.286h-36.571c-9.714 0-18.286 8.571-18.286 18.286v164.571c0 9.714 8.571 18.286 18.286 18.286h36.571c9.714 0 18.286-8.571 18.286-18.286zM950.857 219.429v731.429c0 40-33.143 73.143-73.143 73.143h-804.571c-40 0-73.143-33.143-73.143-73.143v-731.429c0-40 33.143-73.143 73.143-73.143h73.143v-54.857c0-50.286 41.143-91.429 91.429-91.429h36.571c50.286 0 91.429 41.143 91.429 91.429v54.857h219.429v-54.857c0-50.286 41.143-91.429 91.429-91.429h36.571c50.286 0 91.429 41.143 91.429 91.429v54.857h73.143c40 0 73.143 33.143 73.143 73.143z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["calendar"],"defaultCode":61555,"grid":14},"attrs":[],"properties":{"name":"calendar","id":101,"order":111,"prevSize":28,"code":61555},"setIdx":0,"setId":1,"iconIdx":112},{"icon":{"paths":["M380.571 274.857c-32 49.143-55.429 102.286-78.286 156-33.143-69.143-69.714-138.286-156-138.286h-128c-10.286 0-18.286-8-18.286-18.286v-109.714c0-10.286 8-18.286 18.286-18.286h128c101.714 0 176.571 47.429 234.286 128.571zM1024 731.429c0 4.571-1.714 9.714-5.143 13.143l-182.857 182.857c-3.429 3.429-8.571 5.143-13.143 5.143-9.714 0-18.286-8.571-18.286-18.286v-109.714c-169.714 0-274.286 20-380-128.571 31.429-49.143 54.857-102.286 77.714-156 33.143 69.143 69.714 138.286 156 138.286h146.286v-109.714c0-10.286 8-18.286 18.286-18.286 5.143 0 9.714 2.286 13.714 5.714l182.286 182.286c3.429 3.429 5.143 8.571 5.143 13.143zM1024 219.429c0 4.571-1.714 9.714-5.143 13.143l-182.857 182.857c-3.429 3.429-8.571 5.143-13.143 5.143-9.714 0-18.286-8-18.286-18.286v-109.714h-146.286c-76 0-112 52-144 113.714-16.571 32-30.857 65.143-44.571 97.714-63.429 147.429-137.714 300.571-323.429 300.571h-128c-10.286 0-18.286-8-18.286-18.286v-109.714c0-10.286 8-18.286 18.286-18.286h128c76 0 112-52 144-113.714 16.571-32 30.857-65.143 44.571-97.714 63.429-147.429 137.714-300.571 323.429-300.571h146.286v-109.714c0-10.286 8-18.286 18.286-18.286 5.143 0 9.714 2.286 13.714 5.714l182.286 182.286c3.429 3.429 5.143 8.571 5.143 13.143z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["random"],"defaultCode":61556,"grid":14},"attrs":[],"properties":{"name":"random","id":102,"order":112,"prevSize":28,"code":61556},"setIdx":0,"setId":1,"iconIdx":113},{"icon":{"paths":["M1024 512c0 202.286-229.143 365.714-512 365.714-28 0-56-1.714-82.857-4.571-74.857 66.286-164 113.143-262.857 138.286-20.571 5.714-42.857 9.714-65.143 12.571-12.571 1.143-24.571-8-27.429-21.714v-0.571c-2.857-14.286 6.857-22.857 15.429-33.143 36-40.571 77.143-74.857 104-170.286-117.714-66.857-193.143-170.286-193.143-286.286 0-201.714 229.143-365.714 512-365.714s512 163.429 512 365.714z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["comment"],"defaultCode":61557,"grid":14},"attrs":[],"properties":{"name":"comment","id":103,"order":113,"prevSize":28,"code":61557},"setIdx":0,"setId":1,"iconIdx":114},{"icon":{"paths":["M961.714 760.571l-94.857 94.286c-14.286 14.286-37.143 14.286-51.429 0l-303.429-303.429-303.429 303.429c-14.286 14.286-37.143 14.286-51.429 0l-94.857-94.286c-14.286-14.286-14.286-37.714 0-52l424-423.429c14.286-14.286 37.143-14.286 51.429 0l424 423.429c14.286 14.286 14.286 37.714 0 52z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["chevron-up"],"defaultCode":61559,"grid":14},"attrs":[],"properties":{"name":"chevron-up","id":104,"order":115,"prevSize":28,"code":61559},"setIdx":0,"setId":1,"iconIdx":115},{"icon":{"paths":["M961.714 461.714l-424 423.429c-14.286 14.286-37.143 14.286-51.429 0l-424-423.429c-14.286-14.286-14.286-37.714 0-52l94.857-94.286c14.286-14.286 37.143-14.286 51.429 0l303.429 303.429 303.429-303.429c14.286-14.286 37.143-14.286 51.429 0l94.857 94.286c14.286 14.286 14.286 37.714 0 52z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["chevron-down"],"defaultCode":61560,"grid":14},"attrs":[],"properties":{"name":"chevron-down","id":105,"order":116,"prevSize":28,"code":61560},"setIdx":0,"setId":1,"iconIdx":116},{"icon":{"paths":["M731.429 859.429c0 9.714-8.571 18.286-18.286 18.286h-548.571c-21.143 0-18.286-22.286-18.286-36.571v-329.143h-109.714c-20 0-36.571-16.571-36.571-36.571 0-8.571 2.857-17.143 8.571-23.429l182.857-219.429c6.857-8 17.143-12.571 28-12.571s21.143 4.571 28 12.571l182.857 219.429c5.714 6.286 8.571 14.857 8.571 23.429 0 20-16.571 36.571-36.571 36.571h-109.714v219.429h329.143c5.143 0 10.857 2.286 14.286 6.286l91.429 109.714c2.286 3.429 4 8 4 12zM1097.143 621.714c0 8.571-2.857 17.143-8.571 23.429l-182.857 219.429c-6.857 8-17.143 13.143-28 13.143s-21.143-5.143-28-13.143l-182.857-219.429c-5.714-6.286-8.571-14.857-8.571-23.429 0-20 16.571-36.571 36.571-36.571h109.714v-219.429h-329.143c-5.143 0-10.857-2.286-14.286-6.857l-91.429-109.714c-2.286-2.857-4-7.429-4-11.429 0-9.714 8.571-18.286 18.286-18.286h548.571c21.143 0 18.286 22.286 18.286 36.571v329.143h109.714c20 0 36.571 16.571 36.571 36.571z"],"width":1097.142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["retweet"],"defaultCode":61561,"grid":14},"attrs":[],"properties":{"name":"retweet","id":106,"order":117,"prevSize":28,"code":61561},"setIdx":0,"setId":1,"iconIdx":117},{"icon":{"paths":["M950.857 347.429v402.286c0 70.286-57.714 128-128 128h-694.857c-70.286 0-128-57.714-128-128v-548.571c0-70.286 57.714-128 128-128h182.857c70.286 0 128 57.714 128 128v18.286h384c70.286 0 128 57.714 128 128z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["folder"],"defaultCode":61563,"grid":14},"attrs":[],"properties":{"name":"folder","id":107,"order":119,"prevSize":28,"code":61563},"setIdx":0,"setId":1,"iconIdx":118},{"icon":{"paths":["M1073.714 544c0 13.714-8.571 27.429-17.714 37.714l-192 226.286c-33.143 38.857-100.571 69.714-150.857 69.714h-621.714c-20.571 0-49.714-6.286-49.714-32 0-13.714 8.571-27.429 17.714-37.714l192-226.286c33.143-38.857 100.571-69.714 150.857-69.714h621.714c20.571 0 49.714 6.286 49.714 32zM877.714 347.429v91.429h-475.429c-71.429 0-160 40.571-206.286 95.429l-195.429 229.714c0-4.571-0.571-9.714-0.571-14.286v-548.571c0-70.286 57.714-128 128-128h182.857c70.286 0 128 57.714 128 128v18.286h310.857c70.286 0 128 57.714 128 128z"],"width":1073.7371428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["folder-open"],"defaultCode":61564,"grid":14},"attrs":[],"properties":{"name":"folder-open","id":108,"order":120,"prevSize":28,"code":61564},"setIdx":0,"setId":1,"iconIdx":119},{"icon":{"paths":["M402.286 182.857c0 20-16.571 36.571-36.571 36.571h-73.143v585.143h73.143c20 0 36.571 16.571 36.571 36.571 0 9.714-4 18.857-10.857 25.714l-146.286 146.286c-6.857 6.857-16 10.857-25.714 10.857s-18.857-4-25.714-10.857l-146.286-146.286c-6.857-6.857-10.857-16-10.857-25.714 0-20 16.571-36.571 36.571-36.571h73.143v-585.143h-73.143c-20 0-36.571-16.571-36.571-36.571 0-9.714 4-18.857 10.857-25.714l146.286-146.286c6.857-6.857 16-10.857 25.714-10.857s18.857 4 25.714 10.857l146.286 146.286c6.857 6.857 10.857 16 10.857 25.714z"],"width":438.85714285714283,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["arrows-v"],"defaultCode":61565,"grid":14},"attrs":[],"properties":{"name":"arrows-v","id":109,"order":121,"prevSize":28,"code":61565},"setIdx":0,"setId":1,"iconIdx":120},{"icon":{"paths":["M1024 512c0 9.714-4 18.857-10.857 25.714l-146.286 146.286c-6.857 6.857-16 10.857-25.714 10.857-20 0-36.571-16.571-36.571-36.571v-73.143h-585.143v73.143c0 20-16.571 36.571-36.571 36.571-9.714 0-18.857-4-25.714-10.857l-146.286-146.286c-6.857-6.857-10.857-16-10.857-25.714s4-18.857 10.857-25.714l146.286-146.286c6.857-6.857 16-10.857 25.714-10.857 20 0 36.571 16.571 36.571 36.571v73.143h585.143v-73.143c0-20 16.571-36.571 36.571-36.571 9.714 0 18.857 4 25.714 10.857l146.286 146.286c6.857 6.857 10.857 16 10.857 25.714z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["arrows-h"],"defaultCode":61566,"grid":14},"attrs":[],"properties":{"name":"arrows-h","id":110,"order":122,"prevSize":28,"code":61566},"setIdx":0,"setId":1,"iconIdx":121},{"icon":{"paths":["M512 512c0-80.571-65.714-146.286-146.286-146.286s-146.286 65.714-146.286 146.286 65.714 146.286 146.286 146.286 146.286-65.714 146.286-146.286zM950.857 804.571c0-40-33.143-73.143-73.143-73.143s-73.143 33.143-73.143 73.143c0 40.571 33.143 73.143 73.143 73.143 40.571 0 73.143-33.143 73.143-73.143zM950.857 219.429c0-40-33.143-73.143-73.143-73.143s-73.143 33.143-73.143 73.143c0 40.571 33.143 73.143 73.143 73.143 40.571 0 73.143-33.143 73.143-73.143zM731.429 460v105.714c0 7.429-5.714 16-13.143 17.143l-88.571 13.714c-4.571 14.857-10.857 29.143-18.286 43.429 16 22.857 33.143 44 51.429 65.714 2.286 3.429 4 6.857 4 11.429 0 4-1.143 8-4 10.857-11.429 15.429-75.429 85.143-92 85.143-4.571 0-8.571-1.714-12-4l-65.714-51.429c-14.286 7.429-28.571 13.143-44 17.714-2.857 29.143-5.714 60.571-13.143 88.571-2.286 8-9.143 13.714-17.143 13.714h-106.286c-8 0-16-6.286-17.143-14.286l-13.143-87.429c-14.857-4.571-29.143-10.857-42.857-17.714l-67.429 50.857c-2.857 2.857-7.429 4-11.429 4-4.571 0-8.571-1.714-12-4.571-14.857-13.714-82.286-74.857-82.286-91.429 0-4 1.714-7.429 4-10.857 16.571-21.714 33.714-42.857 50.286-65.143-8-15.429-14.857-30.857-20-46.857l-86.857-13.714c-8-1.143-13.714-8.571-13.714-16.571v-105.714c0-7.429 5.714-16 13.143-17.143l88.571-13.714c4.571-14.857 10.857-29.143 18.286-43.429-16-22.857-33.143-44-51.429-65.714-2.286-3.429-4-7.429-4-11.429s1.143-8 4-11.429c11.429-15.429 75.429-84.571 92-84.571 4.571 0 8.571 1.714 12 4l65.714 51.429c14.286-7.429 28.571-13.143 44-18.286 2.857-28.571 5.714-60 13.143-88 2.286-8 9.143-13.714 17.143-13.714h106.286c8 0 16 6.286 17.143 14.286l13.143 87.429c14.857 4.571 29.143 10.857 42.857 17.714l67.429-50.857c3.429-2.857 7.429-4 11.429-4 4.571 0 8.571 1.714 12 4.571 14.857 13.714 82.286 75.429 82.286 91.429 0 4-1.714 7.429-4 10.857-16.571 22.286-33.714 42.857-49.714 65.143 7.429 15.429 14.286 30.857 19.429 46.857l86.857 13.143c8 1.714 13.714 9.143 13.714 17.143zM1097.143 764.571v80c0 8.571-73.714 16.571-85.143 17.714-4.571 10.857-10.286 20.571-17.143 29.714 5.143 11.429 29.143 68.571 29.143 78.857 0 1.714-0.571 2.857-2.286 4-6.857 4-68 40.571-70.857 40.571-7.429 0-50.286-57.143-56-65.714-5.714 0.571-11.429 1.143-17.143 1.143s-11.429-0.571-17.143-1.143c-5.714 8.571-48.571 65.714-56 65.714-2.857 0-64-36.571-70.857-40.571-1.714-1.143-2.286-2.857-2.286-4 0-9.714 24-67.429 29.143-78.857-6.857-9.143-12.571-18.857-17.143-29.714-11.429-1.143-85.143-9.143-85.143-17.714v-80c0-8.571 73.714-16.571 85.143-17.714 4.571-10.286 10.286-20.571 17.143-29.714-5.143-11.429-29.143-69.143-29.143-78.857 0-1.143 0.571-2.857 2.286-4 6.857-3.429 68-40 70.857-40 7.429 0 50.286 56.571 56 65.143 5.714-0.571 11.429-1.143 17.143-1.143s11.429 0.571 17.143 1.143c16-22.286 33.143-44.571 52.571-64l3.429-1.143c2.857 0 64 36 70.857 40 1.714 1.143 2.286 2.857 2.286 4 0 10.286-24 67.429-29.143 78.857 6.857 9.143 12.571 19.429 17.143 29.714 11.429 1.143 85.143 9.143 85.143 17.714zM1097.143 179.429v80c0 8.571-73.714 16.571-85.143 17.714-4.571 10.857-10.286 20.571-17.143 29.714 5.143 11.429 29.143 68.571 29.143 78.857 0 1.714-0.571 2.857-2.286 4-6.857 4-68 40.571-70.857 40.571-7.429 0-50.286-57.143-56-65.714-5.714 0.571-11.429 1.143-17.143 1.143s-11.429-0.571-17.143-1.143c-5.714 8.571-48.571 65.714-56 65.714-2.857 0-64-36.571-70.857-40.571-1.714-1.143-2.286-2.857-2.286-4 0-9.714 24-67.429 29.143-78.857-6.857-9.143-12.571-18.857-17.143-29.714-11.429-1.143-85.143-9.143-85.143-17.714v-80c0-8.571 73.714-16.571 85.143-17.714 4.571-10.286 10.286-20.571 17.143-29.714-5.143-11.429-29.143-69.143-29.143-78.857 0-1.143 0.571-2.857 2.286-4 6.857-3.429 68-40 70.857-40 7.429 0 50.286 56.571 56 65.143 5.714-0.571 11.429-1.143 17.143-1.143s11.429 0.571 17.143 1.143c16-22.286 33.143-44.571 52.571-64l3.429-1.143c2.857 0 64 36 70.857 40 1.714 1.143 2.286 2.857 2.286 4 0 10.286-24 67.429-29.143 78.857 6.857 9.143 12.571 19.429 17.143 29.714 11.429 1.143 85.143 9.143 85.143 17.714z"],"width":1097.142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["cogs","gears"],"defaultCode":61573,"grid":14},"attrs":[],"properties":{"name":"cogs, gears","id":111,"order":128,"prevSize":28,"code":61573},"setIdx":0,"setId":1,"iconIdx":122},{"icon":{"paths":["M475.429 18.286v765.143l-256.571 134.857c-7.429 4-14.857 6.857-22.857 6.857-16.571 0-24-13.714-24-28.571 0-4 0.571-7.429 1.143-11.429l49.143-285.714-208-202.286c-6.857-7.429-14.286-17.143-14.286-27.429 0-17.143 17.714-24 32-26.286l286.857-41.714 128.571-260c5.143-10.857 14.857-23.429 28-23.429v0z"],"width":475.4285714285714,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["star-half"],"defaultCode":61577,"grid":14},"attrs":[],"properties":{"name":"star-half","id":112,"order":132,"prevSize":28,"code":61577},"setIdx":0,"setId":1,"iconIdx":123},{"icon":{"paths":["M950.857 340.571c0-160.571-108.571-194.286-200-194.286-85.143 0-181.143 92-210.857 127.429-13.714 16.571-42.286 16.571-56 0-29.714-35.429-125.714-127.429-210.857-127.429-91.429 0-200 33.714-200 194.286 0 104.571 105.714 201.714 106.857 202.857l332 320 331.429-319.429c1.714-1.714 107.429-98.857 107.429-203.429zM1024 340.571c0 137.143-125.714 252-130.857 257.143l-356 342.857c-6.857 6.857-16 10.286-25.143 10.286s-18.286-3.429-25.143-10.286l-356.571-344c-4.571-4-130.286-118.857-130.286-256 0-167.429 102.286-267.429 273.143-267.429 100 0 193.714 78.857 238.857 123.429 45.143-44.571 138.857-123.429 238.857-123.429 170.857 0 273.143 100 273.143 267.429z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["heart-o"],"defaultCode":61578,"grid":14},"attrs":[],"properties":{"name":"heart-o","id":113,"order":133,"prevSize":28,"code":61578},"setIdx":0,"setId":1,"iconIdx":124},{"icon":{"paths":["M365.714 822.857c0 16 7.429 54.857-18.286 54.857h-182.857c-90.857 0-164.571-73.714-164.571-164.571v-402.286c0-90.857 73.714-164.571 164.571-164.571h182.857c9.714 0 18.286 8.571 18.286 18.286 0 16 7.429 54.857-18.286 54.857h-182.857c-50.286 0-91.429 41.143-91.429 91.429v402.286c0 50.286 41.143 91.429 91.429 91.429h164.571c14.286 0 36.571-2.857 36.571 18.286zM896 512c0 9.714-4 18.857-10.857 25.714l-310.857 310.857c-6.857 6.857-16 10.857-25.714 10.857-20 0-36.571-16.571-36.571-36.571v-164.571h-256c-20 0-36.571-16.571-36.571-36.571v-219.429c0-20 16.571-36.571 36.571-36.571h256v-164.571c0-20 16.571-36.571 36.571-36.571 9.714 0 18.857 4 25.714 10.857l310.857 310.857c6.857 6.857 10.857 16 10.857 25.714z"],"width":896,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["sign-out"],"defaultCode":61579,"grid":14},"attrs":[],"properties":{"name":"sign-out","id":114,"order":134,"prevSize":28,"code":61579},"setIdx":0,"setId":1,"iconIdx":125},{"icon":{"paths":["M274.286 493.714v-256c0-10.286-8-18.286-18.286-18.286s-18.286 8-18.286 18.286v256c0 10.286 8 18.286 18.286 18.286s18.286-8 18.286-18.286zM658.286 694.857c0 20-16.571 36.571-36.571 36.571h-245.143l-29.143 276c-1.143 9.143-8.571 16.571-17.714 16.571h-0.571c-9.143 0-16.571-6.286-18.286-15.429l-43.429-277.143h-230.857c-20 0-36.571-16.571-36.571-36.571 0-93.714 70.857-182.857 146.286-182.857v-292.571c-40 0-73.143-33.143-73.143-73.143s33.143-73.143 73.143-73.143h365.714c40 0 73.143 33.143 73.143 73.143s-33.143 73.143-73.143 73.143v292.571c75.429 0 146.286 89.143 146.286 182.857z"],"width":658.2857142857142,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["thumb-tack"],"defaultCode":61581,"grid":14},"attrs":[],"properties":{"name":"thumb-tack","id":115,"order":136,"prevSize":28,"code":61581},"setIdx":0,"setId":1,"iconIdx":126},{"icon":{"paths":["M804.571 530.286v182.857c0 90.857-73.714 164.571-164.571 164.571h-475.429c-90.857 0-164.571-73.714-164.571-164.571v-475.429c0-90.857 73.714-164.571 164.571-164.571h402.286c10.286 0 18.286 8 18.286 18.286v36.571c0 10.286-8 18.286-18.286 18.286h-402.286c-50.286 0-91.429 41.143-91.429 91.429v475.429c0 50.286 41.143 91.429 91.429 91.429h475.429c50.286 0 91.429-41.143 91.429-91.429v-182.857c0-10.286 8-18.286 18.286-18.286h36.571c10.286 0 18.286 8 18.286 18.286zM1024 36.571v292.571c0 20-16.571 36.571-36.571 36.571-9.714 0-18.857-4-25.714-10.857l-100.571-100.571-372.571 372.571c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-65.143-65.143c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l372.571-372.571-100.571-100.571c-6.857-6.857-10.857-16-10.857-25.714 0-20 16.571-36.571 36.571-36.571h292.571c20 0 36.571 16.571 36.571 36.571z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["external-link"],"defaultCode":61582,"grid":14},"attrs":[],"properties":{"name":"external-link","id":116,"order":137,"prevSize":28,"code":61582},"setIdx":0,"setId":1,"iconIdx":127},{"icon":{"paths":["M676.571 512c0 9.714-4 18.857-10.857 25.714l-310.857 310.857c-6.857 6.857-16 10.857-25.714 10.857-20 0-36.571-16.571-36.571-36.571v-164.571h-256c-20 0-36.571-16.571-36.571-36.571v-219.429c0-20 16.571-36.571 36.571-36.571h256v-164.571c0-20 16.571-36.571 36.571-36.571 9.714 0 18.857 4 25.714 10.857l310.857 310.857c6.857 6.857 10.857 16 10.857 25.714zM877.714 310.857v402.286c0 90.857-73.714 164.571-164.571 164.571h-182.857c-9.714 0-18.286-8.571-18.286-18.286 0-16-7.429-54.857 18.286-54.857h182.857c50.286 0 91.429-41.143 91.429-91.429v-402.286c0-50.286-41.143-91.429-91.429-91.429h-164.571c-14.286 0-36.571 2.857-36.571-18.286 0-16-7.429-54.857 18.286-54.857h182.857c90.857 0 164.571 73.714 164.571 164.571z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["sign-in"],"defaultCode":61584,"grid":14},"attrs":[],"properties":{"name":"sign-in","id":117,"order":138,"prevSize":28,"code":61584},"setIdx":0,"setId":1,"iconIdx":128},{"icon":{"paths":["M731.429 841.143c0-20-16.571-36.571-36.571-36.571s-36.571 16.571-36.571 36.571 16.571 36.571 36.571 36.571 36.571-16.571 36.571-36.571zM877.714 841.143c0-20-16.571-36.571-36.571-36.571s-36.571 16.571-36.571 36.571 16.571 36.571 36.571 36.571 36.571-16.571 36.571-36.571zM950.857 713.143v182.857c0 30.286-24.571 54.857-54.857 54.857h-841.143c-30.286 0-54.857-24.571-54.857-54.857v-182.857c0-30.286 24.571-54.857 54.857-54.857h244c15.429 42.286 56 73.143 103.429 73.143h146.286c47.429 0 88-30.857 103.429-73.143h244c30.286 0 54.857 24.571 54.857 54.857zM765.143 342.857c-5.714 13.714-18.857 22.857-33.714 22.857h-146.286v256c0 20-16.571 36.571-36.571 36.571h-146.286c-20 0-36.571-16.571-36.571-36.571v-256h-146.286c-14.857 0-28-9.143-33.714-22.857-5.714-13.143-2.857-29.143 8-39.429l256-256c6.857-7.429 16.571-10.857 25.714-10.857s18.857 3.429 25.714 10.857l256 256c10.857 10.286 13.714 26.286 8 39.429z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["upload"],"defaultCode":61587,"grid":14},"attrs":[],"properties":{"name":"upload","id":118,"order":141,"prevSize":28,"code":61587},"setIdx":0,"setId":1,"iconIdx":129},{"icon":{"paths":["M640 146.286h-475.429c-50.286 0-91.429 41.143-91.429 91.429v475.429c0 50.286 41.143 91.429 91.429 91.429h475.429c50.286 0 91.429-41.143 91.429-91.429v-475.429c0-50.286-41.143-91.429-91.429-91.429zM804.571 237.714v475.429c0 90.857-73.714 164.571-164.571 164.571h-475.429c-90.857 0-164.571-73.714-164.571-164.571v-475.429c0-90.857 73.714-164.571 164.571-164.571h475.429c90.857 0 164.571 73.714 164.571 164.571z"],"width":804.5714285714286,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["square-o"],"defaultCode":61590,"grid":14},"attrs":[],"properties":{"name":"square-o","id":119,"order":144,"prevSize":28,"code":61590},"setIdx":0,"setId":1,"iconIdx":130},{"icon":{"paths":["M658.286 146.286h-585.143v709.714l292.571-280.571 50.857 48.571 241.714 232v-709.714zM665.143 73.143c8.571 0 17.143 1.714 25.143 5.143 25.143 9.714 41.143 33.143 41.143 58.857v736.571c0 25.714-16 49.143-41.143 58.857-8 3.429-16.571 4.571-25.143 4.571-17.714 0-34.286-6.286-47.429-18.286l-252-242.286-252 242.286c-13.143 12-29.714 18.857-47.429 18.857-8.571 0-17.143-1.714-25.143-5.143-25.143-9.714-41.143-33.143-41.143-58.857v-736.571c0-25.714 16-49.143 41.143-58.857 8-3.429 16.571-5.143 25.143-5.143h598.857z"],"width":731.4285714285713,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["bookmark-o"],"defaultCode":61591,"grid":14},"attrs":[],"properties":{"name":"bookmark-o","id":120,"order":145,"prevSize":28,"code":61591},"setIdx":0,"setId":1,"iconIdx":131},{"icon":{"paths":["M594.286 694.857c0 25.143-20.571 45.714-45.714 45.714s-45.714-20.571-45.714-45.714 20.571-45.714 45.714-45.714 45.714 20.571 45.714 45.714zM740.571 694.857c0 25.143-20.571 45.714-45.714 45.714s-45.714-20.571-45.714-45.714 20.571-45.714 45.714-45.714 45.714 20.571 45.714 45.714zM804.571 786.286v-182.857c0-9.714-8.571-18.286-18.286-18.286h-694.857c-9.714 0-18.286 8.571-18.286 18.286v182.857c0 9.714 8.571 18.286 18.286 18.286h694.857c9.714 0 18.286-8.571 18.286-18.286zM101.714 512h674.286l-89.714-275.429c-2.857-9.714-13.714-17.143-24-17.143h-446.857c-10.286 0-21.143 7.429-24 17.143zM877.714 603.429v182.857c0 50.286-41.143 91.429-91.429 91.429h-694.857c-50.286 0-91.429-41.143-91.429-91.429v-182.857c0-15.429 4.571-28.571 9.143-42.857l112.571-346.286c13.143-40 51.429-68 93.714-68h446.857c42.286 0 80.571 28 93.714 68l112.571 346.286c4.571 14.286 9.143 27.429 9.143 42.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["hdd-o"],"defaultCode":61600,"grid":14},"attrs":[],"properties":{"name":"hdd-o","id":121,"order":153,"prevSize":28,"code":61600},"setIdx":0,"setId":1,"iconIdx":132},{"icon":{"paths":["M521.143 969.143c0-5.143-4-9.143-9.143-9.143-45.143 0-82.286-37.143-82.286-82.286 0-5.143-4-9.143-9.143-9.143s-9.143 4-9.143 9.143c0 55.429 45.143 100.571 100.571 100.571 5.143 0 9.143-4 9.143-9.143zM140.571 804.571h742.857c-102.286-115.429-152-272-152-475.429 0-73.714-69.714-182.857-219.429-182.857s-219.429 109.143-219.429 182.857c0 203.429-49.714 360-152 475.429zM987.429 804.571c0 40-33.143 73.143-73.143 73.143h-256c0 80.571-65.714 146.286-146.286 146.286s-146.286-65.714-146.286-146.286h-256c-40 0-73.143-33.143-73.143-73.143 84.571-71.429 182.857-199.429 182.857-475.429 0-109.714 90.857-229.714 242.286-252-2.857-6.857-4.571-14.286-4.571-22.286 0-30.286 24.571-54.857 54.857-54.857s54.857 24.571 54.857 54.857c0 8-1.714 15.429-4.571 22.286 151.429 22.286 242.286 142.286 242.286 252 0 276 98.286 404 182.857 475.429z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["bell-o"],"defaultCode":61602,"grid":14},"attrs":[],"properties":{"name":"bell-o","id":122,"order":686,"prevSize":28,"code":61602},"setIdx":0,"setId":1,"iconIdx":133},{"icon":{"paths":["M786.286 512l78.857 77.143c10.857 10.286 14.857 25.714 11.429 40-4 14.286-15.429 25.714-29.714 29.143l-107.429 27.429 30.286 106.286c4 14.286 0 29.714-10.857 40-10.286 10.857-25.714 14.857-40 10.857l-106.286-30.286-27.429 107.429c-3.429 14.286-14.857 25.714-29.143 29.714-3.429 0.571-7.429 1.143-10.857 1.143-10.857 0-21.714-4.571-29.143-12.571l-77.143-78.857-77.143 78.857c-10.286 10.857-25.714 14.857-40 11.429-14.857-4-25.714-15.429-29.143-29.714l-27.429-107.429-106.286 30.286c-14.286 4-29.714 0-40-10.857-10.857-10.286-14.857-25.714-10.857-40l30.286-106.286-107.429-27.429c-14.286-3.429-25.714-14.857-29.714-29.143-3.429-14.286 0.571-29.714 11.429-40l78.857-77.143-78.857-77.143c-10.857-10.286-14.857-25.714-11.429-40 4-14.286 15.429-25.714 29.714-29.143l107.429-27.429-30.286-106.286c-4-14.286 0-29.714 10.857-40 10.286-10.857 25.714-14.857 40-10.857l106.286 30.286 27.429-107.429c3.429-14.286 14.857-25.714 29.143-29.143 14.286-4 29.714 0 40 10.857l77.143 79.429 77.143-79.429c10.286-10.857 25.143-14.857 40-10.857 14.286 3.429 25.714 14.857 29.143 29.143l27.429 107.429 106.286-30.286c14.286-4 29.714 0 40 10.857 10.857 10.286 14.857 25.714 10.857 40l-30.286 106.286 107.429 27.429c14.286 3.429 25.714 14.857 29.714 29.143 3.429 14.286-0.571 29.714-11.429 40z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["certificate"],"defaultCode":61603,"grid":14},"attrs":[],"properties":{"name":"certificate","id":123,"order":687,"prevSize":28,"code":61603},"setIdx":0,"setId":1,"iconIdx":134},{"icon":{"paths":["M731.429 548.571v-73.143c0-20-16.571-36.571-36.571-36.571h-286.857l108-108c6.857-6.857 10.857-16 10.857-25.714s-4-18.857-10.857-25.714l-52-52c-6.857-6.857-16-10.286-25.714-10.286s-18.857 3.429-25.714 10.286l-258.857 258.857c-6.857 6.857-10.286 16-10.286 25.714s3.429 18.857 10.286 25.714l258.857 258.857c6.857 6.857 16 10.286 25.714 10.286s18.857-3.429 25.714-10.286l52-52c6.857-6.857 10.286-16 10.286-25.714s-3.429-18.857-10.286-25.714l-108-108h286.857c20 0 36.571-16.571 36.571-36.571zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["arrow-circle-left"],"defaultCode":61608,"grid":14},"attrs":[],"properties":{"name":"arrow-circle-left","id":124,"order":161,"prevSize":28,"code":61608},"setIdx":0,"setId":1,"iconIdx":135},{"icon":{"paths":["M734.286 512c0-9.714-3.429-18.857-10.286-25.714l-258.857-258.857c-6.857-6.857-16-10.286-25.714-10.286s-18.857 3.429-25.714 10.286l-52 52c-6.857 6.857-10.286 16-10.286 25.714s3.429 18.857 10.286 25.714l108 108h-286.857c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h286.857l-108 108c-6.857 6.857-10.857 16-10.857 25.714s4 18.857 10.857 25.714l52 52c6.857 6.857 16 10.286 25.714 10.286s18.857-3.429 25.714-10.286l258.857-258.857c6.857-6.857 10.286-16 10.286-25.714zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["arrow-circle-right"],"defaultCode":61609,"grid":14},"attrs":[],"properties":{"name":"arrow-circle-right","id":125,"order":162,"prevSize":28,"code":61609},"setIdx":0,"setId":1,"iconIdx":136},{"icon":{"paths":["M733.714 511.429c0-9.714-3.429-18.857-10.286-25.714l-258.857-258.857c-6.857-6.857-16-10.286-25.714-10.286s-18.857 3.429-25.714 10.286l-258.857 258.857c-6.857 6.857-10.286 16-10.286 25.714s3.429 18.857 10.286 25.714l52 52c6.857 6.857 16 10.286 25.714 10.286s18.857-3.429 25.714-10.286l108-108v286.857c0 20 16.571 36.571 36.571 36.571h73.143c20 0 36.571-16.571 36.571-36.571v-286.857l108 108c6.857 6.857 16 10.857 25.714 10.857s18.857-4 25.714-10.857l52-52c6.857-6.857 10.286-16 10.286-25.714zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["arrow-circle-up"],"defaultCode":61610,"grid":14},"attrs":[],"properties":{"name":"arrow-circle-up","id":126,"order":163,"prevSize":28,"code":61610},"setIdx":0,"setId":1,"iconIdx":137},{"icon":{"paths":["M733.714 512.571c0-9.714-3.429-18.857-10.286-25.714l-52-52c-6.857-6.857-16-10.286-25.714-10.286s-18.857 3.429-25.714 10.286l-108 108v-286.857c0-20-16.571-36.571-36.571-36.571h-73.143c-20 0-36.571 16.571-36.571 36.571v286.857l-108-108c-6.857-6.857-16-10.857-25.714-10.857s-18.857 4-25.714 10.857l-52 52c-6.857 6.857-10.286 16-10.286 25.714s3.429 18.857 10.286 25.714l258.857 258.857c6.857 6.857 16 10.286 25.714 10.286s18.857-3.429 25.714-10.286l258.857-258.857c6.857-6.857 10.286-16 10.286-25.714zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["arrow-circle-down"],"defaultCode":61611,"grid":14},"attrs":[],"properties":{"name":"arrow-circle-down","id":127,"order":164,"prevSize":28,"code":61611},"setIdx":0,"setId":1,"iconIdx":138},{"icon":{"paths":["M219.429 841.143c0-20-16.571-36.571-36.571-36.571s-36.571 16.571-36.571 36.571 16.571 36.571 36.571 36.571 36.571-16.571 36.571-36.571zM587.429 601.143l-389.714 389.714c-13.143 13.143-32 21.143-51.429 21.143s-38.286-8-52-21.143l-60.571-61.714c-13.714-13.143-21.714-32-21.714-51.429s8-38.286 21.714-52l389.143-389.143c29.714 74.857 89.714 134.857 164.571 164.571zM949.714 352.571c0 18.857-6.857 42.286-13.143 60.571-36 101.714-133.714 172-241.714 172-141.143 0-256-114.857-256-256s114.857-256 256-256c41.714 0 96 12.571 130.857 36 5.714 4 9.143 9.143 9.143 16 0 6.286-4 12.571-9.143 16l-167.429 96.571v128l110.286 61.143c18.857-10.857 151.429-94.286 162.857-94.286s18.286 8.571 18.286 20z"],"width":961.6822857142856,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["wrench"],"defaultCode":61613,"grid":14},"attrs":[],"properties":{"name":"wrench","id":128,"order":166,"prevSize":28,"code":61613},"setIdx":0,"setId":1,"iconIdx":139},{"icon":{"paths":["M585.143 804.571h365.714v-73.143h-365.714v73.143zM365.714 512h585.143v-73.143h-585.143v73.143zM731.429 219.429h219.429v-73.143h-219.429v73.143zM1024 694.857v146.286c0 20-16.571 36.571-36.571 36.571h-950.857c-20 0-36.571-16.571-36.571-36.571v-146.286c0-20 16.571-36.571 36.571-36.571h950.857c20 0 36.571 16.571 36.571 36.571zM1024 402.286v146.286c0 20-16.571 36.571-36.571 36.571h-950.857c-20 0-36.571-16.571-36.571-36.571v-146.286c0-20 16.571-36.571 36.571-36.571h950.857c20 0 36.571 16.571 36.571 36.571zM1024 109.714v146.286c0 20-16.571 36.571-36.571 36.571h-950.857c-20 0-36.571-16.571-36.571-36.571v-146.286c0-20 16.571-36.571 36.571-36.571h950.857c20 0 36.571 16.571 36.571 36.571z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["tasks"],"defaultCode":61614,"grid":14},"attrs":[],"properties":{"name":"tasks","id":129,"order":167,"prevSize":28,"code":61614},"setIdx":0,"setId":1,"iconIdx":140},{"icon":{"paths":["M801.714 168.571c5.714 13.714 2.857 29.714-8 40l-281.714 281.714v424c0 14.857-9.143 28-22.286 33.714-4.571 1.714-9.714 2.857-14.286 2.857-9.714 0-18.857-3.429-25.714-10.857l-146.286-146.286c-6.857-6.857-10.857-16-10.857-25.714v-277.714l-281.714-281.714c-10.857-10.286-13.714-26.286-8-40 5.714-13.143 18.857-22.286 33.714-22.286h731.429c14.857 0 28 9.143 33.714 22.286z"],"width":804.5714285714286,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["filter"],"defaultCode":61616,"grid":14},"attrs":[],"properties":{"name":"filter","id":130,"order":168,"prevSize":28,"code":61616},"setIdx":0,"setId":1,"iconIdx":141},{"icon":{"paths":["M365.714 146.286h292.571v-73.143h-292.571v73.143zM1024 512v274.286c0 50.286-41.143 91.429-91.429 91.429h-841.143c-50.286 0-91.429-41.143-91.429-91.429v-274.286h384v91.429c0 20 16.571 36.571 36.571 36.571h182.857c20 0 36.571-16.571 36.571-36.571v-91.429h384zM585.143 512v73.143h-146.286v-73.143h146.286zM1024 237.714v219.429h-1024v-219.429c0-50.286 41.143-91.429 91.429-91.429h201.143v-91.429c0-30.286 24.571-54.857 54.857-54.857h329.143c30.286 0 54.857 24.571 54.857 54.857v91.429h201.143c50.286 0 91.429 41.143 91.429 91.429z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["briefcase"],"defaultCode":61617,"grid":14},"attrs":[],"properties":{"name":"briefcase","id":131,"order":169,"prevSize":28,"code":61617},"setIdx":0,"setId":1,"iconIdx":142},{"icon":{"paths":["M733.143 309.143l-202.857 202.857 202.857 202.857 82.286-82.286c10.286-10.857 26.286-13.714 40-8 13.143 5.714 22.286 18.857 22.286 33.714v256c0 20-16.571 36.571-36.571 36.571h-256c-14.857 0-28-9.143-33.714-22.857-5.714-13.143-2.857-29.143 8-39.429l82.286-82.286-202.857-202.857-202.857 202.857 82.286 82.286c10.857 10.286 13.714 26.286 8 39.429-5.714 13.714-18.857 22.857-33.714 22.857h-256c-20 0-36.571-16.571-36.571-36.571v-256c0-14.857 9.143-28 22.857-33.714 13.143-5.714 29.143-2.857 39.429 8l82.286 82.286 202.857-202.857-202.857-202.857-82.286 82.286c-6.857 6.857-16 10.857-25.714 10.857-4.571 0-9.714-1.143-13.714-2.857-13.714-5.714-22.857-18.857-22.857-33.714v-256c0-20 16.571-36.571 36.571-36.571h256c14.857 0 28 9.143 33.714 22.857 5.714 13.143 2.857 29.143-8 39.429l-82.286 82.286 202.857 202.857 202.857-202.857-82.286-82.286c-10.857-10.286-13.714-26.286-8-39.429 5.714-13.714 18.857-22.857 33.714-22.857h256c20 0 36.571 16.571 36.571 36.571v256c0 14.857-9.143 28-22.286 33.714-4.571 1.714-9.714 2.857-14.286 2.857-9.714 0-18.857-4-25.714-10.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["arrows-alt"],"defaultCode":61618,"grid":14},"attrs":[],"properties":{"name":"arrows-alt","id":132,"order":170,"prevSize":28,"code":61618},"setIdx":0,"setId":1,"iconIdx":143},{"icon":{"paths":["M1097.143 658.286c0 121.143-98.286 219.429-219.429 219.429h-621.714c-141.143 0-256-114.857-256-256 0-102.286 60.571-190.857 147.429-231.429-0.571-8-1.143-16.571-1.143-24.571 0-161.714 130.857-292.571 292.571-292.571 122.286 0 226.857 74.857 270.857 181.714 25.143-22.286 58.286-35.429 94.857-35.429 80.571 0 146.286 65.714 146.286 146.286 0 29.143-8.571 56-23.429 78.857 97.143 22.857 169.714 109.714 169.714 213.714z"],"width":1097.142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["cloud"],"defaultCode":61634,"grid":14},"attrs":[],"properties":{"name":"cloud","id":133,"order":173,"prevSize":28,"code":61634},"setIdx":0,"setId":1,"iconIdx":144},{"icon":{"paths":["M969.143 219.429c30.286 0 54.857 24.571 54.857 54.857v694.857c0 30.286-24.571 54.857-54.857 54.857h-548.571c-30.286 0-54.857-24.571-54.857-54.857v-164.571h-310.857c-30.286 0-54.857-24.571-54.857-54.857v-384c0-30.286 17.714-72.571 38.857-93.714l233.143-233.143c21.143-21.143 63.429-38.857 93.714-38.857h237.714c30.286 0 54.857 24.571 54.857 54.857v187.429c22.286-13.143 50.857-22.857 73.143-22.857h237.714zM658.286 341.143l-170.857 170.857h170.857v-170.857zM292.571 121.714l-170.857 170.857h170.857v-170.857zM404.571 491.429l180.571-180.571v-237.714h-219.429v237.714c0 30.286-24.571 54.857-54.857 54.857h-237.714v365.714h292.571v-146.286c0-30.286 17.714-72.571 38.857-93.714zM950.857 950.857v-658.286h-219.429v237.714c0 30.286-24.571 54.857-54.857 54.857h-237.714v365.714h512z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["copy","files-o"],"defaultCode":61637,"grid":14},"attrs":[],"properties":{"name":"copy, files-o","id":134,"order":176,"prevSize":28,"code":61637},"setIdx":0,"setId":1,"iconIdx":145},{"icon":{"paths":["M219.429 877.714h438.857v-219.429h-438.857v219.429zM731.429 877.714h73.143v-512c0-10.857-9.714-34.286-17.143-41.714l-160.571-160.571c-8-8-30.286-17.143-41.714-17.143v237.714c0 30.286-24.571 54.857-54.857 54.857h-329.143c-30.286 0-54.857-24.571-54.857-54.857v-237.714h-73.143v731.429h73.143v-237.714c0-30.286 24.571-54.857 54.857-54.857h475.429c30.286 0 54.857 24.571 54.857 54.857v237.714zM512 347.429v-182.857c0-9.714-8.571-18.286-18.286-18.286h-109.714c-9.714 0-18.286 8.571-18.286 18.286v182.857c0 9.714 8.571 18.286 18.286 18.286h109.714c9.714 0 18.286-8.571 18.286-18.286zM877.714 365.714v530.286c0 30.286-24.571 54.857-54.857 54.857h-768c-30.286 0-54.857-24.571-54.857-54.857v-768c0-30.286 24.571-54.857 54.857-54.857h530.286c30.286 0 72 17.143 93.714 38.857l160 160c21.714 21.714 38.857 63.429 38.857 93.714z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["floppy-o","save"],"defaultCode":61639,"grid":14},"attrs":[],"properties":{"name":"floppy-o, save","id":135,"order":178,"prevSize":28,"code":61639},"setIdx":0,"setId":1,"iconIdx":146},{"icon":{"paths":["M877.714 237.714v548.571c0 90.857-73.714 164.571-164.571 164.571h-548.571c-90.857 0-164.571-73.714-164.571-164.571v-548.571c0-90.857 73.714-164.571 164.571-164.571h548.571c90.857 0 164.571 73.714 164.571 164.571z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["square"],"defaultCode":61640,"grid":14},"attrs":[],"properties":{"name":"square","id":136,"order":179,"prevSize":28,"code":61640},"setIdx":0,"setId":1,"iconIdx":147},{"icon":{"paths":["M877.714 768v73.143c0 20-16.571 36.571-36.571 36.571h-804.571c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h804.571c20 0 36.571 16.571 36.571 36.571zM877.714 475.429v73.143c0 20-16.571 36.571-36.571 36.571h-804.571c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h804.571c20 0 36.571 16.571 36.571 36.571zM877.714 182.857v73.143c0 20-16.571 36.571-36.571 36.571h-804.571c-20 0-36.571-16.571-36.571-36.571v-73.143c0-20 16.571-36.571 36.571-36.571h804.571c20 0 36.571 16.571 36.571 36.571z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["bars","navicon","reorder"],"defaultCode":61641,"grid":14},"attrs":[],"properties":{"name":"bars, navicon, reorder","id":137,"order":180,"prevSize":28,"code":61641},"setIdx":0,"setId":1,"iconIdx":148},{"icon":{"paths":["M219.429 804.571c0 60.571-49.143 109.714-109.714 109.714s-109.714-49.143-109.714-109.714 49.143-109.714 109.714-109.714 109.714 49.143 109.714 109.714zM219.429 512c0 60.571-49.143 109.714-109.714 109.714s-109.714-49.143-109.714-109.714 49.143-109.714 109.714-109.714 109.714 49.143 109.714 109.714zM1024 749.714v109.714c0 9.714-8.571 18.286-18.286 18.286h-694.857c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h694.857c9.714 0 18.286 8.571 18.286 18.286zM219.429 219.429c0 60.571-49.143 109.714-109.714 109.714s-109.714-49.143-109.714-109.714 49.143-109.714 109.714-109.714 109.714 49.143 109.714 109.714zM1024 457.143v109.714c0 9.714-8.571 18.286-18.286 18.286h-694.857c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h694.857c9.714 0 18.286 8.571 18.286 18.286zM1024 164.571v109.714c0 9.714-8.571 18.286-18.286 18.286h-694.857c-9.714 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8.571-18.286 18.286-18.286h694.857c9.714 0 18.286 8.571 18.286 18.286z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["list-ul"],"defaultCode":61642,"grid":14},"attrs":[],"properties":{"name":"list-ul","id":138,"order":181,"prevSize":28,"code":61642},"setIdx":0,"setId":1,"iconIdx":149},{"icon":{"paths":["M217.714 925.714c0 62.857-49.143 98.286-108.571 98.286-36 0-72.571-12-98.286-37.714l32.571-50.286c15.429 14.286 38.857 25.714 60.571 25.714 20 0 41.143-9.714 41.143-32.571 0-32-36.571-33.714-60-32l-14.857-32c20.571-26.286 39.429-55.429 64-77.714v-0.571c-18.286 0-37.143 1.143-55.429 1.143v30.286h-60.571v-86.857h190.286v50.286l-54.286 65.714c38.286 9.143 63.429 38.857 63.429 78.286zM218.857 567.429v90.857h-206.857c-1.714-10.286-3.429-20.571-3.429-30.857 0-105.714 129.143-121.714 129.143-169.714 0-19.429-12-29.714-30.857-29.714-20 0-36.571 17.143-46.286 33.143l-48.571-33.714c18.857-39.429 57.714-61.714 101.143-61.714 53.143 0 98.857 31.429 98.857 88 0 84.571-124 103.429-125.714 148h72.571v-34.286h60zM1024 749.714v109.714c0 9.714-8.571 18.286-18.286 18.286h-694.857c-10.286 0-18.286-8.571-18.286-18.286v-109.714c0-10.286 8-18.286 18.286-18.286h694.857c9.714 0 18.286 8 18.286 18.286zM219.429 236v56.571h-191.429v-56.571h61.143c0-46.286 0.571-92.571 0.571-138.857v-6.857h-1.143c-6.286 12.571-17.714 21.143-28.571 30.857l-40.571-43.429 77.714-72.571h60.571v230.857h61.714zM1024 457.143v109.714c0 9.714-8.571 18.286-18.286 18.286h-694.857c-10.286 0-18.286-8.571-18.286-18.286v-109.714c0-10.286 8-18.286 18.286-18.286h694.857c9.714 0 18.286 8 18.286 18.286zM1024 164.571v109.714c0 9.714-8.571 18.286-18.286 18.286h-694.857c-10.286 0-18.286-8.571-18.286-18.286v-109.714c0-9.714 8-18.286 18.286-18.286h694.857c9.714 0 18.286 8.571 18.286 18.286z"],"width":1032.5577142857144,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["list-ol"],"defaultCode":61643,"grid":14},"attrs":[],"properties":{"name":"list-ol","id":139,"order":182,"prevSize":28,"code":61643},"setIdx":0,"setId":1,"iconIdx":150},{"icon":{"paths":["M292.571 786.286v-109.714c0-10.286-8-18.286-18.286-18.286h-182.857c-10.286 0-18.286 8-18.286 18.286v109.714c0 10.286 8 18.286 18.286 18.286h182.857c10.286 0 18.286-8 18.286-18.286zM292.571 566.857v-109.714c0-10.286-8-18.286-18.286-18.286h-182.857c-10.286 0-18.286 8-18.286 18.286v109.714c0 10.286 8 18.286 18.286 18.286h182.857c10.286 0 18.286-8 18.286-18.286zM585.143 786.286v-109.714c0-10.286-8-18.286-18.286-18.286h-182.857c-10.286 0-18.286 8-18.286 18.286v109.714c0 10.286 8 18.286 18.286 18.286h182.857c10.286 0 18.286-8 18.286-18.286zM292.571 347.429v-109.714c0-10.286-8-18.286-18.286-18.286h-182.857c-10.286 0-18.286 8-18.286 18.286v109.714c0 10.286 8 18.286 18.286 18.286h182.857c10.286 0 18.286-8 18.286-18.286zM585.143 566.857v-109.714c0-10.286-8-18.286-18.286-18.286h-182.857c-10.286 0-18.286 8-18.286 18.286v109.714c0 10.286 8 18.286 18.286 18.286h182.857c10.286 0 18.286-8 18.286-18.286zM877.714 786.286v-109.714c0-10.286-8-18.286-18.286-18.286h-182.857c-10.286 0-18.286 8-18.286 18.286v109.714c0 10.286 8 18.286 18.286 18.286h182.857c10.286 0 18.286-8 18.286-18.286zM585.143 347.429v-109.714c0-10.286-8-18.286-18.286-18.286h-182.857c-10.286 0-18.286 8-18.286 18.286v109.714c0 10.286 8 18.286 18.286 18.286h182.857c10.286 0 18.286-8 18.286-18.286zM877.714 566.857v-109.714c0-10.286-8-18.286-18.286-18.286h-182.857c-10.286 0-18.286 8-18.286 18.286v109.714c0 10.286 8 18.286 18.286 18.286h182.857c10.286 0 18.286-8 18.286-18.286zM877.714 347.429v-109.714c0-10.286-8-18.286-18.286-18.286h-182.857c-10.286 0-18.286 8-18.286 18.286v109.714c0 10.286 8 18.286 18.286 18.286h182.857c10.286 0 18.286-8 18.286-18.286zM950.857 164.571v621.714c0 50.286-41.143 91.429-91.429 91.429h-768c-50.286 0-91.429-41.143-91.429-91.429v-621.714c0-50.286 41.143-91.429 91.429-91.429h768c50.286 0 91.429 41.143 91.429 91.429z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["table"],"defaultCode":61646,"grid":14},"attrs":[],"properties":{"name":"table","id":140,"order":185,"prevSize":28,"code":61646},"setIdx":0,"setId":1,"iconIdx":151},{"icon":{"paths":["M585.143 402.286c0 9.714-4 18.857-10.857 25.714l-256 256c-6.857 6.857-16 10.857-25.714 10.857s-18.857-4-25.714-10.857l-256-256c-6.857-6.857-10.857-16-10.857-25.714 0-20 16.571-36.571 36.571-36.571h512c20 0 36.571 16.571 36.571 36.571z"],"width":585.1428571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["caret-down"],"defaultCode":61655,"grid":14},"attrs":[],"properties":{"name":"caret-down","id":141,"order":193,"prevSize":28,"code":61655},"setIdx":0,"setId":1,"iconIdx":152},{"icon":{"paths":["M585.143 694.857c0 20-16.571 36.571-36.571 36.571h-512c-20 0-36.571-16.571-36.571-36.571 0-9.714 4-18.857 10.857-25.714l256-256c6.857-6.857 16-10.857 25.714-10.857s18.857 4 25.714 10.857l256 256c6.857 6.857 10.857 16 10.857 25.714z"],"width":585.1428571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["caret-up"],"defaultCode":61656,"grid":14},"attrs":[],"properties":{"name":"caret-up","id":142,"order":194,"prevSize":28,"code":61656},"setIdx":0,"setId":1,"iconIdx":153},{"icon":{"paths":["M365.714 256v512c0 20-16.571 36.571-36.571 36.571-9.714 0-18.857-4-25.714-10.857l-256-256c-6.857-6.857-10.857-16-10.857-25.714s4-18.857 10.857-25.714l256-256c6.857-6.857 16-10.857 25.714-10.857 20 0 36.571 16.571 36.571 36.571z"],"width":402.2857142857143,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["caret-left"],"defaultCode":61657,"grid":14},"attrs":[],"properties":{"name":"caret-left","id":143,"order":195,"prevSize":28,"code":61657},"setIdx":0,"setId":1,"iconIdx":154},{"icon":{"paths":["M329.143 512c0 9.714-4 18.857-10.857 25.714l-256 256c-6.857 6.857-16 10.857-25.714 10.857-20 0-36.571-16.571-36.571-36.571v-512c0-20 16.571-36.571 36.571-36.571 9.714 0 18.857 4 25.714 10.857l256 256c6.857 6.857 10.857 16 10.857 25.714z"],"width":329.1428571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["caret-right"],"defaultCode":61658,"grid":14},"attrs":[],"properties":{"name":"caret-right","id":144,"order":196,"prevSize":28,"code":61658},"setIdx":0,"setId":1,"iconIdx":155},{"icon":{"paths":["M91.429 877.714h347.429v-658.286h-365.714v640c0 9.714 8.571 18.286 18.286 18.286zM877.714 859.429v-640h-365.714v658.286h347.429c9.714 0 18.286-8.571 18.286-18.286zM950.857 164.571v694.857c0 50.286-41.143 91.429-91.429 91.429h-768c-50.286 0-91.429-41.143-91.429-91.429v-694.857c0-50.286 41.143-91.429 91.429-91.429h768c50.286 0 91.429 41.143 91.429 91.429z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["columns"],"defaultCode":61659,"grid":14},"attrs":[],"properties":{"name":"columns","id":145,"order":197,"prevSize":28,"code":61659},"setIdx":0,"setId":1,"iconIdx":156},{"icon":{"paths":["M585.143 621.714c0 9.714-4 18.857-10.857 25.714l-256 256c-6.857 6.857-16 10.857-25.714 10.857s-18.857-4-25.714-10.857l-256-256c-6.857-6.857-10.857-16-10.857-25.714 0-20 16.571-36.571 36.571-36.571h512c20 0 36.571 16.571 36.571 36.571zM585.143 402.286c0 20-16.571 36.571-36.571 36.571h-512c-20 0-36.571-16.571-36.571-36.571 0-9.714 4-18.857 10.857-25.714l256-256c6.857-6.857 16-10.857 25.714-10.857s18.857 4 25.714 10.857l256 256c6.857 6.857 10.857 16 10.857 25.714z"],"width":585.1428571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["sort","unsorted"],"defaultCode":61660,"grid":14},"attrs":[],"properties":{"name":"sort, unsorted","id":146,"order":198,"prevSize":28,"code":61660},"setIdx":0,"setId":1,"iconIdx":157},{"icon":{"paths":["M585.143 621.714c0 9.714-4 18.857-10.857 25.714l-256 256c-6.857 6.857-16 10.857-25.714 10.857s-18.857-4-25.714-10.857l-256-256c-6.857-6.857-10.857-16-10.857-25.714 0-20 16.571-36.571 36.571-36.571h512c20 0 36.571 16.571 36.571 36.571z"],"width":585.1428571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["sort-desc","sort-down"],"defaultCode":61661,"grid":14},"attrs":[],"properties":{"name":"sort-desc, sort-down","id":147,"order":199,"prevSize":28,"code":61661},"setIdx":0,"setId":1,"iconIdx":158},{"icon":{"paths":["M585.143 402.286c0 20-16.571 36.571-36.571 36.571h-512c-20 0-36.571-16.571-36.571-36.571 0-9.714 4-18.857 10.857-25.714l256-256c6.857-6.857 16-10.857 25.714-10.857s18.857 4 25.714 10.857l256 256c6.857 6.857 10.857 16 10.857 25.714z"],"width":585.1428571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["sort-asc","sort-up"],"defaultCode":61662,"grid":14},"attrs":[],"properties":{"name":"sort-asc, sort-up","id":148,"order":200,"prevSize":28,"code":61662},"setIdx":0,"setId":1,"iconIdx":159},{"icon":{"paths":["M877.714 512c0 241.714-197.143 438.857-438.857 438.857-130.857 0-254.286-57.714-337.714-158.286-5.714-7.429-5.143-18.286 1.143-24.571l78.286-78.857c4-3.429 9.143-5.143 14.286-5.143 5.143 0.571 10.286 2.857 13.143 6.857 56 72.571 140 113.714 230.857 113.714 161.143 0 292.571-131.429 292.571-292.571s-131.429-292.571-292.571-292.571c-74.857 0-145.714 28.571-198.857 78.286l78.286 78.857c10.857 10.286 13.714 26.286 8 39.429-5.714 13.714-18.857 22.857-33.714 22.857h-256c-20 0-36.571-16.571-36.571-36.571v-256c0-14.857 9.143-28 22.857-33.714 13.143-5.714 29.143-2.857 39.429 8l74.286 73.714c80.571-76 189.714-121.143 302.286-121.143 241.714 0 438.857 197.143 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["rotate-left","undo"],"defaultCode":61666,"grid":14},"attrs":[],"properties":{"name":"rotate-left, undo","id":149,"order":203,"prevSize":28,"code":61666},"setIdx":0,"setId":1,"iconIdx":160},{"icon":{"paths":["M838.857 217.143c21.143 21.143 38.857 63.429 38.857 93.714v658.286c0 30.286-24.571 54.857-54.857 54.857h-768c-30.286 0-54.857-24.571-54.857-54.857v-914.286c0-30.286 24.571-54.857 54.857-54.857h512c30.286 0 72.571 17.714 93.714 38.857zM585.143 77.714v214.857h214.857c-3.429-9.714-8.571-19.429-12.571-23.429l-178.857-178.857c-4-4-13.714-9.143-23.429-12.571zM804.571 950.857v-585.143h-237.714c-30.286 0-54.857-24.571-54.857-54.857v-237.714h-438.857v877.714h731.429zM219.429 457.143c0-10.286 8-18.286 18.286-18.286h402.286c10.286 0 18.286 8 18.286 18.286v36.571c0 10.286-8 18.286-18.286 18.286h-402.286c-10.286 0-18.286-8-18.286-18.286v-36.571zM640 585.143c10.286 0 18.286 8 18.286 18.286v36.571c0 10.286-8 18.286-18.286 18.286h-402.286c-10.286 0-18.286-8-18.286-18.286v-36.571c0-10.286 8-18.286 18.286-18.286h402.286zM640 731.429c10.286 0 18.286 8 18.286 18.286v36.571c0 10.286-8 18.286-18.286 18.286h-402.286c-10.286 0-18.286-8-18.286-18.286v-36.571c0-10.286 8-18.286 18.286-18.286h402.286z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["file-text-o"],"defaultCode":61686,"grid":14},"attrs":[],"properties":{"name":"file-text-o","id":150,"order":222,"prevSize":28,"code":61686},"setIdx":0,"setId":1,"iconIdx":161},{"icon":{"paths":["M731.429 548.571v-73.143c0-20-16.571-36.571-36.571-36.571h-182.857v-182.857c0-20-16.571-36.571-36.571-36.571h-73.143c-20 0-36.571 16.571-36.571 36.571v182.857h-182.857c-20 0-36.571 16.571-36.571 36.571v73.143c0 20 16.571 36.571 36.571 36.571h182.857v182.857c0 20 16.571 36.571 36.571 36.571h73.143c20 0 36.571-16.571 36.571-36.571v-182.857h182.857c20 0 36.571-16.571 36.571-36.571zM877.714 237.714v548.571c0 90.857-73.714 164.571-164.571 164.571h-548.571c-90.857 0-164.571-73.714-164.571-164.571v-548.571c0-90.857 73.714-164.571 164.571-164.571h548.571c90.857 0 164.571 73.714 164.571 164.571z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["plus-square"],"defaultCode":61694,"grid":14},"attrs":[],"properties":{"name":"plus-square","id":151,"order":230,"prevSize":28,"code":61694},"setIdx":0,"setId":1,"iconIdx":162},{"icon":{"paths":["M358.286 786.286c0 4.571-2.286 9.714-5.714 13.143l-28.571 28.571c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-266.286-266.286c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l266.286-266.286c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l28.571 28.571c3.429 3.429 5.714 8.571 5.714 13.143s-2.286 9.714-5.714 13.143l-224.571 224.571 224.571 224.571c3.429 3.429 5.714 8.571 5.714 13.143zM577.714 786.286c0 4.571-2.286 9.714-5.714 13.143l-28.571 28.571c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-266.286-266.286c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l266.286-266.286c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l28.571 28.571c3.429 3.429 5.714 8.571 5.714 13.143s-2.286 9.714-5.714 13.143l-224.571 224.571 224.571 224.571c3.429 3.429 5.714 8.571 5.714 13.143z"],"width":603.4285714285714,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["angle-double-left"],"defaultCode":61696,"grid":14},"attrs":[],"properties":{"name":"angle-double-left","id":152,"order":231,"prevSize":28,"code":61696},"setIdx":0,"setId":1,"iconIdx":163},{"icon":{"paths":["M340 548.571c0 4.571-2.286 9.714-5.714 13.143l-266.286 266.286c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-28.571-28.571c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l224.571-224.571-224.571-224.571c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l28.571-28.571c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l266.286 266.286c3.429 3.429 5.714 8.571 5.714 13.143zM559.429 548.571c0 4.571-2.286 9.714-5.714 13.143l-266.286 266.286c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-28.571-28.571c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l224.571-224.571-224.571-224.571c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l28.571-28.571c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l266.286 266.286c3.429 3.429 5.714 8.571 5.714 13.143z"],"width":566.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["angle-double-right"],"defaultCode":61697,"grid":14},"attrs":[],"properties":{"name":"angle-double-right","id":153,"order":232,"prevSize":28,"code":61697},"setIdx":0,"setId":1,"iconIdx":164},{"icon":{"paths":["M614.286 749.714c0 4.571-2.286 9.714-5.714 13.143l-28.571 28.571c-3.429 3.429-8 5.714-13.143 5.714-4.571 0-9.714-2.286-13.143-5.714l-224.571-224.571-224.571 224.571c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-28.571-28.571c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l266.286-266.286c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l266.286 266.286c3.429 3.429 5.714 8.571 5.714 13.143zM614.286 530.286c0 4.571-2.286 9.714-5.714 13.143l-28.571 28.571c-3.429 3.429-8 5.714-13.143 5.714-4.571 0-9.714-2.286-13.143-5.714l-224.571-224.571-224.571 224.571c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-28.571-28.571c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l266.286-266.286c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l266.286 266.286c3.429 3.429 5.714 8.571 5.714 13.143z"],"width":658.2857142857142,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["angle-double-up"],"defaultCode":61698,"grid":14},"attrs":[],"properties":{"name":"angle-double-up","id":154,"order":233,"prevSize":28,"code":61698},"setIdx":0,"setId":1,"iconIdx":165},{"icon":{"paths":["M614.286 493.714c0 4.571-2.286 9.714-5.714 13.143l-266.286 266.286c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-266.286-266.286c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l28.571-28.571c3.429-3.429 8-5.714 13.143-5.714 4.571 0 9.714 2.286 13.143 5.714l224.571 224.571 224.571-224.571c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l28.571 28.571c3.429 3.429 5.714 8.571 5.714 13.143zM614.286 274.286c0 4.571-2.286 9.714-5.714 13.143l-266.286 266.286c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-266.286-266.286c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l28.571-28.571c3.429-3.429 8-5.714 13.143-5.714 4.571 0 9.714 2.286 13.143 5.714l224.571 224.571 224.571-224.571c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l28.571 28.571c3.429 3.429 5.714 8.571 5.714 13.143z"],"width":658.2857142857142,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["angle-double-down"],"defaultCode":61699,"grid":14},"attrs":[],"properties":{"name":"angle-double-down","id":155,"order":234,"prevSize":28,"code":61699},"setIdx":0,"setId":1,"iconIdx":166},{"icon":{"paths":["M358.286 310.857c0 4.571-2.286 9.714-5.714 13.143l-224.571 224.571 224.571 224.571c3.429 3.429 5.714 8.571 5.714 13.143s-2.286 9.714-5.714 13.143l-28.571 28.571c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-266.286-266.286c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l266.286-266.286c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l28.571 28.571c3.429 3.429 5.714 8 5.714 13.143z"],"width":384,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["angle-left"],"defaultCode":61700,"grid":14},"attrs":[],"properties":{"name":"angle-left","id":156,"order":235,"prevSize":28,"code":61700},"setIdx":0,"setId":1,"iconIdx":167},{"icon":{"paths":["M340 548.571c0 4.571-2.286 9.714-5.714 13.143l-266.286 266.286c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-28.571-28.571c-3.429-3.429-5.714-8-5.714-13.143 0-4.571 2.286-9.714 5.714-13.143l224.571-224.571-224.571-224.571c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l28.571-28.571c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l266.286 266.286c3.429 3.429 5.714 8.571 5.714 13.143z"],"width":347.4285714285714,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["angle-right"],"defaultCode":61701,"grid":14},"attrs":[],"properties":{"name":"angle-right","id":157,"order":236,"prevSize":28,"code":61701},"setIdx":0,"setId":1,"iconIdx":168},{"icon":{"paths":["M614.286 676.571c0 4.571-2.286 9.714-5.714 13.143l-28.571 28.571c-3.429 3.429-8 5.714-13.143 5.714-4.571 0-9.714-2.286-13.143-5.714l-224.571-224.571-224.571 224.571c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-28.571-28.571c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l266.286-266.286c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l266.286 266.286c3.429 3.429 5.714 8.571 5.714 13.143z"],"width":658.2857142857142,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["angle-up"],"defaultCode":61702,"grid":14},"attrs":[],"properties":{"name":"angle-up","id":158,"order":237,"prevSize":28,"code":61702},"setIdx":0,"setId":1,"iconIdx":169},{"icon":{"paths":["M614.286 420.571c0 4.571-2.286 9.714-5.714 13.143l-266.286 266.286c-3.429 3.429-8.571 5.714-13.143 5.714s-9.714-2.286-13.143-5.714l-266.286-266.286c-3.429-3.429-5.714-8.571-5.714-13.143s2.286-9.714 5.714-13.143l28.571-28.571c3.429-3.429 8-5.714 13.143-5.714 4.571 0 9.714 2.286 13.143 5.714l224.571 224.571 224.571-224.571c3.429-3.429 8.571-5.714 13.143-5.714s9.714 2.286 13.143 5.714l28.571 28.571c3.429 3.429 5.714 8.571 5.714 13.143z"],"width":658.2857142857142,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["angle-down"],"defaultCode":61703,"grid":14},"attrs":[],"properties":{"name":"angle-down","id":159,"order":238,"prevSize":28,"code":61703},"setIdx":0,"setId":1,"iconIdx":170},{"icon":{"paths":["M438.857 201.143c-171.429 0-310.857 139.429-310.857 310.857s139.429 310.857 310.857 310.857 310.857-139.429 310.857-310.857-139.429-310.857-310.857-310.857zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857v0c242.286 0 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["circle-o"],"defaultCode":61708,"grid":14},"attrs":[],"properties":{"name":"circle-o","id":160,"order":243,"prevSize":28,"code":61708},"setIdx":0,"setId":1,"iconIdx":171},{"icon":{"paths":["M300.571 796.571c0 40-32.571 73.143-73.143 73.143-40 0-73.143-33.143-73.143-73.143 0-40.571 33.143-73.143 73.143-73.143 40.571 0 73.143 32.571 73.143 73.143zM585.143 914.286c0 40.571-32.571 73.143-73.143 73.143s-73.143-32.571-73.143-73.143 32.571-73.143 73.143-73.143 73.143 32.571 73.143 73.143zM182.857 512c0 40.571-32.571 73.143-73.143 73.143s-73.143-32.571-73.143-73.143 32.571-73.143 73.143-73.143 73.143 32.571 73.143 73.143zM869.714 796.571c0 40-33.143 73.143-73.143 73.143-40.571 0-73.143-33.143-73.143-73.143 0-40.571 32.571-73.143 73.143-73.143 40 0 73.143 32.571 73.143 73.143zM318.857 227.429c0 50.286-41.143 91.429-91.429 91.429s-91.429-41.143-91.429-91.429 41.143-91.429 91.429-91.429 91.429 41.143 91.429 91.429zM987.429 512c0 40.571-32.571 73.143-73.143 73.143s-73.143-32.571-73.143-73.143 32.571-73.143 73.143-73.143 73.143 32.571 73.143 73.143zM621.714 109.714c0 60.571-49.143 109.714-109.714 109.714s-109.714-49.143-109.714-109.714 49.143-109.714 109.714-109.714 109.714 49.143 109.714 109.714zM924.571 227.429c0 70.857-57.714 128-128 128-70.857 0-128-57.143-128-128 0-70.286 57.143-128 128-128 70.286 0 128 57.714 128 128z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["spinner"],"defaultCode":61712,"grid":14},"attrs":[],"properties":{"name":"spinner","id":161,"order":246,"prevSize":28,"code":61712},"setIdx":0,"setId":1,"iconIdx":172},{"icon":{"paths":["M877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["circle"],"defaultCode":61713,"grid":14},"attrs":[],"properties":{"name":"circle","id":162,"order":247,"prevSize":28,"code":61713},"setIdx":0,"setId":1,"iconIdx":173},{"icon":{"paths":["M1024 640c0 80-40 184.571-72.571 257.714-6.286 13.143-12.571 31.429-21.143 43.429-4 5.714-8 9.714-16 9.714-11.429 0-18.286-9.143-18.286-20 0-9.143 2.286-19.429 2.857-28.571 1.714-23.429 2.857-46.857 2.857-70.286 0-272.571-161.714-320-408-320h-128v146.286c0 20-16.571 36.571-36.571 36.571-9.714 0-18.857-4-25.714-10.857l-292.571-292.571c-6.857-6.857-10.857-16-10.857-25.714s4-18.857 10.857-25.714l292.571-292.571c6.857-6.857 16-10.857 25.714-10.857 20 0 36.571 16.571 36.571 36.571v146.286h128c187.429 0 420.571 33.143 500 230.286 24 60.571 30.286 126.286 30.286 190.286z"],"width":1024,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["mail-reply","reply"],"defaultCode":61714,"grid":14},"attrs":[],"properties":{"name":"mail-reply, reply","id":163,"order":248,"prevSize":28,"code":61714},"setIdx":0,"setId":1,"iconIdx":174},{"icon":{"paths":["M877.714 749.714v-402.286c0-30.286-24.571-54.857-54.857-54.857h-402.286c-30.286 0-54.857-24.571-54.857-54.857v-36.571c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v548.571c0 30.286 24.571 54.857 54.857 54.857h694.857c30.286 0 54.857-24.571 54.857-54.857zM950.857 347.429v402.286c0 70.286-57.714 128-128 128h-694.857c-70.286 0-128-57.714-128-128v-548.571c0-70.286 57.714-128 128-128h182.857c70.286 0 128 57.714 128 128v18.286h384c70.286 0 128 57.714 128 128z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["folder-o"],"defaultCode":61716,"grid":14},"attrs":[],"properties":{"name":"folder-o","id":164,"order":250,"prevSize":28,"code":61716},"setIdx":0,"setId":1,"iconIdx":175},{"icon":{"paths":["M1017.714 532c0-16-17.714-20-30.286-20h-621.714c-30.286 0-70.286 18.857-89.714 42.286l-168 207.429c-5.143 6.857-10.286 14.286-10.286 22.857 0 16 17.714 20 30.286 20h621.714c30.286 0 70.286-18.857 89.714-42.857l168-207.429c5.143-6.286 10.286-13.714 10.286-22.286zM365.714 438.857h438.857v-91.429c0-30.286-24.571-54.857-54.857-54.857h-329.143c-30.286 0-54.857-24.571-54.857-54.857v-36.571c0-30.286-24.571-54.857-54.857-54.857h-182.857c-30.286 0-54.857 24.571-54.857 54.857v487.429l146.286-180c33.143-40.571 94.286-69.714 146.286-69.714zM1090.857 532c0 25.143-10.857 49.143-26.286 68.571l-168.571 207.429c-32.571 40-94.857 69.714-146.286 69.714h-621.714c-70.286 0-128-57.714-128-128v-548.571c0-70.286 57.714-128 128-128h182.857c70.286 0 128 57.714 128 128v18.286h310.857c70.286 0 128 57.714 128 128v91.429h109.714c38.857 0 77.714 17.714 94.857 54.286 5.714 12 8.571 25.143 8.571 38.857z"],"width":1090.8525714285713,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["folder-open-o"],"defaultCode":61717,"grid":14},"attrs":[],"properties":{"name":"folder-open-o","id":165,"order":251,"prevSize":28,"code":61717},"setIdx":0,"setId":1,"iconIdx":176},{"icon":{"paths":["M219.429 667.429v54.857c0 5.143-4 9.143-9.143 9.143h-54.857c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h54.857c5.143 0 9.143 4 9.143 9.143zM292.571 521.143v54.857c0 5.143-4 9.143-9.143 9.143h-128c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h128c5.143 0 9.143 4 9.143 9.143zM219.429 374.857v54.857c0 5.143-4 9.143-9.143 9.143h-54.857c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h54.857c5.143 0 9.143 4 9.143 9.143zM804.571 667.429v54.857c0 5.143-4 9.143-9.143 9.143h-493.714c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h493.714c5.143 0 9.143 4 9.143 9.143zM438.857 521.143v54.857c0 5.143-4 9.143-9.143 9.143h-54.857c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h54.857c5.143 0 9.143 4 9.143 9.143zM365.714 374.857v54.857c0 5.143-4 9.143-9.143 9.143h-54.857c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h54.857c5.143 0 9.143 4 9.143 9.143zM585.143 521.143v54.857c0 5.143-4 9.143-9.143 9.143h-54.857c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h54.857c5.143 0 9.143 4 9.143 9.143zM512 374.857v54.857c0 5.143-4 9.143-9.143 9.143h-54.857c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h54.857c5.143 0 9.143 4 9.143 9.143zM731.429 521.143v54.857c0 5.143-4 9.143-9.143 9.143h-54.857c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h54.857c5.143 0 9.143 4 9.143 9.143zM950.857 667.429v54.857c0 5.143-4 9.143-9.143 9.143h-54.857c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h54.857c5.143 0 9.143 4 9.143 9.143zM658.286 374.857v54.857c0 5.143-4 9.143-9.143 9.143h-54.857c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h54.857c5.143 0 9.143 4 9.143 9.143zM804.571 374.857v54.857c0 5.143-4 9.143-9.143 9.143h-54.857c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h54.857c5.143 0 9.143 4 9.143 9.143zM950.857 374.857v201.143c0 5.143-4 9.143-9.143 9.143h-128c-5.143 0-9.143-4-9.143-9.143v-54.857c0-5.143 4-9.143 9.143-9.143h64v-137.143c0-5.143 4-9.143 9.143-9.143h54.857c5.143 0 9.143 4 9.143 9.143zM1024 804.571v-512h-950.857v512h950.857zM1097.143 292.571v512c0 40.571-32.571 73.143-73.143 73.143h-950.857c-40.571 0-73.143-32.571-73.143-73.143v-512c0-40.571 32.571-73.143 73.143-73.143h950.857c40.571 0 73.143 32.571 73.143 73.143z"],"width":1097.142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["keyboard-o"],"defaultCode":61724,"grid":14},"attrs":[],"properties":{"name":"keyboard-o","id":166,"order":256,"prevSize":28,"code":61724},"setIdx":0,"setId":1,"iconIdx":177},{"icon":{"paths":["M334.286 561.714l-266.286 266.286c-7.429 7.429-18.857 7.429-26.286 0l-28.571-28.571c-7.429-7.429-7.429-18.857 0-26.286l224.571-224.571-224.571-224.571c-7.429-7.429-7.429-18.857 0-26.286l28.571-28.571c7.429-7.429 18.857-7.429 26.286 0l266.286 266.286c7.429 7.429 7.429 18.857 0 26.286zM950.857 822.857v36.571c0 10.286-8 18.286-18.286 18.286h-548.571c-10.286 0-18.286-8-18.286-18.286v-36.571c0-10.286 8-18.286 18.286-18.286h548.571c10.286 0 18.286 8 18.286 18.286z"],"width":956.5622857142856,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["terminal"],"defaultCode":61728,"grid":14},"attrs":[],"properties":{"name":"terminal","id":167,"order":259,"prevSize":28,"code":61728},"setIdx":0,"setId":1,"iconIdx":178},{"icon":{"paths":["M352.571 799.429l-28.571 28.571c-7.429 7.429-18.857 7.429-26.286 0l-266.286-266.286c-7.429-7.429-7.429-18.857 0-26.286l266.286-266.286c7.429-7.429 18.857-7.429 26.286 0l28.571 28.571c7.429 7.429 7.429 18.857 0 26.286l-224.571 224.571 224.571 224.571c7.429 7.429 7.429 18.857 0 26.286zM690.286 189.714l-213.143 737.714c-2.857 9.714-13.143 15.429-22.286 12.571l-35.429-9.714c-9.714-2.857-15.429-13.143-12.571-22.857l213.143-737.714c2.857-9.714 13.143-15.429 22.286-12.571l35.429 9.714c9.714 2.857 15.429 13.143 12.571 22.857zM1065.714 561.714l-266.286 266.286c-7.429 7.429-18.857 7.429-26.286 0l-28.571-28.571c-7.429-7.429-7.429-18.857 0-26.286l224.571-224.571-224.571-224.571c-7.429-7.429-7.429-18.857 0-26.286l28.571-28.571c7.429-7.429 18.857-7.429 26.286 0l266.286 266.286c7.429 7.429 7.429 18.857 0 26.286z"],"width":1097.142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["code"],"defaultCode":61729,"grid":14},"attrs":[],"properties":{"name":"code","id":168,"order":684,"prevSize":28,"code":61729},"setIdx":0,"setId":1,"iconIdx":179},{"icon":{"paths":["M365.714 618.286v40c0 14.857-9.143 28-22.286 33.714-4.571 1.714-9.714 2.857-14.286 2.857-9.714 0-18.857-3.429-25.714-10.857l-292.571-292.571c-14.286-14.286-14.286-37.143 0-51.429l292.571-292.571c10.286-10.857 26.286-13.714 40-8 13.143 5.714 22.286 18.857 22.286 33.714v39.429l-226.857 227.429c-14.286 14.286-14.286 37.143 0 51.429zM1024 640c0 118.857-89.714 293.714-93.714 301.143-2.857 6.286-9.143 9.714-16 9.714-1.714 0-3.429 0-5.143-0.571-8.571-2.857-13.714-10.857-13.143-19.429 16.571-156-2.857-258.857-60.571-322.857-48.571-54.286-127.429-83.429-250.286-93.143v143.429c0 14.857-9.143 28-22.286 33.714-4.571 1.714-9.714 2.857-14.286 2.857-9.714 0-18.857-3.429-25.714-10.857l-292.571-292.571c-14.286-14.286-14.286-37.143 0-51.429l292.571-292.571c10.286-10.857 26.286-13.714 40-8 13.143 5.714 22.286 18.857 22.286 33.714v149.714c157.714 10.857 270.286 52.571 342.286 126.286 86.286 88.571 96.571 208.571 96.571 290.857z"],"width":1020.5622857142856,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["mail-reply-all","reply-all"],"defaultCode":61730,"grid":14},"attrs":[],"properties":{"name":"mail-reply-all, reply-all","id":169,"order":685,"prevSize":28,"code":61730},"setIdx":0,"setId":1,"iconIdx":180},{"icon":{"paths":["M677.714 546.857l146.857-142.857-241.143-35.429-17.143-34.286-90.857-184v550.286l33.714 17.714 181.714 96-34.286-202.857-6.857-37.714zM936 397.143l-207.429 202.286 49.143 285.714c4 25.143-5.143 40-22.857 40-6.286 0-14.286-2.286-22.857-6.857l-256.571-134.857-256.571 134.857c-8.571 4.571-16.571 6.857-22.857 6.857-17.714 0-26.857-14.857-22.857-40l49.143-285.714-208-202.286c-24.571-24.571-16.571-48.571 17.714-53.714l286.857-41.714 128.571-260c7.429-15.429 17.714-23.429 28-23.429v0c10.286 0 20 8 28 23.429l128.571 260 286.857 41.714c34.286 5.143 42.286 29.143 17.143 53.714z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["star-half-empty","star-half-full","star-half-o"],"defaultCode":61731,"grid":14},"attrs":[],"properties":{"name":"star-half-empty, star-half-full, star-half-o","id":170,"order":262,"prevSize":28,"code":61731},"setIdx":0,"setId":1,"iconIdx":181},{"icon":{"paths":["M318.286 731.429h340v-340zM292.571 705.714l340-340h-340v340zM950.857 749.714v109.714c0 10.286-8 18.286-18.286 18.286h-128v128c0 10.286-8 18.286-18.286 18.286h-109.714c-10.286 0-18.286-8-18.286-18.286v-128h-493.714c-10.286 0-18.286-8-18.286-18.286v-493.714h-128c-10.286 0-18.286-8-18.286-18.286v-109.714c0-10.286 8-18.286 18.286-18.286h128v-128c0-10.286 8-18.286 18.286-18.286h109.714c10.286 0 18.286 8 18.286 18.286v128h486.286l140.571-141.143c7.429-6.857 18.857-6.857 26.286 0 6.857 7.429 6.857 18.857 0 26.286l-141.143 140.571v486.286h128c10.286 0 18.286 8 18.286 18.286z"],"width":952.5394285714285,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["crop"],"defaultCode":61733,"grid":14},"attrs":[],"properties":{"name":"crop","id":171,"order":264,"prevSize":28,"code":61733},"setIdx":0,"setId":1,"iconIdx":182},{"icon":{"paths":["M164.571 841.143c0-30.286-24.571-54.857-54.857-54.857s-54.857 24.571-54.857 54.857 24.571 54.857 54.857 54.857 54.857-24.571 54.857-54.857zM164.571 182.857c0-30.286-24.571-54.857-54.857-54.857s-54.857 24.571-54.857 54.857 24.571 54.857 54.857 54.857 54.857-24.571 54.857-54.857zM530.286 256c0-30.286-24.571-54.857-54.857-54.857s-54.857 24.571-54.857 54.857 24.571 54.857 54.857 54.857 54.857-24.571 54.857-54.857zM585.143 256c0 40.571-22.286 76-54.857 94.857-1.714 206.286-148 252-245.143 282.857-90.857 28.571-120.571 42.286-120.571 97.714v14.857c32.571 18.857 54.857 54.286 54.857 94.857 0 60.571-49.143 109.714-109.714 109.714s-109.714-49.143-109.714-109.714c0-40.571 22.286-76 54.857-94.857v-468.571c-32.571-18.857-54.857-54.286-54.857-94.857 0-60.571 49.143-109.714 109.714-109.714s109.714 49.143 109.714 109.714c0 40.571-22.286 76-54.857 94.857v284c29.143-14.286 60-24 88-32.571 106.286-33.714 166.857-58.857 168-178.286-32.571-18.857-54.857-54.286-54.857-94.857 0-60.571 49.143-109.714 109.714-109.714s109.714 49.143 109.714 109.714z"],"width":585.1428571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["code-fork"],"defaultCode":61734,"grid":14},"attrs":[],"properties":{"name":"code-fork","id":172,"order":265,"prevSize":28,"code":61734},"setIdx":0,"setId":1,"iconIdx":183},{"icon":{"paths":["M250.857 726.286l-146.286 146.286c-4 3.429-8.571 5.143-13.143 5.143s-9.143-1.714-13.143-5.143c-6.857-7.429-6.857-18.857 0-26.286l146.286-146.286c7.429-6.857 18.857-6.857 26.286 0 6.857 7.429 6.857 18.857 0 26.286zM347.429 749.714v182.857c0 10.286-8 18.286-18.286 18.286s-18.286-8-18.286-18.286v-182.857c0-10.286 8-18.286 18.286-18.286s18.286 8 18.286 18.286zM219.429 621.714c0 10.286-8 18.286-18.286 18.286h-182.857c-10.286 0-18.286-8-18.286-18.286s8-18.286 18.286-18.286h182.857c10.286 0 18.286 8 18.286 18.286zM941.714 694.857c0 44-17.143 85.143-48.571 116l-84 83.429c-30.857 30.857-72 47.429-116 47.429s-85.714-17.143-116.571-48.571l-190.857-191.429c-9.714-9.714-17.143-20.571-24-32l136.571-10.286 156 156.571c20.571 20.571 57.143 21.143 77.714 0.571l84-83.429c10.286-10.286 16-24 16-38.286 0-14.857-5.714-28.571-16-38.857l-156.571-157.143 10.286-136.571c11.429 6.857 22.286 14.286 32 24l192 192c30.857 31.429 48 72.571 48 116.571zM589.143 281.143l-136.571 10.286-156-156.571c-10.286-10.286-24-16-38.857-16s-28.571 5.714-38.857 15.429l-84 83.429c-10.286 10.286-16 24-16 38.286 0 14.857 5.714 28.571 16 38.857l156.571 156.571-10.286 137.143c-11.429-6.857-22.286-14.286-32-24l-192-192c-30.857-31.429-48-72.571-48-116.571s17.143-85.143 48.571-116l84-83.429c30.857-30.857 72-47.429 116-47.429s85.714 17.143 116.571 48.571l190.857 191.429c9.714 9.714 17.143 20.571 24 32zM950.857 329.143c0 10.286-8 18.286-18.286 18.286h-182.857c-10.286 0-18.286-8-18.286-18.286s8-18.286 18.286-18.286h182.857c10.286 0 18.286 8 18.286 18.286zM640 18.286v182.857c0 10.286-8 18.286-18.286 18.286s-18.286-8-18.286-18.286v-182.857c0-10.286 8-18.286 18.286-18.286s18.286 8 18.286 18.286zM872.571 104.571l-146.286 146.286c-4 3.429-8.571 5.143-13.143 5.143s-9.143-1.714-13.143-5.143c-6.857-7.429-6.857-18.857 0-26.286l146.286-146.286c7.429-6.857 18.857-6.857 26.286 0 6.857 7.429 6.857 18.857 0 26.286z"],"width":950.8571428571428,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["chain-broken","unlink"],"defaultCode":61735,"grid":14},"attrs":[],"properties":{"name":"chain-broken, unlink","id":173,"order":266,"prevSize":28,"code":61735},"setIdx":0,"setId":1,"iconIdx":184},{"icon":{"paths":["M511.999 960c-88.606 0-175.222-26.276-248.895-75.5-73.673-49.229-131.095-119.199-165.002-201.057-33.908-81.864-42.78-171.94-25.494-258.844s59.954-166.729 122.608-229.383c62.654-62.654 142.48-105.322 229.383-122.608s176.98-8.414 258.844 25.494c81.859 33.908 151.828 91.329 201.057 165.002 49.224 73.673 75.5 160.29 75.5 248.895 0 118.815-47.201 232.765-131.215 316.785-84.019 84.014-197.97 131.215-316.785 131.215zM511.999 128c-75.948 0-150.19 22.521-213.339 64.716s-112.367 102.167-141.431 172.334c-29.064 70.167-36.668 147.375-21.852 221.866 14.817 74.486 51.389 142.909 105.093 196.613s122.126 90.276 196.615 105.093c74.488 14.817 151.699 7.214 221.863-21.852 70.17-29.066 130.14-78.285 172.334-141.43 42.194-63.15 64.717-137.39 64.717-213.34 0-101.843-40.458-199.515-112.471-271.529s-169.687-112.471-271.529-112.471z","M495.999 352c26.511 0 48-21.49 48-48s-21.489-48-48-48c-26.51 0-48 21.49-48 48s21.49 48 48 48z","M671.999 704c0 8.489-3.369 16.625-9.375 22.625-6.001 6.006-14.136 9.375-22.625 9.375h-256c-8.487 0-16.626-3.369-22.627-9.375-6.001-6.001-9.373-14.136-9.373-22.625s3.372-16.625 9.373-22.625c6.001-6.006 14.14-9.375 22.627-9.375h96v-192h-64c-8.487 0-16.626-3.372-22.627-9.373s-9.373-14.14-9.373-22.627c0-8.487 3.372-16.626 9.373-22.627s14.14-9.373 22.627-9.373h96c8.489 0 16.625 3.372 22.625 9.373 6.006 6.001 9.375 14.14 9.375 22.627v224h96c8.489 0 16.625 3.369 22.625 9.375 6.006 6.001 9.375 14.136 9.375 22.625z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["info"],"defaultCode":61737,"grid":14},"attrs":[],"properties":{"name":"info","id":174,"order":678,"prevSize":28,"code":61737},"setIdx":0,"setId":1,"iconIdx":185},{"icon":{"paths":["M917.119 944.34h-812.798c-5.469-0.020-10.84-1.444-15.602-4.137-4.762-2.688-8.755-6.554-11.598-11.223-2.809-4.864-4.287-10.383-4.287-16s1.479-11.136 4.287-16l406.4-799.999c2.685-5.242 6.765-9.64 11.79-12.712s10.8-4.697 16.688-4.697c5.893 0 11.668 1.625 16.691 4.697 5.028 3.072 9.103 7.471 11.791 12.712l406.4 799.999c2.806 4.864 4.285 10.383 4.285 16s-1.48 11.136-4.285 16c-3.057 5.059-7.46 9.175-12.713 11.884-5.253 2.714-11.151 3.917-17.050 3.476zM156.481 880.34h708.481l-354.243-697.279-354.238 697.279z","M510.709 816.34c26.511 0 48-21.489 48-48s-21.489-48-48-48c-26.51 0-48 21.489-48 48s21.49 48 48 48z","M510.709 656.34c-8.487 0-16.626-3.369-22.627-9.375-6.001-6.001-9.373-14.136-9.373-22.625v-224c0-8.487 3.372-16.626 9.373-22.627s14.14-9.373 22.627-9.373c8.489 0 16.625 3.372 22.625 9.373 6.006 6.001 9.375 14.14 9.375 22.627v224c0 8.489-3.369 16.625-9.375 22.625-6.001 6.006-14.136 9.375-22.625 9.375z"],"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["exclamation"],"defaultCode":61738,"grid":14},"attrs":[],"properties":{"name":"exclamation","id":175,"order":268,"prevSize":28,"code":61738},"setIdx":0,"setId":1,"iconIdx":186},{"icon":{"paths":["M822.857 256c0-30.286-24.571-54.857-54.857-54.857s-54.857 24.571-54.857 54.857 24.571 54.857 54.857 54.857 54.857-24.571 54.857-54.857zM950.857 91.429c0 189.714-52.571 316-188 452-33.143 32.571-70.857 66.286-111.429 100.571l-11.429 216.571c-0.571 5.714-4 11.429-9.143 14.857l-219.429 128c-2.857 1.714-5.714 2.286-9.143 2.286-4.571 0-9.143-1.714-13.143-5.143l-36.571-36.571c-4.571-5.143-6.286-12-4.571-18.286l48.571-157.714-160.571-160.571-157.714 48.571c-1.714 0.571-3.429 0.571-5.143 0.571-4.571 0-9.714-1.714-13.143-5.143l-36.571-36.571c-5.714-6.286-6.857-15.429-2.857-22.286l128-219.429c3.429-5.143 9.143-8.571 14.857-9.143l216.571-11.429c34.286-40.571 68-78.286 100.571-111.429 142.857-142.286 252-188 450.857-188 10.286 0 19.429 8 19.429 18.286z"],"width":967.4605714285714,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["rocket"],"defaultCode":61749,"grid":14},"attrs":[],"properties":{"name":"rocket","id":176,"order":682,"prevSize":28,"code":61749},"setIdx":0,"setId":1,"iconIdx":187},{"icon":{"paths":["M997.143 441.714l-93.714 436h-190.857l101.714-475.429c4.571-20 1.714-38.286-8.571-50.286-9.714-12-26.857-18.857-47.429-18.857h-96.571l-116.571 544.571h-190.857l116.571-544.571h-163.429l-116.571 544.571h-190.857l116.571-544.571-87.429-186.857h729.143c77.143 0 147.429 32 192.571 88 45.714 56 62.286 132 46.286 207.429z"],"width":1013.1748571428571,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["maxcdn"],"defaultCode":61750,"grid":14},"attrs":[],"properties":{"name":"maxcdn","id":177,"order":683,"prevSize":28,"code":61750},"setIdx":0,"setId":1,"iconIdx":188},{"icon":{"paths":["M519.429 797.143l58.286-58.286c14.286-14.286 14.286-37.143 0-51.429l-175.429-175.429 175.429-175.429c14.286-14.286 14.286-37.143 0-51.429l-58.286-58.286c-14.286-14.286-37.143-14.286-51.429 0l-259.429 259.429c-14.286 14.286-14.286 37.143 0 51.429l259.429 259.429c14.286 14.286 37.143 14.286 51.429 0zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["chevron-circle-left"],"defaultCode":61751,"grid":14},"attrs":[],"properties":{"name":"chevron-circle-left","id":178,"order":280,"prevSize":28,"code":61751},"setIdx":0,"setId":1,"iconIdx":189},{"icon":{"paths":["M409.714 797.143l259.429-259.429c14.286-14.286 14.286-37.143 0-51.429l-259.429-259.429c-14.286-14.286-37.143-14.286-51.429 0l-58.286 58.286c-14.286 14.286-14.286 37.143 0 51.429l175.429 175.429-175.429 175.429c-14.286 14.286-14.286 37.143 0 51.429l58.286 58.286c14.286 14.286 37.143 14.286 51.429 0zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["chevron-circle-right"],"defaultCode":61752,"grid":14},"attrs":[],"properties":{"name":"chevron-circle-right","id":179,"order":281,"prevSize":28,"code":61752},"setIdx":0,"setId":1,"iconIdx":190},{"icon":{"paths":["M665.714 650.857l58.286-58.286c14.286-14.286 14.286-37.143 0-51.429l-259.429-259.429c-14.286-14.286-37.143-14.286-51.429 0l-259.429 259.429c-14.286 14.286-14.286 37.143 0 51.429l58.286 58.286c14.286 14.286 37.143 14.286 51.429 0l175.429-175.429 175.429 175.429c14.286 14.286 37.143 14.286 51.429 0zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["chevron-circle-up"],"defaultCode":61753,"grid":14},"attrs":[],"properties":{"name":"chevron-circle-up","id":180,"order":282,"prevSize":28,"code":61753},"setIdx":0,"setId":1,"iconIdx":191},{"icon":{"paths":["M464.571 742.286l259.429-259.429c14.286-14.286 14.286-37.143 0-51.429l-58.286-58.286c-14.286-14.286-37.143-14.286-51.429 0l-175.429 175.429-175.429-175.429c-14.286-14.286-37.143-14.286-51.429 0l-58.286 58.286c-14.286 14.286-14.286 37.143 0 51.429l259.429 259.429c14.286 14.286 37.143 14.286 51.429 0zM877.714 512c0 242.286-196.571 438.857-438.857 438.857s-438.857-196.571-438.857-438.857 196.571-438.857 438.857-438.857 438.857 196.571 438.857 438.857z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["chevron-circle-down"],"defaultCode":61754,"grid":14},"attrs":[],"properties":{"name":"chevron-circle-down","id":181,"order":283,"prevSize":28,"code":61754},"setIdx":0,"setId":1,"iconIdx":192},{"icon":{"paths":["M219.429 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-109.714c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h109.714c30.286 0 54.857 24.571 54.857 54.857zM512 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-109.714c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h109.714c30.286 0 54.857 24.571 54.857 54.857zM804.571 420.571v109.714c0 30.286-24.571 54.857-54.857 54.857h-109.714c-30.286 0-54.857-24.571-54.857-54.857v-109.714c0-30.286 24.571-54.857 54.857-54.857h109.714c30.286 0 54.857 24.571 54.857 54.857z"],"width":804.5714285714286,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["ellipsis-h"],"defaultCode":61761,"grid":14},"attrs":[],"properties":{"name":"ellipsis-h","id":182,"order":289,"prevSize":28,"code":61761},"setIdx":0,"setId":1,"iconIdx":193},{"icon":{"paths":["M437.143 742.286c2.857 6.857 1.714 14.286-2.857 20l-200 219.429c-3.429 3.429-8 5.714-13.143 5.714v0c-5.143 0-10.286-2.286-13.714-5.714l-202.857-219.429c-4.571-5.714-5.714-13.143-2.857-20 2.857-6.286 9.143-10.857 16.571-10.857h128v-713.143c0-10.286 8-18.286 18.286-18.286h109.714c10.286 0 18.286 8 18.286 18.286v713.143h128c7.429 0 13.714 4 16.571 10.857z"],"width":438.85714285714283,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["long-arrow-down"],"defaultCode":61813,"grid":14},"attrs":[],"properties":{"name":"long-arrow-down","id":183,"order":338,"prevSize":28,"code":61813},"setIdx":0,"setId":1,"iconIdx":194},{"icon":{"paths":["M437.143 281.714c-2.857 6.286-9.143 10.857-16.571 10.857h-128v713.143c0 10.286-8 18.286-18.286 18.286h-109.714c-10.286 0-18.286-8-18.286-18.286v-713.143h-128c-7.429 0-13.714-4-16.571-10.857s-1.714-14.286 2.857-20l200-219.429c3.429-3.429 8-5.714 13.143-5.714v0c5.143 0 10.286 2.286 13.714 5.714l202.857 219.429c4.571 5.714 5.714 13.143 2.857 20z"],"width":438.85714285714283,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["long-arrow-up"],"defaultCode":61814,"grid":14},"attrs":[],"properties":{"name":"long-arrow-up","id":184,"order":339,"prevSize":28,"code":61814},"setIdx":0,"setId":1,"iconIdx":195},{"icon":{"paths":["M1024 457.143v109.714c0 10.286-8 18.286-18.286 18.286h-713.143v128c0 7.429-4 13.714-10.857 16.571s-14.286 1.714-20-2.857l-219.429-200c-3.429-3.429-5.714-8-5.714-13.143v0c0-5.143 2.286-10.286 5.714-13.714l219.429-202.286c5.714-5.143 13.143-6.286 20-3.429 6.286 2.857 10.857 9.143 10.857 16.571v128h713.143c10.286 0 18.286 8 18.286 18.286z"],"width":1060.5714285714284,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["long-arrow-left"],"defaultCode":61815,"grid":14},"attrs":[],"properties":{"name":"long-arrow-left","id":185,"order":340,"prevSize":28,"code":61815},"setIdx":0,"setId":1,"iconIdx":196},{"icon":{"paths":["M987.429 510.286c0 5.143-2.286 10.286-5.714 13.714l-219.429 202.286c-5.714 5.143-13.143 6.286-20 3.429-6.286-2.857-10.857-9.143-10.857-16.571v-128h-713.143c-10.286 0-18.286-8-18.286-18.286v-109.714c0-10.286 8-18.286 18.286-18.286h713.143v-128c0-7.429 4-13.714 10.857-16.571s14.286-1.714 20 2.857l219.429 200c3.429 3.429 5.714 8 5.714 13.143v0z"],"width":987.4285714285713,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["long-arrow-right"],"defaultCode":61816,"grid":14},"attrs":[],"properties":{"name":"long-arrow-right","id":186,"order":341,"prevSize":28,"code":61816},"setIdx":0,"setId":1,"iconIdx":197},{"icon":{"paths":["M109.714 731.429v73.143h-64c-5.143 0-9.143-4-9.143-9.143v-9.143h-27.429c-5.143 0-9.143-4-9.143-9.143v-18.286c0-5.143 4-9.143 9.143-9.143h27.429v-9.143c0-5.143 4-9.143 9.143-9.143h64zM109.714 585.143v73.143h-64c-5.143 0-9.143-4-9.143-9.143v-9.143h-27.429c-5.143 0-9.143-4-9.143-9.143v-18.286c0-5.143 4-9.143 9.143-9.143h27.429v-9.143c0-5.143 4-9.143 9.143-9.143h64zM109.714 438.857v73.143h-64c-5.143 0-9.143-4-9.143-9.143v-9.143h-27.429c-5.143 0-9.143-4-9.143-9.143v-18.286c0-5.143 4-9.143 9.143-9.143h27.429v-9.143c0-5.143 4-9.143 9.143-9.143h64zM109.714 292.571v73.143h-64c-5.143 0-9.143-4-9.143-9.143v-9.143h-27.429c-5.143 0-9.143-4-9.143-9.143v-18.286c0-5.143 4-9.143 9.143-9.143h27.429v-9.143c0-5.143 4-9.143 9.143-9.143h64zM109.714 146.286v73.143h-64c-5.143 0-9.143-4-9.143-9.143v-9.143h-27.429c-5.143 0-9.143-4-9.143-9.143v-18.286c0-5.143 4-9.143 9.143-9.143h27.429v-9.143c0-5.143 4-9.143 9.143-9.143h64zM731.429 54.857v841.143c0 30.286-24.571 54.857-54.857 54.857h-475.429c-30.286 0-54.857-24.571-54.857-54.857v-841.143c0-30.286 24.571-54.857 54.857-54.857h475.429c30.286 0 54.857 24.571 54.857 54.857zM877.714 758.857v18.286c0 5.143-4 9.143-9.143 9.143h-27.429v9.143c0 5.143-4 9.143-9.143 9.143h-64v-73.143h64c5.143 0 9.143 4 9.143 9.143v9.143h27.429c5.143 0 9.143 4 9.143 9.143zM877.714 612.571v18.286c0 5.143-4 9.143-9.143 9.143h-27.429v9.143c0 5.143-4 9.143-9.143 9.143h-64v-73.143h64c5.143 0 9.143 4 9.143 9.143v9.143h27.429c5.143 0 9.143 4 9.143 9.143zM877.714 466.286v18.286c0 5.143-4 9.143-9.143 9.143h-27.429v9.143c0 5.143-4 9.143-9.143 9.143h-64v-73.143h64c5.143 0 9.143 4 9.143 9.143v9.143h27.429c5.143 0 9.143 4 9.143 9.143zM877.714 320v18.286c0 5.143-4 9.143-9.143 9.143h-27.429v9.143c0 5.143-4 9.143-9.143 9.143h-64v-73.143h64c5.143 0 9.143 4 9.143 9.143v9.143h27.429c5.143 0 9.143 4 9.143 9.143zM877.714 173.714v18.286c0 5.143-4 9.143-9.143 9.143h-27.429v9.143c0 5.143-4 9.143-9.143 9.143h-64v-73.143h64c5.143 0 9.143 4 9.143 9.143v9.143h27.429c5.143 0 9.143 4 9.143 9.143z"],"width":877.7142857142857,"attrs":[],"isMulticolor":false,"isMulticolor2":false,"colorPermutations":{"18919919916779841":[],"12714014111291321":[]},"tags":["microchip"],"defaultCode":62171,"grid":14},"attrs":[],"properties":{"name":"microchip","id":187,"order":693,"prevSize":28,"code":62171},"setIdx":0,"setId":1,"iconIdx":198}],"height":1024,"metadata":{"name":"FontAwesome"},"preferences":{"showGlyphs":true,"showQuickUse":true,"showQuickUse2":true,"showSVGs":true,"fontPref":{"prefix":"fa-","metadata":{"fontFamily":"FontAwesome","majorVersion":1,"minorVersion":0},"metrics":{"emSize":1024,"baseline":6.25,"whitespace":50},"embed":false,"noie8":true,"ie7":false,"showSelector":false,"selector":"i","showMetrics":false,"showMetadata":false,"showVersion":false},"imagePref":{"prefix":"icon-","png":true,"useClassSelector":true,"color":0,"bgColor":16777215,"classSelector":".icon","name":"icomoon"},"historySize":50,"showCodes":true,"gridSize":16}} diff --git a/arduino-ide-extension/package.json b/arduino-ide-extension/package.json index 3cf6e2c6e..f717a4d9a 100644 --- a/arduino-ide-extension/package.json +++ b/arduino-ide-extension/package.json @@ -53,7 +53,6 @@ "@types/js-yaml": "^3.12.2", "@types/keytar": "^4.4.0", "@types/lodash.debounce": "^4.0.6", - "@types/ncp": "^2.0.4", "@types/node-fetch": "^2.5.7", "@types/p-queue": "^2.3.1", "@types/ps-tree": "^1.1.0", @@ -66,6 +65,7 @@ "auth0-js": "^9.14.0", "btoa": "^1.2.1", "classnames": "^2.3.1", + "cpy": "^8.1.2", "cross-fetch": "^3.1.5", "dateformat": "^3.0.3", "deepmerge": "2.0.1", @@ -76,6 +76,7 @@ "glob": "^7.1.6", "google-protobuf": "^3.20.1", "hash.js": "^1.1.7", + "is-online": "^9.0.1", "js-yaml": "^3.13.1", "jsonc-parser": "^2.2.0", "just-diff": "^5.1.1", @@ -83,7 +84,6 @@ "keytar": "7.2.0", "lodash.debounce": "^4.0.8", "minimatch": "^3.1.2", - "ncp": "^2.0.0", "node-fetch": "^2.6.1", "open": "^8.0.6", "p-debounce": "^2.1.0", @@ -120,6 +120,7 @@ "mocha": "^7.0.0", "mockdate": "^3.0.5", "moment": "^2.24.0", + "ncp": "^2.0.0", "protoc": "^1.0.4", "shelljs": "^0.8.3", "uuid": "^3.2.1", diff --git a/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts b/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts index 73ed052e9..6c6b44a63 100644 --- a/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts +++ b/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts @@ -93,6 +93,8 @@ import { EditorCommandContribution as TheiaEditorCommandContribution } from '@th import { FrontendConnectionStatusService, ApplicationConnectionStatusContribution, + DaemonPort, + IsOnline, } from './theia/core/connection-status-service'; import { FrontendConnectionStatusService as TheiaFrontendConnectionStatusService, @@ -353,6 +355,7 @@ import { CreateFeatures } from './create/create-features'; import { Account } from './contributions/account'; import { SidebarBottomMenuWidget } from './theia/core/sidebar-bottom-menu-widget'; import { SidebarBottomMenuWidget as TheiaSidebarBottomMenuWidget } from '@theia/core/lib/browser/shell/sidebar-bottom-menu-widget'; +import { CreateCloudCopy } from './contributions/create-cloud-copy'; export default new ContainerModule((bind, unbind, isBound, rebind) => { // Commands and toolbar items @@ -741,6 +744,8 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => { Contribution.configure(bind, ValidateSketch); Contribution.configure(bind, RenameCloudSketch); Contribution.configure(bind, Account); + Contribution.configure(bind, CloudSketchbookContribution); + Contribution.configure(bind, CreateCloudCopy); bindContributionProvider(bind, StartupTaskProvider); bind(StartupTaskProvider).toService(BoardsServiceProvider); // to reuse the boards config in another window @@ -919,8 +924,6 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => { bind(CreateFsProvider).toSelf().inSingletonScope(); bind(FrontendApplicationContribution).toService(CreateFsProvider); bind(FileServiceContribution).toService(CreateFsProvider); - bind(CloudSketchbookContribution).toSelf().inSingletonScope(); - bind(CommandContribution).toService(CloudSketchbookContribution); bind(LocalCacheFsProvider).toSelf().inSingletonScope(); bind(FileServiceContribution).toService(LocalCacheFsProvider); bind(CloudSketchbookCompositeWidget).toSelf(); @@ -1026,4 +1029,9 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => { rebind(TheiaSidebarBottomMenuWidget).toService(SidebarBottomMenuWidget); bind(ArduinoComponentContextMenuRenderer).toSelf().inSingletonScope(); + + bind(DaemonPort).toSelf().inSingletonScope(); + bind(FrontendApplicationContribution).toService(DaemonPort); + bind(IsOnline).toSelf().inSingletonScope(); + bind(FrontendApplicationContribution).toService(IsOnline); }); diff --git a/arduino-ide-extension/src/browser/contributions/account.ts b/arduino-ide-extension/src/browser/contributions/account.ts index cb82229ad..a8f728de2 100644 --- a/arduino-ide-extension/src/browser/contributions/account.ts +++ b/arduino-ide-extension/src/browser/contributions/account.ts @@ -8,6 +8,7 @@ import { inject, injectable } from '@theia/core/shared/inversify'; import { CloudUserCommands, LEARN_MORE_URL } from '../auth/cloud-user-commands'; import { CreateFeatures } from '../create/create-features'; import { ArduinoMenus } from '../menu/arduino-menus'; +import { ApplicationConnectionStatusContribution } from '../theia/core/connection-status-service'; import { Command, CommandRegistry, @@ -29,6 +30,8 @@ export class Account extends Contribution { private readonly windowService: WindowService; @inject(CreateFeatures) private readonly createFeatures: CreateFeatures; + @inject(ApplicationConnectionStatusContribution) + private readonly connectionStatus: ApplicationConnectionStatusContribution; private readonly toDispose = new DisposableCollection(); private app: FrontendApplication; @@ -50,21 +53,28 @@ export class Account extends Contribution { override registerCommands(registry: CommandRegistry): void { const openExternal = (url: string) => this.windowService.openNewWindow(url, { external: true }); + const loggedIn = () => Boolean(this.createFeatures.session); + const loggedInWithInternetConnection = () => + loggedIn() && this.connectionStatus.offlineStatus !== 'internet'; registry.registerCommand(Account.Commands.LEARN_MORE, { execute: () => openExternal(LEARN_MORE_URL), - isEnabled: () => !Boolean(this.createFeatures.session), + isEnabled: () => !loggedIn(), + isVisible: () => !loggedIn(), }); registry.registerCommand(Account.Commands.GO_TO_PROFILE, { execute: () => openExternal('https://id.arduino.cc/'), - isEnabled: () => Boolean(this.createFeatures.session), + isEnabled: () => loggedInWithInternetConnection(), + isVisible: () => loggedIn(), }); registry.registerCommand(Account.Commands.GO_TO_CLOUD_EDITOR, { execute: () => openExternal('https://create.arduino.cc/editor'), - isEnabled: () => Boolean(this.createFeatures.session), + isEnabled: () => loggedInWithInternetConnection(), + isVisible: () => loggedIn(), }); registry.registerCommand(Account.Commands.GO_TO_IOT_CLOUD, { execute: () => openExternal('https://create.arduino.cc/iot/'), - isEnabled: () => Boolean(this.createFeatures.session), + isEnabled: () => loggedInWithInternetConnection(), + isVisible: () => loggedIn(), }); } diff --git a/arduino-ide-extension/src/browser/contributions/cloud-contribution.ts b/arduino-ide-extension/src/browser/contributions/cloud-contribution.ts index c13abd89c..47e14210d 100644 --- a/arduino-ide-extension/src/browser/contributions/cloud-contribution.ts +++ b/arduino-ide-extension/src/browser/contributions/cloud-contribution.ts @@ -93,7 +93,7 @@ export abstract class CloudSketchContribution extends SketchContribution { ); } try { - await treeModel.sketchbookTree().pull({ node }); + await treeModel.sketchbookTree().pull({ node }, true); return node; } catch (err) { if (isNotFound(err)) { diff --git a/arduino-ide-extension/src/browser/contributions/contribution.ts b/arduino-ide-extension/src/browser/contributions/contribution.ts index 3260ab7b9..c53bac1ff 100644 --- a/arduino-ide-extension/src/browser/contributions/contribution.ts +++ b/arduino-ide-extension/src/browser/contributions/contribution.ts @@ -14,7 +14,6 @@ import { EditorManager } from '@theia/editor/lib/browser/editor-manager'; import { MessageService } from '@theia/core/lib/common/message-service'; import { EnvVariablesServer } from '@theia/core/lib/common/env-variables'; import { open, OpenerService } from '@theia/core/lib/browser/opener-service'; - import { MenuModelRegistry, MenuContribution, @@ -58,7 +57,7 @@ import { ClipboardService } from '@theia/core/lib/browser/clipboard-service'; import { ExecuteWithProgress } from '../../common/protocol/progressible'; import { BoardsServiceProvider } from '../boards/boards-service-provider'; import { BoardsDataStore } from '../boards/boards-data-store'; -import { NotificationManager } from '../theia/messages/notifications-manager'; +import { NotificationManager } from '@theia/messages/lib/browser/notifications-manager'; import { MessageType } from '@theia/core/lib/common/message-service-protocol'; import { WorkspaceService } from '../theia/workspace/workspace-service'; import { MainMenuManager } from '../../common/main-menu-manager'; @@ -295,7 +294,7 @@ export abstract class CoreServiceContribution extends SketchContribution { } private notificationId(message: string, ...actions: string[]): string { - return this.notificationManager.getMessageId({ + return this.notificationManager['getMessageId']({ text: message, actions, type: MessageType.Error, diff --git a/arduino-ide-extension/src/browser/contributions/create-cloud-copy.ts b/arduino-ide-extension/src/browser/contributions/create-cloud-copy.ts new file mode 100644 index 000000000..73b967f0f --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/create-cloud-copy.ts @@ -0,0 +1,118 @@ +import { FrontendApplication } from '@theia/core/lib/browser/frontend-application'; +import { ApplicationShell } from '@theia/core/lib/browser/shell'; +import type { Command, CommandRegistry } from '@theia/core/lib/common/command'; +import { Progress } from '@theia/core/lib/common/message-service-protocol'; +import { nls } from '@theia/core/lib/common/nls'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { Create } from '../create/typings'; +import { ApplicationConnectionStatusContribution } from '../theia/core/connection-status-service'; +import { CloudSketchbookTree } from '../widgets/cloud-sketchbook/cloud-sketchbook-tree'; +import { SketchbookTree } from '../widgets/sketchbook/sketchbook-tree'; +import { SketchbookTreeModel } from '../widgets/sketchbook/sketchbook-tree-model'; +import { CloudSketchContribution, pushingSketch } from './cloud-contribution'; +import { + CreateNewCloudSketchCallback, + NewCloudSketch, + NewCloudSketchParams, +} from './new-cloud-sketch'; +import { saveOntoCopiedSketch } from './save-as-sketch'; + +interface CreateCloudCopyParams { + readonly model: SketchbookTreeModel; + readonly node: SketchbookTree.SketchDirNode; +} +function isCreateCloudCopyParams(arg: unknown): arg is CreateCloudCopyParams { + return ( + typeof arg === 'object' && + (<CreateCloudCopyParams>arg).model !== undefined && + (<CreateCloudCopyParams>arg).model instanceof SketchbookTreeModel && + (<CreateCloudCopyParams>arg).node !== undefined && + SketchbookTree.SketchDirNode.is((<CreateCloudCopyParams>arg).node) + ); +} + +@injectable() +export class CreateCloudCopy extends CloudSketchContribution { + @inject(ApplicationConnectionStatusContribution) + private readonly connectionStatus: ApplicationConnectionStatusContribution; + + private shell: ApplicationShell; + + override onStart(app: FrontendApplication): void { + this.shell = app.shell; + } + + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(CreateCloudCopy.Commands.CREATE_CLOUD_COPY, { + execute: (args: CreateCloudCopyParams) => this.createCloudCopy(args), + isEnabled: (args: unknown) => + Boolean(this.createFeatures.session) && isCreateCloudCopyParams(args), + isVisible: (args: unknown) => + Boolean(this.createFeatures.enabled) && + Boolean(this.createFeatures.session) && + this.connectionStatus.offlineStatus !== 'internet' && + isCreateCloudCopyParams(args), + }); + } + + /** + * - creates new cloud sketch with the name of the params sketch, + * - pulls the cloud sketch, + * - copies files from params sketch to pulled cloud sketch in the cache folder, + * - pushes the cloud sketch, and + * - opens in new window. + */ + private async createCloudCopy(params: CreateCloudCopyParams): Promise<void> { + const sketch = await this.sketchesService.loadSketch( + params.node.fileStat.resource.toString() + ); + const callback: CreateNewCloudSketchCallback = async ( + newSketch: Create.Sketch, + newNode: CloudSketchbookTree.CloudSketchDirNode, + progress: Progress + ) => { + const treeModel = await this.treeModel(); + if (!treeModel) { + throw new Error('Could not retrieve the cloud sketchbook tree model.'); + } + + progress.report({ + message: nls.localize( + 'arduino/createCloudCopy/copyingSketchFilesMessage', + 'Copying local sketch files...' + ), + }); + const localCacheFolderUri = newNode.uri.toString(); + await this.sketchesService.copy(sketch, { + destinationUri: localCacheFolderUri, + onlySketchFiles: true, + }); + await saveOntoCopiedSketch( + sketch, + localCacheFolderUri, + this.shell, + this.editorManager + ); + + progress.report({ message: pushingSketch(newSketch.name) }); + await treeModel.sketchbookTree().push(newNode, true, true); + }; + return this.commandService.executeCommand( + NewCloudSketch.Commands.NEW_CLOUD_SKETCH.id, + <NewCloudSketchParams>{ + initialValue: params.node.fileStat.name, + callback, + skipShowErrorMessageOnOpen: false, + } + ); + } +} + +export namespace CreateCloudCopy { + export namespace Commands { + export const CREATE_CLOUD_COPY: Command = { + id: 'arduino-create-cloud-copy', + iconClass: 'fa fa-arduino-cloud-upload', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/new-cloud-sketch.ts b/arduino-ide-extension/src/browser/contributions/new-cloud-sketch.ts index 4d449b121..d165c4779 100644 --- a/arduino-ide-extension/src/browser/contributions/new-cloud-sketch.ts +++ b/arduino-ide-extension/src/browser/contributions/new-cloud-sketch.ts @@ -6,7 +6,7 @@ import { Progress } from '@theia/core/lib/common/message-service-protocol'; import { nls } from '@theia/core/lib/common/nls'; import { injectable } from '@theia/core/shared/inversify'; import { CreateUri } from '../create/create-uri'; -import { isConflict } from '../create/typings'; +import { Create, isConflict } from '../create/typings'; import { ArduinoMenus } from '../menu/arduino-menus'; import { TaskFactoryImpl, @@ -15,13 +15,36 @@ import { import { CloudSketchbookTree } from '../widgets/cloud-sketchbook/cloud-sketchbook-tree'; import { CloudSketchbookTreeModel } from '../widgets/cloud-sketchbook/cloud-sketchbook-tree-model'; import { SketchbookCommands } from '../widgets/sketchbook/sketchbook-commands'; -import { Command, CommandRegistry, Sketch } from './contribution'; import { CloudSketchContribution, pullingSketch, sketchAlreadyExists, synchronizingSketchbook, } from './cloud-contribution'; +import { Command, CommandRegistry, Sketch } from './contribution'; + +export interface CreateNewCloudSketchCallback { + ( + newSketch: Create.Sketch, + newNode: CloudSketchbookTree.CloudSketchDirNode, + progress: Progress + ): Promise<void>; +} + +export interface NewCloudSketchParams { + /** + * Value to populate the dialog `<input>` when it opens. + */ + readonly initialValue?: string | undefined; + /** + * Additional callback to call when the new cloud sketch has been created. + */ + readonly callback?: CreateNewCloudSketchCallback; + /** + * If `true`, the validation error message will not be visible in the input dialog, but the `OK` button will be disabled. Defaults to `true`. + */ + readonly skipShowErrorMessageOnOpen?: boolean; +} @injectable() export class NewCloudSketch extends CloudSketchContribution { @@ -43,7 +66,12 @@ export class NewCloudSketch extends CloudSketchContribution { override registerCommands(registry: CommandRegistry): void { registry.registerCommand(NewCloudSketch.Commands.NEW_CLOUD_SKETCH, { - execute: () => this.createNewSketch(true), + execute: (params: NewCloudSketchParams) => + this.createNewSketch( + params?.skipShowErrorMessageOnOpen === false ? false : true, + params?.initialValue, + params?.callback + ), isEnabled: () => Boolean(this.createFeatures.session), isVisible: () => this.createFeatures.enabled, }); @@ -66,7 +94,8 @@ export class NewCloudSketch extends CloudSketchContribution { private async createNewSketch( skipShowErrorMessageOnOpen: boolean, - initialValue?: string | undefined + initialValue?: string | undefined, + callback?: CreateNewCloudSketchCallback ): Promise<void> { const treeModel = await this.treeModel(); if (treeModel) { @@ -75,7 +104,8 @@ export class NewCloudSketch extends CloudSketchContribution { rootNode, treeModel, skipShowErrorMessageOnOpen, - initialValue + initialValue, + callback ); } } @@ -84,13 +114,14 @@ export class NewCloudSketch extends CloudSketchContribution { rootNode: CompositeTreeNode, treeModel: CloudSketchbookTreeModel, skipShowErrorMessageOnOpen: boolean, - initialValue?: string | undefined + initialValue?: string | undefined, + callback?: CreateNewCloudSketchCallback ): Promise<void> { const existingNames = rootNode.children .filter(CloudSketchbookTree.CloudSketchDirNode.is) .map(({ fileStat }) => fileStat.name); const taskFactory = new TaskFactoryImpl((value) => - this.createNewSketchWithProgress(treeModel, value) + this.createNewSketchWithProgress(treeModel, value, callback) ); try { const dialog = new WorkspaceInputDialogWithProgress( @@ -118,7 +149,11 @@ export class NewCloudSketch extends CloudSketchContribution { } catch (err) { if (isConflict(err)) { await treeModel.refresh(); - return this.createNewSketch(false, taskFactory.value ?? initialValue); + return this.createNewSketch( + false, + taskFactory.value ?? initialValue, + callback + ); } throw err; } @@ -126,7 +161,8 @@ export class NewCloudSketch extends CloudSketchContribution { private createNewSketchWithProgress( treeModel: CloudSketchbookTreeModel, - value: string + value: string, + callback?: CreateNewCloudSketchCallback ): ( progress: Progress ) => Promise<CloudSketchbookTree.CloudSketchDirNode | undefined> { @@ -143,6 +179,9 @@ export class NewCloudSketch extends CloudSketchContribution { await treeModel.refresh(); progress.report({ message: pullingSketch(sketch.name) }); const node = await this.pull(sketch); + if (callback && node) { + await callback(sketch, node, progress); + } return node; }; } @@ -152,7 +191,7 @@ export class NewCloudSketch extends CloudSketchContribution { ): Promise<void> { return this.commandService.executeCommand( SketchbookCommands.OPEN_NEW_WINDOW.id, - { node } + { node, treeWidgetId: 'cloud-sketchbook-composite-widget' } ); } } diff --git a/arduino-ide-extension/src/browser/contributions/rename-cloud-sketch.ts b/arduino-ide-extension/src/browser/contributions/rename-cloud-sketch.ts index faed8d070..5cee63f0e 100644 --- a/arduino-ide-extension/src/browser/contributions/rename-cloud-sketch.ts +++ b/arduino-ide-extension/src/browser/contributions/rename-cloud-sketch.ts @@ -123,7 +123,7 @@ export class RenameCloudSketch extends CloudSketchContribution { const toPosixPath = params.cloudUri.parent.resolve(value).path.toString(); // push progress.report({ message: pushingSketch(params.sketch.name) }); - await treeModel.sketchbookTree().push(node); + await treeModel.sketchbookTree().push(node, true); // rename progress.report({ diff --git a/arduino-ide-extension/src/browser/contributions/save-as-sketch.ts b/arduino-ide-extension/src/browser/contributions/save-as-sketch.ts index 82fcec530..e57f16191 100644 --- a/arduino-ide-extension/src/browser/contributions/save-as-sketch.ts +++ b/arduino-ide-extension/src/browser/contributions/save-as-sketch.ts @@ -6,6 +6,7 @@ import { ApplicationShell } from '@theia/core/lib/browser/shell/application-shel import { WindowService } from '@theia/core/lib/browser/window/window-service'; import { nls } from '@theia/core/lib/common/nls'; import { inject, injectable } from '@theia/core/shared/inversify'; +import { EditorManager } from '@theia/editor/lib/browser/editor-manager'; import { WorkspaceInput } from '@theia/workspace/lib/browser/workspace-service'; import { StartupTask } from '../../electron-common/startup-task'; import { ArduinoMenus } from '../menu/arduino-menus'; @@ -28,7 +29,7 @@ import { @injectable() export class SaveAsSketch extends CloudSketchContribution { @inject(ApplicationShell) - private readonly applicationShell: ApplicationShell; + private readonly shell: ApplicationShell; @inject(WindowService) private readonly windowService: WindowService; @@ -80,14 +81,17 @@ export class SaveAsSketch extends CloudSketchContribution { return false; } - const newWorkspaceUri = await this.sketchesService.copy(sketch, { + const copiedSketch = await this.sketchesService.copy(sketch, { destinationUri, }); - if (!newWorkspaceUri) { - return false; - } + const newWorkspaceUri = copiedSketch.uri; - await this.saveOntoCopiedSketch(sketch, newWorkspaceUri); + await saveOntoCopiedSketch( + sketch, + newWorkspaceUri, + this.shell, + this.editorManager + ); if (markAsRecentlyOpened) { this.sketchesService.markAsRecentlyOpened(newWorkspaceUri); } @@ -238,53 +242,6 @@ ${dialogContent.question}`.trim(); } return sketchFolderDestinationUri; } - - private async saveOntoCopiedSketch( - sketch: Sketch, - newSketchFolderUri: string - ): Promise<void> { - const widgets = this.applicationShell.widgets; - const snapshots = new Map<string, Saveable.Snapshot>(); - for (const widget of widgets) { - const saveable = Saveable.getDirty(widget); - const uri = NavigatableWidget.getUri(widget); - if (!uri) { - continue; - } - const uriString = uri.toString(); - let relativePath: string; - if ( - uriString.includes(sketch.uri) && - saveable && - saveable.createSnapshot - ) { - // The main file will change its name during the copy process - // We need to store the new name in the map - if (sketch.mainFileUri === uriString) { - const lastPart = new URI(newSketchFolderUri).path.base + uri.path.ext; - relativePath = '/' + lastPart; - } else { - relativePath = uri.toString().substring(sketch.uri.length); - } - snapshots.set(relativePath, saveable.createSnapshot()); - } - } - await Promise.all( - Array.from(snapshots.entries()).map(async ([path, snapshot]) => { - const widgetUri = new URI(newSketchFolderUri + path); - try { - const widget = await this.editorManager.getOrCreateByUri(widgetUri); - const saveable = Saveable.get(widget); - if (saveable && saveable.applySnapshot) { - saveable.applySnapshot(snapshot); - await saveable.save(); - } - } catch (e) { - console.error(e); - } - }) - ); - } } interface InvalidSketchFolderDialogContent { @@ -317,3 +274,48 @@ export namespace SaveAsSketch { }; } } + +export async function saveOntoCopiedSketch( + sketch: Sketch, + newSketchFolderUri: string, + shell: ApplicationShell, + editorManager: EditorManager +): Promise<void> { + const widgets = shell.widgets; + const snapshots = new Map<string, Saveable.Snapshot>(); + for (const widget of widgets) { + const saveable = Saveable.getDirty(widget); + const uri = NavigatableWidget.getUri(widget); + if (!uri) { + continue; + } + const uriString = uri.toString(); + let relativePath: string; + if (uriString.includes(sketch.uri) && saveable && saveable.createSnapshot) { + // The main file will change its name during the copy process + // We need to store the new name in the map + if (sketch.mainFileUri === uriString) { + const lastPart = new URI(newSketchFolderUri).path.base + uri.path.ext; + relativePath = '/' + lastPart; + } else { + relativePath = uri.toString().substring(sketch.uri.length); + } + snapshots.set(relativePath, saveable.createSnapshot()); + } + } + await Promise.all( + Array.from(snapshots.entries()).map(async ([path, snapshot]) => { + const widgetUri = new URI(newSketchFolderUri + path); + try { + const widget = await editorManager.getOrCreateByUri(widgetUri); + const saveable = Saveable.get(widget); + if (saveable && saveable.applySnapshot) { + saveable.applySnapshot(snapshot); + await saveable.save(); + } + } catch (e) { + console.error(e); + } + }) + ); +} diff --git a/arduino-ide-extension/src/browser/create/create-api.ts b/arduino-ide-extension/src/browser/create/create-api.ts index 4c988f5df..72c27cbb0 100644 --- a/arduino-ide-extension/src/browser/create/create-api.ts +++ b/arduino-ide-extension/src/browser/create/create-api.ts @@ -2,7 +2,7 @@ import { MaybePromise } from '@theia/core/lib/common/types'; import { inject, injectable } from '@theia/core/shared/inversify'; import { fetch } from 'cross-fetch'; import { SketchesService } from '../../common/protocol'; -import { unit8ArrayToString } from '../../common/utils'; +import { uint8ArrayToString } from '../../common/utils'; import { ArduinoPreferences } from '../arduino-preferences'; import { AuthenticationClientService } from '../auth/authentication-client-service'; import { SketchCache } from '../widgets/cloud-sketchbook/cloud-sketch-cache'; @@ -10,11 +10,11 @@ import * as createPaths from './create-paths'; import { posix } from './create-paths'; import { Create, CreateError } from './typings'; -export interface ResponseResultProvider { +interface ResponseResultProvider { // eslint-disable-next-line @typescript-eslint/no-explicit-any (response: Response): Promise<any>; } -export namespace ResponseResultProvider { +namespace ResponseResultProvider { export const NOOP: ResponseResultProvider = async () => undefined; export const TEXT: ResponseResultProvider = (response) => response.text(); export const JSON: ResponseResultProvider = (response) => response.json(); @@ -288,10 +288,9 @@ export class CreateApi { if (sketch) { const url = new URL(`${this.domain()}/sketches/${sketch.id}`); const headers = await this.headers(); - // parse the secret file const secrets = ( - typeof content === 'string' ? content : unit8ArrayToString(content) + typeof content === 'string' ? content : uint8ArrayToString(content) ) .split(/\r?\n/) .reduce((prev, curr) => { @@ -355,7 +354,7 @@ export class CreateApi { const headers = await this.headers(); let data: string = - typeof content === 'string' ? content : unit8ArrayToString(content); + typeof content === 'string' ? content : uint8ArrayToString(content); data = await this.toggleSecretsInclude(posixPath, data, 'remove'); const payload = { data: btoa(data) }; diff --git a/arduino-ide-extension/src/browser/create/create-features.ts b/arduino-ide-extension/src/browser/create/create-features.ts index bb61de5b5..befce589d 100644 --- a/arduino-ide-extension/src/browser/create/create-features.ts +++ b/arduino-ide-extension/src/browser/create/create-features.ts @@ -8,6 +8,9 @@ import { AuthenticationSession } from '../../node/auth/types'; import { ArduinoPreferences } from '../arduino-preferences'; import { AuthenticationClientService } from '../auth/authentication-client-service'; import { LocalCacheFsProvider } from '../local-cache/local-cache-fs-provider'; +import { CreateUri } from './create-uri'; + +export type CloudSketchState = 'push' | 'pull'; @injectable() export class CreateFeatures implements FrontendApplicationContribution { @@ -18,13 +21,22 @@ export class CreateFeatures implements FrontendApplicationContribution { @inject(LocalCacheFsProvider) private readonly localCacheFsProvider: LocalCacheFsProvider; + /** + * The keys are the Create URI of the sketches. + */ + private readonly _cloudSketchStates = new Map<string, CloudSketchState>(); private readonly onDidChangeSessionEmitter = new Emitter< AuthenticationSession | undefined >(); private readonly onDidChangeEnabledEmitter = new Emitter<boolean>(); + private readonly onDidChangeCloudSketchStateEmitter = new Emitter<{ + uri: URI; + state: CloudSketchState | undefined; + }>(); private readonly toDispose = new DisposableCollection( this.onDidChangeSessionEmitter, - this.onDidChangeEnabledEmitter + this.onDidChangeEnabledEmitter, + this.onDidChangeCloudSketchStateEmitter ); private _enabled: boolean; private _session: AuthenticationSession | undefined; @@ -64,14 +76,46 @@ export class CreateFeatures implements FrontendApplicationContribution { return this.onDidChangeEnabledEmitter.event; } - get enabled(): boolean { - return this._enabled; + get onDidChangeCloudSketchState(): Event<{ + uri: URI; + state: CloudSketchState | undefined; + }> { + return this.onDidChangeCloudSketchStateEmitter.event; } get session(): AuthenticationSession | undefined { return this._session; } + get enabled(): boolean { + return this._enabled; + } + + cloudSketchState(uri: URI): CloudSketchState | undefined { + return this._cloudSketchStates.get(uri.toString()); + } + + setCloudSketchState(uri: URI, state: CloudSketchState | undefined): void { + if (uri.scheme !== CreateUri.scheme) { + throw new Error( + `Expected a URI with '${uri.scheme}' scheme. Got: ${uri.toString()}` + ); + } + const key = uri.toString(); + if (!state) { + if (!this._cloudSketchStates.delete(key)) { + console.warn( + `Could not reset the cloud sketch state of ${key}. No state existed for the the cloud sketch.` + ); + } else { + this.onDidChangeCloudSketchStateEmitter.fire({ uri, state: undefined }); + } + } else { + this._cloudSketchStates.set(key, state); + this.onDidChangeCloudSketchStateEmitter.fire({ uri, state }); + } + } + /** * `true` if the sketch is under `directories.data/RemoteSketchbook`. Otherwise, `false`. * Returns with `undefined` if `dataDirUri` is `undefined`. @@ -83,7 +127,10 @@ export class CreateFeatures implements FrontendApplicationContribution { ); return undefined; } - return dataDirUri.isEqualOrParent(new URI(sketch.uri)); + return dataDirUri + .resolve('RemoteSketchbook') + .resolve('ArduinoCloud') + .isEqualOrParent(new URI(sketch.uri)); } cloudUri(sketch: Sketch): URI | undefined { diff --git a/arduino-ide-extension/src/browser/style/pull-sketch-icon.svg b/arduino-ide-extension/src/browser/icons/arduino-cloud-download.svg similarity index 100% rename from arduino-ide-extension/src/browser/style/pull-sketch-icon.svg rename to arduino-ide-extension/src/browser/icons/arduino-cloud-download.svg diff --git a/arduino-ide-extension/src/browser/icons/arduino-cloud-filled-offline.svg b/arduino-ide-extension/src/browser/icons/arduino-cloud-filled-offline.svg new file mode 100644 index 000000000..b86bb5209 --- /dev/null +++ b/arduino-ide-extension/src/browser/icons/arduino-cloud-filled-offline.svg @@ -0,0 +1,4 @@ +<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M13.355 3.85509L2.85504 14.3551C2.76026 14.448 2.63281 14.5001 2.50006 14.5001C2.36731 14.5001 2.23986 14.448 2.14508 14.3551C2.0514 14.2607 1.99882 14.1331 1.99882 14.0001C1.99882 13.8671 2.0514 13.7395 2.14508 13.6451L3.82508 11.9651C3.24351 11.8742 2.70645 11.5991 2.29291 11.1802C1.87936 10.7613 1.61116 10.2208 1.52775 9.63811C1.44434 9.05543 1.55012 8.46136 1.82955 7.94328C2.10897 7.4252 2.54728 7.01047 3.08 6.76009C3.20492 6.18251 3.47405 5.64596 3.86232 5.20047C4.25058 4.75498 4.74532 4.41505 5.30042 4.21239C5.85552 4.00972 6.45289 3.9509 7.03686 4.04143C7.62082 4.13196 8.17236 4.36887 8.64004 4.73009C9.01346 4.56809 9.41786 4.48995 9.82475 4.50117C10.2316 4.51239 10.6311 4.6127 10.995 4.79503L12.645 3.14509C12.7392 3.05094 12.8669 2.99805 13 2.99805C13.1332 2.99805 13.2609 3.05094 13.355 3.14509C13.4492 3.23924 13.5021 3.36694 13.5021 3.50009C13.5021 3.63324 13.4492 3.76094 13.355 3.85509V3.85509Z" fill="#7F8C8D"/> +<path d="M14.5 9.25047C14.4987 9.97942 14.2086 10.6782 13.6931 11.1936C13.1777 11.709 12.479 11.9992 11.75 12.0005H6.70996L12.355 6.35547C12.38 6.43042 12.4 6.50547 12.4201 6.58044C13.0153 6.72902 13.5436 7.07272 13.9206 7.55669C14.2976 8.04066 14.5016 8.63699 14.5 9.25047V9.25047Z" fill="#7F8C8D"/> +</svg> diff --git a/arduino-ide-extension/src/browser/icons/arduino-cloud-filled.svg b/arduino-ide-extension/src/browser/icons/arduino-cloud-filled.svg new file mode 100644 index 000000000..e51c12063 --- /dev/null +++ b/arduino-ide-extension/src/browser/icons/arduino-cloud-filled.svg @@ -0,0 +1,3 @@ +<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M14.5 9.24997C14.4987 9.97893 14.2086 10.6777 13.6932 11.1931C13.1777 11.7086 12.479 11.9987 11.75 12H4.25003C3.62476 11.9998 3.01822 11.7866 2.53034 11.3955C2.04247 11.0045 1.70238 10.4589 1.56612 9.84864C1.42986 9.2384 1.50556 8.59995 1.78074 8.0385C2.05593 7.47705 2.51418 7.0261 3.07998 6.75997C3.2049 6.18239 3.47404 5.64584 3.8623 5.20035C4.25056 4.75486 4.74531 4.41494 5.3004 4.21227C5.8555 4.0096 6.45288 3.95078 7.03684 4.04131C7.62081 4.13184 8.17234 4.36875 8.64003 4.72997C8.99025 4.57772 9.36814 4.49942 9.75003 4.49997C10.3635 4.49838 10.9598 4.70238 11.4438 5.07939C11.9278 5.45641 12.2715 5.9847 12.4201 6.57993C13.0153 6.7285 13.5436 7.07221 13.9206 7.55618C14.2976 8.04015 14.5016 8.63649 14.5 9.24997Z" fill="#7F8C8D"/> +</svg> diff --git a/arduino-ide-extension/src/browser/icons/arduino-cloud-offline.svg b/arduino-ide-extension/src/browser/icons/arduino-cloud-offline.svg new file mode 100644 index 000000000..26a284adc --- /dev/null +++ b/arduino-ide-extension/src/browser/icons/arduino-cloud-offline.svg @@ -0,0 +1,4 @@ +<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M12.42 6.58044C12.4 6.50549 12.38 6.43042 12.355 6.35547L11.525 7.18555C11.5575 7.27223 11.6136 7.34811 11.6869 7.40464C11.7603 7.46117 11.8479 7.4961 11.94 7.50549C12.3852 7.55476 12.7947 7.77259 13.0843 8.11428C13.374 8.45597 13.5218 8.89557 13.4975 9.34284C13.4732 9.7901 13.2785 10.2111 12.9536 10.5194C12.6286 10.8276 12.1979 10.9998 11.75 11.0005H7.70996L6.70996 12.0005H11.75C12.421 12.0001 13.0688 11.7545 13.5714 11.3099C14.074 10.8653 14.3969 10.2524 14.4792 9.58644C14.5615 8.92048 14.3977 8.24739 14.0184 7.69379C13.6392 7.14019 13.0708 6.74425 12.42 6.58044V6.58044Z" fill="#7F8C8D"/> +<path d="M13.355 3.14532C13.2606 3.05161 13.133 2.99902 13 2.99902C12.867 2.99902 12.7394 3.05161 12.6451 3.14532L10.995 4.79524C10.6311 4.61291 10.2316 4.5126 9.82472 4.50139C9.41783 4.49017 9.01343 4.56832 8.64002 4.73032C8.17233 4.3691 7.6208 4.13219 7.03684 4.04166C6.45287 3.95114 5.85549 4.00995 5.3004 4.21262C4.7453 4.41529 4.25056 4.75521 3.86229 5.2007C3.47403 5.64619 3.2049 6.18274 3.07997 6.76033C2.54726 7.01071 2.10896 7.42543 1.82954 7.9435C1.55013 8.46157 1.44434 9.05564 1.52775 9.63832C1.61115 10.221 1.87935 10.7615 2.29288 11.1804C2.70641 11.5993 3.24346 11.8744 3.82502 11.9653L2.14502 13.6453C2.05133 13.7397 1.99876 13.8673 1.99876 14.0003C1.99876 14.1333 2.05133 14.2609 2.14502 14.3553C2.23979 14.4482 2.36725 14.5003 2.5 14.5003C2.63275 14.5003 2.7602 14.4482 2.85498 14.3553L13.355 3.85528C13.4487 3.7609 13.5012 3.6333 13.5013 3.50031C13.5013 3.36732 13.4487 3.23972 13.355 3.14532V3.14532ZM4.79006 11.0003H4.25002C3.8356 11.0005 3.43458 10.8535 3.11841 10.5856C2.80224 10.3177 2.59145 9.94623 2.52362 9.5374C2.45578 9.12857 2.53529 8.70893 2.74799 8.35326C2.96069 7.99758 3.29275 7.72898 3.68502 7.59529C3.77434 7.56478 3.85319 7.50962 3.91248 7.43617C3.97176 7.36272 4.00904 7.274 4.02002 7.18025C4.09848 6.57783 4.39334 6.0245 4.84963 5.62341C5.30592 5.22233 5.89251 5.00087 6.50002 5.00032C7.1425 4.99652 7.76054 5.24628 8.21999 5.69539C8.30086 5.77275 8.40511 5.8211 8.5164 5.83285C8.6277 5.8446 8.73974 5.8191 8.83499 5.76033C9.10926 5.58886 9.42655 5.4987 9.75002 5.50032C9.9105 5.50127 10.0702 5.5231 10.225 5.56526L4.79006 11.0003Z" fill="#7F8C8D"/> +</svg> diff --git a/arduino-ide-extension/src/browser/style/push-sketch-icon.svg b/arduino-ide-extension/src/browser/icons/arduino-cloud-upload.svg similarity index 100% rename from arduino-ide-extension/src/browser/style/push-sketch-icon.svg rename to arduino-ide-extension/src/browser/icons/arduino-cloud-upload.svg diff --git a/arduino-ide-extension/src/browser/icons/arduino-cloud.svg b/arduino-ide-extension/src/browser/icons/arduino-cloud.svg new file mode 100644 index 000000000..4d23d15ae --- /dev/null +++ b/arduino-ide-extension/src/browser/icons/arduino-cloud.svg @@ -0,0 +1,3 @@ +<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg"> +<path d="M11.75 12H4.25C3.62484 11.9999 3.01838 11.7868 2.53053 11.3959C2.04269 11.0049 1.70257 10.4595 1.56622 9.84934C1.42987 9.23923 1.50542 8.60087 1.78043 8.03945C2.05543 7.47802 2.51348 7.02702 3.0791 6.76076C3.24864 5.97929 3.68041 5.27932 4.3027 4.77712C4.92499 4.27492 5.70035 4.00071 6.5 4.00002C7.27505 3.99715 8.02853 4.25513 8.63916 4.73244C9.00591 4.57154 9.40329 4.49243 9.8037 4.5006C10.2041 4.50877 10.5979 4.60403 10.9578 4.77976C11.3177 4.9555 11.635 5.20748 11.8876 5.51822C12.1403 5.82895 12.3223 6.19097 12.4209 6.57912C13.0715 6.74324 13.6398 7.13939 14.0188 7.69309C14.3979 8.24679 14.5616 8.91989 14.4792 9.58582C14.3967 10.2518 14.0739 10.8646 13.5713 11.3092C13.0687 11.7538 12.421 11.9995 11.75 12ZM6.5 5.00002C5.89213 5.00017 5.30514 5.22179 4.84885 5.62344C4.39257 6.02508 4.09826 6.57921 4.021 7.18215C4.0093 7.27546 3.97153 7.36357 3.91202 7.43638C3.85252 7.50918 3.77369 7.56374 3.68458 7.59377C3.29236 7.72769 2.9604 7.99647 2.7478 8.35224C2.5352 8.70801 2.45576 9.12768 2.52363 9.53654C2.5915 9.9454 2.80227 10.3169 3.11841 10.5849C3.43455 10.8529 3.83555 11 4.25 11H11.75C12.198 10.9996 12.6289 10.8275 12.9539 10.5191C13.279 10.2108 13.4735 9.7896 13.4975 9.34221C13.5215 8.89481 13.3732 8.45522 13.083 8.11384C12.7929 7.77246 12.3829 7.55524 11.9375 7.50686C11.8238 7.4948 11.7176 7.44411 11.6368 7.36325C11.5559 7.28238 11.5052 7.17624 11.4932 7.06252C11.4474 6.63255 11.2439 6.2348 10.9219 5.94619C10.6 5.65758 10.1824 5.49861 9.75 5.50002C9.42739 5.49791 9.11079 5.58731 8.83692 5.75783C8.74185 5.81746 8.62955 5.84352 8.51794 5.83184C8.40633 5.82015 8.30185 5.77141 8.22119 5.69338C7.76046 5.24569 7.14241 4.99672 6.5 5.00002V5.00002Z" fill="#7F8C8D"/> +</svg> diff --git a/arduino-ide-extension/src/browser/style/account-icon.svg b/arduino-ide-extension/src/browser/style/account-icon.svg deleted file mode 100644 index 2759d882f..000000000 --- a/arduino-ide-extension/src/browser/style/account-icon.svg +++ /dev/null @@ -1 +0,0 @@ -<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" aria-hidden="true" focusable="false" width="1em" height="1em" style="-ms-transform: rotate(360deg); -webkit-transform: rotate(360deg); transform: rotate(360deg);" preserveAspectRatio="xMidYMid meet" viewBox="0 0 16 16"><g fill="#626262"><path d="M16 7.992C16 3.58 12.416 0 8 0S0 3.58 0 7.992c0 2.43 1.104 4.62 2.832 6.09c.016.016.032.016.032.032c.144.112.288.224.448.336c.08.048.144.111.224.175A7.98 7.98 0 0 0 8.016 16a7.98 7.98 0 0 0 4.48-1.375c.08-.048.144-.111.224-.16c.144-.111.304-.223.448-.335c.016-.016.032-.016.032-.032c1.696-1.487 2.8-3.676 2.8-6.106zm-8 7.001c-1.504 0-2.88-.48-4.016-1.279c.016-.128.048-.255.08-.383a4.17 4.17 0 0 1 .416-.991c.176-.304.384-.576.64-.816c.24-.24.528-.463.816-.639c.304-.176.624-.304.976-.4A4.15 4.15 0 0 1 8 10.342a4.185 4.185 0 0 1 2.928 1.166c.368.368.656.8.864 1.295c.112.288.192.592.24.911A7.03 7.03 0 0 1 8 14.993zm-2.448-7.4a2.49 2.49 0 0 1-.208-1.024c0-.351.064-.703.208-1.023c.144-.32.336-.607.576-.847c.24-.24.528-.431.848-.575c.32-.144.672-.208 1.024-.208c.368 0 .704.064 1.024.208c.32.144.608.336.848.575c.24.24.432.528.576.847c.144.32.208.672.208 1.023c0 .368-.064.704-.208 1.023a2.84 2.84 0 0 1-.576.848a2.84 2.84 0 0 1-.848.575a2.715 2.715 0 0 1-2.064 0a2.84 2.84 0 0 1-.848-.575a2.526 2.526 0 0 1-.56-.848zm7.424 5.306c0-.032-.016-.048-.016-.08a5.22 5.22 0 0 0-.688-1.406a4.883 4.883 0 0 0-1.088-1.135a5.207 5.207 0 0 0-1.04-.608a2.82 2.82 0 0 0 .464-.383a4.2 4.2 0 0 0 .624-.784a3.624 3.624 0 0 0 .528-1.934a3.71 3.71 0 0 0-.288-1.47a3.799 3.799 0 0 0-.816-1.199a3.845 3.845 0 0 0-1.2-.8a3.72 3.72 0 0 0-1.472-.287a3.72 3.72 0 0 0-1.472.288a3.631 3.631 0 0 0-1.2.815a3.84 3.84 0 0 0-.8 1.199a3.71 3.71 0 0 0-.288 1.47c0 .352.048.688.144 1.007c.096.336.224.64.4.927c.16.288.384.544.624.784c.144.144.304.271.48.383a5.12 5.12 0 0 0-1.04.624c-.416.32-.784.703-1.088 1.119a4.999 4.999 0 0 0-.688 1.406c-.016.032-.016.064-.016.08C1.776 11.636.992 9.91.992 7.992C.992 4.14 4.144.991 8 .991s7.008 3.149 7.008 7.001a6.96 6.96 0 0 1-2.032 4.907z"/></g></svg> diff --git a/arduino-ide-extension/src/browser/style/cloud-sketchbook.css b/arduino-ide-extension/src/browser/style/cloud-sketchbook.css index f19159260..8982aaf34 100644 --- a/arduino-ide-extension/src/browser/style/cloud-sketchbook.css +++ b/arduino-ide-extension/src/browser/style/cloud-sketchbook.css @@ -15,10 +15,10 @@ .p-TabBar-tabIcon.cloud-sketchbook-tree-icon { background-color: var(--theia-foreground); - -webkit-mask: url(./cloud-sketchbook-tree-icon.svg); + -webkit-mask: url(../icons/arduino-cloud.svg); -webkit-mask-position: center; -webkit-mask-repeat: no-repeat; - width: var(--theia-icon-size); + width: 19px !important; height: var(--theia-icon-size); -webkit-mask-size: 100%; } @@ -26,7 +26,7 @@ .p-mod-current .cloud-sketchbook-tree-icon { background-color: var(--theia-foreground); - -webkit-mask: url(./cloud-sketchbook-tree-icon-filled.svg); + -webkit-mask: url(../icons/arduino-cloud-filled.svg); -webkit-mask-position: center; -webkit-mask-repeat: no-repeat; -webkit-mask-size: 100%; @@ -99,26 +99,7 @@ color: var(--theia-textLink-foreground); } -.pull-sketch-icon { - background-color: var(--theia-foreground); - -webkit-mask: url(./pull-sketch-icon.svg); - -webkit-mask-position: center; - -webkit-mask-repeat: no-repeat; - width: var(--theia-icon-size); - height: var(--theia-icon-size); -} - -.push-sketch-icon { - background-color: var(--theia-foreground); - -webkit-mask: url(./push-sketch-icon.svg); - -webkit-mask-position: center; - -webkit-mask-repeat: no-repeat; - width: var(--theia-icon-size); - height: var(--theia-icon-size); -} - .account-icon { - background: url("./account-icon.svg") center center no-repeat; width: var(--theia-private-sidebar-icon-size); height: var(--theia-private-sidebar-icon-size); border-radius: 50%; @@ -199,3 +180,12 @@ .arduino-share-sketch-dialog .sketch-link-embed textarea { width: 100%; } + +.actions.item.flex-line .fa, +.theia-file-icons-js.file-icon .fa { + font-size: var(--theia-icon-size); +} + +.theia-file-icons-js.file-icon.not-in-sync-offline .fa { + color: var(--theia-activityBar-inactiveForeground); +} diff --git a/arduino-ide-extension/src/browser/style/fonts.css b/arduino-ide-extension/src/browser/style/fonts.css index 65ab9f337..93a855910 100644 --- a/arduino-ide-extension/src/browser/style/fonts.css +++ b/arduino-ide-extension/src/browser/style/fonts.css @@ -11,9 +11,9 @@ @font-face { font-family: 'FontAwesome'; src: - url('fonts/FontAwesome.ttf?2jhpmq') format('truetype'), - url('fonts/FontAwesome.woff?2jhpmq') format('woff'), - url('fonts/FontAwesome.svg?2jhpmq#FontAwesome') format('svg'); + url('fonts/FontAwesome.ttf?h959em') format('truetype'), + url('fonts/FontAwesome.woff?h959em') format('woff'), + url('fonts/FontAwesome.svg?h959em#FontAwesome') format('svg'); font-weight: normal; font-style: normal; font-display: block; @@ -679,3 +679,21 @@ .fa-microchip:before { content: "\f2db"; } +.fa-arduino-cloud-download:before { + content: "\e910"; +} +.fa-arduino-cloud-upload:before { + content: "\e914"; +} +.fa-arduino-cloud:before { + content: "\e915"; +} +.fa-arduino-cloud-filled:before { + content: "\e912"; +} +.fa-arduino-cloud-offline:before { + content: "\e913"; +} +.fa-arduino-cloud-filled-offline:before { + content: "\e911"; +} diff --git a/arduino-ide-extension/src/browser/style/fonts/FontAwesome.svg b/arduino-ide-extension/src/browser/style/fonts/FontAwesome.svg index c1594c55c..867d29761 100644 --- a/arduino-ide-extension/src/browser/style/fonts/FontAwesome.svg +++ b/arduino-ide-extension/src/browser/style/fonts/FontAwesome.svg @@ -23,6 +23,12 @@ <glyph unicode="" glyph-name="arduino-monitor" horiz-adv-x="1536" d="M651.891 59.977c-92.835 0-179.095 28.493-250.5 77.197l-129.659-129.658c-22.494-22.496-58.964-22.496-81.458 0s-22.494 58.963 0 81.459l124.954 124.954c-67.75 78.157-108.777 180.090-108.777 291.489 0 245.759 199.68 445.439 445.44 445.439s445.44-199.679 445.44-445.439c0-245.761-199.68-445.441-445.44-445.441zM651.891 797.257c-161.28 0-291.84-130.559-291.84-291.839s130.56-291.841 291.84-291.841c160.512 0 291.84 130.561 291.84 291.841 0 160.511-130.56 291.839-291.84 291.839zM1149.562 472.766c0-35.423 28.717-64.138 64.141-64.138s64.134 28.716 64.134 64.138c0 35.423-28.71 64.139-64.134 64.139s-64.141-28.716-64.141-64.139zM64.064 408.62c-35.382 0-64.064 28.682-64.064 64.063s28.682 64.064 64.064 64.064c35.381 0 64.064-28.682 64.064-64.064s-28.683-64.063-64.064-64.063zM1458.707 408.628c-35.418 0-64.134 28.716-64.134 64.138s28.717 64.139 64.134 64.139c35.424 0 64.141-28.716 64.141-64.139s-28.717-64.138-64.141-64.138zM652.659 424.010c-44.961 0-81.408 36.447-81.408 81.407s36.447 81.408 81.408 81.408c44.96 0 81.408-36.447 81.408-81.408s-36.448-81.407-81.408-81.407z" /> <glyph unicode="" glyph-name="arduino-sketch-tabs-menu" d="M511.998 347.425c50.495 0 91.432 40.936 91.432 91.432s-40.936 91.432-91.432 91.432c-50.495 0-91.432-40.936-91.432-91.432s40.936-91.432 91.432-91.432zM923.433 347.425c50.494 0 91.432 40.936 91.432 91.432s-40.937 91.432-91.432 91.432c-50.494 0-91.432-40.936-91.432-91.432s40.937-91.432 91.432-91.432zM100.565 347.425c50.495 0 91.432 40.936 91.432 91.432s-40.936 91.432-91.432 91.432c-50.495 0-91.432-40.936-91.432-91.432s40.936-91.432 91.432-91.432z" /> <glyph unicode="" glyph-name="arduino-plotter" horiz-adv-x="862" d="M323.368-19.351c-20.263 0-39 11.42-48.21 29.788l-146.789 293.581h-74.474c-29.789 0-53.895 24.107-53.895 53.895s24.105 53.895 53.895 53.895h107.789c20.421 0 39.053-11.528 48.21-29.788l96.527-193.056 180.263 720.949c5.842 23.579 26.737 40.263 51 40.842 23.947 1.579 45.893-15.158 52.894-38.421l150.162-500.526h67.681c29.788 0 53.895-24.107 53.895-53.895s-24.107-53.895-53.895-53.895h-107.789c-23.789 0-44.787 15.629-51.631 38.422l-105.316 351.104-168.052-672.053c-5.474-21.897-23.948-38.055-46.368-40.529-2-0.21-3.947-0.313-5.895-0.313h-0.001z" /> +<glyph unicode="" glyph-name="arduino-cloud-download" d="M684.256 156.891l-146.286-146.286c-6.932-6.802-16.255-10.606-25.964-10.606s-19.032 3.803-25.964 10.606l-146.286 146.286c-3.41 3.41-6.115 7.458-7.96 11.913s-2.796 9.23-2.796 14.052c-0.001 9.738 3.868 19.079 10.754 25.965s16.226 10.756 25.964 10.756c4.822 0 9.597-0.949 14.052-2.795s8.504-4.549 11.914-7.959l83.749-84.107v423.856c0 9.699 3.853 19.002 10.712 25.86s16.16 10.712 25.86 10.712c9.699 0 19.001-3.853 25.86-10.712s10.712-16.16 10.712-25.86v-423.856l83.749 84.107c6.886 6.886 16.227 10.756 25.966 10.756s19.079-3.869 25.966-10.756c6.886-6.886 10.755-16.227 10.755-25.966s-3.869-19.079-10.755-25.966zM786.286 292.572h-128c-9.699 0-19.001 3.852-25.86 10.711s-10.712 16.161-10.712 25.86c0 9.699 3.853 19.001 10.712 25.86s16.16 10.712 25.86 10.712h128c32.768 0.031 64.285 12.618 88.057 35.172 23.779 22.554 38.005 53.361 39.76 86.085s-9.092 64.877-30.318 89.846c-21.219 24.97-51.207 40.858-83.785 44.396-8.316 0.882-16.084 4.59-21.994 10.505-5.917 5.914-9.626 13.678-10.503 21.996-3.35 31.449-18.235 60.542-41.784 81.652-23.551 21.11-54.092 32.737-85.719 32.634-23.597 0.154-46.754-6.384-66.785-18.857-6.953-4.363-15.168-6.269-23.332-5.414s-15.805 4.42-21.704 10.128c-33.699 32.745-78.905 50.956-125.893 50.714-44.461-0.011-87.395-16.221-120.77-45.598s-54.9-69.908-60.551-114.009c-0.856-6.825-3.618-13.27-7.971-18.595s-10.119-9.315-16.636-11.512c-28.688-9.795-52.969-29.455-68.519-55.477s-21.361-56.718-16.396-86.623c4.964-29.905 20.381-57.078 43.504-76.68s52.454-30.362 82.768-30.363h128c9.699 0 19.002-3.853 25.86-10.712s10.711-16.16 10.711-25.86c0-9.699-3.853-19.002-10.711-25.86s-16.161-10.711-25.86-10.711h-128c-45.726 0.010-90.084 15.596-125.767 44.191s-60.559 68.491-70.532 113.116c-9.973 44.625-4.447 91.317 15.667 132.381s53.618 74.052 94.989 93.527c12.401 57.159 43.982 108.357 89.498 145.089s102.228 56.789 160.717 56.839c56.689 0.21 111.801-18.659 156.464-53.571 26.825 11.769 55.891 17.556 85.178 16.958s58.092-7.565 84.415-20.419c26.323-12.854 49.532-31.284 68.007-54.012 18.483-22.728 31.795-49.208 39.007-77.598 47.587-12.004 89.154-40.98 116.875-81.479 27.728-40.499 39.702-89.732 33.675-138.44-6.034-48.708-29.645-93.536-66.406-126.054s-84.136-50.488-133.215-50.527z" /> +<glyph unicode="" glyph-name="arduino-cloud-filled-offline" d="M854.72 704.131l-671.997-672.001c-6.066-5.946-14.223-9.28-22.719-9.28s-16.653 3.334-22.719 9.28c-5.996 6.042-9.361 14.208-9.361 22.72s3.365 16.678 9.361 22.72l107.52 107.52c-37.22 5.818-71.592 23.424-98.059 50.234s-43.632 61.402-48.97 98.694c-5.338 37.292 1.432 75.312 19.315 108.469s45.935 59.7 80.029 75.724c7.995 36.965 25.219 71.304 50.068 99.816s56.512 50.267 92.038 63.237c35.526 12.971 73.758 16.735 111.132 10.941s72.672-20.956 102.604-44.074c23.899 10.368 49.78 15.369 75.821 14.651 26.038-0.718 51.606-7.138 74.896-18.807l105.6 105.596c6.029 6.026 14.202 9.411 22.72 9.411 8.525 0 16.698-3.385 22.72-9.411 6.029-6.026 9.414-14.198 9.414-22.72s-3.386-16.694-9.414-22.72v0zM928 358.827c-0.083-46.653-18.65-91.375-51.642-124.36-32.986-32.986-77.702-51.558-124.358-51.642h-322.563l361.283 361.282c1.6-4.797 2.88-9.6 4.166-14.398 38.093-9.509 71.904-31.506 96.032-62.48s37.184-69.139 37.082-108.402v0z" /> +<glyph unicode="" glyph-name="arduino-cloud-filled" d="M928 358.859c-0.083-46.653-18.65-91.375-51.635-124.36-32.992-32.992-77.709-51.558-124.365-51.642h-479.998c-40.017 0.013-78.836 13.658-110.060 38.688-31.224 25.024-52.989 59.942-61.71 98.999-8.721 39.055-3.876 79.916 13.736 115.849s46.94 64.794 83.151 81.826c7.995 36.965 25.22 71.304 50.068 99.816s56.513 50.266 92.038 63.237c35.526 12.971 73.759 16.735 111.132 10.941s72.672-20.956 102.604-44.074c22.414 9.744 46.599 14.755 71.040 14.72 39.262 0.102 77.425-12.954 108.401-37.083s52.973-57.94 62.483-96.035c38.093-9.508 71.904-31.506 96.032-62.48s37.184-69.14 37.082-108.403z" /> +<glyph unicode="" glyph-name="arduino-cloud-offline" d="M794.88 529.709c-1.28 4.797-2.56 9.601-4.16 14.398l-53.12-53.125c2.080-5.548 5.67-10.404 10.362-14.022 4.698-3.618 10.304-5.853 16.198-6.454 28.493-3.153 54.701-17.094 73.235-38.963 18.541-21.868 28-50.003 26.445-78.628s-14.016-55.569-34.81-75.3c-20.8-19.725-48.365-30.746-77.030-30.79h-258.563l-64-64h322.563c42.944 0.026 84.403 15.744 116.57 44.198s52.832 67.68 58.099 110.301c5.267 42.621-5.216 85.699-29.491 121.13-24.269 35.43-60.646 60.771-102.298 71.254v0zM854.72 749.557c-6.042 5.997-14.208 9.363-22.72 9.363s-16.678-3.366-22.714-9.363l-105.606-105.595c-23.29 11.669-48.858 18.089-74.898 18.806s-51.923-4.284-75.821-14.652c-29.932 23.118-65.23 38.28-102.604 44.074s-75.606 2.029-111.132-10.941c-35.526-12.971-67.19-34.726-92.039-63.237s-42.073-62.851-50.068-99.816c-34.093-16.024-62.145-42.566-80.028-75.723s-24.653-71.177-19.315-108.468c5.338-37.292 22.502-71.884 48.968-98.693s60.837-44.416 98.057-50.234l-107.52-107.52c-5.996-6.042-9.361-14.208-9.361-22.72s3.364-16.678 9.361-22.72c6.065-5.946 14.223-9.28 22.719-9.28s16.653 3.334 22.719 9.28l672.001 672.001c5.997 6.040 9.357 14.207 9.363 22.718 0 8.511-3.366 16.678-9.363 22.719v0zM306.564 246.838h-34.563c-26.523-0.013-52.188 9.395-72.423 26.541s-33.725 40.92-38.067 67.085c-4.342 26.165 0.747 53.022 14.36 75.785s34.865 39.954 59.97 48.51c5.716 1.953 10.763 5.483 14.557 10.184s6.18 10.379 6.883 16.379c5.021 38.555 23.892 73.968 53.095 99.638s66.744 39.843 105.625 39.878c41.119 0.243 80.673-15.741 110.078-44.484 5.176-4.951 11.848-8.045 18.97-8.797s14.294 0.88 20.39 4.641c17.553 10.974 37.86 16.744 58.562 16.641 10.271-0.061 20.492-1.458 30.399-4.156l-347.836-347.843z" /> +<glyph unicode="" glyph-name="arduino-cloud-upload" d="M684.258 412.892c-6.932-6.799-16.255-10.607-25.964-10.607s-19.032 3.809-25.964 10.607l-83.751 84.118v-423.867c0-9.699-3.853-19.003-10.711-25.856-6.859-6.861-16.161-10.715-25.86-10.715s-19.001 3.855-25.86 10.715c-6.859 6.853-10.712 16.157-10.712 25.856v423.867l-83.749-84.118c-6.886-6.886-16.227-10.756-25.966-10.756s-19.079 3.869-25.966 10.756c-6.886 6.886-10.755 16.227-10.755 25.966s3.869 19.079 10.755 25.966l146.286 146.286c6.903 6.854 16.236 10.701 25.964 10.701s19.062-3.847 25.964-10.701l146.286-146.286c6.853-6.904 10.7-16.237 10.701-25.965s-3.845-19.062-10.698-25.966zM786.286 256.001h-128c-9.699 0-19.001 3.852-25.86 10.711s-10.712 16.161-10.712 25.86c0 9.699 3.853 19.001 10.712 25.86s16.16 10.712 25.86 10.712h128c32.768 0.031 64.285 12.618 88.057 35.172 23.779 22.554 38.005 53.361 39.76 86.085s-9.092 64.877-30.318 89.846c-21.219 24.97-51.207 40.858-83.785 44.396-8.316 0.882-16.084 4.59-21.994 10.505-5.917 5.914-9.626 13.678-10.503 21.996-3.35 31.449-18.235 60.542-41.784 81.652-23.551 21.11-54.092 32.737-85.719 32.634-23.597 0.154-46.754-6.384-66.785-18.857-6.954-4.362-15.168-6.268-23.331-5.413s-15.805 4.419-21.705 10.127c-33.699 32.745-78.905 50.956-125.893 50.714-44.461-0.011-87.395-16.221-120.77-45.598s-54.9-69.908-60.551-114.009c-0.856-6.825-3.618-13.27-7.971-18.595s-10.119-9.315-16.636-11.512c-28.688-9.795-52.969-29.455-68.519-55.477s-21.361-56.718-16.396-86.623c4.964-29.905 20.381-57.078 43.504-76.68s52.454-30.362 82.768-30.363h128c9.699 0 19.002-3.853 25.86-10.712s10.711-16.16 10.711-25.86c0-9.699-3.853-19.002-10.711-25.86s-16.161-10.711-25.86-10.711h-128c-45.726 0.010-90.084 15.596-125.767 44.191s-60.559 68.491-70.532 113.116c-9.973 44.625-4.447 91.317 15.667 132.381s53.618 74.052 94.989 93.527c12.401 57.159 43.982 108.357 89.498 145.089s102.228 56.789 160.717 56.839c56.689 0.21 111.801-18.659 156.464-53.571 26.825 11.769 55.891 17.556 85.178 16.958s58.092-7.565 84.415-20.419c26.323-12.854 49.532-31.284 68.007-54.012 18.483-22.728 31.795-49.208 39.007-77.598 47.587-12.004 89.154-40.98 116.875-81.479 27.728-40.499 39.702-89.732 33.675-138.44-6.034-48.708-29.645-93.536-66.406-126.054s-84.136-50.488-133.215-50.527z" /> +<glyph unicode="" glyph-name="arduino-cloud" d="M752 182.857h-480c-40.010 0.006-78.824 13.645-110.046 38.662-31.222 25.024-52.989 59.93-61.716 98.98-8.726 39.047-3.891 79.902 13.709 115.833s46.915 64.796 83.115 81.836c10.851 50.014 38.484 94.812 78.31 126.953s89.45 49.69 140.627 49.734c49.603 0.184 97.826-16.327 136.906-46.875 23.472 10.298 48.904 15.361 74.531 14.838s50.829-6.62 73.862-17.866c23.034-11.247 43.341-27.374 59.507-47.261 16.173-19.887 27.821-43.056 34.131-67.898 41.638-10.504 78.010-35.857 102.266-71.294 24.262-35.437 34.739-78.515 29.466-121.135-5.28-42.623-25.939-81.842-58.106-110.296s-73.619-44.179-116.563-44.211zM416 630.856c-38.904-0.010-76.471-14.193-105.674-39.899s-48.038-61.169-52.982-99.757c-0.749-5.972-3.166-11.611-6.975-16.271s-8.853-8.151-14.556-10.073c-25.102-8.571-46.348-25.773-59.954-48.542s-18.691-49.628-14.347-75.795c4.344-26.167 17.833-49.943 38.066-67.095s45.897-26.566 72.422-26.566h480c28.672 0.026 56.25 11.040 77.050 30.778 20.806 19.731 33.254 46.688 34.79 75.321s-7.955 56.767-26.528 78.616c-18.566 21.848-44.806 35.75-73.312 38.847-7.277 0.772-14.074 4.016-19.245 9.191-5.178 5.176-8.422 11.969-9.19 19.247-2.931 27.518-15.955 52.974-36.563 71.445-20.602 18.471-47.328 28.645-75.002 28.555-20.647 0.135-40.909-5.587-58.437-16.5-6.084-3.816-13.272-5.484-20.415-4.737s-13.83 3.868-18.992 8.861c-29.487 28.652-69.042 44.586-110.156 44.375v0z" /> <glyph unicode="" glyph-name="music" horiz-adv-x="878" d="M877.714 822.857v-640c0-80.571-120.571-109.714-182.857-109.714s-182.857 29.143-182.857 109.714 120.571 109.714 182.857 109.714c37.714 0 75.429-6.857 109.714-22.286v306.857l-438.857-135.429v-405.143c0-80.571-120.571-109.714-182.857-109.714s-182.857 29.143-182.857 109.714 120.571 109.714 182.857 109.714c37.714 0 75.429-6.857 109.714-22.286v552.571c0 24 16 45.143 38.857 52.571l475.429 146.286c5.143 1.714 10.286 2.286 16 2.286 30.286 0 54.857-24.571 54.857-54.857z" /> <glyph unicode="" glyph-name="search" horiz-adv-x="951" d="M658.286 475.428c0 141.143-114.857 256-256 256s-256-114.857-256-256 114.857-256 256-256 256 114.857 256 256zM950.857 0c0-40-33.143-73.143-73.143-73.143-19.429 0-38.286 8-51.429 21.714l-196 195.429c-66.857-46.286-146.857-70.857-228-70.857-222.286 0-402.286 180-402.286 402.286s180 402.286 402.286 402.286 402.286-180 402.286-402.286c0-81.143-24.571-161.143-70.857-228l196-196c13.143-13.143 21.143-32 21.143-51.429z" /> <glyph unicode="" glyph-name="envelope-o" d="M950.857 91.428v438.857c-12-13.714-25.143-26.286-39.429-37.714-81.714-62.857-164-126.857-243.429-193.143-42.857-36-96-80-155.429-80h-1.143c-59.429 0-112.571 44-155.429 80-79.429 66.286-161.714 130.286-243.429 193.143-14.286 11.429-27.429 24-39.429 37.714v-438.857c0-9.714 8.571-18.286 18.286-18.286h841.143c9.714 0 18.286 8.571 18.286 18.286zM950.857 692c0 14.286 3.429 39.429-18.286 39.429h-841.143c-9.714 0-18.286-8.571-18.286-18.286 0-65.143 32.571-121.714 84-162.286 76.571-60 153.143-120.571 229.143-181.143 30.286-24.571 85.143-77.143 125.143-77.143h1.143c40 0 94.857 52.571 125.143 77.143 76 60.571 152.571 121.143 229.143 181.143 37.143 29.143 84 92.571 84 141.143zM1024 713.143v-621.714c0-50.286-41.143-91.429-91.429-91.429h-841.143c-50.286 0-91.429 41.143-91.429 91.429v621.714c0 50.286 41.143 91.429 91.429 91.429h841.143c50.286 0 91.429-41.143 91.429-91.429z" /> diff --git a/arduino-ide-extension/src/browser/style/fonts/FontAwesome.ttf b/arduino-ide-extension/src/browser/style/fonts/FontAwesome.ttf index 5f0d75b8db6452688aeeb5e11ca85d590ffce5bc..6810cc6265e69d7b238b6e0bf3f523c8d57c4886 100644 GIT binary patch delta 3093 zcmcJRd2Ce29mi+h{nop0-u>R*mv`6pF6(1`g7J-Qj(`oQN!zHg3E_$%Zr~4+(yUd{ zmZmLAF+~vyM^OqWqO=teRESFM@mFIt3E~fwqKcv@rBRi%G^A95ZGZ1Q+c6@_e_g$6 zW_~mCoB95JpV@QoQnznWWrPtzRcH#)sA1iP`X-{1??KHKxW}H}IX-!??Ymz_2uI+) zv2}d+B-G0YQTO02Y@K*v%Z2}(-Ho6#LT5&{Ju|*JGqj=>p*KdLqIDZoh!;5+?~Mac zuHLqD&)(mC({~%n=b%qv;<=}L$4Bxnv?BDg>oCEqJID7<qCers5&F3^QDWEl&S$=T z_^t-!SD^jk<a4|CxO1Uj4m<6LruYA7<{Qck6eds)Vo?FsllYr4y%tYQU%?ZbEk+K? zwrt6!tjnsb$g=F0MOlz}nUh(WlCg})e@TVhBX`Ls<X_~U<YV$z@&UO;{z7h&cgfr2 zk7Snop8STKCuhiMa*CWF$H}YY$K)`1nd~Q{fsdyTQeU6O^x%cB(tnW46oU2B@6o$Z ztFwz4Uc%{AwjLL8u83QjTid#DsmZirIF6M?B|}+gFm#S@gFXxP%W#v^t*zCm@~#&5 zBc0-4_?&C%ee-1rLzQ>IByd4*XF6w83FonEoXffc!kC^nUD$GsydLoM21rxq4zUu? zOY9+<!4&3LHXzVELv!>7_;y=ZZUcM>0hZ-BcFR<m4?qhP0{m34sHg_UM3xIS=Vus> zHWjsCt0}_zIj)Kg_Esmmf}uEr8JZSZBklJKG-D}B-kMr8Ou8o=t`>NKkjA)JOsCct z@*^odZ<={cPf3!_R(BeP!mz1uWJRWY?2zNgA&O(bQShAQC`>WbMtqhJu;3cU2KdSo z8yzEW0SCa_xs|AjQV0f%nr2a$Wtl48$`e`fi8PHl#tz%2xh%>07>1?zsIDzBtsEg_ zejJuHO=D>}l^lr28%TatBpi!`L=jhszObUy7-C&4K9s5Mv+WRsE27XQWYH(7f1{=7 zF@!|y#)+qSw-+soRRW<LaX>D3&Z*{!+Nin8rjr<2Vr9q7Xrv#1Fy?HspJiYn6Okre z4>F7|Ak_xBkgC;(!tIeri>YRHEvs(-%yMNoX!oWozs5U2?nslWYShewF=q_6iigpj zWkR}MibUG&V9p;Y8Aej{aV%&i@K_XgFl-qt{TyG#R?eh*gLW8iry*jJmen40R*lhS zbO~1dCMrT<&hbY=^0UP*ib{h%={c8(by!w{=lDP%A6~o~rCN=a+bui6yPo5%t_QlN zmSWLm;c#7GvBSKescKVX-Zk2l;{?c&MdRrE;2dNa@9e0%;|m#)<dch&v9YZP>CF+x z8j`Vy%ekzRXA74j8eC8|bSDi<&>MFF2(r0G2MkU+FG|Lig_HzSa~>9$4uc#mm}O{@ zF*A}RVXVq>jZt~fgZmSmK|97UvZ}VkJIkJy+tsY5XH~NWqzZ@XH8sQqYo!3hZcx{o zA``BnZhTNDo$m)X(t3u-8qEkkUtD7Zie{LwX|_e<9VX*r*(yeg$^zjlKc!Sqw1wem z`027zYnVBS$UT-}bR-hp<xn^y+;E260kO{uip8*;PfQv{DdNusZ3w%Pu7{Xsy(n=E zsgqu8RYb`jNNajdQG&d;)@ZY)8J0=2n4$%dqAIVunNy20K-iV20bK;4<^Zd>(NvxT zrvf{^z|d~kae!_dGQ`24wa@^8_Ap#sK|Hwfu8?Wa$CY?NQSZak^-;E#AJ)@BJ<RO| z!Ti%30pJQW1<rjwO6S4rVRaD>znH4!{|{F2F~^UMl_wmcIzNfWXBR=#gD%vT!QdDm z(ODU=7KpmU4%VxhMRR}<&aRVX1!JGc0AZP6$U~|KX9FNr(+iea1Ht4%+C5S%!(5t7 z4a8%OQhs$f5)Fq05&L`&QFDf`E*2ZE&h*;BIidnv%Jd2962N6A9KFd$((8-l!0utn zyHT`Q<I+P3?}o$YoW70JKPnEG$_r!?YNN50+00N>&1iZ?QDc6;!p2)vRc4r&9qde0 zei3am%`n5zl)z|lpHE<DO(q!~-!yZwtYQp_o;BP9ht>$m86*~90k=NJ?1*1-xE77M zT+8;tp<-JOgI5cJO-Nc5GT~5nBGF+O7M?LQtvSkwG{a&(2s@|g>40C7iIg*qT1D0! zEodL716hb5(om#L3!w{X{m2i)dw(_h6zRN+su&00=w@i@srmQxwV$*}Z+Z1@Bci6G zr}}NEsfBwJ+?(g#PI>c%u~TnT<rzGHKcS|mS^7RR$m(2#yTVoYI(|$LgdSnPc*H0B zo~&x{FZJIF!~**RA4$#9OVWF!0sg{GDh1`d+NWOC)@n0)gTWa`jZe*H^RyMQPTDDZ zlYJvN5_~^&ICL#^KRghLMP7_tj%K4bV_mU(@tH&@v8SAvO;#u0Ne!oF(t7$U=?|)3 zs{S;yH*+p?FI&hCXZK}~W@mGDZdGny?sV>IO`&G8=1%RGYX4j}Tz4}+k-t^wDI6%g zv&3F9w&Zd#ReZU4rFgx*uKr*{s^NCyK;wr^KWMsMqDsZm@zQUbx#l&^hgx^E9%(b% zCflyG*R+?X+V6B!ckJl6v2=2of7!lefA4&<b9Q;(^4FGM?TU51-t|%U+U_^IulATd z2YWmF<i7U4ul0SW?|k3;{e}LG{rmdw3_L$@c|~Ex@j-d;TZ1!$m7&g|7l*D5j}5;v z{Nc*N%GXxSuJ)~de)at|tJWNUEVfo!yK7x>-MJBcWMJgT$Zd19ee}TS>}X|u)A}vz Sk8U^%hcZHMUATPu4*nlG3hm|q delta 841 zcmaFyh-uA5rg{cO1_lOhh6V;^1_S?KeItG${x+b<9w1Ig&P^<+{y*b70|TQB5I;#z zEG__w3orl`0|7^RPG#Das@3*DJ_iHCycHR#i7ColTNg4gEZhK;H_HGDaBgF30rFn} z`6?N?B^B#yIk^}Z7V!Y}NaW-vJ0{-n+*rfFuv7(TL0@iSMFGP##&8CPWm|w66!H>t zQ(LEe6$bLJ0Ohw8<QJDf>|W6Wl4oFMZk%|aTKEKzlgHq|z{;Qp^p66A!At(hK8!g` z3<i^TFy>_azaq{mAR-_vAS56tz%Rfnz$3sdz%IZdz%0Ndz$n1L|Cj#{|8M?Z{6G0W z^MBxf&;O494gV|tNBj@@@ABW_zs-M!{}lg8{^R`n`S<Xz<X^<Ukbf@!EdH7Nlldp` z_w%>%*Yo@Ez5+Uoaq>i_jL8d_*eCyFa@(xUd{1EWQJE>d(z@-<@%%Pl8Ms-14rO4t z_s3#3jGkPw%3SCeL>w&1zyzdNChuJ3yjf)Rd8T>|hEt4wjQ^Orn69y~u>`Qnv8k~g zW9MKuVb9_a;_%|=<2c1>z&VTa0hbn68`mA~13WT3H+Z9X-|^M){o>Ezzay|o&`ofW z-~*u`p%cPB!skTzL^?$Nh)xi55Ni-yA@)K1l!Tf@n#3i^9?4fyOQdt8kI5*=RLESA zt&#mAms2lyK%Py0l7g1PB1IL&2*o9eHx$1pX(+iVRVW=%`lhU*9Hd;Qd_zS>Wu7XN zYM1I4wH|c|^*;4C8YUVw8b>sFG}AQCX_;wdXtiiv)3(w+r!z(8gYGmv3%wS-b$Yk- zz4Y_+H|hT{urm@faxyw(EMuHue8oh^WS+?dQ!&#Hvw9h`9p)P5Gb}hPDlFbvdRW$3 zp0WzCnq~FNI>EZm`jCy4%?sN-womN1?2PQ9>?YXVuxGH>u%G83=aA-b!_muekCUEL zj?*fq7tU(V4K6$`HZId#Zn%25Rk&?)mvdj?{>{V7<CNzvFDb8E-Vxphyg&Fj`AqS7 q;%nkt;k(NBo`j!}pPPROFit=j<rrfq13x&Ln1E3&ym|8atBe4ej{bZA diff --git a/arduino-ide-extension/src/browser/style/fonts/FontAwesome.woff b/arduino-ide-extension/src/browser/style/fonts/FontAwesome.woff index 86a6f5031d056b826c1fd9479eb2b5860d0e0546..5213d95155f5a7855930444c420e9422ec377a1e 100644 GIT binary patch delta 3155 zcmcInYitzP6`nhD=dtVEx$}PP`{CWSz03NseqzUOZ1V`%K%2CR8cYbU7_b6TNlLR; zMO%`#sKpdTh?h_bs6w<AC{&0_?&DWuH3_0pl%k5zD5X)Av^1ntf^E;t*p3lV{&h5G z=H7G9y>rg}&iU@{y|?L0f1!=9uNfMm5CzvSE>TtPdn<*e-=mEm71Z*}&+HhVq$so% z<c1>$+rImiE#tdE#|(n8FelQMi5E75ZWTqH9d+d5f6ndR`t0~7iu&m>uxWK9GrX*J zD=0yC9s1Rd_+IB;-nwJYUeMix`2|OQ`%VAtiCxct-RcWqgkE)IH2*^Dj`6+l;h$ZF zi3wN!gr3+rzT;WYInKTA$hQyQRVR1t-UIO*Ua(`J#W4G)1Lzy_474YxUW%m(5O?Bl z`t(sWF)h#&TTLw4k|mjvA!(8#$&w@mB%dTmyu?YYL`z7b$bU(N+#`3%C*)t`pX6im zSMmY5McyMf$=l>j@&__Yen);yE|9b23^`3sk`v@r@?&zCyh8SqvEauP<8JQ6^eSff z;#ubRQkkY|!MS&tov=v|S%w!;I+d+QMU*R|mgd&BZd7VA%ovIzc~MW77Y1~V<J(}) zf_*1ya;CMlIx6pOaU1Cr2g~PNQ?JdJMFcAEhL6Avvz^a5tBNR(T;p8UT@cpvyy-@! zYvj#<r?)_wK7WW6d0u1>F&NQ^W7(j<@R;G4b<lQ4SZ*COgdodu9J_g{%m-lvIzfKQ zF3O6I5Rs&U#RV|t7(-SHmXacDfa9uIyRSOgZHM9*VTSRsdO8pg7;MUN-ke&rOu9E5 zt`>NKkjA*Lm`<%N<VRCl-Z1j2mJ&sct?trw8MCQyWLc(s{E*|wA)3SBD0t3tG@>!R z9-ZTZEV#z8LB8_jddJ8M-~f0#7l|Uv1=}vFs!1c3#Z|nSCz9;<F%06c6}AkcGs*ff zW@$dEsY?tqM+li;hh+^zUs_Hj2jlSul3x)C$08x04^{d6VOg%xeRZ+;aHhK7vO<uu z6iscUOy(5*Z)z#^I7Ru8n<pOTJzlmfMhSp&zyY}6Ift4DYNP5Rn@%DaiIp8Qy^(q1 z!3JlO11yF>CL&FmW@GFRinTTuQq=lTxIGeSF_f&PW|eK9SuPLTR$sdEE3_Tpjx;HX zO3ysl;H<$`@vz!+IHYN%NTl7ebAd=n*ONX!#{y;ok9@xEm@R{4fa9y!%Gq?EZH3V` z1~MjTn(a|1YD8_KE<@Cps3LUc9DgJwKMQtIR_e?t&$&db!!#2-#|MM?@ZxCXY9(53 zH?0KkdXBcZ9%!mkibXra;kw{rhj~F&l%~kMYm5uWNq{3ujZ@zP=b*xPXGh%~U#N&A zpIlswjcr9JZ;m+DP>e-X&SjlCTeuz2;D)}gIb~Ra*{B<cAe(D+h`}l6Ma9^%P?BJ3 z%##IT!T?7LVlm^xMn)7xgcM1t(JK#n(Lkchwqh7diqaDADtlONQ?ja-Rg4yZDjcd; zl@Mpwib2R-Thp2%6E31|e$c0!_JbQ~Ekh)g!Ghl(SFu1d7>5m`EgJ7Iu%BhCuo#sD z!dHGmD}ZPV<{7v&Nv_q6oJgczQ`b8ZiJo#OoDps~OKykU=LOlsEa&$nb-fe`<ZKJl zuB2%p{G691jv;-@%dLt}3<T4vmXl?h_hOAUtEz4q42x(+@X>VTHMeqVsSGgea;kxH z&WJgJmECMA&k?5#JHEi7J+R|Ix^buwhX&1s0Z6om$<+nKBUj!9G7b2+5HBF=H9TA& z<<|1Ucsf)M-}aJV{^_j%<O*yGJooujI#0YFtuCU&FJ{&9|A$u5amSDKl_woWbuN)d z=N6HuN4lUbgTZm2L?<%fT42;AmR+x?Cc^=Ra8{ip$q4y<7#J4YA&*jha5ey?s#?J` zY9N_hl6H?2Q#Y0-Q-kqXqnKYAjzq&D!H4{Qhf#C7zb+OVsm}CS_8g-Ex0IQa^kpEI z9dPs}A1SXdf&;mSDeq>{VvI`<6}+1cpL6;)(*LM9#8h5jCZRSOTb|7fN0p4KWn?85 z2*_-_MNuS-W0u{OsQf(IW*A|N8Ct+<-0v4Kqe>*Bp_@idk`#oX(6hRG;4ms7Ii19U zEYPhV8y)e>4zERHF0W<#;83wlhl5uNf<;JL5i;RWPa@Hw>n57fRkb;aeGFz1Z^O>1 zS~?gIB_iewy;hbq2Mfl}X}~N*@G;P343nZR?$VC@AiVdNV^5Q=yHpi+2%NeZntFQv zJ)Jn+Ccfe6-9d_;-gbJx0!=N*MvzT&Z>PWM;`!5W(&ZU6h(4jG=vn4I9%3~v!d>Mm zd>y|*5QJV~zwd}&@;_D85Lg<x6^sS<2R{;<#h1i)Ndx?ho0JRk1*KoPrmj|Jv<98i zkLsTq&BhrsVxF>6)<)}wJ!-!nIvlzlx*r~l#3C<7u0*rZo3ZZLz4%Nbl-N^F%qFXo zZ>2_3GifdT)$|9|FI9h<*_%0^xtA?uN3#2}N3*jzE4L!IFLx$)t)@^jS#ziM%e8;5 z8>zdQpUB@T^cD^j-dbWU*|6kFF;#q}c(wRWeO>**hE&7t#=*u9o4()lPKhoROD9Ud zY37<&H6Lo--g>0XXq#-i+FsLMo@&3-QQfh<<Hpj-&OqnB&cAm()iwKA|6|7<yVf1+ zey#hXp4B~<dam^vy$Acc`lbH%{;&0ar~g9#`vZl6^#l6`?hHOZcx72(*@+=(=vzZG zLzUsK;TMOmk8BwE;mC)}3(JqKm|f{#`TWZJt5&Q!@px>txO(TB;+pfL+UVfuk<r_U pvG%b8W3ywGwM}a`uRXf%9309N^#=M9MO+MN__Ls1OrQND`XBC(_lf`j delta 885 zcmdn;nCZtwCb4pVH#Y`G1|V4RgMk}NuVG-E{E$g(qK<HVTXJq<0RsbL1`t01;p+c0 zuBRs!1I3tqfQmVwSRg&8G7Tse!oV<Z1qffMT5X?^nwY}Cu<#F1jTs0lb8TIi0Tg6l zSY!g^tAH@)Hnx_G+>#2QSOieN1PHIM<>boAPX?;<TMDwg4}@=cZmh{otN`+t1NAW| zfbliP@Vvy_RG=7;&$tbQTc>;#F32w~0s7|#Tpcrz#mw9|nTN4j_ymxh$Kb%g%Ag1I zw*rH~Oa93-7;~5y3?{QM<z)T8BF-uxA|NavBp@ijFTg9nBfu@dF2EwdEWjkdD8Rt~ zm;Vp{Z~kBWKlwlNf8c-5|Bn9+|117S{15r>^55aV&3}gf6#q&7<NW*i_wcXeU&OzV ze=h$l{+axf`6uxA^SAQX^ZW3=VqgY`amwTmOx%-QncX&*Gv5=~EGRprS6a8dIiBC< zD+4zR(4h<r_x@PShS8G`tTGom1`!8KGB5!tmdUKEoi`_}KF?II!ElPvkMSQ<7t=Ks zHkJTZIW{%6W9%I4ChS=pLL6QkeH^Da4LE0UKH$>gYU8@YeSk-X=LT;S?>oLazF+(~ z{C5O43Aza`5_}*OBy>X9NBEowpGb$uAJGY74q^>rE5tsCpOR3MNRzlE*(3Q%YKe4? z^f4I)nF^T;vNf__<Z|le4#=~~Pg2lQSfr?;7@@dC@rL3TB@HDvr3$4ZO5c<<l!KJ( zly9iWsLWGkQteXxqSm7>q28zdM#Ds-M&pPkk7k<YIW04-46PQeYuZ-Y=X9p%e9)by zXQ9`kw@&YtzL$QU{wDn&26jebMovbDjAe{7jIWsJn9MV|U@B(XVOB3=w!>V*e1-*w zMTNyXOApIB%TrbXR<o>rStnT6Ss${ovUy><$M%UGmz|Mal-&fo8}<zL8us%X<Q&o* zZa8{5?s3v{%5hrd^uk%qxxt0U#l~ft%MDi#w+gpy?sD!c+`oBvd7Sdx<t62H%R9pR yfcFO<C!Z-kPkc>$D|}b^-jnbX@^kYC<^gbqI>s2vzz>clCSZ0F-h6-kRYm|*GX;PE diff --git a/arduino-ide-extension/src/browser/style/main.css b/arduino-ide-extension/src/browser/style/main.css index fa98d63f3..874db8448 100644 --- a/arduino-ide-extension/src/browser/style/main.css +++ b/arduino-ide-extension/src/browser/style/main.css @@ -77,7 +77,7 @@ .arduino-upload-sketch--toolbar-icon { -webkit-mask: url(../icons/upload.svg) center no-repeat; - background-color: var(--theia-titleBar-activeBackground); + background-color: var(--theia-titleBar-activeBackground); } .toggle-serial-monitor-icon { @@ -114,6 +114,10 @@ z-index: 0; } +.p-TabBar-toolbar .item > div { + text-align: center; +} + :root { --theia-private-menubar-height: 40px; /* set the topbar height */ } diff --git a/arduino-ide-extension/src/browser/style/sketch-folder-icon.svg b/arduino-ide-extension/src/browser/style/sketch-folder-icon.svg deleted file mode 100644 index 363c5df10..000000000 --- a/arduino-ide-extension/src/browser/style/sketch-folder-icon.svg +++ /dev/null @@ -1,4 +0,0 @@ -<svg width="8" height="7" viewBox="0 0 8 7" fill="none" xmlns="http://www.w3.org/2000/svg"> -<path d="M2.5 6.18999C2.415 6.18999 2.33 6.16999 2.25 6.12499C1.17 5.49999 0.5 4.33999 0.5 3.09499C0.5 1.84999 1.17 0.689992 2.25 0.0649925C2.49 -0.0700075 2.795 0.00999246 2.935 0.249992C3.07 0.489992 2.99 0.794992 2.75 0.934992C1.98 1.37499 1.5 2.20499 1.5 3.09499C1.5 3.98499 1.98 4.81499 2.75 5.25499C2.99 5.39499 3.07 5.69999 2.935 5.93999C2.84 6.09999 2.675 6.18999 2.5 6.18999Z" fill="#008184"/> -<path d="M5.49993 6.18999C5.32493 6.18999 5.15993 6.09999 5.06493 5.93999C4.92493 5.69999 5.00993 5.39499 5.24993 5.25499C6.01993 4.81499 6.49993 3.98499 6.49993 3.09499C6.49993 2.20499 6.01993 1.37499 5.24993 0.934992C5.00993 0.794992 4.92993 0.489992 5.06493 0.249992C5.20493 0.00999246 5.50993 -0.0700075 5.74993 0.0649925C6.82993 0.689992 7.49993 1.84999 7.49993 3.09499C7.49993 4.33999 6.82993 5.49999 5.74993 6.12499C5.66993 6.16999 5.58493 6.18999 5.49993 6.18999Z" fill="#008184"/> -</svg> diff --git a/arduino-ide-extension/src/browser/style/sketchbook.css b/arduino-ide-extension/src/browser/style/sketchbook.css index 87143e60c..8a9270c36 100644 --- a/arduino-ide-extension/src/browser/style/sketchbook.css +++ b/arduino-ide-extension/src/browser/style/sketchbook.css @@ -3,13 +3,6 @@ mask: url('./sketchbook.svg'); } -.sketch-folder-icon { - background: url('./sketch-folder-icon.svg') center center no-repeat; - background-position-x: 1px; - width: var(--theia-icon-size); - height: var(--theia-icon-size); -} - .p-TabBar-tabIcon.sketchbook-tree-icon { background-color: var(--theia-foreground); -webkit-mask: url(./sketchbook-tree-icon.svg); diff --git a/arduino-ide-extension/src/browser/theia/core/connection-status-service.ts b/arduino-ide-extension/src/browser/theia/core/connection-status-service.ts index 0738772c6..a0eb05941 100644 --- a/arduino-ide-extension/src/browser/theia/core/connection-status-service.ts +++ b/arduino-ide-extension/src/browser/theia/core/connection-status-service.ts @@ -1,106 +1,324 @@ +import { + ApplicationConnectionStatusContribution as TheiaApplicationConnectionStatusContribution, + ConnectionStatus, + FrontendConnectionStatusService as TheiaFrontendConnectionStatusService, +} from '@theia/core/lib/browser/connection-status-service'; +import type { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application'; +import { StatusBarAlignment } from '@theia/core/lib/browser/status-bar/status-bar'; +import { Disposable } from '@theia/core/lib/common/disposable'; +import { Emitter, Event } from '@theia/core/lib/common/event'; +import { MessageService } from '@theia/core/lib/common/message-service'; +import { MessageType } from '@theia/core/lib/common/message-service-protocol'; +import { nls } from '@theia/core/lib/common/nls'; import { inject, injectable, postConstruct, } from '@theia/core/shared/inversify'; -import { Disposable } from '@theia/core/lib/common/disposable'; -import { StatusBarAlignment } from '@theia/core/lib/browser/status-bar/status-bar'; -import { - FrontendConnectionStatusService as TheiaFrontendConnectionStatusService, - ApplicationConnectionStatusContribution as TheiaApplicationConnectionStatusContribution, - ConnectionStatus, -} from '@theia/core/lib/browser/connection-status-service'; +import { NotificationManager } from '@theia/messages/lib/browser/notifications-manager'; import { ArduinoDaemon } from '../../../common/protocol'; +import { assertUnreachable } from '../../../common/utils'; +import { CreateFeatures } from '../../create/create-features'; import { NotificationCenter } from '../../notification-center'; -import { nls } from '@theia/core/lib/common'; import debounce = require('lodash.debounce'); +import isOnline = require('is-online'); @injectable() -export class FrontendConnectionStatusService extends TheiaFrontendConnectionStatusService { - @inject(ArduinoDaemon) - protected readonly daemon: ArduinoDaemon; +export class IsOnline implements FrontendApplicationContribution { + private readonly onDidChangeOnlineEmitter = new Emitter<boolean>(); + private _online = false; + private stopped = false; + + onStart(): void { + const checkOnline = async () => { + if (!this.stopped) { + try { + const online = await isOnline(); + this.setOnline(online); + } finally { + window.setTimeout(() => checkOnline(), 6_000); // 6 seconds poll interval + } + } + }; + checkOnline(); + } + + onStop(): void { + this.stopped = true; + this.onDidChangeOnlineEmitter.dispose(); + } + + get online(): boolean { + return this._online; + } + get onDidChangeOnline(): Event<boolean> { + return this.onDidChangeOnlineEmitter.event; + } + + private setOnline(online: boolean) { + const oldOnline = this._online; + this._online = online; + if (!this.stopped && this._online !== oldOnline) { + this.onDidChangeOnlineEmitter.fire(this._online); + } + } +} + +@injectable() +export class DaemonPort implements FrontendApplicationContribution { + @inject(ArduinoDaemon) + private readonly daemon: ArduinoDaemon; @inject(NotificationCenter) - protected readonly notificationCenter: NotificationCenter; + private readonly notificationCenter: NotificationCenter; + + private readonly onPortDidChangeEmitter = new Emitter<string | undefined>(); + private _port: string | undefined; + + onStart(): void { + this.daemon.tryGetPort().then( + (port) => this.setPort(port), + (reason) => + console.warn('Could not retrieve the CLI daemon port.', reason) + ); + this.notificationCenter.onDaemonDidStart((port) => this.setPort(port)); + this.notificationCenter.onDaemonDidStop(() => this.setPort(undefined)); + } + + onStop(): void { + this.onPortDidChangeEmitter.dispose(); + } - protected connectedPort: string | undefined; + get port(): string | undefined { + return this._port; + } + + get onDidChangePort(): Event<string | undefined> { + return this.onPortDidChangeEmitter.event; + } + + private setPort(port: string | undefined): void { + const oldPort = this._port; + this._port = port; + if (this._port !== oldPort) { + this.onPortDidChangeEmitter.fire(this._port); + } + } +} + +@injectable() +export class FrontendConnectionStatusService extends TheiaFrontendConnectionStatusService { + @inject(DaemonPort) + private readonly daemonPort: DaemonPort; + @inject(IsOnline) + private readonly isOnline: IsOnline; @postConstruct() protected override async init(): Promise<void> { this.schedulePing(); - try { - this.connectedPort = await this.daemon.tryGetPort(); - } catch {} - this.notificationCenter.onDaemonDidStart( - (port) => (this.connectedPort = port) - ); - this.notificationCenter.onDaemonDidStop( - () => (this.connectedPort = undefined) - ); const refresh = debounce(() => { - this.updateStatus(!!this.connectedPort); + this.updateStatus(Boolean(this.daemonPort.port) && this.isOnline.online); this.schedulePing(); }, this.options.offlineTimeout - 10); this.wsConnectionProvider.onIncomingMessageActivity(() => refresh()); } + + protected override async performPingRequest(): Promise<void> { + try { + await this.pingService.ping(); + this.updateStatus(this.isOnline.online); + } catch (e) { + this.updateStatus(false); + this.logger.error(e); + } + } } +const connectionStatusStatusBar = 'connection-status'; +const theiaOffline = 'theia-mod-offline'; + +export type OfflineConnectionStatus = + /** + * There is no websocket connection between the frontend and the backend. + */ + | 'backend' + /** + * The CLI daemon port is not available. Could not establish the gRPC connection between the backend and the CLI. + */ + | 'daemon' + /** + * Cloud not connect to the Internet from the browser. + */ + | 'internet'; + @injectable() export class ApplicationConnectionStatusContribution extends TheiaApplicationConnectionStatusContribution { - @inject(ArduinoDaemon) - protected readonly daemon: ArduinoDaemon; + @inject(DaemonPort) + private readonly daemonPort: DaemonPort; + @inject(IsOnline) + private readonly isOnline: IsOnline; + @inject(MessageService) + private readonly messageService: MessageService; + @inject(NotificationManager) + private readonly notificationManager: NotificationManager; + @inject(CreateFeatures) + private readonly createFeatures: CreateFeatures; - @inject(NotificationCenter) - protected readonly notificationCenter: NotificationCenter; + private readonly offlineStatusDidChangeEmitter = new Emitter< + OfflineConnectionStatus | undefined + >(); + private noInternetConnectionNotificationId: string | undefined; + private _offlineStatus: OfflineConnectionStatus | undefined; - protected connectedPort: string | undefined; + get offlineStatus(): OfflineConnectionStatus | undefined { + return this._offlineStatus; + } - @postConstruct() - protected async init(): Promise<void> { - try { - this.connectedPort = await this.daemon.tryGetPort(); - } catch {} - this.notificationCenter.onDaemonDidStart( - (port) => (this.connectedPort = port) - ); - this.notificationCenter.onDaemonDidStop( - () => (this.connectedPort = undefined) - ); + get onOfflineStatusDidChange(): Event<OfflineConnectionStatus | undefined> { + return this.offlineStatusDidChangeEmitter.event; } protected override onStateChange(state: ConnectionStatus): void { - if (!this.connectedPort && state === ConnectionStatus.ONLINE) { + if ( + (!Boolean(this.daemonPort.port) || !this.isOnline.online) && + state === ConnectionStatus.ONLINE + ) { return; } super.onStateChange(state); } protected override handleOffline(): void { - this.statusBar.setElement('connection-status', { + const params = { + port: this.daemonPort.port, + online: this.isOnline.online, + }; + this._offlineStatus = offlineConnectionStatusType(params); + const { text, tooltip } = offlineMessage(params); + this.statusBar.setElement(connectionStatusStatusBar, { alignment: StatusBarAlignment.LEFT, - text: this.connectedPort - ? nls.localize('theia/core/offline', 'Offline') - : '$(bolt) ' + - nls.localize('theia/core/daemonOffline', 'CLI Daemon Offline'), - tooltip: this.connectedPort - ? nls.localize( - 'theia/core/cannotConnectBackend', - 'Cannot connect to the backend.' - ) - : nls.localize( - 'theia/core/cannotConnectDaemon', - 'Cannot connect to the CLI daemon.' - ), + text, + tooltip, priority: 5000, }); - this.toDisposeOnOnline.push( - Disposable.create(() => this.statusBar.removeElement('connection-status')) - ); - document.body.classList.add('theia-mod-offline'); - this.toDisposeOnOnline.push( + document.body.classList.add(theiaOffline); + this.toDisposeOnOnline.pushAll([ Disposable.create(() => - document.body.classList.remove('theia-mod-offline') - ) - ); + this.statusBar.removeElement(connectionStatusStatusBar) + ), + Disposable.create(() => document.body.classList.remove(theiaOffline)), + Disposable.create(() => { + this._offlineStatus = undefined; + this.fireStatusDidChange(); + }), + ]); + if (!this.isOnline.online) { + const text = nls.localize( + 'arduino/connectionStatus/connectionLost', + "Connection lost. Cloud sketch actions and updates won't be available." + ); + this.noInternetConnectionNotificationId = this.notificationManager[ + 'getMessageId' + ]({ text, type: MessageType.Warning }); + if (this.createFeatures.enabled) { + this.messageService.warn(text); + } + this.toDisposeOnOnline.push( + Disposable.create(() => this.clearNoInternetConnectionNotification()) + ); + } + this.fireStatusDidChange(); + } + + private clearNoInternetConnectionNotification(): void { + if (this.noInternetConnectionNotificationId) { + this.notificationManager.clear(this.noInternetConnectionNotificationId); + this.noInternetConnectionNotificationId = undefined; + } + } + + private fireStatusDidChange(): void { + if (this.createFeatures.enabled) { + return this.offlineStatusDidChangeEmitter.fire(this._offlineStatus); + } + } +} + +interface OfflineMessageParams { + readonly port: string | undefined; + readonly online: boolean; +} +interface OfflineMessage { + readonly text: string; + readonly tooltip: string; +} + +/** + * (non-API) exported for testing + * + * The precedence of the offline states are the following: + * - No connection to the Theia backend, + * - CLI daemon is offline, and + * - There is no Internet connection. + */ +export function offlineMessage(params: OfflineMessageParams): OfflineMessage { + const statusType = offlineConnectionStatusType(params); + const text = getOfflineText(statusType); + const tooltip = getOfflineTooltip(statusType); + return { text, tooltip }; +} + +function offlineConnectionStatusType( + params: OfflineMessageParams +): OfflineConnectionStatus { + const { port, online } = params; + if (port && online) { + return 'backend'; + } + if (!port) { + return 'daemon'; + } + return 'internet'; +} + +export const backendOfflineText = nls.localize('theia/core/offline', 'Offline'); +export const daemonOfflineText = nls.localize( + 'theia/core/daemonOffline', + 'CLI Daemon Offline' +); +export const offlineText = nls.localize('theia/core/offlineText', 'Offline'); +export const backendOfflineTooltip = nls.localize( + 'theia/core/cannotConnectBackend', + 'Cannot connect to the backend.' +); +export const daemonOfflineTooltip = nls.localize( + 'theia/core/cannotConnectDaemon', + 'Cannot connect to the CLI daemon.' +); +export const offlineTooltip = offlineText; + +function getOfflineText(statusType: OfflineConnectionStatus): string { + switch (statusType) { + case 'backend': + return backendOfflineText; + case 'daemon': + return '$(bolt) ' + daemonOfflineText; + case 'internet': + return '$(alert) ' + offlineText; + default: + assertUnreachable(statusType); + } +} + +function getOfflineTooltip(statusType: OfflineConnectionStatus): string { + switch (statusType) { + case 'backend': + return backendOfflineTooltip; + case 'daemon': + return daemonOfflineTooltip; + case 'internet': + return offlineTooltip; + default: + assertUnreachable(statusType); } } diff --git a/arduino-ide-extension/src/browser/theia/core/sidebar-bottom-menu-widget.tsx b/arduino-ide-extension/src/browser/theia/core/sidebar-bottom-menu-widget.tsx index 308d77260..0c7104c85 100644 --- a/arduino-ide-extension/src/browser/theia/core/sidebar-bottom-menu-widget.tsx +++ b/arduino-ide-extension/src/browser/theia/core/sidebar-bottom-menu-widget.tsx @@ -10,17 +10,21 @@ import { import * as React from '@theia/core/shared/react'; import { accountMenu } from '../../contributions/account'; import { CreateFeatures } from '../../create/create-features'; +import { ApplicationConnectionStatusContribution } from './connection-status-service'; @injectable() export class SidebarBottomMenuWidget extends TheiaSidebarBottomMenuWidget { @inject(CreateFeatures) private readonly createFeatures: CreateFeatures; + @inject(ApplicationConnectionStatusContribution) + private readonly connectionStatue: ApplicationConnectionStatusContribution; @postConstruct() protected init(): void { - this.toDispose.push( - this.createFeatures.onDidChangeSession(() => this.update()) - ); + this.toDispose.pushAll([ + this.createFeatures.onDidChangeSession(() => this.update()), + this.connectionStatue.onOfflineStatusDidChange(() => this.update()), + ]); } protected override onClick( @@ -28,7 +32,7 @@ export class SidebarBottomMenuWidget extends TheiaSidebarBottomMenuWidget { menuPath: MenuPath ): void { const button = e.currentTarget.getBoundingClientRect(); - this.contextMenuRenderer.render({ + const options = { menuPath, includeAnchorArg: false, anchor: { @@ -37,7 +41,9 @@ export class SidebarBottomMenuWidget extends TheiaSidebarBottomMenuWidget { // https://github.com/eclipse-theia/theia/discussions/12170 y: button.top, }, - }); + showDisabled: true, + }; + this.contextMenuRenderer.render(options); } protected override render(): React.ReactNode { @@ -55,7 +61,9 @@ export class SidebarBottomMenuWidget extends TheiaSidebarBottomMenuWidget { } const arduinoAccount = menu.id === accountMenu.id; const picture = - arduinoAccount && this.createFeatures.session?.account.picture; + arduinoAccount && + this.connectionStatue.offlineStatus !== 'internet' && + this.createFeatures.session?.account.picture; const className = typeof picture === 'string' ? undefined : menu.iconClass; return ( <i diff --git a/arduino-ide-extension/src/browser/theia/core/window-title-updater.ts b/arduino-ide-extension/src/browser/theia/core/window-title-updater.ts index 9e786e262..6d5b70cab 100644 --- a/arduino-ide-extension/src/browser/theia/core/window-title-updater.ts +++ b/arduino-ide-extension/src/browser/theia/core/window-title-updater.ts @@ -1,18 +1,28 @@ import * as remote from '@theia/core/electron-shared/@electron/remote'; +import { FrontendApplication } from '@theia/core/lib/browser/frontend-application'; import { FrontendApplicationConfigProvider } from '@theia/core/lib/browser/frontend-application-config-provider'; import { NavigatableWidget } from '@theia/core/lib/browser/navigatable-types'; import { ApplicationShell } from '@theia/core/lib/browser/shell/application-shell'; import { Widget } from '@theia/core/lib/browser/widgets/widget'; import { WindowTitleUpdater as TheiaWindowTitleUpdater } from '@theia/core/lib/browser/window/window-title-updater'; import { ApplicationServer } from '@theia/core/lib/common/application-protocol'; +import { DisposableCollection } from '@theia/core/lib/common/disposable'; +import { nls } from '@theia/core/lib/common/nls'; import { isOSX } from '@theia/core/lib/common/os'; import { inject, injectable, postConstruct, } from '@theia/core/shared/inversify'; +import { EditorManager } from '@theia/editor/lib/browser/editor-manager'; import { EditorWidget } from '@theia/editor/lib/browser/editor-widget'; import { WorkspaceService } from '@theia/workspace/lib/browser/workspace-service'; +import { ConfigServiceClient } from '../../config/config-service-client'; +import { CreateFeatures } from '../../create/create-features'; +import { + CurrentSketch, + SketchesServiceClientImpl, +} from '../../sketches-service-client-impl'; @injectable() export class WindowTitleUpdater extends TheiaWindowTitleUpdater { @@ -22,12 +32,22 @@ export class WindowTitleUpdater extends TheiaWindowTitleUpdater { private readonly applicationShell: ApplicationShell; @inject(WorkspaceService) private readonly workspaceService: WorkspaceService; - - private _previousRepresentedFilename: string | undefined; + @inject(SketchesServiceClientImpl) + private readonly sketchesServiceClient: SketchesServiceClientImpl; + @inject(ConfigServiceClient) + private readonly configServiceClient: ConfigServiceClient; + @inject(CreateFeatures) + private readonly createFeatures: CreateFeatures; + @inject(EditorManager) + private readonly editorManager: EditorManager; private readonly applicationName = FrontendApplicationConfigProvider.get().applicationName; + private readonly toDispose = new DisposableCollection(); + + private previousRepresentedFilename: string | undefined; private applicationVersion: string | undefined; + private hasCloudPrefix: boolean | undefined; @postConstruct() protected init(): void { @@ -43,6 +63,22 @@ export class WindowTitleUpdater extends TheiaWindowTitleUpdater { ); } + override onStart(app: FrontendApplication): void { + super.onStart(app); + this.toDispose.pushAll([ + this.sketchesServiceClient.onCurrentSketchDidChange(() => + this.maybeSetCloudPrefix() + ), + this.configServiceClient.onDidChangeDataDirUri(() => + this.maybeSetCloudPrefix() + ), + ]); + } + + onStop(): void { + this.toDispose.dispose(); + } + protected override handleWidgetChange(widget?: Widget | undefined): void { if (isOSX) { this.maybeUpdateRepresentedFilename(widget); @@ -54,7 +90,7 @@ export class WindowTitleUpdater extends TheiaWindowTitleUpdater { protected override updateTitleWidget(widget?: Widget | undefined): void { let activeEditorShort = ''; - const rootName = this.workspaceService.workspace?.name ?? ''; + let rootName = this.workspaceService.workspace?.name ?? ''; let appName = `${this.applicationName}${ this.applicationVersion ? ` ${this.applicationVersion}` : '' }`; @@ -69,6 +105,12 @@ export class WindowTitleUpdater extends TheiaWindowTitleUpdater { activeEditorShort = ` - ${base} `; } } + if (this.hasCloudPrefix) { + rootName = `[${nls.localize( + 'arduino/title/cloud', + 'Cloud' + )}] ${rootName}`; + } this.windowTitleService.update({ rootName, appName, activeEditorShort }); } @@ -77,10 +119,32 @@ export class WindowTitleUpdater extends TheiaWindowTitleUpdater { const { uri } = widget.editor; const filename = uri.path.toString(); // Do not necessarily require the current window if not needed. It's a synchronous, blocking call. - if (this._previousRepresentedFilename !== filename) { + if (this.previousRepresentedFilename !== filename) { const currentWindow = remote.getCurrentWindow(); currentWindow.setRepresentedFilename(uri.path.toString()); - this._previousRepresentedFilename = filename; + this.previousRepresentedFilename = filename; + } + } + } + + private maybeSetCloudPrefix(): void { + if (typeof this.hasCloudPrefix === 'boolean') { + return; + } + const sketch = this.sketchesServiceClient.tryGetCurrentSketch(); + if (!CurrentSketch.isValid(sketch)) { + return; + } + const dataDirUri = this.configServiceClient.tryGetDataDirUri(); + if (!dataDirUri) { + return; + } + this.hasCloudPrefix = this.createFeatures.isCloud(sketch, dataDirUri); + if (typeof this.hasCloudPrefix === 'boolean') { + const editor = + this.editorManager.activeEditor ?? this.editorManager.currentEditor; + if (editor) { + this.updateTitleWidget(editor); } } } diff --git a/arduino-ide-extension/src/browser/theia/messages/notifications-manager.ts b/arduino-ide-extension/src/browser/theia/messages/notifications-manager.ts index bdc1ed35f..51339dbf3 100644 --- a/arduino-ide-extension/src/browser/theia/messages/notifications-manager.ts +++ b/arduino-ide-extension/src/browser/theia/messages/notifications-manager.ts @@ -1,6 +1,5 @@ import { CancellationToken } from '@theia/core/lib/common/cancellation'; import type { - Message, ProgressMessage, ProgressUpdate, } from '@theia/core/lib/common/message-service-protocol'; @@ -46,11 +45,4 @@ export class NotificationManager extends TheiaNotificationManager { } return Math.min((update.work.done / update.work.total) * 100, 100); } - - /** - * For `public` visibility. - */ - override getMessageId(message: Message): string { - return super.getMessageId(message); - } } diff --git a/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-commands.ts b/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-commands.ts new file mode 100644 index 000000000..7f4602a21 --- /dev/null +++ b/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-commands.ts @@ -0,0 +1,88 @@ +import { TreeNode } from '@theia/core/lib/browser/tree'; +import { Command } from '@theia/core/lib/common/command'; +import { CloudSketchbookTreeModel } from './cloud-sketchbook-tree-model'; + +export namespace CloudSketchbookCommands { + export interface Arg { + model: CloudSketchbookTreeModel; + node: TreeNode; + event?: MouseEvent; + } + export namespace Arg { + export function is(arg: unknown): arg is Arg { + return ( + typeof arg === 'object' && + (<Arg>arg).model !== undefined && + (<Arg>arg).model instanceof CloudSketchbookTreeModel && + (<Arg>arg).node !== undefined && + TreeNode.is((<Arg>arg).node) + ); + } + } + + export const TOGGLE_CLOUD_SKETCHBOOK = Command.toLocalizedCommand( + { + id: 'arduino-cloud-sketchbook--disable', + label: 'Show/Hide Cloud Sketchbook', + }, + 'arduino/cloud/showHideSketchbook' + ); + + export const PULL_SKETCH = Command.toLocalizedCommand( + { + id: 'arduino-cloud-sketchbook--pull-sketch', + label: 'Pull Sketch', + iconClass: 'fa fa-arduino-cloud-download', + }, + 'arduino/cloud/pullSketch' + ); + + export const PUSH_SKETCH = Command.toLocalizedCommand( + { + id: 'arduino-cloud-sketchbook--push-sketch', + label: 'Push Sketch', + iconClass: 'fa fa-arduino-cloud-upload', + }, + 'arduino/cloud/pullSketch' + ); + + export const PULL_SKETCH__TOOLBAR = { + ...PULL_SKETCH, + id: `${PULL_SKETCH.id}-toolbar`, + }; + + export const PUSH_SKETCH__TOOLBAR = { + ...PUSH_SKETCH, + id: `${PUSH_SKETCH.id}-toolbar`, + }; + + export const OPEN_IN_CLOUD_EDITOR = Command.toLocalizedCommand( + { + id: 'arduino-cloud-sketchbook--open-in-cloud-editor', + label: 'Open in Cloud Editor', + }, + 'arduino/cloud/openInCloudEditor' + ); + + export const OPEN_SKETCHBOOKSYNC_CONTEXT_MENU = Command.toLocalizedCommand( + { + id: 'arduino-sketchbook-sync--open-sketch-context-menu', + label: 'Options...', + iconClass: 'sketchbook-tree__opts', + }, + 'arduino/cloud/options' + ); + + export const OPEN_SKETCH_SHARE_DIALOG = Command.toLocalizedCommand( + { + id: 'arduino-cloud-sketchbook--share-modal', + label: 'Share...', + }, + 'arduino/cloud/share' + ); + + export const OPEN_PROFILE_CONTEXT_MENU: Command = { + id: 'arduino-cloud-sketchbook--open-profile-menu', + label: 'Contextual menu', + }; +} diff --git a/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-composite-widget.tsx b/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-composite-widget.tsx index 0b4d26a94..46e273b25 100644 --- a/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-composite-widget.tsx +++ b/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-composite-widget.tsx @@ -5,7 +5,7 @@ import { injectable, postConstruct, } from '@theia/core/shared/inversify'; -import { CloudStatus } from './cloud-user-status'; +import { CloudStatus } from './cloud-status'; import { nls } from '@theia/core/lib/common/nls'; import { CloudSketchbookTreeWidget } from './cloud-sketchbook-tree-widget'; import { AuthenticationClientService } from '../../auth/authentication-client-service'; @@ -13,6 +13,7 @@ import { CloudSketchbookTreeModel } from './cloud-sketchbook-tree-model'; import { BaseSketchbookCompositeWidget } from '../sketchbook/sketchbook-composite-widget'; import { CreateNew } from '../sketchbook/create-new'; import { AuthenticationSession } from '../../../node/auth/types'; +import { ApplicationConnectionStatusContribution } from '../../theia/core/connection-status-service'; @injectable() export class CloudSketchbookCompositeWidget extends BaseSketchbookCompositeWidget<CloudSketchbookTreeWidget> { @@ -20,6 +21,9 @@ export class CloudSketchbookCompositeWidget extends BaseSketchbookCompositeWidge private readonly authenticationService: AuthenticationClientService; @inject(CloudSketchbookTreeWidget) private readonly cloudSketchbookTreeWidget: CloudSketchbookTreeWidget; + @inject(ApplicationConnectionStatusContribution) + private readonly connectionStatus: ApplicationConnectionStatusContribution; + private _session: AuthenticationSession | undefined; constructor() { @@ -66,6 +70,7 @@ export class CloudSketchbookCompositeWidget extends BaseSketchbookCompositeWidge this.cloudSketchbookTreeWidget.model as CloudSketchbookTreeModel } authenticationService={this.authenticationService} + connectionStatus={this.connectionStatus} /> </> ); diff --git a/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-contributions.ts b/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-contributions.ts index 212fc5f62..f58f747e7 100644 --- a/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-contributions.ts +++ b/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-contributions.ts @@ -1,145 +1,94 @@ -import { inject, injectable } from '@theia/core/shared/inversify'; -import { TreeNode } from '@theia/core/lib/browser/tree'; -import { FileService } from '@theia/filesystem/lib/browser/file-service'; -import { Command, CommandRegistry } from '@theia/core/lib/common/command'; import { ContextMenuRenderer, RenderContextMenuOptions, -} from '@theia/core/lib/browser'; +} from '@theia/core/lib/browser/context-menu-renderer'; +import { FrontendApplication } from '@theia/core/lib/browser/frontend-application'; +import { + PreferenceScope, + PreferenceService, +} from '@theia/core/lib/browser/preferences/preference-service'; +import { ApplicationShell } from '@theia/core/lib/browser/shell/application-shell'; +import { WindowService } from '@theia/core/lib/browser/window/window-service'; +import { CommandRegistry } from '@theia/core/lib/common/command'; import { Disposable, DisposableCollection, } from '@theia/core/lib/common/disposable'; -import { WindowService } from '@theia/core/lib/browser/window/window-service'; +import { Emitter, Event } from '@theia/core/lib/common/event'; import { MenuModelRegistry } from '@theia/core/lib/common/menu'; -import { CloudSketchbookTree } from './cloud-sketchbook-tree'; -import { CloudSketchbookTreeModel } from './cloud-sketchbook-tree-model'; -import { ShareSketchDialog } from '../../dialogs/cloud-share-sketch-dialog'; -import { CreateApi } from '../../create/create-api'; +import { nls } from '@theia/core/lib/common/nls'; +import { Widget } from '@theia/core/shared/@phosphor/widgets'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { ArduinoPreferences } from '../../arduino-preferences'; +import { ConfigServiceClient } from '../../config/config-service-client'; +import { CloudSketchContribution } from '../../contributions/cloud-contribution'; import { - PreferenceService, - PreferenceScope, -} from '@theia/core/lib/browser/preferences/preference-service'; + Sketch, + TabBarToolbarRegistry, +} from '../../contributions/contribution'; +import { ShareSketchDialog } from '../../dialogs/cloud-share-sketch-dialog'; import { ArduinoMenus, PlaceholderMenuNode } from '../../menu/arduino-menus'; +import { CurrentSketch } from '../../sketches-service-client-impl'; +import { ApplicationConnectionStatusContribution } from '../../theia/core/connection-status-service'; import { SketchbookCommands } from '../sketchbook/sketchbook-commands'; -import { - CurrentSketch, - SketchesServiceClientImpl, -} from '../../sketches-service-client-impl'; -import { Contribution } from '../../contributions/contribution'; -import { ArduinoPreferences } from '../../arduino-preferences'; -import { MainMenuManager } from '../../../common/main-menu-manager'; -import { nls } from '@theia/core/lib/common'; +import { CloudSketchbookCommands } from './cloud-sketchbook-commands'; +import { CloudSketchbookTree } from './cloud-sketchbook-tree'; +import { CreateUri } from '../../create/create-uri'; -export const SKETCHBOOKSYNC__CONTEXT = ['arduino-sketchbook-sync--context']; +const SKETCHBOOKSYNC__CONTEXT = ['arduino-sketchbook-sync--context']; // `Open Folder`, `Open in New Window` -export const SKETCHBOOKSYNC__CONTEXT__MAIN_GROUP = [ +const SKETCHBOOKSYNC__CONTEXT__MAIN_GROUP = [ ...SKETCHBOOKSYNC__CONTEXT, '0_main', ]; -export namespace CloudSketchbookCommands { - export interface Arg { - model: CloudSketchbookTreeModel; - node: TreeNode; - event?: MouseEvent; - } - export namespace Arg { - export function is(arg: Partial<Arg> | undefined): arg is Arg { - return ( - !!arg && !!arg.node && arg.model instanceof CloudSketchbookTreeModel - ); - } - } - - export const TOGGLE_CLOUD_SKETCHBOOK = Command.toLocalizedCommand( - { - id: 'arduino-cloud-sketchbook--disable', - label: 'Show/Hide Cloud Sketchbook', - }, - 'arduino/cloud/showHideSketchbook' - ); - - export const PULL_SKETCH = Command.toLocalizedCommand( - { - id: 'arduino-cloud-sketchbook--pull-sketch', - label: 'Pull Sketch', - iconClass: 'pull-sketch-icon', - }, - 'arduino/cloud/pullSketch' - ); - - export const PUSH_SKETCH = Command.toLocalizedCommand( - { - id: 'arduino-cloud-sketchbook--push-sketch', - label: 'Push Sketch', - iconClass: 'push-sketch-icon', - }, - 'arduino/cloud/pullSketch' - ); - - export const OPEN_IN_CLOUD_EDITOR = Command.toLocalizedCommand( - { - id: 'arduino-cloud-sketchbook--open-in-cloud-editor', - label: 'Open in Cloud Editor', - }, - 'arduino/cloud/openInCloudEditor' - ); - - export const OPEN_SKETCHBOOKSYNC_CONTEXT_MENU = Command.toLocalizedCommand( - { - id: 'arduino-sketchbook-sync--open-sketch-context-menu', - label: 'Options...', - iconClass: 'sketchbook-tree__opts', - }, - 'arduino/cloud/options' - ); - - export const OPEN_SKETCH_SHARE_DIALOG = Command.toLocalizedCommand( - { - id: 'arduino-cloud-sketchbook--share-modal', - label: 'Share...', - }, - 'arduino/cloud/share' - ); - - export const OPEN_PROFILE_CONTEXT_MENU: Command = { - id: 'arduino-cloud-sketchbook--open-profile-menu', - label: 'Contextual menu', - }; -} - @injectable() -export class CloudSketchbookContribution extends Contribution { - @inject(FileService) - protected readonly fileService: FileService; - +export class CloudSketchbookContribution extends CloudSketchContribution { @inject(ContextMenuRenderer) - protected readonly contextMenuRenderer: ContextMenuRenderer; - + private readonly contextMenuRenderer: ContextMenuRenderer; @inject(MenuModelRegistry) - protected readonly menuRegistry: MenuModelRegistry; - - @inject(SketchesServiceClientImpl) - protected readonly sketchServiceClient: SketchesServiceClientImpl; - + private readonly menuRegistry: MenuModelRegistry; + @inject(CommandRegistry) + private readonly commandRegistry: CommandRegistry; @inject(WindowService) - protected readonly windowService: WindowService; - - @inject(CreateApi) - protected readonly createApi: CreateApi; - + private readonly windowService: WindowService; @inject(ArduinoPreferences) - protected readonly arduinoPreferences: ArduinoPreferences; - + private readonly arduinoPreferences: ArduinoPreferences; @inject(PreferenceService) - protected readonly preferenceService: PreferenceService; - - @inject(MainMenuManager) - protected readonly mainMenuManager: MainMenuManager; + private readonly preferenceService: PreferenceService; + @inject(ConfigServiceClient) + private readonly configServiceClient: ConfigServiceClient; + @inject(ApplicationConnectionStatusContribution) + private readonly connectionStatus: ApplicationConnectionStatusContribution; + + private readonly onDidChangeToolbarEmitter = new Emitter<void>(); + private readonly toDisposeBeforeNewContextMenu = new DisposableCollection(); + private readonly toDisposeOnStop = new DisposableCollection( + this.onDidChangeToolbarEmitter, + this.toDisposeBeforeNewContextMenu + ); + private shell: ApplicationShell | undefined; + + override onStart(app: FrontendApplication): void { + this.shell = app.shell; + this.toDisposeOnStop.pushAll([ + this.connectionStatus.onOfflineStatusDidChange((offlineStatus) => { + if (!offlineStatus || offlineStatus === 'internet') { + this.fireToolbarChange(); + } + }), + this.createFeatures.onDidChangeSession(() => this.fireToolbarChange()), + this.createFeatures.onDidChangeEnabled(() => this.fireToolbarChange()), + this.createFeatures.onDidChangeCloudSketchState(() => + this.fireToolbarChange() + ), + ]); + } - protected readonly toDisposeBeforeNewContextMenu = new DisposableCollection(); + onStop(): void { + this.toDisposeOnStop.dispose(); + } override registerMenus(menus: MenuModelRegistry): void { menus.registerMenuAction(ArduinoMenus.FILE__ADVANCED_SUBMENU, { @@ -149,6 +98,23 @@ export class CloudSketchbookContribution extends Contribution { }); } + override registerToolbarItems(registry: TabBarToolbarRegistry): void { + registry.registerItem({ + id: CloudSketchbookCommands.PULL_SKETCH__TOOLBAR.id, + command: CloudSketchbookCommands.PULL_SKETCH__TOOLBAR.id, + tooltip: CloudSketchbookCommands.PULL_SKETCH__TOOLBAR.label, + priority: -2, + onDidChange: this.onDidChangeToolbar, + }); + registry.registerItem({ + id: CloudSketchbookCommands.PUSH_SKETCH__TOOLBAR.id, + command: CloudSketchbookCommands.PUSH_SKETCH__TOOLBAR.id, + tooltip: CloudSketchbookCommands.PUSH_SKETCH__TOOLBAR.label, + priority: -1, + onDidChange: this.onDidChangeToolbar, + }); + } + override registerCommands(registry: CommandRegistry): void { registry.registerCommand(CloudSketchbookCommands.TOGGLE_CLOUD_SKETCHBOOK, { execute: () => { @@ -158,32 +124,41 @@ export class CloudSketchbookContribution extends Contribution { PreferenceScope.User ); }, - isEnabled: () => true, - isVisible: () => true, }); registry.registerCommand(CloudSketchbookCommands.PULL_SKETCH, { execute: (arg) => arg.model.sketchbookTree().pull(arg), - isEnabled: (arg) => - CloudSketchbookCommands.Arg.is(arg) && - CloudSketchbookTree.CloudSketchDirNode.is(arg.node), - isVisible: (arg) => - CloudSketchbookCommands.Arg.is(arg) && - CloudSketchbookTree.CloudSketchDirNode.is(arg.node), + isEnabled: (arg) => this.isCloudSketchDirNodeCommandArg(arg), + isVisible: (arg) => this.isCloudSketchDirNodeCommandArg(arg), }); registry.registerCommand(CloudSketchbookCommands.PUSH_SKETCH, { execute: (arg) => arg.model.sketchbookTree().push(arg.node), isEnabled: (arg) => - CloudSketchbookCommands.Arg.is(arg) && - CloudSketchbookTree.CloudSketchDirNode.is(arg.node) && + this.isCloudSketchDirNodeCommandArg(arg) && CloudSketchbookTree.CloudSketchTreeNode.isSynced(arg.node), isVisible: (arg) => - CloudSketchbookCommands.Arg.is(arg) && - CloudSketchbookTree.CloudSketchDirNode.is(arg.node) && + this.isCloudSketchDirNodeCommandArg(arg) && CloudSketchbookTree.CloudSketchTreeNode.isSynced(arg.node), }); + registry.registerCommand(CloudSketchbookCommands.PUSH_SKETCH__TOOLBAR, { + execute: () => + this.executeDelegateWithCurrentSketch( + CloudSketchbookCommands.PUSH_SKETCH.id + ), + isEnabled: (arg) => this.isEnabledCloudSketchToolbar(arg), + isVisible: (arg) => this.isVisibleCloudSketchToolbar(arg), + }); + registry.registerCommand(CloudSketchbookCommands.PULL_SKETCH__TOOLBAR, { + execute: () => + this.executeDelegateWithCurrentSketch( + CloudSketchbookCommands.PULL_SKETCH.id + ), + isEnabled: (arg) => this.isEnabledCloudSketchToolbar(arg), + isVisible: (arg) => this.isVisibleCloudSketchToolbar(arg), + }); + registry.registerCommand(CloudSketchbookCommands.OPEN_IN_CLOUD_EDITOR, { execute: (arg) => { this.windowService.openNewWindow( @@ -191,12 +166,8 @@ export class CloudSketchbookContribution extends Contribution { { external: true } ); }, - isEnabled: (arg) => - CloudSketchbookCommands.Arg.is(arg) && - CloudSketchbookTree.CloudSketchDirNode.is(arg.node), - isVisible: (arg) => - CloudSketchbookCommands.Arg.is(arg) && - CloudSketchbookTree.CloudSketchDirNode.is(arg.node), + isEnabled: (arg) => this.isCloudSketchDirNodeCommandArg(arg), + isVisible: (arg) => this.isCloudSketchDirNodeCommandArg(arg), }); registry.registerCommand(CloudSketchbookCommands.OPEN_SKETCH_SHARE_DIALOG, { @@ -207,12 +178,8 @@ export class CloudSketchbookContribution extends Contribution { createApi: this.createApi, }).open(); }, - isEnabled: (arg) => - CloudSketchbookCommands.Arg.is(arg) && - CloudSketchbookTree.CloudSketchDirNode.is(arg.node), - isVisible: (arg) => - CloudSketchbookCommands.Arg.is(arg) && - CloudSketchbookTree.CloudSketchDirNode.is(arg.node), + isEnabled: (arg) => this.isCloudSketchDirNodeCommandArg(arg), + isVisible: (arg) => this.isCloudSketchDirNodeCommandArg(arg), }); registry.registerCommand( @@ -316,7 +283,118 @@ export class CloudSketchbookContribution extends Contribution { }, } ); + } + + private get currentCloudSketch(): Sketch | undefined { + const currentSketch = this.sketchServiceClient.tryGetCurrentSketch(); + // could not load sketch via CLI + if (!CurrentSketch.isValid(currentSketch)) { + return undefined; + } + // cannot determine if the sketch is in the cloud cache folder + const dataDirUri = this.configServiceClient.tryGetDataDirUri(); + if (!dataDirUri) { + return undefined; + } + // sketch is not in the cache folder + if (!this.createFeatures.isCloud(currentSketch, dataDirUri)) { + return undefined; + } + return currentSketch; + } + + private isVisibleCloudSketchToolbar(arg: unknown): boolean { + // cloud preference is disabled + if (!this.createFeatures.enabled) { + return false; + } + if (!this.currentCloudSketch) { + return false; + } + if (arg instanceof Widget) { + return !!this.shell && this.shell.getWidgets('main').indexOf(arg) !== -1; + } + return false; + } + + private isEnabledCloudSketchToolbar(arg: unknown): boolean { + if (!this.isVisibleCloudSketchToolbar(arg)) { + return false; + } + // not logged in + if (!this.createFeatures.session) { + return false; + } + // no Internet connection + if (this.connectionStatus.offlineStatus === 'internet') { + return false; + } + // no pull/push context for the current cloud sketch + const sketch = this.currentCloudSketch; + if (sketch) { + const cloudUri = this.createFeatures.cloudUri(sketch); + if (cloudUri) { + return !this.createFeatures.cloudSketchState( + CreateUri.toUri(cloudUri.path.toString()) + ); + } + } + return false; + } + + private isCloudSketchDirNodeCommandArg( + arg: unknown + ): arg is CloudSketchbookCommands.Arg & { + node: CloudSketchbookTree.CloudSketchDirNode; + } { + return ( + CloudSketchbookCommands.Arg.is(arg) && + CloudSketchbookTree.CloudSketchDirNode.is(arg.node) && + !this.createFeatures.cloudSketchState(arg.node.remoteUri) + ); + } + + private async commandArgFromCurrentSketch(): Promise< + CloudSketchbookCommands.Arg | undefined + > { + const sketch = this.currentCloudSketch; + if (!sketch) { + return undefined; + } + const model = await this.treeModel(); + if (!model) { + return undefined; + } + const cloudUri = this.createFeatures.cloudUri(sketch); + if (!cloudUri) { + return undefined; + } + const posixPath = cloudUri.path.toString(); + const node = model.getNode(posixPath); + if (CloudSketchbookTree.CloudSketchDirNode.is(node)) { + return { model, node }; + } + return undefined; + } + + private async executeDelegateWithCurrentSketch(id: string): Promise<unknown> { + const arg = await this.commandArgFromCurrentSketch(); + if (!arg) { + return; + } + if (!this.commandRegistry.getActiveHandler(id, arg)) { + throw new Error( + `No active handler was available for the delegate command: ${id}. Cloud sketch tree node: ${arg.node.id}` + ); + } + return this.commandRegistry.executeCommand(id, arg); + } + + private fireToolbarChange(): void { + this.onDidChangeToolbarEmitter.fire(); + } - this.registerMenus(this.menuRegistry); + private get onDidChangeToolbar(): Event<void> { + return this.onDidChangeToolbarEmitter.event; } } diff --git a/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-tree-model.ts b/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-tree-model.ts index 3211a85f0..e57926465 100644 --- a/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-tree-model.ts +++ b/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-tree-model.ts @@ -20,6 +20,7 @@ import URI from '@theia/core/lib/common/uri'; import { Create } from '../../create/typings'; import { nls } from '@theia/core/lib/common/nls'; import { Deferred } from '@theia/core/lib/common/promise-util'; +import { ApplicationConnectionStatusContribution } from '../../theia/core/connection-status-service'; function sketchBaseDir(sketch: Create.Sketch): FileStat { // extract the sketch path @@ -63,15 +64,22 @@ export class CloudSketchbookTreeModel extends SketchbookTreeModel { private readonly authenticationService: AuthenticationClientService; @inject(LocalCacheFsProvider) private readonly localCacheFsProvider: LocalCacheFsProvider; + @inject(ApplicationConnectionStatusContribution) + private readonly connectionStatus: ApplicationConnectionStatusContribution; private _localCacheFsProviderReady: Deferred<void> | undefined; @postConstruct() protected override init(): void { super.init(); - this.toDispose.push( - this.authenticationService.onSessionDidChange(() => this.updateRoot()) - ); + this.toDispose.pushAll([ + this.authenticationService.onSessionDidChange(() => this.updateRoot()), + this.connectionStatus.onOfflineStatusDidChange((offlineStatus) => { + if (!offlineStatus) { + this.updateRoot(); + } + }), + ]); } override *getNodesByUri(uri: URI): IterableIterator<TreeNode> { diff --git a/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-tree-widget.tsx b/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-tree-widget.tsx index 3f1ae430f..8877d2381 100644 --- a/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-tree-widget.tsx +++ b/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-tree-widget.tsx @@ -15,6 +15,7 @@ import { CompositeTreeNode } from '@theia/core/lib/browser'; import { shell } from '@theia/core/electron-shared/@electron/remote'; import { SketchbookTreeWidget } from '../sketchbook/sketchbook-tree-widget'; import { nls } from '@theia/core/lib/common'; +import { ApplicationConnectionStatusContribution } from '../../theia/core/connection-status-service'; @injectable() export class CloudSketchbookTreeWidget extends SketchbookTreeWidget { @@ -27,6 +28,9 @@ export class CloudSketchbookTreeWidget extends SketchbookTreeWidget { @inject(CloudSketchbookTree) protected readonly cloudSketchbookTree: CloudSketchbookTree; + @inject(ApplicationConnectionStatusContribution) + private readonly connectionStatus: ApplicationConnectionStatusContribution; + protected override renderTree(model: TreeModel): React.ReactNode { if (this.shouldShowWelcomeView()) return this.renderViewWelcome(); if (this.shouldShowEmptyView()) return this.renderEmptyView(); @@ -91,10 +95,33 @@ export class CloudSketchbookTreeWidget extends SketchbookTreeWidget { return classNames; } + protected override renderIcon( + node: TreeNode, + props: NodeProps + ): React.ReactNode { + if (CloudSketchbookTree.CloudSketchDirNode.is(node)) { + const synced = CloudSketchbookTree.CloudSketchTreeNode.isSynced(node); + const offline = this.connectionStatus.offlineStatus === 'internet'; + const icon = `fa fa-arduino-cloud${synced ? '-filled' : ''}${ + offline ? '-offline' : '' + }`; + return ( + <div + className={`theia-file-icons-js file-icon${ + !synced && offline ? ' not-in-sync-offline' : '' + }`} + > + <div className={icon} /> + </div> + ); + } + return super.renderIcon(node, props); + } + protected override renderInlineCommands(node: any): React.ReactNode { if (CloudSketchbookTree.CloudSketchDirNode.is(node) && node.commands) { return Array.from(new Set(node.commands)).map((command) => - this.renderInlineCommand(command.id, node, { + this.renderInlineCommand(command, node, { username: this.authenticationService.session?.account?.label, }) ); diff --git a/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-tree.ts b/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-tree.ts index e3dd60e70..9a5571da2 100644 --- a/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-tree.ts +++ b/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-tree.ts @@ -22,15 +22,22 @@ import { LocalCacheFsProvider, LocalCacheUri, } from '../../local-cache/local-cache-fs-provider'; -import { CloudSketchbookCommands } from './cloud-sketchbook-contributions'; +import { CloudSketchbookCommands } from './cloud-sketchbook-commands'; import { DoNotAskAgainConfirmDialog } from '../../dialogs/do-not-ask-again-dialog'; import { SketchbookTree } from '../sketchbook/sketchbook-tree'; -import { firstToUpperCase } from '../../../common/utils'; +import { assertUnreachable } from '../../../common/utils'; import { FileStat } from '@theia/filesystem/lib/common/files'; import { WorkspaceNode } from '@theia/navigator/lib/browser/navigator-tree'; import { posix, splitSketchPath } from '../../create/create-paths'; import { Create } from '../../create/typings'; import { nls } from '@theia/core/lib/common'; +import { ApplicationConnectionStatusContribution } from '../../theia/core/connection-status-service'; +import { ExecuteWithProgress } from '../../../common/protocol/progressible'; +import { + pullingSketch, + pushingSketch, +} from '../../contributions/cloud-contribution'; +import { CloudSketchState, CreateFeatures } from '../../create/create-features'; const MESSAGE_TIMEOUT = 5 * 1000; const deepmerge = require('deepmerge').default; @@ -54,6 +61,19 @@ export class CloudSketchbookTree extends SketchbookTree { @inject(CreateApi) private readonly createApi: CreateApi; + @inject(ApplicationConnectionStatusContribution) + private readonly connectionStatus: ApplicationConnectionStatusContribution; + + @inject(CreateFeatures) + private readonly createFeatures: CreateFeatures; + + protected override init(): void { + this.toDispose.push( + this.connectionStatus.onOfflineStatusDidChange(() => this.refresh()) + ); + super.init(); + } + async pushPublicWarn( node: CloudSketchbookTree.CloudSketchDirNode ): Promise<boolean> { @@ -84,7 +104,7 @@ export class CloudSketchbookTree extends SketchbookTree { } // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any - async pull(arg: any): Promise<void> { + async pull(arg: any, noProgress = false): Promise<void> { const { // model, node, @@ -118,32 +138,45 @@ export class CloudSketchbookTree extends SketchbookTree { return; } } - return this.runWithState(node, 'pulling', async (node) => { - const commandsCopy = node.commands; - node.commands = []; + return this.runWithState( + node, + 'pull', + async (node) => { + await this.pullNode(node); + }, + noProgress + ); + } - const localUri = await this.fileService.toUnderlyingResource( - LocalCacheUri.root.resolve(node.remoteUri.path) - ); - await this.sync(node.remoteUri, localUri); + private async pullNode(node: CloudSketchbookTree.CloudSketchDirNode) { + const commandsCopy = node.commands; + node.commands = []; - this.createApi.sketchCache.purgeByPath(node.remoteUri.path.toString()); + const localUri = await this.fileService.toUnderlyingResource( + LocalCacheUri.root.resolve(node.remoteUri.path) + ); + await this.sync(node.remoteUri, localUri); - node.commands = commandsCopy; - this.messageService.info( - nls.localize( - 'arduino/cloud/donePulling', - 'Done pulling ‘{0}’.', - node.fileStat.name - ), - { - timeout: MESSAGE_TIMEOUT, - } - ); - }); + this.createApi.sketchCache.purgeByPath(node.remoteUri.path.toString()); + + node.commands = commandsCopy; + this.messageService.info( + nls.localize( + 'arduino/cloud/donePulling', + "Done pulling '{0}'.", + node.fileStat.name + ), + { + timeout: MESSAGE_TIMEOUT, + } + ); } - async push(node: CloudSketchbookTree.CloudSketchDirNode): Promise<void> { + async push( + node: CloudSketchbookTree.CloudSketchDirNode, + noProgress = false, + ignorePushWarnings = false + ): Promise<void> { if (!CloudSketchbookTree.CloudSketchTreeNode.isSynced(node)) { throw new Error( nls.localize( @@ -158,7 +191,8 @@ export class CloudSketchbookTree extends SketchbookTree { return; } - const warn = this.arduinoPreferences['arduino.cloud.push.warn']; + const warn = + !ignorePushWarnings && this.arduinoPreferences['arduino.cloud.push.warn']; if (warn) { const ok = await new DoNotAskAgainConfirmDialog({ @@ -178,37 +212,46 @@ export class CloudSketchbookTree extends SketchbookTree { return; } } - return this.runWithState(node, 'pushing', async (node) => { - if (!CloudSketchbookTree.CloudSketchTreeNode.isSynced(node)) { - throw new Error( - nls.localize( - 'arduino/cloud/pullFirst', - 'You have to pull first to be able to push to the Cloud.' - ) - ); - } - const commandsCopy = node.commands; - node.commands = []; + return this.runWithState( + node, + 'push', + async (node) => { + await this.pushNode(node); + }, + noProgress + ); + } - const localUri = await this.fileService.toUnderlyingResource( - LocalCacheUri.root.resolve(node.remoteUri.path) + private async pushNode(node: CloudSketchbookTree.CloudSketchDirNode) { + if (!CloudSketchbookTree.CloudSketchTreeNode.isSynced(node)) { + throw new Error( + nls.localize( + 'arduino/cloud/pullFirst', + 'You have to pull first to be able to push to the Cloud.' + ) ); - await this.sync(localUri, node.remoteUri); + } + const commandsCopy = node.commands; + node.commands = []; - this.createApi.sketchCache.purgeByPath(node.remoteUri.path.toString()); + const localUri = await this.fileService.toUnderlyingResource( + LocalCacheUri.root.resolve(node.remoteUri.path) + ); + await this.sync(localUri, node.remoteUri); - node.commands = commandsCopy; - this.messageService.info( - nls.localize( - 'arduino/cloud/donePushing', - 'Done pushing ‘{0}’.', - node.fileStat.name - ), - { - timeout: MESSAGE_TIMEOUT, - } - ); - }); + this.createApi.sketchCache.purgeByPath(node.remoteUri.path.toString()); + + node.commands = commandsCopy; + this.messageService.info( + nls.localize( + 'arduino/cloud/donePushing', + "Done pushing '{0}'.", + node.fileStat.name + ), + { + timeout: MESSAGE_TIMEOUT, + } + ); } private async recursiveURIs(uri: URI): Promise<URI[]> { @@ -310,31 +353,37 @@ export class CloudSketchbookTree extends SketchbookTree { private async runWithState<T>( node: CloudSketchbookTree.CloudSketchDirNode & Partial<DecoratedTreeNode>, - state: CloudSketchbookTree.CloudSketchDirNode.State, - task: (node: CloudSketchbookTree.CloudSketchDirNode) => MaybePromise<T> + state: CloudSketchState, + task: (node: CloudSketchbookTree.CloudSketchDirNode) => MaybePromise<T>, + noProgress = false ): Promise<T> { - const decoration: WidgetDecoration.TailDecoration = { - data: `${firstToUpperCase(state)}...`, - fontData: { - color: 'var(--theia-list-highlightForeground)', - }, - }; + this.createFeatures.setCloudSketchState(node.remoteUri, state); try { - node.state = state; - this.mergeDecoration(node, { tailDecorations: [decoration] }); + const result = await (noProgress + ? task(node) + : ExecuteWithProgress.withProgress( + this.taskMessage(state, node.uri.path.name), + this.messageService, + async (progress) => { + progress.report({ work: { done: 0, total: NaN } }); + return task(node); + } + )); await this.refresh(node); - const result = await task(node); return result; } finally { - delete node.state; - // TODO: find a better way to attach and detach decorators. Do we need a proper `TreeDecorator` instead? - const index = node.decorationData?.tailDecorations?.findIndex( - (candidate) => JSON.stringify(decoration) === JSON.stringify(candidate) - ); - if (typeof index === 'number' && index !== -1) { - node.decorationData?.tailDecorations?.splice(index, 1); - } - await this.refresh(node); + this.createFeatures.setCloudSketchState(node.remoteUri, undefined); + } + } + + private taskMessage(state: CloudSketchState, input: string): string { + switch (state) { + case 'pull': + return pullingSketch(input); + case 'push': + return pushingSketch(input); + default: + assertUnreachable(state); } } @@ -501,7 +550,7 @@ export class CloudSketchbookTree extends SketchbookTree { }; } - protected readonly notInSyncDecoration: WidgetDecoration.Data = { + protected readonly notInSyncOfflineDecoration: WidgetDecoration.Data = { fontData: { color: 'var(--theia-activityBar-inactiveForeground)', }, @@ -522,11 +571,15 @@ export class CloudSketchbookTree extends SketchbookTree { node.fileStat.resource.path.toString() ); - const commands = [CloudSketchbookCommands.PULL_SKETCH]; + const commands: Command[] = []; + if (this.connectionStatus.offlineStatus !== 'internet') { + commands.push(CloudSketchbookCommands.PULL_SKETCH); + } if ( CloudSketchbookTree.CloudSketchTreeNode.is(node) && - CloudSketchbookTree.CloudSketchTreeNode.isSynced(node) + CloudSketchbookTree.CloudSketchTreeNode.isSynced(node) && + this.connectionStatus.offlineStatus !== 'internet' ) { commands.push(CloudSketchbookCommands.PUSH_SKETCH); } @@ -557,14 +610,15 @@ export class CloudSketchbookTree extends SketchbookTree { } } - // add style decoration for not-in-sync files + // add style decoration for not-in-sync files when offline if ( CloudSketchbookTree.CloudSketchTreeNode.is(node) && - !CloudSketchbookTree.CloudSketchTreeNode.isSynced(node) + !CloudSketchbookTree.CloudSketchTreeNode.isSynced(node) && + this.connectionStatus.offlineStatus === 'internet' ) { - this.mergeDecoration(node, this.notInSyncDecoration); + this.mergeDecoration(node, this.notInSyncOfflineDecoration); } else { - this.removeDecoration(node, this.notInSyncDecoration); + this.removeDecoration(node, this.notInSyncOfflineDecoration); } return node; @@ -644,7 +698,7 @@ export namespace CloudSketchbookTree { export interface CloudSketchDirNode extends Omit<SketchbookTree.SketchDirNode, 'fileStat'>, CloudSketchTreeNode { - state?: CloudSketchDirNode.State; + state?: CloudSketchState; isPublic?: boolean; sketchId?: string; commands?: Command[]; @@ -653,7 +707,5 @@ export namespace CloudSketchbookTree { export function is(node: TreeNode | undefined): node is CloudSketchDirNode { return SketchbookTree.SketchDirNode.is(node); } - - export type State = 'syncing' | 'pulling' | 'pushing'; } } diff --git a/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-user-status.tsx b/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-status.tsx similarity index 62% rename from arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-user-status.tsx rename to arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-status.tsx index 68a7da5eb..cd329369d 100644 --- a/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-user-status.tsx +++ b/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-status.tsx @@ -1,19 +1,17 @@ import * as React from '@theia/core/shared/react'; -import { - Disposable, - DisposableCollection, -} from '@theia/core/lib/common/disposable'; +import { DisposableCollection } from '@theia/core/lib/common/disposable'; import { CloudSketchbookTreeModel } from './cloud-sketchbook-tree-model'; import { AuthenticationClientService } from '../../auth/authentication-client-service'; import { nls } from '@theia/core/lib/common'; +import { ApplicationConnectionStatusContribution } from '../../theia/core/connection-status-service'; export class CloudStatus extends React.Component< - UserStatus.Props, - UserStatus.State + CloudStatus.Props, + CloudStatus.State > { protected readonly toDispose = new DisposableCollection(); - constructor(props: UserStatus.Props) { + constructor(props: CloudStatus.Props) { super(props); this.state = { status: this.status, @@ -22,17 +20,11 @@ export class CloudStatus extends React.Component< } override componentDidMount(): void { - const statusListener = () => this.setState({ status: this.status }); - window.addEventListener('online', statusListener); - window.addEventListener('offline', statusListener); - this.toDispose.pushAll([ - Disposable.create(() => - window.removeEventListener('online', statusListener) - ), - Disposable.create(() => - window.removeEventListener('offline', statusListener) - ), - ]); + this.toDispose.push( + this.props.connectionStatus.onOfflineStatusDidChange(() => + this.setState({ status: this.status }) + ) + ); } override componentWillUnmount(): void { @@ -58,14 +50,21 @@ export class CloudStatus extends React.Component< : nls.localize('arduino/cloud/offline', 'Offline')} </div> <div className="actions item flex-line"> - <div - title={nls.localize('arduino/cloud/sync', 'Sync')} - className={`fa fa-reload ${ - (this.state.refreshing && 'rotating') || '' - }`} - style={{ cursor: 'pointer' }} - onClick={this.onDidClickRefresh} - /> + {this.props.connectionStatus.offlineStatus === 'internet' ? ( + <div + className="fa fa-arduino-cloud-offline" + title={nls.localize('arduino/cloud/offline', 'Offline')} + /> + ) : ( + <div + title={nls.localize('arduino/cloud/sync', 'Sync')} + className={`fa fa-reload ${ + (this.state.refreshing && 'rotating') || '' + }`} + style={{ cursor: 'pointer' }} + onClick={this.onDidClickRefresh} + /> + )} </div> </div> ); @@ -83,14 +82,17 @@ export class CloudStatus extends React.Component< }; private get status(): 'connected' | 'offline' { - return window.navigator.onLine ? 'connected' : 'offline'; + return this.props.connectionStatus.offlineStatus === 'internet' + ? 'offline' + : 'connected'; } } -export namespace UserStatus { +export namespace CloudStatus { export interface Props { readonly model: CloudSketchbookTreeModel; readonly authenticationService: AuthenticationClientService; + readonly connectionStatus: ApplicationConnectionStatusContribution; } export interface State { status: 'connected' | 'offline'; diff --git a/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-commands.ts b/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-commands.ts index 50b5f9008..c8935d663 100644 --- a/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-commands.ts +++ b/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-commands.ts @@ -27,17 +27,14 @@ export namespace SketchbookCommands { export const OPEN_SKETCHBOOK_CONTEXT_MENU: Command = { id: 'arduino-sketchbook--open-sketch-context-menu', - label: 'Contextual menu', iconClass: 'sketchbook-tree__opts', }; export const SKETCHBOOK_HIDE_FILES: Command = { id: 'arduino-sketchbook--hide-files', - label: 'Contextual menu', }; export const SKETCHBOOK_SHOW_FILES: Command = { id: 'arduino-sketchbook--show-files', - label: 'Contextual menu', }; } diff --git a/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-tree-widget.tsx b/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-tree-widget.tsx index ece7a1a20..5d1152e21 100644 --- a/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-tree-widget.tsx +++ b/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-tree-widget.tsx @@ -5,7 +5,7 @@ import { postConstruct, } from '@theia/core/shared/inversify'; import { TreeNode } from '@theia/core/lib/browser/tree/tree'; -import { CommandRegistry } from '@theia/core/lib/common/command'; +import { Command, CommandRegistry } from '@theia/core/lib/common/command'; import { NodeProps, TreeProps, @@ -23,7 +23,6 @@ import { SketchesServiceClientImpl, } from '../../sketches-service-client-impl'; import { SelectableTreeNode } from '@theia/core/lib/browser/tree/tree-selection'; -import { Sketch } from '../../contributions/contribution'; import { nls } from '@theia/core/lib/common'; const customTreeProps: TreeProps = { @@ -91,8 +90,8 @@ export class SketchbookTreeWidget extends FileTreeWidget { node: TreeNode, props: NodeProps ): React.ReactNode { - if (SketchbookTree.SketchDirNode.is(node) || Sketch.isSketchFile(node.id)) { - return <div className="sketch-folder-icon file-icon"></div>; + if (SketchbookTree.SketchDirNode.is(node)) { + return undefined; } const icon = this.toNodeIcon(node); if (icon) { @@ -133,26 +132,34 @@ export class SketchbookTreeWidget extends FileTreeWidget { protected renderInlineCommands(node: TreeNode): React.ReactNode { if (SketchbookTree.SketchDirNode.is(node) && node.commands) { return Array.from(new Set(node.commands)).map((command) => - this.renderInlineCommand(command.id, node) + this.renderInlineCommand(command, node) ); } return undefined; } protected renderInlineCommand( - commandId: string, + command: Command | string | [command: string, label: string], node: SketchbookTree.SketchDirNode, options?: any ): React.ReactNode { - const command = this.commandRegistry.getCommand(commandId); - const icon = command?.iconClass; + const commandId = Command.is(command) + ? command.id + : Array.isArray(command) + ? command[0] + : command; + const resolvedCommand = this.commandRegistry.getCommand(commandId); + const icon = resolvedCommand?.iconClass; const args = { model: this.model, node: node, ...options }; if ( - command && + resolvedCommand && icon && this.commandRegistry.isEnabled(commandId, args) && this.commandRegistry.isVisible(commandId, args) ) { + const label = Array.isArray(command) + ? command[1] + : resolvedCommand.label ?? resolvedCommand.id; const className = [ TREE_NODE_SEGMENT_CLASS, TREE_NODE_TAIL_CLASS, @@ -164,7 +171,7 @@ export class SketchbookTreeWidget extends FileTreeWidget { <div key={`${commandId}--${node.id}`} className={className} - title={command?.label || command.id} + title={label} onClick={(event) => { event.preventDefault(); event.stopPropagation(); diff --git a/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-tree.ts b/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-tree.ts index 6726f12b6..86391c7db 100644 --- a/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-tree.ts +++ b/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-tree.ts @@ -9,6 +9,7 @@ import { WorkspaceRootNode, } from '@theia/navigator/lib/browser/navigator-tree'; import { ArduinoPreferences } from '../../arduino-preferences'; +import { nls } from '@theia/core/lib/common/nls'; @injectable() export class SketchbookTree extends FileNavigatorTree { @@ -18,7 +19,9 @@ export class SketchbookTree extends FileNavigatorTree { @inject(ArduinoPreferences) protected readonly arduinoPreferences: ArduinoPreferences; - override async resolveChildren(parent: CompositeTreeNode): Promise<TreeNode[]> { + override async resolveChildren( + parent: CompositeTreeNode + ): Promise<TreeNode[]> { const showAllFiles = this.arduinoPreferences['arduino.sketchbook.showAllFiles']; @@ -71,7 +74,13 @@ export class SketchbookTree extends FileNavigatorTree { protected async augmentSketchNode(node: DirNode): Promise<void> { Object.assign(node, { type: 'sketch', - commands: [SketchbookCommands.OPEN_SKETCHBOOK_CONTEXT_MENU], + commands: [ + [ + 'arduino-create-cloud-copy', + nls.localize('arduino/createCloudCopy', 'Push Sketch to Cloud'), + ], + SketchbookCommands.OPEN_SKETCHBOOK_CONTEXT_MENU, + ], }); } @@ -96,7 +105,10 @@ export class SketchbookTree extends FileNavigatorTree { export namespace SketchbookTree { export interface SketchDirNode extends DirNode { readonly type: 'sketch'; - readonly commands?: Command[]; + /** + * Theia command, the command ID string, or a tuple of command ID and preferred UI label. If the array construct is used, the label is the 1<sup>st</sup> of the array. + */ + readonly commands?: (Command | string | [string, string])[]; } export namespace SketchDirNode { export function is( diff --git a/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-widget-contribution.ts b/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-widget-contribution.ts index ba3794233..511ac486f 100644 --- a/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-widget-contribution.ts +++ b/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-widget-contribution.ts @@ -106,7 +106,7 @@ export class SketchbookWidgetContribution this.revealSketchNode(treeWidgetId, nodeUri), }); registry.registerCommand(SketchbookCommands.OPEN_NEW_WINDOW, { - execute: (arg) => this.openNewWindow(arg.node), + execute: (arg) => this.openNewWindow(arg.node, arg?.treeWidgetId), isEnabled: (arg) => !!arg && 'node' in arg && SketchbookTree.SketchDirNode.is(arg.node), isVisible: (arg) => @@ -209,14 +209,20 @@ export class SketchbookWidgetContribution }); } - private openNewWindow(node: SketchbookTree.SketchDirNode): void { - const widget = this.tryGetWidget(); - if (widget) { - const treeWidgetId = widget.activeTreeWidgetId(); - if (!treeWidgetId) { + private openNewWindow( + node: SketchbookTree.SketchDirNode, + treeWidgetId?: string + ): void { + if (!treeWidgetId) { + const widget = this.tryGetWidget(); + if (!widget) { console.warn(`Could not retrieve active sketchbook tree ID.`); return; } + treeWidgetId = widget.activeTreeWidgetId(); + } + const widget = this.tryGetWidget(); + if (widget) { const nodeUri = node.uri.toString(); const options: WorkspaceInput = {}; Object.assign(options, { diff --git a/arduino-ide-extension/src/common/protocol/sketches-service.ts b/arduino-ide-extension/src/common/protocol/sketches-service.ts index 7953be720..9364639f6 100644 --- a/arduino-ide-extension/src/common/protocol/sketches-service.ts +++ b/arduino-ide-extension/src/common/protocol/sketches-service.ts @@ -74,12 +74,15 @@ export interface SketchesService { isTemp(sketch: SketchRef): Promise<boolean>; /** - * If `isTemp` is `true` for the `sketch`, you can call this method to move the sketch from the temp - * location to `directories.user`. Resolves with the URI of the sketch after the move. Rejects, when the sketch - * was not in the temp folder. This method always overrides. It's the callers responsibility to ask the user whether - * the files at the destination can be overwritten or not. + * Recursively copies the sketch folder content including all files into the destination folder. + * Resolves with the new URI of the sketch after the move. This method always overrides. It's the callers responsibility to ask the user whether + * the files at the destination can be overwritten or not. This method copies all filesystem files, if you want to copy only sketch files, + * but exclude, for example, language server log file, set the `onlySketchFiles` property to `true`. `onlySketchFiles` is `false` by default. */ - copy(sketch: Sketch, options: { destinationUri: string }): Promise<string>; + copy( + sketch: Sketch, + options: { destinationUri: string; onlySketchFiles?: boolean } + ): Promise<Sketch>; /** * Returns with the container sketch for the input `uri`. If the `uri` is not in a sketch folder, the promise resolves to `undefined`. diff --git a/arduino-ide-extension/src/common/utils.ts b/arduino-ide-extension/src/common/utils.ts index 994e02ec0..56ed366c1 100644 --- a/arduino-ide-extension/src/common/utils.ts +++ b/arduino-ide-extension/src/common/utils.ts @@ -21,8 +21,15 @@ export function isNullOrUndefined(what: unknown): what is undefined | null { return what === undefined || what === null; } +// Use it for and exhaustive `switch` statements +// https://stackoverflow.com/a/39419171/5529090 +// eslint-disable-next-line @typescript-eslint/no-unused-vars +export function assertUnreachable(_: never): never { + throw new Error(); +} + // Text encoder can crash in electron browser: https://github.com/arduino/arduino-ide/issues/634#issuecomment-1440039171 -export function unit8ArrayToString(uint8Array: Uint8Array): string { +export function uint8ArrayToString(uint8Array: Uint8Array): string { return uint8Array.reduce( (text, byte) => text + String.fromCharCode(byte), '' diff --git a/arduino-ide-extension/src/node/sketches-service-impl.ts b/arduino-ide-extension/src/node/sketches-service-impl.ts index f4ff29db2..c6fd56a8a 100644 --- a/arduino-ide-extension/src/node/sketches-service-impl.ts +++ b/arduino-ide-extension/src/node/sketches-service-impl.ts @@ -6,7 +6,6 @@ import * as path from 'path'; import * as glob from 'glob'; import * as crypto from 'crypto'; import * as PQueue from 'p-queue'; -import { ncp } from 'ncp'; import { Mutable } from '@theia/core/lib/common/types'; import URI from '@theia/core/lib/common/uri'; import { ILogger } from '@theia/core/lib/common/logger'; @@ -44,6 +43,7 @@ import { startsWithUpperCase, } from '../common/utils'; import { SettingsReader } from './settings-reader'; +import cpy = require('cpy'); const RecentSketches = 'recent-sketches.json'; const DefaultIno = `void setup() { @@ -368,63 +368,66 @@ export class SketchesServiceImpl const destinationUri = FileUri.create( path.join(parentPath, sketch.name) ).toString(); - const copiedSketchUri = await this.copy(sketch, { destinationUri }); - return this.doLoadSketch(copiedSketchUri, false); - } - - async createNewSketch(): Promise<Sketch> { - const monthNames = [ - 'jan', - 'feb', - 'mar', - 'apr', - 'may', - 'jun', - 'jul', - 'aug', - 'sep', - 'oct', - 'nov', - 'dec', - ]; - const today = new Date(); + const copiedSketch = await this.copy(sketch, { destinationUri }); + return this.doLoadSketch(copiedSketch.uri, false); + } + + async createNewSketch(name?: string, content?: string): Promise<Sketch> { + let sketchName: string | undefined = name; const parentPath = await this.createTempFolder(); - const sketchBaseName = `sketch_${ - monthNames[today.getMonth()] - }${today.getDate()}`; - const { config } = await this.configService.getConfiguration(); - const sketchbookPath = config?.sketchDirUri - ? FileUri.fsPath(config?.sketchDirUri) - : os.homedir(); - let sketchName: string | undefined; - - // If it's another day, reset the count of sketches created today - if (this.lastSketchBaseName !== sketchBaseName) this.sketchSuffixIndex = 1; - - let nameFound = false; - while (!nameFound) { - const sketchNameCandidate = `${sketchBaseName}${sketchIndexToLetters( - this.sketchSuffixIndex++ - )}`; - // Note: we check the future destination folder (`directories.user`) for name collision and not the temp folder! - const sketchExists = await exists( - path.join(sketchbookPath, sketchNameCandidate) - ); - if (!sketchExists) { - nameFound = true; - sketchName = sketchNameCandidate; + if (!sketchName) { + const monthNames = [ + 'jan', + 'feb', + 'mar', + 'apr', + 'may', + 'jun', + 'jul', + 'aug', + 'sep', + 'oct', + 'nov', + 'dec', + ]; + const today = new Date(); + const sketchBaseName = `sketch_${ + monthNames[today.getMonth()] + }${today.getDate()}`; + const { config } = await this.configService.getConfiguration(); + const sketchbookPath = config?.sketchDirUri + ? FileUri.fsPath(config?.sketchDirUri) + : os.homedir(); + + // If it's another day, reset the count of sketches created today + if (this.lastSketchBaseName !== sketchBaseName) + this.sketchSuffixIndex = 1; + + let nameFound = false; + while (!nameFound) { + const sketchNameCandidate = `${sketchBaseName}${sketchIndexToLetters( + this.sketchSuffixIndex++ + )}`; + // Note: we check the future destination folder (`directories.user`) for name collision and not the temp folder! + const sketchExists = await exists( + path.join(sketchbookPath, sketchNameCandidate) + ); + if (!sketchExists) { + nameFound = true; + sketchName = sketchNameCandidate; + } } + this.lastSketchBaseName = sketchBaseName; } if (!sketchName) { throw new Error('Cannot create a unique sketch name'); } - this.lastSketchBaseName = sketchBaseName; const sketchDir = path.join(parentPath, sketchName); const sketchFile = path.join(sketchDir, `${sketchName}.ino`); const [inoContent] = await Promise.all([ - this.loadInoContent(), + content ? content : this.loadInoContent(), fs.mkdir(sketchDir, { recursive: true }), ]); await fs.writeFile(sketchFile, inoContent, { encoding: 'utf8' }); @@ -441,7 +444,7 @@ export class SketchesServiceImpl * For example, on Windows, instead of getting an [8.3 filename](https://en.wikipedia.org/wiki/8.3_filename), callers will get a fully resolved path. * `C:\\Users\\KITTAA~1\\AppData\\Local\\Temp\\.arduinoIDE-unsaved2022615-21100-iahybb.yyvh\\sketch_jul15a` will be `C:\\Users\\kittaakos\\AppData\\Local\\Temp\\.arduinoIDE-unsaved2022615-21100-iahybb.yyvh\\sketch_jul15a` */ - private createTempFolder(): Promise<string> { + createTempFolder(): Promise<string> { return new Promise<string>((resolve, reject) => { temp.mkdir({ prefix: TempSketchPrefix }, (createError, dirPath) => { if (createError) { @@ -499,58 +502,37 @@ export class SketchesServiceImpl async copy( sketch: Sketch, - { destinationUri }: { destinationUri: string } - ): Promise<string> { - const source = FileUri.fsPath(sketch.uri); - const sketchExists = await exists(source); - if (!sketchExists) { - throw new Error(`Sketch does not exist: ${sketch}`); + { + destinationUri, + onlySketchFiles, + }: { destinationUri: string; onlySketchFiles?: boolean } + ): Promise<Sketch> { + const sourceUri = sketch.uri; + const source = FileUri.fsPath(sourceUri); + const destination = FileUri.fsPath(destinationUri); + if (source === destination) { + const reloadedSketch = await this.doLoadSketch(sourceUri, false); + return reloadedSketch; } - // Nothing to do when source and destination are the same. - if (sketch.uri === destinationUri) { - await this.doLoadSketch(sketch.uri, false); // Sanity check. - return sketch.uri; + const sourceFolderBasename = path.basename(source); + const destinationFolderBasename = path.basename(destination); + let filter: cpy.Options['filter']; + if (onlySketchFiles) { + const sketchFilePaths = Sketch.uris(sketch).map(FileUri.fsPath); + filter = (file) => sketchFilePaths.includes(file.path); + } else { + filter = () => true; } - - const copy = async (sourcePath: string, destinationPath: string) => { - return new Promise<void>((resolve, reject) => { - ncp.ncp(sourcePath, destinationPath, async (error) => { - if (error) { - reject(error); - return; - } - const newName = path.basename(destinationPath); - try { - const oldPath = path.join( - destinationPath, - new URI(sketch.mainFileUri).path.base - ); - const newPath = path.join(destinationPath, `${newName}.ino`); - if (oldPath !== newPath) { - await fs.rename(oldPath, newPath); - } - await this.doLoadSketch( - FileUri.create(destinationPath).toString(), - false - ); // Sanity check. - resolve(); - } catch (e) { - reject(e); - } - }); - }); - }; - // https://github.com/arduino/arduino-ide/issues/65 - // When copying `/path/to/sketchbook/sketch_A` to `/path/to/sketchbook/sketch_A/anything` on a non-POSIX filesystem, - // `ncp` makes a recursion and copies the folders over and over again. In such cases, we copy the source into a temp folder, - // then move it to the desired destination. - const destination = FileUri.fsPath(destinationUri); - let tempDestination = await this.createTempFolder(); - tempDestination = path.join(tempDestination, sketch.name); - await fs.mkdir(tempDestination, { recursive: true }); - await copy(source, tempDestination); - await copy(tempDestination, destination); - return FileUri.create(destination).toString(); + await cpy(source, destination, { + rename: (basename) => + sourceFolderBasename !== destinationFolderBasename && + basename === `${sourceFolderBasename}.ino` + ? `${destinationFolderBasename}.ino` + : basename, + filter, + }); + const copiedSketch = await this.doLoadSketch(destinationUri, false); + return copiedSketch; } async archive(sketch: Sketch, destinationUri: string): Promise<string> { diff --git a/arduino-ide-extension/src/test/browser/connection-status-service.test.ts b/arduino-ide-extension/src/test/browser/connection-status-service.test.ts new file mode 100644 index 000000000..1f1228ce6 --- /dev/null +++ b/arduino-ide-extension/src/test/browser/connection-status-service.test.ts @@ -0,0 +1,46 @@ +import { enableJSDOM } from '@theia/core/lib/browser/test/jsdom'; +const disableJSDOM = enableJSDOM(); + +import { FrontendApplicationConfigProvider } from '@theia/core/lib/browser/frontend-application-config-provider'; +FrontendApplicationConfigProvider.set({}); + +import { expect } from 'chai'; +import { + backendOfflineText, + backendOfflineTooltip, + daemonOfflineText, + daemonOfflineTooltip, + offlineText, + offlineTooltip, + offlineMessage, +} from '../../browser/theia/core/connection-status-service'; + +disableJSDOM(); + +describe('connection-status-service', () => { + describe('offlineMessage', () => { + it('should warn about the offline backend if connected to both CLI daemon and Internet but offline', () => { + const actual = offlineMessage({ port: '50051', online: true }); + expect(actual.text).to.be.equal(backendOfflineText); + expect(actual.tooltip).to.be.equal(backendOfflineTooltip); + }); + + it('should warn about the offline CLI daemon if the CLI daemon port is missing but has Internet connection', () => { + const actual = offlineMessage({ port: undefined, online: true }); + expect(actual.text.endsWith(daemonOfflineText)).to.be.true; + expect(actual.tooltip).to.be.equal(daemonOfflineTooltip); + }); + + it('should warn about the offline CLI daemon if the CLI daemon port is missing and has no Internet connection', () => { + const actual = offlineMessage({ port: undefined, online: false }); + expect(actual.text.endsWith(daemonOfflineText)).to.be.true; + expect(actual.tooltip).to.be.equal(daemonOfflineTooltip); + }); + + it('should warn about no Internet connection if CLI daemon port is available but the Internet connection is offline', () => { + const actual = offlineMessage({ port: '50051', online: false }); + expect(actual.text.endsWith(offlineText)).to.be.true; + expect(actual.tooltip).to.be.equal(offlineTooltip); + }); + }); +}); diff --git a/arduino-ide-extension/src/test/node/boards-service-impl.slow-test.ts b/arduino-ide-extension/src/test/node/boards-service-impl.slow-test.ts index dd9ec71ae..fe89cc4b2 100644 --- a/arduino-ide-extension/src/test/node/boards-service-impl.slow-test.ts +++ b/arduino-ide-extension/src/test/node/boards-service-impl.slow-test.ts @@ -1,4 +1,4 @@ -import { Disposable } from '@theia/core/lib/common/disposable'; +import { DisposableCollection } from '@theia/core/lib/common/disposable'; import { Container } from '@theia/core/shared/inversify'; import { expect } from 'chai'; import { BoardSearch, BoardsService } from '../../common/protocol'; @@ -10,26 +10,18 @@ import { describe('boards-service-impl', () => { let boardService: BoardsService; - let toDispose: Disposable[] = []; + let toDispose: DisposableCollection; before(async function () { configureBackendApplicationConfigProvider(); this.timeout(20_000); - toDispose = []; + toDispose = new DisposableCollection(); const container = createContainer(); await start(container, toDispose); boardService = container.get<BoardsService>(BoardsService); }); - after(() => { - let disposable = toDispose.pop(); - while (disposable) { - try { - disposable?.dispose(); - } catch {} - disposable = toDispose.pop(); - } - }); + after(() => toDispose.dispose()); describe('search', () => { it('should run search', async function () { @@ -37,7 +29,7 @@ describe('boards-service-impl', () => { expect(result).is.not.empty; }); - it("should boost a result when 'types' includes 'arduino', and lower the score if deprecated", async function () { + it("should boost a result when 'types' includes 'arduino', and lower the score if deprecated", async () => { const result = await boardService.search({}); const arduinoIndexes: number[] = []; const otherIndexes: number[] = []; @@ -108,7 +100,7 @@ function createContainer(): Container { async function start( container: Container, - toDispose: Disposable[] + toDispose: DisposableCollection ): Promise<void> { return startDaemon(container, toDispose); } diff --git a/arduino-ide-extension/src/test/node/core-service-impl.slow-test.ts b/arduino-ide-extension/src/test/node/core-service-impl.slow-test.ts index fa73f6549..700673c32 100644 --- a/arduino-ide-extension/src/test/node/core-service-impl.slow-test.ts +++ b/arduino-ide-extension/src/test/node/core-service-impl.slow-test.ts @@ -1,6 +1,6 @@ import { CancellationTokenSource } from '@theia/core/lib/common/cancellation'; import { CommandRegistry } from '@theia/core/lib/common/command'; -import { Disposable } from '@theia/core/lib/common/disposable'; +import { DisposableCollection } from '@theia/core/lib/common/disposable'; import { isWindows } from '@theia/core/lib/common/os'; import { FileUri } from '@theia/core/lib/node/file-uri'; import { Container, injectable } from '@theia/core/shared/inversify'; @@ -23,7 +23,7 @@ const uno = 'arduino:avr:uno'; describe('core-service-impl', () => { let container: Container; - let toDispose: Disposable[]; + let toDispose: DisposableCollection; before(() => { configureBackendApplicationConfigProvider(); @@ -31,20 +31,12 @@ describe('core-service-impl', () => { beforeEach(async function () { this.timeout(setupTimeout); - toDispose = []; + toDispose = new DisposableCollection(); container = createContainer(); await start(container, toDispose); }); - afterEach(() => { - let disposable = toDispose.pop(); - while (disposable) { - try { - disposable?.dispose(); - } catch {} - disposable = toDispose.pop(); - } - }); + afterEach(() => toDispose.dispose()); describe('compile', () => { it('should execute a command with the build path', async function () { @@ -92,7 +84,7 @@ describe('core-service-impl', () => { async function start( container: Container, - toDispose: Disposable[] + toDispose: DisposableCollection ): Promise<void> { await startDaemon(container, toDispose, async (container) => { const boardService = container.get<BoardsService>(BoardsService); diff --git a/arduino-ide-extension/src/test/node/library-service-impl.slow-test.ts b/arduino-ide-extension/src/test/node/library-service-impl.slow-test.ts index cd0f85737..95613395e 100644 --- a/arduino-ide-extension/src/test/node/library-service-impl.slow-test.ts +++ b/arduino-ide-extension/src/test/node/library-service-impl.slow-test.ts @@ -1,4 +1,4 @@ -import { Disposable } from '@theia/core/lib/common/disposable'; +import { DisposableCollection } from '@theia/core/lib/common/disposable'; import { Container } from '@theia/core/shared/inversify'; import { expect } from 'chai'; import { LibrarySearch, LibraryService } from '../../common/protocol'; @@ -11,26 +11,18 @@ import { describe('library-service-impl', () => { let libraryService: LibraryService; - let toDispose: Disposable[] = []; + let toDispose: DisposableCollection; before(async function () { configureBackendApplicationConfigProvider(); this.timeout(20_000); - toDispose = []; + toDispose = new DisposableCollection(); const container = createContainer(); await start(container, toDispose); libraryService = container.get<LibraryService>(LibraryService); }); - after(() => { - let disposable = toDispose.pop(); - while (disposable) { - try { - disposable?.dispose(); - } catch {} - disposable = toDispose.pop(); - } - }); + after(() => toDispose.dispose()); describe('search', () => { it('should run search', async function () { @@ -89,7 +81,7 @@ function createContainer(): Container { async function start( container: Container, - toDispose: Disposable[] + toDispose: DisposableCollection ): Promise<void> { return startDaemon(container, toDispose); } diff --git a/arduino-ide-extension/src/test/node/sketches-service-impl.slow-test.ts b/arduino-ide-extension/src/test/node/sketches-service-impl.slow-test.ts new file mode 100644 index 000000000..7669971b1 --- /dev/null +++ b/arduino-ide-extension/src/test/node/sketches-service-impl.slow-test.ts @@ -0,0 +1,262 @@ +import { + Disposable, + DisposableCollection, +} from '@theia/core/lib/common/disposable'; +import { FileUri } from '@theia/core/lib/node/file-uri'; +import { Container } from '@theia/core/shared/inversify'; +import { expect } from 'chai'; +import { promises as fs } from 'fs'; +import { basename, join } from 'path'; +import { sync as rimrafSync } from 'rimraf'; +import { Sketch, SketchesService } from '../../common/protocol'; +import { SketchesServiceImpl } from '../../node/sketches-service-impl'; +import { ErrnoException } from '../../node/utils/errors'; +import { + configureBackendApplicationConfigProvider, + createBaseContainer, + startDaemon, +} from './test-bindings'; + +const testTimeout = 10_000; + +describe('sketches-service-impl', () => { + let container: Container; + let toDispose: DisposableCollection; + + before(async () => { + configureBackendApplicationConfigProvider(); + toDispose = new DisposableCollection(); + container = createContainer(); + await start(container, toDispose); + }); + + after(() => toDispose.dispose()); + + describe('copy', () => { + it('should copy a sketch when the destination does not exist', async function () { + this.timeout(testTimeout); + const sketchesService = + container.get<SketchesServiceImpl>(SketchesService); + const destinationPath = await sketchesService['createTempFolder'](); + let sketch = await sketchesService.createNewSketch(); + toDispose.push(disposeSketch(sketch)); + const sourcePath = FileUri.fsPath(sketch.uri); + const libBasename = 'lib.cpp'; + const libContent = 'lib content'; + const libPath = join(sourcePath, libBasename); + await fs.writeFile(libPath, libContent, { encoding: 'utf8' }); + const headerBasename = 'header.h'; + const headerContent = 'header content'; + const headerPath = join(sourcePath, headerBasename); + await fs.writeFile(headerPath, headerContent, { encoding: 'utf8' }); + + sketch = await sketchesService.loadSketch(sketch.uri); + expect(Sketch.isInSketch(FileUri.create(libPath), sketch)).to.be.true; + expect(Sketch.isInSketch(FileUri.create(headerPath), sketch)).to.be.true; + + const copied = await sketchesService.copy(sketch, { + destinationUri: FileUri.create(destinationPath).toString(), + }); + toDispose.push(disposeSketch(copied)); + expect(copied.name).to.be.equal(basename(destinationPath)); + expect( + Sketch.isInSketch( + FileUri.create( + join(destinationPath, `${basename(destinationPath)}.ino`) + ), + copied + ) + ).to.be.true; + expect( + Sketch.isInSketch( + FileUri.create(join(destinationPath, libBasename)), + copied + ) + ).to.be.true; + expect( + Sketch.isInSketch( + FileUri.create(join(destinationPath, headerBasename)), + copied + ) + ).to.be.true; + }); + + it("should copy only sketch files if 'onlySketchFiles' is true", async function () { + this.timeout(testTimeout); + const sketchesService = + container.get<SketchesServiceImpl>(SketchesService); + const destinationPath = await sketchesService['createTempFolder'](); + let sketch = await sketchesService.createNewSketch(); + toDispose.push(disposeSketch(sketch)); + const sourcePath = FileUri.fsPath(sketch.uri); + const libBasename = 'lib.cpp'; + const libContent = 'lib content'; + const libPath = join(sourcePath, libBasename); + await fs.writeFile(libPath, libContent, { encoding: 'utf8' }); + const headerBasename = 'header.h'; + const headerContent = 'header content'; + const headerPath = join(sourcePath, headerBasename); + await fs.writeFile(headerPath, headerContent, { encoding: 'utf8' }); + const logBasename = 'inols-clangd-err.log'; + const logContent = 'log file content'; + const logPath = join(sourcePath, logBasename); + await fs.writeFile(logPath, logContent, { encoding: 'utf8' }); + + sketch = await sketchesService.loadSketch(sketch.uri); + expect(Sketch.isInSketch(FileUri.create(libPath), sketch)).to.be.true; + expect(Sketch.isInSketch(FileUri.create(headerPath), sketch)).to.be.true; + expect(Sketch.isInSketch(FileUri.create(logPath), sketch)).to.be.false; + const reloadedLogContent = await fs.readFile(logPath, { + encoding: 'utf8', + }); + expect(reloadedLogContent).to.be.equal(logContent); + + const copied = await sketchesService.copy(sketch, { + destinationUri: FileUri.create(destinationPath).toString(), + onlySketchFiles: true, + }); + toDispose.push(disposeSketch(copied)); + expect(copied.name).to.be.equal(basename(destinationPath)); + expect( + Sketch.isInSketch( + FileUri.create( + join(destinationPath, `${basename(destinationPath)}.ino`) + ), + copied + ) + ).to.be.true; + expect( + Sketch.isInSketch( + FileUri.create(join(destinationPath, libBasename)), + copied + ) + ).to.be.true; + expect( + Sketch.isInSketch( + FileUri.create(join(destinationPath, headerBasename)), + copied + ) + ).to.be.true; + expect( + Sketch.isInSketch( + FileUri.create(join(destinationPath, logBasename)), + copied + ) + ).to.be.false; + try { + await fs.readFile(join(destinationPath, logBasename), { + encoding: 'utf8', + }); + expect.fail( + 'Log file must not exist in the destination. Expected ENOENT when loading the log file.' + ); + } catch (err) { + expect(ErrnoException.isENOENT(err)).to.be.true; + } + }); + + it('should copy sketch inside the sketch folder', async function () { + this.timeout(testTimeout); + const sketchesService = + container.get<SketchesServiceImpl>(SketchesService); + let sketch = await sketchesService.createNewSketch(); + const destinationPath = join(FileUri.fsPath(sketch.uri), 'nested_copy'); + toDispose.push(disposeSketch(sketch)); + const sourcePath = FileUri.fsPath(sketch.uri); + const libBasename = 'lib.cpp'; + const libContent = 'lib content'; + const libPath = join(sourcePath, libBasename); + await fs.writeFile(libPath, libContent, { encoding: 'utf8' }); + const headerBasename = 'header.h'; + const headerContent = 'header content'; + const headerPath = join(sourcePath, headerBasename); + await fs.writeFile(headerPath, headerContent, { encoding: 'utf8' }); + + sketch = await sketchesService.loadSketch(sketch.uri); + expect(Sketch.isInSketch(FileUri.create(libPath), sketch)).to.be.true; + expect(Sketch.isInSketch(FileUri.create(headerPath), sketch)).to.be.true; + + const copied = await sketchesService.copy(sketch, { + destinationUri: FileUri.create(destinationPath).toString(), + }); + toDispose.push(disposeSketch(copied)); + expect(copied.name).to.be.equal(basename(destinationPath)); + expect( + Sketch.isInSketch( + FileUri.create( + join(destinationPath, `${basename(destinationPath)}.ino`) + ), + copied + ) + ).to.be.true; + expect( + Sketch.isInSketch( + FileUri.create(join(destinationPath, libBasename)), + copied + ) + ).to.be.true; + expect( + Sketch.isInSketch( + FileUri.create(join(destinationPath, headerBasename)), + copied + ) + ).to.be.true; + }); + + it('should copy sketch with overwrite when source and destination sketch folder names are the same', async function () { + this.timeout(testTimeout); + const sketchesService = + container.get<SketchesServiceImpl>(SketchesService); + const sketchFolderName = 'alma'; + const contentOne = 'korte'; + const contentTwo = 'szilva'; + const [sketchOne, sketchTwo] = await Promise.all([ + sketchesService.createNewSketch(sketchFolderName, contentOne), + sketchesService.createNewSketch(sketchFolderName, contentTwo), + ]); + toDispose.push(disposeSketch(sketchOne, sketchTwo)); + const [mainFileContentOne, mainFileContentTwo] = await Promise.all([ + mainFileContentOf(sketchOne), + mainFileContentOf(sketchTwo), + ]); + expect(mainFileContentOne).to.be.equal(contentOne); + expect(mainFileContentTwo).to.be.equal(contentTwo); + + await sketchesService.copy(sketchOne, { destinationUri: sketchTwo.uri }); + const [mainFileContentOneAfterCopy, mainFileContentTwoAfterCopy] = + await Promise.all([ + mainFileContentOf(sketchOne), + mainFileContentOf(sketchTwo), + ]); + expect(mainFileContentOneAfterCopy).to.be.equal(contentOne); + expect(mainFileContentTwoAfterCopy).to.be.equal(contentOne); + }); + }); +}); + +function disposeSketch(...sketch: Sketch[]): Disposable { + return new DisposableCollection( + ...sketch + .map(({ uri }) => FileUri.fsPath(uri)) + .map((path) => + Disposable.create(() => rimrafSync(path, { maxBusyTries: 5 })) + ) + ); +} + +async function mainFileContentOf(sketch: Sketch): Promise<string> { + return fs.readFile(FileUri.fsPath(sketch.mainFileUri), { + encoding: 'utf8', + }); +} + +async function start( + container: Container, + toDispose: DisposableCollection +): Promise<void> { + await startDaemon(container, toDispose); +} + +function createContainer(): Container { + return createBaseContainer(); +} diff --git a/arduino-ide-extension/src/test/node/test-bindings.ts b/arduino-ide-extension/src/test/node/test-bindings.ts index 19b99f3a3..80a3eea7c 100644 --- a/arduino-ide-extension/src/test/node/test-bindings.ts +++ b/arduino-ide-extension/src/test/node/test-bindings.ts @@ -4,7 +4,10 @@ import { CommandService, } from '@theia/core/lib/common/command'; import { bindContributionProvider } from '@theia/core/lib/common/contribution-provider'; -import { Disposable } from '@theia/core/lib/common/disposable'; +import { + Disposable, + DisposableCollection, +} from '@theia/core/lib/common/disposable'; import { EnvVariablesServer as TheiaEnvVariablesServer } from '@theia/core/lib/common/env-variables'; import { ILogger, Loggable } from '@theia/core/lib/common/logger'; import { LogLevel } from '@theia/core/lib/common/logger-protocol'; @@ -289,18 +292,23 @@ export function createBaseContainer( export async function startDaemon( container: Container, - toDispose: Disposable[], + toDispose: DisposableCollection, startCustomizations?: ( container: Container, - toDispose: Disposable[] + toDispose: DisposableCollection ) => Promise<void> ): Promise<void> { const daemon = container.get<ArduinoDaemonImpl>(ArduinoDaemonImpl); const configService = container.get<ConfigServiceImpl>(ConfigServiceImpl); + const coreClientProvider = + container.get<CoreClientProvider>(CoreClientProvider); toDispose.push(Disposable.create(() => daemon.stop())); configService.onStart(); daemon.onStart(); - await waitForEvent(daemon.onDaemonStarted, 10_000); + await Promise.all([ + waitForEvent(daemon.onDaemonStarted, 10_000), + coreClientProvider.client, + ]); if (startCustomizations) { await startCustomizations(container, toDispose); } diff --git a/i18n/en.json b/i18n/en.json index b6e67e855..22419c5bf 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -93,8 +93,8 @@ "cloudSketchbook": "Cloud Sketchbook", "connected": "Connected", "continue": "Continue", - "donePulling": "Done pulling ‘{0}’.", - "donePushing": "Done pushing ‘{0}’.", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "Embed:", "emptySketchbook": "Your Sketchbook is empty", "goToCloud": "Go to Cloud", @@ -179,6 +179,9 @@ "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "Add File", "fileAdded": "One file added to the sketch.", @@ -199,6 +202,7 @@ "copyError": "Copy error messages", "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Restart Daemon", "start": "Start Daemon", @@ -462,6 +466,9 @@ "dismissSurvey": "Don't show again", "surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better." }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Update Indexes", "updateLibraryIndex": "Update Library Index", @@ -494,6 +501,7 @@ "couldNotSave": "Could not save the sketch. Please copy your unsaved work into your favorite text editor, and restart the IDE.", "daemonOffline": "CLI Daemon Offline", "offline": "Offline", + "offlineText": "Offline", "quitTitle": "Are you sure you want to quit?" }, "editor": { diff --git a/yarn.lock b/yarn.lock index 3ed199799..44833b671 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1184,6 +1184,11 @@ "@jridgewell/resolve-uri" "^3.0.3" "@jridgewell/sourcemap-codec" "^1.4.10" +"@leichtgewicht/ip-codec@^2.0.1": + version "2.0.4" + resolved "https://registry.yarnpkg.com/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz#b2ac626d6cb9c8718ab459166d4bb405b8ffa78b" + integrity sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A== + "@lerna/add@6.1.0": version "6.1.0" resolved "https://registry.yarnpkg.com/@lerna/add/-/add-6.1.0.tgz#0f09495c5e1af4c4f316344af34b6d1a91b15b19" @@ -1890,6 +1895,14 @@ semver "^7.3.5" tar "^6.1.11" +"@mrmlnc/readdir-enhanced@^2.2.1": + version "2.2.1" + resolved "https://registry.yarnpkg.com/@mrmlnc/readdir-enhanced/-/readdir-enhanced-2.2.1.tgz#524af240d1a360527b730475ecfa1344aa540dde" + integrity sha512-bPHp6Ji8b41szTOcaP63VlnbbO5Ny6dwAATtY6JTjh5N2OLrb5Qk/Th5cRkRQhkWCt+EJsYrNB0MiL+Gpn6e3g== + dependencies: + call-me-maybe "^1.0.1" + glob-to-regexp "^0.3.0" + "@msgpackr-extract/msgpackr-extract-darwin-arm64@2.1.2": version "2.1.2" resolved "https://registry.yarnpkg.com/@msgpackr-extract/msgpackr-extract-darwin-arm64/-/msgpackr-extract-darwin-arm64-2.1.2.tgz#9571b87be3a3f2c46de05585470bc4f3af2f6f00" @@ -1933,6 +1946,11 @@ resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz#5bd262af94e9d25bd1e71b05deed44876a222e8b" integrity sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A== +"@nodelib/fs.stat@^1.1.2": + version "1.1.3" + resolved "https://registry.yarnpkg.com/@nodelib/fs.stat/-/fs.stat-1.1.3.tgz#2b5a3ab3f918cca48a8c754c08168e3f03eba61b" + integrity sha512-shAmDyaQC4H92APFoIaVDHCx5bStIocgvbwQyxPRrbUY20V1EYTbSDchWbuwlMG3V17cprZhA6+78JfB+3DTPw== + "@nodelib/fs.walk@^1.2.3": version "1.2.8" resolved "https://registry.yarnpkg.com/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz#e95737e8bb6746ddedf69c556953494f196fe69a" @@ -3294,7 +3312,7 @@ dependencies: "@types/node" "*" -"@types/glob@*", "@types/glob@^7.2.0": +"@types/glob@*", "@types/glob@^7.1.1", "@types/glob@^7.2.0": version "7.2.0" resolved "https://registry.yarnpkg.com/@types/glob/-/glob-7.2.0.tgz#bc1b5bf3aa92f25bd5dd39f35c57361bdce5b2eb" integrity sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA== @@ -3461,13 +3479,6 @@ dependencies: "@types/express" "*" -"@types/ncp@^2.0.4": - version "2.0.5" - resolved "https://registry.yarnpkg.com/@types/ncp/-/ncp-2.0.5.tgz#5c53b229a321946102a188b603306162137f4fb9" - integrity sha512-ocK0p8JuFmX7UkMabFPjY0F7apPvQyLWt5qtdvuvQEBz9i4m2dbzV+6L1zNaUp042RfnL6pHnxDE53OH6XQ9VQ== - dependencies: - "@types/node" "*" - "@types/node-fetch@^2.5.7": version "2.6.2" resolved "https://registry.yarnpkg.com/@types/node-fetch/-/node-fetch-2.6.2.tgz#d1a9c5fd049d9415dce61571557104dec3ec81da" @@ -4531,7 +4542,7 @@ array-sort@^0.1.4: get-value "^2.0.6" kind-of "^5.0.2" -array-union@^1.0.1: +array-union@^1.0.1, array-union@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/array-union/-/array-union-1.0.2.tgz#9a34410e4f4e3da23dea375be5be70f24778ec39" integrity sha512-Dxr6QJj/RdU/hCaBjOfxW+q6lyuVE6JFWIrAUpuOOhoJJoQ99cUn3igRaHVB5P9WrgFVN0FfArM3x0cueOU8ng== @@ -5187,6 +5198,11 @@ call-bind@^1.0.0, call-bind@^1.0.2: function-bind "^1.1.1" get-intrinsic "^1.0.2" +call-me-maybe@^1.0.1: + version "1.0.2" + resolved "https://registry.yarnpkg.com/call-me-maybe/-/call-me-maybe-1.0.2.tgz#03f964f19522ba643b1b0693acb9152fe2074baa" + integrity sha512-HpX65o1Hnr9HH25ojC1YGs7HCQLq0GCOibSaWER0eNpgJ/Z1MZv2mTc7+xh6WOPxbRVcmgbv4hGU+uSQ/2xFZQ== + callsites@^3.0.0: version "3.1.0" resolved "https://registry.yarnpkg.com/callsites/-/callsites-3.1.0.tgz#b3630abd8943432f54b3f0519238e33cd7df2f73" @@ -5943,6 +5959,31 @@ cp-file@^6.1.0: pify "^4.0.1" safe-buffer "^5.0.1" +cp-file@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/cp-file/-/cp-file-7.0.0.tgz#b9454cfd07fe3b974ab9ea0e5f29655791a9b8cd" + integrity sha512-0Cbj7gyvFVApzpK/uhCtQ/9kE9UnYpxMzaq5nQQC/Dh4iaj5fxp7iEFIullrYwzj8nf0qnsI1Qsx34hAeAebvw== + dependencies: + graceful-fs "^4.1.2" + make-dir "^3.0.0" + nested-error-stacks "^2.0.0" + p-event "^4.1.0" + +cpy@^8.1.2: + version "8.1.2" + resolved "https://registry.yarnpkg.com/cpy/-/cpy-8.1.2.tgz#e339ea54797ad23f8e3919a5cffd37bfc3f25935" + integrity sha512-dmC4mUesv0OYH2kNFEidtf/skUwv4zePmGeepjyyJ0qTo5+8KhA1o99oIAwVVLzQMAeDJml74d6wPPKb6EZUTg== + dependencies: + arrify "^2.0.1" + cp-file "^7.0.0" + globby "^9.2.0" + has-glob "^1.0.0" + junk "^3.1.0" + nested-error-stacks "^2.1.0" + p-all "^2.1.0" + p-filter "^2.1.0" + p-map "^3.0.0" + create-frame@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/create-frame/-/create-frame-1.0.0.tgz#8b95f2691e3249b6080443e33d0bad9f8f6975aa" @@ -6402,7 +6443,7 @@ diff@^5.0.0: resolved "https://registry.yarnpkg.com/diff/-/diff-5.1.0.tgz#bc52d298c5ea8df9194800224445ed43ffc87e40" integrity sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw== -dir-glob@^2.0.0: +dir-glob@^2.0.0, dir-glob@^2.2.2: version "2.2.2" resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-2.2.2.tgz#fa09f0694153c8918b18ba0deafae94769fc50c4" integrity sha512-f9LBi5QWzIW3I6e//uxZoLBlUt9kcp66qo0sSCxL6YZKc75R1c4MFCoe/LaZiBGmgujvQdxc5Bn3QhfyvK5Hsw== @@ -6416,6 +6457,20 @@ dir-glob@^3.0.1: dependencies: path-type "^4.0.0" +dns-packet@^5.2.4: + version "5.4.0" + resolved "https://registry.yarnpkg.com/dns-packet/-/dns-packet-5.4.0.tgz#1f88477cf9f27e78a213fb6d118ae38e759a879b" + integrity sha512-EgqGeaBB8hLiHLZtp/IbaDQTL8pZ0+IvwzSHA6d7VyMDM+B9hgddEMa9xjK5oYnw0ci0JQ6g2XCD7/f6cafU6g== + dependencies: + "@leichtgewicht/ip-codec" "^2.0.1" + +dns-socket@^4.2.2: + version "4.2.2" + resolved "https://registry.yarnpkg.com/dns-socket/-/dns-socket-4.2.2.tgz#58b0186ec053ea0731feb06783c7eeac4b95b616" + integrity sha512-BDeBd8najI4/lS00HSKpdFia+OvUMytaVjfzR9n5Lq8MlZRSvtbI+uLtx1+XmQFls5wFU9dssccTmQQ6nfpjdg== + dependencies: + dns-packet "^5.2.4" + doctrine@^2.1.0: version "2.1.0" resolved "https://registry.yarnpkg.com/doctrine/-/doctrine-2.1.0.tgz#5cd01fc101621b42c4cd7f5d1a66243716d3f39d" @@ -7236,6 +7291,18 @@ fast-glob@3.2.7: merge2 "^1.3.0" micromatch "^4.0.4" +fast-glob@^2.2.6: + version "2.2.7" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.7.tgz#6953857c3afa475fff92ee6015d52da70a4cd39d" + integrity sha512-g1KuQwHOZAmOZMuBtHdxDtju+T2RT8jgCC9aANsbpdiDDTSnjgfuVsIBNKbUeJI3oKMRExcfNDtJl4OhbffMsw== + dependencies: + "@mrmlnc/readdir-enhanced" "^2.2.1" + "@nodelib/fs.stat" "^1.1.2" + glob-parent "^3.1.0" + is-glob "^4.0.0" + merge2 "^1.2.3" + micromatch "^3.1.10" + fast-glob@^3.2.5, fast-glob@^3.2.9: version "3.2.11" resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.2.11.tgz#a1172ad95ceb8a16e20caa5c5e56480e5129c1d9" @@ -7925,6 +7992,14 @@ github-from-package@0.0.0: resolved "https://registry.yarnpkg.com/github-from-package/-/github-from-package-0.0.0.tgz#97fb5d96bfde8973313f20e8288ef9a167fa64ce" integrity sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw== +glob-parent@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-3.1.0.tgz#9e6af6299d8d3bd2bd40430832bd113df906c5ae" + integrity sha512-E8Ak/2+dZY6fnzlR7+ueWvhsH1SjHr4jjss4YS/h4py44jY9MhK/VFdaZJAWDz6BbL21KeteKxFSFpq8OS5gVA== + dependencies: + is-glob "^3.1.0" + path-dirname "^1.0.0" + glob-parent@^5.1.1, glob-parent@^5.1.2, glob-parent@~5.1.0, glob-parent@~5.1.2: version "5.1.2" resolved "https://registry.yarnpkg.com/glob-parent/-/glob-parent-5.1.2.tgz#869832c58034fe68a4093c17dc15e8340d8401c4" @@ -7932,6 +8007,11 @@ glob-parent@^5.1.1, glob-parent@^5.1.2, glob-parent@~5.1.0, glob-parent@~5.1.2: dependencies: is-glob "^4.0.1" +glob-to-regexp@^0.3.0: + version "0.3.0" + resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.3.0.tgz#8c5a1494d2066c570cc3bfe4496175acc4d502ab" + integrity sha512-Iozmtbqv0noj0uDDqoL0zNq0VBEfK2YFoMAZoxJe4cwphvLR+JskfF30QhXHOR4m3KrE6NLRYw+U9MRXvifyig== + glob-to-regexp@^0.4.1: version "0.4.1" resolved "https://registry.yarnpkg.com/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz#c75297087c851b9a578bd217dd59a92f59fe546e" @@ -8049,6 +8129,20 @@ globby@^7.1.1: pify "^3.0.0" slash "^1.0.0" +globby@^9.2.0: + version "9.2.0" + resolved "https://registry.yarnpkg.com/globby/-/globby-9.2.0.tgz#fd029a706c703d29bdd170f4b6db3a3f7a7cb63d" + integrity sha512-ollPHROa5mcxDEkwg6bPt3QbEf4pDQSNtd6JPL1YvOvAo/7/0VAm9TccUeoTmarjPw4pfUthSCqcyfNB1I3ZSg== + dependencies: + "@types/glob" "^7.1.1" + array-union "^1.0.2" + dir-glob "^2.2.2" + fast-glob "^2.2.6" + glob "^7.1.3" + ignore "^4.0.3" + pify "^4.0.1" + slash "^2.0.0" + google-protobuf@3.12.4: version "3.12.4" resolved "https://registry.yarnpkg.com/google-protobuf/-/google-protobuf-3.12.4.tgz#fd89b7e5052cdb35a80f9b455612851d542a5c9f" @@ -8076,6 +8170,23 @@ got@^11.7.0, got@^11.8.5: p-cancelable "^2.0.0" responselike "^2.0.0" +got@^11.8.0: + version "11.8.6" + resolved "https://registry.yarnpkg.com/got/-/got-11.8.6.tgz#276e827ead8772eddbcfc97170590b841823233a" + integrity sha512-6tfZ91bOr7bOXnK7PRDCGBLa1H4U080YHNaAQ2KsMGlLEzRbk44nsZF2E1IeRc3vtJHPVbKCYgdFbaGO2ljd8g== + dependencies: + "@sindresorhus/is" "^4.0.0" + "@szmarczak/http-timer" "^4.0.5" + "@types/cacheable-request" "^6.0.1" + "@types/responselike" "^1.0.0" + cacheable-lookup "^5.0.3" + cacheable-request "^7.0.2" + decompress-response "^6.0.0" + http2-wrapper "^1.0.0-beta.5.2" + lowercase-keys "^2.0.0" + p-cancelable "^2.0.0" + responselike "^2.0.0" + got@^8.3.1: version "8.3.2" resolved "https://registry.yarnpkg.com/got/-/got-8.3.2.tgz#1d23f64390e97f776cac52e5b936e5f514d2e937" @@ -8257,6 +8368,13 @@ has-flag@^4.0.0: resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-4.0.0.tgz#944771fd9c81c81265c4d6941860da06bb59479b" integrity sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ== +has-glob@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/has-glob/-/has-glob-1.0.0.tgz#9aaa9eedbffb1ba3990a7b0010fb678ee0081207" + integrity sha512-D+8A457fBShSEI3tFCj65PAbT++5sKiFtdCdOam0gnfBgw9D277OERk+HM9qYJXmdVLZ/znez10SqHN0BBQ50g== + dependencies: + is-glob "^3.0.0" + has-property-descriptors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/has-property-descriptors/-/has-property-descriptors-1.0.0.tgz#610708600606d36961ed04c196193b6a607fa861" @@ -8595,7 +8713,7 @@ ignore@^3.3.5: resolved "https://registry.yarnpkg.com/ignore/-/ignore-3.3.10.tgz#0a97fb876986e8081c631160f8f9f389157f0043" integrity sha512-Pgs951kaMm5GXP7MOvxERINe3gsaVjUWFm+UZPSq9xYriQAksyhg0csnS0KXSNRD5NmNdapXEpjxG49+AKh/ug== -ignore@^4.0.6: +ignore@^4.0.3, ignore@^4.0.6: version "4.0.6" resolved "https://registry.yarnpkg.com/ignore/-/ignore-4.0.6.tgz#750e3db5862087b4737ebac8207ffd1ef27b25fc" integrity sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg== @@ -8745,6 +8863,11 @@ invert-kv@^2.0.0: resolved "https://registry.yarnpkg.com/invert-kv/-/invert-kv-2.0.0.tgz#7393f5afa59ec9ff5f67a27620d11c226e3eec02" integrity sha512-wPVv/y/QQ/Uiirj/vh3oP+1Ww+AWehmi1g5fFWGPF6IpCBCDVrhgHRMvrLfdYcwDh3QJbGXDW4JAuzxElLSqKA== +ip-regex@^4.0.0: + version "4.3.0" + resolved "https://registry.yarnpkg.com/ip-regex/-/ip-regex-4.3.0.tgz#687275ab0f57fa76978ff8f4dddc8a23d5990db5" + integrity sha512-B9ZWJxHHOHUhUjCPrMpLD4xEq35bUTClHM1S6CBU5ixQnkZmwipwgc96vAd7AAGM9TGHvJR+Uss+/Ak6UphK+Q== + ip@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/ip/-/ip-2.0.0.tgz#4cf4ab182fee2314c75ede1276f8c80b479936da" @@ -8900,7 +9023,7 @@ is-extendable@^1.0.1: dependencies: is-plain-object "^2.0.4" -is-extglob@^2.1.1: +is-extglob@^2.1.0, is-extglob@^2.1.1: version "2.1.1" resolved "https://registry.yarnpkg.com/is-extglob/-/is-extglob-2.1.1.tgz#a88c02535791f02ed37c76a1b9ea9773c833f8c2" integrity sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ== @@ -8922,6 +9045,13 @@ is-fullwidth-code-point@^3.0.0: resolved "https://registry.yarnpkg.com/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz#f116f8064fe90b3f7844a38997c0b75051269f1d" integrity sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg== +is-glob@^3.0.0, is-glob@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-3.1.0.tgz#7ba5ae24217804ac70707b96922567486cc3e84a" + integrity sha512-UFpDDrPgM6qpnFNI+rh/p3bUaq9hKLZN8bMUWzxmcnZVS3omf4IPK+BrewlnWjO1WmUsMYuSjKh4UJuV4+Lqmw== + dependencies: + is-extglob "^2.1.0" + is-glob@^4.0.0, is-glob@^4.0.1, is-glob@~4.0.1: version "4.0.3" resolved "https://registry.yarnpkg.com/is-glob/-/is-glob-4.0.3.tgz#64f61e42cbbb2eec2071a9dac0b28ba1e65d5084" @@ -8934,6 +9064,13 @@ is-interactive@^1.0.0: resolved "https://registry.yarnpkg.com/is-interactive/-/is-interactive-1.0.0.tgz#cea6e6ae5c870a7b0a0004070b7b587e0252912e" integrity sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w== +is-ip@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/is-ip/-/is-ip-3.1.0.tgz#2ae5ddfafaf05cb8008a62093cf29734f657c5d8" + integrity sha512-35vd5necO7IitFPjd/YBeqwWnyDWbuLH9ZXQdMfDA8TEo7pv5X8yfrvVO3xbJbLUlERCMvf6X0hTUamQxCYJ9Q== + dependencies: + ip-regex "^4.0.0" + is-lambda@^1.0.1: version "1.0.1" resolved "https://registry.yarnpkg.com/is-lambda/-/is-lambda-1.0.1.tgz#3d9877899e6a53efc0160504cde15f82e6f061d5" @@ -9002,6 +9139,16 @@ is-odd@^0.1.2: dependencies: is-number "^3.0.0" +is-online@^9.0.1: + version "9.0.1" + resolved "https://registry.yarnpkg.com/is-online/-/is-online-9.0.1.tgz#71a34202fa826bae6f3ff8bea420c56573448a5f" + integrity sha512-+08dRW0dcFOtleR2N3rHRVxDyZtQitUp9cC+KpKTds0mXibbQyW5js7xX0UGyQXkaLUJObe0w6uQ4ex34lX9LA== + dependencies: + got "^11.8.0" + p-any "^3.0.0" + p-timeout "^3.2.0" + public-ip "^4.0.4" + is-path-inside@^3.0.2: version "3.0.3" resolved "https://registry.yarnpkg.com/is-path-inside/-/is-path-inside-3.0.3.tgz#d231362e53a07ff2b0e0ea7fed049161ffd16283" @@ -9418,6 +9565,11 @@ jsprim@^1.2.2: array-includes "^3.1.5" object.assign "^4.1.2" +junk@^3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/junk/-/junk-3.1.0.tgz#31499098d902b7e98c5d9b9c80f43457a88abfa1" + integrity sha512-pBxcB3LFc8QVgdggvZWyeys+hnrNWg4OcZIU/1X59k5jQdLBlCsYGRQaz234SqoRLTCgMH00fY0xRJH+F9METQ== + just-diff-apply@^5.2.0: version "5.4.1" resolved "https://registry.yarnpkg.com/just-diff-apply/-/just-diff-apply-5.4.1.tgz#1debed059ad009863b4db0e8d8f333d743cdd83b" @@ -10167,7 +10319,7 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -merge2@^1.3.0, merge2@^1.4.1: +merge2@^1.2.3, merge2@^1.3.0, merge2@^1.4.1: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== @@ -10372,7 +10524,7 @@ micromark@^3.0.0: micromark-util-types "^1.0.1" uvu "^0.5.0" -micromatch@^3.1.4: +micromatch@^3.1.10, micromatch@^3.1.4: version "3.1.10" resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-3.1.10.tgz#70859bc95c9840952f359a068a3fc49f9ecfac23" integrity sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg== @@ -10841,7 +10993,7 @@ neo-async@^2.6.0, neo-async@^2.6.2: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== -nested-error-stacks@^2.0.0: +nested-error-stacks@^2.0.0, nested-error-stacks@^2.1.0: version "2.1.1" resolved "https://registry.yarnpkg.com/nested-error-stacks/-/nested-error-stacks-2.1.1.tgz#26c8a3cee6cc05fbcf1e333cd2fc3e003326c0b5" integrity sha512-9iN1ka/9zmX1ZvLV9ewJYEk9h7RyRRtqdK0woXcqohu8EWIerfPUjYJPg0ULy0UqP7cslmdGc8xKDJcojlKiaw== @@ -11438,6 +11590,21 @@ os-tmpdir@~1.0.2: resolved "https://registry.yarnpkg.com/os-tmpdir/-/os-tmpdir-1.0.2.tgz#bbe67406c79aa85c5cfec766fe5734555dfa1274" integrity sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g== +p-all@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-all/-/p-all-2.1.0.tgz#91419be56b7dee8fe4c5db875d55e0da084244a0" + integrity sha512-HbZxz5FONzz/z2gJfk6bFca0BCiSRF8jU3yCsWOen/vR6lZjfPOu/e7L3uFzTW1i0H8TlC3vqQstEJPQL4/uLA== + dependencies: + p-map "^2.0.0" + +p-any@^3.0.0: + version "3.0.0" + resolved "https://registry.yarnpkg.com/p-any/-/p-any-3.0.0.tgz#79847aeed70b5d3a10ea625296c0c3d2e90a87b9" + integrity sha512-5rqbqfsRWNb0sukt0awwgJMlaep+8jV45S15SKKB34z4UuzjcofIfnriCBhWjZP2jbVtjt9yRl7buB6RlKsu9w== + dependencies: + p-cancelable "^2.0.0" + p-some "^5.0.0" + p-cancelable@^0.4.0: version "0.4.1" resolved "https://registry.yarnpkg.com/p-cancelable/-/p-cancelable-0.4.1.tgz#35f363d67d52081c8d9585e37bcceb7e0bbcb2a0" @@ -11470,6 +11637,20 @@ p-event@^2.1.0: dependencies: p-timeout "^2.0.1" +p-event@^4.1.0: + version "4.2.0" + resolved "https://registry.yarnpkg.com/p-event/-/p-event-4.2.0.tgz#af4b049c8acd91ae81083ebd1e6f5cae2044c1b5" + integrity sha512-KXatOjCRXXkSePPb1Nbi0p0m+gQAwdlbhi4wQKJPI1HsMQS9g+Sqp2o+QHziPr7eYJyOZet836KoHEVM1mwOrQ== + dependencies: + p-timeout "^3.1.0" + +p-filter@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-filter/-/p-filter-2.1.0.tgz#1b1472562ae7a0f742f0f3d3d3718ea66ff9c09c" + integrity sha512-ZBxxZ5sL2HghephhpGAQdoskxplTwr7ICaehZwLIlfL6acuVgZPm8yBNuRAFBGEqtD/hmUeq9eqLg2ys9Xr/yw== + dependencies: + p-map "^2.0.0" + p-finally@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/p-finally/-/p-finally-1.0.0.tgz#3fbcfb15b899a44123b34b6dcc18b724336a2cae" @@ -11532,6 +11713,11 @@ p-map-series@^2.1.0: resolved "https://registry.yarnpkg.com/p-map-series/-/p-map-series-2.1.0.tgz#7560d4c452d9da0c07e692fdbfe6e2c81a2a91f2" integrity sha512-RpYIIK1zXSNEOdwxcfe7FdvGcs7+y5n8rifMhMNWvaxRNMPINJHF5GDeuVxWqnfrcHPSCnp7Oo5yNXHId9Av2Q== +p-map@^2.0.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/p-map/-/p-map-2.1.0.tgz#310928feef9c9ecc65b68b17693018a665cea175" + integrity sha512-y3b8Kpd8OAN444hxfBbFfj1FY/RjtTd8tzYwhUqNYXx0fXx2iX4maP4Qr6qhIKbQXI02wTLAda4fYUbDagTUFw== + p-map@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/p-map/-/p-map-3.0.0.tgz#d704d9af8a2ba684e2600d9a215983d4141a979d" @@ -11569,6 +11755,14 @@ p-reduce@^2.0.0, p-reduce@^2.1.0: resolved "https://registry.yarnpkg.com/p-reduce/-/p-reduce-2.1.0.tgz#09408da49507c6c274faa31f28df334bc712b64a" integrity sha512-2USApvnsutq8uoxZBGbbWM0JIYLiEMJ9RlaN7fAzVNb9OZN0SHjjTTfIcb667XynS5Y1VhwDJVDa72TnPzAYWw== +p-some@^5.0.0: + version "5.0.0" + resolved "https://registry.yarnpkg.com/p-some/-/p-some-5.0.0.tgz#8b730c74b4fe5169d7264a240ad010b6ebc686a4" + integrity sha512-Js5XZxo6vHjB9NOYAzWDYAIyyiPvva0DWESAIWIK7uhSpGsyg5FwUPxipU/SOQx5x9EqhOh545d1jo6cVkitig== + dependencies: + aggregate-error "^3.0.0" + p-cancelable "^2.0.0" + p-timeout@^2.0.1: version "2.0.1" resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-2.0.1.tgz#d8dd1979595d2dc0139e1fe46b8b646cb3cdf038" @@ -11576,7 +11770,7 @@ p-timeout@^2.0.1: dependencies: p-finally "^1.0.0" -p-timeout@^3.2.0: +p-timeout@^3.1.0, p-timeout@^3.2.0: version "3.2.0" resolved "https://registry.yarnpkg.com/p-timeout/-/p-timeout-3.2.0.tgz#c7e17abc971d2a7962ef83626b35d635acf23dfe" integrity sha512-rhIwUycgwwKcP9yTOOFK/AKsAopjjCakVqLHePO3CC6Mir1Z99xT+R63jZxAT5lFZLa2inS5h+ZS2GvR99/FBg== @@ -11719,6 +11913,11 @@ path-case@^3.0.4: dot-case "^3.0.4" tslib "^2.0.3" +path-dirname@^1.0.0: + version "1.0.2" + resolved "https://registry.yarnpkg.com/path-dirname/-/path-dirname-1.0.2.tgz#cc33d24d525e099a5388c0336c6e32b9160609e0" + integrity sha512-ALzNPpyNq9AqXMBjeymIjFDAkAFH06mHJH/cSBHAgU0s4vfpBn6b2nf8tiRLvagKD8RbTpq2FKTBg7cl9l3c7Q== + path-exists@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/path-exists/-/path-exists-3.0.0.tgz#ce0ebeaa5f78cb18925ea7d810d7b59b010fd515" @@ -12147,6 +12346,15 @@ psl@^1.1.28, psl@^1.1.33: resolved "https://registry.yarnpkg.com/psl/-/psl-1.9.0.tgz#d0df2a137f00794565fcaf3b2c00cd09f8d5a5a7" integrity sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag== +public-ip@^4.0.4: + version "4.0.4" + resolved "https://registry.yarnpkg.com/public-ip/-/public-ip-4.0.4.tgz#b3784a5a1ff1b81d015b9a18450be65ffd929eb3" + integrity sha512-EJ0VMV2vF6Cu7BIPo3IMW1Maq6ME+fbR0NcPmqDfpfNGIRPue1X8QrGjrg/rfjDkOsIkKHIf2S5FlEa48hFMTA== + dependencies: + dns-socket "^4.2.2" + got "^9.6.0" + is-ip "^3.1.0" + pump@^1.0.0: version "1.0.3" resolved "https://registry.yarnpkg.com/pump/-/pump-1.0.3.tgz#5dfe8311c33bbf6fc18261f9f34702c47c08a954" @@ -13229,6 +13437,11 @@ slash@^1.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-1.0.0.tgz#c41f2f6c39fc16d1cd17ad4b5d896114ae470d55" integrity sha512-3TYDR7xWt4dIqV2JauJr+EJeW356RXijHeUlO+8djJ+uBXPn8/2dpzBc8yQhh583sVvc9CvFAeQVgijsH+PNNg== +slash@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" + integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== + slash@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" From 9b49712669b06c97bda68a1e5f04eee4664c13f8 Mon Sep 17 00:00:00 2001 From: Akos Kitta <a.kitta@arduino.cc> Date: Fri, 10 Mar 2023 15:28:53 +0100 Subject: [PATCH 13/32] feat: omit release details to speed up lib search Signed-off-by: Akos Kitta <a.kitta@arduino.cc> --- arduino-ide-extension/package.json | 2 +- .../cc/arduino/cli/commands/v1/lib_pb.d.ts | 10 ++ .../cc/arduino/cli/commands/v1/lib_pb.js | 92 ++++++++++++++++++- .../src/node/library-service-impl.ts | 6 +- 4 files changed, 102 insertions(+), 8 deletions(-) diff --git a/arduino-ide-extension/package.json b/arduino-ide-extension/package.json index f717a4d9a..5bd714377 100644 --- a/arduino-ide-extension/package.json +++ b/arduino-ide-extension/package.json @@ -166,7 +166,7 @@ "version": { "owner": "arduino", "repo": "arduino-cli", - "commitish": "6992de7" + "commitish": "71a8576" } }, "fwuploader": { diff --git a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/lib_pb.d.ts b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/lib_pb.d.ts index 1f02e1682..27866d15a 100644 --- a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/lib_pb.d.ts +++ b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/lib_pb.d.ts @@ -406,6 +406,9 @@ export class LibrarySearchRequest extends jspb.Message { getQuery(): string; setQuery(value: string): LibrarySearchRequest; + getOmitReleasesDetails(): boolean; + setOmitReleasesDetails(value: boolean): LibrarySearchRequest; + serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): LibrarySearchRequest.AsObject; @@ -421,6 +424,7 @@ export namespace LibrarySearchRequest { export type AsObject = { instance?: cc_arduino_cli_commands_v1_common_pb.Instance.AsObject, query: string, + omitReleasesDetails: boolean, } } @@ -465,6 +469,11 @@ export class SearchedLibrary extends jspb.Message { getLatest(): LibraryRelease | undefined; setLatest(value?: LibraryRelease): SearchedLibrary; + clearAvailableVersionsList(): void; + getAvailableVersionsList(): Array<string>; + setAvailableVersionsList(value: Array<string>): SearchedLibrary; + addAvailableVersions(value: string, index?: number): string; + serializeBinary(): Uint8Array; toObject(includeInstance?: boolean): SearchedLibrary.AsObject; @@ -482,6 +491,7 @@ export namespace SearchedLibrary { releasesMap: Array<[string, LibraryRelease.AsObject]>, latest?: LibraryRelease.AsObject, + availableVersionsList: Array<string>, } } diff --git a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/lib_pb.js b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/lib_pb.js index 0ccd1856c..4923acaa8 100644 --- a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/lib_pb.js +++ b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/lib_pb.js @@ -374,7 +374,7 @@ if (goog.DEBUG && !COMPILED) { * @constructor */ proto.cc.arduino.cli.commands.v1.SearchedLibrary = function(opt_data) { - jspb.Message.initialize(this, opt_data, 0, -1, null, null); + jspb.Message.initialize(this, opt_data, 0, -1, proto.cc.arduino.cli.commands.v1.SearchedLibrary.repeatedFields_, null); }; goog.inherits(proto.cc.arduino.cli.commands.v1.SearchedLibrary, jspb.Message); if (goog.DEBUG && !COMPILED) { @@ -3202,7 +3202,8 @@ proto.cc.arduino.cli.commands.v1.LibrarySearchRequest.prototype.toObject = funct proto.cc.arduino.cli.commands.v1.LibrarySearchRequest.toObject = function(includeInstance, msg) { var f, obj = { instance: (f = msg.getInstance()) && cc_arduino_cli_commands_v1_common_pb.Instance.toObject(includeInstance, f), - query: jspb.Message.getFieldWithDefault(msg, 2, "") + query: jspb.Message.getFieldWithDefault(msg, 2, ""), + omitReleasesDetails: jspb.Message.getBooleanFieldWithDefault(msg, 3, false) }; if (includeInstance) { @@ -3248,6 +3249,10 @@ proto.cc.arduino.cli.commands.v1.LibrarySearchRequest.deserializeBinaryFromReade var value = /** @type {string} */ (reader.readString()); msg.setQuery(value); break; + case 3: + var value = /** @type {boolean} */ (reader.readBool()); + msg.setOmitReleasesDetails(value); + break; default: reader.skipField(); break; @@ -3292,6 +3297,13 @@ proto.cc.arduino.cli.commands.v1.LibrarySearchRequest.serializeBinaryToWriter = f ); } + f = message.getOmitReleasesDetails(); + if (f) { + writer.writeBool( + 3, + f + ); + } }; @@ -3350,6 +3362,24 @@ proto.cc.arduino.cli.commands.v1.LibrarySearchRequest.prototype.setQuery = funct }; +/** + * optional bool omit_releases_details = 3; + * @return {boolean} + */ +proto.cc.arduino.cli.commands.v1.LibrarySearchRequest.prototype.getOmitReleasesDetails = function() { + return /** @type {boolean} */ (jspb.Message.getBooleanFieldWithDefault(this, 3, false)); +}; + + +/** + * @param {boolean} value + * @return {!proto.cc.arduino.cli.commands.v1.LibrarySearchRequest} returns this + */ +proto.cc.arduino.cli.commands.v1.LibrarySearchRequest.prototype.setOmitReleasesDetails = function(value) { + return jspb.Message.setProto3BooleanField(this, 3, value); +}; + + /** * List of repeated fields within this message type. @@ -3541,6 +3571,13 @@ proto.cc.arduino.cli.commands.v1.LibrarySearchResponse.prototype.setStatus = fun +/** + * List of repeated fields within this message type. + * @private {!Array<number>} + * @const + */ +proto.cc.arduino.cli.commands.v1.SearchedLibrary.repeatedFields_ = [4]; + if (jspb.Message.GENERATE_TO_OBJECT) { @@ -3574,7 +3611,8 @@ proto.cc.arduino.cli.commands.v1.SearchedLibrary.toObject = function(includeInst var f, obj = { name: jspb.Message.getFieldWithDefault(msg, 1, ""), releasesMap: (f = msg.getReleasesMap()) ? f.toObject(includeInstance, proto.cc.arduino.cli.commands.v1.LibraryRelease.toObject) : [], - latest: (f = msg.getLatest()) && proto.cc.arduino.cli.commands.v1.LibraryRelease.toObject(includeInstance, f) + latest: (f = msg.getLatest()) && proto.cc.arduino.cli.commands.v1.LibraryRelease.toObject(includeInstance, f), + availableVersionsList: (f = jspb.Message.getRepeatedField(msg, 4)) == null ? undefined : f }; if (includeInstance) { @@ -3626,6 +3664,10 @@ proto.cc.arduino.cli.commands.v1.SearchedLibrary.deserializeBinaryFromReader = f reader.readMessage(value,proto.cc.arduino.cli.commands.v1.LibraryRelease.deserializeBinaryFromReader); msg.setLatest(value); break; + case 4: + var value = /** @type {string} */ (reader.readString()); + msg.addAvailableVersions(value); + break; default: reader.skipField(); break; @@ -3674,6 +3716,13 @@ proto.cc.arduino.cli.commands.v1.SearchedLibrary.serializeBinaryToWriter = funct proto.cc.arduino.cli.commands.v1.LibraryRelease.serializeBinaryToWriter ); } + f = message.getAvailableVersionsList(); + if (f.length > 0) { + writer.writeRepeatedString( + 4, + f + ); + } }; @@ -3754,6 +3803,43 @@ proto.cc.arduino.cli.commands.v1.SearchedLibrary.prototype.hasLatest = function( }; +/** + * repeated string available_versions = 4; + * @return {!Array<string>} + */ +proto.cc.arduino.cli.commands.v1.SearchedLibrary.prototype.getAvailableVersionsList = function() { + return /** @type {!Array<string>} */ (jspb.Message.getRepeatedField(this, 4)); +}; + + +/** + * @param {!Array<string>} value + * @return {!proto.cc.arduino.cli.commands.v1.SearchedLibrary} returns this + */ +proto.cc.arduino.cli.commands.v1.SearchedLibrary.prototype.setAvailableVersionsList = function(value) { + return jspb.Message.setField(this, 4, value || []); +}; + + +/** + * @param {string} value + * @param {number=} opt_index + * @return {!proto.cc.arduino.cli.commands.v1.SearchedLibrary} returns this + */ +proto.cc.arduino.cli.commands.v1.SearchedLibrary.prototype.addAvailableVersions = function(value, opt_index) { + return jspb.Message.addToRepeatedField(this, 4, value, opt_index); +}; + + +/** + * Clears the list making it empty but non-null. + * @return {!proto.cc.arduino.cli.commands.v1.SearchedLibrary} returns this + */ +proto.cc.arduino.cli.commands.v1.SearchedLibrary.prototype.clearAvailableVersionsList = function() { + return this.setAvailableVersionsList([]); +}; + + /** * List of repeated fields within this message type. diff --git a/arduino-ide-extension/src/node/library-service-impl.ts b/arduino-ide-extension/src/node/library-service-impl.ts index bd5eb8cb1..1bb836dcc 100644 --- a/arduino-ide-extension/src/node/library-service-impl.ts +++ b/arduino-ide-extension/src/node/library-service-impl.ts @@ -79,6 +79,7 @@ export class LibraryServiceImpl const req = new LibrarySearchRequest(); req.setQuery(options.query || ''); req.setInstance(instance); + req.setOmitReleasesDetails(true); const resp = await new Promise<LibrarySearchResponse>((resolve, reject) => client.librarySearch(req, (err, resp) => !!err ? reject(err) : resolve(resp) @@ -88,11 +89,8 @@ export class LibraryServiceImpl .getLibrariesList() .filter((item) => !!item.getLatest()) .map((item) => { - // TODO: This seems to contain only the latest item instead of all of the items. const availableVersions = item - .getReleasesMap() - .getEntryList() - .map(([key, _]) => key) + .getAvailableVersionsList() .sort(Installable.Version.COMPARATOR) .reverse(); let installedVersion: string | undefined; From dafb2454fd3133e229d0081a2b6788f88ac39e95 Mon Sep 17 00:00:00 2001 From: Akos Kitta <a.kitta@arduino.cc> Date: Wed, 22 Mar 2023 13:23:58 +0100 Subject: [PATCH 14/32] chore: latest VSIX handles custom directories.data so when starting the debugger the CLI config path is used by the CLI for the `daemon -I` command. Closes #1911 Signed-off-by: Akos Kitta <a.kitta@arduino.cc> --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 266f0feac..2e97fea6e 100644 --- a/package.json +++ b/package.json @@ -72,7 +72,7 @@ "theiaPluginsDir": "plugins", "theiaPlugins": { "vscode-builtin-cpp": "https://open-vsx.org/api/vscode/cpp/1.52.1/file/vscode.cpp-1.52.1.vsix", - "vscode-arduino-tools": "https://downloads.arduino.cc/vscode-arduino-tools/vscode-arduino-tools-0.0.2-beta.7.vsix", + "vscode-arduino-tools": "https://downloads.arduino.cc/vscode-arduino-tools/vscode-arduino-tools-0.0.2-beta.8.vsix", "vscode-builtin-json": "https://open-vsx.org/api/vscode/json/1.46.1/file/vscode.json-1.46.1.vsix", "vscode-builtin-json-language-features": "https://open-vsx.org/api/vscode/json-language-features/1.46.1/file/vscode.json-language-features-1.46.1.vsix", "cortex-debug": "https://downloads.arduino.cc/marus25.cortex-debug/marus25.cortex-debug-1.5.1.vsix", From 39ab836880ce7a958ce1d61e43e7e3e75120d3fc Mon Sep 17 00:00:00 2001 From: Akos Kitta <a.kitta@arduino.cc> Date: Tue, 21 Mar 2023 10:25:37 +0100 Subject: [PATCH 15/32] fix: let the resource finish all write operation before checking if it's in sync or not. Closes #437 Signed-off-by: Akos Kitta <a.kitta@arduino.cc> --- .../browser/arduino-ide-frontend-module.ts | 6 ++ .../browser/theia/filesystem/file-resource.ts | 78 +++++++++++++++++++ 2 files changed, 84 insertions(+) create mode 100644 arduino-ide-extension/src/browser/theia/filesystem/file-resource.ts diff --git a/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts b/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts index 6c6b44a63..d2161ebf2 100644 --- a/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts +++ b/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts @@ -356,6 +356,8 @@ import { Account } from './contributions/account'; import { SidebarBottomMenuWidget } from './theia/core/sidebar-bottom-menu-widget'; import { SidebarBottomMenuWidget as TheiaSidebarBottomMenuWidget } from '@theia/core/lib/browser/shell/sidebar-bottom-menu-widget'; import { CreateCloudCopy } from './contributions/create-cloud-copy'; +import { FileResourceResolver } from './theia/filesystem/file-resource'; +import { FileResourceResolver as TheiaFileResourceResolver } from '@theia/filesystem/lib/browser/file-resource'; export default new ContainerModule((bind, unbind, isBound, rebind) => { // Commands and toolbar items @@ -1034,4 +1036,8 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => { bind(FrontendApplicationContribution).toService(DaemonPort); bind(IsOnline).toSelf().inSingletonScope(); bind(FrontendApplicationContribution).toService(IsOnline); + + // https://github.com/arduino/arduino-ide/issues/437 + bind(FileResourceResolver).toSelf().inSingletonScope(); + rebind(TheiaFileResourceResolver).toService(FileResourceResolver); }); diff --git a/arduino-ide-extension/src/browser/theia/filesystem/file-resource.ts b/arduino-ide-extension/src/browser/theia/filesystem/file-resource.ts new file mode 100644 index 000000000..168883910 --- /dev/null +++ b/arduino-ide-extension/src/browser/theia/filesystem/file-resource.ts @@ -0,0 +1,78 @@ +import { ResourceSaveOptions } from '@theia/core/lib/common/resource'; +import { Readable } from '@theia/core/lib/common/stream'; +import URI from '@theia/core/lib/common/uri'; +import { injectable } from '@theia/core/shared/inversify'; +import { + FileResource, + FileResourceOptions, + FileResourceResolver as TheiaFileResourceResolver, +} from '@theia/filesystem/lib/browser/file-resource'; +import { FileService } from '@theia/filesystem/lib/browser/file-service'; +import { + FileOperationError, + FileOperationResult, + FileStat, +} from '@theia/filesystem/lib/common/files'; +import * as PQueue from 'p-queue'; + +@injectable() +export class FileResourceResolver extends TheiaFileResourceResolver { + override async resolve(uri: URI): Promise<WriteQueuedFileResource> { + let stat: FileStat | undefined; + try { + stat = await this.fileService.resolve(uri); + } catch (e) { + if ( + !( + e instanceof FileOperationError && + e.fileOperationResult === FileOperationResult.FILE_NOT_FOUND + ) + ) { + throw e; + } + } + if (stat && stat.isDirectory) { + throw new Error( + 'The given uri is a directory: ' + this.labelProvider.getLongName(uri) + ); + } + return new WriteQueuedFileResource(uri, this.fileService, { + shouldOverwrite: () => this.shouldOverwrite(uri), + shouldOpenAsText: (error) => this.shouldOpenAsText(uri, error), + }); + } +} + +class WriteQueuedFileResource extends FileResource { + private readonly writeQueue = new PQueue({ autoStart: true, concurrency: 1 }); + + constructor( + uri: URI, + fileService: FileService, + options: FileResourceOptions + ) { + super(uri, fileService, options); + const originalSaveContentChanges = this['saveContentChanges']; + if (originalSaveContentChanges) { + this['saveContentChanges'] = (changes, options) => { + return this.writeQueue.add(() => + originalSaveContentChanges.bind(this)(changes, options) + ); + }; + } + } + + protected override async doWrite( + content: string | Readable<string>, + options?: ResourceSaveOptions + ): Promise<void> { + return this.writeQueue.add(() => super.doWrite(content, options)); + } + + protected override async isInSync(): Promise<boolean> { + // Let all the write operations finish to update the version (mtime) before checking whether the resource is in sync. + // https://github.com/eclipse-theia/theia/issues/12327 + await this.writeQueue.onIdle(); + return super.isInSync(); + } +} From e4beb03a404b6f6f7ecfad3a7d3b9ea24476632c Mon Sep 17 00:00:00 2001 From: Akos Kitta <a.kitta@arduino.cc> Date: Mon, 20 Mar 2023 14:27:03 +0100 Subject: [PATCH 16/32] fix: incorrect editor widget key calculation to avoid duplicate editor tabs when opening a sketch with no previously saved workbench layout Closes #1791 Signed-off-by: Akos Kitta <a.kitta@arduino.cc> --- .../src/browser/contributions/open-sketch-files.ts | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/arduino-ide-extension/src/browser/contributions/open-sketch-files.ts b/arduino-ide-extension/src/browser/contributions/open-sketch-files.ts index 01fa997d3..86cf971d0 100644 --- a/arduino-ide-extension/src/browser/contributions/open-sketch-files.ts +++ b/arduino-ide-extension/src/browser/contributions/open-sketch-files.ts @@ -45,7 +45,11 @@ export class OpenSketchFiles extends SketchContribution { await this.ensureOpened(uri); } if (focusMainSketchFile) { - await this.ensureOpened(mainFileUri, true, { mode: 'activate' }); + await this.ensureOpened(mainFileUri, true, { + mode: 'activate', + preview: false, + counter: 0, + }); } if (mainFileUri.endsWith('.pde')) { const message = nls.localize( From 6e72be1b4cb3ef6c119ab0caae3dcfe008aa7c8d Mon Sep 17 00:00:00 2001 From: Akos Kitta <a.kitta@arduino.cc> Date: Fri, 24 Mar 2023 17:24:11 +0100 Subject: [PATCH 17/32] feat: re-focus monitor widget after verify/upload supported when the monitor widget was the current in the bottom panel, and the core command (upload/verify/etc./) was successful Signed-off-by: Akos Kitta <a.kitta@arduino.cc> --- .../src/browser/contributions/contribution.ts | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/arduino-ide-extension/src/browser/contributions/contribution.ts b/arduino-ide-extension/src/browser/contributions/contribution.ts index c53bac1ff..b34f3ee4e 100644 --- a/arduino-ide-extension/src/browser/contributions/contribution.ts +++ b/arduino-ide-extension/src/browser/contributions/contribution.ts @@ -6,6 +6,10 @@ import { } from '@theia/core/shared/inversify'; import URI from '@theia/core/lib/common/uri'; import { ILogger } from '@theia/core/lib/common/logger'; +import { + Disposable, + DisposableCollection, +} from '@theia/core/lib/common/disposable'; import { Saveable } from '@theia/core/lib/browser/saveable'; import { FileService } from '@theia/filesystem/lib/browser/file-service'; import { MaybePromise } from '@theia/core/lib/common/types'; @@ -62,6 +66,7 @@ import { MessageType } from '@theia/core/lib/common/message-service-protocol'; import { WorkspaceService } from '../theia/workspace/workspace-service'; import { MainMenuManager } from '../../common/main-menu-manager'; import { ConfigServiceClient } from '../config/config-service-client'; +import { ApplicationShell } from '@theia/core/lib/browser/shell/application-shell'; export { Command, @@ -217,6 +222,9 @@ export abstract class CoreServiceContribution extends SketchContribution { @inject(NotificationManager) private readonly notificationManager: NotificationManager; + @inject(ApplicationShell) + private readonly shell: ApplicationShell; + /** * This is the internal (Theia) ID of the notification that is currently visible. * It's stored here as a field to be able to close it before executing any new core command (such as verify, upload, etc.) @@ -279,6 +287,9 @@ export abstract class CoreServiceContribution extends SketchContribution { keepOutput?: boolean; task: (progressId: string, coreService: CoreService) => Promise<T>; }): Promise<T> { + const toDisposeOnComplete = new DisposableCollection( + this.maybeActivateMonitorWidget() + ); const { progressText, keepOutput, task } = options; this.outputChannelManager .getChannel('Arduino') @@ -290,9 +301,24 @@ export abstract class CoreServiceContribution extends SketchContribution { run: ({ progressId }) => task(progressId, this.coreService), keepOutput, }); + toDisposeOnComplete.dispose(); return result; } + // TODO: cleanup! + // this dependency does not belong here + // support core command contribution handlers, the monitor-widget should implement it and register itself as a handler + // the monitor widget should reveal itself after a successful core command execution + private maybeActivateMonitorWidget(): Disposable { + const currentWidget = this.shell.bottomPanel.currentTitle?.owner; + if (currentWidget?.id === 'serial-monitor') { + return Disposable.create(() => + this.shell.bottomPanel.activateWidget(currentWidget) + ); + } + return Disposable.NULL; + } + private notificationId(message: string, ...actions: string[]): string { return this.notificationManager['getMessageId']({ text: message, From eb1f247296a1993c38a65b1b5707a238a8d8a77d Mon Sep 17 00:00:00 2001 From: Akos Kitta <a.kitta@arduino.cc> Date: Fri, 24 Mar 2023 10:42:17 +0100 Subject: [PATCH 18/32] fix: the focus in the sketchbook widget Ref: arduino/arduino-ide#1720 Signed-off-by: Akos Kitta <a.kitta@arduino.cc> --- .../browser/library/library-list-widget.ts | 13 +------ .../src/browser/utils/dom.ts | 37 +++++++++++++++++++ .../sketchbook-composite-widget.tsx | 11 ++++-- .../widgets/sketchbook/sketchbook-widget.tsx | 8 +--- 4 files changed, 47 insertions(+), 22 deletions(-) create mode 100644 arduino-ide-extension/src/browser/utils/dom.ts diff --git a/arduino-ide-extension/src/browser/library/library-list-widget.ts b/arduino-ide-extension/src/browser/library/library-list-widget.ts index 050783816..25480de95 100644 --- a/arduino-ide-extension/src/browser/library/library-list-widget.ts +++ b/arduino-ide-extension/src/browser/library/library-list-widget.ts @@ -20,6 +20,7 @@ import { Installable } from '../../common/protocol'; import { ListItemRenderer } from '../widgets/component-list/list-item-renderer'; import { nls } from '@theia/core/lib/common'; import { LibraryFilterRenderer } from '../widgets/component-list/filter-renderer'; +import { findChildTheiaButton } from '../utils/dom'; @injectable() export class LibraryListWidget extends ListWidget< @@ -243,17 +244,7 @@ class MessageBoxDialog extends AbstractDialog<MessageBoxDialog.Result> { protected override onAfterAttach(message: Message): void { super.onAfterAttach(message); - let buttonToFocus: HTMLButtonElement | undefined = undefined; - for (const child of Array.from(this.controlPanel.children)) { - if (child instanceof HTMLButtonElement) { - if (child.classList.contains('main')) { - buttonToFocus = child; - break; - } - buttonToFocus = child; - } - } - buttonToFocus?.focus(); + findChildTheiaButton(this.controlPanel)?.focus(); } } export namespace MessageBoxDialog { diff --git a/arduino-ide-extension/src/browser/utils/dom.ts b/arduino-ide-extension/src/browser/utils/dom.ts new file mode 100644 index 000000000..5d6e65d3c --- /dev/null +++ b/arduino-ide-extension/src/browser/utils/dom.ts @@ -0,0 +1,37 @@ +import { notEmpty } from '@theia/core'; + +/** + * Finds the closest child HTMLButtonElement representing a Theia button. + * A button is a Theia button if it's a `<button>` element and has the `"theia-button"` class. + * If an element has multiple Theia button children, this function prefers `"main"` over `"secondary"` button. + */ +export function findChildTheiaButton( + element: HTMLElement, + recursive = false +): HTMLButtonElement | undefined { + let button: HTMLButtonElement | undefined = undefined; + const children = Array.from(element.children); + for (const child of children) { + if ( + child instanceof HTMLButtonElement && + child.classList.contains('theia-button') + ) { + if (child.classList.contains('main')) { + return child; + } + button = child; + } + } + if (!button && recursive) { + button = children + .filter(isHTMLElement) + .map((childElement) => findChildTheiaButton(childElement, true)) + .filter(notEmpty) + .shift(); + } + return button; +} + +function isHTMLElement(element: Element): element is HTMLElement { + return element instanceof HTMLElement; +} diff --git a/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-composite-widget.tsx b/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-composite-widget.tsx index b0ba780be..897ce61fb 100644 --- a/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-composite-widget.tsx +++ b/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-composite-widget.tsx @@ -9,6 +9,7 @@ import { BaseWidget } from '@theia/core/lib/browser/widgets/widget'; import { CommandService } from '@theia/core/lib/common/command'; import { SketchbookTreeWidget } from './sketchbook-tree-widget'; import { CreateNew } from '../sketchbook/create-new'; +import { findChildTheiaButton } from '../../utils/dom'; @injectable() export abstract class BaseSketchbookCompositeWidget< @@ -18,16 +19,17 @@ export abstract class BaseSketchbookCompositeWidget< protected readonly commandService: CommandService; private readonly compositeNode: HTMLElement; + private readonly footerNode: HTMLElement; private readonly footerRoot: Root; constructor() { super(); this.compositeNode = document.createElement('div'); this.compositeNode.classList.add('composite-node'); - const footerNode = document.createElement('div'); - footerNode.classList.add('footer-node'); - this.compositeNode.appendChild(footerNode); - this.footerRoot = createRoot(footerNode); + this.footerNode = document.createElement('div'); + this.footerNode.classList.add('footer-node'); + this.compositeNode.appendChild(this.footerNode); + this.footerRoot = createRoot(this.footerNode); this.node.appendChild(this.compositeNode); this.title.closable = false; } @@ -51,6 +53,7 @@ export abstract class BaseSketchbookCompositeWidget< super.onActivateRequest(message); // Sending a resize message is needed because otherwise the tree widget would render empty this.onResize(Widget.ResizeMessage.UnknownSize); + findChildTheiaButton(this.footerNode, true)?.focus(); } protected override onResize(message: Widget.ResizeMessage): void { diff --git a/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-widget.tsx b/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-widget.tsx index 93533e37e..2d99f97b7 100644 --- a/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-widget.tsx +++ b/arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-widget.tsx @@ -128,13 +128,7 @@ export class SketchbookWidget extends BaseWidget { protected override onActivateRequest(message: Message): void { super.onActivateRequest(message); - - // TODO: focus the active sketchbook - // if (this.editor) { - // this.editor.focus(); - // } else { - // } - this.node.focus(); + this.sketchbookCompositeWidget.activate(); } protected override onResize(message: Widget.ResizeMessage): void { From f5c98c8400a23ddaa9ea0c5afb15a3f068014659 Mon Sep 17 00:00:00 2001 From: Akos Kitta <a.kitta@arduino.cc> Date: Wed, 12 Apr 2023 16:55:01 +0200 Subject: [PATCH 19/32] feat(infra): support for `topic: cloud` label Signed-off-by: Akos Kitta <a.kitta@arduino.cc> --- .github/label-configuration-files/labels.yml | 3 +++ 1 file changed, 3 insertions(+) diff --git a/.github/label-configuration-files/labels.yml b/.github/label-configuration-files/labels.yml index a938431b2..b0ae38dc2 100644 --- a/.github/label-configuration-files/labels.yml +++ b/.github/label-configuration-files/labels.yml @@ -7,6 +7,9 @@ - name: "topic: CLI" color: "00ffff" description: Related to Arduino CLI +- name: "topic: cloud" + color: "00ffff" + description: Related to Arduino Cloud and cloud sketches - name: "topic: debugger" color: "00ffff" description: Related to the integrated debugger From 0a53550b0b4865ff46da20caea947b9a85492834 Mon Sep 17 00:00:00 2001 From: Akos Kitta <a.kitta@arduino.cc> Date: Wed, 29 Mar 2023 10:04:32 +0200 Subject: [PATCH 20/32] ci: use `ubuntu-latest` for the Linux build Signed-off-by: Akos Kitta <a.kitta@arduino.cc> --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index d26c26def..b4a7ba472 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -43,7 +43,7 @@ jobs: certificate-secret: WINDOWS_SIGNING_CERTIFICATE_PFX # Name of the secret that contains the certificate. certificate-password-secret: WINDOWS_SIGNING_CERTIFICATE_PASSWORD # Name of the secret that contains the certificate password. certificate-extension: pfx # File extension for the certificate. - - os: ubuntu-18.04 # https://github.com/arduino/arduino-ide/issues/259 + - os: ubuntu-latest - os: macos-latest # APPLE_SIGNING_CERTIFICATE_P12 secret was produced by following the procedure from: # https://www.kencochrane.com/2020/08/01/build-and-sign-golang-binaries-for-macos-with-github-actions/#exporting-the-developer-certificate From ab5c63c4b7f34f76dafae1b21f8ec771a52b5a5e Mon Sep 17 00:00:00 2001 From: Akos Kitta <1405703+kittaakos@users.noreply.github.com> Date: Tue, 11 Apr 2023 09:45:23 +0200 Subject: [PATCH 21/32] Update .github/workflows/build.yml Co-authored-by: per1234 <accounts@perglass.com> --- .github/workflows/build.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index b4a7ba472..1113042eb 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -43,7 +43,7 @@ jobs: certificate-secret: WINDOWS_SIGNING_CERTIFICATE_PFX # Name of the secret that contains the certificate. certificate-password-secret: WINDOWS_SIGNING_CERTIFICATE_PASSWORD # Name of the secret that contains the certificate password. certificate-extension: pfx # File extension for the certificate. - - os: ubuntu-latest + - os: ubuntu-20.04 - os: macos-latest # APPLE_SIGNING_CERTIFICATE_P12 secret was produced by following the procedure from: # https://www.kencochrane.com/2020/08/01/build-and-sign-golang-binaries-for-macos-with-github-actions/#exporting-the-developer-certificate From 80d5b5afa70c82cf43a64b7c7eb0e145dc140891 Mon Sep 17 00:00:00 2001 From: Akos Kitta <a.kitta@arduino.cc> Date: Fri, 17 Mar 2023 15:41:34 +0100 Subject: [PATCH 22/32] fix: propagate monitor errors to the frontend - Handle when the board's platform is not installed (Closes #1974) - UX: Smoother monitor widget reset (Closes #1985) - Fixed monitor <input> readOnly state (Closes #1984) - Set monitor widget header color (Ref #682) Closes #1508 Signed-off-by: Akos Kitta <a.kitta@arduino.cc> --- .../browser/arduino-ide-frontend-module.ts | 10 +- .../monitor-manager-proxy-client-impl.ts | 92 +++-- .../src/browser/monitor-model.ts | 84 ++-- .../monitor/monitor-view-contribution.tsx | 8 +- .../browser/serial/monitor/monitor-widget.tsx | 94 +++-- .../monitor/serial-monitor-send-input.tsx | 86 +++- .../src/browser/style/index.css | 32 +- .../src/browser/style/monitor.css | 33 +- .../src/common/protocol/core-service.ts | 10 +- .../src/common/protocol/monitor-service.ts | 186 ++++++++- .../src/node/core-service-impl.ts | 4 +- .../src/node/monitor-manager-proxy-impl.ts | 14 +- .../src/node/monitor-manager.ts | 33 +- .../src/node/monitor-service.ts | 372 ++++++++++-------- .../monitor-settings-provider.ts | 5 +- i18n/en.json | 8 + 16 files changed, 718 insertions(+), 353 deletions(-) diff --git a/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts b/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts index d2161ebf2..09475690b 100644 --- a/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts +++ b/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts @@ -496,15 +496,7 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => { bind(TabBarToolbarContribution).toService(MonitorViewContribution); bind(WidgetFactory).toDynamicValue((context) => ({ id: MonitorWidget.ID, - createWidget: () => { - return new MonitorWidget( - context.container.get<MonitorModel>(MonitorModel), - context.container.get<MonitorManagerProxyClient>( - MonitorManagerProxyClient - ), - context.container.get<BoardsServiceProvider>(BoardsServiceProvider) - ); - }, + createWidget: () => context.container.get(MonitorWidget), })); bind(MonitorManagerProxyFactory).toFactory( diff --git a/arduino-ide-extension/src/browser/monitor-manager-proxy-client-impl.ts b/arduino-ide-extension/src/browser/monitor-manager-proxy-client-impl.ts index 94ab4d0f5..ebbafa385 100644 --- a/arduino-ide-extension/src/browser/monitor-manager-proxy-client-impl.ts +++ b/arduino-ide-extension/src/browser/monitor-manager-proxy-client-impl.ts @@ -1,11 +1,14 @@ import { - CommandRegistry, + ApplicationError, Disposable, Emitter, MessageService, nls, } from '@theia/core'; +import { Deferred } from '@theia/core/lib/common/promise-util'; import { inject, injectable } from '@theia/core/shared/inversify'; +import { NotificationManager } from '@theia/messages/lib/browser/notifications-manager'; +import { MessageType } from '@theia/core/lib/common/message-service-protocol'; import { Board, Port } from '../common/protocol'; import { Monitor, @@ -23,21 +26,31 @@ import { BoardsServiceProvider } from './boards/boards-service-provider'; export class MonitorManagerProxyClientImpl implements MonitorManagerProxyClient { + @inject(MessageService) + private readonly messageService: MessageService; + // This is necessary to call the backend methods from the frontend + @inject(MonitorManagerProxyFactory) + private readonly server: MonitorManagerProxyFactory; + @inject(BoardsServiceProvider) + private readonly boardsServiceProvider: BoardsServiceProvider; + @inject(NotificationManager) + private readonly notificationManager: NotificationManager; + // When pluggable monitor messages are received from the backend // this event is triggered. // Ideally a frontend component is connected to this event // to update the UI. - protected readonly onMessagesReceivedEmitter = new Emitter<{ + private readonly onMessagesReceivedEmitter = new Emitter<{ messages: string[]; }>(); readonly onMessagesReceived = this.onMessagesReceivedEmitter.event; - protected readonly onMonitorSettingsDidChangeEmitter = + private readonly onMonitorSettingsDidChangeEmitter = new Emitter<MonitorSettings>(); readonly onMonitorSettingsDidChange = this.onMonitorSettingsDidChangeEmitter.event; - protected readonly onMonitorShouldResetEmitter = new Emitter(); + private readonly onMonitorShouldResetEmitter = new Emitter<void>(); readonly onMonitorShouldReset = this.onMonitorShouldResetEmitter.event; // WebSocket used to handle pluggable monitor communication between @@ -51,29 +64,16 @@ export class MonitorManagerProxyClientImpl return this.wsPort; } - constructor( - @inject(MessageService) - protected messageService: MessageService, - - // This is necessary to call the backend methods from the frontend - @inject(MonitorManagerProxyFactory) - protected server: MonitorManagerProxyFactory, - - @inject(CommandRegistry) - protected readonly commandRegistry: CommandRegistry, - - @inject(BoardsServiceProvider) - protected readonly boardsServiceProvider: BoardsServiceProvider - ) {} - /** * Connects a localhost WebSocket using the specified port. * @param addressPort port of the WebSocket */ async connect(addressPort: number): Promise<void> { - if (!!this.webSocket) { - if (this.wsPort === addressPort) return; - else this.disconnect(); + if (this.webSocket) { + if (this.wsPort === addressPort) { + return; + } + this.disconnect(); } try { this.webSocket = new WebSocket(`ws://localhost:${addressPort}`); @@ -87,6 +87,9 @@ export class MonitorManagerProxyClientImpl return; } + const opened = new Deferred<void>(); + this.webSocket.onopen = () => opened.resolve(); + this.webSocket.onerror = () => opened.reject(); this.webSocket.onmessage = (message) => { const parsedMessage = JSON.parse(message.data); if (Array.isArray(parsedMessage)) @@ -99,19 +102,26 @@ export class MonitorManagerProxyClientImpl } }; this.wsPort = addressPort; + return opened.promise; } /** * Disconnects the WebSocket if connected. */ disconnect(): void { - if (!this.webSocket) return; + if (!this.webSocket) { + return; + } this.onBoardsConfigChanged?.dispose(); this.onBoardsConfigChanged = undefined; try { - this.webSocket?.close(); + this.webSocket.close(); this.webSocket = undefined; - } catch { + } catch (err) { + console.error( + 'Could not close the websocket connection for the monitor.', + err + ); this.messageService.error( nls.localize( 'arduino/monitor/unableToCloseWebSocket', @@ -126,6 +136,7 @@ export class MonitorManagerProxyClientImpl } async startMonitor(settings?: PluggableMonitorSettings): Promise<void> { + await this.boardsServiceProvider.reconciled; this.lastConnectedBoard = { selectedBoard: this.boardsServiceProvider.boardsConfig.selectedBoard, selectedPort: this.boardsServiceProvider.boardsConfig.selectedPort, @@ -150,11 +161,11 @@ export class MonitorManagerProxyClientImpl ? Port.keyOf(this.lastConnectedBoard.selectedPort) : undefined) ) { - this.onMonitorShouldResetEmitter.fire(null); this.lastConnectedBoard = { selectedBoard: selectedBoard, selectedPort: selectedPort, }; + this.onMonitorShouldResetEmitter.fire(); } else { // a board is plugged and it's the same as prev, rerun "this.startMonitor" to // recreate the listener callback @@ -167,7 +178,14 @@ export class MonitorManagerProxyClientImpl const { selectedBoard, selectedPort } = this.boardsServiceProvider.boardsConfig; if (!selectedBoard || !selectedBoard.fqbn || !selectedPort) return; - await this.server().startMonitor(selectedBoard, selectedPort, settings); + try { + this.clearVisibleNotification(); + await this.server().startMonitor(selectedBoard, selectedPort, settings); + } catch (err) { + const message = ApplicationError.is(err) ? err.message : String(err); + this.previousNotificationId = this.notificationId(message); + this.messageService.error(message); + } } getCurrentSettings(board: Board, port: Port): Promise<MonitorSettings> { @@ -199,4 +217,24 @@ export class MonitorManagerProxyClientImpl }) ); } + + /** + * This is the internal (Theia) ID of the notification that is currently visible. + * It's stored here as a field to be able to close it before starting a new monitor connection. It's a hack. + */ + private previousNotificationId: string | undefined; + private clearVisibleNotification(): void { + if (this.previousNotificationId) { + this.notificationManager.clear(this.previousNotificationId); + this.previousNotificationId = undefined; + } + } + + private notificationId(message: string, ...actions: string[]): string { + return this.notificationManager['getMessageId']({ + text: message, + actions, + type: MessageType.Error, + }); + } } diff --git a/arduino-ide-extension/src/browser/monitor-model.ts b/arduino-ide-extension/src/browser/monitor-model.ts index 3ebea1819..c3c8a26f4 100644 --- a/arduino-ide-extension/src/browser/monitor-model.ts +++ b/arduino-ide-extension/src/browser/monitor-model.ts @@ -4,7 +4,14 @@ import { LocalStorageService, } from '@theia/core/lib/browser'; import { inject, injectable } from '@theia/core/shared/inversify'; -import { MonitorManagerProxyClient } from '../common/protocol'; +import { + isMonitorConnected, + MonitorConnectionStatus, + monitorConnectionStatusEquals, + MonitorEOL, + MonitorManagerProxyClient, + MonitorState, +} from '../common/protocol'; import { isNullOrUndefined } from '../common/utils'; import { MonitorSettings } from '../node/monitor-settings/monitor-settings-provider'; @@ -19,36 +26,36 @@ export class MonitorModel implements FrontendApplicationContribution { protected readonly monitorManagerProxy: MonitorManagerProxyClient; protected readonly onChangeEmitter: Emitter< - MonitorModel.State.Change<keyof MonitorModel.State> + MonitorState.Change<keyof MonitorState> >; protected _autoscroll: boolean; protected _timestamp: boolean; - protected _lineEnding: MonitorModel.EOL; + protected _lineEnding: MonitorEOL; protected _interpolate: boolean; protected _darkTheme: boolean; protected _wsPort: number; protected _serialPort: string; - protected _connected: boolean; + protected _connectionStatus: MonitorConnectionStatus; constructor() { this._autoscroll = true; this._timestamp = false; this._interpolate = false; - this._lineEnding = MonitorModel.EOL.DEFAULT; + this._lineEnding = MonitorEOL.DEFAULT; this._darkTheme = false; this._wsPort = 0; this._serialPort = ''; - this._connected = true; + this._connectionStatus = 'not-connected'; this.onChangeEmitter = new Emitter< - MonitorModel.State.Change<keyof MonitorModel.State> + MonitorState.Change<keyof MonitorState> >(); } onStart(): void { this.localStorageService - .getData<MonitorModel.State>(MonitorModel.STORAGE_ID) + .getData<MonitorState>(MonitorModel.STORAGE_ID) .then(this.restoreState.bind(this)); this.monitorManagerProxy.onMonitorSettingsDidChange( @@ -56,11 +63,11 @@ export class MonitorModel implements FrontendApplicationContribution { ); } - get onChange(): Event<MonitorModel.State.Change<keyof MonitorModel.State>> { + get onChange(): Event<MonitorState.Change<keyof MonitorState>> { return this.onChangeEmitter.event; } - protected restoreState(state: MonitorModel.State): void { + protected restoreState(state: MonitorState): void { if (!state) { return; } @@ -125,11 +132,11 @@ export class MonitorModel implements FrontendApplicationContribution { this.timestamp = !this._timestamp; } - get lineEnding(): MonitorModel.EOL { + get lineEnding(): MonitorEOL { return this._lineEnding; } - set lineEnding(lineEnding: MonitorModel.EOL) { + set lineEnding(lineEnding: MonitorEOL) { if (lineEnding === this._lineEnding) return; this._lineEnding = lineEnding; this.monitorManagerProxy.changeSettings({ @@ -211,19 +218,26 @@ export class MonitorModel implements FrontendApplicationContribution { ); } - get connected(): boolean { - return this._connected; + get connectionStatus(): MonitorConnectionStatus { + return this._connectionStatus; } - set connected(connected: boolean) { - if (connected === this._connected) return; - this._connected = connected; + set connectionStatus(connectionStatus: MonitorConnectionStatus) { + if ( + monitorConnectionStatusEquals(connectionStatus, this.connectionStatus) + ) { + return; + } + this._connectionStatus = connectionStatus; this.monitorManagerProxy.changeSettings({ - monitorUISettings: { connected }, + monitorUISettings: { + connectionStatus, + connected: isMonitorConnected(connectionStatus), + }, }); this.onChangeEmitter.fire({ - property: 'connected', - value: this._connected, + property: 'connectionStatus', + value: this._connectionStatus, }); } @@ -238,7 +252,7 @@ export class MonitorModel implements FrontendApplicationContribution { darkTheme, wsPort, serialPort, - connected, + connectionStatus, } = monitorUISettings; if (!isNullOrUndefined(autoscroll)) this.autoscroll = autoscroll; @@ -248,31 +262,7 @@ export class MonitorModel implements FrontendApplicationContribution { if (!isNullOrUndefined(darkTheme)) this.darkTheme = darkTheme; if (!isNullOrUndefined(wsPort)) this.wsPort = wsPort; if (!isNullOrUndefined(serialPort)) this.serialPort = serialPort; - if (!isNullOrUndefined(connected)) this.connected = connected; + if (!isNullOrUndefined(connectionStatus)) + this.connectionStatus = connectionStatus; }; } - -// TODO: Move this to /common -export namespace MonitorModel { - export interface State { - autoscroll: boolean; - timestamp: boolean; - lineEnding: EOL; - interpolate: boolean; - darkTheme: boolean; - wsPort: number; - serialPort: string; - connected: boolean; - } - export namespace State { - export interface Change<K extends keyof State> { - readonly property: K; - readonly value: State[K]; - } - } - - export type EOL = '' | '\n' | '\r' | '\r\n'; - export namespace EOL { - export const DEFAULT: EOL = '\n'; - } -} diff --git a/arduino-ide-extension/src/browser/serial/monitor/monitor-view-contribution.tsx b/arduino-ide-extension/src/browser/serial/monitor/monitor-view-contribution.tsx index 36f13c3b2..925d221ec 100644 --- a/arduino-ide-extension/src/browser/serial/monitor/monitor-view-contribution.tsx +++ b/arduino-ide-extension/src/browser/serial/monitor/monitor-view-contribution.tsx @@ -10,6 +10,7 @@ import { import { ArduinoToolbar } from '../../toolbar/arduino-toolbar'; import { ArduinoMenus } from '../../menu/arduino-menus'; import { nls } from '@theia/core/lib/common'; +import { Event } from '@theia/core/lib/common/event'; import { MonitorModel } from '../../monitor-model'; import { MonitorManagerProxyClient } from '../../../common/protocol'; @@ -84,13 +85,13 @@ export class MonitorViewContribution id: 'monitor-autoscroll', render: () => this.renderAutoScrollButton(), isVisible: (widget) => widget instanceof MonitorWidget, - onDidChange: this.model.onChange as any, // XXX: it's a hack. See: https://github.com/eclipse-theia/theia/pull/6696/ + onDidChange: this.model.onChange as Event<unknown> as Event<void>, }); registry.registerItem({ id: 'monitor-timestamp', render: () => this.renderTimestampButton(), isVisible: (widget) => widget instanceof MonitorWidget, - onDidChange: this.model.onChange as any, // XXX: it's a hack. See: https://github.com/eclipse-theia/theia/pull/6696/ + onDidChange: this.model.onChange as Event<unknown> as Event<void>, }); registry.registerItem({ id: SerialMonitor.Commands.CLEAR_OUTPUT.id, @@ -143,8 +144,7 @@ export class MonitorViewContribution protected async reset(): Promise<void> { const widget = this.tryGetWidget(); if (widget) { - widget.dispose(); - await this.openView({ activate: true, reveal: true }); + widget.reset(); } } diff --git a/arduino-ide-extension/src/browser/serial/monitor/monitor-widget.tsx b/arduino-ide-extension/src/browser/serial/monitor/monitor-widget.tsx index ec83f5a0a..c2311a11c 100644 --- a/arduino-ide-extension/src/browser/serial/monitor/monitor-widget.tsx +++ b/arduino-ide-extension/src/browser/serial/monitor/monitor-widget.tsx @@ -1,7 +1,14 @@ import * as React from '@theia/core/shared/react'; -import { injectable, inject } from '@theia/core/shared/inversify'; +import { + injectable, + inject, + postConstruct, +} from '@theia/core/shared/inversify'; import { Emitter } from '@theia/core/lib/common/event'; -import { Disposable } from '@theia/core/lib/common/disposable'; +import { + Disposable, + DisposableCollection, +} from '@theia/core/lib/common/disposable'; import { ReactWidget, Message, @@ -13,9 +20,13 @@ import { SerialMonitorSendInput } from './serial-monitor-send-input'; import { SerialMonitorOutput } from './serial-monitor-send-output'; import { BoardsServiceProvider } from '../../boards/boards-service-provider'; import { nls } from '@theia/core/lib/common'; -import { MonitorManagerProxyClient } from '../../../common/protocol'; +import { + MonitorEOL, + MonitorManagerProxyClient, +} from '../../../common/protocol'; import { MonitorModel } from '../../monitor-model'; import { MonitorSettings } from '../../../node/monitor-settings/monitor-settings-provider'; +import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state'; @injectable() export class MonitorWidget extends ReactWidget { @@ -40,40 +51,46 @@ export class MonitorWidget extends ReactWidget { protected closing = false; protected readonly clearOutputEmitter = new Emitter<void>(); - constructor( - @inject(MonitorModel) - protected readonly monitorModel: MonitorModel, + @inject(MonitorModel) + private readonly monitorModel: MonitorModel; + @inject(MonitorManagerProxyClient) + private readonly monitorManagerProxy: MonitorManagerProxyClient; + @inject(BoardsServiceProvider) + private readonly boardsServiceProvider: BoardsServiceProvider; + @inject(FrontendApplicationStateService) + private readonly appStateService: FrontendApplicationStateService; - @inject(MonitorManagerProxyClient) - protected readonly monitorManagerProxy: MonitorManagerProxyClient, + private readonly toDisposeOnReset: DisposableCollection; - @inject(BoardsServiceProvider) - protected readonly boardsServiceProvider: BoardsServiceProvider - ) { + constructor() { super(); this.id = MonitorWidget.ID; this.title.label = MonitorWidget.LABEL; this.title.iconClass = 'monitor-tab-icon'; this.title.closable = true; this.scrollOptions = undefined; + this.toDisposeOnReset = new DisposableCollection(); this.toDispose.push(this.clearOutputEmitter); - this.toDispose.push( - Disposable.create(() => this.monitorManagerProxy.disconnect()) - ); } - protected override onBeforeAttach(msg: Message): void { - this.update(); - this.toDispose.push(this.monitorModel.onChange(() => this.update())); - this.getCurrentSettings().then(this.onMonitorSettingsDidChange.bind(this)); - this.monitorManagerProxy.onMonitorSettingsDidChange( - this.onMonitorSettingsDidChange.bind(this) - ); + @postConstruct() + protected init(): void { + this.toDisposeOnReset.dispose(); + this.toDisposeOnReset.pushAll([ + Disposable.create(() => this.monitorManagerProxy.disconnect()), + this.monitorModel.onChange(() => this.update()), + this.monitorManagerProxy.onMonitorSettingsDidChange((event) => + this.updateSettings(event) + ), + ]); + this.startMonitor(); + } - this.monitorManagerProxy.startMonitor(); + reset(): void { + this.init(); } - onMonitorSettingsDidChange(settings: MonitorSettings): void { + private updateSettings(settings: MonitorSettings): void { this.settings = { ...this.settings, pluggableMonitorSettings: { @@ -90,6 +107,7 @@ export class MonitorWidget extends ReactWidget { } override dispose(): void { + this.toDisposeOnReset.dispose(); super.dispose(); } @@ -122,7 +140,7 @@ export class MonitorWidget extends ReactWidget { this.update(); } - protected onFocusResolved = (element: HTMLElement | undefined) => { + protected onFocusResolved = (element: HTMLElement | undefined): void => { if (this.closing || !this.isAttached) { return; } @@ -132,7 +150,7 @@ export class MonitorWidget extends ReactWidget { ); }; - protected get lineEndings(): SerialMonitorOutput.SelectOption<MonitorModel.EOL>[] { + protected get lineEndings(): SerialMonitorOutput.SelectOption<MonitorEOL>[] { return [ { label: nls.localize('arduino/serial/noLineEndings', 'No Line Ending'), @@ -156,11 +174,23 @@ export class MonitorWidget extends ReactWidget { ]; } - private getCurrentSettings(): Promise<MonitorSettings> { + private async startMonitor(): Promise<void> { + await this.appStateService.reachedState('ready'); + await this.boardsServiceProvider.reconciled; + await this.syncSettings(); + await this.monitorManagerProxy.startMonitor(); + } + + private async syncSettings(): Promise<void> { + const settings = await this.getCurrentSettings(); + this.updateSettings(settings); + } + + private async getCurrentSettings(): Promise<MonitorSettings> { const board = this.boardsServiceProvider.boardsConfig.selectedBoard; const port = this.boardsServiceProvider.boardsConfig.selectedPort; if (!board || !port) { - return Promise.resolve(this.settings || {}); + return this.settings || {}; } return this.monitorManagerProxy.getCurrentSettings(board, port); } @@ -171,7 +201,7 @@ export class MonitorWidget extends ReactWidget { : undefined; const baudrateOptions = baudrate?.values.map((b) => ({ - label: b + ' baud', + label: nls.localize('arduino/monitor/baudRate', '{0} baud', b), value: b, })); const baudrateSelectedOption = baudrateOptions?.find( @@ -181,7 +211,7 @@ export class MonitorWidget extends ReactWidget { const lineEnding = this.lineEndings.find( (item) => item.value === this.monitorModel.lineEnding - ) || this.lineEndings[1]; // Defaults to `\n`. + ) || MonitorEOL.DEFAULT; return ( <div className="serial-monitor"> @@ -228,13 +258,13 @@ export class MonitorWidget extends ReactWidget { ); } - protected readonly onSend = (value: string) => this.doSend(value); - protected async doSend(value: string): Promise<void> { + protected readonly onSend = (value: string): void => this.doSend(value); + protected doSend(value: string): void { this.monitorManagerProxy.send(value); } protected readonly onChangeLineEnding = ( - option: SerialMonitorOutput.SelectOption<MonitorModel.EOL> + option: SerialMonitorOutput.SelectOption<MonitorEOL> ): void => { this.monitorModel.lineEnding = option.value; }; diff --git a/arduino-ide-extension/src/browser/serial/monitor/serial-monitor-send-input.tsx b/arduino-ide-extension/src/browser/serial/monitor/serial-monitor-send-input.tsx index 163fdbafd..21e54e2fd 100644 --- a/arduino-ide-extension/src/browser/serial/monitor/serial-monitor-send-input.tsx +++ b/arduino-ide-extension/src/browser/serial/monitor/serial-monitor-send-input.tsx @@ -5,6 +5,10 @@ import { DisposableCollection, nls } from '@theia/core/lib/common'; import { BoardsServiceProvider } from '../../boards/boards-service-provider'; import { MonitorModel } from '../../monitor-model'; import { Unknown } from '../../../common/nls'; +import { + isMonitorConnectionError, + MonitorConnectionStatus, +} from '../../../common/protocol'; class HistoryList { private readonly items: string[] = []; @@ -62,7 +66,7 @@ export namespace SerialMonitorSendInput { } export interface State { text: string; - connected: boolean; + connectionStatus: MonitorConnectionStatus; history: HistoryList; } } @@ -75,18 +79,27 @@ export class SerialMonitorSendInput extends React.Component< constructor(props: Readonly<SerialMonitorSendInput.Props>) { super(props); - this.state = { text: '', connected: true, history: new HistoryList() }; + this.state = { + text: '', + connectionStatus: 'not-connected', + history: new HistoryList(), + }; this.onChange = this.onChange.bind(this); this.onSend = this.onSend.bind(this); this.onKeyDown = this.onKeyDown.bind(this); } override componentDidMount(): void { - this.setState({ connected: this.props.monitorModel.connected }); + this.setState({ + connectionStatus: this.props.monitorModel.connectionStatus, + }); this.toDisposeBeforeUnmount.push( this.props.monitorModel.onChange(({ property }) => { - if (property === 'connected') - this.setState({ connected: this.props.monitorModel.connected }); + if (property === 'connected' || property === 'connectionStatus') { + this.setState({ + connectionStatus: this.props.monitorModel.connectionStatus, + }); + } }) ); } @@ -97,44 +110,83 @@ export class SerialMonitorSendInput extends React.Component< } override render(): React.ReactNode { + const status = this.state.connectionStatus; + const input = this.renderInput(status); + if (status !== 'connecting') { + return input; + } + return <label>{input}</label>; + } + + private renderInput(status: MonitorConnectionStatus): React.ReactNode { + const inputClassName = this.inputClassName(status); + const placeholder = this.placeholder; + const readOnly = Boolean(inputClassName); return ( <input ref={this.setRef} type="text" - className={`theia-input ${this.shouldShowWarning() ? 'warning' : ''}`} - placeholder={this.placeholder} - value={this.state.text} + className={`theia-input ${inputClassName}`} + readOnly={readOnly} + placeholder={placeholder} + title={placeholder} + value={readOnly ? '' : this.state.text} // always show the placeholder if cannot edit the <input> onChange={this.onChange} onKeyDown={this.onKeyDown} /> ); } + private inputClassName( + status: MonitorConnectionStatus + ): 'error' | 'warning' | '' { + if (isMonitorConnectionError(status)) { + return 'error'; + } + if (status === 'connected') { + return ''; + } + return 'warning'; + } + protected shouldShowWarning(): boolean { const board = this.props.boardsServiceProvider.boardsConfig.selectedBoard; const port = this.props.boardsServiceProvider.boardsConfig.selectedPort; - return !this.state.connected || !board || !port; + return !this.state.connectionStatus || !board || !port; } protected get placeholder(): string { - if (this.shouldShowWarning()) { + const status = this.state.connectionStatus; + if (isMonitorConnectionError(status)) { + return status.errorMessage; + } + if (status === 'not-connected') { return nls.localize( 'arduino/serial/notConnected', 'Not connected. Select a board and a port to connect automatically.' ); } - const board = this.props.boardsServiceProvider.boardsConfig.selectedBoard; const port = this.props.boardsServiceProvider.boardsConfig.selectedPort; + const boardLabel = board + ? Board.toString(board, { + useFqbn: false, + }) + : Unknown; + const portLabel = port ? port.address : Unknown; + if (status === 'connecting') { + return nls.localize( + 'arduino/serial/connecting', + "Connecting to '{0}' on '{1}'...", + boardLabel, + portLabel + ); + } return nls.localize( 'arduino/serial/message', "Message (Enter to send message to '{0}' on '{1}')", - board - ? Board.toString(board, { - useFqbn: false, - }) - : Unknown, - port ? port.address : Unknown + boardLabel, + portLabel ); } diff --git a/arduino-ide-extension/src/browser/style/index.css b/arduino-ide-extension/src/browser/style/index.css index d0ac1e45e..4698d4a33 100644 --- a/arduino-ide-extension/src/browser/style/index.css +++ b/arduino-ide-extension/src/browser/style/index.css @@ -29,9 +29,11 @@ /* https://github.com/arduino/arduino-ide/pull/1662#issuecomment-1324997134 */ body { --theia-icon-loading: url(../icons/loading-light.svg); + --theia-icon-loading-warning: url(../icons/loading-dark.svg); } body.theia-dark { --theia-icon-loading: url(../icons/loading-dark.svg); + --theia-icon-loading-warning: url(../icons/loading-light.svg); } .theia-input.warning:focus { @@ -48,22 +50,32 @@ body.theia-dark { } .theia-input.warning::placeholder { - /* Chrome, Firefox, Opera, Safari 10.1+ */ color: var(--theia-warningForeground); background-color: var(--theia-warningBackground); - opacity: 1; /* Firefox */ } -.theia-input.warning:-ms-input-placeholder { - /* Internet Explorer 10-11 */ - color: var(--theia-warningForeground); - background-color: var(--theia-warningBackground); +.hc-black.hc-theia.theia-hc .theia-input.warning, +.hc-black.hc-theia.theia-hc .theia-input.warning::placeholder { + color: var(--theia-warningBackground); + background-color: var(--theia-warningForeground); } -.theia-input.warning::-ms-input-placeholder { - /* Microsoft Edge */ - color: var(--theia-warningForeground); - background-color: var(--theia-warningBackground); +.theia-input.error:focus { + outline-width: 1px; + outline-style: solid; + outline-offset: -1px; + opacity: 1 !important; + color: var(--theia-errorForeground); + background-color: var(--theia-errorBackground); +} + +.theia-input.error { + background-color: var(--theia-errorBackground); +} + +.theia-input.error::placeholder { + color: var(--theia-errorForeground); + background-color: var(--theia-errorBackground); } /* Makes the sidepanel a bit wider when opening the widget */ diff --git a/arduino-ide-extension/src/browser/style/monitor.css b/arduino-ide-extension/src/browser/style/monitor.css index fdcdfc21c..6787ea4cb 100644 --- a/arduino-ide-extension/src/browser/style/monitor.css +++ b/arduino-ide-extension/src/browser/style/monitor.css @@ -20,22 +20,47 @@ .serial-monitor .head { display: flex; - padding: 5px; + padding: 0px 5px 5px 0px; height: 27px; + background-color: var(--theia-activityBar-background); } .serial-monitor .head .send { display: flex; flex: 1; - margin-right: 2px; } -.serial-monitor .head .send > input { +.serial-monitor .head .send > label:before { + content: ""; + position: absolute; + top: -1px; + background: var(--theia-icon-loading-warning) center center no-repeat; + animation: theia-spin 1.25s linear infinite; + width: 30px; + height: 30px; +} + +.serial-monitor .head .send > label { + position: relative; + width: 100%; + display: flex; + align-self: baseline; +} + +.serial-monitor .head .send > input, +.serial-monitor .head .send > label > input { line-height: var(--theia-content-line-height); + height: 27px; width: 100%; } -.serial-monitor .head .send > input:focus { +.serial-monitor .head .send > label > input { + padding-left: 30px; + box-sizing: border-box; +} + +.serial-monitor .head .send > input:focus, +.serial-monitor .head .send > label > input:focus { border-color: var(--theia-focusBorder); } diff --git a/arduino-ide-extension/src/common/protocol/core-service.ts b/arduino-ide-extension/src/common/protocol/core-service.ts index 809f3a7c6..7dfcfb896 100644 --- a/arduino-ide-extension/src/common/protocol/core-service.ts +++ b/arduino-ide-extension/src/common/protocol/core-service.ts @@ -73,12 +73,12 @@ export namespace CoreError { UploadUsingProgrammer: 4003, BurnBootloader: 4004, }; - export const VerifyFailed = create(Codes.Verify); - export const UploadFailed = create(Codes.Upload); - export const UploadUsingProgrammerFailed = create( + export const VerifyFailed = declareCoreError(Codes.Verify); + export const UploadFailed = declareCoreError(Codes.Upload); + export const UploadUsingProgrammerFailed = declareCoreError( Codes.UploadUsingProgrammer ); - export const BurnBootloaderFailed = create(Codes.BurnBootloader); + export const BurnBootloaderFailed = declareCoreError(Codes.BurnBootloader); export function is( error: unknown ): error is ApplicationError<number, ErrorLocation[]> { @@ -88,7 +88,7 @@ export namespace CoreError { Object.values(Codes).includes(error.code) ); } - function create( + function declareCoreError( code: number ): ApplicationError.Constructor<number, ErrorLocation[]> { return ApplicationError.declare( diff --git a/arduino-ide-extension/src/common/protocol/monitor-service.ts b/arduino-ide-extension/src/common/protocol/monitor-service.ts index 7374951db..6c9bbcac9 100644 --- a/arduino-ide-extension/src/common/protocol/monitor-service.ts +++ b/arduino-ide-extension/src/common/protocol/monitor-service.ts @@ -1,4 +1,4 @@ -import { Event, JsonRpcServer } from '@theia/core'; +import { ApplicationError, Event, JsonRpcServer, nls } from '@theia/core'; import { PluggableMonitorSettings, MonitorSettings, @@ -31,7 +31,7 @@ export interface MonitorManagerProxyClient { onMessagesReceived: Event<{ messages: string[] }>; onMonitorSettingsDidChange: Event<MonitorSettings>; onMonitorShouldReset: Event<void>; - connect(addressPort: number): void; + connect(addressPort: number): Promise<void>; disconnect(): void; getWebSocketPort(): number | undefined; isWSConnected(): Promise<boolean>; @@ -46,7 +46,7 @@ export interface PluggableMonitorSetting { readonly id: string; // A human-readable label of the setting (to be displayed on the GUI) readonly label: string; - // The setting type (at the moment only "enum" is avaiable) + // The setting type (at the moment only "enum" is available) readonly type: string; // The values allowed on "enum" types readonly values: string[]; @@ -72,24 +72,168 @@ export namespace Monitor { }; } -export interface Status {} -export type OK = Status; -export interface ErrorStatus extends Status { - readonly message: string; +export const MonitorErrorCodes = { + ConnectionFailed: 6001, + NotConnected: 6002, + AlreadyConnected: 6003, + MissingConfiguration: 6004, +} as const; + +export const ConnectionFailedError = declareMonitorError( + MonitorErrorCodes.ConnectionFailed +); +export const NotConnectedError = declareMonitorError( + MonitorErrorCodes.NotConnected +); +export const AlreadyConnectedError = declareMonitorError( + MonitorErrorCodes.AlreadyConnected +); +export const MissingConfigurationError = declareMonitorError( + MonitorErrorCodes.MissingConfiguration +); + +export function createConnectionFailedError( + port: Port, + details?: string +): ApplicationError<number, PortDescriptor> { + const { protocol, address } = port; + let message; + if (details) { + const detailsWithPeriod = details.endsWith('.') ? details : `${details}.`; + message = nls.localize( + 'arduino/monitor/connectionFailedErrorWithDetails', + '{0} Could not connect to {1} {2} port.', + detailsWithPeriod, + address, + protocol + ); + } else { + message = nls.localize( + 'arduino/monitor/connectionFailedError', + 'Could not connect to {0} {1} port.', + address, + protocol + ); + } + return ConnectionFailedError(message, { protocol, address }); +} +export function createNotConnectedError( + port: Port +): ApplicationError<number, PortDescriptor> { + const { protocol, address } = port; + return NotConnectedError( + nls.localize( + 'arduino/monitor/notConnectedError', + 'Not connected to {0} {1} port.', + address, + protocol + ), + { protocol, address } + ); +} +export function createAlreadyConnectedError( + port: Port +): ApplicationError<number, PortDescriptor> { + const { protocol, address } = port; + return AlreadyConnectedError( + nls.localize( + 'arduino/monitor/alreadyConnectedError', + 'Could not connect to {0} {1} port. Already connected.', + address, + protocol + ), + { protocol, address } + ); +} +export function createMissingConfigurationError( + port: Port +): ApplicationError<number, PortDescriptor> { + const { protocol, address } = port; + return MissingConfigurationError( + nls.localize( + 'arduino/monitor/missingConfigurationError', + 'Could not connect to {0} {1} port. The monitor configuration is missing.', + address, + protocol + ), + { protocol, address } + ); +} + +/** + * Bare minimum representation of a port. Supports neither UI labels nor properties. + */ +interface PortDescriptor { + readonly protocol: string; + readonly address: string; +} +function declareMonitorError( + code: number +): ApplicationError.Constructor<number, PortDescriptor> { + return ApplicationError.declare( + code, + (message: string, data: PortDescriptor) => ({ data, message }) + ); +} + +export interface MonitorConnectionError { + readonly errorMessage: string; +} + +export type MonitorConnectionStatus = + | 'connecting' + | 'connected' + | 'not-connected' + | MonitorConnectionError; + +export function monitorConnectionStatusEquals( + left: MonitorConnectionStatus, + right: MonitorConnectionStatus +): boolean { + if (typeof left === 'object' && typeof right === 'object') { + return left.errorMessage === right.errorMessage; + } + return left === right; +} + +/** + * @deprecated see `MonitorState#connected` + */ +export function isMonitorConnected( + status: MonitorConnectionStatus +): status is 'connected' { + return status === 'connected'; } -export namespace Status { - export function isOK(status: Status & { message?: string }): status is OK { - return !!status && typeof status.message !== 'string'; + +export function isMonitorConnectionError( + status: MonitorConnectionStatus +): status is MonitorConnectionError { + return typeof status === 'object'; +} + +export interface MonitorState { + autoscroll: boolean; + timestamp: boolean; + lineEnding: MonitorEOL; + interpolate: boolean; + darkTheme: boolean; + wsPort: number; + serialPort: string; + connectionStatus: MonitorConnectionStatus; + /** + * @deprecated This property is never get by IDE2 only set. This value is present to be backward compatible with the plotter app. + * IDE2 uses `MonitorState#connectionStatus`. + */ + connected: boolean; +} +export namespace MonitorState { + export interface Change<K extends keyof MonitorState> { + readonly property: K; + readonly value: MonitorState[K]; } - export const OK: OK = {}; - export const NOT_CONNECTED: ErrorStatus = { message: 'Not connected.' }; - export const ALREADY_CONNECTED: ErrorStatus = { - message: 'Already connected.', - }; - export const CONFIG_MISSING: ErrorStatus = { - message: 'Serial Config missing.', - }; - export const UPLOAD_IN_PROGRESS: ErrorStatus = { - message: 'Upload in progress.', - }; +} + +export type MonitorEOL = '' | '\n' | '\r' | '\r\n'; +export namespace MonitorEOL { + export const DEFAULT: MonitorEOL = '\n'; } diff --git a/arduino-ide-extension/src/node/core-service-impl.ts b/arduino-ide-extension/src/node/core-service-impl.ts index f438ca2e6..08cfe4260 100644 --- a/arduino-ide-extension/src/node/core-service-impl.ts +++ b/arduino-ide-extension/src/node/core-service-impl.ts @@ -23,7 +23,7 @@ import { UploadUsingProgrammerResponse, } from './cli-protocol/cc/arduino/cli/commands/v1/upload_pb'; import { ResponseService } from '../common/protocol/response-service'; -import { OutputMessage, Port, Status } from '../common/protocol'; +import { OutputMessage, Port } from '../common/protocol'; import { ArduinoCoreServiceClient } from './cli-protocol/cc/arduino/cli/commands/v1/commands_grpc_pb'; import { Port as RpcPort } from './cli-protocol/cc/arduino/cli/commands/v1/port_pb'; import { ApplicationError, CommandService, Disposable, nls } from '@theia/core'; @@ -392,7 +392,7 @@ export class CoreServiceImpl extends CoreClientAware implements CoreService { }: { fqbn?: string | undefined; port?: Port | undefined; - }): Promise<Status> { + }): Promise<void> { this.boardDiscovery.setUploadInProgress(false); return this.monitorManager.notifyUploadFinished(fqbn, port); } diff --git a/arduino-ide-extension/src/node/monitor-manager-proxy-impl.ts b/arduino-ide-extension/src/node/monitor-manager-proxy-impl.ts index 7f284ac3f..079b85d48 100644 --- a/arduino-ide-extension/src/node/monitor-manager-proxy-impl.ts +++ b/arduino-ide-extension/src/node/monitor-manager-proxy-impl.ts @@ -2,7 +2,6 @@ import { inject, injectable } from '@theia/core/shared/inversify'; import { MonitorManagerProxy, MonitorManagerProxyClient, - Status, } from '../common/protocol'; import { Board, Port } from '../common/protocol'; import { MonitorManager } from './monitor-manager'; @@ -41,11 +40,16 @@ export class MonitorManagerProxyImpl implements MonitorManagerProxy { await this.changeMonitorSettings(board, port, settings); } - const connectToClient = (status: Status) => { - if (status === Status.ALREADY_CONNECTED || status === Status.OK) { - // Monitor started correctly, connect it with the frontend - this.client.connect(this.manager.getWebsocketAddressPort(board, port)); + const connectToClient = async () => { + const address = this.manager.getWebsocketAddressPort(board, port); + if (!this.client) { + throw new Error( + `No client was connected to this monitor manager. Board: ${ + board.fqbn ?? board.name + }, port: ${port.address}, address: ${address}` + ); } + await this.client.connect(address); }; return this.manager.startMonitor(board, port, connectToClient); } diff --git a/arduino-ide-extension/src/node/monitor-manager.ts b/arduino-ide-extension/src/node/monitor-manager.ts index 38360a39f..ea63aa8cb 100644 --- a/arduino-ide-extension/src/node/monitor-manager.ts +++ b/arduino-ide-extension/src/node/monitor-manager.ts @@ -1,6 +1,11 @@ import { ILogger } from '@theia/core'; import { inject, injectable, named } from '@theia/core/shared/inversify'; -import { Board, BoardsService, Port, Status } from '../common/protocol'; +import { + AlreadyConnectedError, + Board, + BoardsService, + Port, +} from '../common/protocol'; import { CoreClientAware } from './core-client-provider'; import { MonitorService } from './monitor-service'; import { MonitorServiceFactory } from './monitor-service-factory'; @@ -36,7 +41,7 @@ export class MonitorManager extends CoreClientAware { private monitorServiceStartQueue: { monitorID: string; serviceStartParams: [Board, Port]; - connectToClient: (status: Status) => void; + connectToClient: () => Promise<void>; }[] = []; @inject(MonitorServiceFactory) @@ -104,7 +109,7 @@ export class MonitorManager extends CoreClientAware { async startMonitor( board: Board, port: Port, - connectToClient: (status: Status) => void + connectToClient: () => Promise<void> ): Promise<void> { const monitorID = this.monitorID(board.fqbn, port); @@ -127,8 +132,14 @@ export class MonitorManager extends CoreClientAware { return; } - const result = await monitor.start(); - connectToClient(result); + try { + await connectToClient(); + await monitor.start(); + } catch (err) { + if (!AlreadyConnectedError.is(err)) { + throw err; + } + } } /** @@ -202,8 +213,7 @@ export class MonitorManager extends CoreClientAware { async notifyUploadFinished( fqbn?: string | undefined, port?: Port - ): Promise<Status> { - let status: Status = Status.NOT_CONNECTED; + ): Promise<void> { let portDidChangeOnUpload = false; // We have no way of knowing which monitor @@ -214,7 +224,7 @@ export class MonitorManager extends CoreClientAware { const monitor = this.monitorServices.get(monitorID); if (monitor) { - status = await monitor.start(); + await monitor.start(); } // this monitorID will only be present in "disposedForUpload" @@ -232,7 +242,6 @@ export class MonitorManager extends CoreClientAware { } await this.startQueuedServices(portDidChangeOnUpload); - return status; } async startQueuedServices(portDidChangeOnUpload: boolean): Promise<void> { @@ -246,7 +255,7 @@ export class MonitorManager extends CoreClientAware { for (const { monitorID, - serviceStartParams: [_, port], + serviceStartParams: [, port], connectToClient, } of queued) { const boardsState = await this.boardsService.getState(); @@ -261,8 +270,8 @@ export class MonitorManager extends CoreClientAware { const monitorService = this.monitorServices.get(monitorID); if (monitorService) { - const result = await monitorService.start(); - connectToClient(result); + await connectToClient(); + await monitorService.start(); } } } diff --git a/arduino-ide-extension/src/node/monitor-service.ts b/arduino-ide-extension/src/node/monitor-service.ts index db5f100d7..ff7a9019f 100644 --- a/arduino-ide-extension/src/node/monitor-service.ts +++ b/arduino-ide-extension/src/node/monitor-service.ts @@ -1,8 +1,23 @@ -import { ClientDuplexStream } from '@grpc/grpc-js'; -import { Disposable, Emitter, ILogger } from '@theia/core'; +import { ClientDuplexStream, status } from '@grpc/grpc-js'; +import { + ApplicationError, + Disposable, + Emitter, + ILogger, + nls, +} from '@theia/core'; import { inject, named, postConstruct } from '@theia/core/shared/inversify'; import { diff, Operation } from 'just-diff'; -import { Board, Port, Status, Monitor } from '../common/protocol'; +import { + Board, + Port, + Monitor, + createAlreadyConnectedError, + createMissingConfigurationError, + createNotConnectedError, + createConnectionFailedError, + isMonitorConnected, +} from '../common/protocol'; import { EnumerateMonitorPortSettingsRequest, EnumerateMonitorPortSettingsResponse, @@ -19,8 +34,13 @@ import { PluggableMonitorSettings, MonitorSettingsProvider, } from './monitor-settings/monitor-settings-provider'; -import { Deferred } from '@theia/core/lib/common/promise-util'; +import { + Deferred, + retry, + timeoutReject, +} from '@theia/core/lib/common/promise-util'; import { MonitorServiceFactoryOptions } from './monitor-service-factory'; +import { ServiceError } from './service-error'; export const MonitorServiceName = 'monitor-service'; type DuplexHandlerKeys = @@ -76,7 +96,7 @@ export class MonitorService extends CoreClientAware implements Disposable { readonly onDispose = this.onDisposeEmitter.event; private _initialized = new Deferred<void>(); - private creating: Deferred<Status>; + private creating: Deferred<void>; private readonly board: Board; private readonly port: Port; private readonly monitorID: string; @@ -114,7 +134,7 @@ export class MonitorService extends CoreClientAware implements Disposable { this.updateClientsSettings(this.settings); }); - this.portMonitorSettings(this.port.protocol, this.board.fqbn!).then( + this.portMonitorSettings(this.port.protocol, this.board.fqbn!, true).then( async (settings) => { this.settings = { ...this.settings, @@ -154,74 +174,85 @@ export class MonitorService extends CoreClientAware implements Disposable { /** * Start and connects a monitor using currently set board and port. - * If a monitor is already started or board fqbn, port address and/or protocol - * are missing nothing happens. - * @returns a status to verify connection has been established. + * If a monitor is already started, the promise will reject with an `AlreadyConnectedError`. + * If the board fqbn, port address and/or protocol are missing, the promise rejects with a `MissingConfigurationError`. */ - async start(): Promise<Status> { + async start(): Promise<void> { if (this.creating?.state === 'unresolved') return this.creating.promise; this.creating = new Deferred(); if (this.duplex) { this.updateClientsSettings({ - monitorUISettings: { connected: true, serialPort: this.port.address }, + monitorUISettings: { + connectionStatus: 'connected', + connected: true, // TODO: should be removed when plotter app understand the `connectionStatus` message + serialPort: this.port.address, + }, }); - this.creating.resolve(Status.ALREADY_CONNECTED); + this.creating.reject(createAlreadyConnectedError(this.port)); return this.creating.promise; } if (!this.board?.fqbn || !this.port?.address || !this.port?.protocol) { - this.updateClientsSettings({ monitorUISettings: { connected: false } }); + this.updateClientsSettings({ + monitorUISettings: { + connectionStatus: 'not-connected', + connected: false, // TODO: should be removed when plotter app understand the `connectionStatus` message + }, + }); - this.creating.resolve(Status.CONFIG_MISSING); + this.creating.reject(createMissingConfigurationError(this.port)); return this.creating.promise; } this.logger.info('starting monitor'); - // get default monitor settings from the CLI - const defaultSettings = await this.portMonitorSettings( - this.port.protocol, - this.board.fqbn - ); - // get actual settings from the settings provider - this.settings = { - ...this.settings, - pluggableMonitorSettings: { - ...this.settings.pluggableMonitorSettings, - ...(await this.monitorSettingsProvider.getSettings( - this.monitorID, - defaultSettings - )), - }, - }; + try { + // get default monitor settings from the CLI + const defaultSettings = await this.portMonitorSettings( + this.port.protocol, + this.board.fqbn + ); - const coreClient = await this.coreClient; + this.updateClientsSettings({ + monitorUISettings: { connectionStatus: 'connecting' }, + }); - const { instance } = coreClient; - const monitorRequest = new MonitorRequest(); - monitorRequest.setInstance(instance); - if (this.board?.fqbn) { - monitorRequest.setFqbn(this.board.fqbn); - } - if (this.port?.address && this.port?.protocol) { - const rpcPort = new RpcPort(); - rpcPort.setAddress(this.port.address); - rpcPort.setProtocol(this.port.protocol); - monitorRequest.setPort(rpcPort); - } - const config = new MonitorPortConfiguration(); - for (const id in this.settings.pluggableMonitorSettings) { - const s = new MonitorPortSetting(); - s.setSettingId(id); - s.setValue(this.settings.pluggableMonitorSettings[id].selectedValue); - config.addSettings(s); - } - monitorRequest.setPortConfiguration(config); + // get actual settings from the settings provider + this.settings = { + ...this.settings, + pluggableMonitorSettings: { + ...this.settings.pluggableMonitorSettings, + ...(await this.monitorSettingsProvider.getSettings( + this.monitorID, + defaultSettings + )), + }, + }; - const wroteToStreamSuccessfully = await this.pollWriteToStream( - monitorRequest - ); - if (wroteToStreamSuccessfully) { + const coreClient = await this.coreClient; + + const { instance } = coreClient; + const monitorRequest = new MonitorRequest(); + monitorRequest.setInstance(instance); + if (this.board?.fqbn) { + monitorRequest.setFqbn(this.board.fqbn); + } + if (this.port?.address && this.port?.protocol) { + const rpcPort = new RpcPort(); + rpcPort.setAddress(this.port.address); + rpcPort.setProtocol(this.port.protocol); + monitorRequest.setPort(rpcPort); + } + const config = new MonitorPortConfiguration(); + for (const id in this.settings.pluggableMonitorSettings) { + const s = new MonitorPortSetting(); + s.setSettingId(id); + s.setValue(this.settings.pluggableMonitorSettings[id].selectedValue); + config.addSettings(s); + } + monitorRequest.setPortConfiguration(config); + + await this.pollWriteToStream(monitorRequest); // Only store the config, if the monitor has successfully started. this.currentPortConfigSnapshot = MonitorPortConfiguration.toObject( false, @@ -237,15 +268,34 @@ export class MonitorService extends CoreClientAware implements Disposable { `started monitor to ${this.port?.address} using ${this.port?.protocol}` ); this.updateClientsSettings({ - monitorUISettings: { connected: true, serialPort: this.port.address }, + monitorUISettings: { + connectionStatus: 'connected', + connected: true, // TODO: should be removed when plotter app understand the `connectionStatus` message + serialPort: this.port.address, + }, }); - this.creating.resolve(Status.OK); + this.creating.resolve(); return this.creating.promise; - } else { + } catch (err) { this.logger.warn( `failed starting monitor to ${this.port?.address} using ${this.port?.protocol}` ); - this.creating.resolve(Status.NOT_CONNECTED); + const appError = ApplicationError.is(err) + ? err + : createConnectionFailedError( + this.port, + ServiceError.is(err) + ? err.details + : err instanceof Error + ? err.message + : String(err) + ); + this.creating.reject(appError); + this.updateClientsSettings({ + monitorUISettings: { + connectionStatus: { errorMessage: appError.message }, + }, + }); return this.creating.promise; } } @@ -264,19 +314,29 @@ export class MonitorService extends CoreClientAware implements Disposable { // default handlers duplex .on('close', () => { - this.duplex = null; - this.updateClientsSettings({ - monitorUISettings: { connected: false }, - }); + if (duplex === this.duplex) { + this.duplex = null; + this.updateClientsSettings({ + monitorUISettings: { + connected: false, // TODO: should be removed when plotter app understand the `connectionStatus` message + connectionStatus: 'not-connected', + }, + }); + } this.logger.info( `monitor to ${this.port?.address} using ${this.port?.protocol} closed by client` ); }) .on('end', () => { - this.duplex = null; - this.updateClientsSettings({ - monitorUISettings: { connected: false }, - }); + if (duplex === this.duplex) { + this.duplex = null; + this.updateClientsSettings({ + monitorUISettings: { + connected: false, // TODO: should be removed when plotter app understand the `connectionStatus` message + connectionStatus: 'not-connected', + }, + }); + } this.logger.info( `monitor to ${this.port?.address} using ${this.port?.protocol} closed by server` ); @@ -287,21 +347,17 @@ export class MonitorService extends CoreClientAware implements Disposable { } } - pollWriteToStream(request: MonitorRequest): Promise<boolean> { - let attemptsRemaining = MAX_WRITE_TO_STREAM_TRIES; - const writeTimeoutMs = WRITE_TO_STREAM_TIMEOUT_MS; - + pollWriteToStream(request: MonitorRequest): Promise<void> { const createWriteToStreamExecutor = (duplex: ClientDuplexStream<MonitorRequest, MonitorResponse>) => - (resolve: (value: boolean) => void, reject: () => void) => { + (resolve: () => void, reject: (reason?: unknown) => void) => { const resolvingDuplexHandlers: DuplexHandler[] = [ { key: 'error', callback: async (err: Error) => { this.logger.error(err); - resolve(false); - // TODO - // this.theiaFEClient?.notifyError() + const details = ServiceError.is(err) ? err.details : err.message; + reject(createConnectionFailedError(this.port, details)); }, }, { @@ -313,79 +369,47 @@ export class MonitorService extends CoreClientAware implements Disposable { return; } if (monitorResponse.getSuccess()) { - resolve(true); + resolve(); return; } const data = monitorResponse.getRxData(); const message = typeof data === 'string' ? data - : this.streamingTextDecoder.decode(data, {stream:true}); + : this.streamingTextDecoder.decode(data, { stream: true }); this.messages.push(...splitLines(message)); }, }, ]; this.setDuplexHandlers(duplex, resolvingDuplexHandlers); - - setTimeout(() => { - reject(); - }, writeTimeoutMs); duplex.write(request); }; - const pollWriteToStream = new Promise<boolean>((resolve) => { - const startPolling = async () => { - // here we create a new duplex but we don't yet - // set "this.duplex", nor do we use "this.duplex" in our poll - // as duplex 'end' / 'close' events (which we do not "await") - // will set "this.duplex" to null - const createdDuplex = await this.createDuplex(); - - let pollingIsSuccessful; - // attempt a "writeToStream" and "await" CLI response: success (true) or error (false) - // if we get neither within WRITE_TO_STREAM_TIMEOUT_MS or an error we get undefined - try { - const writeToStream = createWriteToStreamExecutor(createdDuplex); - pollingIsSuccessful = await new Promise(writeToStream); - } catch (error) { - this.logger.error(error); - } - - // CLI confirmed port opened successfully - if (pollingIsSuccessful) { - this.duplex = createdDuplex; - resolve(true); - return; - } - - // if "pollingIsSuccessful" is false - // the CLI gave us an error, lets try again - // after waiting 2 seconds if we've not already - // reached MAX_WRITE_TO_STREAM_TRIES - if (pollingIsSuccessful === false) { - attemptsRemaining -= 1; - if (attemptsRemaining > 0) { - setTimeout(startPolling, 2000); - return; - } else { - resolve(false); - return; + return Promise.race([ + retry( + async () => { + let createdDuplex = undefined; + try { + createdDuplex = await this.createDuplex(); + await new Promise<void>(createWriteToStreamExecutor(createdDuplex)); + this.duplex = createdDuplex; + } catch (err) { + createdDuplex?.end(); + throw err; } - } - - // "pollingIsSuccessful" remains undefined: - // we got no response from the CLI within 30 seconds - // resolve to false and end the duplex connection - resolve(false); - createdDuplex.end(); - return; - }; - - startPolling(); - }); - - return pollWriteToStream; + }, + 2_000, + MAX_WRITE_TO_STREAM_TRIES + ), + timeoutReject( + WRITE_TO_STREAM_TIMEOUT_MS, + nls.localize( + 'arduino/monitor/connectionTimeout', + "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it" + ) + ), + ]) as Promise<unknown> as Promise<void>; } /** @@ -429,9 +453,9 @@ export class MonitorService extends CoreClientAware implements Disposable { * @param message string sent to running monitor * @returns a status to verify message has been sent. */ - async send(message: string): Promise<Status> { + async send(message: string): Promise<void> { if (!this.duplex) { - return Status.NOT_CONNECTED; + throw createNotConnectedError(this.port); } const coreClient = await this.coreClient; const { instance } = coreClient; @@ -439,14 +463,12 @@ export class MonitorService extends CoreClientAware implements Disposable { const req = new MonitorRequest(); req.setInstance(instance); req.setTxData(new TextEncoder().encode(message)); - return new Promise<Status>((resolve) => { + return new Promise<void>((resolve, reject) => { if (this.duplex) { - this.duplex?.write(req, () => { - resolve(Status.OK); - }); + this.duplex?.write(req, resolve); return; } - this.stop().then(() => resolve(Status.NOT_CONNECTED)); + this.stop().then(() => reject(createNotConnectedError(this.port))); }); } @@ -469,7 +491,8 @@ export class MonitorService extends CoreClientAware implements Disposable { */ private async portMonitorSettings( protocol: string, - fqbn: string + fqbn: string, + swallowsPlatformNotFoundError = false ): Promise<PluggableMonitorSettings> { const coreClient = await this.coreClient; const { client, instance } = coreClient; @@ -478,19 +501,33 @@ export class MonitorService extends CoreClientAware implements Disposable { req.setPortProtocol(protocol); req.setFqbn(fqbn); - const res = await new Promise<EnumerateMonitorPortSettingsResponse>( - (resolve, reject) => { - client.enumerateMonitorPortSettings(req, (err, resp) => { - if (!!err) { - reject(err); + const resp = await new Promise< + EnumerateMonitorPortSettingsResponse | undefined + >((resolve, reject) => { + client.enumerateMonitorPortSettings(req, async (err, resp) => { + if (err) { + // Check whether the platform is installed: https://github.com/arduino/arduino-ide/issues/1974. + // No error codes. Look for `Unknown FQBN: platform arduino:mbed_nano is not installed` message similarities: https://github.com/arduino/arduino-cli/issues/1762. + if ( + swallowsPlatformNotFoundError && + ServiceError.is(err) && + err.code === status.NOT_FOUND && + err.details.includes('FQBN') && + err.details.includes(fqbn.split(':', 2).join(':')) // create a platform ID from the FQBN + ) { + resolve(undefined); } - resolve(resp); - }); - } - ); + reject(err); + } + resolve(resp); + }); + }); const settings: PluggableMonitorSettings = {}; - for (const iterator of res.getSettingsList()) { + if (!resp) { + return settings; + } + for (const iterator of resp.getSettingsList()) { settings[iterator.getSettingId()] = { id: iterator.getSettingId(), label: iterator.getLabel(), @@ -510,7 +547,7 @@ export class MonitorService extends CoreClientAware implements Disposable { * @param settings map of monitor settings to change * @returns a status to verify settings have been sent. */ - async changeSettings(settings: MonitorSettings): Promise<Status> { + async changeSettings(settings: MonitorSettings): Promise<void> { const config = new MonitorPortConfiguration(); const { pluggableMonitorSettings } = settings; const reconciledSettings = await this.monitorSettingsProvider.setSettings( @@ -527,17 +564,23 @@ export class MonitorService extends CoreClientAware implements Disposable { } } + const connectionStatus = Boolean(this.duplex) + ? 'connected' + : 'not-connected'; this.updateClientsSettings({ monitorUISettings: { ...settings.monitorUISettings, - connected: !!this.duplex, + connectionStatus, serialPort: this.port.address, + connected: isMonitorConnected(connectionStatus), // TODO: should be removed when plotter app understand the `connectionStatus` message }, pluggableMonitorSettings: reconciledSettings, }); if (!this.duplex) { - return Status.NOT_CONNECTED; + // instead of throwing an error, return silently like the original logic + // https://github.com/arduino/arduino-ide/blob/9b49712669b06c97bda68a1e5f04eee4664c13f8/arduino-ide-extension/src/node/monitor-service.ts#L540 + return; } const diffConfig = this.maybeUpdatePortConfigSnapshot(config); @@ -545,7 +588,7 @@ export class MonitorService extends CoreClientAware implements Disposable { this.logger.info( `No port configuration changes have been detected. No need to send configure commands to the running monitor ${this.port.protocol}:${this.port.address}.` ); - return Status.OK; + return; } const coreClient = await this.coreClient; @@ -560,7 +603,6 @@ export class MonitorService extends CoreClientAware implements Disposable { req.setInstance(instance); req.setPortConfiguration(diffConfig); this.duplex.write(req); - return Status.OK; } /** @@ -688,6 +730,26 @@ export class MonitorService extends CoreClientAware implements Disposable { updateClientsSettings(settings: MonitorSettings): void { this.settings = { ...this.settings, ...settings }; + if ( + settings.monitorUISettings?.connectionStatus && + !('connected' in settings.monitorUISettings) + ) { + // Make sure the deprecated `connected` prop is set. + settings.monitorUISettings.connected = isMonitorConnected( + settings.monitorUISettings.connectionStatus + ); + } + if ( + typeof settings.monitorUISettings?.connected === 'boolean' && + !('connectionStatus' in settings.monitorUISettings) + ) { + // Set the connectionStatus if the message was sent by the plotter which does not handle the new protocol. Assuming that the plotter can send anything. + // https://github.com/arduino/arduino-serial-plotter-webapp#monitor-settings + settings.monitorUISettings.connectionStatus = settings.monitorUISettings + .connected + ? 'connected' + : 'not-connected'; + } const command: Monitor.Message = { command: Monitor.MiddlewareCommand.ON_SETTINGS_DID_CHANGE, data: settings, diff --git a/arduino-ide-extension/src/node/monitor-settings/monitor-settings-provider.ts b/arduino-ide-extension/src/node/monitor-settings/monitor-settings-provider.ts index e8949a60b..293751781 100644 --- a/arduino-ide-extension/src/node/monitor-settings/monitor-settings-provider.ts +++ b/arduino-ide-extension/src/node/monitor-settings/monitor-settings-provider.ts @@ -1,10 +1,9 @@ -import { MonitorModel } from '../../browser/monitor-model'; -import { PluggableMonitorSetting } from '../../common/protocol'; +import { MonitorState, PluggableMonitorSetting } from '../../common/protocol'; export type PluggableMonitorSettings = Record<string, PluggableMonitorSetting>; export interface MonitorSettings { pluggableMonitorSettings?: PluggableMonitorSettings; - monitorUISettings?: Partial<MonitorModel.State>; + monitorUISettings?: Partial<MonitorState>; } export const MonitorSettingsProvider = Symbol('MonitorSettingsProvider'); diff --git a/i18n/en.json b/i18n/en.json index 22419c5bf..320be23f1 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -328,6 +328,13 @@ "tools": "Tools" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Unable to close websocket", "unableToConnectToWebSocket": "Unable to connect to websocket" }, @@ -408,6 +415,7 @@ "serial": { "autoscroll": "Autoscroll", "carriageReturn": "Carriage Return", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Message (Enter to send message to '{0}' on '{1}')", "newLine": "New Line", "newLineCarriageReturn": "Both NL & CR", From 3aee575a358c95f766dec9ceb8bc44f9a681eeb9 Mon Sep 17 00:00:00 2001 From: Akos Kitta <a.kitta@arduino.cc> Date: Wed, 5 Apr 2023 11:34:24 +0200 Subject: [PATCH 23/32] chore(cli): Updated to `0.32.2` CLI Signed-off-by: Akos Kitta <a.kitta@arduino.cc> Co-authored-by: per1234 <accounts@perglass.com> Co-authored-by: Akos Kitta <a.kitta@arduino.cc> --- arduino-ide-extension/package.json | 6 +--- .../arduino/cli/commands/v1/compile_pb.d.ts | 4 --- .../cc/arduino/cli/commands/v1/compile_pb.js | 30 ------------------- 3 files changed, 1 insertion(+), 39 deletions(-) diff --git a/arduino-ide-extension/package.json b/arduino-ide-extension/package.json index 5bd714377..37e682b7f 100644 --- a/arduino-ide-extension/package.json +++ b/arduino-ide-extension/package.json @@ -163,11 +163,7 @@ ], "arduino": { "cli": { - "version": { - "owner": "arduino", - "repo": "arduino-cli", - "commitish": "71a8576" - } + "version": "0.32.2" }, "fwuploader": { "version": "2.2.2" diff --git a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/compile_pb.d.ts b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/compile_pb.d.ts index 5954b8501..692e2a3d5 100644 --- a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/compile_pb.d.ts +++ b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/compile_pb.d.ts @@ -48,9 +48,6 @@ export class CompileRequest extends jspb.Message { getQuiet(): boolean; setQuiet(value: boolean): CompileRequest; - getVidPid(): string; - setVidPid(value: string): CompileRequest; - getJobs(): number; setJobs(value: number): CompileRequest; @@ -122,7 +119,6 @@ export namespace CompileRequest { warnings: string, verbose: boolean, quiet: boolean, - vidPid: string, jobs: number, librariesList: Array<string>, optimizeForDebug: boolean, diff --git a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/compile_pb.js b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/compile_pb.js index d5d0a7812..f32a64b87 100644 --- a/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/compile_pb.js +++ b/arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/compile_pb.js @@ -137,7 +137,6 @@ proto.cc.arduino.cli.commands.v1.CompileRequest.toObject = function(includeInsta warnings: jspb.Message.getFieldWithDefault(msg, 9, ""), verbose: jspb.Message.getBooleanFieldWithDefault(msg, 10, false), quiet: jspb.Message.getBooleanFieldWithDefault(msg, 11, false), - vidPid: jspb.Message.getFieldWithDefault(msg, 12, ""), jobs: jspb.Message.getFieldWithDefault(msg, 14, 0), librariesList: (f = jspb.Message.getRepeatedField(msg, 15)) == null ? undefined : f, optimizeForDebug: jspb.Message.getBooleanFieldWithDefault(msg, 16, false), @@ -232,10 +231,6 @@ proto.cc.arduino.cli.commands.v1.CompileRequest.deserializeBinaryFromReader = fu var value = /** @type {boolean} */ (reader.readBool()); msg.setQuiet(value); break; - case 12: - var value = /** @type {string} */ (reader.readString()); - msg.setVidPid(value); - break; case 14: var value = /** @type {number} */ (reader.readInt32()); msg.setJobs(value); @@ -398,13 +393,6 @@ proto.cc.arduino.cli.commands.v1.CompileRequest.serializeBinaryToWriter = functi f ); } - f = message.getVidPid(); - if (f.length > 0) { - writer.writeString( - 12, - f - ); - } f = message.getJobs(); if (f !== 0) { writer.writeInt32( @@ -733,24 +721,6 @@ proto.cc.arduino.cli.commands.v1.CompileRequest.prototype.setQuiet = function(va }; -/** - * optional string vid_pid = 12; - * @return {string} - */ -proto.cc.arduino.cli.commands.v1.CompileRequest.prototype.getVidPid = function() { - return /** @type {string} */ (jspb.Message.getFieldWithDefault(this, 12, "")); -}; - - -/** - * @param {string} value - * @return {!proto.cc.arduino.cli.commands.v1.CompileRequest} returns this - */ -proto.cc.arduino.cli.commands.v1.CompileRequest.prototype.setVidPid = function(value) { - return jspb.Message.setProto3StringField(this, 12, value); -}; - - /** * optional int32 jobs = 14; * @return {number} From ef5762599a9e58393fd2e635e52f1db165b3f0ee Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Wed, 5 Apr 2023 20:05:59 +0000 Subject: [PATCH 24/32] build(deps): Bump peter-evans/create-pull-request from 4 to 5 Bumps [peter-evans/create-pull-request](https://github.com/peter-evans/create-pull-request) from 4 to 5. - [Release notes](https://github.com/peter-evans/create-pull-request/releases) - [Commits](https://github.com/peter-evans/create-pull-request/compare/v4...v5) --- updated-dependencies: - dependency-name: peter-evans/create-pull-request dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] <support@github.com> --- .github/workflows/i18n-weekly-pull.yml | 2 +- .github/workflows/themes-weekly-pull.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/i18n-weekly-pull.yml b/.github/workflows/i18n-weekly-pull.yml index 435d1e572..9398b0e4f 100644 --- a/.github/workflows/i18n-weekly-pull.yml +++ b/.github/workflows/i18n-weekly-pull.yml @@ -45,7 +45,7 @@ jobs: TRANSIFEX_API_KEY: ${{ secrets.TRANSIFEX_API_KEY }} - name: Create Pull Request - uses: peter-evans/create-pull-request@v4 + uses: peter-evans/create-pull-request@v5 with: commit-message: Updated translation files title: Update translation files diff --git a/.github/workflows/themes-weekly-pull.yml b/.github/workflows/themes-weekly-pull.yml index a236db537..872f3faec 100644 --- a/.github/workflows/themes-weekly-pull.yml +++ b/.github/workflows/themes-weekly-pull.yml @@ -54,7 +54,7 @@ jobs: run: yarn run themes:generate - name: Create Pull Request - uses: peter-evans/create-pull-request@v4 + uses: peter-evans/create-pull-request@v5 with: commit-message: Updated themes title: Update themes From 96da5bb5ea7e85759152e3264d09210174dcf8f3 Mon Sep 17 00:00:00 2001 From: Akos Kitta <1405703+kittaakos@users.noreply.github.com> Date: Thu, 13 Apr 2023 17:53:43 +0200 Subject: [PATCH 25/32] fix: updated to `electron-builder@23.6.0` (#1986) - updated to `electron-builder@23.6.0` - set `CSC_FOR_PULL_REQUEST` env to run notarization for a PR build. Signed-off-by: Akos Kitta <a.kitta@arduino.cc> --- .github/workflows/build.yml | 1 + electron/build/template-package.json | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 1113042eb..6213a4a88 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -99,6 +99,7 @@ jobs: export CSC_LINK="${{ runner.temp }}/signing_certificate.${{ matrix.config.certificate-extension }}" echo "${{ secrets[matrix.config.certificate-secret] }}" | base64 --decode > "$CSC_LINK" export CSC_KEY_PASSWORD="${{ secrets[matrix.config.certificate-password-secret] }}" + export CSC_FOR_PULL_REQUEST=true fi if [ "${{ runner.OS }}" = "Windows" ]; then diff --git a/electron/build/template-package.json b/electron/build/template-package.json index f3692a416..a835ee23e 100644 --- a/electron/build/template-package.json +++ b/electron/build/template-package.json @@ -3,7 +3,7 @@ "author": "Arduino SA", "resolutions": { "**/fs-extra": "^4.0.3", - "electron-builder": "23.0.2" + "electron-builder": "23.6.0" }, "dependencies": { "node-log-rotate": "^0.1.5" @@ -11,7 +11,7 @@ "devDependencies": { "@theia/cli": "1.31.1", "cross-env": "^7.0.2", - "electron-builder": "23.3.3", + "electron-builder": "23.6.0", "electron-notarize": "^1.1.1", "is-ci": "^2.0.0", "ncp": "^2.0.0", From cb2a3712636a6f247abb9fe3657be811f7646624 Mon Sep 17 00:00:00 2001 From: Akos Kitta <a.kitta@arduino.cc> Date: Fri, 31 Mar 2023 16:15:54 +0200 Subject: [PATCH 26/32] fix: update `themeId` settings after theme change In Theia, the theme ID is not always in sync with the persisted `workbench.colorTheme` preference value. For example, one can preview a theme with the `CtrlCmd+K` + `CtrlCmd+T` key chords. On quick pick selection change events, the theme changes, but the change is persisted only on accept (user presses `Enter`). IDE2 has its own way of showing and managing different settings in the UI. When the theme is changed from outside of the IDE2's UI, the model could get out of sync. This PR ensures that on `workbench.colorTheme` preference change, IDE2's settings model is synchronized with persisted Theia preferences. Closes #1987 Signed-off-by: Akos Kitta <a.kitta@arduino.cc> --- .../src/browser/dialogs/settings/settings.ts | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/arduino-ide-extension/src/browser/dialogs/settings/settings.ts b/arduino-ide-extension/src/browser/dialogs/settings/settings.ts index e4923c760..c120d6a9a 100644 --- a/arduino-ide-extension/src/browser/dialogs/settings/settings.ts +++ b/arduino-ide-extension/src/browser/dialogs/settings/settings.ts @@ -123,6 +123,17 @@ export class SettingsService { this._settings = deepClone(settings); this.ready.resolve(); }); + this.preferenceService.onPreferenceChanged(async (event) => { + await this.ready.promise; + const { preferenceName, newValue } = event; + if ( + preferenceName === 'workbench.colorTheme' && + typeof newValue === 'string' && + this._settings.themeId !== newValue + ) { + this.reset(); + } + }); } protected async loadSettings(): Promise<Settings> { From 7cc252fc36608be85c5d9269f498fc76019a8f23 Mon Sep 17 00:00:00 2001 From: Akos Kitta <a.kitta@arduino.cc> Date: Mon, 3 Apr 2023 16:50:09 +0200 Subject: [PATCH 27/32] fix: location of possible drop-in folder for VSIX Closes #1851 Signed-off-by: Akos Kitta <a.kitta@arduino.cc> --- .../build/scripts/arduino-ide-electron-main.js | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/electron/build/scripts/arduino-ide-electron-main.js b/electron/build/scripts/arduino-ide-electron-main.js index 82a63fbec..12ad02e72 100644 --- a/electron/build/scripts/arduino-ide-electron-main.js +++ b/electron/build/scripts/arduino-ide-electron-main.js @@ -1,9 +1,15 @@ const os = require('os'); const path = require('path'); // Enables the discovery of the VS Code extensions in the embedded `plugins` folder in the final app. -process.env.THEIA_DEFAULT_PLUGINS = `local-dir:${path.resolve(__dirname, '..', 'plugins')}`; +process.env.THEIA_DEFAULT_PLUGINS = `local-dir:${path.resolve( + __dirname, + '..', + 'plugins' +)}`; process.env.THEIA_PLUGINS = [ - process.env.THEIA_PLUGINS, - `local-dir:${path.resolve(os.homedir(), '.arduinoProIDE', 'plugins')}` -].filter(Boolean).join(','); + process.env.THEIA_PLUGINS, + `local-dir:${path.resolve(os.homedir(), '.arduinoIDE', 'plugins')}`, +] + .filter(Boolean) + .join(','); require('../src-gen/frontend/electron-main.js'); From 5540170341e791e43bfcac0bb4c8ef305ff10ad0 Mon Sep 17 00:00:00 2001 From: Akos Kitta <a.kitta@arduino.cc> Date: Mon, 3 Apr 2023 15:33:46 +0200 Subject: [PATCH 28/32] feat: removed the non official themes from the UI Closes #1283 Ref eclipse-theia/theia#11151 Signed-off-by: Akos Kitta <a.kitta@arduino.cc> --- .../browser/arduino-ide-frontend-module.ts | 23 +- .../dialogs/settings/settings-component.tsx | 58 ++++- .../src/browser/theia/core/theming.ts | 180 +++++++++++++- .../theia/monaco/monaco-theming-service.ts | 228 +++++++++++++++++- .../src/test/browser/theming.test.ts | 179 ++++++++++++++ i18n/en.json | 8 + 6 files changed, 642 insertions(+), 34 deletions(-) create mode 100644 arduino-ide-extension/src/test/browser/theming.test.ts diff --git a/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts b/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts index 09475690b..8a5b4467a 100644 --- a/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts +++ b/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts @@ -238,7 +238,6 @@ import { UploadFirmwareDialog, UploadFirmwareDialogProps, } from './dialogs/firmware-uploader/firmware-uploader-dialog'; - import { UploadCertificate } from './contributions/upload-certificate'; import { ArduinoFirmwareUploader, @@ -328,9 +327,13 @@ import { NewCloudSketch } from './contributions/new-cloud-sketch'; import { SketchbookCompositeWidget } from './widgets/sketchbook/sketchbook-composite-widget'; import { WindowTitleUpdater } from './theia/core/window-title-updater'; import { WindowTitleUpdater as TheiaWindowTitleUpdater } from '@theia/core/lib/browser/window/window-title-updater'; -import { ThemeServiceWithDB } from './theia/core/theming'; -import { ThemeServiceWithDB as TheiaThemeServiceWithDB } from '@theia/monaco/lib/browser/monaco-indexed-db'; -import { MonacoThemingService } from './theia/monaco/monaco-theming-service'; +import { + MonacoThemingService, + CleanupObsoleteThemes, + ThemesRegistrationSummary, + MonacoThemeRegistry, +} from './theia/monaco/monaco-theming-service'; +import { MonacoThemeRegistry as TheiaMonacoThemeRegistry } from '@theia/monaco/lib/browser/textmate/monaco-theme-registry'; import { MonacoThemingService as TheiaMonacoThemingService } from '@theia/monaco/lib/browser/monaco-theming-service'; import { TypeHierarchyServiceProvider } from './theia/typehierarchy/type-hierarchy-service'; import { TypeHierarchyServiceProvider as TheiaTypeHierarchyServiceProvider } from '@theia/typehierarchy/lib/browser/typehierarchy-service'; @@ -973,11 +976,19 @@ export default new ContainerModule((bind, unbind, isBound, rebind) => { rebind(TheiaWindowTitleUpdater).toService(WindowTitleUpdater); // register Arduino themes - bind(ThemeServiceWithDB).toSelf().inSingletonScope(); - rebind(TheiaThemeServiceWithDB).toService(ThemeServiceWithDB); bind(MonacoThemingService).toSelf().inSingletonScope(); rebind(TheiaMonacoThemingService).toService(MonacoThemingService); + // workaround for themes cannot be removed after registration + // https://github.com/eclipse-theia/theia/issues/11151 + bind(CleanupObsoleteThemes).toSelf().inSingletonScope(); + bind(FrontendApplicationContribution).toService( + CleanupObsoleteThemes + ); + bind(ThemesRegistrationSummary).toSelf().inSingletonScope(); + bind(MonacoThemeRegistry).toSelf().inSingletonScope(); + rebind(TheiaMonacoThemeRegistry).toService(MonacoThemeRegistry); + // disable type-hierarchy support // https://github.com/eclipse-theia/theia/commit/16c88a584bac37f5cf3cc5eb92ffdaa541bda5be bind(TypeHierarchyServiceProvider).toSelf().inSingletonScope(); diff --git a/arduino-ide-extension/src/browser/dialogs/settings/settings-component.tsx b/arduino-ide-extension/src/browser/dialogs/settings/settings-component.tsx index a5249326b..644484f01 100644 --- a/arduino-ide-extension/src/browser/dialogs/settings/settings-component.tsx +++ b/arduino-ide-extension/src/browser/dialogs/settings/settings-component.tsx @@ -24,6 +24,12 @@ import { } from '@theia/core/lib/common/i18n/localization'; import SettingsStepInput from './settings-step-input'; import { InterfaceScale } from '../../contributions/interface-scale'; +import { + userConfigurableThemes, + themeLabelForSettings, + arduinoThemeTypeOf, +} from '../../theia/core/theming'; +import { Theme } from '@theia/core/lib/common/theme'; const maxScale = InterfaceScale.ZoomLevel.toPercentage( InterfaceScale.ZoomLevel.MAX @@ -218,14 +224,10 @@ export class SettingsComponent extends React.Component< <div className="flex-line"> <select className="theia-select" - value={this.props.themeService.getCurrentTheme().label} + value={this.currentThemeLabel} onChange={this.themeDidChange} > - {this.props.themeService.getThemes().map(({ id, label }) => ( - <option key={id} value={label}> - {label} - </option> - ))} + {this.themeSelectOptions} </select> </div> <div className="flex-line"> @@ -333,6 +335,46 @@ export class SettingsComponent extends React.Component< ); } + private get currentThemeLabel(): string { + const currentTheme = this.props.themeService.getCurrentTheme(); + return themeLabelForSettings(currentTheme); + } + + private get separatedThemes(): (Theme | string)[] { + const separatedThemes: (Theme | string)[] = []; + const groupedThemes = userConfigurableThemes(this.props.themeService); + for (const group of groupedThemes) { + for (let i = 0; i < group.length; i++) { + const theme = group[i]; + if (i === 0 && separatedThemes.length) { + const arduinoThemeType = arduinoThemeTypeOf(theme); + separatedThemes.push(`separator-${arduinoThemeType}`); + } + separatedThemes.push(theme); + } + } + return separatedThemes; + } + + private get themeSelectOptions(): React.ReactNode[] { + return this.separatedThemes.map((item) => { + if (typeof item === 'string') { + return ( + // ─ -> BOX DRAWINGS LIGHT HORIZONTAL + <option key={item} disabled> + ────────── + </option> + ); + } + const label = themeLabelForSettings(item); + return ( + <option key={item.id} value={label}> + {label} + </option> + ); + }); + } + private toSelectOptions(language: string | LanguageInfo): JSX.Element { const plain = typeof language === 'string'; const key = plain ? language : language.languageId; @@ -610,8 +652,8 @@ export class SettingsComponent extends React.Component< event: React.ChangeEvent<HTMLSelectElement> ): void => { const { selectedIndex } = event.target.options; - const theme = this.props.themeService.getThemes()[selectedIndex]; - if (theme) { + const theme = this.separatedThemes[selectedIndex]; + if (theme && typeof theme !== 'string') { this.setState({ themeId: theme.id }); if (this.props.themeService.getCurrentTheme().id !== theme.id) { this.props.themeService.setCurrentTheme(theme.id); diff --git a/arduino-ide-extension/src/browser/theia/core/theming.ts b/arduino-ide-extension/src/browser/theia/core/theming.ts index 9f95f780d..b46f04b9b 100644 --- a/arduino-ide-extension/src/browser/theia/core/theming.ts +++ b/arduino-ide-extension/src/browser/theia/core/theming.ts @@ -1,15 +1,19 @@ -import type { Theme } from '@theia/core/lib/common/theme'; -import { injectable } from '@theia/core/shared/inversify'; -import { ThemeServiceWithDB as TheiaThemeServiceWithDB } from '@theia/monaco/lib/browser/monaco-indexed-db'; +import { + BuiltinThemeProvider, + ThemeService, +} from '@theia/core/lib/browser/theming'; +import { nls } from '@theia/core/lib/common/nls'; +import type { Theme, ThemeType } from '@theia/core/lib/common/theme'; +import { assertUnreachable } from '../../../common/utils'; export namespace ArduinoThemes { - export const Light: Theme = { + export const light: Theme = { id: 'arduino-theme', type: 'light', label: 'Light (Arduino)', editorTheme: 'arduino-theme', }; - export const Dark: Theme = { + export const dark: Theme = { id: 'arduino-theme-dark', type: 'dark', label: 'Dark (Arduino)', @@ -17,10 +21,166 @@ export namespace ArduinoThemes { }; } -@injectable() -export class ThemeServiceWithDB extends TheiaThemeServiceWithDB { - protected override init(): void { - this.register(ArduinoThemes.Light, ArduinoThemes.Dark); - super.init(); +const builtInThemeIds = new Set( + [ + ArduinoThemes.light, + ArduinoThemes.dark, + BuiltinThemeProvider.hcTheme, + // TODO: add the HC light theme after Theia 1.36 + ].map(({ id }) => id) +); +const deprecatedThemeIds = new Set( + [BuiltinThemeProvider.lightTheme, BuiltinThemeProvider.darkTheme].map( + ({ id }) => id + ) +); + +export const lightThemeLabel = nls.localize('arduino/theme/light', 'Light'); +export const darkThemeLabel = nls.localize('arduino/theme/dark', 'Dark'); +export const hcThemeLabel = nls.localize('arduino/theme/hc', 'High Contrast'); +export function userThemeLabel(theme: Theme): string { + return nls.localize('arduino/theme/user', '{0} (user)', theme.label); +} +export function deprecatedThemeLabel(theme: Theme): string { + return nls.localize( + 'arduino/theme/deprecated', + '{0} (deprecated)', + theme.label + ); +} + +export function themeLabelForSettings(theme: Theme): string { + switch (theme.id) { + case ArduinoThemes.light.id: + return lightThemeLabel; + case ArduinoThemes.dark.id: + return darkThemeLabel; + case BuiltinThemeProvider.hcTheme.id: + return hcThemeLabel; + case BuiltinThemeProvider.lightTheme.id: // fall-through + case BuiltinThemeProvider.darkTheme.id: + return deprecatedThemeLabel(theme); + default: + return userThemeLabel(theme); + } +} + +export function compatibleBuiltInTheme(theme: Theme): Theme { + switch (theme.type) { + case 'light': + return ArduinoThemes.light; + case 'dark': + return ArduinoThemes.dark; + case 'hc': + return BuiltinThemeProvider.hcTheme; + default: { + console.warn( + `Unhandled theme type: ${theme.type}. Theme ID: ${theme.id}, label: ${theme.label}` + ); + return ArduinoThemes.light; + } + } +} + +// For tests without DI +interface ThemeProvider { + themes(): Theme[]; + currentTheme(): Theme; +} + +/** + * Returns with a list of built-in themes officially supported by IDE2 (https://github.com/arduino/arduino-ide/issues/1283). + * The themes in the array follow the following order: + * - built-in themes first (in `Light`, `Dark`, `High Contrast`), // TODO -> High Contrast will be split up to HC Dark and HC Light after the Theia version uplift + * - followed by user installed (VSIX) themes grouped by theme type, then alphabetical order, + * - if the `currentTheme` is either Light (Theia) or Dark (Theia), the last item of the array will be the selected theme with `(deprecated)` suffix. + */ +export function userConfigurableThemes(service: ThemeService): Theme[][]; +export function userConfigurableThemes(provider: ThemeProvider): Theme[][]; +export function userConfigurableThemes( + serviceOrProvider: ThemeService | ThemeProvider +): Theme[][] { + const provider = + serviceOrProvider instanceof ThemeService + ? { + currentTheme: () => serviceOrProvider.getCurrentTheme(), + themes: () => serviceOrProvider.getThemes(), + } + : serviceOrProvider; + const currentTheme = provider.currentTheme(); + const allThemes = provider + .themes() + .map((theme) => ({ ...theme, arduinoThemeType: arduinoThemeTypeOf(theme) })) + .filter( + (theme) => + theme.arduinoThemeType !== 'deprecated' || currentTheme.id === theme.id + ) + .sort((left, right) => { + const leftArduinoThemeType = left.arduinoThemeType; + const rightArduinoThemeType = right.arduinoThemeType; + if (leftArduinoThemeType === rightArduinoThemeType) { + const result = themeTypeOrder[left.type] - themeTypeOrder[right.type]; + if (result) { + return result; + } + return left.label.localeCompare(right.label); // alphabetical order + } + return ( + arduinoThemeTypeOrder[leftArduinoThemeType] - + arduinoThemeTypeOrder[rightArduinoThemeType] + ); + }); + const builtInThemes: Theme[] = []; + const userThemes: Theme[] = []; + const deprecatedThemes: Theme[] = []; + allThemes.forEach((theme) => { + const { arduinoThemeType } = theme; + switch (arduinoThemeType) { + case 'built-in': + builtInThemes.push(theme); + break; + case 'user': + userThemes.push(theme); + break; + case 'deprecated': + deprecatedThemes.push(theme); + break; + default: + assertUnreachable(arduinoThemeType); + } + }); + const groupedThemes: Theme[][] = []; + if (builtInThemes.length) { + groupedThemes.push(builtInThemes); + } + if (userThemes.length) { + groupedThemes.push(userThemes); + } + if (deprecatedThemes.length) { + groupedThemes.push(deprecatedThemes); + } + return groupedThemes; +} + +export type ArduinoThemeType = 'built-in' | 'user' | 'deprecated'; +const arduinoThemeTypeOrder: Record<ArduinoThemeType, number> = { + 'built-in': 0, + user: 1, + deprecated: 2, +}; +const themeTypeOrder: Record<ThemeType, number> = { + light: 0, + dark: 1, + hc: 2, +}; + +export function arduinoThemeTypeOf(theme: Theme | string): ArduinoThemeType { + const themeId = typeof theme === 'string' ? theme : theme.id; + if (builtInThemeIds.has(themeId)) { + return 'built-in'; + } + if (deprecatedThemeIds.has(themeId)) { + return 'deprecated'; } + return 'user'; } diff --git a/arduino-ide-extension/src/browser/theia/monaco/monaco-theming-service.ts b/arduino-ide-extension/src/browser/theia/monaco/monaco-theming-service.ts index 4951ba771..40d703423 100644 --- a/arduino-ide-extension/src/browser/theia/monaco/monaco-theming-service.ts +++ b/arduino-ide-extension/src/browser/theia/monaco/monaco-theming-service.ts @@ -1,23 +1,231 @@ -import { injectable } from '@theia/core/shared/inversify'; -import { MonacoThemingService as TheiaMonacoThemingService } from '@theia/monaco/lib/browser/monaco-theming-service'; -import { ArduinoThemes } from '../core/theming'; +import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application'; +import { ThemeService } from '@theia/core/lib/browser/theming'; +import { + Disposable, + DisposableCollection, +} from '@theia/core/lib/common/disposable'; +import { MessageService } from '@theia/core/lib/common/message-service'; +import { nls } from '@theia/core/lib/common/nls'; +import { deepClone } from '@theia/core/lib/common/objects'; +import { wait } from '@theia/core/lib/common/promise-util'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { + MonacoThemeState, + deleteTheme as deleteThemeFromIndexedDB, + getThemes as getThemesFromIndexedDB, +} from '@theia/monaco/lib/browser/monaco-indexed-db'; +import { + MonacoTheme, + MonacoThemingService as TheiaMonacoThemingService, +} from '@theia/monaco/lib/browser/monaco-theming-service'; +import { MonacoThemeRegistry as TheiaMonacoThemeRegistry } from '@theia/monaco/lib/browser/textmate/monaco-theme-registry'; +import type { ThemeMix } from '@theia/monaco/lib/browser/textmate/monaco-theme-types'; +import { HostedPluginSupport } from '@theia/plugin-ext/lib/hosted/browser/hosted-plugin'; +import { ArduinoThemes, compatibleBuiltInTheme } from '../core/theming'; +import { WindowServiceExt } from '../core/window-service-ext'; + +type MonacoThemeRegistrationSource = + /** + * When reading JS/TS contributed theme from a JSON file. Such as the Arduino themes and the ones contributed by Theia. + */ + | 'compiled' + /** + * When reading and registering previous monaco themes from the `indexedDB`. + */ + | 'indexedDB' + /** + * Contributed by VS Code extensions when starting the app and loading the plugins. + */ + | 'vsix'; + +@injectable() +export class ThemesRegistrationSummary { + private readonly _summary: Record<MonacoThemeRegistrationSource, string[]> = { + compiled: [], + indexedDB: [], + vsix: [], + }; + + add(source: MonacoThemeRegistrationSource, themeId: string): void { + const themeIds = this._summary[source]; + if (!themeIds.includes(themeId)) { + themeIds.push(themeId); + } + } + + get summary(): Record<MonacoThemeRegistrationSource, string[]> { + return deepClone(this._summary); + } +} + +@injectable() +export class MonacoThemeRegistry extends TheiaMonacoThemeRegistry { + @inject(ThemesRegistrationSummary) + private readonly summary: ThemesRegistrationSummary; + + private initializing = false; + + override initializeDefaultThemes(): void { + this.initializing = true; + try { + super.initializeDefaultThemes(); + } finally { + this.initializing = false; + } + } + + override setTheme(name: string, data: ThemeMix): void { + super.setTheme(name, data); + if (this.initializing) { + this.summary.add('compiled', name); + } + } +} @injectable() export class MonacoThemingService extends TheiaMonacoThemingService { - override initialize(): void { - super.initialize(); - const { Light, Dark } = ArduinoThemes; + @inject(ThemesRegistrationSummary) + private readonly summary: ThemesRegistrationSummary; + + private themeRegistrationSource: MonacoThemeRegistrationSource | undefined; + + protected override async restore(): Promise<void> { + // The custom theme registration must happen before restoring the themes. + // Otherwise, theme changes are not picked up. + // https://github.com/arduino/arduino-ide/issues/1251#issuecomment-1436737702 + this.registerArduinoThemes(); + this.themeRegistrationSource = 'indexedDB'; + try { + await super.restore(); + } finally { + this.themeRegistrationSource = 'indexedDB'; + } + } + + private registerArduinoThemes(): void { + const { light, dark } = ArduinoThemes; this.registerParsedTheme({ - id: Light.id, - label: Light.label, + id: light.id, + label: light.label, uiTheme: 'vs', json: require('../../../../src/browser/data/default.color-theme.json'), }); this.registerParsedTheme({ - id: Dark.id, - label: Dark.label, + id: dark.id, + label: dark.label, uiTheme: 'vs-dark', json: require('../../../../src/browser/data/dark.color-theme.json'), }); } + + protected override doRegisterParsedTheme( + state: MonacoThemeState + ): Disposable { + const themeId = state.id; + const source = this.themeRegistrationSource ?? 'compiled'; + const disposable = super.doRegisterParsedTheme(state); + this.summary.add(source, themeId); + return disposable; + } + + protected override async doRegister( + theme: MonacoTheme, + // eslint-disable-next-line @typescript-eslint/no-explicit-any + pending: { [uri: string]: Promise<any> }, + toDispose: DisposableCollection + ): Promise<void> { + try { + this.themeRegistrationSource = 'vsix'; + await super.doRegister(theme, pending, toDispose); + } finally { + this.themeRegistrationSource = undefined; + } + } +} + +/** + * Workaround for removing VSIX themes from the indexedDB if they were not loaded during the app startup. + */ +@injectable() +export class CleanupObsoleteThemes implements FrontendApplicationContribution { + @inject(HostedPluginSupport) + private readonly hostedPlugin: HostedPluginSupport; + @inject(ThemesRegistrationSummary) + private readonly summary: ThemesRegistrationSummary; + @inject(ThemeService) + private readonly themeService: ThemeService; + @inject(MessageService) + private readonly messageService: MessageService; + @inject(WindowServiceExt) + private readonly windowService: WindowServiceExt; + + onStart(): void { + this.hostedPlugin.didStart.then(() => this.cleanupObsoleteThemes()); + } + + private async cleanupObsoleteThemes(): Promise<void> { + const persistedThemes = await getThemesFromIndexedDB(); + const obsoleteThemeIds = collectObsoleteThemeIds( + persistedThemes, + this.summary.summary + ); + if (!obsoleteThemeIds.length) { + return; + } + const firstWindow = await this.windowService.isFirstWindow(); + if (firstWindow) { + await this.removeObsoleteThemesFromIndexedDB(obsoleteThemeIds); + this.unregisterObsoleteThemes(obsoleteThemeIds); + } + } + + private removeObsoleteThemesFromIndexedDB(themeIds: string[]): Promise<void> { + return themeIds.reduce(async (previousTask, themeId) => { + await previousTask; + return deleteThemeFromIndexedDB(themeId); + }, Promise.resolve()); + } + + private unregisterObsoleteThemes(themeIds: string[]): void { + const currentTheme = this.themeService.getCurrentTheme(); + const switchToCompatibleTheme = themeIds.includes(currentTheme.id); + for (const themeId of themeIds) { + delete this.themeService['themes'][themeId]; + } + this.themeService['doUpdateColorThemePreference'](); + if (switchToCompatibleTheme) { + this.themeService.setCurrentTheme( + compatibleBuiltInTheme(currentTheme).id, + true + ); + wait(250).then(() => + requestAnimationFrame(() => + this.messageService.info( + nls.localize( + 'arduino/theme/currentThemeNotFound', + 'Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.', + currentTheme.label + ) + ) + ) + ); + } + } +} + +/** + * An indexedDB registered theme is obsolete if it is in the indexedDB but was registered + * from neither a `vsix` nor `compiled` source during the app startup. + */ +export function collectObsoleteThemeIds( + indexedDBThemes: MonacoThemeState[], + summary: Record<MonacoThemeRegistrationSource, string[]> +): string[] { + const vsixThemeIds = summary['vsix']; + const compiledThemeIds = summary['compiled']; + return indexedDBThemes + .map(({ id }) => id) + .filter( + (id) => !vsixThemeIds.includes(id) && !compiledThemeIds.includes(id) + ); } diff --git a/arduino-ide-extension/src/test/browser/theming.test.ts b/arduino-ide-extension/src/test/browser/theming.test.ts new file mode 100644 index 000000000..89265e61a --- /dev/null +++ b/arduino-ide-extension/src/test/browser/theming.test.ts @@ -0,0 +1,179 @@ +import { enableJSDOM } from '@theia/core/lib/browser/test/jsdom'; +const disableJSDOM = enableJSDOM(); + +import { BuiltinThemeProvider } from '@theia/core/lib/browser/theming'; +import { Theme } from '@theia/core/lib/common/theme'; +import { expect } from 'chai'; +import { + ArduinoThemeType, + ArduinoThemes, + arduinoThemeTypeOf, + darkThemeLabel, + deprecatedThemeLabel, + hcThemeLabel, + lightThemeLabel, + themeLabelForSettings, + userConfigurableThemes, + userThemeLabel, +} from '../../browser/theia/core/theming'; + +disableJSDOM(); + +const testTheme: Theme = { + id: 'testTheme', + label: 'Test Theme', + type: 'light', +}; +const anotherTestTheme: Theme = { + id: 'anotherTestTheme', + label: 'Another Test Theme', + type: 'light', +}; +const darkTestTheme: Theme = { + id: 'darkTestTheme', + label: 'Dark Test Theme', + type: 'dark', +}; +const anotherDarkTestTheme: Theme = { + id: 'anotherTestTheme', + label: 'AAAnother Dark Test Theme', + type: 'dark', +}; + +describe('theming', () => { + describe('userConfigurableThemes', () => { + it('should show only built-in and user installed themes but not deprecated (Theia) ones if current theme is a built-in', () => { + const actual = userConfigurableThemes({ + themes: () => [ + BuiltinThemeProvider.darkTheme, + BuiltinThemeProvider.lightTheme, + ArduinoThemes.dark, + ArduinoThemes.light, + testTheme, + BuiltinThemeProvider.hcTheme, + anotherTestTheme, + ], + currentTheme: () => BuiltinThemeProvider.hcTheme, + }).reduce((acc, curr) => acc.concat(curr), []); + expect(actual.length).to.be.equal(5); + expect(actual[0].id).to.be.equal(ArduinoThemes.light.id); + expect(actual[1].id).to.be.equal(ArduinoThemes.dark.id); + expect(actual[2].id).to.be.equal(BuiltinThemeProvider.hcTheme.id); + expect(actual[3].id).to.be.equal(anotherTestTheme.id); + expect(actual[4].id).to.be.equal(testTheme.id); + }); + + it('should show only built-in and user installed themes but not deprecated (Theia) ones if current theme is a user', () => { + const actual = userConfigurableThemes({ + themes: () => [ + BuiltinThemeProvider.hcTheme, + BuiltinThemeProvider.lightTheme, + BuiltinThemeProvider.darkTheme, + ArduinoThemes.dark, + testTheme, + anotherTestTheme, + ArduinoThemes.light, + ], + currentTheme: () => testTheme, + }).reduce((acc, curr) => acc.concat(curr), []); + expect(actual.length).to.be.equal(5); + expect(actual[0].id).to.be.equal(ArduinoThemes.light.id); + expect(actual[1].id).to.be.equal(ArduinoThemes.dark.id); + expect(actual[2].id).to.be.equal(BuiltinThemeProvider.hcTheme.id); + expect(actual[3].id).to.be.equal(anotherTestTheme.id); + expect(actual[4].id).to.be.equal(testTheme.id); + }); + + it('should show built-in, user installed, and deprecated (Theia) themes if current theme is a deprecated (Theia)', () => { + const actual = userConfigurableThemes({ + themes: () => [ + ArduinoThemes.dark, + ArduinoThemes.light, + testTheme, + BuiltinThemeProvider.hcTheme, + anotherTestTheme, + darkTestTheme, + anotherDarkTestTheme, + BuiltinThemeProvider.lightTheme, + BuiltinThemeProvider.darkTheme, + ], + currentTheme: () => BuiltinThemeProvider.lightTheme, + }).reduce((acc, curr) => acc.concat(curr), []); + expect(actual.length).to.be.equal(8); + expect(actual[0].id).to.be.equal(ArduinoThemes.light.id); + expect(actual[1].id).to.be.equal(ArduinoThemes.dark.id); + expect(actual[2].id).to.be.equal(BuiltinThemeProvider.hcTheme.id); + expect(actual[3].id).to.be.equal(anotherTestTheme.id); + expect(actual[4].id).to.be.equal(testTheme.id); + expect(actual[5].id).to.be.equal(anotherDarkTestTheme.id); + expect(actual[6].id).to.be.equal(darkTestTheme.id); + expect(actual[7].id).to.be.equal(BuiltinThemeProvider.lightTheme.id); + }); + + it('should group the themes by arduino theme types', () => { + const actual = userConfigurableThemes({ + themes: () => [ + ArduinoThemes.dark, + ArduinoThemes.light, + testTheme, + BuiltinThemeProvider.hcTheme, + anotherTestTheme, + darkTestTheme, + anotherDarkTestTheme, + BuiltinThemeProvider.lightTheme, + BuiltinThemeProvider.darkTheme, + ], + currentTheme: () => BuiltinThemeProvider.lightTheme, + }); + expect(actual.length).to.be.equal(3); + expect(actual[0].length).to.be.equal(3); + expect(actual[1].length).to.be.equal(4); + expect(actual[2].length).to.be.equal(1); + }); + }); + + describe('arduinoThemeTypeOf', () => { + ( + [ + [BuiltinThemeProvider.lightTheme, 'deprecated'], + [BuiltinThemeProvider.darkTheme, 'deprecated'], + [BuiltinThemeProvider.hcTheme, 'built-in'], + [ArduinoThemes.light, 'built-in'], + [ArduinoThemes.dark, 'built-in'], + [testTheme, 'user'], + [anotherTestTheme, 'user'], + [darkTestTheme, 'user'], + [anotherDarkTestTheme, 'user'], + ] as [Theme, ArduinoThemeType][] + ).map(([theme, expected]) => + it(`should detect the '${theme.label}' theme as '${expected}' theme`, () => + expect(arduinoThemeTypeOf(theme)).to.be.equal(expected)) + ); + }); + + describe('themeLabelForSettings', () => { + ( + [ + [ + BuiltinThemeProvider.lightTheme, + deprecatedThemeLabel(BuiltinThemeProvider.lightTheme), + ], + [ + BuiltinThemeProvider.darkTheme, + deprecatedThemeLabel(BuiltinThemeProvider.darkTheme), + ], + [BuiltinThemeProvider.hcTheme, hcThemeLabel], + [ArduinoThemes.light, lightThemeLabel], + [ArduinoThemes.dark, darkThemeLabel], + [testTheme, userThemeLabel(testTheme)], + [anotherTestTheme, userThemeLabel(anotherTestTheme)], + [darkTestTheme, userThemeLabel(darkTestTheme)], + [anotherDarkTestTheme, userThemeLabel(anotherDarkTestTheme)], + ] as [Theme, string][] + ).map(([theme, expected]) => { + it(`should map the theme with ID '${theme.id}' to ${expected} in the settings UI`, () => { + expect(themeLabelForSettings(theme)).to.be.equal(expected); + }); + }); + }); +}); diff --git a/i18n/en.json b/i18n/en.json index 320be23f1..08a47309e 100644 --- a/i18n/en.json +++ b/i18n/en.json @@ -474,6 +474,14 @@ "dismissSurvey": "Don't show again", "surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, "title": { "cloud": "Cloud" }, From 54f210d4deaa1192e859804524ea67d7ec93a590 Mon Sep 17 00:00:00 2001 From: Akos Kitta <a.kitta@arduino.cc> Date: Tue, 11 Apr 2023 10:06:12 +0200 Subject: [PATCH 29/32] fix: try fetch the sketch by path if not in the cache The sketch cache might be empty, when trying to generate the secrets include in the main sketch file from the `secrets` property. Closes #1999 Signed-off-by: Akos Kitta <a.kitta@arduino.cc> --- .../src/browser/create/create-api.ts | 61 ++++++++++++++++++- .../cloud-sketchbook/cloud-sketch-cache.ts | 12 +++- .../src/test/browser/create-api.test.ts | 34 +++++++++++ 3 files changed, 102 insertions(+), 5 deletions(-) diff --git a/arduino-ide-extension/src/browser/create/create-api.ts b/arduino-ide-extension/src/browser/create/create-api.ts index 72c27cbb0..b2aac2b02 100644 --- a/arduino-ide-extension/src/browser/create/create-api.ts +++ b/arduino-ide-extension/src/browser/create/create-api.ts @@ -57,6 +57,30 @@ export class CreateApi { return result; } + /** + * `sketchPath` is not the POSIX path but the path with the user UUID, username, etc. + * See [Create.Resource#path](./typings.ts). If `cache` is `true` and a sketch exists with the path, + * the cache will be updated with the new state of the sketch. + */ + // TODO: no nulls in API + async sketchByPath( + sketchPath: string, + cache = false + ): Promise<Create.Sketch | null> { + const url = new URL(`${this.domain()}/sketches/byPath/${sketchPath}`); + const headers = await this.headers(); + const sketch = await this.run<Create.Sketch>(url, { + method: 'GET', + headers, + }); + if (sketch && cache) { + this.sketchCache.addSketch(sketch); + const posixPath = createPaths.toPosixPath(sketch.path); + this.sketchCache.purgeByPath(posixPath); + } + return sketch; + } + async sketches(limit = 50): Promise<Create.Sketch[]> { const url = new URL(`${this.domain()}/sketches`); url.searchParams.set('user_id', 'me'); @@ -86,7 +110,11 @@ export class CreateApi { async createSketch( posixPath: string, - contentProvider: MaybePromise<string> = this.sketchesService.defaultInoContent() + contentProvider: MaybePromise<string> = this.sketchesService.defaultInoContent(), + payloadOverride: Record< + string, + string | boolean | number | Record<string, unknown> + > = {} ): Promise<Create.Sketch> { const url = new URL(`${this.domain()}/sketches`); const [headers, content] = await Promise.all([ @@ -97,6 +125,7 @@ export class CreateApi { ino: btoa(content), path: posixPath, user_id: 'me', + ...payloadOverride, }; const init = { method: 'PUT', @@ -212,7 +241,17 @@ export class CreateApi { return data; } - const sketch = this.sketchCache.getSketch(createPaths.parentPosix(path)); + const posixPath = createPaths.parentPosix(path); + let sketch = this.sketchCache.getSketch(posixPath); + // Workaround for https://github.com/arduino/arduino-ide/issues/1999. + if (!sketch) { + // Convert the ordinary sketch POSIX path to the Create path. + // For example, `/sketch_apr6a` will be transformed to `8a694e4b83878cc53472bd75ee928053:kittaakos/sketches_v2/sketch_apr6a`. + const createPathPrefix = this.sketchCache.createPathPrefix; + if (createPathPrefix) { + sketch = await this.sketchByPath(createPathPrefix + posixPath, true); + } + } if ( sketch && @@ -448,13 +487,18 @@ export class CreateApi { await this.run(url, init, ResponseResultProvider.NOOP); } + private fetchCounter = 0; private async run<T>( requestInfo: URL, init: RequestInit | undefined, resultProvider: ResponseResultProvider = ResponseResultProvider.JSON ): Promise<T> { - console.debug(`HTTP ${init?.method}: ${requestInfo.toString()}`); + const fetchCount = `[${++this.fetchCounter}]`; + const fetchStart = performance.now(); + const method = init?.method ? `${init.method}: ` : ''; + const url = requestInfo.toString(); const response = await fetch(requestInfo.toString(), init); + const fetchEnd = performance.now(); if (!response.ok) { let details: string | undefined = undefined; try { @@ -465,7 +509,18 @@ export class CreateApi { const { statusText, status } = response; throw new CreateError(statusText, status, details); } + const parseStart = performance.now(); const result = await resultProvider(response); + const parseEnd = performance.now(); + console.debug( + `HTTP ${fetchCount} ${method} ${url} [fetch: ${( + fetchEnd - fetchStart + ).toFixed(2)} ms, parse: ${(parseEnd - parseStart).toFixed( + 2 + )} ms] body: ${ + typeof result === 'string' ? result : JSON.stringify(result) + }` + ); return result; } diff --git a/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketch-cache.ts b/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketch-cache.ts index 21469d2de..0b0fc024a 100644 --- a/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketch-cache.ts +++ b/arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketch-cache.ts @@ -1,12 +1,13 @@ import { FileStat } from '@theia/filesystem/lib/common/files'; import { injectable } from '@theia/core/shared/inversify'; -import { toPosixPath } from '../../create/create-paths'; +import { splitSketchPath } from '../../create/create-paths'; import { Create } from '../../create/typings'; @injectable() export class SketchCache { sketches: Record<string, Create.Sketch> = {}; fileStats: Record<string, FileStat> = {}; + private _createPathPrefix: string | undefined; init(): void { // reset the data @@ -32,7 +33,10 @@ export class SketchCache { addSketch(sketch: Create.Sketch): void { const { path } = sketch; - const posixPath = toPosixPath(path); + const [pathPrefix, posixPath] = splitSketchPath(path); + if (pathPrefix !== this._createPathPrefix) { + this._createPathPrefix = pathPrefix; + } this.sketches[posixPath] = sketch; } @@ -40,6 +44,10 @@ export class SketchCache { return this.sketches[path] || null; } + get createPathPrefix(): string | undefined { + return this._createPathPrefix; + } + toString(): string { return JSON.stringify({ sketches: this.sketches, diff --git a/arduino-ide-extension/src/test/browser/create-api.test.ts b/arduino-ide-extension/src/test/browser/create-api.test.ts index a623854c6..a18609cb1 100644 --- a/arduino-ide-extension/src/test/browser/create-api.test.ts +++ b/arduino-ide-extension/src/test/browser/create-api.test.ts @@ -1,6 +1,7 @@ import { Container, ContainerModule } from '@theia/core/shared/inversify'; import { assert, expect } from 'chai'; import fetch from 'cross-fetch'; +import { posix } from 'path'; import { v4 } from 'uuid'; import { ArduinoPreferences } from '../../browser/arduino-preferences'; import { AuthenticationClientService } from '../../browser/auth/authentication-client-service'; @@ -251,6 +252,39 @@ describe('create-api', () => { expect(sketch).to.be.undefined; }); }); + + it("should fetch the sketch when transforming the 'secrets' into '#include' and the sketch is not in the cache", async () => { + const name = v4(); + const posixPath = toPosix(name); + const newSketch = await createApi.createSketch( + posixPath, + 'void setup(){} void loop(){}', + { + secrets: { + data: [ + { + name: 'SECRET_THING', + value: '❤︎', + }, + ], + }, + } + ); + expect(newSketch).to.be.not.undefined; + expect(newSketch.secrets).to.be.not.undefined; + expect(Array.isArray(newSketch.secrets)).to.be.true; + expect(newSketch.secrets?.length).to.be.equal(1); + expect(newSketch.secrets?.[0]).to.be.deep.equal({ + name: 'SECRET_THING', + value: '❤︎', + }); + createApi.sketchCache.init(); // invalidate the cache + const content = await createApi.readFile( + posix.join(posixPath, `${name}.ino`) + ); + expect(content.includes(`#include "${Create.arduino_secrets_file}"`)).to.be + .true; + }); }); // Using environment variables is recommended for testing but you can modify the module too. From 4c2f0fb841698bd1d8c5ad35a502719aa837410a Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 17 Apr 2023 02:19:03 +0000 Subject: [PATCH 30/32] Updated translation files --- i18n/af.json | 49 ++++- i18n/ar.json | 49 ++++- i18n/az.json | 49 ++++- i18n/bg.json | 49 ++++- i18n/bn.json | 538 ++++++++++++++++++++++++++++++++++++++++++++++ i18n/ca_ES.json | 101 ++++++--- i18n/cs.json | 49 ++++- i18n/da.json | 49 ++++- i18n/de.json | 107 +++++---- i18n/el.json | 53 ++++- i18n/es.json | 63 ++++-- i18n/eu.json | 49 ++++- i18n/fa.json | 49 ++++- i18n/fil.json | 51 ++++- i18n/fr.json | 49 ++++- i18n/he.json | 49 ++++- i18n/hi.json | 234 ++++++++++++++++---- i18n/hu.json | 49 ++++- i18n/id.json | 49 ++++- i18n/it.json | 103 ++++++--- i18n/ja.json | 57 ++++- i18n/ko.json | 49 ++++- i18n/my_MM.json | 49 ++++- i18n/ne.json | 49 ++++- i18n/nl.json | 173 +++++++++------ i18n/pl.json | 49 ++++- i18n/pt.json | 299 ++++++++++++++------------ i18n/ro.json | 51 ++++- i18n/ru.json | 55 ++++- i18n/sl.json | 49 ++++- i18n/sr.json | 49 ++++- i18n/sv.json | 538 ++++++++++++++++++++++++++++++++++++++++++++++ i18n/th.json | 49 ++++- i18n/tr.json | 49 ++++- i18n/uk.json | 49 ++++- i18n/vi.json | 49 ++++- i18n/zh-Hant.json | 49 ++++- i18n/zh.json | 63 ++++-- i18n/zh_TW.json | 49 ++++- 39 files changed, 3078 insertions(+), 584 deletions(-) create mode 100644 i18n/bn.json create mode 100644 i18n/sv.json diff --git a/i18n/af.json b/i18n/af.json index 383b19186..f991c25ed 100644 --- a/i18n/af.json +++ b/i18n/af.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "About {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "Board{0}", "boardConfigDialogTitle": "Select Other Board and Port", @@ -83,13 +89,12 @@ "mouseError": "'Mouse' not found. Does your sketch include the line '#include <Mouse.h>'?" }, "cloud": { - "account": "Account", "chooseSketchVisibility": "Choose visibility of your Sketch:", "cloudSketchbook": "Wolk Skets", "connected": "Connected", "continue": "Continue", - "donePulling": "Done pulling ‘{0}’.", - "donePushing": "Done pushing ‘{0}’.", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "Embed:", "emptySketchbook": "Jou Sketsboek is leeg", "goToCloud": "Go to Cloud", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "Boards included in this package:", "by": "by", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "Filter your search...", "install": "Install", - "installed": "Installed", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "Meer inligting", + "otherVersions": "Other Versions", + "remove": "Remove", + "title": "{0} by {1}", "uninstall": "Uninstall", "uninstallMsg": "Do you want to uninstall {0}?", - "version": "Weergawe {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "Add File", "fileAdded": "Een lêer by skets gevoeg", @@ -188,6 +202,7 @@ "copyError": "Copy error messages", "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Restart Daemon", "start": "Start Daemon", @@ -313,6 +328,13 @@ "tools": "Gereedskap" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Unable to close websocket", "unableToConnectToWebSocket": "Unable to connect to websocket" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "Autoscroll", "carriageReturn": "Wagterugkeer", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Message (Enter to send message to '{0}' on '{1}')", "newLine": "Nuwe lyn", "newLineCarriageReturn": "Beide NL & CR", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "Export Compiled Binary", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "Moving", "movingMsg": "The file \"{0}\" needs to be inside a sketch folder named \"{1}\".\nCreate this folder, move the file, and continue?", "new": "New Sketch", @@ -451,6 +474,17 @@ "dismissSurvey": "Don't show again", "surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Update Indexes", "updateLibraryIndex": "Update Library Index", @@ -483,6 +517,7 @@ "couldNotSave": "Could not save the sketch. Please copy your unsaved work into your favorite text editor, and restart the IDE.", "daemonOffline": "CLI Daemon Offline", "offline": "Aflyn", + "offlineText": "Aflyn", "quitTitle": "Are you sure you want to quit?" }, "editor": { diff --git a/i18n/ar.json b/i18n/ar.json index dea546143..fff35a478 100644 --- a/i18n/ar.json +++ b/i18n/ar.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "حول {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "اللوحة {0}", "boardConfigDialogTitle": "أختر متحكم و منفذ مختلفين ", @@ -83,13 +89,12 @@ "mouseError": "تعذر ايجاد الفأرة 'Mouse' . هل يحتوي مشروعك على '#include <Mouse.h>' ؟" }, "cloud": { - "account": "الحساب", "chooseSketchVisibility": "اختر خصوصية مشروعك:", "cloudSketchbook": "مشاريع على السحابة", "connected": "متصل", "continue": "استئناف", - "donePulling": "تم السحب بنجاح '{0}'", - "donePushing": "تم الدفع بنجاح '{0}'", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "تضمين:", "emptySketchbook": "ملف المشاريع الخاص بك فارغ", "goToCloud": "Go to Cloud", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "Boards included in this package:", "by": "بواسطة", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "ترشيح بحثك...", "install": "تنصيب", - "installed": "Installed", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "عرض المزيد", + "otherVersions": "Other Versions", + "remove": "حذف", + "title": "{0} by {1}", "uninstall": "الغاء التثبيت", "uninstallMsg": "هل تريد الغاء تثبيت {0}؟", - "version": "النسخة {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "اضف ملف...", "fileAdded": "تمت اضافة ملف واحد الى المشروع", @@ -188,6 +202,7 @@ "copyError": "نسخ رسالة الخطأ", "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Restart Daemon", "start": "Start Daemon", @@ -313,6 +328,13 @@ "tools": "ادوات" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "تعذر اغلاق مقبس الويب", "unableToConnectToWebSocket": "تعذر الاتصال بمقبس الويب" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "تمرير تلقائي", "carriageReturn": "اعادة الحمل", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Message (Enter to send message to '{0}' on '{1}')", "newLine": "سطر جديد", "newLineCarriageReturn": " NL & CR معاً", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "تصدير الملف الثنائي المترجم", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "يتم النقل", "movingMsg": "الملف \"{0}\" يجب ان يكون داخل مجلد مشروع مسمى \"{1}\"\nهل انشئ المجلد , ثم انقل الملف و اكمل ؟", "new": "New Sketch", @@ -451,6 +474,17 @@ "dismissSurvey": "لا تظهر مرة اخرى", "surveyMessage": "يرجى ان تساعدنا لنحسن ادائنا من خلال الاجابة على هذا الاستبيان القصير جدا . نحن نحترم المجتمع الخاص بنا و نريد ان نتعرف بشكل افضل على داعمينا " }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Update Indexes", "updateLibraryIndex": "Update Library Index", @@ -483,6 +517,7 @@ "couldNotSave": "تعذر حفظ المشروع . الرجاء نسخ عملك الغير محفوظ الى محرر النصوص المفضل لديك و اعادة تشغيل Arduino IDE", "daemonOffline": "CLI Daemon غير متصل", "offline": "غير متصل", + "offlineText": "غير متصل", "quitTitle": "هل انت متاكد بانك تريد الخروج؟" }, "editor": { diff --git a/i18n/az.json b/i18n/az.json index d4e949964..99fd7271a 100644 --- a/i18n/az.json +++ b/i18n/az.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "Haqqında {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "Board{0}", "boardConfigDialogTitle": "Select Other Board and Port", @@ -83,13 +89,12 @@ "mouseError": "'Mouse' not found. Does your sketch include the line '#include <Mouse.h>'?" }, "cloud": { - "account": "Account", "chooseSketchVisibility": "Choose visibility of your Sketch:", "cloudSketchbook": "Cloud Sketchbook", "connected": "Əlaqə Yaradıldı", "continue": "Davam Et", - "donePulling": "Done pulling ‘{0}’.", - "donePushing": "Done pushing ‘{0}’.", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "Embed:", "emptySketchbook": "Your Sketchbook is empty", "goToCloud": "Go to Cloud", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "Boards included in this package:", "by": "by", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "Filter your search...", "install": "Yüklə", - "installed": "Installed", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "More info", + "otherVersions": "Other Versions", + "remove": "Sil", + "title": "{0} by {1}", "uninstall": "Sil", "uninstallMsg": "Do you want to uninstall {0}?", - "version": "Version {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "Fayl Əlavə Et", "fileAdded": "One file added to the sketch.", @@ -188,6 +202,7 @@ "copyError": "Copy error messages", "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Restart Daemon", "start": "Start Daemon", @@ -313,6 +328,13 @@ "tools": "Tools" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Unable to close websocket", "unableToConnectToWebSocket": "Unable to connect to websocket" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "Autoscroll", "carriageReturn": "Carriage Return", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Message (Enter to send message to '{0}' on '{1}')", "newLine": "New Line", "newLineCarriageReturn": "Both NL & CR", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "Export Compiled Binary", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "Moving", "movingMsg": "The file \"{0}\" needs to be inside a sketch folder named \"{1}\".\nCreate this folder, move the file, and continue?", "new": "New Sketch", @@ -451,6 +474,17 @@ "dismissSurvey": "Don't show again", "surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Update Indexes", "updateLibraryIndex": "Update Library Index", @@ -483,6 +517,7 @@ "couldNotSave": "Could not save the sketch. Please copy your unsaved work into your favorite text editor, and restart the IDE.", "daemonOffline": "CLI Daemon Offline", "offline": "Offlayn", + "offlineText": "Offlayn", "quitTitle": "Are you sure you want to quit?" }, "editor": { diff --git a/i18n/bg.json b/i18n/bg.json index 56b3a9393..a5ea1899f 100644 --- a/i18n/bg.json +++ b/i18n/bg.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "Относно {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "Платка{0}", "boardConfigDialogTitle": "Select Other Board and Port", @@ -83,13 +89,12 @@ "mouseError": "'Mouse' not found. Does your sketch include the line '#include <Mouse.h>'?" }, "cloud": { - "account": "Account", "chooseSketchVisibility": "Изберете видимост на вашата скица:", "cloudSketchbook": "Облачен скицник", "connected": "Свързано", "continue": "Продължи", - "donePulling": "Изтеглянето на „{0}“ приключи.", - "donePushing": "Изпращането на „{0}“ приключи.", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "Вграждане:", "emptySketchbook": "Вашият Скицник е празен", "goToCloud": "Go to Cloud", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "Boards included in this package:", "by": "от", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "Филтрирайте търсенето си...", "install": "Инсталирай", - "installed": "Installed", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "Повече информация", + "otherVersions": "Other Versions", + "remove": "Премахване", + "title": "{0} by {1}", "uninstall": "Деинсталиране", "uninstallMsg": "Искате ли да деинсталирате {0}?", - "version": "Версия {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "Добави файл", "fileAdded": "Към скицата е добавен един файл.", @@ -188,6 +202,7 @@ "copyError": "Copy error messages", "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Restart Daemon", "start": "Start Daemon", @@ -313,6 +328,13 @@ "tools": "Инструменти" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Unable to close websocket", "unableToConnectToWebSocket": "Unable to connect to websocket" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "Автоматично превъртане", "carriageReturn": "Carriage Return", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Message (Enter to send message to '{0}' on '{1}')", "newLine": "Нов ред", "newLineCarriageReturn": "Както NL, така и CR", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "Експортиране на компилиран двоичен файл", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "Преместване", "movingMsg": "The file \"{0}\" needs to be inside a sketch folder named \"{1}\".\nCreate this folder, move the file, and continue?", "new": "New Sketch", @@ -451,6 +474,17 @@ "dismissSurvey": "Don't show again", "surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Update Indexes", "updateLibraryIndex": "Update Library Index", @@ -483,6 +517,7 @@ "couldNotSave": "Скицата не можа да бъде запазена. Моля, копирайте незапазената си работа в любимия си текстов редактор и рестартирайте IDE-то.", "daemonOffline": "CLI Daemon офлайн", "offline": "Офлайн", + "offlineText": "Офлайн", "quitTitle": "Are you sure you want to quit?" }, "editor": { diff --git a/i18n/bn.json b/i18n/bn.json new file mode 100644 index 000000000..08a47309e --- /dev/null +++ b/i18n/bn.json @@ -0,0 +1,538 @@ +{ + "arduino": { + "about": { + "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", + "label": "About {0}" + }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, + "board": { + "board": "Board{0}", + "boardConfigDialogTitle": "Select Other Board and Port", + "boardInfo": "Board Info", + "boards": "boards", + "configDialog1": "Select both a Board and a Port if you want to upload a sketch.", + "configDialog2": "If you only select a Board you will be able to compile, but not to upload your sketch.", + "couldNotFindPreviouslySelected": "Could not find previously selected board '{0}' in installed platform '{1}'. Please manually reselect the board you want to use. Do you want to reselect it now?", + "disconnected": "Disconnected", + "getBoardInfo": "Get Board Info", + "inSketchbook": " (in Sketchbook)", + "installNow": "The \"{0} {1}\" core has to be installed for the currently selected \"{2}\" board. Do you want to install it now?", + "noBoardsFound": "No boards found for \"{0}\"", + "noFQBN": "The FQBN is not available for the selected board \"{0}\". Do you have the corresponding core installed?", + "noNativeSerialPort": "Native serial port, can't obtain info.", + "noPortsDiscovered": "No ports discovered", + "noPortsSelected": "No ports selected for board: '{0}'.", + "nonSerialPort": "Non-serial port, can't obtain info.", + "noneSelected": "No boards selected.", + "openBoardsConfig": "Select other board and port…", + "pleasePickBoard": "Please pick a board connected to the port you have selected.", + "port": "Port{0}", + "portLabel": "Port: {0}", + "ports": "ports", + "programmer": "Programmer", + "reselectLater": "Reselect later", + "searchBoard": "Search board", + "selectBoard": "Select Board", + "selectPortForInfo": "Please select a port to obtain board info.", + "showAllAvailablePorts": "Shows all available ports when enabled", + "showAllPorts": "Show all ports", + "succesfullyInstalledPlatform": "Successfully installed platform {0}:{1}", + "succesfullyUninstalledPlatform": "Successfully uninstalled platform {0}:{1}", + "typeOfPorts": "{0} ports", + "unknownBoard": "Unknown board" + }, + "boardsManager": "Boards Manager", + "boardsType": { + "arduinoCertified": "Arduino Certified" + }, + "bootloader": { + "burnBootloader": "Burn Bootloader", + "burningBootloader": "Burning bootloader...", + "doneBurningBootloader": "Done burning bootloader." + }, + "burnBootloader": { + "error": "Error while burning the bootloader: {0}" + }, + "certificate": { + "addNew": "Add New", + "addURL": "Add URL to fetch SSL certificate", + "boardAtPort": "{0} at {1}", + "certificatesUploaded": "Certificates uploaded.", + "enterURL": "Enter URL", + "noSupportedBoardConnected": "No supported board connected", + "openContext": "Open context", + "remove": "Remove", + "selectBoard": "Select a board...", + "selectCertificateToUpload": "1. Select certificate to upload", + "selectDestinationBoardToUpload": "2. Select destination board and upload certificate", + "upload": "Upload", + "uploadFailed": "Upload failed. Please try again.", + "uploadRootCertificates": "Upload SSL Root Certificates", + "uploadingCertificates": "Uploading certificates." + }, + "checkForUpdates": { + "checkForUpdates": "Check for Arduino Updates", + "installAll": "Install All", + "noUpdates": "There are no recent updates available.", + "promptUpdateBoards": "Updates are available for some of your boards.", + "promptUpdateLibraries": "Updates are available for some of your libraries.", + "updatingBoards": "Updating boards...", + "updatingLibraries": "Updating libraries..." + }, + "cli-error-parser": { + "keyboardError": "'Keyboard' not found. Does your sketch include the line '#include <Keyboard.h>'?", + "mouseError": "'Mouse' not found. Does your sketch include the line '#include <Mouse.h>'?" + }, + "cloud": { + "chooseSketchVisibility": "Choose visibility of your Sketch:", + "cloudSketchbook": "Cloud Sketchbook", + "connected": "Connected", + "continue": "Continue", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", + "embed": "Embed:", + "emptySketchbook": "Your Sketchbook is empty", + "goToCloud": "Go to Cloud", + "learnMore": "Learn more", + "link": "Link:", + "notYetPulled": "Cannot push to Cloud. It is not yet pulled.", + "offline": "Offline", + "openInCloudEditor": "Open in Cloud Editor", + "options": "Options...", + "privateVisibility": "Private. Only you can view the Sketch.", + "profilePicture": "Profile picture", + "publicVisibility": "Public. Anyone with the link can view the Sketch.", + "pull": "Pull", + "pullFirst": "You have to pull first to be able to push to the Cloud.", + "pullSketch": "Pull Sketch", + "pullSketchMsg": "Pulling this Sketch from the Cloud will overwrite its local version. Are you sure you want to continue?", + "push": "Push", + "pushSketch": "Push Sketch", + "pushSketchMsg": "This is a Public Sketch. Before pushing, make sure any sensitive information is defined in arduino_secrets.h files. You can make a Sketch private from the Share panel.", + "remote": "Remote", + "share": "Share...", + "shareSketch": "Share Sketch", + "showHideSketchbook": "Show/Hide Cloud Sketchbook", + "signIn": "SIGN IN", + "signInToCloud": "Sign in to Arduino Cloud", + "signOut": "Sign Out", + "sync": "Sync", + "syncEditSketches": "Sync and edit your Arduino Cloud Sketches", + "visitArduinoCloud": "Visit Arduino Cloud to create Cloud Sketches." + }, + "cloudSketch": { + "alreadyExists": "Cloud sketch '{0}' already exists.", + "creating": "Creating cloud sketch '{0}'...", + "new": "New Cloud Sketch", + "notFound": "Could not pull the cloud sketch '{0}'. It does not exist.", + "pulling": "Synchronizing sketchbook, pulling '{0}'...", + "pushing": "Synchronizing sketchbook, pushing '{0}'...", + "renaming": "Renaming cloud sketch from '{0}' to '{1}'...", + "synchronizingSketchbook": "Synchronizing sketchbook..." + }, + "common": { + "all": "All", + "contributed": "Contributed", + "installManually": "Install Manually", + "later": "Later", + "noBoardSelected": "No board selected", + "notConnected": "[not connected]", + "offlineIndicator": "You appear to be offline. Without an Internet connection, the Arduino CLI might not be able to download the required resources and could cause malfunction. Please connect to the Internet and restart the application.", + "oldFormat": "The '{0}' still uses the old `.pde` format. Do you want to switch to the new `.ino` extension?", + "partner": "Partner", + "processing": "Processing", + "recommended": "Recommended", + "retired": "Retired", + "selectedOn": "on {0}", + "serialMonitor": "Serial Monitor", + "type": "Type", + "unknown": "Unknown", + "updateable": "Updatable" + }, + "compile": { + "error": "Compilation error: {0}" + }, + "component": { + "boardsIncluded": "Boards included in this package:", + "by": "by", + "clickToOpen": "Click to open in browser: {0}", + "filterSearch": "Filter your search...", + "install": "Install", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", + "moreInfo": "More info", + "otherVersions": "Other Versions", + "remove": "Remove", + "title": "{0} by {1}", + "uninstall": "Uninstall", + "uninstallMsg": "Do you want to uninstall {0}?", + "update": "Update" + }, + "configuration": { + "cli": { + "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" + } + }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, + "contributions": { + "addFile": "Add File", + "fileAdded": "One file added to the sketch.", + "plotter": { + "couldNotOpen": "Couldn't open serial plotter" + }, + "replaceTitle": "Replace" + }, + "core": { + "compilerWarnings": { + "all": "All", + "default": "Default", + "more": "More", + "none": "None" + } + }, + "coreContribution": { + "copyError": "Copy error messages", + "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." + }, + "createCloudCopy": "Push Sketch to Cloud", + "daemon": { + "restart": "Restart Daemon", + "start": "Start Daemon", + "stop": "Stop Daemon" + }, + "debug": { + "debugWithMessage": "Debug - {0}", + "debuggingNotSupported": "Debugging is not supported by '{0}'", + "noPlatformInstalledFor": "Platform is not installed for '{0}'", + "optimizeForDebugging": "Optimize for Debugging", + "sketchIsNotCompiled": "Sketch '{0}' must be verified before starting a debug session. Please verify the sketch and start debugging again. Do you want to verify the sketch now?" + }, + "dialog": { + "dontAskAgain": "Don't ask again" + }, + "editor": { + "autoFormat": "Auto Format", + "commentUncomment": "Comment/Uncomment", + "copyForForum": "Copy for Forum (Markdown)", + "decreaseFontSize": "Decrease Font Size", + "decreaseIndent": "Decrease Indent", + "increaseFontSize": "Increase Font Size", + "increaseIndent": "Increase Indent", + "nextError": "Next Error", + "previousError": "Previous Error", + "revealError": "Reveal Error" + }, + "electron": { + "couldNotSave": "Could not save the sketch. Please copy your unsaved work into your favorite text editor, and restart the IDE.", + "unsavedChanges": "Any unsaved changes will not be saved." + }, + "examples": { + "builtInExamples": "Built-in examples", + "couldNotInitializeExamples": "Could not initialize built-in examples.", + "customLibrary": "Examples from Custom Libraries", + "for": "Examples for {0}", + "forAny": "Examples for any board", + "menu": "Examples" + }, + "firmware": { + "checkUpdates": "Check Updates", + "failedInstall": "Installation failed. Please try again.", + "install": "Install", + "installingFirmware": "Installing firmware.", + "overwriteSketch": "Installation will overwrite the Sketch on the board.", + "selectBoard": "Select Board", + "selectVersion": "Select firmware version", + "successfullyInstalled": "Firmware successfully installed.", + "updater": "WiFi101 / WiFiNINA Firmware Updater" + }, + "help": { + "environment": "Environment", + "faq": "Frequently Asked Questions", + "findInReference": "Find in Reference", + "gettingStarted": "Getting Started", + "keyword": "Type a keyword", + "privacyPolicy": "Privacy Policy", + "reference": "Reference", + "search": "Search on Arduino.cc", + "troubleshooting": "Troubleshooting", + "visit": "Visit Arduino.cc" + }, + "ide-updater": { + "checkForUpdates": "Check for Arduino IDE Updates", + "closeAndInstallButton": "Close and Install", + "closeToInstallNotice": "Close the software and install the update on your machine.", + "downloadButton": "Download", + "downloadingNotice": "Downloading the latest version of the Arduino IDE.", + "errorCheckingForUpdates": "Error while checking for Arduino IDE updates.\n{0}", + "goToDownloadButton": "Go To Download", + "goToDownloadPage": "An update for the Arduino IDE is available, but we're not able to download and install it automatically. Please go to the download page and download the latest version from there.", + "ideUpdaterDialog": "Software Update", + "newVersionAvailable": "A new version of Arduino IDE ({0}) is available for download.", + "noUpdatesAvailable": "There are no recent updates available for the Arduino IDE", + "notNowButton": "Not now", + "skipVersionButton": "Skip Version", + "updateAvailable": "Update Available", + "versionDownloaded": "Arduino IDE {0} has been downloaded." + }, + "library": { + "addZip": "Add .ZIP Library...", + "arduinoLibraries": "Arduino libraries", + "contributedLibraries": "Contributed libraries", + "include": "Include Library", + "installAll": "Install All", + "installLibraryDependencies": "Install library dependencies", + "installMissingDependencies": "Would you like to install all the missing dependencies?", + "installOneMissingDependency": "Would you like to install the missing dependency?", + "installWithoutDependencies": "Install without dependencies", + "installedSuccessfully": "Successfully installed library {0}:{1}", + "libraryAlreadyExists": "A library already exists. Do you want to overwrite it?", + "manageLibraries": "Manage Libraries...", + "namedLibraryAlreadyExists": "A library folder named {0} already exists. Do you want to overwrite it?", + "needsMultipleDependencies": "The library <b>{0}:{1}</b> needs some other dependencies currently not installed:", + "needsOneDependency": "The library <b>{0}:{1}</b> needs another dependency currently not installed:", + "overwriteExistingLibrary": "Do you want to overwrite the existing library?", + "successfullyInstalledZipLibrary": "Successfully installed library from {0} archive", + "title": "Library Manager", + "uninstalledSuccessfully": "Successfully uninstalled library {0}:{1}", + "zipLibrary": "Library" + }, + "librarySearchProperty": { + "topic": "Topic" + }, + "libraryTopic": { + "communication": "Communication", + "dataProcessing": "Data Processing", + "dataStorage": "Data Storage", + "deviceControl": "Device Control", + "display": "Display", + "other": "Other", + "sensors": "Sensors", + "signalInputOutput": "Signal Input/Output", + "timing": "Timing", + "uncategorized": "Uncategorized" + }, + "libraryType": { + "installed": "Installed" + }, + "menu": { + "advanced": "Advanced", + "sketch": "Sketch", + "tools": "Tools" + }, + "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", + "unableToCloseWebSocket": "Unable to close websocket", + "unableToConnectToWebSocket": "Unable to connect to websocket" + }, + "newCloudSketch": { + "newSketchTitle": "Name of the new Cloud Sketch" + }, + "portProtocol": { + "network": "Network", + "serial": "Serial" + }, + "preferences": { + "additionalManagerURLs": "Additional Boards Manager URLs", + "auth.audience": "The OAuth2 audience.", + "auth.clientID": "The OAuth2 client ID.", + "auth.domain": "The OAuth2 domain.", + "auth.registerUri": "The URI used to register a new user.", + "automatic": "Automatic", + "board.certificates": "List of certificates that can be uploaded to boards", + "browse": "Browse", + "checkForUpdate": "Receive notifications of available updates for the IDE, boards, and libraries. Requires an IDE restart after change. It's true by default.", + "choose": "Choose", + "cli.daemonDebug": "Enable debug logging of the gRPC calls to the Arduino CLI. A restart of the IDE is needed for this setting to take effect. It's false by default.", + "cloud.enabled": "True if the sketch sync functions are enabled. Defaults to true.", + "cloud.pull.warn": "True if users should be warned before pulling a cloud sketch. Defaults to true.", + "cloud.push.warn": "True if users should be warned before pushing a cloud sketch. Defaults to true.", + "cloud.pushpublic.warn": "True if users should be warned before pushing a public sketch to the cloud. Defaults to true.", + "cloud.sketchSyncEndpoint": "The endpoint used to push and pull sketches from a backend. By default it points to Arduino Cloud API.", + "compile": "compile", + "compile.experimental": "True if the IDE should handle multiple compiler errors. False by default", + "compile.revealRange": "Adjusts how compiler errors are revealed in the editor after a failed verify/upload. Possible values: 'auto': Scroll vertically as necessary and reveal a line. 'center': Scroll vertically as necessary and reveal a line centered vertically. 'top': Scroll vertically as necessary and reveal a line close to the top of the viewport, optimized for viewing a code definition. 'centerIfOutsideViewport': Scroll vertically as necessary and reveal a line centered vertically only if it lies outside the viewport. The default value is '{0}'.", + "compile.verbose": "True for verbose compile output. False by default", + "compile.warnings": "Tells gcc which warning level to use. It's 'None' by default", + "compilerWarnings": "Compiler warnings", + "editorFontSize": "Editor font size", + "editorQuickSuggestions": "Editor Quick Suggestions", + "enterAdditionalURLs": "Enter additional URLs, one for each row", + "files.inside.sketches": "Show files inside Sketches", + "ide.updateBaseUrl": "The base URL where to download updates from. Defaults to 'https://downloads.arduino.cc/arduino-ide'", + "ide.updateChannel": "Release channel to get updated from. 'stable' is the stable release, 'nightly' is the latest development build.", + "interfaceScale": "Interface scale", + "invalid.editorFontSize": "Invalid editor font size. It must be a positive integer.", + "invalid.sketchbook.location": "Invalid sketchbook location: {0}", + "invalid.theme": "Invalid theme.", + "language.log": "True if the Arduino Language Server should generate log files into the sketch folder. Otherwise, false. It's false by default.", + "language.realTimeDiagnostics": "If true, the language server provides real-time diagnostics when typing in the editor. It's false by default.", + "manualProxy": "Manual proxy configuration", + "network": "Network", + "newSketchbookLocation": "Select new sketchbook location", + "noCliConfig": "Could not load the CLI configuration", + "noProxy": "No proxy", + "proxySettings": { + "hostname": "Host name", + "password": "Password", + "port": "Port number", + "username": "Username" + }, + "showVerbose": "Show verbose output during", + "sketch": { + "inoBlueprint": "Absolute filesystem path to the default `.ino` blueprint file. If specified, the content of the blueprint file will be used for every new sketch created by the IDE. The sketches will be generated with the default Arduino content if not specified. Unaccessible blueprint files are ignored. **A restart of the IDE is needed** for this setting to take effect." + }, + "sketchbook.location": "Sketchbook location", + "sketchbook.showAllFiles": "True to show all sketch files inside the sketch. It is false by default.", + "survey.notification": "True if users should be notified if a survey is available. True by default.", + "unofficialBoardSupport": "Click for a list of unofficial board support URLs", + "upload": "upload", + "upload.verbose": "True for verbose upload output. False by default.", + "verifyAfterUpload": "Verify code after upload", + "window.autoScale": "True if the user interface automatically scales with the font size.", + "window.zoomLevel": { + "deprecationMessage": "Deprecated. Use 'window.zoomLevel' instead." + } + }, + "renameCloudSketch": { + "renameSketchTitle": "New name of the Cloud Sketch" + }, + "replaceMsg": "Replace the existing version of {0}?", + "selectZip": "Select a zip file containing the library you'd like to add", + "serial": { + "autoscroll": "Autoscroll", + "carriageReturn": "Carriage Return", + "connecting": "Connecting to '{0}' on '{1}'...", + "message": "Message (Enter to send message to '{0}' on '{1}')", + "newLine": "New Line", + "newLineCarriageReturn": "Both NL & CR", + "noLineEndings": "No Line Ending", + "notConnected": "Not connected. Select a board and a port to connect automatically.", + "openSerialPlotter": "Serial Plotter", + "timestamp": "Timestamp", + "toggleTimestamp": "Toggle Timestamp" + }, + "sketch": { + "archiveSketch": "Archive Sketch", + "cantOpen": "A folder named \"{0}\" already exists. Can't open sketch.", + "close": "Are you sure you want to close the sketch?", + "compile": "Compiling sketch...", + "configureAndUpload": "Configure and Upload", + "createdArchive": "Created archive '{0}'.", + "doneCompiling": "Done compiling.", + "doneUploading": "Done uploading.", + "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", + "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", + "exportBinary": "Export Compiled Binary", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", + "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", + "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "moving": "Moving", + "movingMsg": "The file \"{0}\" needs to be inside a sketch folder named \"{1}\".\nCreate this folder, move the file, and continue?", + "new": "New Sketch", + "noTrailingPeriod": "A filename cannot end with a dot", + "openFolder": "Open Folder", + "openRecent": "Open Recent", + "openSketchInNewWindow": "Open Sketch in New Window", + "reservedFilename": "'{0}' is a reserved filename.", + "saveFolderAs": "Save sketch folder as...", + "saveSketch": "Save your sketch to open it again later.", + "saveSketchAs": "Save sketch folder as...", + "showFolder": "Show Sketch Folder", + "sketch": "Sketch", + "sketchbook": "Sketchbook", + "titleLocalSketchbook": "Local Sketchbook", + "titleSketchbook": "Sketchbook", + "upload": "Upload", + "uploadUsingProgrammer": "Upload Using Programmer", + "uploading": "Uploading...", + "userFieldsNotFoundError": "Can't find user fields for connected board", + "verify": "Verify", + "verifyOrCompile": "Verify/Compile" + }, + "sketchbook": { + "newCloudSketch": "New Cloud Sketch", + "newSketch": "New Sketch" + }, + "survey": { + "answerSurvey": "Answer survey", + "dismissSurvey": "Don't show again", + "surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better." + }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, + "updateIndexes": { + "updateIndexes": "Update Indexes", + "updateLibraryIndex": "Update Library Index", + "updatePackageIndex": "Update Package Index" + }, + "upload": { + "error": "{0} error: {1}" + }, + "userFields": { + "cancel": "Cancel", + "enterField": "Enter {0}", + "upload": "Upload" + }, + "validateSketch": { + "abortFixMessage": "The sketch is still invalid. Do you want to fix the remaining problems? By clicking '{0}', a new sketch will open.", + "abortFixTitle": "Invalid sketch", + "renameSketchFileMessage": "The sketch file '{0}' cannot be used. {1} Do you want to rename the sketch file now?", + "renameSketchFileTitle": "Invalid sketch filename", + "renameSketchFolderMessage": "The sketch '{0}' cannot be used. {1} To get rid of this message, rename the sketch. Do you want to rename the sketch now?", + "renameSketchFolderTitle": "Invalid sketch name" + }, + "workspace": { + "alreadyExists": "'{0}' already exists." + } + }, + "theia": { + "core": { + "cannotConnectBackend": "Cannot connect to the backend.", + "cannotConnectDaemon": "Cannot connect to the CLI daemon.", + "couldNotSave": "Could not save the sketch. Please copy your unsaved work into your favorite text editor, and restart the IDE.", + "daemonOffline": "CLI Daemon Offline", + "offline": "Offline", + "offlineText": "Offline", + "quitTitle": "Are you sure you want to quit?" + }, + "editor": { + "unsavedTitle": "Unsaved – {0}" + }, + "messages": { + "collapse": "Collapse", + "expand": "Expand" + }, + "workspace": { + "deleteCloudSketch": "The cloud sketch '{0}' will be permanently deleted from the Arduino servers and the local caches. This action is irreversible. Do you want to delete the current sketch?", + "deleteCurrentSketch": "The sketch '{0}' will be permanently deleted. This action is irreversible. Do you want to delete the current sketch?", + "fileNewName": "Name for new file", + "invalidExtension": ".{0} is not a valid extension", + "newFileName": "New name for file" + } + } +} diff --git a/i18n/ca_ES.json b/i18n/ca_ES.json index 43017de46..224a0cd01 100644 --- a/i18n/ca_ES.json +++ b/i18n/ca_ES.json @@ -4,6 +4,12 @@ "detail": "Versió: {0}\nData: {1}{2}\nVersió de CLI: {3}{4} [{5}]\n\n{6}", "label": "Sobre{0}" }, + "account": { + "goToCloudEditor": "Ves a l'editor del núvol", + "goToIoTCloud": "Ves al núvol de l'IoT", + "goToProfile": "Ves al perfil", + "menuTitle": "Núvol d'Arduino" + }, "board": { "board": "Placa {0}", "boardConfigDialogTitle": "Selecciona una altra placa i port", @@ -83,13 +89,12 @@ "mouseError": "No s'ha trobat \"Mouse\". El teu programa té la línia \"#include <Mouse.h>\"?" }, "cloud": { - "account": "Compte", "chooseSketchVisibility": "Trieu la visibilitat del vostre programa:", "cloudSketchbook": "Quadern de programes del núvol", "connected": "Connectat", "continue": "Continua", "donePulling": "Descarregat correctament \"{0}\".", - "donePushing": "Enviat correctament \"{0}\".", + "donePushing": "Pujat correctament \"{0}\".", "embed": "Encasta:", "emptySketchbook": "El teu quadern de programes està buit", "goToCloud": "Ves al núvol", @@ -112,7 +117,7 @@ "remote": "Remot", "share": "Comparteix...", "shareSketch": "Comparteix programa...", - "showHideSketchbook": "Show/Hide Cloud Sketchbook", + "showHideSketchbook": "Mostra/Amaga el quadern de programes del núvol", "signIn": "Inicia sessió", "signInToCloud": "Inicia la sessió a Arduino Cloud", "signOut": "Tanca sessió", @@ -121,14 +126,14 @@ "visitArduinoCloud": "Visiteu Arduino Cloud per crear programes al núvol." }, "cloudSketch": { - "alreadyExists": "Cloud sketch '{0}' already exists.", - "creating": "Creating cloud sketch '{0}'...", - "new": "New Cloud Sketch", - "notFound": "Could not pull the cloud sketch '{0}'. It does not exist.", + "alreadyExists": "El programa del núvol \"{0}\" ja existeix.", + "creating": "Creant programa al núvol \"{0}\"...", + "new": "Programa al núvol nou", + "notFound": "No s'ha pogut baixar el programa del núvol \"{0}\". No existeix.", "pulling": "Sincronitzant quadern de programes, descarregant \"{0}\"...", - "pushing": "Synchronizing sketchbook, pushing '{0}'...", - "renaming": "Renaming cloud sketch from '{0}' to '{1}'...", - "synchronizingSketchbook": "Synchronizing sketchbook..." + "pushing": "Sincronitzant el quadern de programes, pujant \"{0}\"...", + "renaming": "Reanomenant el programa del núvol de \"{0}\" a \"{1}\"...", + "synchronizingSketchbook": "Sincronitzant el quadern de programes..." }, "common": { "all": "Tot", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "Plaques incloses al paquet:", "by": "per", + "clickToOpen": "Fes clic per obrir-ho al navegador: {0}", "filterSearch": "Filtra la teva cerca...", "install": "Instal·la", - "installed": "Instal·lat", + "installLatest": "Instal·la l'última", + "installVersion": "Instal·la {0}", + "installed": "{0} instal·lada", "moreInfo": "Més informació", + "otherVersions": "Altres versions", + "remove": "Elimina", + "title": "{0} en {1}", "uninstall": "Desinstal·la", "uninstallMsg": "Vols desinstal·lar {0}?", - "version": "Versió {0}" + "update": "Actualitza" }, "configuration": { "cli": { "inaccessibleDirectory": "No s'ha pogut accedir a la ubicació del quadern de programes a \"{0}\": {1}" } }, + "connectionStatus": { + "connectionLost": "Connexió perduda. Les accions i actualitzacions del programa del núvol no estaran disponibles." + }, "contributions": { "addFile": "Afegeix un fitxer", "fileAdded": "S'ha afegit un fitxer al programa.", @@ -188,6 +202,7 @@ "copyError": "Còpia els missatges d'error", "noBoardSelected": "No s'ha seleccionat cap placa. Tria una placa Arduino des d'Eines > Plaques" }, + "createCloudCopy": "Puja el programa al núvol", "daemon": { "restart": "Reinicia el servei", "start": "Inicia el servei", @@ -313,11 +328,18 @@ "tools": "Eines" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "No s'ha pogut tancar la ranura web", "unableToConnectToWebSocket": "No s'ha pogut connectar a la ranura web" }, "newCloudSketch": { - "newSketchTitle": "Name of the new Cloud Sketch" + "newSketchTitle": "Nom del nou programa del núvol" }, "portProtocol": { "network": "Xarxa", @@ -386,13 +408,14 @@ } }, "renameCloudSketch": { - "renameSketchTitle": "New name of the Cloud Sketch" + "renameSketchTitle": "Nou nom del programa del núvol" }, "replaceMsg": "Substitueix la versió existent de {0}?", "selectZip": "Seleccioneu un fitxer zip que contingui la llibreria que voleu afegir", "serial": { "autoscroll": "Desplaçament automàtic", "carriageReturn": "Retorn de carro", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Missatge (escriu per enviar un missatge a \"{0}\" en \"{1}\")", "newLine": "Línia nova", "newLineCarriageReturn": "Ambdós NL & CR", @@ -411,22 +434,22 @@ "createdArchive": "S'ha creat l'arxiu \"{0}\".", "doneCompiling": "Compilació enllestida.", "doneUploading": "Pujada enllestida.", - "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", - "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", + "editInvalidSketchFolderLocationQuestion": "Vols provar guardant el programa en una ubicació diferent?", + "editInvalidSketchFolderQuestion": "Vols provar guardant el programa amb un nom diferent?", "exportBinary": "Exporta el binari compilat", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", - "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", - "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", - "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidCloudSketchName": "El nom ha de començar amb una lletra, un número o una barra baixa, seguit per lletres, números, guions, punts i barres baixes. La llargària màxima és de 36 caràcters.", + "invalidSketchFolderLocationDetails": "No pots guardar un programa en una carpeta dins d'ell mateix.", + "invalidSketchFolderLocationMessage": "La carpeta d'ubicació del programa no és vàlida: \"{0}\"", + "invalidSketchFolderNameMessage": "El nom de la carpeta del programa no és vàlid: \"{0}\"", + "invalidSketchName": "El nom ha de començar amb una lletra, un número o una barra baixa, seguit per lletres, números, guions, punts i barres baixes. La llargària màxima és de 63 caràcters.", "moving": "Movent-se", "movingMsg": "El fitxer \"{0}\" ha d'estar dins d'una carpeta anomenada \"{1}\".\nVoleu crear aquesta carpeta, moure el fitxer i continuar?", "new": "Programa nou", - "noTrailingPeriod": "A filename cannot end with a dot", + "noTrailingPeriod": "Un nom de fitxer no pot acabar amb un punt", "openFolder": "Obri la carpeta", "openRecent": "Obri recent", "openSketchInNewWindow": "Obri el programa en una finestra nova", - "reservedFilename": "'{0}' is a reserved filename.", + "reservedFilename": "\"{0}\" és un nom de fitxer reservat.", "saveFolderAs": "Desa la carpeta del programa com a...", "saveSketch": "Guarda el fitxer per obrir-lo de nou més tard.", "saveSketchAs": "Desa la carpeta del programa com a...", @@ -443,7 +466,7 @@ "verifyOrCompile": "Verifica/Compila" }, "sketchbook": { - "newCloudSketch": "New Cloud Sketch", + "newCloudSketch": "Programa del núvol nou", "newSketch": "Programa nou" }, "survey": { @@ -451,6 +474,17 @@ "dismissSurvey": "No ho tornes a mostrar", "surveyMessage": "Ajuda'ns a millorar contestant aquesta enquesta súper curta. Valorem la nostra comunitat i volem conéixer els nostres usuaris un poc millor." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Núvol" + }, "updateIndexes": { "updateIndexes": "Actualitza els índexs", "updateLibraryIndex": "Actualitza l'índex de la llibreria", @@ -465,15 +499,15 @@ "upload": "Carrega" }, "validateSketch": { - "abortFixMessage": "The sketch is still invalid. Do you want to fix the remaining problems? By clicking '{0}', a new sketch will open.", - "abortFixTitle": "Invalid sketch", - "renameSketchFileMessage": "The sketch file '{0}' cannot be used. {1} Do you want to rename the sketch file now?", - "renameSketchFileTitle": "Invalid sketch filename", - "renameSketchFolderMessage": "The sketch '{0}' cannot be used. {1} To get rid of this message, rename the sketch. Do you want to rename the sketch now?", - "renameSketchFolderTitle": "Invalid sketch name" + "abortFixMessage": "El programa encara no és vàlid. Vols corregir els problemes persistents? Clicant \"{0}\" s'obrirà un nou programa.", + "abortFixTitle": "El programa no és vàlid", + "renameSketchFileMessage": "L'arxiu del programa \"{0}\" no es pot usar. {1} Vols reanomenar-lo ara?", + "renameSketchFileTitle": "El nom del fitxer del programa no és vàlid", + "renameSketchFolderMessage": "El programa \"{0}\" no es pot usar. {1} Per obtindre detalls del missatge, reanomena el programa. Vols reanomenar-lo ara?", + "renameSketchFolderTitle": "El nom del programa no és vàlid" }, "workspace": { - "alreadyExists": "'{0}' already exists." + "alreadyExists": "\"{0}\" ja existeix." } }, "theia": { @@ -483,6 +517,7 @@ "couldNotSave": "No s'ha pogut desar el programa. Copieu el vostre treball no desat al vostre editor de text preferit i reinicieu l'IDE.", "daemonOffline": "El servei CLI està fora de línia", "offline": "Fora de línia", + "offlineText": "Fora de línia", "quitTitle": "Segur que vols eixir?" }, "editor": { @@ -493,8 +528,8 @@ "expand": "Expandeix" }, "workspace": { - "deleteCloudSketch": "The cloud sketch '{0}' will be permanently deleted from the Arduino servers and the local caches. This action is irreversible. Do you want to delete the current sketch?", - "deleteCurrentSketch": "The sketch '{0}' will be permanently deleted. This action is irreversible. Do you want to delete the current sketch?", + "deleteCloudSketch": "El programa del núvol \"{0}\" s'eliminarà per sempre dels servidors d'Arduino i de les memòries cau locals. Aquesta acció no es pot desfer. Vols eliminar el programa actual?", + "deleteCurrentSketch": "Voleu eliminar el programa actual?", "fileNewName": "Nom del nou fitxer", "invalidExtension": ". {0} no és una extensió vàlida", "newFileName": "Nou nom per al fitxer" diff --git a/i18n/cs.json b/i18n/cs.json index d4a2e9eff..10fc40e72 100644 --- a/i18n/cs.json +++ b/i18n/cs.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "O {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "Deska {0}", "boardConfigDialogTitle": "Zvolit jinou Desku a Port", @@ -83,13 +89,12 @@ "mouseError": "'Mouse' not found. Does your sketch include the line '#include <Mouse.h>'?" }, "cloud": { - "account": "Účet", "chooseSketchVisibility": "Zvolte viditelnost sketche:", "cloudSketchbook": "Cloudové umístění projektů", "connected": "Připojen", "continue": "Pokračovat", - "donePulling": "Stahování dokončeno ’{0}’.", - "donePushing": "Odesílání dokončeno ‘{0}’.", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "Vložit: ", "emptySketchbook": "Umístění projektů je prázdné", "goToCloud": "Jít na Cloud", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "Boards included in this package:", "by": "od", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "Filtrovat vyhledávání... ", "install": "Instalovat", - "installed": "Nainstalováno", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "Více informací", + "otherVersions": "Other Versions", + "remove": "Odstranit", + "title": "{0} by {1}", "uninstall": "Odinstalovat", "uninstallMsg": "Chcete odinstalovat {0}?", - "version": "Verze {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "Přidat soubor", "fileAdded": "Soubor byl přidán do sketche.", @@ -188,6 +202,7 @@ "copyError": "Copy error messages", "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Restart Daemon", "start": "Spustit Daemon", @@ -313,6 +328,13 @@ "tools": "Nástroje" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Unable to close websocket", "unableToConnectToWebSocket": "Unable to connect to websocket" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "Autoscroll", "carriageReturn": "Enter (CR)", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Message (Enter to send message to '{0}' on '{1}')", "newLine": "Nový řádek (NL)", "newLineCarriageReturn": "Oba NL & CR", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "Exportovat kompilované soubory", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "Přesouvám", "movingMsg": "Soubor \"{0}\" musí být uvnitř složky která je shodná názvem \"{1}\".\nVytvořit složku, přesunout tam- soubor a pokračovat? ", "new": "New Sketch", @@ -451,6 +474,17 @@ "dismissSurvey": "Znovu nezobrazovat", "surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Update Indexes", "updateLibraryIndex": "Update Library Index", @@ -483,6 +517,7 @@ "couldNotSave": "Nebylo možné uložit sketch. Zkopírujte prosím neuloženou práci do Vašeho oblíbeného textového editoru a restartujte IDE. ", "daemonOffline": "CLI Daemon nepřipojen", "offline": "Nepřipojen", + "offlineText": "Nepřipojen", "quitTitle": "Jste si jisti že chcete odejít" }, "editor": { diff --git a/i18n/da.json b/i18n/da.json index 8fd1a3a1b..08a47309e 100644 --- a/i18n/da.json +++ b/i18n/da.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "About {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "Board{0}", "boardConfigDialogTitle": "Select Other Board and Port", @@ -83,13 +89,12 @@ "mouseError": "'Mouse' not found. Does your sketch include the line '#include <Mouse.h>'?" }, "cloud": { - "account": "Account", "chooseSketchVisibility": "Choose visibility of your Sketch:", "cloudSketchbook": "Cloud Sketchbook", "connected": "Connected", "continue": "Continue", - "donePulling": "Done pulling ‘{0}’.", - "donePushing": "Done pushing ‘{0}’.", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "Embed:", "emptySketchbook": "Your Sketchbook is empty", "goToCloud": "Go to Cloud", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "Boards included in this package:", "by": "by", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "Filter your search...", "install": "Install", - "installed": "Installed", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "More info", + "otherVersions": "Other Versions", + "remove": "Remove", + "title": "{0} by {1}", "uninstall": "Uninstall", "uninstallMsg": "Do you want to uninstall {0}?", - "version": "Version {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "Add File", "fileAdded": "One file added to the sketch.", @@ -188,6 +202,7 @@ "copyError": "Copy error messages", "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Restart Daemon", "start": "Start Daemon", @@ -313,6 +328,13 @@ "tools": "Tools" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Unable to close websocket", "unableToConnectToWebSocket": "Unable to connect to websocket" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "Autoscroll", "carriageReturn": "Carriage Return", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Message (Enter to send message to '{0}' on '{1}')", "newLine": "New Line", "newLineCarriageReturn": "Both NL & CR", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "Export Compiled Binary", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "Moving", "movingMsg": "The file \"{0}\" needs to be inside a sketch folder named \"{1}\".\nCreate this folder, move the file, and continue?", "new": "New Sketch", @@ -451,6 +474,17 @@ "dismissSurvey": "Don't show again", "surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Update Indexes", "updateLibraryIndex": "Update Library Index", @@ -483,6 +517,7 @@ "couldNotSave": "Could not save the sketch. Please copy your unsaved work into your favorite text editor, and restart the IDE.", "daemonOffline": "CLI Daemon Offline", "offline": "Offline", + "offlineText": "Offline", "quitTitle": "Are you sure you want to quit?" }, "editor": { diff --git a/i18n/de.json b/i18n/de.json index fbce134f0..f36fe6e4c 100644 --- a/i18n/de.json +++ b/i18n/de.json @@ -1,9 +1,15 @@ { "arduino": { "about": { - "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", + "detail": "Version: {0}\nDatum: {1}{2}\nCLI Version: {3}{4} [{5}]\n\n{6}", "label": "Über {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Profil aufrufen", + "menuTitle": "Arduino-Cloud" + }, "board": { "board": "Board{0}", "boardConfigDialogTitle": "Anderes Boards und Ports wählen", @@ -18,10 +24,10 @@ "installNow": "Der \"{0} {1}\" Core muss für das ausgewählte \"{2}\" Board installiert werden. Jetzt installieren?", "noBoardsFound": "Für \"{0}\" wurden keine Boards gefunden.", "noFQBN": "Der FQBN ist für das gewählte Board \"{0}\" nicht verfügbar. Wurde der zugehörige Core installiert?", - "noNativeSerialPort": "Native serial port, can't obtain info.", + "noNativeSerialPort": "Nativer serieller Port, keine Informationen verfügbar.", "noPortsDiscovered": "Keine Ports gefunden", "noPortsSelected": "Kein Port für das Board : '{0}' ausgewählt.", - "nonSerialPort": "Non-serial port, can't obtain info.", + "nonSerialPort": "Nicht-serieller Port, keine Informationen verfügbar.", "noneSelected": "Kein Board ausgewählt.", "openBoardsConfig": "Wähle einen anderes Board und einen anderen Port...", "pleasePickBoard": "Bitte wählen Sie das Board, welches am ausgewählten Port angeschlossen ist.", @@ -38,7 +44,7 @@ "succesfullyInstalledPlatform": "Plattform erfolgreich installiert {0}:{1}", "succesfullyUninstalledPlatform": "Plattform erfolgreich deinstalliert {0}:{1}", "typeOfPorts": "{0} Ports", - "unknownBoard": "Unknown board" + "unknownBoard": "Unbekanntes Board" }, "boardsManager": "Board-Verwaltung", "boardsType": { @@ -83,7 +89,6 @@ "mouseError": "'Mouse' nicht gefunden. Enthält ihr Sketch die Zeile '#include <Mouse.h>'?" }, "cloud": { - "account": "Konto", "chooseSketchVisibility": "Wähle die Sichtbarkeit deines Sketches:", "cloudSketchbook": "Cloud Sketchbook", "connected": "Verbunden", @@ -121,13 +126,13 @@ "visitArduinoCloud": "Besuche Arduino Cloud um Cloud Sketche zu erstellen." }, "cloudSketch": { - "alreadyExists": "Cloud sketch '{0}' already exists.", - "creating": "Creating cloud sketch '{0}'...", - "new": "New Cloud Sketch", - "notFound": "Could not pull the cloud sketch '{0}'. It does not exist.", + "alreadyExists": "Cloud-Sketch '{0}' existiert bereits.", + "creating": "Cloud-Sketch '{0}' wird erstellt...", + "new": "Neuer Cloud-Sketch", + "notFound": "Cloud-Sketch '{0}' konnte nicht heruntergeladen werden. Er existiert nicht.", "pulling": "Synchronizing sketchbook, pulling '{0}'...", "pushing": "Synchronizing sketchbook, pushing '{0}'...", - "renaming": "Renaming cloud sketch from '{0}' to '{1}'...", + "renaming": "Cloud-Sketch wird von '{0}' nach '{1}' umbenannt ...", "synchronizingSketchbook": "Synchronizing sketchbook..." }, "common": { @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "In diesem Paket enthaltene Boards:", "by": "von", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "Filtern Sie Ihre Suche ...", "install": "Installieren", - "installed": "Installiert", + "installLatest": "Install Latest", + "installVersion": "Installiere {0}", + "installed": "{0} installiert", "moreInfo": "Mehr Information", + "otherVersions": "Andere Versionen", + "remove": "Entfernen", + "title": "{0} durch {1}", "uninstall": "Deinstallieren", "uninstallMsg": "Möchten Sie {0} deinstallieren?", - "version": "Version {0}" + "update": "Aktualisieren" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "Datei hinzufügen...", "fileAdded": "Eine Datei wurde zum Sketch hinzugefügt.", @@ -188,6 +202,7 @@ "copyError": "Fehlermeldungen kopieren", "noBoardSelected": "Kein Board ausgewählt. Bitte Arduino Board im Menü wählen mit Werkzeuge > Board" }, + "createCloudCopy": "Sketch in Cloud hochladen", "daemon": { "restart": "Daemon neustarten", "start": "Daemon starten", @@ -313,11 +328,18 @@ "tools": "Werkzeuge" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Websocket wurde nicht geschlossen", "unableToConnectToWebSocket": "Websocket wurde nicht verbunden" }, "newCloudSketch": { - "newSketchTitle": "Name of the new Cloud Sketch" + "newSketchTitle": "Name des neuen Cloud-Sketches" }, "portProtocol": { "network": "Netzwerk", @@ -361,7 +383,7 @@ "manualProxy": "Manuelle Proxy Einstellung", "network": "Netzwerk", "newSketchbookLocation": "Wähle einen neuen Ort für das Sketchbook ", - "noCliConfig": "Could not load the CLI configuration", + "noCliConfig": "CLI-Konfiguration konnte nicht geladen werden", "noProxy": "Kein Proxy", "proxySettings": { "hostname": "Hostname", @@ -371,7 +393,7 @@ }, "showVerbose": "Compiler-Meldungen anzeigen beim", "sketch": { - "inoBlueprint": "Absolute filesystem path to the default `.ino` blueprint file. If specified, the content of the blueprint file will be used for every new sketch created by the IDE. The sketches will be generated with the default Arduino content if not specified. Unaccessible blueprint files are ignored. **A restart of the IDE is needed** for this setting to take effect." + "inoBlueprint": "Absoluter Dateipfad zur Standard-'.ino'-Dateivorlage. Wenn angegeben, wird der Inhalt der Dateivorlage für jeden, mit der IDE erstellten, Sketch verwendet. Wenn nicht angegeben, werden die Sketches mit dem Standard-Arduino-Inhalt erstellt. Unauffindbare Dateivorlagen werden ignoriert. **Ein Neustarten der IDE ist erforderlich**, um diese Einstellung zu übernehmen." }, "sketchbook.location": "Dateipfad des Sketchbooks", "sketchbook.showAllFiles": "Wenn aktiviert, werden alle Sketch-Dateien innerhalb des Sketch angezeigt. Standardgemäß deaktiviert. ", @@ -382,17 +404,18 @@ "verifyAfterUpload": "Code nach Hochladen überprüfen ", "window.autoScale": "Wenn aktiviert: Benutzeroberfläche soll mit Schriftgröße skalieren.", "window.zoomLevel": { - "deprecationMessage": "Deprecated. Use 'window.zoomLevel' instead." + "deprecationMessage": "Veraltet. Bitte 'window.zommLevel' stattdessen benutzen." } }, "renameCloudSketch": { - "renameSketchTitle": "New name of the Cloud Sketch" + "renameSketchTitle": "Neuer Name des Cloud-Sketches" }, "replaceMsg": "Existierende Version von {0} ersetzen?", "selectZip": "Wähle die ZIP-Datei, welche die hinzuzufügende Bibliothek enthält", "serial": { "autoscroll": "Automatisch scrollen", "carriageReturn": "Zeilenumbruch", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Nachicht (Enter um Nachricht für '{0}' auf '{1}' zu senden)", "newLine": "Neue Zeile", "newLineCarriageReturn": "Sowohl NL als auch CR", @@ -411,22 +434,22 @@ "createdArchive": "Archiv '{0}' erstellt.", "doneCompiling": "Kompilieren erfolgreich!", "doneUploading": "Hochladen erfolgreich! ", - "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", - "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", + "editInvalidSketchFolderLocationQuestion": "Wollen Sie versuchen, den Sketch an einer anderen Stelle abzuspeichern?", + "editInvalidSketchFolderQuestion": "Wollen Sie versuchen, den Sketch mit einem anderen Namen abzuspeichern?", "exportBinary": "Kompilierte Binärdatei exportieren", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "Der Name muss mit einem Buchstaben, einer Ziffer oder einem Unterstrich beginnen und darf Buchstaben, Ziffern, Bindestriche, Punkte und Unterstriche enthalten. Die maximale Länge ist 36 Zeichen.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", - "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchFolderNameMessage": "Ungültiger Name für einen Sketch-Ordner: '{0}'", + "invalidSketchName": "Der Name muss mit einem Buchstaben, einer Ziffer oder einem Unterstrich beginnen und darf Buchstaben, Ziffern, Bindestriche, Punkte und Unterstriche enthalten. Die maximale Länge ist 63 Zeichen.", "moving": "Übertragen...", "movingMsg": "Die Datei \"{0}\" muss sich in einen Sketch Ordner \"{1}\" befinden.\nOrdner erstellen, Datei verschieben und fortfahren?", - "new": "New Sketch", - "noTrailingPeriod": "A filename cannot end with a dot", + "new": "Neu", + "noTrailingPeriod": "Ein Dateiname kann nicht mit einem Punkt enden", "openFolder": "Ordner öffnen", "openRecent": "Zuletzt geöffnet", "openSketchInNewWindow": "Sketch in neuen Fenster öffnen", - "reservedFilename": "'{0}' is a reserved filename.", + "reservedFilename": "'{0}' ist ein reservierter Dateiname.", "saveFolderAs": "Sketch Ordner speichern als...", "saveSketch": "Sketch speichern und später wieder öffnen", "saveSketchAs": "Sketch Ordner speichern als...", @@ -443,14 +466,25 @@ "verifyOrCompile": "Überprüfen/Kompilieren" }, "sketchbook": { - "newCloudSketch": "New Cloud Sketch", - "newSketch": "New Sketch" + "newCloudSketch": "Neuer Cloud-Sketch", + "newSketch": "Neu" }, "survey": { "answerSurvey": "Umfrage beantworten", "dismissSurvey": "Nicht erneut anzeigen", "surveyMessage": "Helfen Sie uns, uns zu verbessern, indem Sie diese kurze Umfrage ausfüllen. Wir wissen unsere Community wertzuschätzen und möchten unsere Unterstützer gerne ein wenig besser kennenlernen." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Indizes aktualisieren", "updateLibraryIndex": "Bibliotheksverzeichnis aktualisieren", @@ -465,15 +499,15 @@ "upload": "Hochladen" }, "validateSketch": { - "abortFixMessage": "The sketch is still invalid. Do you want to fix the remaining problems? By clicking '{0}', a new sketch will open.", - "abortFixTitle": "Invalid sketch", - "renameSketchFileMessage": "The sketch file '{0}' cannot be used. {1} Do you want to rename the sketch file now?", - "renameSketchFileTitle": "Invalid sketch filename", - "renameSketchFolderMessage": "The sketch '{0}' cannot be used. {1} To get rid of this message, rename the sketch. Do you want to rename the sketch now?", - "renameSketchFolderTitle": "Invalid sketch name" + "abortFixMessage": "Der Sketch ist noch immer ungültig. Sollen die verbliebenen Probleme behoben werden? Durch Klicken auf '{0}' wird ein neuer Sketch geöffnet.", + "abortFixTitle": "Ungültiger Sketch", + "renameSketchFileMessage": "Die Sketch-Datei '{0}' kann nicht verwendet werden. {1} Soll die Sketch-Datei jetzt umbenannt werden?", + "renameSketchFileTitle": "Ungültiger Sketch-Dateiname", + "renameSketchFolderMessage": "Der Sketch '{0}' kann nicht verwendet werden. {1} Um diese Nachricht loszuwerden, muss der Sketch umbenannt werden. Wollen Sie den Sketch jetzt umbenennen?", + "renameSketchFolderTitle": "Ungültiger Sketch-Name" }, "workspace": { - "alreadyExists": "'{0}' already exists." + "alreadyExists": "{0} existiert bereits." } }, "theia": { @@ -483,6 +517,7 @@ "couldNotSave": "Der Sketch konnte nicht gesichert werden. Bitte kopiere deine ungesicherte Arbeit in deinen bevorzugten Texteditor und starte die IDE neu.", "daemonOffline": "CLI Daemon Offline", "offline": "Offline", + "offlineText": "Offline", "quitTitle": "Sind Sie sicher, dass das Fenster schließen möchten?" }, "editor": { @@ -493,8 +528,8 @@ "expand": "Ausklappen" }, "workspace": { - "deleteCloudSketch": "The cloud sketch '{0}' will be permanently deleted from the Arduino servers and the local caches. This action is irreversible. Do you want to delete the current sketch?", - "deleteCurrentSketch": "The sketch '{0}' will be permanently deleted. This action is irreversible. Do you want to delete the current sketch?", + "deleteCloudSketch": "Der Cloud-Sketch '{0}' wird dauerhaft vpn den Arduino-Servern und den lokalen Caches gelöscht. Diese Aktion ist nicht umkehrbar. Wollen Sie den aktuellen Sketch löschen?", + "deleteCurrentSketch": "Der Sketch '{0}' wird dauerhaft gelöscht. Diese Aktion ist nicht umkehrbar. Wollen Sie den aktuellen Sketch löschen?", "fileNewName": "Name für die neue Datei", "invalidExtension": "\".{0}\" ist keine gültige Dateierweiterung.", "newFileName": "Neuer Name für die Datei" diff --git a/i18n/el.json b/i18n/el.json index b12595f4e..f69125e70 100644 --- a/i18n/el.json +++ b/i18n/el.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "Σχετικά με {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "Πλακέτα{0}", "boardConfigDialogTitle": "Select Other Board and Port", @@ -55,7 +61,7 @@ "certificate": { "addNew": "Προσθήκη Νέου", "addURL": "Add URL to fetch SSL certificate", - "boardAtPort": "{0} at {1}", + "boardAtPort": "{0} στο {1}", "certificatesUploaded": "Certificates uploaded.", "enterURL": "Enter URL", "noSupportedBoardConnected": "No supported board connected", @@ -83,13 +89,12 @@ "mouseError": "'Mouse' not found. Does your sketch include the line '#include <Mouse.h>'?" }, "cloud": { - "account": "Account", "chooseSketchVisibility": "Επίλεξε την ορατότητα του Σχεδίου σου:", "cloudSketchbook": "Σχέδια Cloud", "connected": "Συνδέθηκε", "continue": "Συνέχεια", - "donePulling": "Done pulling ‘{0}’.", - "donePushing": "Done pushing ‘{0}’.", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "Ενσωμάτωση:", "emptySketchbook": "Τα Σχέδια σου είναι άδεια.", "goToCloud": "Go to Cloud", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "Boards included in this package:", "by": "από", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "Filter your search...", "install": "Εγκατάσταση", - "installed": "Installed", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "Περισσότερες πληροφορίες", + "otherVersions": "Other Versions", + "remove": "Αφαίρεση", + "title": "{0} by {1}", "uninstall": "Απεγκατάσταση", "uninstallMsg": "Do you want to uninstall {0}?", - "version": "Έκδοση {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "Προσθήκη αρχείου", "fileAdded": "Ένα αρχείο προστέθηκε στον κώδικα.", @@ -188,6 +202,7 @@ "copyError": "Copy error messages", "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Restart Daemon", "start": "Start Daemon", @@ -216,7 +231,7 @@ "revealError": "Reveal Error" }, "electron": { - "couldNotSave": "Could not save the sketch. Please copy your unsaved work into your favorite text editor, and restart the IDE.", + "couldNotSave": "Δεν έγινε αποθήκευση του προγράμματος. Παρακαλώ αντιγράψτε ό,τι δεν έχει αποθηκευθεί στον αγαπημένο σας επεξεργαστή κειμένου, και επανεκινήστε το Ολοκληρωμένο Περιβάλλον Ανάπτυξης IDE.", "unsavedChanges": "Οι μη αποθηκευμένες αλλαγές θα χαθούν." }, "examples": { @@ -313,6 +328,13 @@ "tools": "Εργαλεία" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Unable to close websocket", "unableToConnectToWebSocket": "Unable to connect to websocket" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "Autoscroll", "carriageReturn": "Carriage Return", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Message (Enter to send message to '{0}' on '{1}')", "newLine": "Νέα γραμμή", "newLineCarriageReturn": "Both NL & CR", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "Export Compiled Binary", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "Moving", "movingMsg": "The file \"{0}\" needs to be inside a sketch folder named \"{1}\".\nCreate this folder, move the file, and continue?", "new": "New Sketch", @@ -451,6 +474,17 @@ "dismissSurvey": "Don't show again", "surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Update Indexes", "updateLibraryIndex": "Update Library Index", @@ -483,6 +517,7 @@ "couldNotSave": "Δεν έγινε αποθήκευση του προγράμματος. Παρακαλώ αντιγράψτε ό,τι δεν έχει αποθηκευθεί στον αγαπημένο σας επεξεργαστή κειμένου, και επανεκινήστε το Ολοκληρωμένο Περιβάλλον Ανάπτυξης IDE.", "daemonOffline": "CLI Daemon Offline", "offline": "Εκτός Σύνδεσης", + "offlineText": "Εκτός Σύνδεσης", "quitTitle": "Are you sure you want to quit?" }, "editor": { diff --git a/i18n/es.json b/i18n/es.json index c498a5476..6cb212da6 100644 --- a/i18n/es.json +++ b/i18n/es.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "Acerca de {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Ir al Perfil", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "Placa{0}", "boardConfigDialogTitle": "Seleccionar Otra Placa y Puerto", @@ -38,7 +44,7 @@ "succesfullyInstalledPlatform": "Plataforma {0}:{1} instalada correctamente", "succesfullyUninstalledPlatform": "Plataforma {0}:{1} desinstalada correctamente", "typeOfPorts": "{0} puertos", - "unknownBoard": "Unknown board" + "unknownBoard": "Placa desconocida" }, "boardsManager": "Gestor de placas", "boardsType": { @@ -83,13 +89,12 @@ "mouseError": "'Mouse' no encontrado. ¿Tiene tu proyecto incluida la linea '#include <Mouse.h>'?" }, "cloud": { - "account": "Cuenta", "chooseSketchVisibility": "Elige la visibilidad de tu Sketch:", "cloudSketchbook": "Libro de bocetos en la nube", "connected": "Conectado", "continue": "Continuar", - "donePulling": "Extracción de '{0}' realizada.", - "donePushing": "Envío a '{0}' realizado.", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "Incrustado:", "emptySketchbook": "Tu Sketchbook está vacío", "goToCloud": "Ir al Cloud", @@ -128,7 +133,7 @@ "pulling": "Synchronizing sketchbook, pulling '{0}'...", "pushing": "Synchronizing sketchbook, pushing '{0}'...", "renaming": "Renaming cloud sketch from '{0}' to '{1}'...", - "synchronizingSketchbook": "Synchronizing sketchbook..." + "synchronizingSketchbook": "Sincronizando carpeta..." }, "common": { "all": "Todo", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "Placas incluidas en este paquete:", "by": "de", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "Filtre su búsqueda...", "install": "Instalar", - "installed": "Instalado", + "installLatest": "Install Latest", + "installVersion": "Instalar {0}", + "installed": "{0}instalado", "moreInfo": "Más información", + "otherVersions": "Otras versiones", + "remove": "Eliminar", + "title": "{0} by {1}", "uninstall": "Desinstalar", "uninstallMsg": "¿Quieres desinstalar {0}?", - "version": "Versión {0}" + "update": "Actualizar" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "Añadir fichero...", "fileAdded": "Un archivo añadido al sketch.", @@ -188,6 +202,7 @@ "copyError": "Copiar mensajes de error", "noBoardSelected": "Ninguna placa seleccionada. Por favor selecciona una placa Arduino en el menú Herramientas > Placas" }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Reiniciar Daemon", "start": "Iniciar Daemon", @@ -313,6 +328,13 @@ "tools": "Herramientas" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "No se puede cerrar websocket", "unableToConnectToWebSocket": "No se puede conectar al websocket" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "Autoscroll", "carriageReturn": "Retorno de carro", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Mensaje (Intro para mandar el mensaje de '{0}' a '{1}')", "newLine": "Nueva línea", "newLineCarriageReturn": "Ambos NL & CR", @@ -411,18 +434,18 @@ "createdArchive": "Archivo '{0}' creado.", "doneCompiling": "Compilación completada.", "doneUploading": "Carga completada.", - "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", - "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", + "editInvalidSketchFolderLocationQuestion": "¿Quieres intentar guardar el código en una ubicación diferente?", + "editInvalidSketchFolderQuestion": "¿Quieres intentar guardar el código con un nombre diferente?", "exportBinary": "Exportar binario compilado", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "El nombre debe comenzar con una letra, un número, o un guión bajo, seguido de letras, números, guiones, puntos y guiones bajos. El máximo número de caracteres es 36.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "El nombre debe comenzar con una letra, un número, o un guión bajo, seguido de letras, números, guiones, puntos y guiones bajos. El máximo número de caracteres es 63.", "moving": "Moviendo", "movingMsg": "El archivo \"{0}\" tiene que estar dentro de una carpeta de bocetos llamada \"{1}\".\n¿Crear esta carpeta, mover el archivo y continuar?", "new": "New Sketch", - "noTrailingPeriod": "A filename cannot end with a dot", + "noTrailingPeriod": "El nombre del archivo no puede terminar con un punto.", "openFolder": "Abrir carpeta", "openRecent": "Abierto recientemente", "openSketchInNewWindow": "Abrir Sketch en una ventana nueva", @@ -451,6 +474,17 @@ "dismissSurvey": "No volver a mostrar", "surveyMessage": "Por favor ayudenos mejorar completando esta breve encuesta. Valoramos nuestra comunidad y nos gustaría conocer algo mejor a los que nos apoyan." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Actualizar indices", "updateLibraryIndex": "Actualizar Indice de librerías", @@ -473,7 +507,7 @@ "renameSketchFolderTitle": "Invalid sketch name" }, "workspace": { - "alreadyExists": "'{0}' already exists." + "alreadyExists": "'{0}' ya existe." } }, "theia": { @@ -483,6 +517,7 @@ "couldNotSave": "No se ha podido guardar el sketch. Por favor, copia tu trabajo no guardado en tu editor de texto favorito y reinicia el IDE.", "daemonOffline": "Demonio del CLI fuera de línea", "offline": "Desconectado", + "offlineText": "Desconectado", "quitTitle": "Seguro que quiere salir ?" }, "editor": { @@ -494,7 +529,7 @@ }, "workspace": { "deleteCloudSketch": "The cloud sketch '{0}' will be permanently deleted from the Arduino servers and the local caches. This action is irreversible. Do you want to delete the current sketch?", - "deleteCurrentSketch": "The sketch '{0}' will be permanently deleted. This action is irreversible. Do you want to delete the current sketch?", + "deleteCurrentSketch": "El código '{0}' será permanentemente eliminado. Esta acción es irreversible. ¿Quieres eliminar el código actual?", "fileNewName": "Nombre del nuevo archivo", "invalidExtension": "\".{0}\" no es una extensión válida", "newFileName": "Nuevo nombre para el archivo" diff --git a/i18n/eu.json b/i18n/eu.json index 71b238814..1603763c3 100644 --- a/i18n/eu.json +++ b/i18n/eu.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "{0}ri buruz" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "{0} plaka", "boardConfigDialogTitle": "Select Other Board and Port", @@ -83,13 +89,12 @@ "mouseError": "'Mouse' not found. Does your sketch include the line '#include <Mouse.h>'?" }, "cloud": { - "account": "Account", "chooseSketchVisibility": "Aukeratu zure programaren ikusgaitasuna:", "cloudSketchbook": "Hodeiko programa bilduma", "connected": "Konektatuta", "continue": "Jarraitu", - "donePulling": "Hodeitik kargatzea burututa: '{0}'.", - "donePushing": "Hodeian gordetzea burututa: '{0}'.", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "Kapsulatu:", "emptySketchbook": "Zure programa bilduma hutsik dago", "goToCloud": "Go to Cloud", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "Boards included in this package:", "by": "Egilea:", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "Iragazi zure bilaketa...", "install": "Instalatu", - "installed": "Installed", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "Informazio gehiago", + "otherVersions": "Other Versions", + "remove": "Kendu", + "title": "{0} by {1}", "uninstall": "Desinstalatu", "uninstallMsg": "{0} desinstalatu nahi duzu?", - "version": "{0} bertsioa" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "Gehitu fitxategia", "fileAdded": "Fitxategi bat gehitu da programara.", @@ -188,6 +202,7 @@ "copyError": "Copy error messages", "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Restart Daemon", "start": "Start Daemon", @@ -313,6 +328,13 @@ "tools": "Tresnak" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Unable to close websocket", "unableToConnectToWebSocket": "Unable to connect to websocket" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "Korritze automatikoa", "carriageReturn": "Orga-itzulera", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Message (Enter to send message to '{0}' on '{1}')", "newLine": "Lerro berria", "newLineCarriageReturn": "NL & CR biak", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "Esportatu konpilatutako bitarra", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "Lekuz aldatzen", "movingMsg": "\"{0}\" fitxategiak \"{1}\" izeneko programa-karpetaren barruan egon behar du.\nSortu karpeta, eraman fitxategia bertara eta jarraitu?", "new": "New Sketch", @@ -451,6 +474,17 @@ "dismissSurvey": "Don't show again", "surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Update Indexes", "updateLibraryIndex": "Update Library Index", @@ -483,6 +517,7 @@ "couldNotSave": "Ezin izan da programa gorde. Kopiatu gorde gabeko zure lana zure testu-editore gogokoenera eta berrabiarazi IDEa.", "daemonOffline": "CLI daemon-a lineaz kanpo", "offline": "Lineaz kanpo", + "offlineText": "Lineaz kanpo", "quitTitle": "Are you sure you want to quit?" }, "editor": { diff --git a/i18n/fa.json b/i18n/fa.json index 40a13963e..b0af6dd47 100644 --- a/i18n/fa.json +++ b/i18n/fa.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "درباره {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "بورد {0}", "boardConfigDialogTitle": "انتخاب یک بورد و پورت دیگر", @@ -83,13 +89,12 @@ "mouseError": "\"موس\" پیدا نشد. آیا طرح شما شامل خط \"#include <Mouse.h>\" است؟" }, "cloud": { - "account": "حساب کاربری", "chooseSketchVisibility": "قابلیت مشاهده طرح خود را انتخاب کنید:", "cloudSketchbook": "منبع ابری طرح ها", "connected": "متصل", "continue": "ادامه", - "donePulling": "پایان دریافت {0}", - "donePushing": "پایان ارسال {0}", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "قرار دادن:", "emptySketchbook": "طرح شما خالی است", "goToCloud": "به فضای ابری بروید", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "بردهای موجود در این بسته :", "by": "توسط", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "محدود کردن جستجوی شما ...", "install": "نصب", - "installed": "نصب شده است", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "اطلاعات بیشتر", + "otherVersions": "Other Versions", + "remove": "حذف", + "title": "{0} by {1}", "uninstall": "لغو نصب", "uninstallMsg": "آیا شما می خواهید {0} را لغو نصب کنید؟", - "version": "ورژن {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "فایل اظافه کن", "fileAdded": "یک فایل به طرح افزوده شد.", @@ -188,6 +202,7 @@ "copyError": "کپی پیام های خطا", "noBoardSelected": "هیچ بردی انتخاب نشده است. لطفاً برد آردوینو خود را از منوی Tools > Board انتخاب کنید" }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "راه اندازی مجدد Daemon", "start": "شروع Daemon", @@ -313,6 +328,13 @@ "tools": "ابزار ها" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "بسته شدن وب سوکت ممکن نیست", "unableToConnectToWebSocket": "اتصال به وب سوکت امکان پذیر نیست" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "پیمایش خودکار", "carriageReturn": "رفتن به سر سطر", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "پیام (برای ارسال پیام به '' د{0}ر '' وارد شوید{1})", "newLine": "خط جدید", "newLineCarriageReturn": "هم NL و هم CR", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "دریافت خروجی باینری کامپایل شده", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "جابجا کردن", "movingMsg": "فایل \"{0}\" باید داخل یک پوشه طرح به نام \"{1}\" باشد.\nاین پوشه را ایجاد کنید، فایل را منتقل کنید و ادامه دهید؟", "new": "New Sketch", @@ -451,6 +474,17 @@ "dismissSurvey": "دیگر نشان نده", "surveyMessage": "لطفاً با پاسخ دادن به این نظرسنجی فوق العاده کوتاه ما را در پیشرفت خود یاری کنید. ما برای جامعه خود ارزش قائلیم و دوست داریم حامیان خود را کمی بهتر بشناسیم." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "به روز رسانی شاخص ها", "updateLibraryIndex": "به روز رسانی فهرست کتابخانه", @@ -483,6 +517,7 @@ "couldNotSave": "ابر طرح را ذخیره نکرد. لطفا کار ذخیره نشده خود را به ویرایشگر متن مورد علاقه خود کپی کنید، و آردوینو را دوباره راه اندازی کنید.", "daemonOffline": "CLI آفلاین پس زمینه", "offline": "آفلاین", + "offlineText": "آفلاین", "quitTitle": "آیا مطمئن هستید که می خواهید خارج شوید؟" }, "editor": { diff --git a/i18n/fil.json b/i18n/fil.json index 710477141..8520aa969 100644 --- a/i18n/fil.json +++ b/i18n/fil.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "About {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "Board{0}", "boardConfigDialogTitle": "Select Other Board and Port", @@ -83,13 +89,12 @@ "mouseError": "'Mouse' not found. Does your sketch include the line '#include <Mouse.h>'?" }, "cloud": { - "account": "Account", "chooseSketchVisibility": "Choose visibility of your Sketch:", "cloudSketchbook": "Cloud Sketchbook", "connected": "Connected", "continue": "Continue", - "donePulling": "Done pulling ‘{0}’.", - "donePushing": "Done pushing ‘{0}’.", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "Embed:", "emptySketchbook": "Your Sketchbook is empty", "goToCloud": "Go to Cloud", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "Boards included in this package:", "by": "by", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "Filter your search...", "install": "Install", - "installed": "Installed", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "More info", + "otherVersions": "Other Versions", + "remove": "Remove", + "title": "{0} by {1}", "uninstall": "Uninstall", "uninstallMsg": "Do you want to uninstall {0}?", - "version": "Version {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "Add File", "fileAdded": "One file added to the sketch.", @@ -188,6 +202,7 @@ "copyError": "Copy error messages", "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Restart Daemon", "start": "Start Daemon", @@ -233,7 +248,7 @@ "install": "Install", "installingFirmware": "Installing firmware.", "overwriteSketch": "Installation will overwrite the Sketch on the board.", - "selectBoard": "Select Board", + "selectBoard": "Pumili ng board", "selectVersion": "Select firmware version", "successfullyInstalled": "Firmware successfully installed.", "updater": "WiFi101 / WiFiNINA Firmware Updater" @@ -313,6 +328,13 @@ "tools": "Mga Tools" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Unable to close websocket", "unableToConnectToWebSocket": "Unable to connect to websocket" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "Autoscroll", "carriageReturn": "Carriage Return", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Message (Enter to send message to '{0}' on '{1}')", "newLine": "New Line", "newLineCarriageReturn": "Both NL & CR", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "Export Compiled Binary", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "Moving", "movingMsg": "The file \"{0}\" needs to be inside a sketch folder named \"{1}\".\nCreate this folder, move the file, and continue?", "new": "New Sketch", @@ -451,6 +474,17 @@ "dismissSurvey": "Don't show again", "surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Update Indexes", "updateLibraryIndex": "Update Library Index", @@ -483,6 +517,7 @@ "couldNotSave": "Could not save the sketch. Please copy your unsaved work into your favorite text editor, and restart the IDE.", "daemonOffline": "CLI Daemon Offline", "offline": "Offline", + "offlineText": "Offline", "quitTitle": "Are you sure you want to quit?" }, "editor": { diff --git a/i18n/fr.json b/i18n/fr.json index dced35c4d..0ea17712a 100644 --- a/i18n/fr.json +++ b/i18n/fr.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "A propos de {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "Carte{0}", "boardConfigDialogTitle": "Select Other Board and Port", @@ -83,13 +89,12 @@ "mouseError": "'Mouse' not found. Does your sketch include the line '#include <Mouse.h>'?" }, "cloud": { - "account": "Compte", "chooseSketchVisibility": "Choisissez la visibilité du croquis :", "cloudSketchbook": "Carnet de Croquis Cloud", "connected": "Connecté", "continue": "Continuer", - "donePulling": "Récupération de '{0}' terminée.", - "donePushing": "Téléchargement terminé pour '{0}'", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "Embarqué : ", "emptySketchbook": "Votre carnet de croquis est vide", "goToCloud": "Go to Cloud", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "Boards included in this package:", "by": "par", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "Filtrez votre recherche...", "install": "Installer", - "installed": "Installed", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "Plus d'information", + "otherVersions": "Other Versions", + "remove": "Supprimer ", + "title": "{0} by {1}", "uninstall": "Désinstaller", "uninstallMsg": "Voulez vous désinstaller {0}?", - "version": "Version {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "Ajouter un fichier", "fileAdded": "Un fichier a été ajouté au croquis", @@ -188,6 +202,7 @@ "copyError": "Copier les messages d'erreur", "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Redémarrer Daemon", "start": "Démarrer Daemon", @@ -313,6 +328,13 @@ "tools": "Outils" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Impossible de fermer le web socket", "unableToConnectToWebSocket": "Impossible de se connecter au web socket" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "Défilement automatique", "carriageReturn": "Retour chariot", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Message (Enter to send message to '{0}' on '{1}')", "newLine": "Nouvelle ligne", "newLineCarriageReturn": "Les deux, NL et CR", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "Exporter les binaires compilés", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "Déplacement", "movingMsg": "Le fichier \"{0}\" à besoin d'être à l'intérieur d'un dossier de croquis appelé \"{1}\".\nCréer ce dossier, déplacer le fichier et continuer ?", "new": "New Sketch", @@ -451,6 +474,17 @@ "dismissSurvey": "Ne pas montrer de nouveau", "surveyMessage": "Aide-nous à nous améliorer en répondant à cette enquête très courte. Nous apprécions notre communauté et nous aimerions connaître un peu mieux nos supporters." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Update Indexes", "updateLibraryIndex": "Update Library Index", @@ -483,6 +517,7 @@ "couldNotSave": "Impossible d'enregistrer le croquis. Veuillez copier votre travail non enregistré dans votre éditeur de texte favori et redémarrer l'IDE.", "daemonOffline": "CLI Deamon hors ligne", "offline": "Hors-ligne", + "offlineText": "Hors-ligne", "quitTitle": "Est que-vous sur vous voulez quitter? " }, "editor": { diff --git a/i18n/he.json b/i18n/he.json index 0f55630b2..2b727b281 100644 --- a/i18n/he.json +++ b/i18n/he.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "פרטים על {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "לוח{0}", "boardConfigDialogTitle": "יש לבחור לוח ופורט אחר", @@ -83,13 +89,12 @@ "mouseError": "'Mouse' not found. Does your sketch include the line '#include <Mouse.h>'?" }, "cloud": { - "account": "חשבון", "chooseSketchVisibility": "בחר.י נראות של הסקיצה שלך:", "cloudSketchbook": "Cloud Sketchbook", "connected": "מחובר", "continue": "המשך", - "donePulling": "סיים למשוך '{0}'.", - "donePushing": "סיים לדחוף '{0}'.", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "הטמע:", "emptySketchbook": "הסקיצה ריקה.", "goToCloud": "Go to Cloud", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "לוחות המוכלים בחבילות הבאות:", "by": "על ידי", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "סנן את החיפוש...", "install": "התקן", - "installed": "Installed", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "מידע נוסף", + "otherVersions": "Other Versions", + "remove": "הסר", + "title": "{0} by {1}", "uninstall": "הסרה", "uninstallMsg": "האם ברצונך להסיר את {0}?", - "version": "גירסה {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "הוסף קובץ", "fileAdded": "קובץ אחד נוסף לסקיצה.", @@ -188,6 +202,7 @@ "copyError": "העתקת הודעת שגיאה", "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "איתחול מחדש של Daemon", "start": "התחל Daemon", @@ -313,6 +328,13 @@ "tools": "כלים" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Unable to close websocket", "unableToConnectToWebSocket": "Unable to connect to websocket" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "גלילה אוטומטית", "carriageReturn": "Carriage Return", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Message (Enter to send message to '{0}' on '{1}')", "newLine": "שורה חדשה", "newLineCarriageReturn": "Both NL & CR", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "ייצוא בינארי מקומפל.", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "מעביר", "movingMsg": "The file \"{0}\" needs to be inside a sketch folder named \"{1}\".\nCreate this folder, move the file, and continue?", "new": "New Sketch", @@ -451,6 +474,17 @@ "dismissSurvey": "אל תראה שוב.", "surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Update Indexes", "updateLibraryIndex": "Update Library Index", @@ -483,6 +517,7 @@ "couldNotSave": "לא ניתן לשמור את הסקיצה. נא להעתיק את העבודה הלא שמורה לתוך עורך טקסט חיצוני, ולהפעיל מחדש את הIDE.", "daemonOffline": "CLI daemon במצב לא מקוון", "offline": "מנותק", + "offlineText": "מנותק", "quitTitle": "בטוח.ה שתרצה.י לצאת?" }, "editor": { diff --git a/i18n/hi.json b/i18n/hi.json index 19a3645e0..08a47309e 100644 --- a/i18n/hi.json +++ b/i18n/hi.json @@ -1,41 +1,58 @@ { "arduino": { "about": { - "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}{4} [{5}]\n\n{6}", + "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "About {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "Board{0}", + "boardConfigDialogTitle": "Select Other Board and Port", "boardInfo": "Board Info", + "boards": "boards", "configDialog1": "Select both a Board and a Port if you want to upload a sketch.", "configDialog2": "If you only select a Board you will be able to compile, but not to upload your sketch.", - "configDialogTitle": "Select Other Board & Port", "couldNotFindPreviouslySelected": "Could not find previously selected board '{0}' in installed platform '{1}'. Please manually reselect the board you want to use. Do you want to reselect it now?", "disconnected": "Disconnected", "getBoardInfo": "Get Board Info", "inSketchbook": " (in Sketchbook)", - "installManually": "Install Manually", "installNow": "The \"{0} {1}\" core has to be installed for the currently selected \"{2}\" board. Do you want to install it now?", + "noBoardsFound": "No boards found for \"{0}\"", "noFQBN": "The FQBN is not available for the selected board \"{0}\". Do you have the corresponding core installed?", + "noNativeSerialPort": "Native serial port, can't obtain info.", + "noPortsDiscovered": "No ports discovered", "noPortsSelected": "No ports selected for board: '{0}'.", + "nonSerialPort": "Non-serial port, can't obtain info.", "noneSelected": "No boards selected.", "openBoardsConfig": "Select other board and port…", - "platformMissing": "The platform for the selected '{0}' board is not installed.", "pleasePickBoard": "Please pick a board connected to the port you have selected.", "port": "Port{0}", "portLabel": "Port: {0}", + "ports": "ports", "programmer": "Programmer", "reselectLater": "Reselect later", + "searchBoard": "Search board", "selectBoard": "Select Board", - "selectBoardForInfo": "Please select a board to obtain board info.", "selectPortForInfo": "Please select a port to obtain board info.", "showAllAvailablePorts": "Shows all available ports when enabled", + "showAllPorts": "Show all ports", "succesfullyInstalledPlatform": "Successfully installed platform {0}:{1}", - "succesfullyUninstalledPlatform": "Successfully uninstalled platform {0}:{1}" + "succesfullyUninstalledPlatform": "Successfully uninstalled platform {0}:{1}", + "typeOfPorts": "{0} ports", + "unknownBoard": "Unknown board" }, "boardsManager": "Boards Manager", + "boardsType": { + "arduinoCertified": "Arduino Certified" + }, "bootloader": { "burnBootloader": "Burn Bootloader", + "burningBootloader": "Burning bootloader...", "doneBurningBootloader": "Done burning bootloader." }, "burnBootloader": { @@ -58,19 +75,29 @@ "uploadRootCertificates": "Upload SSL Root Certificates", "uploadingCertificates": "Uploading certificates." }, + "checkForUpdates": { + "checkForUpdates": "Check for Arduino Updates", + "installAll": "Install All", + "noUpdates": "There are no recent updates available.", + "promptUpdateBoards": "Updates are available for some of your boards.", + "promptUpdateLibraries": "Updates are available for some of your libraries.", + "updatingBoards": "Updating boards...", + "updatingLibraries": "Updating libraries..." + }, "cli-error-parser": { "keyboardError": "'Keyboard' not found. Does your sketch include the line '#include <Keyboard.h>'?", "mouseError": "'Mouse' not found. Does your sketch include the line '#include <Mouse.h>'?" }, "cloud": { - "account": "Account", "chooseSketchVisibility": "Choose visibility of your Sketch:", + "cloudSketchbook": "Cloud Sketchbook", "connected": "Connected", "continue": "Continue", - "donePulling": "Done pulling ‘{0}’.", - "donePushing": "Done pushing ‘{0}’.", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "Embed:", "emptySketchbook": "Your Sketchbook is empty", + "goToCloud": "Go to Cloud", "learnMore": "Learn more", "link": "Link:", "notYetPulled": "Cannot push to Cloud. It is not yet pulled.", @@ -88,10 +115,9 @@ "pushSketch": "Push Sketch", "pushSketchMsg": "This is a Public Sketch. Before pushing, make sure any sensitive information is defined in arduino_secrets.h files. You can make a Sketch private from the Share panel.", "remote": "Remote", - "remoteSketchbook": "Remote Sketchbook", "share": "Share...", "shareSketch": "Share Sketch", - "showHideRemoveSketchbook": "Show/Hide Remote Sketchbook", + "showHideSketchbook": "Show/Hide Cloud Sketchbook", "signIn": "SIGN IN", "signInToCloud": "Sign in to Arduino Cloud", "signOut": "Sign Out", @@ -99,38 +125,84 @@ "syncEditSketches": "Sync and edit your Arduino Cloud Sketches", "visitArduinoCloud": "Visit Arduino Cloud to create Cloud Sketches." }, + "cloudSketch": { + "alreadyExists": "Cloud sketch '{0}' already exists.", + "creating": "Creating cloud sketch '{0}'...", + "new": "New Cloud Sketch", + "notFound": "Could not pull the cloud sketch '{0}'. It does not exist.", + "pulling": "Synchronizing sketchbook, pulling '{0}'...", + "pushing": "Synchronizing sketchbook, pushing '{0}'...", + "renaming": "Renaming cloud sketch from '{0}' to '{1}'...", + "synchronizingSketchbook": "Synchronizing sketchbook..." + }, "common": { + "all": "All", + "contributed": "Contributed", + "installManually": "Install Manually", "later": "Later", "noBoardSelected": "No board selected", "notConnected": "[not connected]", "offlineIndicator": "You appear to be offline. Without an Internet connection, the Arduino CLI might not be able to download the required resources and could cause malfunction. Please connect to the Internet and restart the application.", "oldFormat": "The '{0}' still uses the old `.pde` format. Do you want to switch to the new `.ino` extension?", + "partner": "Partner", "processing": "Processing", - "selectBoard": "Select Board", + "recommended": "Recommended", + "retired": "Retired", "selectedOn": "on {0}", "serialMonitor": "Serial Monitor", - "unknown": "Unknown" + "type": "Type", + "unknown": "Unknown", + "updateable": "Updatable" }, "compile": { "error": "Compilation error: {0}" }, "component": { + "boardsIncluded": "Boards included in this package:", "by": "by", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "Filter your search...", - "install": "INSTALL", + "install": "Install", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "More info", + "otherVersions": "Other Versions", + "remove": "Remove", + "title": "{0} by {1}", "uninstall": "Uninstall", "uninstallMsg": "Do you want to uninstall {0}?", - "version": "Version {0}" + "update": "Update" + }, + "configuration": { + "cli": { + "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" + } + }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." }, "contributions": { "addFile": "Add File", "fileAdded": "One file added to the sketch.", + "plotter": { + "couldNotOpen": "Couldn't open serial plotter" + }, "replaceTitle": "Replace" }, + "core": { + "compilerWarnings": { + "all": "All", + "default": "Default", + "more": "More", + "none": "None" + } + }, "coreContribution": { - "copyError": "Copy error messages" + "copyError": "Copy error messages", + "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Restart Daemon", "start": "Start Daemon", @@ -140,7 +212,8 @@ "debugWithMessage": "Debug - {0}", "debuggingNotSupported": "Debugging is not supported by '{0}'", "noPlatformInstalledFor": "Platform is not installed for '{0}'", - "optimizeForDebugging": "Optimize for Debugging" + "optimizeForDebugging": "Optimize for Debugging", + "sketchIsNotCompiled": "Sketch '{0}' must be verified before starting a debug session. Please verify the sketch and start debugging again. Do you want to verify the sketch now?" }, "dialog": { "dontAskAgain": "Don't ask again" @@ -154,7 +227,8 @@ "increaseFontSize": "Increase Font Size", "increaseIndent": "Increase Indent", "nextError": "Next Error", - "previousError": "Previous Error" + "previousError": "Previous Error", + "revealError": "Reveal Error" }, "electron": { "couldNotSave": "Could not save the sketch. Please copy your unsaved work into your favorite text editor, and restart the IDE.", @@ -192,7 +266,7 @@ "visit": "Visit Arduino.cc" }, "ide-updater": { - "checkForUpdates": "Check for Arduino IDE updates", + "checkForUpdates": "Check for Arduino IDE Updates", "closeAndInstallButton": "Close and Install", "closeToInstallNotice": "Close the software and install the update on your machine.", "downloadButton": "Download", @@ -212,12 +286,12 @@ "addZip": "Add .ZIP Library...", "arduinoLibraries": "Arduino libraries", "contributedLibraries": "Contributed libraries", - "dependenciesForLibrary": "Dependencies for library {0}:{1}", "include": "Include Library", - "installAll": "Install all", + "installAll": "Install All", + "installLibraryDependencies": "Install library dependencies", "installMissingDependencies": "Would you like to install all the missing dependencies?", "installOneMissingDependency": "Would you like to install the missing dependency?", - "installOnly": "Install {0} only", + "installWithoutDependencies": "Install without dependencies", "installedSuccessfully": "Successfully installed library {0}:{1}", "libraryAlreadyExists": "A library already exists. Do you want to overwrite it?", "manageLibraries": "Manage Libraries...", @@ -230,15 +304,47 @@ "uninstalledSuccessfully": "Successfully uninstalled library {0}:{1}", "zipLibrary": "Library" }, + "librarySearchProperty": { + "topic": "Topic" + }, + "libraryTopic": { + "communication": "Communication", + "dataProcessing": "Data Processing", + "dataStorage": "Data Storage", + "deviceControl": "Device Control", + "display": "Display", + "other": "Other", + "sensors": "Sensors", + "signalInputOutput": "Signal Input/Output", + "timing": "Timing", + "uncategorized": "Uncategorized" + }, + "libraryType": { + "installed": "Installed" + }, "menu": { "advanced": "Advanced", "sketch": "Sketch", "tools": "Tools" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Unable to close websocket", "unableToConnectToWebSocket": "Unable to connect to websocket" }, + "newCloudSketch": { + "newSketchTitle": "Name of the new Cloud Sketch" + }, + "portProtocol": { + "network": "Network", + "serial": "Serial" + }, "preferences": { "additionalManagerURLs": "Additional Boards Manager URLs", "auth.audience": "The OAuth2 audience.", @@ -248,6 +354,7 @@ "automatic": "Automatic", "board.certificates": "List of certificates that can be uploaded to boards", "browse": "Browse", + "checkForUpdate": "Receive notifications of available updates for the IDE, boards, and libraries. Requires an IDE restart after change. It's true by default.", "choose": "Choose", "cli.daemonDebug": "Enable debug logging of the gRPC calls to the Arduino CLI. A restart of the IDE is needed for this setting to take effect. It's false by default.", "cloud.enabled": "True if the sketch sync functions are enabled. Defaults to true.", @@ -276,8 +383,18 @@ "manualProxy": "Manual proxy configuration", "network": "Network", "newSketchbookLocation": "Select new sketchbook location", + "noCliConfig": "Could not load the CLI configuration", "noProxy": "No proxy", + "proxySettings": { + "hostname": "Host name", + "password": "Password", + "port": "Port number", + "username": "Username" + }, "showVerbose": "Show verbose output during", + "sketch": { + "inoBlueprint": "Absolute filesystem path to the default `.ino` blueprint file. If specified, the content of the blueprint file will be used for every new sketch created by the IDE. The sketches will be generated with the default Arduino content if not specified. Unaccessible blueprint files are ignored. **A restart of the IDE is needed** for this setting to take effect." + }, "sketchbook.location": "Sketchbook location", "sketchbook.showAllFiles": "True to show all sketch files inside the sketch. It is false by default.", "survey.notification": "True if users should be notified if a survey is available. True by default.", @@ -286,14 +403,20 @@ "upload.verbose": "True for verbose upload output. False by default.", "verifyAfterUpload": "Verify code after upload", "window.autoScale": "True if the user interface automatically scales with the font size.", - "window.zoomLevel": "Adjust the zoom level of the window. The original size is 0 and each increment above (e.g. 1) or below (e.g. -1) represents zooming 20% larger or smaller. You can also enter decimals to adjust the zoom level with a finer granularity." + "window.zoomLevel": { + "deprecationMessage": "Deprecated. Use 'window.zoomLevel' instead." + } + }, + "renameCloudSketch": { + "renameSketchTitle": "New name of the Cloud Sketch" }, "replaceMsg": "Replace the existing version of {0}?", "selectZip": "Select a zip file containing the library you'd like to add", "serial": { "autoscroll": "Autoscroll", "carriageReturn": "Carriage Return", - "message": "Message ({0} + Enter to send message to '{1}' on '{2}')", + "connecting": "Connecting to '{0}' on '{1}'...", + "message": "Message (Enter to send message to '{0}' on '{1}')", "newLine": "New Line", "newLineCarriageReturn": "Both NL & CR", "noLineEndings": "No Line Ending", @@ -306,20 +429,30 @@ "archiveSketch": "Archive Sketch", "cantOpen": "A folder named \"{0}\" already exists. Can't open sketch.", "close": "Are you sure you want to close the sketch?", - "configureAndUpload": "Configure And Upload", + "compile": "Compiling sketch...", + "configureAndUpload": "Configure and Upload", "createdArchive": "Created archive '{0}'.", "doneCompiling": "Done compiling.", "doneUploading": "Done uploading.", + "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", + "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "Export Compiled Binary", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", + "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", + "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "Moving", "movingMsg": "The file \"{0}\" needs to be inside a sketch folder named \"{1}\".\nCreate this folder, move the file, and continue?", - "new": "New", + "new": "New Sketch", + "noTrailingPeriod": "A filename cannot end with a dot", "openFolder": "Open Folder", "openRecent": "Open Recent", "openSketchInNewWindow": "Open Sketch in New Window", + "reservedFilename": "'{0}' is a reserved filename.", "saveFolderAs": "Save sketch folder as...", + "saveSketch": "Save your sketch to open it again later.", "saveSketchAs": "Save sketch folder as...", - "saveTempSketch": "Save your sketch to open it again later.", "showFolder": "Show Sketch Folder", "sketch": "Sketch", "sketchbook": "Sketchbook", @@ -327,26 +460,56 @@ "titleSketchbook": "Sketchbook", "upload": "Upload", "uploadUsingProgrammer": "Upload Using Programmer", + "uploading": "Uploading...", "userFieldsNotFoundError": "Can't find user fields for connected board", "verify": "Verify", "verifyOrCompile": "Verify/Compile" }, + "sketchbook": { + "newCloudSketch": "New Cloud Sketch", + "newSketch": "New Sketch" + }, "survey": { "answerSurvey": "Answer survey", "dismissSurvey": "Don't show again", "surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, + "updateIndexes": { + "updateIndexes": "Update Indexes", + "updateLibraryIndex": "Update Library Index", + "updatePackageIndex": "Update Package Index" + }, "upload": { "error": "{0} error: {1}" }, "userFields": { "cancel": "Cancel", + "enterField": "Enter {0}", "upload": "Upload" + }, + "validateSketch": { + "abortFixMessage": "The sketch is still invalid. Do you want to fix the remaining problems? By clicking '{0}', a new sketch will open.", + "abortFixTitle": "Invalid sketch", + "renameSketchFileMessage": "The sketch file '{0}' cannot be used. {1} Do you want to rename the sketch file now?", + "renameSketchFileTitle": "Invalid sketch filename", + "renameSketchFolderMessage": "The sketch '{0}' cannot be used. {1} To get rid of this message, rename the sketch. Do you want to rename the sketch now?", + "renameSketchFolderTitle": "Invalid sketch name" + }, + "workspace": { + "alreadyExists": "'{0}' already exists." } }, - "cloud": { - "GoToCloud": "GO TO CLOUD" - }, "theia": { "core": { "cannotConnectBackend": "Cannot connect to the backend.", @@ -354,14 +517,9 @@ "couldNotSave": "Could not save the sketch. Please copy your unsaved work into your favorite text editor, and restart the IDE.", "daemonOffline": "CLI Daemon Offline", "offline": "Offline", - "quitMessage": "Any unsaved changes will not be saved.", + "offlineText": "Offline", "quitTitle": "Are you sure you want to quit?" }, - "debug": { - "start": "Start...", - "startError": "There was an error starting the debug session, check the logs for more details.", - "typeNotSupported": "The debug session type \"{0}\" is not supported." - }, "editor": { "unsavedTitle": "Unsaved – {0}" }, @@ -370,10 +528,10 @@ "expand": "Expand" }, "workspace": { - "deleteCurrentSketch": "Do you want to delete the current sketch?", + "deleteCloudSketch": "The cloud sketch '{0}' will be permanently deleted from the Arduino servers and the local caches. This action is irreversible. Do you want to delete the current sketch?", + "deleteCurrentSketch": "The sketch '{0}' will be permanently deleted. This action is irreversible. Do you want to delete the current sketch?", "fileNewName": "Name for new file", "invalidExtension": ".{0} is not a valid extension", - "invalidFilename": "Invalid filename.", "newFileName": "New name for file" } } diff --git a/i18n/hu.json b/i18n/hu.json index cff9eebc3..ab78b060a 100644 --- a/i18n/hu.json +++ b/i18n/hu.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "About {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "Alaplap {0}", "boardConfigDialogTitle": "Select Other Board and Port", @@ -83,13 +89,12 @@ "mouseError": "'Mouse' not found. Does your sketch include the line '#include <Mouse.h>'?" }, "cloud": { - "account": "Account", "chooseSketchVisibility": "Válaszd ki a vázlat/sketch láthatóságát: ", "cloudSketchbook": "Felhő vázlatfüzet/sketchbook ", "connected": "Kapcsolódva", "continue": "Tovább", - "donePulling": "Letöltés kész: '{0}'.", - "donePushing": "Feltöltés kész: '{0}'.", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "Beágyazva:", "emptySketchbook": "A vázlatfüzeted/Sketchbook-od üres ", "goToCloud": "Go to Cloud", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "Boards included in this package:", "by": "által", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "Keresési eredmény szűrése... ", "install": "Telepítés", - "installed": "Installed", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "Több info", + "otherVersions": "Other Versions", + "remove": "Eltávolítás", + "title": "{0} by {1}", "uninstall": "Eltávolítás", "uninstallMsg": "El szeretnéd távolítani a következőt: {0}? ", - "version": "Verzió: {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "Fájl hozzáadása", "fileAdded": "Egy fájl hozzáadása megtörtént a vázlathoz/sketch-hez. ", @@ -188,6 +202,7 @@ "copyError": "Copy error messages", "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Restart Daemon", "start": "Start Daemon", @@ -313,6 +328,13 @@ "tools": "Eszközök" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Unable to close websocket", "unableToConnectToWebSocket": "Unable to connect to websocket" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "Automatikus görgetés", "carriageReturn": "Kocsi vissza", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Message (Enter to send message to '{0}' on '{1}')", "newLine": "Új sor", "newLineCarriageReturn": "Mindkettő: Új sor és Kocsi vissza - NL&CR", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "Összeállított bináris exportálása", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "Mozgatás", "movingMsg": "The file \"{0}\" needs to be inside a sketch folder named \"{1}\".\nCreate this folder, move the file, and continue?", "new": "New Sketch", @@ -451,6 +474,17 @@ "dismissSurvey": "Don't show again", "surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Update Indexes", "updateLibraryIndex": "Update Library Index", @@ -483,6 +517,7 @@ "couldNotSave": "Nem sikerült menteni a vázlatot/sketch-et. Másold át a nem mentett munkát kedvenc szövegszerkesztődbe és indítsd újra az IDE-t. ", "daemonOffline": "CLI Daemon offline/elérhetetlen ", "offline": "Offline / nincs hálózat", + "offlineText": "Offline / nincs hálózat", "quitTitle": "Are you sure you want to quit?" }, "editor": { diff --git a/i18n/id.json b/i18n/id.json index 8fd1a3a1b..08a47309e 100644 --- a/i18n/id.json +++ b/i18n/id.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "About {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "Board{0}", "boardConfigDialogTitle": "Select Other Board and Port", @@ -83,13 +89,12 @@ "mouseError": "'Mouse' not found. Does your sketch include the line '#include <Mouse.h>'?" }, "cloud": { - "account": "Account", "chooseSketchVisibility": "Choose visibility of your Sketch:", "cloudSketchbook": "Cloud Sketchbook", "connected": "Connected", "continue": "Continue", - "donePulling": "Done pulling ‘{0}’.", - "donePushing": "Done pushing ‘{0}’.", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "Embed:", "emptySketchbook": "Your Sketchbook is empty", "goToCloud": "Go to Cloud", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "Boards included in this package:", "by": "by", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "Filter your search...", "install": "Install", - "installed": "Installed", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "More info", + "otherVersions": "Other Versions", + "remove": "Remove", + "title": "{0} by {1}", "uninstall": "Uninstall", "uninstallMsg": "Do you want to uninstall {0}?", - "version": "Version {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "Add File", "fileAdded": "One file added to the sketch.", @@ -188,6 +202,7 @@ "copyError": "Copy error messages", "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Restart Daemon", "start": "Start Daemon", @@ -313,6 +328,13 @@ "tools": "Tools" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Unable to close websocket", "unableToConnectToWebSocket": "Unable to connect to websocket" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "Autoscroll", "carriageReturn": "Carriage Return", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Message (Enter to send message to '{0}' on '{1}')", "newLine": "New Line", "newLineCarriageReturn": "Both NL & CR", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "Export Compiled Binary", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "Moving", "movingMsg": "The file \"{0}\" needs to be inside a sketch folder named \"{1}\".\nCreate this folder, move the file, and continue?", "new": "New Sketch", @@ -451,6 +474,17 @@ "dismissSurvey": "Don't show again", "surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Update Indexes", "updateLibraryIndex": "Update Library Index", @@ -483,6 +517,7 @@ "couldNotSave": "Could not save the sketch. Please copy your unsaved work into your favorite text editor, and restart the IDE.", "daemonOffline": "CLI Daemon Offline", "offline": "Offline", + "offlineText": "Offline", "quitTitle": "Are you sure you want to quit?" }, "editor": { diff --git a/i18n/it.json b/i18n/it.json index 4d37bae14..535028fb9 100644 --- a/i18n/it.json +++ b/i18n/it.json @@ -4,6 +4,12 @@ "detail": "Versione: {0}\nData: {1}{2}\nVersione CLI: {3}\n\n{4}", "label": "Informazioni su {0}" }, + "account": { + "goToCloudEditor": "Vai all'editor del cloud", + "goToIoTCloud": "Vai al cloud IoT", + "goToProfile": "Vai al profilo", + "menuTitle": "Cloud di Arduino" + }, "board": { "board": "Scheda{0}", "boardConfigDialogTitle": "Seleziona un'altra scheda e un'altra porta", @@ -83,13 +89,12 @@ "mouseError": "'Mouse' non è stato trovato. Il tuo sketch include la linea '#include <Mouse.h>' nel codice?" }, "cloud": { - "account": "Account", "chooseSketchVisibility": "Scegli a chi far vedere il tuo Sketch:", "cloudSketchbook": "Cloud Sketchbook", "connected": "Connesso", "continue": "Continua", - "donePulling": "Pulling terminato ‘{0}’.", - "donePushing": "Invio terminato ‘{0}’.", + "donePulling": "Scaricamento di '{0}' effettuato.", + "donePushing": "Invio di '{0}' effettuato.", "embed": "Includi:", "emptySketchbook": "La raccolta degli sketch è vuota", "goToCloud": "Vai al Cloud", @@ -112,7 +117,7 @@ "remote": "Remoto", "share": "Condividi...", "shareSketch": "Condividi sketch", - "showHideSketchbook": "Show/Hide Cloud Sketchbook", + "showHideSketchbook": "Mostra/Nascondi la raccolta remota degli sketch", "signIn": "ACCEDI", "signInToCloud": "Effettua la registrazione su Arduino Cloud", "signOut": "Disconnetti", @@ -121,14 +126,14 @@ "visitArduinoCloud": "Visita Arduino Cloud per creare Cloud Sketch " }, "cloudSketch": { - "alreadyExists": "Cloud sketch '{0}' already exists.", - "creating": "Creating cloud sketch '{0}'...", - "new": "New Cloud Sketch", - "notFound": "Could not pull the cloud sketch '{0}'. It does not exist.", + "alreadyExists": "Lo sketch remoto '{0}' è già presente.", + "creating": "Creazione in corso dello sketch remoto '{0}'...", + "new": "Nuovo Sketch remoto", + "notFound": "Impossibile scaricare lo sketch remoto '{0}'. Non esiste.", "pulling": "Sincronizzazione degli sketch, pulling \"{0}\"...", - "pushing": "Synchronizing sketchbook, pushing '{0}'...", - "renaming": "Renaming cloud sketch from '{0}' to '{1}'...", - "synchronizingSketchbook": "Synchronizing sketchbook..." + "pushing": "Sincronizzazione della raccolta degli sketch in corso, sto inviando '{0}'...", + "renaming": "Sto rinominando lo sketch remoto da '{0}' a '{1}'...", + "synchronizingSketchbook": "Sincronizzazione della raccolta degli sketch in corso..." }, "common": { "all": "Tutti", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "Schede incluse in questo pacchetto:", "by": "da", + "clickToOpen": "Cliccare per aprire nel browser: {0}", "filterSearch": "Filtra la tua ricerca...", "install": "Installa", - "installed": "Installata", + "installLatest": "Installa il più recente", + "installVersion": "Installa {0}", + "installed": "{0} installato", "moreInfo": "Maggiori informazioni", + "otherVersions": "Altre versioni", + "remove": "Rimuovi", + "title": "{0} di {1}", "uninstall": "Disinstalla", "uninstallMsg": "Vuoi veramente disinstallare {0}?", - "version": "Versione {0}" + "update": "Aggiornamento" }, "configuration": { "cli": { "inaccessibleDirectory": "Impossibile accedere alla raccolta degli sketch presenti in '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connessione persa. Le azioni e gli aggiornamenti degli sketch del cloud non saranno disponibili." + }, "contributions": { "addFile": "Aggiungi file", "fileAdded": "Aggiunto un file allo sketch.", @@ -188,6 +202,7 @@ "copyError": "Copia messaggi di errore", "noBoardSelected": "Non è stata selezionata alcuna scheda. Selezionare la tua scheda Arduino dal menu Strumenti > Scheda." }, + "createCloudCopy": "Invia lo sketch nel cloud", "daemon": { "restart": "Riavvia il demone", "start": "Avvia il demone", @@ -313,11 +328,18 @@ "tools": "Strumenti" }, "monitor": { + "alreadyConnectedError": "Impossibile connettere alla porta {0} {1}. Già connesso.", + "baudRate": "{0} baud", + "connectionFailedError": "Impossibile connettere alla porta {0} {1}.", + "connectionFailedErrorWithDetails": "{0} Impossibile connettere alla porta {1} {2}.", + "connectionTimeout": "Tempo scaduto. L'IDE non ha ricevuto il messaggio di 'successo' dal monitor dopo essersi connesso con esso.", + "missingConfigurationError": "Impossibile connettere alla porta {0} {1}. Manca la configurazione del monitor.", + "notConnectedError": "Non connesso alla porta {0} {1}.", "unableToCloseWebSocket": "Impossibile chiudere il websocket", "unableToConnectToWebSocket": "Impossibile connettersi al websocket" }, "newCloudSketch": { - "newSketchTitle": "Name of the new Cloud Sketch" + "newSketchTitle": "Nome del nuovo sketch remoto" }, "portProtocol": { "network": "Rete", @@ -386,13 +408,14 @@ } }, "renameCloudSketch": { - "renameSketchTitle": "New name of the Cloud Sketch" + "renameSketchTitle": "Nuovo nome dello sketch remoto" }, "replaceMsg": "Sostituire la versione esistente con la versione {0}?", "selectZip": "Scegli il file zip che contiene la libreria che vuoi aggiungere", "serial": { "autoscroll": "Scorrimento automatico", "carriageReturn": "Ritorno carrello (CR)", + "connecting": "Connessione in corso di '{0}' su '{1}'...", "message": "Messaggio (premi Enter per inviare il messaggio a '{0}' on '{1}')", "newLine": "A capo (NL)", "newLineCarriageReturn": "Entrambi NL & CR", @@ -411,22 +434,22 @@ "createdArchive": "Creato l'archivio '{0}'.", "doneCompiling": "Compilazione completata.", "doneUploading": "Caricamento terminato.", - "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", - "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", + "editInvalidSketchFolderLocationQuestion": "Vuoi provare a salvare lo sketch in una posizione diversa?", + "editInvalidSketchFolderQuestion": "Vuoi provare a salvare lo sketch con un nome diverso?", "exportBinary": "Esporta sketch compilato", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", - "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", - "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", - "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidCloudSketchName": "Il nome deve iniziare con una lettera, un numero o un trattino basso, seguito da lettere, numeri, trattini, punti e trattini bassi. La lunghezza massima è di 36 caratteri.", + "invalidSketchFolderLocationDetails": "Non è possibile salvare uno sketch in una cartella al suo interno.", + "invalidSketchFolderLocationMessage": "Posizione della cartella degli sketch non valida: '{0}'", + "invalidSketchFolderNameMessage": "Nome della cartella degli sketch non valida: '{0}'", + "invalidSketchName": "Il nome deve iniziare con una lettera, un numero o un trattino basso, seguito da lettere, numeri, trattini, punti e trattini bassi. La lunghezza massima è di 63 caratteri.", "moving": "Spostando", "movingMsg": "Il file \"{0}\" deve essere all'interno della cartella \"{1}\".\nCreare questa cartella, spostare il file e continuare?", "new": "Nuovo Sketch", - "noTrailingPeriod": "A filename cannot end with a dot", + "noTrailingPeriod": "Il nome di un file non può terminare con un punto", "openFolder": "Apri Cartella", "openRecent": "Apri recenti", "openSketchInNewWindow": "Apri lo sketch in una Nuova Finestra", - "reservedFilename": "'{0}' is a reserved filename.", + "reservedFilename": "'{0}' è il nome di un file riservato.", "saveFolderAs": "Salva la cartella sketch come...", "saveSketch": "Salva il tuo sketch per riaprirlo in seguito.", "saveSketchAs": "Salva la cartella dello sketch come...", @@ -443,7 +466,7 @@ "verifyOrCompile": "Verifica/Compila" }, "sketchbook": { - "newCloudSketch": "New Cloud Sketch", + "newCloudSketch": "Nuovo sketch remoto", "newSketch": "Nuovo Sketch" }, "survey": { @@ -451,6 +474,17 @@ "dismissSurvey": "Non mostrare più", "surveyMessage": "Aiutaci a migliorare rispondendo a questo brevissimo questionario. Abbiamo a cuore la nostra comunità e vorremmo conoscere meglio chi ci supporta!" }, + "theme": { + "currentThemeNotFound": "Impossibile trovare il tema attualmente selezionato: {0}. Arduino IDE ha selezionato un tema integrato compatibile con quello mancante.", + "dark": "Scuro", + "deprecated": "{0} (deprecato)", + "hc": "Alto contrasto", + "light": "Luce", + "user": "{0} (utente)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Aggiorna gli indici", "updateLibraryIndex": "Aggiorna l'indice di libreria", @@ -465,15 +499,15 @@ "upload": "Carica" }, "validateSketch": { - "abortFixMessage": "The sketch is still invalid. Do you want to fix the remaining problems? By clicking '{0}', a new sketch will open.", - "abortFixTitle": "Invalid sketch", - "renameSketchFileMessage": "The sketch file '{0}' cannot be used. {1} Do you want to rename the sketch file now?", - "renameSketchFileTitle": "Invalid sketch filename", - "renameSketchFolderMessage": "The sketch '{0}' cannot be used. {1} To get rid of this message, rename the sketch. Do you want to rename the sketch now?", - "renameSketchFolderTitle": "Invalid sketch name" + "abortFixMessage": "Lo sketch non è ancora valido. Vuoi risolvere i problemi rimanenti? Facendo clic su '{0}', si aprirà un nuovo sketch.", + "abortFixTitle": "Lo sketch non è valido", + "renameSketchFileMessage": "Il file dello sketch '{0}' non può essere usato. {1} Vuoi rinominare adesso lo sketch?", + "renameSketchFileTitle": "Il nome del file dello sketch non è valido", + "renameSketchFolderMessage": "Lo sketch '{0}' non può essere usato. {1} Per eliminare questo messaggio, rinomina lo sketch. Vuoi rinominare adesso lo sketch?", + "renameSketchFolderTitle": "Il nome dello sketch non è valido" }, "workspace": { - "alreadyExists": "'{0}' already exists." + "alreadyExists": "'{0}' è già presente." } }, "theia": { @@ -483,6 +517,7 @@ "couldNotSave": "Non è stato possibile salvare lo sketch. Si consiglia di copiarlo è salvarlo su un file di testo e solo successivamente riavviare l' Arduino IDE. ", "daemonOffline": "Il CLI Daemon è disconnesso", "offline": "Offline", + "offlineText": "Offline", "quitTitle": "Sei sicuro di volere chiudere?" }, "editor": { @@ -493,8 +528,8 @@ "expand": "Espandi" }, "workspace": { - "deleteCloudSketch": "The cloud sketch '{0}' will be permanently deleted from the Arduino servers and the local caches. This action is irreversible. Do you want to delete the current sketch?", - "deleteCurrentSketch": "The sketch '{0}' will be permanently deleted. This action is irreversible. Do you want to delete the current sketch?", + "deleteCloudSketch": "Lo sketch remoto '{0}' sarà eliminato definitivamente dai server di Arduino e dalle cache locali. Questa azione è irreversibile. Vuoi eliminare lo sketch?", + "deleteCurrentSketch": "Vuoi eliminare lo sketch attuale?", "fileNewName": "Nome per il nuovo file", "invalidExtension": "\".{0}\" non è un'estensione valida", "newFileName": "Nuovo nome del file" diff --git a/i18n/ja.json b/i18n/ja.json index 0d8981ba7..857e377d8 100644 --- a/i18n/ja.json +++ b/i18n/ja.json @@ -4,6 +4,12 @@ "detail": "バージョン:{0}\n日付:{1}{2}\nCLIバージョン:{3}\n\n{4}", "label": "{0}について" }, + "account": { + "goToCloudEditor": "クラウドエディターへ移動", + "goToIoTCloud": "IoTクラウドへ移動", + "goToProfile": "プロファイルへ移動", + "menuTitle": "Arduinoクラウド" + }, "board": { "board": "ボード{0}", "boardConfigDialogTitle": "他のボードとポートを選択", @@ -83,13 +89,12 @@ "mouseError": "'Mouse'が見つかりません。スケッチに'#include <Mouse.h>'という行はありますか?" }, "cloud": { - "account": "アカウント", "chooseSketchVisibility": "スケッチの可視性を選択:", "cloudSketchbook": "クラウドスケッチブック", "connected": "接続済み", "continue": "続ける", - "donePulling": "‘{0}’のプルが完了しました。", - "donePushing": "‘{0}’のプッシュが完了しました。", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "埋め込み:", "emptySketchbook": "スケッチブックは空です", "goToCloud": "クラウドへ", @@ -97,7 +102,7 @@ "link": "リンク:", "notYetPulled": "クラウドにプッシュできません。まだプルされていません。", "offline": "オフライン", - "openInCloudEditor": "クラウドエディタで開く", + "openInCloudEditor": "クラウドエディターで開く", "options": "オプション…", "privateVisibility": "プライベート:スケッチを見られるのは自分だけです。", "profilePicture": "プロフィール画像", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "このパッケージに含まれるボード:", "by": "by", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "検索をフィルタ…", "install": "インストール", - "installed": "インストール済み", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "詳細情報", + "otherVersions": "Other Versions", + "remove": "削除", + "title": "{0} by {1}", "uninstall": "アンインストール", "uninstallMsg": "{0}をアンインストールしますか?", - "version": "バージョン{0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "'{0}': {1}にあるスケッチブックにアクセスできませんでした" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "ファイルを追加...", "fileAdded": "スケッチにファイルが1つ追加されました。", @@ -188,6 +202,7 @@ "copyError": "エラーメッセージをコピー", "noBoardSelected": "ボードが選択されていません。ツール > ボードメニューからArduinoボードを選択してください。" }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Daemonを再起動", "start": "Daemonを開始", @@ -216,7 +231,7 @@ "revealError": "エラーを表示" }, "electron": { - "couldNotSave": "スケッチを保存できませんでした。保存されていない作業内容を好きなテキストエディタにコピーして、IDEを再起動してください。", + "couldNotSave": "スケッチを保存できませんでした。保存されていない作業内容を好きなテキストエディターにコピーして、IDEを再起動してください。", "unsavedChanges": "未保存の変更は保存されません。" }, "examples": { @@ -313,6 +328,13 @@ "tools": "ツール" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "websocketを閉じることができません", "unableToConnectToWebSocket": "websocketに接続することができません" }, @@ -353,7 +375,7 @@ "ide.updateBaseUrl": "アップデートをダウンロードするためのベースURL。デフォルトは 'https://downloads.arduino.cc/arduino-ide' です。", "ide.updateChannel": "アップデート元のリリースチャンネル。stableは安定版リリース、nightlyは最新の開発用ビルドです。", "interfaceScale": "インターフェイスのスケール", - "invalid.editorFontSize": "エディタのフォントサイズが無効です。正の整数でなければなりません。", + "invalid.editorFontSize": "エディターのフォントサイズが無効です。正の整数でなければなりません。", "invalid.sketchbook.location": "スケッチブックの場所が無効です: {0}", "invalid.theme": "無効なテーマです。", "language.log": "Arduino Language Serverがスケッチフォルダにログファイルを生成した方がよい場合はtrue。それ以外はfalse。デフォルトではfalse。", @@ -393,6 +415,7 @@ "serial": { "autoscroll": "自動スクロール", "carriageReturn": "CRのみ", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "メッセージ('{1}'の{0}にメッセージを送信するにはEnter)", "newLine": "LFのみ", "newLineCarriageReturn": "CRおよびLF", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "スケッチを別の場所に保存してみますか?", "editInvalidSketchFolderQuestion": "スケッチを別の名前で保存しますか?", "exportBinary": "コンパイル済みバイナリをエクスポート", - "invalidCloudSketchName": "名前は、文字または数字で始まり、文字、数字、ダッシュ、ドット、アンダースコアが続く必要があります。最大文字数は36文字です。", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "スケッチは、それ自身の中のフォルダに保存することはできません。", "invalidSketchFolderLocationMessage": "無効なスケッチフォルダの場所:'{0}'。", "invalidSketchFolderNameMessage": "スケッチフォルダの名前が無効です:'{0}'", - "invalidSketchName": "名前は、文字または数字で始まり、文字、数字、ダッシュ、ドット、アンダースコアが続く必要があります。最大文字数は63文字です。", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "移動", "movingMsg": "ファイル\"{0}\"は、\"{1}\"という名前のスケッチフォルダの中にあることが必要です。\nこのフォルダを作成し、ファイルを移動させ、継続しますか?", "new": "新規スケッチ", @@ -451,6 +474,17 @@ "dismissSurvey": "次回から表示しない", "surveyMessage": "とても簡単なアンケートに答えて、私たちの改善にご協力ください。私たちはコミュニティを大切にしており、サポーターのことをもう少しよく知りたいのです。" }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "インデックスを更新", "updateLibraryIndex": "ライブラリのインデックスを更新", @@ -480,9 +514,10 @@ "core": { "cannotConnectBackend": "バックエンドに接続できません。", "cannotConnectDaemon": "CLI daemonに接続できません。", - "couldNotSave": "スケッチを保存できませんでした。保存されていない作業内容を好きなテキストエディタにコピーして、IDEを再起動してください。", + "couldNotSave": "スケッチを保存できませんでした。保存されていない作業内容を好きなテキストエディターにコピーして、IDEを再起動してください。", "daemonOffline": "CLI Daemonはオフラインです", "offline": "オフライン", + "offlineText": "オフライン", "quitTitle": "本当に終了しますか?" }, "editor": { diff --git a/i18n/ko.json b/i18n/ko.json index 3c7a507cf..7ed1df8ac 100644 --- a/i18n/ko.json +++ b/i18n/ko.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "프로그램 정보 {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "보드{0}", "boardConfigDialogTitle": "보드 및 포트 선택", @@ -83,13 +89,12 @@ "mouseError": "'Mouse'를 찾을 수 없습니다. 스케치에 '#include <Mouse.h>' 줄이 포함되어 있습니까?" }, "cloud": { - "account": "계정", "chooseSketchVisibility": "보여질 스케치를 선택하세요", "cloudSketchbook": "Cloud Sketchbook", "connected": "연결됨", "continue": "계속", - "donePulling": "pulling 완료 ‘{0}’.", - "donePushing": "pushing 완료 ‘{0}’.", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "Embed:", "emptySketchbook": "스케치북이 비어 있습니다.", "goToCloud": "Go to Cloud", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "이 패키지에 포함된 보드:", "by": "by", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "필터 검색...", "install": "설치", - "installed": "설치됨", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "더 많은 정보", + "otherVersions": "Other Versions", + "remove": "제거", + "title": "{0} by {1}", "uninstall": "설치해제", "uninstallMsg": "설치해제를 원하십니까 {0}?", - "version": "버전 {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "파일 추가", "fileAdded": "스케치에 하나의 파일이 추가되었습니다.", @@ -188,6 +202,7 @@ "copyError": "에러 메시지 복사", "noBoardSelected": "보드가 선택되지 않았습니다. Tools > Board menu 에서 당신의 보드를 선택해주세요." }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "데몬 재시작", "start": "데몬 시작", @@ -313,6 +328,13 @@ "tools": "도구" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "웹소켓을 닫을 수 없습니다.", "unableToConnectToWebSocket": "웹소켓에 연결 할 수 없습니다." }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "자동스크롤", "carriageReturn": "캐리지 리턴", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Message (Enter to send message to '{0}' on '{1}')", "newLine": "새 줄", "newLineCarriageReturn": "Both NL & CR", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "컴파일된 바이너리 내보내기", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "Moving", "movingMsg": "The file \"{0}\" needs to be inside a sketch folder named \"{1}\".\nCreate this folder, move the file, and continue?", "new": "New Sketch", @@ -451,6 +474,17 @@ "dismissSurvey": "다시보지 않기", "surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Update Indexes", "updateLibraryIndex": "Update Library Index", @@ -483,6 +517,7 @@ "couldNotSave": "스케치를 저장할 수 없습니다. 저장하지 않은 작업을 즐겨 사용하는 텍스트 편집기에 복사하고 IDE를 다시 시작하세요.", "daemonOffline": "CLI 데몬 오프라인", "offline": "오프라인", + "offlineText": "오프라인", "quitTitle": "정말 종료하시겠습니까?" }, "editor": { diff --git a/i18n/my_MM.json b/i18n/my_MM.json index 13ab1710b..4556ad438 100644 --- a/i18n/my_MM.json +++ b/i18n/my_MM.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "{0} အကြောင်း" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "ဘုတ်{0}", "boardConfigDialogTitle": "အခြားဘုတ်နှင့်အပေါက်ကို ရွေးချယ်ပါ", @@ -83,13 +89,12 @@ "mouseError": "'မောက်စ်' ရှာမတွေ့ပါ။ '#include <Mouse.h>' ကုတ်စာကြောင်းကို သင့်ကုတ်ပုံကြမ်းထဲတွင် ထည့်ရေးထားပါသလား?" }, "cloud": { - "account": "အကောင့်", "chooseSketchVisibility": "သင့်ကုတ်ပုံကြမ်း၏ မြင်နိုင်စွမ်းအား ရွေးချယ်ခြင်း - ", "cloudSketchbook": "တိမ်တိုက် Sketchbook ဖိုင်တွဲ", "connected": "ချိတ်ဆက်ထားသည်", "continue": "ဆက်သွားမည်", - "donePulling": "‘{0}’ကိုဆွဲယူပြီးပါပြီ။", - "donePushing": "‘{0}’တွန်းပို့ပြီးပါပြီ။", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "မြှုပ်သွင်းထားသော -", "emptySketchbook": "သင့်ကုတ်ပုံကြမ်းဖိုင်တွဲထဲတွင် ဘာမှမရှိပါ", "goToCloud": "ကလောက်သို့သွားမည်", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "ဤပတ်ကေ့တွင်ပါဝင်သောဘုတ်များ-", "by": "မှ", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "သင်၏ရှာဖွေမှုရလဒ်ကိုစစ်ထုတ်မည်…", "install": "တပ်ဆင်မည်", - "installed": "တပ်ဆင်ထားပြီး", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "နောက်ထပ်အချက်အလက်များ", + "otherVersions": "Other Versions", + "remove": "ဖယ်ရှားမည်", + "title": "{0} by {1}", "uninstall": "ဖြုတ်ချ", "uninstallMsg": "သင် {0} ကိုဖြုတ်ချချင်ပါသလား?", - "version": "ဗားရှင်း {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "ဖိုင်လ်ထည့်မည်", "fileAdded": "ကုတ်ပုံကြမ်းထဲသို့ ဖိုင်တစ်ခု ထည့်လိုက်သည်။", @@ -188,6 +202,7 @@ "copyError": "အမှားပြစာများကို ကော်ပီဆွဲသည်", "noBoardSelected": "မည်သည့်ဘုတ်မှ မရွေးထားပါ။ သင်၏အာဒီနိုဘုတ်ကို ကိရိယာများ>ဘုတ် မီနူးတွင် ရွေးချယ်ပါ။" }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Daemon ပြန်စမည်", "start": "Daemon စတင်မည်", @@ -313,6 +328,13 @@ "tools": "ကိရိယာများ" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "ဝက်ဘ်ဆော့ကတ်ကိုမပိတ်နိုင်ပါ", "unableToConnectToWebSocket": "ဝက်ဘ်ဆော့ကတ်သို့မချိတ်ဆက်နိုင်ပါ" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "အလိုအလျောက်လှိမ့်ဆွဲခြင်း", "carriageReturn": "လက်နှိပ်စက်အတံပြန်အက္ခရာ", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "စာတို (စာတိုကို '{0}'သို့ '{1}'တွင် ပို့ရန် ရိုက်နှိပ်ပါ)", "newLine": "စာကြောင်းအသစ်အက္ခရာ", "newLineCarriageReturn": "စာကြောင်းအသစ်နှင့်လက်နှိပ်စက်အတံပြန်အက္ခရာနှစ်ခုလုံး", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "ကုတ်ပေါင်းထားသောဘိုင်နရီဖိုင် ထုတ်ပို့မည်", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "ရွှေ့နေသည်", "movingMsg": "ဖိုင်လ် \"{0}\" သည် ကုတ်ဖိုင်လ်ဖိုလ်ဒါ \"{1}\"အတွင်းရှိရန်လိုသည်။\nဖိုလ်ဒါတည်ဆောက်ပြီးဖိုင်လ်ကိုရွှေ့မည်လား။", "new": "New Sketch", @@ -451,6 +474,17 @@ "dismissSurvey": "နောက်ထပ်မပြပါနှင့်", "surveyMessage": "ဤစစ်တမ်းကိုဖြေဆိုခြင်းအားဖြင့် ကျွန်ုပ်တို့အား ကူညီလိုက်ပါ။" }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "အပ်ဒိတ်စာရင်းများ", "updateLibraryIndex": "ကုတ်ကြည့်တိုက်အပ်ဒိတ်စာရင်း", @@ -483,6 +517,7 @@ "couldNotSave": "ကုတ်ဖိုင်လ်ကိုမသိမ်းဆည်းနိုင်ခဲ့ပါ။ မသိမ်းဆည်းရသေးသော ကုတ်များကို သင်နှစ်သက်ရာစာသားတည်းဖြတ်ပရိုဂရမ်သို့ ကူးယူပြီး အိုင်ဒီအီး ပြန်စတင်ပါ။", "daemonOffline": "CLIနောက်ကွယ်လုပ်ဆောင်ပရိုဂရမ် အော့ဖ်လိုင်းဖြစ်နေသည်", "offline": "အော့ဖ်လိုင်း", + "offlineText": "အော့ဖ်လိုင်း", "quitTitle": "သင်ထွက်မှာသေချာပါသလား။" }, "editor": { diff --git a/i18n/ne.json b/i18n/ne.json index f45c811aa..3788879f2 100644 --- a/i18n/ne.json +++ b/i18n/ne.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "About {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "Board{0}", "boardConfigDialogTitle": "Select Other Board and Port", @@ -83,13 +89,12 @@ "mouseError": "'Mouse' not found. Does your sketch include the line '#include <Mouse.h>'?" }, "cloud": { - "account": "Account", "chooseSketchVisibility": "Choose visibility of your Sketch:", "cloudSketchbook": "Cloud Sketchbook", "connected": "Connected", "continue": "Continue", - "donePulling": "Done pulling ‘{0}’.", - "donePushing": "Done pushing ‘{0}’.", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "Embed:", "emptySketchbook": "Your Sketchbook is empty", "goToCloud": "Go to Cloud", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "Boards included in this package:", "by": "by", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "Filter your search...", "install": "Install", - "installed": "Installed", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "More info", + "otherVersions": "Other Versions", + "remove": "Remove", + "title": "{0} by {1}", "uninstall": "Uninstall", "uninstallMsg": "Do you want to uninstall {0}?", - "version": "Version {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "Add File", "fileAdded": "One file added to the sketch.", @@ -188,6 +202,7 @@ "copyError": "Copy error messages", "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Restart Daemon", "start": "Start Daemon", @@ -313,6 +328,13 @@ "tools": "Tools" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Unable to close websocket", "unableToConnectToWebSocket": "Unable to connect to websocket" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "Autoscroll", "carriageReturn": "Carriage Return", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Message (Enter to send message to '{0}' on '{1}')", "newLine": "New Line", "newLineCarriageReturn": "Both NL & CR", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "Export Compiled Binary", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "Moving", "movingMsg": "The file \"{0}\" needs to be inside a sketch folder named \"{1}\".\nCreate this folder, move the file, and continue?", "new": "New Sketch", @@ -451,6 +474,17 @@ "dismissSurvey": "Don't show again", "surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Update Indexes", "updateLibraryIndex": "Update Library Index", @@ -483,6 +517,7 @@ "couldNotSave": "Could not save the sketch. Please copy your unsaved work into your favorite text editor, and restart the IDE.", "daemonOffline": "CLI Daemon Offline", "offline": "Offline", + "offlineText": "Offline", "quitTitle": "Are you sure you want to quit?" }, "editor": { diff --git a/i18n/nl.json b/i18n/nl.json index 95f6f82c3..a369e991a 100644 --- a/i18n/nl.json +++ b/i18n/nl.json @@ -1,14 +1,20 @@ { "arduino": { "about": { - "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", + "detail": "Versie: {0}\nDatum: {1}{2}\nCLI Versie: {3}\n\n{4}\n ", "label": "Over {0}" }, + "account": { + "goToCloudEditor": "Ga naar de Cloud Editor", + "goToIoTCloud": "Ga naar de IoT Cloud", + "goToProfile": "Ga naar profiel", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "Bord{0}", "boardConfigDialogTitle": "Selecteer Ander Bord en Poort", "boardInfo": "Bord Informatie", - "boards": "boards", + "boards": "borden", "configDialog1": "Selecteer een Bord en een Poort als U een schets wilt uploaden.", "configDialog2": "Als je alleen een Board kiest, kun je wel compileren, maar niet je schets uploaden.", "couldNotFindPreviouslySelected": "Kon het voordien geselecteerde bord '{0}' in het geïnstalleerde platform '{1}' niet vinden. Gelieve manueel het bord te kiezen dat U wilt gebruiken. Wilt U het bord nu selecteren?", @@ -16,29 +22,29 @@ "getBoardInfo": "Verkrijg Bord Informatie", "inSketchbook": "(in Schetsboek)", "installNow": "De \"{0} {1}\" kern moet geïnstalleerd zijn om het huidige geselecteerde \"{2}\" bord. Wilt U dit nu installeren?", - "noBoardsFound": "No boards found for \"{0}\"", + "noBoardsFound": "Geen borden gevonden voor \"{0}\"", "noFQBN": "De FQBN is niet beschikbaar voor het geselecteerde bord \"{0}\". Heeft U de bijhorende kern geïnstalleerd?", - "noNativeSerialPort": "Native serial port, can't obtain info.", + "noNativeSerialPort": "Oorpronkelijke seriële poort, ik kan geen info verkrijgen", "noPortsDiscovered": "Geen poorten gevonden", "noPortsSelected": "Geen poorten geselecteerd voor bord: '{0}'.", - "nonSerialPort": "Non-serial port, can't obtain info.", + "nonSerialPort": "Dit is geen seriële poort, ik kan geen info verkrijgen", "noneSelected": "Geen borden geselecteerd.", "openBoardsConfig": "Selecteer een ander bord en poort...", "pleasePickBoard": "Gelieve een bord te selecteren dat verbonden is met de door U gekozen poort.", "port": "Poort{0}", "portLabel": "Poort: {0}", - "ports": "ports", + "ports": "poorten", "programmer": "Programmeerapparaat", "reselectLater": "Later opnieuw selecteren", "searchBoard": "Bord zoeken", "selectBoard": "Selecteer Bord", "selectPortForInfo": "Selecteer een poort om bord informatie te bekomen.", "showAllAvailablePorts": "Toont alle beschikbare poorten indien ingeschakeld", - "showAllPorts": "Show all ports", + "showAllPorts": "Toon alle poorten", "succesfullyInstalledPlatform": "Platform {0}:{1} succesvol geïnstalleerd", "succesfullyUninstalledPlatform": "Platform {0}:{1} is succesvol verwijderd", - "typeOfPorts": "{0} ports", - "unknownBoard": "Unknown board" + "typeOfPorts": "\"{0}\" poorten", + "unknownBoard": "Onbekend bord" }, "boardsManager": "Borden Beheerder", "boardsType": { @@ -46,7 +52,7 @@ }, "bootloader": { "burnBootloader": "Bootloader branden", - "burningBootloader": "Bootloader branden...", + "burningBootloader": "Bootloader aan het branden", "doneBurningBootloader": "Klaar met het branden van de bootloader." }, "burnBootloader": { @@ -83,16 +89,15 @@ "mouseError": "'Mouse' niet gevonden. Bevat je schets de regel '#include <Mouse.h>'?" }, "cloud": { - "account": "Account", "chooseSketchVisibility": "Kies de zichtbaarheid van je Sketch:", "cloudSketchbook": "Cload Schetsboek", "connected": "Verbonden", "continue": "Doorgaan", - "donePulling": "Klaar met trekken van '{0}'.", - "donePushing": "Klaar met pushen van '{0}'.", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "Integreren:", "emptySketchbook": "Je schetsboek is leeg", - "goToCloud": "Go to Cloud", + "goToCloud": "Ga naar de Cloud", "learnMore": "Leer meer", "link": "Koppeling:", "notYetPulled": "Kan niet pushen naar Cloud. Het is nog niet getrokken.", @@ -112,7 +117,7 @@ "remote": "Op Afstand", "share": "Delen...", "shareSketch": "Schets Delen", - "showHideSketchbook": "Show/Hide Cloud Sketchbook", + "showHideSketchbook": "Toon / Verberg het Cloud Schetsboek", "signIn": "INLOGGEN", "signInToCloud": "Aanmelden bij Arduino Cloud", "signOut": "Uitloggen", @@ -121,14 +126,14 @@ "visitArduinoCloud": "Bezoek Arduino Cloud om Cloud Sketches te maken." }, "cloudSketch": { - "alreadyExists": "Cloud sketch '{0}' already exists.", - "creating": "Creating cloud sketch '{0}'...", - "new": "New Cloud Sketch", - "notFound": "Could not pull the cloud sketch '{0}'. It does not exist.", - "pulling": "Synchronizing sketchbook, pulling '{0}'...", - "pushing": "Synchronizing sketchbook, pushing '{0}'...", - "renaming": "Renaming cloud sketch from '{0}' to '{1}'...", - "synchronizingSketchbook": "Synchronizing sketchbook..." + "alreadyExists": "Cloud sketch '{0}' bestaat al", + "creating": "cloud sketch '{0}'  maken...", + "new": "Nieuwe Cloud Sketch", + "notFound": "Kan de cloud sketch '{0}'niet vinden, het bestaat niet.", + "pulling": "Schetsboek synchroniseren, ik haal '{0}'. op .....", + "pushing": "Schetsboek synchroniseren, ik sla '{0}' op.......", + "renaming": "Cloud schets hernoemen van '{0}' naar '{1}' ...", + "synchronizingSketchbook": "Schetsboek synchroniseren..." }, "common": { "all": "Alle", @@ -155,39 +160,49 @@ "component": { "boardsIncluded": "Borden in dit pakket:", "by": "door", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "Filter je zoekopdracht...", "install": "Installeren", - "installed": "Geïnstalleerd", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "Meer informatie", + "otherVersions": "Other Versions", + "remove": "Verwijder", + "title": "{0} by {1}", "uninstall": "Verwijderen", "uninstallMsg": "Wil je {0} verwijderen?", - "version": "Versie {0}" + "update": "Update" }, "configuration": { "cli": { - "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" + "inaccessibleDirectory": "Geen toegang tot schetsboek locatie in '{0}': {1} " } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "Bestand Toevoegen", "fileAdded": "Één bestand toegevoegd aan de schets.", "plotter": { - "couldNotOpen": "Couldn't open serial plotter" + "couldNotOpen": "Kon de seriële plotter niet openen" }, "replaceTitle": "Vervangen" }, "core": { "compilerWarnings": { "all": "Alle", - "default": "Default", - "more": "More", - "none": "None" + "default": "Standaard", + "more": "Meer", + "none": "Geen" } }, "coreContribution": { "copyError": "Foutmeldingen kopiëren", "noBoardSelected": "Geen bord geselecteerd. Selecteer je Arduino-bord in het menu Extra > Board." }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Daemon opnieuw starten", "start": "Daemon starten", @@ -198,7 +213,7 @@ "debuggingNotSupported": "Foutopsporing wordt niet ondersteund door '{0}'", "noPlatformInstalledFor": "Platform is niet geïnstalleerd voor '{0}'", "optimizeForDebugging": "Optimaliseren voor foutopsporing", - "sketchIsNotCompiled": "Sketch '{0}' must be verified before starting a debug session. Please verify the sketch and start debugging again. Do you want to verify the sketch now?" + "sketchIsNotCompiled": "Schets '{0}' moet geverifieerd worden voordag de foutopsporing kan beginnen. Verifieer aub de schets opnieuw en start foutopsporing opnieuw. Wil je de schets opnieuw verifiëren?" }, "dialog": { "dontAskAgain": "Niet meer vragen" @@ -273,10 +288,10 @@ "contributedLibraries": "Bijgedragen bibliotheken", "include": "Bibliotheek Gebruiken", "installAll": "Alles installeren", - "installLibraryDependencies": "Install library dependencies", + "installLibraryDependencies": "Installeer de bibliotheek afhankelijkheden", "installMissingDependencies": "Wilt u de ontbrekende afhankelijkheid installeren?", "installOneMissingDependency": "Wilt u de ontbrekende afhankelijkheid installeren?", - "installWithoutDependencies": "Install without dependencies", + "installWithoutDependencies": "Installeer zonder afhankelijkheden", "installedSuccessfully": "Bibliotheek {0}:{1} succesvol geïnstalleerd", "libraryAlreadyExists": "Er bestaat al een bibliotheek. Wil U het overschrijven? ", "manageLibraries": "Bibliotheken Beheren...", @@ -313,15 +328,22 @@ "tools": "Hulpmiddelen" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Kan websocket niet sluiten", "unableToConnectToWebSocket": "Kan geen verbinding maken met websocket" }, "newCloudSketch": { - "newSketchTitle": "Name of the new Cloud Sketch" + "newSketchTitle": "Naam van de nieuwe Cloud schets" }, "portProtocol": { "network": "Netwerk", - "serial": "Serial" + "serial": "Seriëel" }, "preferences": { "additionalManagerURLs": "Bijkomende Borden Beheerder URL's", @@ -361,17 +383,17 @@ "manualProxy": "Manuele proxy configuratie", "network": "Netwerk", "newSketchbookLocation": "Selecteer een nieuwe schetsboeklocatie.", - "noCliConfig": "Could not load the CLI configuration", + "noCliConfig": "De Cloud kon de CLI configuratie niet laden", "noProxy": "Geen proxy", "proxySettings": { - "hostname": "Host name", - "password": "Password", - "port": "Port number", - "username": "Username" + "hostname": "Naam van de host", + "password": "Wachtwoord", + "port": "Poortnummer", + "username": "Gebruikersnaam" }, "showVerbose": "Uitgebreide uitvoer weergeven tijdens", "sketch": { - "inoBlueprint": "Absolute filesystem path to the default `.ino` blueprint file. If specified, the content of the blueprint file will be used for every new sketch created by the IDE. The sketches will be generated with the default Arduino content if not specified. Unaccessible blueprint files are ignored. **A restart of the IDE is needed** for this setting to take effect." + "inoBlueprint": "Absoluut pad naar het standaard `.ino` systeem blauwdrukbestand. Indien gespecificeerd,, zal de inhoud van het systeem blauwdrukbestand gebruikt worden voor elke nieuwe schets gemaakt met behulp van de IDE. De schetsen zullen gegenereerd worden met de standaard Arduino inhoud indien niet gespecificeerd. Ontoegangelijke blauwdrukbestanden worden genegeerd. **Een herstart van de IDE is nodig** om deze instelling te activeren." }, "sketchbook.location": "Schetsboek locatie", "sketchbook.showAllFiles": "Waar om al de schets bestanden in de schets weer te geven. Standaard ingesteld op onwaar.", @@ -382,18 +404,19 @@ "verifyAfterUpload": "Verifieer de code na het uploaden", "window.autoScale": "Waar als de gebruikersinterface automatisch wordt geschaald met de lettergrootte.", "window.zoomLevel": { - "deprecationMessage": "Deprecated. Use 'window.zoomLevel' instead." + "deprecationMessage": "Niet langer valide. Gebruik 'window.zoomLevel' in plaats daarvan." } }, "renameCloudSketch": { - "renameSketchTitle": "New name of the Cloud Sketch" + "renameSketchTitle": "Nieuwe naam van de Cloud schets" }, "replaceMsg": "De bestaande versie van {0} vervangen?", "selectZip": "Selecteer een zipbestand met de bibliotheek die U wilt toevoegen", "serial": { "autoscroll": "Automatisch scrollen", "carriageReturn": "Carriage Return", - "message": "Message (Enter to send message to '{0}' on '{1}')", + "connecting": "Connecting to '{0}' on '{1}'...", + "message": "Bericht (Enter om het bericht naar '{0}' op '{1}' te zenden)", "newLine": "Nieuwe Regel", "newLineCarriageReturn": "Zowel NL & CR", "noLineEndings": "Geen RegelEinde", @@ -407,26 +430,26 @@ "cantOpen": "Er bestaat al een map met de naam \"{0}\". Kan schets niet openen.", "close": "Weet je zeker dat je de schets wilt sluiten?", "compile": "Sketch compileren...", - "configureAndUpload": "Configure and Upload", + "configureAndUpload": "Configureer en upload", "createdArchive": "Archief '{0}' gemaakt.", "doneCompiling": "Klaar met compileren.", "doneUploading": "Klaar met uploaden.", - "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", - "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", + "editInvalidSketchFolderLocationQuestion": "Wil je proberen om de schets op een andere locatie op te slaan?", + "editInvalidSketchFolderQuestion": "Wil je proberen om de schets onder een andere naam op te slaan?", "exportBinary": "Gecompileerd binair bestand exporteren", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", - "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", - "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", - "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidSketchFolderLocationDetails": "Je kunt de schets niet opslaan in een map in de eigen map", + "invalidSketchFolderLocationMessage": "Foute locatie van de schets map: '{0}'", + "invalidSketchFolderNameMessage": "Ongeldige schets mapnaam: '{0}'", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "Verplaatsten", "movingMsg": "Het bestand \"{0}\" moet binnen een schetsmap met de naam \"{1}\" staan.\nMaak deze map, verplaats het bestand, en ga verder?", - "new": "New Sketch", - "noTrailingPeriod": "A filename cannot end with a dot", + "new": "Nieuwe schets", + "noTrailingPeriod": "Een bestandsnaam kan niet met een punt eindigen", "openFolder": "Map Openen", "openRecent": "Recentelijk geopend", "openSketchInNewWindow": "Schets openen in nieuw venster", - "reservedFilename": "'{0}' is a reserved filename.", + "reservedFilename": "'{0}' is een gereserveerde bestandsnaam.", "saveFolderAs": "Sla de schets map op als...", "saveSketch": "Bewaar je schets om hem later weer te openen.", "saveSketchAs": "Sla de schetsmap op als...", @@ -443,18 +466,29 @@ "verifyOrCompile": "Verifiëren/Compileren" }, "sketchbook": { - "newCloudSketch": "New Cloud Sketch", - "newSketch": "New Sketch" + "newCloudSketch": "Nieuwe Cloud Sketch", + "newSketch": "Nieuwe schets" }, "survey": { "answerSurvey": "Antwoord enquête", "dismissSurvey": "Niet meer laten zien", "surveyMessage": "Help ons alsjeblieft te verbeteren door deze super korte enquête te beantwoorden. We waarderen onze gemeenschap en willen onze supporters graag wat beter leren kennen." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { - "updateIndexes": "Update Indexes", - "updateLibraryIndex": "Update Library Index", - "updatePackageIndex": "Update Package Index" + "updateIndexes": "Update de indices", + "updateLibraryIndex": "Update de bibliotheek index", + "updatePackageIndex": "Update de index van het pakket" }, "upload": { "error": "{0} fout: {1}" @@ -465,15 +499,15 @@ "upload": "Uploaden" }, "validateSketch": { - "abortFixMessage": "The sketch is still invalid. Do you want to fix the remaining problems? By clicking '{0}', a new sketch will open.", - "abortFixTitle": "Invalid sketch", - "renameSketchFileMessage": "The sketch file '{0}' cannot be used. {1} Do you want to rename the sketch file now?", - "renameSketchFileTitle": "Invalid sketch filename", - "renameSketchFolderMessage": "The sketch '{0}' cannot be used. {1} To get rid of this message, rename the sketch. Do you want to rename the sketch now?", - "renameSketchFolderTitle": "Invalid sketch name" + "abortFixMessage": "De schets is nog steeds niet correct. Wil je de problemen oplossen? Door op '{0}' te klikken, zal een nieuwe schets worden geopend.", + "abortFixTitle": "Incorrecte schets", + "renameSketchFileMessage": "De schetsnaam '{0}' kan niet gebruikt worden. {1} Wil je de schets nu hernoemen?", + "renameSketchFileTitle": "Ongeldige bestandsnaam van de schets", + "renameSketchFolderMessage": "De schets '{0}' kan niet gebruikt worden. {1} Om van deze melding af te komen, hernoem de schets. Wil je de schets nu hernoemen?", + "renameSketchFolderTitle": "Ongeldige schetsnaam" }, "workspace": { - "alreadyExists": "'{0}' already exists." + "alreadyExists": "'{0}' bestaat al." } }, "theia": { @@ -483,6 +517,7 @@ "couldNotSave": "Kan de schets niet opslaan. Kopieer uw niet-opgeslagen werk naar uw favoriete teksteditor en start de IDE opnieuw. ", "daemonOffline": "CLI Daemon Offline", "offline": "Offline", + "offlineText": "Offline", "quitTitle": "Weet je zeker dat je wilt stoppen?" }, "editor": { @@ -493,8 +528,8 @@ "expand": "Uitvouwen" }, "workspace": { - "deleteCloudSketch": "The cloud sketch '{0}' will be permanently deleted from the Arduino servers and the local caches. This action is irreversible. Do you want to delete the current sketch?", - "deleteCurrentSketch": "The sketch '{0}' will be permanently deleted. This action is irreversible. Do you want to delete the current sketch?", + "deleteCloudSketch": "De Cloud schets '{0}' zal permanent verwijderd worden van de Arduino servers en van de locale caches. Deze actie is onomkeerbaar. Wil je de huidige schets verwijderen?", + "deleteCurrentSketch": "De schets '{0}' zal permanent verwijderd worden. Deze actie is onomkeerbaar. Wil je de huidige schets verwijderen?", "fileNewName": "Naam voor nieuw bestand", "invalidExtension": ".{0} is geen geldige extensie", "newFileName": "Nieuwe naam voor bestand" diff --git a/i18n/pl.json b/i18n/pl.json index a57e4d7e5..b8eba6602 100644 --- a/i18n/pl.json +++ b/i18n/pl.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "O {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "Płytka{0}", "boardConfigDialogTitle": "Wybierz inną płytkę i port", @@ -83,13 +89,12 @@ "mouseError": "Nie znaleziono myszy. Czy szkic posiada linię kodu: '#include <Mouse.h>'?" }, "cloud": { - "account": "Konto", "chooseSketchVisibility": "Wybierz widoczność swojego Szkicu:", "cloudSketchbook": "Cloud Sketchbook", "connected": "Połączony", "continue": "Kontynuuj", - "donePulling": "Zakończono zaciąganie ‘{0}’.", - "donePushing": "Gotowe pchanie ‘{0}’.", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "Osadzić:", "emptySketchbook": "Twój Szkicownik jest pusty", "goToCloud": "Go to Cloud", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "Płytka dołączona w pakiecie:", "by": "przez", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "Filtruj przeszukiwanie....", "install": "Zainstaluj", - "installed": "Zainstalowane", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "Więcej informacji", + "otherVersions": "Other Versions", + "remove": "Usuń", + "title": "{0} by {1}", "uninstall": "Odinstaluj", "uninstallMsg": "Czy chcesz odinstalować {0}?", - "version": "Wersja {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "Dodaj plik", "fileAdded": "Jeden plik dodany do szkicu.", @@ -188,6 +202,7 @@ "copyError": "Kopiuj komunikat błędu", "noBoardSelected": "Nie wybrano płytki. Proszę wybierz płytkę z Narzędzia > Lista płytek" }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Restartuj Daemon", "start": "Start Daemon", @@ -313,6 +328,13 @@ "tools": "Narzędzia" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Nie można zamknąć gniazda sieciowego", "unableToConnectToWebSocket": "Nie można połączyć się z gniazdem sieciowym" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "Autoscroll", "carriageReturn": "Powrót karetki", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Message(Kliknij aby wysłać wiadomość do '{0}' od '{1}')", "newLine": "Nowa linia", "newLineCarriageReturn": "Nowa linia i powrót karetki", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "Eksportuj skompilowane binarnie", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "Przenoszenie", "movingMsg": "Plik \"{0}\" musi znajdować się w folderze szkiców o nazwie \"{1}\".\nCzy utworzyć ten folder, przenieść podany plik i kontynuować?", "new": "New Sketch", @@ -451,6 +474,17 @@ "dismissSurvey": "Pomóż nam się rozwijać wypełniając tą super krótką ankietę. Cenimy naszą społeczność i chcielibyśmy lepiej poznać tych którzy nas wspierają.", "surveyMessage": "Pomóż nam się rozwijać wypełniając tą super krótką ankietę. Cenimy naszą społeczność i chcielibyśmy lepiej poznać tych którzy nas wspierają." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Aktualizuj indeksy", "updateLibraryIndex": "Aktualizuj indeksy bibliotek", @@ -483,6 +517,7 @@ "couldNotSave": "Nie można zapisać szkicu. Skopiuj niezapisany szkic do edytora tekstu i zrestartuj IDE.", "daemonOffline": "CLI Daemon Offline", "offline": "Offline", + "offlineText": "Offline", "quitTitle": "Jesteś pewien, że chcesz wyjść?" }, "editor": { diff --git a/i18n/pt.json b/i18n/pt.json index 8734ca9a3..a175c9adc 100644 --- a/i18n/pt.json +++ b/i18n/pt.json @@ -1,52 +1,58 @@ { "arduino": { "about": { - "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", + "detail": "Versão: {0}\nData: {1}{2}\nVersão do CLI : {3}{4} [{5}]\n\n{6}", "label": "Sobre {0}" }, + "account": { + "goToCloudEditor": "Ir para Editor em Nuvem", + "goToIoTCloud": "Ir para Nuvem IoT", + "goToProfile": "Ir para Perfil", + "menuTitle": "Nuvem Arduino" + }, "board": { "board": "Placa{0}", - "boardConfigDialogTitle": "Select Other Board and Port", + "boardConfigDialogTitle": "Selecionar Outra Placa e Porta", "boardInfo": "Informações da Placa", - "boards": "boards", + "boards": "placas", "configDialog1": "Selecione uma placa e uma porta se quiser fazer o upload de um sketch.", - "configDialog2": "Se você selecionar apenas uma Placa, você será capaz de compilar, mas não de carregar o seu sketch.", + "configDialog2": "Se você selecionar apenas uma Placa, você será capaz de compilar, mas não de enviar o seu esboço.", "couldNotFindPreviouslySelected": "Não foi possível encontrar a placa selecionada anteriormente '{0}' na plataforma instalada '{1}'. Por favor, selecione manualmente a placa que deseja usar. Você deseja selecioná-la novamente agora?", "disconnected": "Desconectado", "getBoardInfo": "Obter Informações da Placa", "inSketchbook": "(no Sketchbook)", "installNow": "O núcleo \"{0} {1}\" deve ser instalado para a placa \"{2}\" atualmente selecionada. Quer instalar agora?", - "noBoardsFound": "No boards found for \"{0}\"", + "noBoardsFound": "Nenhuma placa encontrada para \"{0}\"", "noFQBN": "O FQBN não está disponível para a placa selecionada \"{0}\". Você tem o núcleo correspondente instalado?", - "noNativeSerialPort": "Native serial port, can't obtain info.", + "noNativeSerialPort": "Porta serial nativa, não é possível obter informações.", "noPortsDiscovered": "Nenhuma porta detectada", "noPortsSelected": "Nenhuma porta selecionada para placa: '{0}'.", - "nonSerialPort": "Non-serial port, can't obtain info.", + "nonSerialPort": "Porta não-serial, não é possível obter informações.", "noneSelected": "Nenhuma placa selecionada.", "openBoardsConfig": "Selecione outra placa e porta...", "pleasePickBoard": "Escolha uma placa conectada à porta que você selecionou.", "port": "Porta{0}", "portLabel": "Porta{0}", - "ports": "ports", + "ports": "portas", "programmer": "Programador/Gravador", "reselectLater": "Selecionar novamente mais tarde", "searchBoard": "Procurar placa", "selectBoard": "Selecionar Placa", "selectPortForInfo": "Selecione uma porta para obter informações sobre a placa.", "showAllAvailablePorts": "Mostrar todas as portas disponíveis quando habilitado", - "showAllPorts": "Show all ports", + "showAllPorts": "Mostrar todas as portas", "succesfullyInstalledPlatform": "Plataforma instalada com sucesso {0}: {1}", "succesfullyUninstalledPlatform": "Plataforma desinstalada com sucesso {0}: {1}", - "typeOfPorts": "{0} ports", - "unknownBoard": "Unknown board" + "typeOfPorts": "{0} portas", + "unknownBoard": "Placa desconhecida" }, "boardsManager": "Gerenciador de Placas", "boardsType": { - "arduinoCertified": "Arduino Certified" + "arduinoCertified": "Certificado pelo Arduino" }, "bootloader": { "burnBootloader": "Gravar bootloader", - "burningBootloader": "Burning bootloader...", + "burningBootloader": "Gravando carregador de inicialização...", "doneBurningBootloader": "Feita a gravação do bootloader." }, "burnBootloader": { @@ -70,49 +76,48 @@ "uploadingCertificates": "Enviando certificados." }, "checkForUpdates": { - "checkForUpdates": "Check for Arduino Updates", + "checkForUpdates": "Verificar se há Atualizações do Arduino", "installAll": "Instalar todas", "noUpdates": "Não há atualizações recentes disponíveis.", - "promptUpdateBoards": "Updates are available for some of your boards.", - "promptUpdateLibraries": "Updates are available for some of your libraries.", + "promptUpdateBoards": "Atualizações estão disponíveis para algumas de suas placas.", + "promptUpdateLibraries": "Atualizações estão disponíveis para algumas de suas bibliotecas.", "updatingBoards": "Atualizando placas...", "updatingLibraries": "Atualizando bibliotecas..." }, "cli-error-parser": { - "keyboardError": "'Keyboard' não encontrado. O seu sketch inclue a linha '#include <Keyboard.h>'?", - "mouseError": "\"Mouse\" não encontrado. O seu sketch inclue a linha '#include <Mouse.h>' ?" + "keyboardError": "'Keyboard' não encontrado. O seu esboço inclui a linha '#include <Keyboard.h>'?", + "mouseError": "\"Mouse\" não encontrado. O seu esboço inclui a linha '#include <Mouse.h>' ?" }, "cloud": { - "account": "Conta", - "chooseSketchVisibility": "Escolha a visibilidade do seu Sketch:", - "cloudSketchbook": "Sketchbook na nuvem", + "chooseSketchVisibility": "Escolha a visibilidade do seu Esboço:", + "cloudSketchbook": "Caderno de Esboços na Nuvem", "connected": "Conectado", "continue": "Continuar", - "donePulling": "Terminou de baixar '{0}'.", - "donePushing": "Concluído o envio de ‘{0}’.", + "donePulling": "'{0}' terminou de baixar.", + "donePushing": "'{0}' foi enviado.", "embed": "Embutir:", - "emptySketchbook": "O seu Sketchbook está vazio", - "goToCloud": "Go to Cloud", + "emptySketchbook": "O seu Caderno de Esboços está vazio", + "goToCloud": "Ir para Nuvem", "learnMore": "Saiba mais", "link": "Endereço", "notYetPulled": "Não é possível enviar para a nuvem. Ainda não foi baixado.", "offline": "Desconectado", "openInCloudEditor": "Abrir no Cloud Editor", "options": "Opções...", - "privateVisibility": "Privado. Só você poderá ver o Sketch.", + "privateVisibility": "Particular. Apenas você poderá ver o Esboço.", "profilePicture": "Foto do perfil", - "publicVisibility": "Público. Qualquer pessoa com o link poderá visualizar o Sketch.", + "publicVisibility": "Público. Qualquer pessoa com o link poderá ver o Esboço.", "pull": "Baixar", "pullFirst": "Você precisa baixar primeiro para poder enviar para a nuvem.", - "pullSketch": "Baixar Sketch", - "pullSketchMsg": "Baixar este Sketch da nuvem irá sobrescrever sua versão local. Você tem certeza que deseja continuar?", + "pullSketch": "Baixar Esboço", + "pullSketchMsg": "Baixar esse Esboço da Nuvem irá sobrescrever a sua versão local. Você tem certeza que deseja continuar?", "push": "Enviar", - "pushSketch": "Enviar Sketch", - "pushSketchMsg": "Este é um Sketch Público. Antes de enviar, verifique qualquer informação sensível que esteja denifinda nos arquivos arduino_secrets.h. Você pode tornar um Sketch privado a partir do painel Compartilhar.", + "pushSketch": "Enviar Esboço", + "pushSketchMsg": "Esse é um Esboço Público. Antes de enviá-lo, tenha certeza que qualquer informação sensível esteja definida nos arquivos arduino_secrets.h. Você pode tornar um Esboço particular no painel Compartilhar.", "remote": "Remoto", "share": "Compartilhar...", - "shareSketch": "Compartilhar Sketch", - "showHideSketchbook": "Show/Hide Cloud Sketchbook", + "shareSketch": "Compartilhar Esboço", + "showHideSketchbook": "Mostrar/Esconder Caderno de esboços na Nuvem", "signIn": "ENTRAR", "signInToCloud": "Faça login no Arduino Cloud", "signOut": "Sair", @@ -121,17 +126,17 @@ "visitArduinoCloud": "Visite Arduino Cloud para criar Cloud Sketches." }, "cloudSketch": { - "alreadyExists": "Cloud sketch '{0}' already exists.", - "creating": "Creating cloud sketch '{0}'...", - "new": "New Cloud Sketch", - "notFound": "Could not pull the cloud sketch '{0}'. It does not exist.", - "pulling": "Synchronizing sketchbook, pulling '{0}'...", - "pushing": "Synchronizing sketchbook, pushing '{0}'...", - "renaming": "Renaming cloud sketch from '{0}' to '{1}'...", - "synchronizingSketchbook": "Synchronizing sketchbook..." + "alreadyExists": "Esboço na nuvem '{0}' já existe.", + "creating": "Criando esboço na nuvem '{0}'...", + "new": "Novo Esboço na Nuvem", + "notFound": "Não foi possível baixar o esboço na nuvem '{0}'. Esboço inexistente.", + "pulling": "Sincronizando cadernos de esboços, baixando '{0}'...", + "pushing": "Sincronizando cadernos de esboço, enviando '{0}'.", + "renaming": "Renomeando esboço na nuvem de '{0}' para '{1}'...", + "synchronizingSketchbook": "Sincronizando cadernos de esboço..." }, "common": { - "all": "All", + "all": "Todos", "contributed": "Contribuído", "installManually": "Instalar Manualmente", "later": "Depois", @@ -139,15 +144,15 @@ "notConnected": "[não está conectado]", "offlineIndicator": "Parece que você está offline. Sem conexão com a Internet, o Arduino CLI não será capaz de baixar os recursos exigidos e poderá provovar mau funcionamento. Por favor, conecte-se à Internet e reinicie o aplicativo.", "oldFormat": "O '{0}' ainda utiliza o formato antigo `.pde`. Deseja mudar para a nova extensão `.ino`?", - "partner": "Partner", + "partner": "Parceiro", "processing": "Em processamento", "recommended": "Recomendado", - "retired": "Retired", + "retired": "Afastado", "selectedOn": "em {0}", "serialMonitor": "Monitor Serial", "type": "Tipo", "unknown": "Desconhecido", - "updateable": "Updatable" + "updateable": "Atualizável" }, "compile": { "error": "Erro de compilação: {0}" @@ -155,39 +160,49 @@ "component": { "boardsIncluded": "Placas incluídas nesse pacote:", "by": "por", + "clickToOpen": "Aperte para abrir no navegador: {0}", "filterSearch": "Filtrar a sua pesquisa…", "install": "Instalar", - "installed": "Installed", + "installLatest": "Instalar mais recente", + "installVersion": "Instalar {0}", + "installed": "{0} instalado", "moreInfo": "Mais informações", + "otherVersions": "Outras Versões", + "remove": "Remover", + "title": "{0} por {1}", "uninstall": "Desinstalar", "uninstallMsg": "Deseja desinstalar {0}?", - "version": "Versão {0}" + "update": "Atualizar" }, "configuration": { "cli": { - "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" + "inaccessibleDirectory": "Não foi possível acessar a localização do caderno de esboço em '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Conexão perdida. Atualizações e Ações de Esboço na Nuvem não estarão disponíveis." + }, "contributions": { "addFile": "Adicionar Arquivo", "fileAdded": "Um arquivo adicionado ao sketch.", "plotter": { - "couldNotOpen": "Couldn't open serial plotter" + "couldNotOpen": "Não foi possível abrir o planejador serial" }, "replaceTitle": "Substituir" }, "core": { "compilerWarnings": { - "all": "All", - "default": "Default", - "more": "More", - "none": "None" + "all": "Todos", + "default": "Padrão", + "more": "Mais", + "none": "Nenhum" } }, "coreContribution": { "copyError": "Mensagem de erro Copiar", - "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." + "noBoardSelected": "Nenhuma placa selecionada. Por favor, selecione a sua placa Arduino do menu Ferramentas -> Placas." }, + "createCloudCopy": "Enviar Esboço para Nuvem", "daemon": { "restart": "Reiniciar Daemon", "start": "Iniciar Daemon", @@ -198,7 +213,7 @@ "debuggingNotSupported": "A depuração não é suportada por '{0}'", "noPlatformInstalledFor": "A plataforma não está instalada para '{0}'", "optimizeForDebugging": "Otimizar para Depuração", - "sketchIsNotCompiled": "Sketch '{0}' must be verified before starting a debug session. Please verify the sketch and start debugging again. Do you want to verify the sketch now?" + "sketchIsNotCompiled": "O Esboço '{0}' deve ser verificado antes de iniciar uma sessão de depuramento. Por favor, verifique o esboço e comece a depurar novamente. Você quer verificar o esboço agora?" }, "dialog": { "dontAskAgain": "Não perguntar novamente" @@ -213,7 +228,7 @@ "increaseIndent": "Aumentar Recuo", "nextError": "Próximo Erro", "previousError": "Erro Anterior", - "revealError": "Reveal Error" + "revealError": "Mostrar Erro" }, "electron": { "couldNotSave": "Não foi possível salvar o sketch. Por favor, copie seu trabalho não salvo para o seu editor de texto favorito e reinicie a IDE.", @@ -273,10 +288,10 @@ "contributedLibraries": "Bibliotecas contribuídas", "include": "Incluir Biblioteca", "installAll": "Instalar todas", - "installLibraryDependencies": "Install library dependencies", + "installLibraryDependencies": "Instalar dependências da biblioteca", "installMissingDependencies": "Deseja instalar todas as dependências ausentes?", "installOneMissingDependency": "Deseja instalar a dependência ausente?", - "installWithoutDependencies": "Install without dependencies", + "installWithoutDependencies": "Instalar sem dependências", "installedSuccessfully": "Biblioteca instalada com sucesso {0}: {1}", "libraryAlreadyExists": "Essa biblioteca já existe. Você deseja sobrescreve-la?", "manageLibraries": "Gerenciar bibliotecas...", @@ -290,22 +305,22 @@ "zipLibrary": "Biblioteca" }, "librarySearchProperty": { - "topic": "Topic" + "topic": "Tópico" }, "libraryTopic": { - "communication": "Communication", - "dataProcessing": "Data Processing", - "dataStorage": "Data Storage", - "deviceControl": "Device Control", - "display": "Display", - "other": "Other", - "sensors": "Sensors", - "signalInputOutput": "Signal Input/Output", - "timing": "Timing", - "uncategorized": "Uncategorized" + "communication": "Comunicação", + "dataProcessing": "Processamento de Dados", + "dataStorage": "Armazenamento de Dados", + "deviceControl": "Controle do Dispositivo", + "display": "Mostrar", + "other": "Outros", + "sensors": "Sensores", + "signalInputOutput": "Sinal de Entrada/Saída", + "timing": "Temporização", + "uncategorized": "Sem categoria" }, "libraryType": { - "installed": "Installed" + "installed": "Instalados" }, "menu": { "advanced": "Avançado", @@ -313,11 +328,18 @@ "tools": "Ferramentas" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Impossível fechar websocket", "unableToConnectToWebSocket": "Impossível conectar ao websocket" }, "newCloudSketch": { - "newSketchTitle": "Name of the new Cloud Sketch" + "newSketchTitle": "Nome do novo Esboço na Nuvem" }, "portProtocol": { "network": "Rede", @@ -332,14 +354,14 @@ "automatic": "Automático", "board.certificates": "Lista de certificados que podem ser carregados nas placas", "browse": "Procurar", - "checkForUpdate": "Receive notifications of available updates for the IDE, boards, and libraries. Requires an IDE restart after change. It's true by default.", + "checkForUpdate": "Receba notificações de atualizações disponíveis para a IDE, placas, e bibliotecas. Requer que a IDE seja reinicializada depois de mudanças. Verdadeiro por padrão.", "choose": "Escolher", "cli.daemonDebug": "Habilite o log de depuração das chamadas gRPC para a CLI do Arduino. Uma reinicialização do IDE é necessária para que essa configuração tenha efeito. É falso por padrão.", - "cloud.enabled": "Verdadeiro se as funções de sincronização de sketch estiverem ativadas. O padrão é verdadeiro.", - "cloud.pull.warn": "Verdadeiro se os usuários devem ser avisados antes de baixar um sketch da nuvem. O padrão é verdadeiro.", - "cloud.push.warn": "Verdadeiro se os usuários devem ser avisados antes de enviar um sketch para a nuvem. O padrão é verdadeiro.", - "cloud.pushpublic.warn": "Verdadeiro se os usuários devem ser avisados antes de enviar um sketch público para a nuvem. O padrão é verdadeiro.", - "cloud.sketchSyncEndpoint": "O endpoint usado para enviar e baixar os sketches de um backend. Por padrão, ele aponta para a Arduino Cloud API.", + "cloud.enabled": "Verdadeiro se as funções de sincronização de Esboço estiverem habilitadas. O padrão é verdadeiro.", + "cloud.pull.warn": "Verdadeiro se os usuários devem ser avisados antes de baixar um esboço da nuvem. O padrão é verdadeiro.", + "cloud.push.warn": "Verdadeiro se os usuários devem ser avisados antes de enviar um esboço para a nuvem. O padrão é verdadeiro.", + "cloud.pushpublic.warn": "Verdadeiro se os usuários devem ser avisados antes de enviar um esboço público para a nuvem. O padrão é verdadeiro.", + "cloud.sketchSyncEndpoint": "O endpoint usado para enviar e baixar os esboços de um backend. Por padrão, ele aponta para a API da Nuvem Arduino.", "compile": "compilar", "compile.experimental": "Verdadeiro se o IDE deve trabalhar com múltiplos erros de compilação. Falso por padrão", "compile.revealRange": "Ajusta como os erros do compilador são revelados no editor após uma falha na verificação/upload. Valores possíveis: 'auto': Role verticalmente conforme necessário e revele uma linha. 'center': Role verticalmente conforme necessário e revele uma linha centralizada verticalmente. 'top': Role verticalmente conforme necessário e revele uma linha próxima ao topo da janela de visualização, otimizada para visualizar uma definição de código. 'centerIfOutsideViewport': Role verticalmente conforme necessário e revele uma linha centralizada verticalmente somente se estiver fora da viewport. O valor padrão é '{0}'.", @@ -349,32 +371,32 @@ "editorFontSize": "Tamanho da fonte do editor", "editorQuickSuggestions": "Dicas do editor", "enterAdditionalURLs": "Insira URLs adicionais, uma por linha", - "files.inside.sketches": "Mostrar arquivos dentro dos Sketches", + "files.inside.sketches": "Mostrar arquivos dentro dos Esboços", "ide.updateBaseUrl": "A URL base de onde baixar atualizações. Padrão para 'https://downloads.arduino.cc/arduino-ide'", "ide.updateChannel": "Canal de lançamento para se atualizar. 'stable' é o lançamento estável, 'nightly' é o último build de desenvolvimento.", "interfaceScale": "Dimensões da interface", "invalid.editorFontSize": "Tamanho da fonte do editor inválido. Deve ser um número inteiro positivo.", - "invalid.sketchbook.location": "Localização inválida para o sketchbook: {0}", + "invalid.sketchbook.location": "Localização inválida para o caderno de esboços: {0}", "invalid.theme": "Tema inválido", - "language.log": "Verdadeiro se o Arduino Language Server deverá gerar arquivos de log na pasta do sketch. Caso contrário, falso. Falso é padrão.", + "language.log": "Verdadeiro se o Arduino Language Server deverá gerar arquivos de log na pasta do esboço. Caso contrário, falso. O padrão é falso.", "language.realTimeDiagnostics": "Se marcado, diagnósticos em tempo-real serão exibidos enquanto digita no editor. Fica desmarcado por padrão.", "manualProxy": "Configurações manuais de proxy", "network": "Rede", - "newSketchbookLocation": "Escolher", - "noCliConfig": "Could not load the CLI configuration", + "newSketchbookLocation": "Escolher nova localização para o Caderno de Esboços", + "noCliConfig": "Não foi possível carregar a configuração CLI", "noProxy": "Sem proxy", "proxySettings": { - "hostname": "Host name", - "password": "Password", - "port": "Port number", - "username": "Username" + "hostname": "Nome do Hospedeiro", + "password": "Senha", + "port": "número da Porta", + "username": "Nome de usuário" }, "showVerbose": "Mostrar a saída detalhada durante", "sketch": { - "inoBlueprint": "Absolute filesystem path to the default `.ino` blueprint file. If specified, the content of the blueprint file will be used for every new sketch created by the IDE. The sketches will be generated with the default Arduino content if not specified. Unaccessible blueprint files are ignored. **A restart of the IDE is needed** for this setting to take effect." + "inoBlueprint": "Caminho absoluto do sistema de arquivos para o arquivo de projeto `.ino`. Se especificado, o conteúdo do arquivo de projeto vai ser usado a cada esboço novo criado pela IDE. Se não especificado, os esboços vão ser gerados com o conteúdo padrão do Arduino. Arquivos de projeto inacessíveis são ignorados. **Uma reinicialização da IDE é necessária** para que essa configuração entre em efeito." }, - "sketchbook.location": "Localização dos Sketchbooks", - "sketchbook.showAllFiles": "Verdadeiro para mostrar todos os arquivos de sketch dentro do sketch. Falso é padrão.", + "sketchbook.location": "Localização do Caderno de Esboços", + "sketchbook.showAllFiles": "Verdadeiro para mostrar todos os arquivos de esboço dentro do esboço. O padrão é falso.", "survey.notification": "Verdadeiro se o usuário deve ser notificado se uma pesquisa estiver disponível. Verdadeiro por padrão", "unofficialBoardSupport": "Clique para obter uma lista de URLs de placas não oficiais suportadas", "upload": "enviar", @@ -382,18 +404,19 @@ "verifyAfterUpload": "Verificar o código após enviar", "window.autoScale": "Verdadeiro se a interface do usuário for dimensionada automaticamente com o tamanho da fonte.", "window.zoomLevel": { - "deprecationMessage": "Deprecated. Use 'window.zoomLevel' instead." + "deprecationMessage": "Descontinuada. Use 'window.zoomLevel' ao invés disso." } }, "renameCloudSketch": { - "renameSketchTitle": "New name of the Cloud Sketch" + "renameSketchTitle": "Novo nome para o Esboço na Nuvem" }, "replaceMsg": "Substituir a versão existente de {0}?", "selectZip": "Selecione um arquivo zip contendo a biblioteca que deseja adicionar", "serial": { "autoscroll": "Avanço automático de linha", "carriageReturn": "Retorno de linha", - "message": "Message (Enter to send message to '{0}' on '{1}')", + "connecting": "Connecting to '{0}' on '{1}'...", + "message": "Mensagem ({0} + Enter para enviar mensagem para '{1}' em '{2}'", "newLine": "Nova linha", "newLineCarriageReturn": "Nova linha e retorno de linha", "noLineEndings": "Sem final de linha", @@ -403,77 +426,88 @@ "toggleTimestamp": "Mudar Data e Hora" }, "sketch": { - "archiveSketch": "Arquivar Sketch", - "cantOpen": "Directoria chamada \"{0}\" já existe. Não é possível abrir o rascunho.", - "close": "Tem certeza que deseja fechar o sketch?", - "compile": "Compiling sketch...", - "configureAndUpload": "Configure and Upload", + "archiveSketch": "Arquivar Esboço", + "cantOpen": "Um diretório chamado de \"{0}\" já existe. Não é possível abrir o esboço.", + "close": "Você tem certeza de que você quer fechar esse esboço?", + "compile": "Compilando esboço...", + "configureAndUpload": "Configurar e fazer Envio", "createdArchive": "Arquivo criado '{0}'.", "doneCompiling": "Compilação concluída.", "doneUploading": "Envio concluído.", - "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", - "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", + "editInvalidSketchFolderLocationQuestion": "Você quer tentar salvar o esboço para um local diferente?", + "editInvalidSketchFolderQuestion": "Você quer tentar salvar o esboço com um nome diferente?", "exportBinary": "Exportar Binário Compilado", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", - "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", - "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", - "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidCloudSketchName": "O nome deve começar com uma letra, número, ou underline, seguido por letras, números, hífens, pontos ou underlines. O tamanho máximo é 36 caracteres. ", + "invalidSketchFolderLocationDetails": "Você não pode salvar um esboço em um diretório dentro de si mesmo.", + "invalidSketchFolderLocationMessage": "Localização de diretório de esboço inválida: '{0}'", + "invalidSketchFolderNameMessage": "Nome de diretório de esboço inválido: '{0}'", + "invalidSketchName": "O nome deve começar com uma letra, número, ou underline, seguido por letras, números, hífens, pontos ou underlines. O tamanho máximo é 63 caracteres. ", "moving": "Movendo", "movingMsg": "O ficheiro \"{0}\" tem que estar dentro de uma pasta de esboços chamada \"{1}\".\nCriar esta pasta, mover o ficheiro e continuar?", - "new": "New Sketch", - "noTrailingPeriod": "A filename cannot end with a dot", + "new": "Novo Esboço", + "noTrailingPeriod": "Um nome de arquivo não pode terminar com um ponto.", "openFolder": "Abrir Pasta", "openRecent": "Abrir Recente", - "openSketchInNewWindow": "Abrir sketch em uma nova janela", - "reservedFilename": "'{0}' is a reserved filename.", - "saveFolderAs": "Salvar a pasta de sketch como...", - "saveSketch": "Salve seu sketch para abrí-lo novamente mais tarde", - "saveSketchAs": "Salvar a pasta de sketch como...", - "showFolder": "Mostrar a pasta de Sketches", - "sketch": "Sketch", - "sketchbook": "Sketchbook", - "titleLocalSketchbook": "Sketchbook Local", - "titleSketchbook": "Sketchbook", + "openSketchInNewWindow": "Abrir Esboço em uma Nova Janela", + "reservedFilename": "'{0}' é um nome de arquivo reservado.", + "saveFolderAs": "Salvar diretório de esboço como...", + "saveSketch": "Salve o seu esboço para abrí-lo novamente mais tarde.", + "saveSketchAs": "Salvar o diretório de esboços como...", + "showFolder": "Mostrar o diretório de Esboços...", + "sketch": "Esboço", + "sketchbook": "Caderno de Esboços", + "titleLocalSketchbook": "Caderno de Esboços local", + "titleSketchbook": "Caderno de Esboços", "upload": "Enviar usando Programador", "uploadUsingProgrammer": "Enviar Usando Programador", - "uploading": "Uploading...", + "uploading": "Enviando...", "userFieldsNotFoundError": "Não é possível encontrar dados de usuário para placa conectada", "verify": "Verificar", "verifyOrCompile": "Verificar/Compilar" }, "sketchbook": { - "newCloudSketch": "New Cloud Sketch", - "newSketch": "New Sketch" + "newCloudSketch": "Novo Esboço na Nuvem", + "newSketch": "Novo Esboço" }, "survey": { "answerSurvey": "Responder a pesquisa", "dismissSurvey": "Não mostrar novamente", "surveyMessage": "Por favor, ajude-nos a melhorar respondendo essa pequena pesquisa. Nós valorizamos nossa comunidade e gostaríamos de conhecer nossos colaboradores um pouco melhor." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Nuvem" + }, "updateIndexes": { - "updateIndexes": "Update Indexes", - "updateLibraryIndex": "Update Library Index", - "updatePackageIndex": "Update Package Index" + "updateIndexes": "Atualizar Índices", + "updateLibraryIndex": "Atualizar Índice de Biblioteca", + "updatePackageIndex": "Atualizar Índice de Pacote" }, "upload": { "error": "{0} erro: {1}" }, "userFields": { "cancel": "Cancelar", - "enterField": "Enter {0}", + "enterField": "Insira {0}", "upload": "Carregar" }, "validateSketch": { - "abortFixMessage": "The sketch is still invalid. Do you want to fix the remaining problems? By clicking '{0}', a new sketch will open.", - "abortFixTitle": "Invalid sketch", - "renameSketchFileMessage": "The sketch file '{0}' cannot be used. {1} Do you want to rename the sketch file now?", - "renameSketchFileTitle": "Invalid sketch filename", - "renameSketchFolderMessage": "The sketch '{0}' cannot be used. {1} To get rid of this message, rename the sketch. Do you want to rename the sketch now?", - "renameSketchFolderTitle": "Invalid sketch name" + "abortFixMessage": "O esboço ainda é inválido. Você quer consertar os problemas restantes? Ao apertar '{0}', um novo esboço irá abrir.", + "abortFixTitle": "Esboço inválido", + "renameSketchFileMessage": "O arquivo de esboço '{0}' não pode ser usado. {1} Você quer renomear o nome do arquivo de esboço agora?", + "renameSketchFileTitle": "Nome de arquivo de esboço inválido.", + "renameSketchFolderMessage": "O esboço '{0}' não pode ser usado. {1} Para se livrar dessa mensagem, renomeie o esboço. Você quer renomear o esboço agora?", + "renameSketchFolderTitle": "Nome de esboço inválido." }, "workspace": { - "alreadyExists": "'{0}' already exists." + "alreadyExists": "'{0}' já existe." } }, "theia": { @@ -483,6 +517,7 @@ "couldNotSave": "Não foi possível salvar o sketch. Copie seu trabalho não salvo em seu editor de texto favorito e reinicie a IDE.", "daemonOffline": "CLI Daemon Offline", "offline": "Offline", + "offlineText": "Desconectado", "quitTitle": "Você tem certeza que quer sair?" }, "editor": { @@ -493,8 +528,8 @@ "expand": "Expandir" }, "workspace": { - "deleteCloudSketch": "The cloud sketch '{0}' will be permanently deleted from the Arduino servers and the local caches. This action is irreversible. Do you want to delete the current sketch?", - "deleteCurrentSketch": "The sketch '{0}' will be permanently deleted. This action is irreversible. Do you want to delete the current sketch?", + "deleteCloudSketch": "O Esboço na Nuvem '{0}' vai ser permanentemente deletado dos servidores Arduino e das memórias locais. Essa ação é irreversível. Você quer deletar o esboço atual?", + "deleteCurrentSketch": "O Esboço '{0}' vai ser permanentemente deletado. Essa ação é irreversível. Você quer deletar o esboço atual?", "fileNewName": "Nome para o novo arquivo", "invalidExtension": "\".{0}\" não é uma extensão válida.", "newFileName": "Novo nome para o arquivo" diff --git a/i18n/ro.json b/i18n/ro.json index bd5ef08fd..fc74bc520 100644 --- a/i18n/ro.json +++ b/i18n/ro.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "Despre {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "Board{0}", "boardConfigDialogTitle": "Select Other Board and Port", @@ -83,13 +89,12 @@ "mouseError": "'Mouse' not found. Does your sketch include the line '#include <Mouse.h>'?" }, "cloud": { - "account": "Account", "chooseSketchVisibility": "Choose visibility of your Sketch:", "cloudSketchbook": "Cloud Sketchbook", "connected": "Conectat", "continue": "Continuă", - "donePulling": "Done pulling ‘{0}’.", - "donePushing": "Done pushing ‘{0}’.", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "Embed:", "emptySketchbook": "Your Sketchbook is empty", "goToCloud": "Go to Cloud", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "Boards included in this package:", "by": "de", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "Filtrează căutarea...", "install": "Instalează", - "installed": "Installed", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "Mai multe informații", + "otherVersions": "Other Versions", + "remove": "Remove", + "title": "{0} by {1}", "uninstall": "Dezinstalează", "uninstallMsg": "Dorești să dezinstalezi {0}?", - "version": "Versiunea {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "Adaugă Fișier", "fileAdded": "One file added to the sketch.", @@ -188,6 +202,7 @@ "copyError": "Copy error messages", "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Restart Daemon", "start": "Start Daemon", @@ -313,6 +328,13 @@ "tools": "Unelte" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Unable to close websocket", "unableToConnectToWebSocket": "Unable to connect to websocket" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "Autoderulare", "carriageReturn": "Carriage Return", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Message (Enter to send message to '{0}' on '{1}')", "newLine": "Linie Nouă", "newLineCarriageReturn": "NL și CR", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "Export Compiled Binary", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "Moving", "movingMsg": "The file \"{0}\" needs to be inside a sketch folder named \"{1}\".\nCreate this folder, move the file, and continue?", "new": "New Sketch", @@ -431,7 +454,7 @@ "saveSketch": "Save your sketch to open it again later.", "saveSketchAs": "Save sketch folder as...", "showFolder": "Show Sketch Folder", - "sketch": "Sketch", + "sketch": "Schița", "sketchbook": "Sketchbook", "titleLocalSketchbook": "Local Sketchbook", "titleSketchbook": "Sketchbook", @@ -451,6 +474,17 @@ "dismissSurvey": "Don't show again", "surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Update Indexes", "updateLibraryIndex": "Update Library Index", @@ -483,6 +517,7 @@ "couldNotSave": "Could not save the sketch. Please copy your unsaved work into your favorite text editor, and restart the IDE.", "daemonOffline": "CLI Daemon Offline", "offline": "Deconectat", + "offlineText": "Deconectat", "quitTitle": "Are you sure you want to quit?" }, "editor": { diff --git a/i18n/ru.json b/i18n/ru.json index 16d640bad..06f0ae305 100644 --- a/i18n/ru.json +++ b/i18n/ru.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "О программе {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "Плата{0}", "boardConfigDialogTitle": "Select Other Board and Port", @@ -83,13 +89,12 @@ "mouseError": "'Mouse' не найдено. В вашем скетче есть строка '#include <Mouse.h>'?" }, "cloud": { - "account": "Аккаунт", "chooseSketchVisibility": "Выберите видимость своего скетча:", "cloudSketchbook": "Альбом в облаке", "connected": "Подключено", "continue": "Продолжить", - "donePulling": "Закончить вытягивание ‘{0}’.", - "donePushing": "Отправлено ‘{0}’.", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "Встроить:", "emptySketchbook": "Ваш альбом пуст", "goToCloud": "Go to Cloud", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "Boards included in this package:", "by": "от", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "Отфильтровать результаты поиска...", "install": "Установка", - "installed": "Installed", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "Дополнительная информация", + "otherVersions": "Other Versions", + "remove": "Удалить", + "title": "{0} by {1}", "uninstall": "Удалить", "uninstallMsg": "Вы хотите удалить {0}?", - "version": "Версия {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "Добавить файл...", "fileAdded": "Один файл добавлен в скетч.", @@ -188,6 +202,7 @@ "copyError": "Скопировать сообщения ошибок", "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Перезапустить Daemon", "start": "Запустить Daemon", @@ -313,6 +328,13 @@ "tools": "Инструменты" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Не удалось закрыть веб-сокет.", "unableToConnectToWebSocket": "Не удается подключиться к веб-сокету." }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "Автопрокрутка", "carriageReturn": "CR Возврат каретки", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Message (Enter to send message to '{0}' on '{1}')", "newLine": "Новая строка", "newLineCarriageReturn": "NL & CR", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "Экспортировать скомпилированный бинарный файл", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "Переместить", "movingMsg": "Файл «{0}» должен быть в папке с именем скетча «{1}». \nСоздать эту папку, переместить файл и продолжить?", "new": "New Sketch", @@ -426,7 +449,7 @@ "openFolder": "Открыть папку", "openRecent": "Открыть предыдущий", "openSketchInNewWindow": "Открыть скетч в новом окне", - "reservedFilename": "'{0}' is a reserved filename.", + "reservedFilename": "{0} это зарезервированное имя файла.", "saveFolderAs": "Сохранить папку со скетчем как...", "saveSketch": "Сохраните свой скетч, чтобы открыть его позже.", "saveSketchAs": "Сохранить папку скетча как...", @@ -451,6 +474,17 @@ "dismissSurvey": "Больше не показывать", "surveyMessage": "Пожалуйста, помоги нам стать лучше, пройдя этот супер-короткий опрос. Мы ценим наше сообщество и хотели бы узнать наших сторонников немного лучше!" }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Update Indexes", "updateLibraryIndex": "Update Library Index", @@ -470,10 +504,10 @@ "renameSketchFileMessage": "The sketch file '{0}' cannot be used. {1} Do you want to rename the sketch file now?", "renameSketchFileTitle": "Invalid sketch filename", "renameSketchFolderMessage": "The sketch '{0}' cannot be used. {1} To get rid of this message, rename the sketch. Do you want to rename the sketch now?", - "renameSketchFolderTitle": "Invalid sketch name" + "renameSketchFolderTitle": "Неверное название скетча" }, "workspace": { - "alreadyExists": "'{0}' already exists." + "alreadyExists": "{0} уже существует." } }, "theia": { @@ -483,6 +517,7 @@ "couldNotSave": "Скетч не сохранён. Пожалуйста, скопируйте вашу не сохраненную работу в ваш внешний текстовый редактор и перезапустите IDE.", "daemonOffline": "CLI демон не подключен", "offline": "Не подключено", + "offlineText": "Не подключено", "quitTitle": "Вы уверены, что хотите выйти?" }, "editor": { diff --git a/i18n/sl.json b/i18n/sl.json index 8fd1a3a1b..08a47309e 100644 --- a/i18n/sl.json +++ b/i18n/sl.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "About {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "Board{0}", "boardConfigDialogTitle": "Select Other Board and Port", @@ -83,13 +89,12 @@ "mouseError": "'Mouse' not found. Does your sketch include the line '#include <Mouse.h>'?" }, "cloud": { - "account": "Account", "chooseSketchVisibility": "Choose visibility of your Sketch:", "cloudSketchbook": "Cloud Sketchbook", "connected": "Connected", "continue": "Continue", - "donePulling": "Done pulling ‘{0}’.", - "donePushing": "Done pushing ‘{0}’.", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "Embed:", "emptySketchbook": "Your Sketchbook is empty", "goToCloud": "Go to Cloud", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "Boards included in this package:", "by": "by", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "Filter your search...", "install": "Install", - "installed": "Installed", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "More info", + "otherVersions": "Other Versions", + "remove": "Remove", + "title": "{0} by {1}", "uninstall": "Uninstall", "uninstallMsg": "Do you want to uninstall {0}?", - "version": "Version {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "Add File", "fileAdded": "One file added to the sketch.", @@ -188,6 +202,7 @@ "copyError": "Copy error messages", "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Restart Daemon", "start": "Start Daemon", @@ -313,6 +328,13 @@ "tools": "Tools" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Unable to close websocket", "unableToConnectToWebSocket": "Unable to connect to websocket" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "Autoscroll", "carriageReturn": "Carriage Return", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Message (Enter to send message to '{0}' on '{1}')", "newLine": "New Line", "newLineCarriageReturn": "Both NL & CR", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "Export Compiled Binary", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "Moving", "movingMsg": "The file \"{0}\" needs to be inside a sketch folder named \"{1}\".\nCreate this folder, move the file, and continue?", "new": "New Sketch", @@ -451,6 +474,17 @@ "dismissSurvey": "Don't show again", "surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Update Indexes", "updateLibraryIndex": "Update Library Index", @@ -483,6 +517,7 @@ "couldNotSave": "Could not save the sketch. Please copy your unsaved work into your favorite text editor, and restart the IDE.", "daemonOffline": "CLI Daemon Offline", "offline": "Offline", + "offlineText": "Offline", "quitTitle": "Are you sure you want to quit?" }, "editor": { diff --git a/i18n/sr.json b/i18n/sr.json index b6d06fd8c..989a1a542 100644 --- a/i18n/sr.json +++ b/i18n/sr.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "О {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "Плоча{0}", "boardConfigDialogTitle": "Select Other Board and Port", @@ -83,13 +89,12 @@ "mouseError": "'Mouse' not found. Does your sketch include the line '#include <Mouse.h>'?" }, "cloud": { - "account": "Account", "chooseSketchVisibility": "Одабери видљивост твог рада:", "cloudSketchbook": "Cloud Sketchbook", "connected": "Повезан", "continue": "Наставите", - "donePulling": "Готово повлачење ‘{0}’.", - "donePushing": "Done pushing ‘{0}’.", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "Угради:", "emptySketchbook": "Твоја радна свеска је празна", "goToCloud": "Go to Cloud", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "Boards included in this package:", "by": "од", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "Филтрирај претрагу...", "install": "Инсталирај", - "installed": "Installed", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "Више информација", + "otherVersions": "Other Versions", + "remove": "Избаци", + "title": "{0} by {1}", "uninstall": "Деинсталирај", "uninstallMsg": "Да ли желиш да деинсталираш {0}? ", - "version": "Верзија {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "Додај датотеку", "fileAdded": "Датотека је додата у рад.", @@ -188,6 +202,7 @@ "copyError": "Copy error messages", "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Restart Daemon", "start": "Start Daemon", @@ -313,6 +328,13 @@ "tools": "Алатке" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Unable to close websocket", "unableToConnectToWebSocket": "Unable to connect to websocket" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "Аутоматско скроловање", "carriageReturn": "Carriage Return", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Message (Enter to send message to '{0}' on '{1}')", "newLine": "Нова линија", "newLineCarriageReturn": "И нова линија и CR", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "Export Compiled Binary", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "Премјешта се", "movingMsg": "Датотека \"{0}\" мора да буде унутар радног директоријума \"{1}\".\nКреирај овај директоријум, премјести датотеку, и настави?", "new": "New Sketch", @@ -451,6 +474,17 @@ "dismissSurvey": "Don't show again", "surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Update Indexes", "updateLibraryIndex": "Update Library Index", @@ -483,6 +517,7 @@ "couldNotSave": "Could not save the sketch. Please copy your unsaved work into your favorite text editor, and restart the IDE.", "daemonOffline": "CLI Daemon Offline", "offline": "Није на мрежи", + "offlineText": "Није на мрежи", "quitTitle": "Are you sure you want to quit?" }, "editor": { diff --git a/i18n/sv.json b/i18n/sv.json new file mode 100644 index 000000000..08a47309e --- /dev/null +++ b/i18n/sv.json @@ -0,0 +1,538 @@ +{ + "arduino": { + "about": { + "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", + "label": "About {0}" + }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, + "board": { + "board": "Board{0}", + "boardConfigDialogTitle": "Select Other Board and Port", + "boardInfo": "Board Info", + "boards": "boards", + "configDialog1": "Select both a Board and a Port if you want to upload a sketch.", + "configDialog2": "If you only select a Board you will be able to compile, but not to upload your sketch.", + "couldNotFindPreviouslySelected": "Could not find previously selected board '{0}' in installed platform '{1}'. Please manually reselect the board you want to use. Do you want to reselect it now?", + "disconnected": "Disconnected", + "getBoardInfo": "Get Board Info", + "inSketchbook": " (in Sketchbook)", + "installNow": "The \"{0} {1}\" core has to be installed for the currently selected \"{2}\" board. Do you want to install it now?", + "noBoardsFound": "No boards found for \"{0}\"", + "noFQBN": "The FQBN is not available for the selected board \"{0}\". Do you have the corresponding core installed?", + "noNativeSerialPort": "Native serial port, can't obtain info.", + "noPortsDiscovered": "No ports discovered", + "noPortsSelected": "No ports selected for board: '{0}'.", + "nonSerialPort": "Non-serial port, can't obtain info.", + "noneSelected": "No boards selected.", + "openBoardsConfig": "Select other board and port…", + "pleasePickBoard": "Please pick a board connected to the port you have selected.", + "port": "Port{0}", + "portLabel": "Port: {0}", + "ports": "ports", + "programmer": "Programmer", + "reselectLater": "Reselect later", + "searchBoard": "Search board", + "selectBoard": "Select Board", + "selectPortForInfo": "Please select a port to obtain board info.", + "showAllAvailablePorts": "Shows all available ports when enabled", + "showAllPorts": "Show all ports", + "succesfullyInstalledPlatform": "Successfully installed platform {0}:{1}", + "succesfullyUninstalledPlatform": "Successfully uninstalled platform {0}:{1}", + "typeOfPorts": "{0} ports", + "unknownBoard": "Unknown board" + }, + "boardsManager": "Boards Manager", + "boardsType": { + "arduinoCertified": "Arduino Certified" + }, + "bootloader": { + "burnBootloader": "Burn Bootloader", + "burningBootloader": "Burning bootloader...", + "doneBurningBootloader": "Done burning bootloader." + }, + "burnBootloader": { + "error": "Error while burning the bootloader: {0}" + }, + "certificate": { + "addNew": "Add New", + "addURL": "Add URL to fetch SSL certificate", + "boardAtPort": "{0} at {1}", + "certificatesUploaded": "Certificates uploaded.", + "enterURL": "Enter URL", + "noSupportedBoardConnected": "No supported board connected", + "openContext": "Open context", + "remove": "Remove", + "selectBoard": "Select a board...", + "selectCertificateToUpload": "1. Select certificate to upload", + "selectDestinationBoardToUpload": "2. Select destination board and upload certificate", + "upload": "Upload", + "uploadFailed": "Upload failed. Please try again.", + "uploadRootCertificates": "Upload SSL Root Certificates", + "uploadingCertificates": "Uploading certificates." + }, + "checkForUpdates": { + "checkForUpdates": "Check for Arduino Updates", + "installAll": "Install All", + "noUpdates": "There are no recent updates available.", + "promptUpdateBoards": "Updates are available for some of your boards.", + "promptUpdateLibraries": "Updates are available for some of your libraries.", + "updatingBoards": "Updating boards...", + "updatingLibraries": "Updating libraries..." + }, + "cli-error-parser": { + "keyboardError": "'Keyboard' not found. Does your sketch include the line '#include <Keyboard.h>'?", + "mouseError": "'Mouse' not found. Does your sketch include the line '#include <Mouse.h>'?" + }, + "cloud": { + "chooseSketchVisibility": "Choose visibility of your Sketch:", + "cloudSketchbook": "Cloud Sketchbook", + "connected": "Connected", + "continue": "Continue", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", + "embed": "Embed:", + "emptySketchbook": "Your Sketchbook is empty", + "goToCloud": "Go to Cloud", + "learnMore": "Learn more", + "link": "Link:", + "notYetPulled": "Cannot push to Cloud. It is not yet pulled.", + "offline": "Offline", + "openInCloudEditor": "Open in Cloud Editor", + "options": "Options...", + "privateVisibility": "Private. Only you can view the Sketch.", + "profilePicture": "Profile picture", + "publicVisibility": "Public. Anyone with the link can view the Sketch.", + "pull": "Pull", + "pullFirst": "You have to pull first to be able to push to the Cloud.", + "pullSketch": "Pull Sketch", + "pullSketchMsg": "Pulling this Sketch from the Cloud will overwrite its local version. Are you sure you want to continue?", + "push": "Push", + "pushSketch": "Push Sketch", + "pushSketchMsg": "This is a Public Sketch. Before pushing, make sure any sensitive information is defined in arduino_secrets.h files. You can make a Sketch private from the Share panel.", + "remote": "Remote", + "share": "Share...", + "shareSketch": "Share Sketch", + "showHideSketchbook": "Show/Hide Cloud Sketchbook", + "signIn": "SIGN IN", + "signInToCloud": "Sign in to Arduino Cloud", + "signOut": "Sign Out", + "sync": "Sync", + "syncEditSketches": "Sync and edit your Arduino Cloud Sketches", + "visitArduinoCloud": "Visit Arduino Cloud to create Cloud Sketches." + }, + "cloudSketch": { + "alreadyExists": "Cloud sketch '{0}' already exists.", + "creating": "Creating cloud sketch '{0}'...", + "new": "New Cloud Sketch", + "notFound": "Could not pull the cloud sketch '{0}'. It does not exist.", + "pulling": "Synchronizing sketchbook, pulling '{0}'...", + "pushing": "Synchronizing sketchbook, pushing '{0}'...", + "renaming": "Renaming cloud sketch from '{0}' to '{1}'...", + "synchronizingSketchbook": "Synchronizing sketchbook..." + }, + "common": { + "all": "All", + "contributed": "Contributed", + "installManually": "Install Manually", + "later": "Later", + "noBoardSelected": "No board selected", + "notConnected": "[not connected]", + "offlineIndicator": "You appear to be offline. Without an Internet connection, the Arduino CLI might not be able to download the required resources and could cause malfunction. Please connect to the Internet and restart the application.", + "oldFormat": "The '{0}' still uses the old `.pde` format. Do you want to switch to the new `.ino` extension?", + "partner": "Partner", + "processing": "Processing", + "recommended": "Recommended", + "retired": "Retired", + "selectedOn": "on {0}", + "serialMonitor": "Serial Monitor", + "type": "Type", + "unknown": "Unknown", + "updateable": "Updatable" + }, + "compile": { + "error": "Compilation error: {0}" + }, + "component": { + "boardsIncluded": "Boards included in this package:", + "by": "by", + "clickToOpen": "Click to open in browser: {0}", + "filterSearch": "Filter your search...", + "install": "Install", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", + "moreInfo": "More info", + "otherVersions": "Other Versions", + "remove": "Remove", + "title": "{0} by {1}", + "uninstall": "Uninstall", + "uninstallMsg": "Do you want to uninstall {0}?", + "update": "Update" + }, + "configuration": { + "cli": { + "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" + } + }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, + "contributions": { + "addFile": "Add File", + "fileAdded": "One file added to the sketch.", + "plotter": { + "couldNotOpen": "Couldn't open serial plotter" + }, + "replaceTitle": "Replace" + }, + "core": { + "compilerWarnings": { + "all": "All", + "default": "Default", + "more": "More", + "none": "None" + } + }, + "coreContribution": { + "copyError": "Copy error messages", + "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." + }, + "createCloudCopy": "Push Sketch to Cloud", + "daemon": { + "restart": "Restart Daemon", + "start": "Start Daemon", + "stop": "Stop Daemon" + }, + "debug": { + "debugWithMessage": "Debug - {0}", + "debuggingNotSupported": "Debugging is not supported by '{0}'", + "noPlatformInstalledFor": "Platform is not installed for '{0}'", + "optimizeForDebugging": "Optimize for Debugging", + "sketchIsNotCompiled": "Sketch '{0}' must be verified before starting a debug session. Please verify the sketch and start debugging again. Do you want to verify the sketch now?" + }, + "dialog": { + "dontAskAgain": "Don't ask again" + }, + "editor": { + "autoFormat": "Auto Format", + "commentUncomment": "Comment/Uncomment", + "copyForForum": "Copy for Forum (Markdown)", + "decreaseFontSize": "Decrease Font Size", + "decreaseIndent": "Decrease Indent", + "increaseFontSize": "Increase Font Size", + "increaseIndent": "Increase Indent", + "nextError": "Next Error", + "previousError": "Previous Error", + "revealError": "Reveal Error" + }, + "electron": { + "couldNotSave": "Could not save the sketch. Please copy your unsaved work into your favorite text editor, and restart the IDE.", + "unsavedChanges": "Any unsaved changes will not be saved." + }, + "examples": { + "builtInExamples": "Built-in examples", + "couldNotInitializeExamples": "Could not initialize built-in examples.", + "customLibrary": "Examples from Custom Libraries", + "for": "Examples for {0}", + "forAny": "Examples for any board", + "menu": "Examples" + }, + "firmware": { + "checkUpdates": "Check Updates", + "failedInstall": "Installation failed. Please try again.", + "install": "Install", + "installingFirmware": "Installing firmware.", + "overwriteSketch": "Installation will overwrite the Sketch on the board.", + "selectBoard": "Select Board", + "selectVersion": "Select firmware version", + "successfullyInstalled": "Firmware successfully installed.", + "updater": "WiFi101 / WiFiNINA Firmware Updater" + }, + "help": { + "environment": "Environment", + "faq": "Frequently Asked Questions", + "findInReference": "Find in Reference", + "gettingStarted": "Getting Started", + "keyword": "Type a keyword", + "privacyPolicy": "Privacy Policy", + "reference": "Reference", + "search": "Search on Arduino.cc", + "troubleshooting": "Troubleshooting", + "visit": "Visit Arduino.cc" + }, + "ide-updater": { + "checkForUpdates": "Check for Arduino IDE Updates", + "closeAndInstallButton": "Close and Install", + "closeToInstallNotice": "Close the software and install the update on your machine.", + "downloadButton": "Download", + "downloadingNotice": "Downloading the latest version of the Arduino IDE.", + "errorCheckingForUpdates": "Error while checking for Arduino IDE updates.\n{0}", + "goToDownloadButton": "Go To Download", + "goToDownloadPage": "An update for the Arduino IDE is available, but we're not able to download and install it automatically. Please go to the download page and download the latest version from there.", + "ideUpdaterDialog": "Software Update", + "newVersionAvailable": "A new version of Arduino IDE ({0}) is available for download.", + "noUpdatesAvailable": "There are no recent updates available for the Arduino IDE", + "notNowButton": "Not now", + "skipVersionButton": "Skip Version", + "updateAvailable": "Update Available", + "versionDownloaded": "Arduino IDE {0} has been downloaded." + }, + "library": { + "addZip": "Add .ZIP Library...", + "arduinoLibraries": "Arduino libraries", + "contributedLibraries": "Contributed libraries", + "include": "Include Library", + "installAll": "Install All", + "installLibraryDependencies": "Install library dependencies", + "installMissingDependencies": "Would you like to install all the missing dependencies?", + "installOneMissingDependency": "Would you like to install the missing dependency?", + "installWithoutDependencies": "Install without dependencies", + "installedSuccessfully": "Successfully installed library {0}:{1}", + "libraryAlreadyExists": "A library already exists. Do you want to overwrite it?", + "manageLibraries": "Manage Libraries...", + "namedLibraryAlreadyExists": "A library folder named {0} already exists. Do you want to overwrite it?", + "needsMultipleDependencies": "The library <b>{0}:{1}</b> needs some other dependencies currently not installed:", + "needsOneDependency": "The library <b>{0}:{1}</b> needs another dependency currently not installed:", + "overwriteExistingLibrary": "Do you want to overwrite the existing library?", + "successfullyInstalledZipLibrary": "Successfully installed library from {0} archive", + "title": "Library Manager", + "uninstalledSuccessfully": "Successfully uninstalled library {0}:{1}", + "zipLibrary": "Library" + }, + "librarySearchProperty": { + "topic": "Topic" + }, + "libraryTopic": { + "communication": "Communication", + "dataProcessing": "Data Processing", + "dataStorage": "Data Storage", + "deviceControl": "Device Control", + "display": "Display", + "other": "Other", + "sensors": "Sensors", + "signalInputOutput": "Signal Input/Output", + "timing": "Timing", + "uncategorized": "Uncategorized" + }, + "libraryType": { + "installed": "Installed" + }, + "menu": { + "advanced": "Advanced", + "sketch": "Sketch", + "tools": "Tools" + }, + "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", + "unableToCloseWebSocket": "Unable to close websocket", + "unableToConnectToWebSocket": "Unable to connect to websocket" + }, + "newCloudSketch": { + "newSketchTitle": "Name of the new Cloud Sketch" + }, + "portProtocol": { + "network": "Network", + "serial": "Serial" + }, + "preferences": { + "additionalManagerURLs": "Additional Boards Manager URLs", + "auth.audience": "The OAuth2 audience.", + "auth.clientID": "The OAuth2 client ID.", + "auth.domain": "The OAuth2 domain.", + "auth.registerUri": "The URI used to register a new user.", + "automatic": "Automatic", + "board.certificates": "List of certificates that can be uploaded to boards", + "browse": "Browse", + "checkForUpdate": "Receive notifications of available updates for the IDE, boards, and libraries. Requires an IDE restart after change. It's true by default.", + "choose": "Choose", + "cli.daemonDebug": "Enable debug logging of the gRPC calls to the Arduino CLI. A restart of the IDE is needed for this setting to take effect. It's false by default.", + "cloud.enabled": "True if the sketch sync functions are enabled. Defaults to true.", + "cloud.pull.warn": "True if users should be warned before pulling a cloud sketch. Defaults to true.", + "cloud.push.warn": "True if users should be warned before pushing a cloud sketch. Defaults to true.", + "cloud.pushpublic.warn": "True if users should be warned before pushing a public sketch to the cloud. Defaults to true.", + "cloud.sketchSyncEndpoint": "The endpoint used to push and pull sketches from a backend. By default it points to Arduino Cloud API.", + "compile": "compile", + "compile.experimental": "True if the IDE should handle multiple compiler errors. False by default", + "compile.revealRange": "Adjusts how compiler errors are revealed in the editor after a failed verify/upload. Possible values: 'auto': Scroll vertically as necessary and reveal a line. 'center': Scroll vertically as necessary and reveal a line centered vertically. 'top': Scroll vertically as necessary and reveal a line close to the top of the viewport, optimized for viewing a code definition. 'centerIfOutsideViewport': Scroll vertically as necessary and reveal a line centered vertically only if it lies outside the viewport. The default value is '{0}'.", + "compile.verbose": "True for verbose compile output. False by default", + "compile.warnings": "Tells gcc which warning level to use. It's 'None' by default", + "compilerWarnings": "Compiler warnings", + "editorFontSize": "Editor font size", + "editorQuickSuggestions": "Editor Quick Suggestions", + "enterAdditionalURLs": "Enter additional URLs, one for each row", + "files.inside.sketches": "Show files inside Sketches", + "ide.updateBaseUrl": "The base URL where to download updates from. Defaults to 'https://downloads.arduino.cc/arduino-ide'", + "ide.updateChannel": "Release channel to get updated from. 'stable' is the stable release, 'nightly' is the latest development build.", + "interfaceScale": "Interface scale", + "invalid.editorFontSize": "Invalid editor font size. It must be a positive integer.", + "invalid.sketchbook.location": "Invalid sketchbook location: {0}", + "invalid.theme": "Invalid theme.", + "language.log": "True if the Arduino Language Server should generate log files into the sketch folder. Otherwise, false. It's false by default.", + "language.realTimeDiagnostics": "If true, the language server provides real-time diagnostics when typing in the editor. It's false by default.", + "manualProxy": "Manual proxy configuration", + "network": "Network", + "newSketchbookLocation": "Select new sketchbook location", + "noCliConfig": "Could not load the CLI configuration", + "noProxy": "No proxy", + "proxySettings": { + "hostname": "Host name", + "password": "Password", + "port": "Port number", + "username": "Username" + }, + "showVerbose": "Show verbose output during", + "sketch": { + "inoBlueprint": "Absolute filesystem path to the default `.ino` blueprint file. If specified, the content of the blueprint file will be used for every new sketch created by the IDE. The sketches will be generated with the default Arduino content if not specified. Unaccessible blueprint files are ignored. **A restart of the IDE is needed** for this setting to take effect." + }, + "sketchbook.location": "Sketchbook location", + "sketchbook.showAllFiles": "True to show all sketch files inside the sketch. It is false by default.", + "survey.notification": "True if users should be notified if a survey is available. True by default.", + "unofficialBoardSupport": "Click for a list of unofficial board support URLs", + "upload": "upload", + "upload.verbose": "True for verbose upload output. False by default.", + "verifyAfterUpload": "Verify code after upload", + "window.autoScale": "True if the user interface automatically scales with the font size.", + "window.zoomLevel": { + "deprecationMessage": "Deprecated. Use 'window.zoomLevel' instead." + } + }, + "renameCloudSketch": { + "renameSketchTitle": "New name of the Cloud Sketch" + }, + "replaceMsg": "Replace the existing version of {0}?", + "selectZip": "Select a zip file containing the library you'd like to add", + "serial": { + "autoscroll": "Autoscroll", + "carriageReturn": "Carriage Return", + "connecting": "Connecting to '{0}' on '{1}'...", + "message": "Message (Enter to send message to '{0}' on '{1}')", + "newLine": "New Line", + "newLineCarriageReturn": "Both NL & CR", + "noLineEndings": "No Line Ending", + "notConnected": "Not connected. Select a board and a port to connect automatically.", + "openSerialPlotter": "Serial Plotter", + "timestamp": "Timestamp", + "toggleTimestamp": "Toggle Timestamp" + }, + "sketch": { + "archiveSketch": "Archive Sketch", + "cantOpen": "A folder named \"{0}\" already exists. Can't open sketch.", + "close": "Are you sure you want to close the sketch?", + "compile": "Compiling sketch...", + "configureAndUpload": "Configure and Upload", + "createdArchive": "Created archive '{0}'.", + "doneCompiling": "Done compiling.", + "doneUploading": "Done uploading.", + "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", + "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", + "exportBinary": "Export Compiled Binary", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", + "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", + "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "moving": "Moving", + "movingMsg": "The file \"{0}\" needs to be inside a sketch folder named \"{1}\".\nCreate this folder, move the file, and continue?", + "new": "New Sketch", + "noTrailingPeriod": "A filename cannot end with a dot", + "openFolder": "Open Folder", + "openRecent": "Open Recent", + "openSketchInNewWindow": "Open Sketch in New Window", + "reservedFilename": "'{0}' is a reserved filename.", + "saveFolderAs": "Save sketch folder as...", + "saveSketch": "Save your sketch to open it again later.", + "saveSketchAs": "Save sketch folder as...", + "showFolder": "Show Sketch Folder", + "sketch": "Sketch", + "sketchbook": "Sketchbook", + "titleLocalSketchbook": "Local Sketchbook", + "titleSketchbook": "Sketchbook", + "upload": "Upload", + "uploadUsingProgrammer": "Upload Using Programmer", + "uploading": "Uploading...", + "userFieldsNotFoundError": "Can't find user fields for connected board", + "verify": "Verify", + "verifyOrCompile": "Verify/Compile" + }, + "sketchbook": { + "newCloudSketch": "New Cloud Sketch", + "newSketch": "New Sketch" + }, + "survey": { + "answerSurvey": "Answer survey", + "dismissSurvey": "Don't show again", + "surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better." + }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, + "updateIndexes": { + "updateIndexes": "Update Indexes", + "updateLibraryIndex": "Update Library Index", + "updatePackageIndex": "Update Package Index" + }, + "upload": { + "error": "{0} error: {1}" + }, + "userFields": { + "cancel": "Cancel", + "enterField": "Enter {0}", + "upload": "Upload" + }, + "validateSketch": { + "abortFixMessage": "The sketch is still invalid. Do you want to fix the remaining problems? By clicking '{0}', a new sketch will open.", + "abortFixTitle": "Invalid sketch", + "renameSketchFileMessage": "The sketch file '{0}' cannot be used. {1} Do you want to rename the sketch file now?", + "renameSketchFileTitle": "Invalid sketch filename", + "renameSketchFolderMessage": "The sketch '{0}' cannot be used. {1} To get rid of this message, rename the sketch. Do you want to rename the sketch now?", + "renameSketchFolderTitle": "Invalid sketch name" + }, + "workspace": { + "alreadyExists": "'{0}' already exists." + } + }, + "theia": { + "core": { + "cannotConnectBackend": "Cannot connect to the backend.", + "cannotConnectDaemon": "Cannot connect to the CLI daemon.", + "couldNotSave": "Could not save the sketch. Please copy your unsaved work into your favorite text editor, and restart the IDE.", + "daemonOffline": "CLI Daemon Offline", + "offline": "Offline", + "offlineText": "Offline", + "quitTitle": "Are you sure you want to quit?" + }, + "editor": { + "unsavedTitle": "Unsaved – {0}" + }, + "messages": { + "collapse": "Collapse", + "expand": "Expand" + }, + "workspace": { + "deleteCloudSketch": "The cloud sketch '{0}' will be permanently deleted from the Arduino servers and the local caches. This action is irreversible. Do you want to delete the current sketch?", + "deleteCurrentSketch": "The sketch '{0}' will be permanently deleted. This action is irreversible. Do you want to delete the current sketch?", + "fileNewName": "Name for new file", + "invalidExtension": ".{0} is not a valid extension", + "newFileName": "New name for file" + } + } +} diff --git a/i18n/th.json b/i18n/th.json index c9644f06d..c00cfd34c 100644 --- a/i18n/th.json +++ b/i18n/th.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "เกี่ยวกับ{0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "บอร์ด{0}", "boardConfigDialogTitle": "เลือกบอร์ดและพอร์ตอื่นๆ", @@ -83,13 +89,12 @@ "mouseError": "'Mouse' not found. Does your sketch include the line '#include <Mouse.h>'?" }, "cloud": { - "account": "Account", "chooseSketchVisibility": "Choose visibility of your Sketch:", "cloudSketchbook": "Cloud Sketchbook", "connected": "Connected", "continue": "Continue", - "donePulling": "Done pulling ‘{0}’.", - "donePushing": "Done pushing ‘{0}’.", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "Embed:", "emptySketchbook": "Your Sketchbook is empty", "goToCloud": "Go to Cloud", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "Boards included in this package:", "by": "by", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "Filter your search...", "install": "Install", - "installed": "Installed", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "More info", + "otherVersions": "Other Versions", + "remove": "Remove", + "title": "{0} by {1}", "uninstall": "Uninstall", "uninstallMsg": "Do you want to uninstall {0}?", - "version": "Version {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "Add File", "fileAdded": "One file added to the sketch.", @@ -188,6 +202,7 @@ "copyError": "Copy error messages", "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Restart Daemon", "start": "Start Daemon", @@ -313,6 +328,13 @@ "tools": "Tools" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Unable to close websocket", "unableToConnectToWebSocket": "Unable to connect to websocket" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "Autoscroll", "carriageReturn": "Carriage Return", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Message (Enter to send message to '{0}' on '{1}')", "newLine": "New Line", "newLineCarriageReturn": "Both NL & CR", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "Export Compiled Binary", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "Moving", "movingMsg": "The file \"{0}\" needs to be inside a sketch folder named \"{1}\".\nCreate this folder, move the file, and continue?", "new": "New Sketch", @@ -451,6 +474,17 @@ "dismissSurvey": "Don't show again", "surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Update Indexes", "updateLibraryIndex": "Update Library Index", @@ -483,6 +517,7 @@ "couldNotSave": "Could not save the sketch. Please copy your unsaved work into your favorite text editor, and restart the IDE.", "daemonOffline": "CLI Daemon Offline", "offline": "Offline", + "offlineText": "Offline", "quitTitle": "Are you sure you want to quit?" }, "editor": { diff --git a/i18n/tr.json b/i18n/tr.json index c319e02c6..afef553bb 100644 --- a/i18n/tr.json +++ b/i18n/tr.json @@ -4,6 +4,12 @@ "detail": "Versiyon: {0}\nTarih: {1}{2}\nCLI Versiyonu: {3}\n\n{4}", "label": "{0} Hakkında" }, + "account": { + "goToCloudEditor": "Bulut Düzenleyici'ye Git", + "goToIoTCloud": "IoT Bulut'a Git", + "goToProfile": "Profile Git", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "Kart{0}", "boardConfigDialogTitle": "Başka Kart ve Port Seç", @@ -83,13 +89,12 @@ "mouseError": "'Mouse' bulunamadı. Eskiziniz '#include <Mouse.h>' satırını içeriyor mu? " }, "cloud": { - "account": "Hesap", "chooseSketchVisibility": "Eskizinizin görünürlüğünü seçin", "cloudSketchbook": "Bulut Eskiz Defteri", "connected": "Bağlandı", "continue": "Devam et", - "donePulling": "Çekme bitti: ‘{0}’.", - "donePushing": "Gönderme bitti: ‘{0}’.", + "donePulling": "Çekme bitti: '{0}'.", + "donePushing": "Gönderme bitti: '{0}'.", "embed": "Yerleştir:", "emptySketchbook": "Eskiz Defteriniz boş", "goToCloud": "Buluta Git", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "Bu pakete dahil kartlar:", "by": "-", + "clickToOpen": "Tarayıca açmak için tıkla: {0}", "filterSearch": "Aramayı Filtrele...", "install": "Kur", - "installed": "Kurulu", + "installLatest": "En Yeniyi Kur", + "installVersion": "{0}'i kur", + "installed": "{0} kuruldu", "moreInfo": "Daha fazla bilgi", + "otherVersions": "Diğer Sürümler", + "remove": "Kaldır", + "title": "{0} / {1}", "uninstall": "Kaldır", "uninstallMsg": "{0} kaldırılsın mı?", - "version": "Versiyon {0}" + "update": "Güncelle" }, "configuration": { "cli": { "inaccessibleDirectory": "'{0}': {1} konumundaki eskiz defterine erişilemedi" } }, + "connectionStatus": { + "connectionLost": "Bağlantı koptu. Bulut eskiz işlemleri ve güncellemeleri kullanılamayacak." + }, "contributions": { "addFile": "Dosya Ekle", "fileAdded": "Eskize bir dosya eklendi.", @@ -188,6 +202,7 @@ "copyError": "Hata mesajlarını kopyala", "noBoardSelected": "Kart seçili değil. Lütfen Araçlar > Kart menüsünden Arduino kartınızı seçin." }, + "createCloudCopy": "Eskizi Bulut'a Gönder", "daemon": { "restart": "Arthizmeti Yeniden Başlat", "start": "Arthizmeti Başlat", @@ -313,6 +328,13 @@ "tools": "Araçlar" }, "monitor": { + "alreadyConnectedError": " {0} {1} portuna bağlanılamadı. Zaten bağlı.", + "baudRate": "{0} baud", + "connectionFailedError": "{0} {1} portuna bağlanılamadı.", + "connectionFailedErrorWithDetails": "{0} {1} {2} portuna bağlanılamadı.", + "connectionTimeout": "Zaman aşımı. IDE başarılı bağlantıdan sonra ekrandan 'başarılı' mesajını almadı", + "missingConfigurationError": " {0} {1} portuna bağlanılamadı. Ekran yapılandırması eksik.", + "notConnectedError": " {0} {1} portuna bağlı değil.", "unableToCloseWebSocket": "Websocket kapatılamadı ", "unableToConnectToWebSocket": "Websocket'e bağlanılamadı" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "Otomatik Kaydırma", "carriageReturn": "Satır Başı", + "connecting": "'{1}' üzerindeki '{0}' bağlantısı kuruluyor...", "message": "Mesaj ('{0}' - '{1}''a mesaj göndermek için Enter'a basın)", "newLine": "Yeni Satır", "newLineCarriageReturn": "NL ve CR ile Birlikte", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Eskizi farklı bir konuma kaydetmeyi denemek ister misiniz?", "editInvalidSketchFolderQuestion": "Eskizi farklı bir isimle kaydetmeyi denemek ister misiniz?", "exportBinary": "Derlenmiş Dosyayı Dışa Aktar", - "invalidCloudSketchName": "İsim bir harf veya rakam ile başlamalı, harfler, rakamlar, orta çizgi, nokta veya altçizgi ile devam etmelidir. Azami uzunluk 36 karakterdir.", + "invalidCloudSketchName": "İsim bir harf, rakam veya altçizgi ile başlamalı, harfler, rakamlar, orta çizgi, nokta veya altçizgi ile devam etmelidir. Azami uzunluk 36 karakterdir.", "invalidSketchFolderLocationDetails": "Bir eskizi kendi içindeki bir klasöre kaydedemezsiniz.", "invalidSketchFolderLocationMessage": "Hatalı eskiz klasörü konumu: {0}", "invalidSketchFolderNameMessage": "Hatalı eskiz klasörü adı: {0}", - "invalidSketchName": "İsim bir harf veya rakam ile başlamalı, harfler, rakamlar, orta çizgi, nokta veya altçizgi ile devam etmelidir. Azami uzunluk 63 karakterdir.", + "invalidSketchName": "İsim bir harf, rakam veya altçizgi ile başlamalı, harfler, rakamlar, orta çizgi, nokta veya altçizgi ile devam etmelidir. Azami uzunluk 63 karakterdir.", "moving": "Taşınıyor", "movingMsg": "\"{0}\" dosyasının \"{1}\" isminde bir eskiz klasörünün içinde olması gerekiyor.\nKlasörü oluştur, dosyayı taşı ve devam et?", "new": "Yeni Eskiz", @@ -451,6 +474,17 @@ "dismissSurvey": "Tekrar gösterme", "surveyMessage": "Lütfen bu çok kısa anketi yanıtlayarak gelişmemize yardım edin. Topluluğumuza değer veriyoruz e destekçilerimizi biraz daha iyi tanımak isteriz." }, + "theme": { + "currentThemeNotFound": "Mevcut seçili tema bulunamadı: {0}. Arduino IDE kayıp olanın yerine uyumlu dahili bir tane seçti.", + "dark": "Koyu", + "deprecated": "{0} (kaldırıldı)", + "hc": "Yüksek Karşıtlık", + "light": "Açık", + "user": "{0} (kullanıcı)" + }, + "title": { + "cloud": "Bulut" + }, "updateIndexes": { "updateIndexes": "Katalogları Güncelle", "updateLibraryIndex": "Kütüphane Kataloğunu Güncelle", @@ -483,6 +517,7 @@ "couldNotSave": "Eskiz kaydedilemedi. Lütfen kaydedilmeyen işinizi favori metin düzenleyicinize kopyalayın ve IDE'yi yeniden başlatın.", "daemonOffline": "CLI Daemon Çevrimdışı", "offline": "Çevrimdışı", + "offlineText": "Çevrimdışı", "quitTitle": "Çıkmak istediğinizden emin misiniz?" }, "editor": { diff --git a/i18n/uk.json b/i18n/uk.json index 9c7ec97c1..48106a3db 100644 --- a/i18n/uk.json +++ b/i18n/uk.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "Про {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "Плата {0}", "boardConfigDialogTitle": "Оберіть іншу плату або порт", @@ -83,13 +89,12 @@ "mouseError": "'Mouse' not found. Does your sketch include the line '#include <Mouse.h>'?" }, "cloud": { - "account": "Account", "chooseSketchVisibility": "Choose visibility of your Sketch:", "cloudSketchbook": "Cloud Sketchbook", "connected": "Connected", "continue": "Продовжити", - "donePulling": "Done pulling ‘{0}’.", - "donePushing": "Done pushing ‘{0}’.", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "Embed:", "emptySketchbook": "Your Sketchbook is empty", "goToCloud": "Go to Cloud", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "Boards included in this package:", "by": "by", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "Filter your search...", "install": "Встановити", - "installed": "Встановлено ", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "Більше інформації ", + "otherVersions": "Other Versions", + "remove": "Видалити ", + "title": "{0} by {1}", "uninstall": "Видалити", "uninstallMsg": "Do you want to uninstall {0}?", - "version": "Version {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "Додати Файл", "fileAdded": "One file added to the sketch.", @@ -188,6 +202,7 @@ "copyError": "Copy error messages", "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Restart Daemon", "start": "Start Daemon", @@ -313,6 +328,13 @@ "tools": "Tools" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Unable to close websocket", "unableToConnectToWebSocket": "Unable to connect to websocket" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "Autoscroll", "carriageReturn": "Carriage Return", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Message (Enter to send message to '{0}' on '{1}')", "newLine": "Нова лінія", "newLineCarriageReturn": "Both NL & CR", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "Export Compiled Binary", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "Moving", "movingMsg": "The file \"{0}\" needs to be inside a sketch folder named \"{1}\".\nCreate this folder, move the file, and continue?", "new": "New Sketch", @@ -451,6 +474,17 @@ "dismissSurvey": "Don't show again", "surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Update Indexes", "updateLibraryIndex": "Update Library Index", @@ -483,6 +517,7 @@ "couldNotSave": "Could not save the sketch. Please copy your unsaved work into your favorite text editor, and restart the IDE.", "daemonOffline": "CLI Daemon Offline", "offline": "Offline", + "offlineText": "Offline", "quitTitle": "Are you sure you want to quit?" }, "editor": { diff --git a/i18n/vi.json b/i18n/vi.json index 9f4cea759..7b65daa25 100644 --- a/i18n/vi.json +++ b/i18n/vi.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "Về {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "Bo mạch {0}", "boardConfigDialogTitle": "Select Other Board and Port", @@ -83,13 +89,12 @@ "mouseError": "'Mouse' not found. Does your sketch include the line '#include <Mouse.h>'?" }, "cloud": { - "account": "Account", "chooseSketchVisibility": "Chọn khả năng hiển thị của Sketch của bạn:", "cloudSketchbook": "Cloud Sketchbook", "connected": "Đã kết nối", "continue": "Tiếp tục", - "donePulling": "Hoàn tất tải xuống '{0}'.", - "donePushing": "Hoàn tất đẩy lên '{0}'.", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "Nhúng: ", "emptySketchbook": "Sketchbook của bạn đang trống", "goToCloud": "Go to Cloud", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "Boards included in this package:", "by": "bởi", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "Lọc kết quả tìm kiếm của bạn...", "install": "Cài đặt", - "installed": "Installed", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "Thêm thông tin", + "otherVersions": "Other Versions", + "remove": "Loại bỏ", + "title": "{0} by {1}", "uninstall": "Gỡ cài đặt", "uninstallMsg": "Bạn có muốn gỡ cài đặt {0}?", - "version": "Phiên bản {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "Thêm tệp...", "fileAdded": "Một tệp đã được thêm vào sketch.", @@ -188,6 +202,7 @@ "copyError": "Copy error messages", "noBoardSelected": "No board selected. Please select your Arduino board from the Tools > Board menu." }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "Restart Daemon", "start": "Start Daemon", @@ -313,6 +328,13 @@ "tools": "Công cụ" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "Unable to close websocket", "unableToConnectToWebSocket": "Unable to connect to websocket" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "Tự động cuộn", "carriageReturn": "Về đầu dòng", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Message (Enter to send message to '{0}' on '{1}')", "newLine": "Dòng mới", "newLineCarriageReturn": "Vừa xuống dòng & về đầu dòng", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "Xuất tệp nhị phân đã biên dịch", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "Chuyển", "movingMsg": "Tệp \"{0}\" cần phải được chứa trong thư mục sketch tên \"{1}\".\nTạo thư mục này, chuyển tệp tin vào đó, và tiếp tục?", "new": "New Sketch", @@ -451,6 +474,17 @@ "dismissSurvey": "Don't show again", "surveyMessage": "Please help us improve by answering this super short survey. We value our community and would like to get to know our supporters a little better." }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Update Indexes", "updateLibraryIndex": "Update Library Index", @@ -483,6 +517,7 @@ "couldNotSave": "Không thể lưu sketch. Hãy sao chép tất cả những phần việc chưa được lưu lại vào trình chỉnh sửa văn bản yêu thích của bạn, và khởi động lại IDE.", "daemonOffline": "Trình chạy nền CLI ngoại tuyến", "offline": "Ngoại tuyến", + "offlineText": "Ngoại tuyến", "quitTitle": "Are you sure you want to quit?" }, "editor": { diff --git a/i18n/zh-Hant.json b/i18n/zh-Hant.json index 91ffe68e7..cff284a55 100644 --- a/i18n/zh-Hant.json +++ b/i18n/zh-Hant.json @@ -4,6 +4,12 @@ "detail": "版本: {0}\n日期: {1}{2}\n命令列版本: {3}\n\n{4}", "label": "關於 {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "{0} 開發板", "boardConfigDialogTitle": "選擇其他開發板和序列埠", @@ -83,13 +89,12 @@ "mouseError": "找不到 'Mouse', 請檢查草稿碼中是否有 '#include <Mouse.h>'?" }, "cloud": { - "account": "帳戶", "chooseSketchVisibility": "選擇草稿碼的能見度:", "cloudSketchbook": "Cloud Sketchbook", "connected": "已連線", "continue": "繼續", - "donePulling": "已完成拉取 '{0}'。", - "donePushing": "已完成推送 '{0}'。", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "嵌入:", "emptySketchbook": "您的草稿碼簿是空的", "goToCloud": "前往 Cloud", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "包含在此套件的開發版:", "by": "提供者:", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "篩選搜尋結果...", "install": "安裝", - "installed": "已安装", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "詳細資訊", + "otherVersions": "Other Versions", + "remove": "移除", + "title": "{0} by {1}", "uninstall": "移除安裝", "uninstallMsg": "你要移除 {0} 嗎?", - "version": "版本 {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "無法存取位於 '{0}' :{1} 的草稿碼簿。" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "加入檔案", "fileAdded": "已加入一個檔案到草稿碼中", @@ -188,6 +202,7 @@ "copyError": "複製錯誤訊息", "noBoardSelected": "未選取開發版。請從 工具 > 開發版 中選取您的開發版" }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "重新啟動背景服務程式", "start": "啟動背景服務程式", @@ -313,6 +328,13 @@ "tools": "工具" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "無法關閉 websocket", "unableToConnectToWebSocket": "無法連線到 websocket" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "自動捲動", "carriageReturn": "歸位", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "訊息 (按 Enter 將訊息發送連接到 {1} 的 {0})", "newLine": "換行", "newLineCarriageReturn": "換行加歸位", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "會出編譯好的二進位檔", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "移動", "movingMsg": "檔案{0}需要放在草稿碼資料夾內名稱為{1}的資料夾,\n要建立此資料夾, 搬移檔案再繼續嗎?", "new": "建立新草稿碼", @@ -451,6 +474,17 @@ "dismissSurvey": "不要再顯示", "surveyMessage": "請回答這個超簡短的問卷來幫助我們改進, 我們很重視社群,也希望能多了解我們的支持者。" }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "更新索引", "updateLibraryIndex": "更新函式庫索引", @@ -483,6 +517,7 @@ "couldNotSave": "無法儲存草稿, 請先將尚未存檔的內容複製到慣用的文字編輯器中, 再重新啟動 IDE。", "daemonOffline": "CLI 背景服務程式離線", "offline": "離線", + "offlineText": "離線", "quitTitle": "你確定要退出嗎?" }, "editor": { diff --git a/i18n/zh.json b/i18n/zh.json index 4311c2ac5..d68eff8ab 100644 --- a/i18n/zh.json +++ b/i18n/zh.json @@ -4,6 +4,12 @@ "detail": "版本:{0}\n日期:{1}{2}\nCLI 版本:{3}\n\n{4}", "label": "关于 {0}" }, + "account": { + "goToCloudEditor": "转到云编辑器", + "goToIoTCloud": "转到物联网云", + "goToProfile": "转到个人资料", + "menuTitle": "Arduino 云" + }, "board": { "board": "开发板 {0}", "boardConfigDialogTitle": "选择其他开发板和端口", @@ -46,7 +52,7 @@ }, "bootloader": { "burnBootloader": "烧录引导程序", - "burningBootloader": "正在烧录引导程序。。。", + "burningBootloader": "正在烧录引导程序…", "doneBurningBootloader": "完成烧录引导程序。" }, "burnBootloader": { @@ -83,13 +89,12 @@ "mouseError": "没有找到 ‘Mouse’,请检查您的项目是否包含 ‘#include<Mouse.h>’?" }, "cloud": { - "account": "账户", "chooseSketchVisibility": "选择项目的可见性:", "cloudSketchbook": "云项目文件夹", "connected": "已连接", "continue": "继续", - "donePulling": "已完成拉取 ‘{0}’。", - "donePushing": "已完成推送 ‘{0}’。", + "donePulling": "拉取完成 ‘{0}’。", + "donePushing": "推送完成 ‘{0}’。", "embed": "嵌入:", "emptySketchbook": "你的项目文件夹是空的", "goToCloud": "前往 Cloud", @@ -123,7 +128,7 @@ "cloudSketch": { "alreadyExists": "云端项目 '{0}' 已经存在。", "creating": "正在创建云端项目 '{0}'...", - "new": "新的云端草图", + "new": "新的云端项目", "notFound": "无法拉取云端项目 '{0}'。它并不存在。", "pulling": "正在同步远程项目文件夹,拉取“{0}”中...", "pushing": "同步项目中,正在推送 '{0}'...", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "包含在此包中的开发板:", "by": "by", - "filterSearch": "筛选搜索结果......", + "clickToOpen": "单击以在浏览器中打开:{0}", + "filterSearch": "筛选搜索结果…", "install": "安装", - "installed": "已安装", + "installLatest": "安装最新版本", + "installVersion": "安装 {0}", + "installed": "{0} 已安装", "moreInfo": "更多信息", + "otherVersions": "其他版本", + "remove": "移除", + "title": "{0} by {1}", "uninstall": "卸载", "uninstallMsg": "是否要卸载 {0}?", - "version": "版本 {0}" + "update": "更新" }, "configuration": { "cli": { "inaccessibleDirectory": "无法访问位于 ‘{0}’ 的项目文件夹:{1}。" } }, + "connectionStatus": { + "connectionLost": "连接丢失。云项目操作和更新操作将不可用。" + }, "contributions": { "addFile": "添加文件", "fileAdded": "将一个文件添加到项目中。", @@ -188,6 +202,7 @@ "copyError": "复制错误信息", "noBoardSelected": "未选择开发板。请从工具 > 板菜单中选择您的 Arduino 开发板。" }, + "createCloudCopy": "推送项目到云端", "daemon": { "restart": "重启守护进程", "start": "启动守护进程", @@ -313,6 +328,13 @@ "tools": "工具" }, "monitor": { + "alreadyConnectedError": "无法连接至 {0} {1} 端口。已有连接。", + "baudRate": "波特率 {0}", + "connectionFailedError": "无法连接至 {0} {1} 端口。", + "connectionFailedErrorWithDetails": "{0} 无法连接至 {1} {2} 端口。", + "connectionTimeout": "超时。IDE 在连接到监视器后,没有收到“成功”消息", + "missingConfigurationError": "无法连接至 {0} {1} 端口。监视器配置缺失。", + "notConnectedError": "没有连接至 {0} {1} 端口。", "unableToCloseWebSocket": "无法关闭 websocket", "unableToConnectToWebSocket": "无法连接 websocket" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "自动滚屏", "carriageReturn": "回车", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "消息(按回车将消息发送到“{1}”上的“{0}”)", "newLine": "换行", "newLineCarriageReturn": "换行 和 回车 两者都是", @@ -406,7 +429,7 @@ "archiveSketch": "项目存档", "cantOpen": "“{0}” 文件夹已存在。无法打开项目。", "close": "是否确实要关闭项目?", - "compile": "正在编译项目。。。", + "compile": "正在编译项目…", "configureAndUpload": "配置并上传", "createdArchive": "已创建存档 ‘{0}’。", "doneCompiling": "编译完成", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "你想试试把项目保存到不同的位置吗?", "editInvalidSketchFolderQuestion": "你想尝试用不同的名字保存项目吗?", "exportBinary": "导出已编译的二进制文件", - "invalidCloudSketchName": "名称必须以字母或数字开头,后面可以是字母、数字、破折号、点和下划线。最大长度为 36 个字符。", + "invalidCloudSketchName": "名称必须以字母、数字或下划线开头,后面接着字母、数字、破折号、点和下划线。最大长度为 36 个字符。", "invalidSketchFolderLocationDetails": "你不能把一个项目保存到它本身的一个文件夹里。", "invalidSketchFolderLocationMessage": "无效的项目文件夹位置: '{0}'", "invalidSketchFolderNameMessage": "无效的项目文件夹名称:'{0}'", - "invalidSketchName": "名称必须以字母或数字开头,后面可以是字母、数字、破折号、点和下划线。最大长度为 63 个字符。", + "invalidSketchName": "名称必须以字母、数字或下划线开头,后面接着字母、数字、破折号、点和下划线。最大长度为 63 个字符。", "moving": "移动", "movingMsg": "“{0}” 文件需要位于 “{1}” 项目文件夹中。\n创建此文件夹,移动文件,然后继续?", "new": "新建项目", @@ -427,9 +450,9 @@ "openRecent": "打开最近", "openSketchInNewWindow": "在新窗口打开项目", "reservedFilename": "'{0}' 是一个保留的文件名。", - "saveFolderAs": "将项目文件夹另存为。。。", + "saveFolderAs": "将项目文件夹另存为…", "saveSketch": "保存你的项目,以便以后再次打开它。", - "saveSketchAs": "将项目文件夹另存为。。。", + "saveSketchAs": "将项目文件夹另存为…", "showFolder": "显示项目文件夹", "sketch": "项目", "sketchbook": "项目文件夹", @@ -437,7 +460,7 @@ "titleSketchbook": "项目文件夹", "upload": "上传", "uploadUsingProgrammer": "使用编程器上传", - "uploading": "正在上传。。。", + "uploading": "正在上传…", "userFieldsNotFoundError": "找不到已连接开发板的用户字段", "verify": "验证", "verifyOrCompile": "验证/编译" @@ -451,6 +474,17 @@ "dismissSurvey": "不要再显示", "surveyMessage": "请回答这份很短的调查来帮助我们改进。我们重视我们的社区,也希望能够更好地了解我们的支持者。" }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "云" + }, "updateIndexes": { "updateIndexes": "更新索引", "updateLibraryIndex": "更新库索引", @@ -483,6 +517,7 @@ "couldNotSave": "无法保存项目。请将未保存的工作复制到您喜爱的文本编辑器中,然后重新启动 IDE。", "daemonOffline": "CLI 守护进程离线", "offline": "离线", + "offlineText": "离线", "quitTitle": "你确定你要退出吗?" }, "editor": { diff --git a/i18n/zh_TW.json b/i18n/zh_TW.json index fd5e14c65..f39db000d 100644 --- a/i18n/zh_TW.json +++ b/i18n/zh_TW.json @@ -4,6 +4,12 @@ "detail": "Version: {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}", "label": "關於 {0}" }, + "account": { + "goToCloudEditor": "Go to Cloud Editor", + "goToIoTCloud": "Go to IoT Cloud", + "goToProfile": "Go to Profile", + "menuTitle": "Arduino Cloud" + }, "board": { "board": "{0} 開發板", "boardConfigDialogTitle": "選擇其他開發板和埠", @@ -83,13 +89,12 @@ "mouseError": "找不到 'Mouse',請檢查項目是否包含 '#include <Mouse.h>'。" }, "cloud": { - "account": "帳戶", "chooseSketchVisibility": "選擇草稿的能見度:", "cloudSketchbook": "雲端草稿資料夾", "connected": "已連接", "continue": "繼續", - "donePulling": "完成讀取'{0}'。", - "donePushing": "完成更改'{0}'。", + "donePulling": "Done pulling '{0}'.", + "donePushing": "Done pushing '{0}'.", "embed": "嵌入:", "emptySketchbook": "您的草稿資料夾是空的", "goToCloud": "Go to Cloud", @@ -155,19 +160,28 @@ "component": { "boardsIncluded": "包含在此包的開發版:", "by": "by", + "clickToOpen": "Click to open in browser: {0}", "filterSearch": "過濾你的搜尋 ...", "install": "安裝", - "installed": "安裝", + "installLatest": "Install Latest", + "installVersion": "Install {0}", + "installed": "{0} installed", "moreInfo": "更多資訊", + "otherVersions": "Other Versions", + "remove": "移除", + "title": "{0} by {1}", "uninstall": "移除安裝", "uninstallMsg": "你要移除 {0}?", - "version": "版本 {0}" + "update": "Update" }, "configuration": { "cli": { "inaccessibleDirectory": "Could not access the sketchbook location at '{0}': {1}" } }, + "connectionStatus": { + "connectionLost": "Connection lost. Cloud sketch actions and updates won't be available." + }, "contributions": { "addFile": "加入檔案", "fileAdded": "一個檔案加入到 Sketch", @@ -188,6 +202,7 @@ "copyError": "複製錯誤訊息", "noBoardSelected": "未選擇開發版。請從 工具 > 開發版 中選擇您的開發版" }, + "createCloudCopy": "Push Sketch to Cloud", "daemon": { "restart": "重啟進程", "start": "開啟進程", @@ -313,6 +328,13 @@ "tools": "工具" }, "monitor": { + "alreadyConnectedError": "Could not connect to {0} {1} port. Already connected.", + "baudRate": "{0} baud", + "connectionFailedError": "Could not connect to {0} {1} port.", + "connectionFailedErrorWithDetails": "{0} Could not connect to {1} {2} port.", + "connectionTimeout": "Timeout. The IDE has not received the 'success' message from the monitor after successfully connecting to it", + "missingConfigurationError": "Could not connect to {0} {1} port. The monitor configuration is missing.", + "notConnectedError": "Not connected to {0} {1} port.", "unableToCloseWebSocket": "無法關閉 websocket", "unableToConnectToWebSocket": "無法連接到 websocket" }, @@ -393,6 +415,7 @@ "serial": { "autoscroll": "自動滾頁面", "carriageReturn": "回車", + "connecting": "Connecting to '{0}' on '{1}'...", "message": "Message (Enter to send message to '{0}' on '{1}')", "newLine": "換行", "newLineCarriageReturn": "兩者都是NL和CR", @@ -414,11 +437,11 @@ "editInvalidSketchFolderLocationQuestion": "Do you want to try saving the sketch to a different location?", "editInvalidSketchFolderQuestion": "Do you want to try saving the sketch with a different name?", "exportBinary": "會出已編譯的二進位檔", - "invalidCloudSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", + "invalidCloudSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 36 characters.", "invalidSketchFolderLocationDetails": "You cannot save a sketch into a folder inside itself.", "invalidSketchFolderLocationMessage": "Invalid sketch folder location: '{0}'", "invalidSketchFolderNameMessage": "Invalid sketch folder name: '{0}'", - "invalidSketchName": "The name must start with a letter or number, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", + "invalidSketchName": "The name must start with a letter, number, or underscore, followed by letters, numbers, dashes, dots and underscores. Maximum length is 63 characters.", "moving": "移動", "movingMsg": "\"{0}\"必須在命名為\"{1}\"的草稿資料夾中。建立這個資料夾,移動草稿並繼續?", "new": "New Sketch", @@ -451,6 +474,17 @@ "dismissSurvey": "不要再顯示", "surveyMessage": "請通過回答這個超簡短的調查來幫助我們改進。 我們重視我們的社群,並希望更好地了解我們的支持者。" }, + "theme": { + "currentThemeNotFound": "Could not find the currently selected theme: {0}. Arduino IDE has picked a built-in theme compatible with the missing one.", + "dark": "Dark", + "deprecated": "{0} (deprecated)", + "hc": "High Contrast", + "light": "Light", + "user": "{0} (user)" + }, + "title": { + "cloud": "Cloud" + }, "updateIndexes": { "updateIndexes": "Update Indexes", "updateLibraryIndex": "Update Library Index", @@ -483,6 +517,7 @@ "couldNotSave": "無法儲存草稿,請複製你未存檔的工作到你偏好的文字編輯器中並重新啟動 IDE 整合開發環境", "daemonOffline": "CLI 命令列常駐程式離線", "offline": "離線", + "offlineText": "離線", "quitTitle": "你確定要退出嗎?" }, "editor": { From 9fff553f1a628b6e50be8e07545ddafe33095409 Mon Sep 17 00:00:00 2001 From: Akos Kitta <a.kitta@arduino.cc> Date: Mon, 17 Apr 2023 08:32:51 +0200 Subject: [PATCH 31/32] chore: Prepared for the `2.1.0` release Signed-off-by: Akos Kitta <a.kitta@arduino.cc> --- arduino-ide-extension/package.json | 2 +- electron-app/package.json | 4 ++-- package.json | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/arduino-ide-extension/package.json b/arduino-ide-extension/package.json index 37e682b7f..9d9eb0a7b 100644 --- a/arduino-ide-extension/package.json +++ b/arduino-ide-extension/package.json @@ -1,6 +1,6 @@ { "name": "arduino-ide-extension", - "version": "2.0.5", + "version": "2.1.0", "description": "An extension for Theia building the Arduino IDE", "license": "AGPL-3.0-or-later", "scripts": { diff --git a/electron-app/package.json b/electron-app/package.json index 1ffc8860b..d7d71539a 100644 --- a/electron-app/package.json +++ b/electron-app/package.json @@ -1,7 +1,7 @@ { "private": true, "name": "electron-app", - "version": "2.0.5", + "version": "2.1.0", "license": "AGPL-3.0-or-later", "main": "src-gen/frontend/electron-main.js", "dependencies": { @@ -21,7 +21,7 @@ "@theia/process": "1.31.1", "@theia/terminal": "1.31.1", "@theia/workspace": "1.31.1", - "arduino-ide-extension": "2.0.5" + "arduino-ide-extension": "2.1.0" }, "devDependencies": { "@theia/cli": "1.31.1", diff --git a/package.json b/package.json index 2e97fea6e..6b274847a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "arduino-ide", - "version": "2.0.5", + "version": "2.1.0", "description": "Arduino IDE", "repository": "https://github.com/arduino/arduino-ide.git", "author": "Arduino SA", From 2c74ad6437429bb547934a90a1e87348b162e98d Mon Sep 17 00:00:00 2001 From: per1234 <accounts@perglass.com> Date: Tue, 18 Apr 2023 00:12:46 -0700 Subject: [PATCH 32/32] Don't upload "channel update info files" related to manual builds to S3 on release Arduino IDE offers an update to the user when a newer version is available. The availability of an update is determined by comparing the user's IDE version against data file ("channel update info file") stored on Arduino's download server. These "channel update info files" are automatically generated by the build workflow. Previously the release process was fully automated, including the upload of the "channel update info files" to the server. As a temporary workaround for limitations of the GitHub Actions runner machines used to produce the automated builds, some release builds are now produced manually: - Linux build (because the Ubuntu 18.04 runner was shut down and newer runner versions produce builds incompatible with older Linux versions) - macOS Apple Silicon build (because GitHub hosted Apple Silicon runners are not available) The automatic upload of the "channel update info files" produced by the build workflow is problematic because if users receive update offers before the "channel update info files" are updated for the manually produced builds, they can receive an update to a different build than intended: - Users of older Linux versions would update to a build that won't start on their machine - macOS Apple Silicon users would update to macOS x86 build that is less performant on their machine For this reason, the build workflow is adjusted to no longer upload the Linux and macOS "channel update info files" to the download server on release. These files will now be manually uploaded after they have been updated to provide the manually produced builds. This workaround will be reverted once a fully automated release system is regained. --- .github/workflows/build.yml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 6213a4a88..77c506bff 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -245,6 +245,15 @@ jobs: file_glob: true body: ${{ needs.changelog.outputs.BODY }} + # Temporary measure to prevent release update offers before the manually produced builds are uploaded. + # The step must be removed once fully automated builds are regained. + - name: Remove "channel update info files" related to manual builds + run: | + # See: https://github.com/arduino/arduino-ide/issues/2018 + rm "${{ env.JOB_TRANSFER_ARTIFACT }}/stable-linux.yml" + # See: https://github.com/arduino/arduino-ide/issues/408 + rm "${{ env.JOB_TRANSFER_ARTIFACT }}/stable-mac.yml" + - name: Publish Release [S3] if: github.repository == 'arduino/arduino-ide' uses: docker://plugins/s3