From 33c1b679f013617e13f586c59b9d3dc2f8ffb89a Mon Sep 17 00:00:00 2001 From: youxie <2608238945@qq.com> Date: Fri, 27 Dec 2024 10:21:11 +0800 Subject: [PATCH] two --- .eslintrc.js | 67 + .github/ISSUE_TEMPLATE/bug-report.yml | 74 + .github/ISSUE_TEMPLATE/config.yml | 19 + .github/ISSUE_TEMPLATE/feature-request.yml | 69 + .github/PULL_REQUEST_TEMPLATE.md | 18 + .github/dependabot.yml | 15 + .github/label-configuration-files/labels.yml | 27 + .github/workflows/assets/linux.Dockerfile | 112 + .github/workflows/build.yml | 641 + .github/workflows/check-certificates.yml | 173 + .github/workflows/check-containers.yml | 58 + .github/workflows/check-i18n-task.yml | 85 + .github/workflows/compose-full-changelog.yml | 55 + .github/workflows/i18n-nightly-push.yml | 46 + .github/workflows/i18n-weekly-pull.yml | 54 + .github/workflows/push-container-images.yml | 70 + .github/workflows/sync-labels.yml | 139 + .github/workflows/themes-weekly-pull.yml | 63 + .gitignore | 22 + .prettierignore | 11 + .prettierrc.json | 28 + .vscode/launch.json | 126 + .vscode/settings.json | 12 + .vscode/tasks.json | 50 + BUILDING.md | 3 + LICENSE.txt | 661 + README.md | 53 + arduino-ide-extension/README.md | 86 + arduino-ide-extension/arduino-icons.json | 1 + arduino-ide-extension/package.json | 184 + .../scripts/compose-changelog.js | 115 + arduino-ide-extension/scripts/download-cli.js | 95 + .../scripts/download-examples.js | 119 + .../scripts/download-fwuploader.js | 102 + arduino-ide-extension/scripts/download-ls.js | 158 + arduino-ide-extension/scripts/downloader.js | 126 + .../scripts/generate-protocol.js | 193 + arduino-ide-extension/scripts/utils.js | 143 + .../src/browser/app-service.ts | 16 + .../browser/arduino-frontend-contribution.tsx | 475 + .../browser/arduino-ide-frontend-module.ts | 1174 ++ .../src/browser/arduino-preferences.ts | 299 + .../auth/authentication-client-service.ts | 99 + .../src/browser/auth/cloud-user-commands.ts | 22 + .../boardImg/boardImg-widget-contribution.ts | 131 + .../src/browser/boardImg/boardImg-widget.ts | 258 + .../src/browser/boardImg/icon/diecimila.png | Bin 0 -> 96196 bytes .../src/browser/boardImg/icon/lingzhiM4.svg | 3014 ++++ .../src/browser/boardImg/icon/lingzhiMini.svg | 911 ++ .../browser/boardImg/icon/lingzhistandard.svg | 3982 +++++ .../src/browser/boardImg/icon/lz_ble52.svg | 3454 +++++ .../src/browser/boardImg/icon/lzesp32.svg | 738 + .../src/browser/boardImg/icon/lzesp8266.png | Bin 0 -> 135160 bytes .../src/browser/boardImg/icon/lzesp8266.svg | 585 + .../src/browser/boardImg/icon/mega.png | Bin 0 -> 38613 bytes .../src/browser/boardImg/icon/nano.png | Bin 0 -> 201372 bytes .../src/browser/boardImg/icon/uno.png | Bin 0 -> 157574 bytes .../src/browser/boardImg/icon/unomini.png | Bin 0 -> 55595 bytes .../src/browser/boardImg/icon/yun.png | Bin 0 -> 135160 bytes .../browser/boards/boards-auto-installer.ts | 229 + .../boards/boards-config-component.tsx | 345 + .../browser/boards/boards-config-dialog.tsx | 197 + .../src/browser/boards/boards-data-store.ts | 373 + .../src/browser/boards/boards-list-widget.ts | 91 + .../browser/boards/boards-service-provider.ts | 655 + .../browser/boards/boards-toolbar-item.tsx | 349 + .../boards-widget-frontend-contribution.ts | 40 + .../src/browser/components/ProgressBar.tsx | 28 + .../browser/config/config-service-client.ts | 103 + .../src/browser/contributions/about.ts | 184 + .../src/browser/contributions/account.ts | 148 + .../src/browser/contributions/add-file.ts | 106 + .../browser/contributions/add-zip-library.ts | 138 + .../browser/contributions/archive-sketch.ts | 72 + .../contributions/auto-select-programmer.ts | 123 + .../browser/contributions/board-selection.ts | 411 + .../contributions/boards-data-menu-updater.ts | 191 + .../browser/contributions/burn-bootloader.ts | 83 + .../contributions/check-for-ide-updates.ts | 75 + .../contributions/check-for-updates.ts | 218 + .../src/browser/contributions/close.ts | 244 + .../contributions/cloud-contribution.ts | 122 + .../browser/contributions/compiler-errors.ts | 802 + .../src/browser/contributions/contribution.ts | 360 + .../contributions/core-error-handler.ts | 32 + .../contributions/create-cloud-copy.ts | 118 + .../src/browser/contributions/daemon.ts | 41 + .../src/browser/contributions/debug.ts | 472 + .../browser/contributions/delete-sketch.ts | 159 + .../contributions/edit-contributions.ts | 262 + .../src/browser/contributions/examples.ts | 415 + .../contributions/first-startup-installer.ts | 201 + .../src/browser/contributions/format.ts | 78 + .../src/browser/contributions/help.ts | 196 + .../browser/contributions/include-library.ts | 231 + .../contributions/indexes-update-progress.ts | 75 + .../src/browser/contributions/ino-language.ts | 328 + .../browser/contributions/interface-scale.ts | 167 + .../browser/contributions/new-cloud-sketch.ts | 199 + .../src/browser/contributions/new-sketch.ts | 86 + .../contributions/open-boards-config.ts | 25 + .../contributions/open-recent-sketch.ts | 128 + .../browser/contributions/open-settings.ts | 87 + .../contributions/open-sketch-external.ts | 55 + .../contributions/open-sketch-files.ts | 239 + .../src/browser/contributions/open-sketch.ts | 260 + .../src/browser/contributions/quit-app.ts | 53 + .../contributions/rename-cloud-sketch.ts | 163 + .../browser/contributions/save-as-sketch.ts | 328 + .../src/browser/contributions/save-sketch.ts | 90 + .../browser/contributions/selected-board.ts | 118 + .../browser/contributions/sketch-control.ts | 221 + .../contributions/sketch-files-tracker.ts | 65 + .../src/browser/contributions/sketchbook.ts | 63 + .../contributions/startup-tasks-executor.ts | 65 + .../contributions/survey-notification.ts | 75 + .../contributions/update-arduino-state.ts | 184 + .../browser/contributions/update-indexes.ts | 193 + .../contributions/upload-certificate.ts | 139 + .../browser/contributions/upload-firmware.ts | 45 + .../browser/contributions/upload-sketch.ts | 310 + .../src/browser/contributions/user-fields.ts | 137 + .../browser/contributions/validate-sketch.ts | 177 + .../browser/contributions/verify-sketch.ts | 247 + .../src/browser/create/create-api.ts | 528 + .../src/browser/create/create-features.ts | 146 + .../src/browser/create/create-fs-provider.ts | 195 + .../src/browser/create/create-paths.ts | 59 + .../src/browser/create/create-uri.ts | 39 + .../src/browser/create/typings.ts | 100 + .../src/browser/data/dark.color-theme.json | 167 + .../src/browser/data/default.color-theme.json | 169 + .../src/browser/dialog-service.ts | 15 + .../dialogs/Keymaps/keymaps-dialog.tsx | 158 + .../browser/dialogs/Keymaps/open-keymaps.ts | 24 + .../certificate-add-new.tsx | 49 + .../certificate-uploader/certificate-list.tsx | 51 + .../certificate-uploader-component.tsx | 195 + .../certificate-uploader-dialog.tsx | 200 + .../select-board-components.tsx | 109 + .../dialogs/certificate-uploader/utils.ts | 38 + .../dialogs/cloud-share-sketch-dialog.tsx | 193 + .../dialogs/do-not-ask-again-dialog.ts | 73 + .../firmware-uploader-component.tsx | 243 + .../firmware-uploader-dialog.tsx | 111 + .../ide-updater/ide-updater-component.tsx | 112 + .../ide-updater/ide-updater-dialog.tsx | 252 + .../dialogs/librarys/librarys-dialog.tsx | 268 + .../browser/dialogs/librarys/open-librarys.ts | 24 + .../dialogs/settings/settings-component.tsx | 843 ++ .../dialogs/settings/settings-dialog.tsx | 224 + .../dialogs/settings/settings-step-input.tsx | 143 + .../src/browser/dialogs/settings/settings.ts | 358 + .../user-fields/user-fields-component.tsx | 106 + .../user-fields/user-fields-dialog.tsx | 86 + .../src/browser/home/home-commands.ts | 11 + .../browser/home/home-widget-contribution.ts | 42 + .../src/browser/home/home-widget.ts | 808 + .../browser/hosted/hosted-plugin-events.ts | 74 + .../browser/hosted/hosted-plugin-support.ts | 14 + .../browser/icons/arduino-cloud-download.svg | 8 + .../icons/arduino-cloud-filled-offline.svg | 4 + .../browser/icons/arduino-cloud-filled.svg | 1 + .../browser/icons/arduino-cloud-offline.svg | 4 + .../browser/icons/arduino-cloud-upload.svg | 8 + .../src/browser/icons/arduino-cloud.svg | 1 + .../src/browser/icons/buttons.svg | 869 ++ .../src/browser/icons/debug-dark.svg | 1 + .../src/browser/icons/library-tab-icon.svg | 7 + .../src/browser/icons/loading-dark.svg | 6 + .../src/browser/icons/loading-light.svg | 6 + .../src/browser/icons/mask-buttons.svg | 70 + .../src/browser/icons/monitor-tab-icon.svg | 10 + .../src/browser/icons/monitor.svg | 1 + .../src/browser/icons/plotter.svg | 1 + .../src/browser/icons/sketch-tabs-menu.svg | 5 + .../src/browser/icons/upload.svg | 60 + .../src/browser/icons/verify.svg | 67 + .../ide-updater/ide-updater-client-impl.ts | 47 + .../ide-updater/ide-updater-commands.ts | 72 + .../browser/library/library-list-widget.ts | 306 + .../library-widget-frontend-contribution.ts | 56 + .../browser/library/my-library-list-widget.ts | 668 + ...my-library-widget-frontend-contribution.ts | 17 + .../local-cache/local-cache-fs-provider.ts | 180 + .../src/browser/menu/arduino-menus.ts | 247 + .../monitor-manager-proxy-client-impl.ts | 291 + .../src/browser/monitor-model.ts | 268 + .../src/browser/notification-center.ts | 176 + .../src/browser/response-service-impl.ts | 45 + .../src/browser/selectors.ts | 22 + .../browser/serial/monitor/monitor-utils.ts | 69 + .../monitor/monitor-view-contribution.tsx | 225 + .../browser/serial/monitor/monitor-widget.tsx | 279 + .../monitor/serial-monitor-send-input.tsx | 214 + .../monitor/serial-monitor-send-output.tsx | 148 + .../plotter/plotter-frontend-contribution.ts | 149 + .../browser/sketches-service-client-impl.ts | 345 + .../src/browser/style/arduino-select.css | 53 + .../browser/style/boards-config-dialog.css | 324 + .../src/browser/style/browser-menu.css | 15 + .../style/certificate-uploader-dialog.css | 80 + .../cloud-sketchbook-tree-icon-filled.svg | 14 + .../style/cloud-sketchbook-tree-icon.svg | 3 + .../src/browser/style/cloud-sketchbook.css | 181 + .../browser/style/connected-status-icon.svg | 3 + .../src/browser/style/custom-codicon.css | 4 + .../src/browser/style/debug.css | 13 + .../src/browser/style/dialogs.css | 109 + .../src/browser/style/editor.css | 16 + .../style/firmware-uploader-dialog.css | 31 + .../src/browser/style/fonts.css | 1018 ++ .../src/browser/style/fonts/FontAwesome.svg | 209 + .../src/browser/style/fonts/FontAwesome.ttf | Bin 0 -> 45416 bytes .../src/browser/style/fonts/FontAwesome.woff | Bin 0 -> 45492 bytes .../style/fonts/OpenSans-Bold-webfont.woff | Bin 0 -> 20676 bytes .../style/fonts/OpenSans-Regular-webfont.woff | Bin 0 -> 20696 bytes .../src/browser/style/ide-logo.png | Bin 0 -> 7439 bytes .../src/browser/style/ide-updater-dialog.css | 124 + .../src/browser/style/index.css | 183 + .../src/browser/style/library-widget.css | 204 + .../src/browser/style/librarys-dialog.css | 86 + .../src/browser/style/list-widget.css | 223 + .../src/browser/style/main.css | 499 + .../src/browser/style/monitor.css | 99 + .../src/browser/style/offline-status-icon.svg | 3 + .../src/browser/style/progress-bar.css | 32 + .../src/browser/style/refresh-icon.svg | 3 + .../style/resources/fonts/icon/down.png | Bin 0 -> 18721 bytes .../style/resources/fonts/iconfont.css | 111 + .../browser/style/resources/fonts/iconfont.js | 1 + .../style/resources/fonts/iconfont.json | 177 + .../style/resources/fonts/iconfont.svg | 37 + .../style/resources/fonts/iconfont.ttf | Bin 0 -> 43196 bytes .../style/resources/fonts/iconfont.woff | Bin 0 -> 24092 bytes .../style/resources/fonts/iconfont.woff2 | Bin 0 -> 18184 bytes .../src/browser/style/settings-dialog.css | 104 + .../src/browser/style/settings-step-input.css | 50 + .../browser/style/sketchbook-opts-icon.svg | 10 + .../style/sketchbook-tree-icon-filled.svg | 1 + .../browser/style/sketchbook-tree-icon.svg | 1 + .../src/browser/style/sketchbook.css | 80 + .../src/browser/style/sketchbook.svg | 157 + .../src/browser/style/status-bar.css | 7 + .../src/browser/style/terminal.css | 3 + .../src/browser/style/user-fields-dialog.css | 32 + .../src/browser/theia/core/about-dialog.ts | 8 + .../browser/theia/core/application-shell.ts | 486 + .../browser/theia/core/browser-menu-plugin.ts | 11 + .../core/common-frontend-contribution.ts | 100 + .../theia/core/connection-status-service.ts | 334 + .../theia/core/frontend-application.ts | 84 + .../browser/theia/core/json-schema-store.ts | 11 + .../theia/core/shell-layout-restorer.ts | 259 + .../core/sidebar-bottom-menu-widget copy.tsx | 91 + .../theia/core/sidebar-bottom-menu-widget.tsx | 123 + .../browser/theia/core/tab-bar-decorator.ts | 48 + .../src/browser/theia/core/tab-bars.ts | 124 + .../src/browser/theia/core/theming.ts | 198 + .../src/browser/theia/core/widget-manager.ts | 80 + .../browser/theia/core/window-contribution.ts | 15 + .../browser/theia/core/window-service-ext.ts | 11 + .../theia/core/window-title-updater.ts | 148 + .../debug/debug-configuration-manager.ts | 156 + .../theia/debug/debug-configuration-model.ts | 55 + .../debug/debug-configuration-widget.tsx | 76 + ...debug-frontend-application-contribution.ts | 37 + .../theia/debug/debug-session-contribution.ts | 50 + .../theia/debug/debug-session-manager.ts | 39 + .../src/browser/theia/debug/debug-session.ts | 12 + .../src/browser/theia/debug/debug-widget.ts | 71 + .../src/browser/theia/dialogs/dialogs.tsx | 45 + .../theia/dialogs/theiaDialogs/dialogs.ts | 579 + .../dialogs/theiaDialogs/react-dialog.tsx | 60 + .../src/browser/theia/dialogs/widgets.ts | 51 + .../browser/theia/editor/editor-command.ts | 21 + .../theia/editor/editor-contribution.ts | 39 + .../src/browser/theia/editor/editor-file.ts | 41 + .../browser/theia/editor/editor-manager.ts | 9 + .../editor/editor-navigation-contribution.ts | 11 + .../theia/editor/editor-widget-factory.ts | 68 + .../browser/theia/filesystem/file-resource.ts | 116 + .../filesystem-watcher-error-handler.ts | 28 + .../keymaps/keymaps-frontend-contribution.ts | 47 + .../theia/keymaps/keymaps-frontend-widget.tsx | 97 + .../theia/markers/problem-contribution.ts | 25 + .../browser/theia/markers/problem-manager.ts | 61 + .../notification-center-component.tsx | 48 + .../theia/messages/notification-component.tsx | 107 + .../notification-toasts-component.tsx | 25 + .../messages/notifications-contribution.ts | 16 + .../theia/messages/notifications-manager.ts | 48 + .../theia/messages/notifications-renderer.tsx | 37 + .../theia/monaco/monaco-editor-provider.ts | 133 + .../monaco/monaco-formatting-conflicts.ts | 12 + .../src/browser/theia/monaco/monaco-menu.ts | 135 + .../monaco/monaco-status-bar-contribution.ts | 9 + .../theia/monaco/monaco-text-model-service.ts | 84 + .../theia/monaco/monaco-theming-service.ts | 231 + .../theia/navigator/navigator-contribution.ts | 46 + .../navigator/navigator-tab-bar-decorator.ts | 19 + .../browser/theia/out-put/out-put-widget.ts | 10 + .../theia/out-put/output-contribution.ts | 28 + .../theia/outline/outline-contribution.ts | 18 + .../browser/theia/output/output-channel.ts | 62 + .../theia/output/output-editor-factory.ts | 24 + .../output/output-toolbar-contribution.ts | 49 + .../browser/theia/plugin-ext/hosted-plugin.ts | 72 + .../output-channel-registry-main.ts | 46 + .../preferences/preference-editor-widget.ts | 19 + .../preferences/preference-tree-generator.ts | 44 + .../preferences/preferences-contribution.ts | 22 + .../src/browser/theia/scm/scm-contribution.ts | 17 + .../search-in-workspace-factory.ts | 19 + ...arch-in-workspace-frontend-contribution.ts | 147 + .../search-in-workspace-widget.tsx | 189 + .../terminal-frontend-contribution.ts | 16 + .../type-hierarchy-contribution.ts | 32 + .../typehierarchy/type-hierarchy-service.ts | 9 + .../theia/workspace/workspace-commands.ts | 483 + .../workspace/workspace-delete-handler.ts | 81 + .../workspace-frontend-contribution.ts | 50 + .../theia/workspace/workspace-input-dialog.ts | 206 + .../theia/workspace/workspace-service.ts | 198 + .../workspace-variable-contribution.ts | 49 + .../toolbar/arduino-toolbar-contribution.ts | 80 + .../src/browser/toolbar/arduino-toolbar.tsx | 254 + .../src/browser/toolbar/icon/close_normal.png | Bin 0 -> 1872 bytes .../src/browser/toolbar/icon/icon.ico | Bin 0 -> 58510 bytes .../src/browser/toolbar/icon/max_normal.png | Bin 0 -> 16619 bytes .../src/browser/toolbar/icon/menu_normal.png | Bin 0 -> 1515 bytes .../src/browser/toolbar/icon/min_normal.png | Bin 0 -> 16092 bytes .../src/browser/utils/constants.ts | 2 + .../src/browser/utils/dom.ts | 69 + .../src/browser/utils/window.ts | 7 + .../src/browser/widgets/arduino-select.tsx | 62 + .../widgets/cloud-sketchbook/README.md | 1 + .../cloud-sketchbook/cloud-sketch-cache.ts | 57 + .../cloud-sketchbook-commands.ts | 88 + .../cloud-sketchbook-composite-widget.tsx | 79 + .../cloud-sketchbook-contributions.ts | 404 + .../cloud-sketchbook-tree-container.ts | 29 + .../cloud-sketchbook-tree-model.ts | 196 + .../cloud-sketchbook-tree-widget.tsx | 195 + .../cloud-sketchbook/cloud-sketchbook-tree.ts | 711 + .../cloud-sketchbook-widget.ts | 76 + .../widgets/cloud-sketchbook/cloud-status.tsx | 99 + .../component-list/component-list-item.tsx | 96 + .../widgets/component-list/component-list.tsx | 46 + .../component-list/filter-renderer.tsx | 121 + .../filterable-list-container.tsx | 269 + .../component-list/list-item-renderer.tsx | 783 + .../list-widget-frontend-contribution.ts | 78 + .../widgets/component-list/list-widget.tsx | 201 + .../widgets/component-list/search-bar.tsx | 50 + .../browser/widgets/sketchbook/create-new.tsx | 20 + .../widgets/sketchbook/sketchbook-commands.ts | 40 + .../sketchbook-composite-widget.tsx | 122 + .../sketchbook/sketchbook-tree-container.ts | 42 + .../sketchbook/sketchbook-tree-model.ts | 340 + .../sketchbook/sketchbook-tree-widget.tsx | 238 + .../widgets/sketchbook/sketchbook-tree.ts | 120 + .../sketchbook-widget-contribution.ts | 352 + .../widgets/sketchbook/sketchbook-widget.tsx | 560 + .../src/common/decorators.ts | 64 + .../src/common/main-menu-manager.ts | 8 + arduino-ide-extension/src/common/nls.ts | 32 + .../src/common/protocol/arduino-component.ts | 35 + .../common/protocol/arduino-context-mapper.ts | 126 + .../src/common/protocol/arduino-daemon.ts | 18 + .../protocol/arduino-firmware-uploader.ts | 24 + .../common/protocol/authentication-service.ts | 41 + .../src/common/protocol/board-list.ts | 707 + .../src/common/protocol/boards-service.ts | 970 ++ .../src/common/protocol/config-service.ts | 186 + .../src/common/protocol/core-service.ts | 230 + .../src/common/protocol/examples-service.ts | 16 + .../src/common/protocol/executable-service.ts | 9 + .../src/common/protocol/filesystem-ext.ts | 5 + .../src/common/protocol/formatter.ts | 23 + .../src/common/protocol/ide-updater.ts | 73 + .../src/common/protocol/index.ts | 15 + .../src/common/protocol/installable.ts | 195 + .../src/common/protocol/library-service.ts | 297 + .../src/common/protocol/monitor-service.ts | 257 + .../common/protocol/notification-service.ts | 83 + .../src/common/protocol/progressible.ts | 60 + .../src/common/protocol/response-service.ts | 50 + .../src/common/protocol/searchable.ts | 62 + .../src/common/protocol/sketches-service.ts | 481 + .../src/common/protocol/survey-service.ts | 7 + arduino-ide-extension/src/common/types.ts | 7 + arduino-ide-extension/src/common/utils.ts | 40 + .../electron-browser/electron-app-service.ts | 26 + .../electron-arduino-module.ts | 12 + .../electron-dialog-service.ts | 25 + .../src/electron-browser/preload.ts | 159 + .../core/electron-context-menu-renderer.ts | 55 + .../theia/core/electron-main-menu-factory.ts | 377 + .../theia/core/electron-menu-contribution.ts | 66 + .../theia/core/electron-menu-module.ts | 22 + .../theia/core/electron-window-module.ts | 10 + .../theia/core/electron-window-service.ts | 60 + .../src/electron-common/electron-arduino.ts | 107 + .../src/electron-common/startup-task.ts | 54 + .../arduino-electron-main-module.ts | 66 + .../src/electron-main/electron-arduino.ts | 212 + .../src/electron-main/fix-app-image-icon.ts | 34 + .../ide-updater/ide-updater-impl.ts | 185 + .../theia/electron-main-application.ts | 907 ++ .../theia/electron-main-window-service.ts | 50 + .../src/electron-main/theia/theia-api-main.ts | 263 + .../theia/theia-electron-window.ts | 52 + .../src/node/arduino-daemon-impl.ts | 314 + .../node/arduino-firmware-uploader-impl.ts | 94 + .../src/node/arduino-ide-backend-module.ts | 422 + .../src/node/auth/arduino-auth-provider.ts | 336 + .../src/node/auth/authentication-server.ts | 67 + .../node/auth/authentication-service-impl.ts | 93 + arduino-ide-extension/src/node/auth/body.ts | 134 + .../src/node/auth/keychain.ts | 85 + arduino-ide-extension/src/node/auth/types.ts | 19 + arduino-ide-extension/src/node/auth/utils.ts | 112 + .../src/node/board-discovery.ts | 331 + .../src/node/boards-service-impl.ts | 815 + .../src/node/clang-formatter.ts | 140 + arduino-ide-extension/src/node/cli-config.ts | 116 + .../src/node/cli-error-parser.ts | 228 + .../arduino/cli/commands/v1/board_grpc_pb.js | 1 + .../cc/arduino/cli/commands/v1/board_pb.d.ts | 618 + .../cc/arduino/cli/commands/v1/board_pb.js | 5127 +++++++ .../cli/commands/v1/commands_grpc_pb.d.ts | 707 + .../cli/commands/v1/commands_grpc_pb.js | 1474 ++ .../arduino/cli/commands/v1/commands_pb.d.ts | 612 + .../cc/arduino/cli/commands/v1/commands_pb.js | 4632 ++++++ .../arduino/cli/commands/v1/common_grpc_pb.js | 1 + .../cc/arduino/cli/commands/v1/common_pb.d.ts | 374 + .../cc/arduino/cli/commands/v1/common_pb.js | 2972 ++++ .../cli/commands/v1/compile_grpc_pb.js | 1 + .../arduino/cli/commands/v1/compile_pb.d.ts | 205 + .../cc/arduino/cli/commands/v1/compile_pb.js | 1798 +++ .../arduino/cli/commands/v1/core_grpc_pb.js | 1 + .../cc/arduino/cli/commands/v1/core_pb.d.ts | 394 + .../cc/arduino/cli/commands/v1/core_pb.js | 3119 ++++ .../arduino/cli/commands/v1/debug_grpc_pb.js | 1 + .../cc/arduino/cli/commands/v1/debug_pb.d.ts | 274 + .../cc/arduino/cli/commands/v1/debug_pb.js | 2221 +++ .../cc/arduino/cli/commands/v1/lib_grpc_pb.js | 1 + .../cc/arduino/cli/commands/v1/lib_pb.d.ts | 901 ++ .../cc/arduino/cli/commands/v1/lib_pb.js | 7248 +++++++++ .../cli/commands/v1/monitor_grpc_pb.js | 1 + .../arduino/cli/commands/v1/monitor_pb.d.ts | 215 + .../cc/arduino/cli/commands/v1/monitor_pb.js | 1760 +++ .../arduino/cli/commands/v1/port_grpc_pb.js | 1 + .../cc/arduino/cli/commands/v1/port_pb.d.ts | 44 + .../cc/arduino/cli/commands/v1/port_pb.js | 329 + .../arduino/cli/commands/v1/upload_grpc_pb.js | 1 + .../cc/arduino/cli/commands/v1/upload_pb.d.ts | 445 + .../cc/arduino/cli/commands/v1/upload_pb.js | 3572 +++++ .../cli/settings/v1/settings_grpc_pb.d.ts | 126 + .../cli/settings/v1/settings_grpc_pb.js | 231 + .../arduino/cli/settings/v1/settings_pb.d.ts | 238 + .../cc/arduino/cli/settings/v1/settings_pb.js | 1763 +++ .../cli-protocol/google/rpc/status_grpc_pb.js | 1 + .../cli-protocol/google/rpc/status_pb.d.ts | 36 + .../node/cli-protocol/google/rpc/status_pb.js | 268 + .../src/node/config-service-impl.ts | 451 + .../src/node/core-client-provider.ts | 564 + .../src/node/core-service-impl.ts | 773 + .../src/node/default-formatter-config.json | 193 + .../src/node/examples-service-impl.ts | 227 + arduino-ide-extension/src/node/exec-util.ts | 52 + .../src/node/executable-service-impl.ts | 23 + .../src/node/grpc-progressible.ts | 434 + .../i18n/arduino-localization-contribution.ts | 58 + .../src/node/is-temp-sketch.ts | 47 + .../src/node/library-service-impl.ts | 934 ++ .../src/node/monitor-manager-proxy-impl.ts | 100 + .../src/node/monitor-manager.ts | 362 + .../src/node/monitor-service-factory.ts | 16 + .../src/node/monitor-service.ts | 781 + .../monitor-settings-provider-impl.ts | 134 + .../monitor-settings-provider.ts | 13 + .../monitor-settings-utils.ts | 81 + .../src/node/node-filesystem-ext.ts | 10 + .../src/node/notification-service-server.ts | 109 + .../plotter/plotter-backend-contribution.ts | 23 + arduino-ide-extension/src/node/resources.ts | 33 + .../src/node/service-error.ts | 26 + .../src/node/settings-reader.ts | 67 + .../src/node/sketches-service-impl.ts | 986 ++ .../src/node/survey-service-impl.ts | 20 + .../node/theia/core/backend-application.ts | 26 + .../node/theia/core/messaging-contribution.ts | 11 + .../env-variables/env-variables-server.ts | 253 + .../node/theia/filesystem/nsfw-bindings.ts | 42 + .../theia/filesystem/nsfw-watcher/index.ts | 31 + .../nsfw-watcher/nsfw-filesystem-service.ts | 32 + .../hosted-plugin-localization-service.ts | 13 + .../node/theia/plugin-ext/plugin-deployer.ts | 100 + .../node/theia/plugin-ext/plugin-reader.ts | 104 + .../workspace/default-workspace-server.ts | 56 + .../src/node/utils/buffers.ts | 100 + .../src/node/utils/errors.ts | 54 + .../web-socket/web-socket-provider-impl.ts | 56 + .../node/web-socket/web-socket-provider.ts | 11 + .../browser/auto-select-programmer.test.ts | 176 + .../browser/board-service-provider.test.ts | 420 + .../test/browser/boards-data-store.test.ts | 681 + .../src/test/browser/browser-test-bindings.ts | 112 + .../browser/connection-status-service.test.ts | 62 + .../src/test/browser/create-api.slow-test.ts | 484 + .../src/test/browser/debug.test.ts | 378 + .../src/test/browser/dom.test.ts | 52 + .../src/test/browser/fixtures/boards.ts | 53 + .../src/test/browser/monitor-utils.test.ts | 171 + .../src/test/browser/theming.test.ts | 189 + .../test/browser/update-arduino-state.test.ts | 634 + .../src/test/browser/widgets.test.ts | 121 + .../test/browser/workspace-commands.test.ts | 221 + .../common/arduino-context-mapper.test.ts | 43 + .../src/test/common/board-list.test.ts | 718 + .../src/test/common/boards-service.test.ts | 237 + .../src/test/common/common-test-bindings.ts | 108 + .../src/test/common/config-service.test.ts | 35 + .../src/test/common/fixtures.ts | 176 + .../src/test/common/installable.test.ts | 141 + .../src/test/common/searchable.test.ts | 136 + .../src/test/common/sketches-service.test.ts | 205 + .../__test_sketchbook__/a_sketch/a_sketch.ino | 0 .../__test_sketchbook__/bar++ 2/bar++ 2.ino | 0 .../node/__test_sketchbook__/bar++/bar++.ino | 0 .../__test_sketchbook__/bar++/foo++/foo++.ino | 0 .../node/__test_sketchbook__/defaultIno.ino | 0 .../node/__test_sketchbook__/empty/.gitkeep | 0 .../examples/Ethernet/Example_1/Example_1.ino | 0 .../examples/WiFi/Example_2/Example_2.ino | 0 .../mismatchingName/MismatchingName.ino | 0 .../nested_3/nested_2/nested_1/nested_1.ino | 0 .../nested_4/nested_3/nested_2/nested_2.ino | 0 .../project1/CodeA/version1A/version1A.ino | 0 .../project1/CodeA/version2A/version2A.ino | 0 .../project1/CodeB/version1B/version1B.ino | 0 .../project1/CodeB/version2B/version2B.pde | 0 .../src/test/node/arduino-daemon-impl.test.ts | 85 + .../node/boards-service-impl.slow-test.ts | 101 + .../src/test/node/clang-formatter.test.ts | 162 + .../src/test/node/cli-config.test.ts | 49 + .../node/core-client-provider.slow-test.ts | 341 + .../test/node/core-service-impl.slow-test.ts | 125 + .../src/test/node/core-service-impl.test.ts | 55 + .../src/test/node/exec-util.test.ts | 165 + .../node/library-service-impl.slow-test.ts | 78 + .../test/node/monitor-settings-utils.test.ts | 193 + .../src/test/node/node-test-bindings.ts | 327 + .../src/test/node/settings.reader.test.ts | 45 + .../node/sketches-service-impl.slow-test.ts | 565 + .../test/node/sketches-service-impl.test.ts | 174 + arduino-ide-extension/src/test/utils.ts | 6 + arduino-ide-extension/tsconfig.json | 31 + docs/CONTRIBUTING.md | 29 + docs/README.md | 47 + docs/advanced-usage.md | 68 + docs/assets/preferences.png | Bin 0 -> 85288 bytes docs/assets/remote.png | Bin 0 -> 100086 bytes docs/contributor-guide/assets/checks-tab.png | Bin 0 -> 42700 bytes docs/contributor-guide/assets/checks.png | Bin 0 -> 40075 bytes .../assets/tester-build-artifacts.png | Bin 0 -> 17208 bytes .../assets/tester-build-link.png | Bin 0 -> 20961 bytes docs/contributor-guide/beta-testing.md | 108 + docs/contributor-guide/issues.md | 33 + docs/contributor-guide/pull-requests.md | 199 + docs/contributor-guide/translation.md | 33 + docs/development.md | 204 + docs/internal/Ubuntu.md | 37 + docs/internal/release-procedure.md | 176 + electron-app/arduino-ide-backend-main.js | 17 + electron-app/arduino-ide-electron-main.js | 23 + electron-app/lingzhi-backend-main.js | 17 + electron-app/lingzhi-electron-main.js | 23 + .../ctags-5.8-arduino11-pm-i686-mingw32.zip | Bin 0 -> 116455 bytes .../dfu-discovery_v0.1.2_Windows_64bit.zip | Bin 0 -> 2282491 bytes .../mdns-discovery_v1.0.9_Windows_64bit.zip | Bin 0 -> 2633749 bytes .../serial-discovery_v1.4.1_Windows_64bit.zip | Bin 0 -> 1924625 bytes .../serial-monitor_v0.14.1_Windows_64bit.zip | Bin 0 -> 2263204 bytes electron-app/package.json | 236 + electron-app/resources/akte3-p5rt0.svg | 76 + electron-app/resources/entitlements.mac.plist | 14 + electron-app/resources/eula.txt | 12 + electron-app/resources/icon.icns | Bin 0 -> 366131 bytes electron-app/resources/icon.ico | Bin 0 -> 58510 bytes electron-app/resources/icons/512x512.png | Bin 0 -> 46413 bytes electron-app/resources/installerSidebar.bmp | Bin 0 -> 144390 bytes electron-app/resources/logoR.ico | Bin 0 -> 8515 bytes electron-app/resources/preload.html | 80 + electron-app/scripts/archive.js | 135 + electron-app/scripts/notarize.js | 46 + electron-app/scripts/package.js | 166 + electron-app/scripts/post-package.js | 186 + electron-app/scripts/utils.js | 8 + electron-app/test/archive.test.js | 158 + .../test/test-resources/not-a-zip.dmg | Bin 0 -> 8380416 bytes .../test-resources/zip with whitespace.zip | Bin 0 -> 1425 bytes .../test-resources/zip-with-base-folder.zip | Bin 0 -> 3136 bytes .../test/test-resources/zip-with-symlink.zip | Bin 0 -> 729 bytes .../test-resources/zip-without-symlink.zip | Bin 0 -> 1425 bytes electron-app/webpack.base.js | 104 + electron-app/webpack.config.js | 53 + electron-app/webpack.dev.js | 22 + i18n/README.md | 11 + i18n/af.json | 551 + i18n/ar.json | 551 + i18n/az.json | 551 + i18n/bg.json | 551 + i18n/ca_ES.json | 551 + i18n/cs.json | 551 + i18n/de.json | 551 + i18n/el.json | 551 + i18n/en.json | 554 + i18n/es.json | 551 + i18n/eu.json | 551 + i18n/fa.json | 551 + i18n/fil.json | 551 + i18n/fr.json | 551 + i18n/he.json | 551 + i18n/hu.json | 551 + i18n/id.json | 551 + i18n/it.json | 551 + i18n/ja.json | 551 + i18n/ko.json | 551 + i18n/my_MM.json | 551 + i18n/ne.json | 551 + i18n/nl.json | 551 + i18n/pl.json | 551 + i18n/pt.json | 551 + i18n/ro.json | 551 + i18n/ru.json | 551 + i18n/sr.json | 551 + i18n/th.json | 551 + i18n/tr.json | 551 + i18n/uk.json | 551 + i18n/vi.json | 551 + i18n/zh-Hant.json | 551 + i18n/zh.json | 555 + i18n/zh_TW.json | 551 + lerna.json | 10 + package.json | 82 + scripts/i18n/transifex-pull.js | 160 + scripts/i18n/transifex-push.js | 95 + scripts/i18n/transifex.js | 51 + scripts/merge-channel-files.js | 73 + scripts/package.sh | 12 + scripts/sort-dependencies | 26 + scripts/themes/theme-generator.js | 112 + scripts/themes/theme-tokens-pull.js | 34 + scripts/update-version.js | 59 + static/screenshot.png | Bin 0 -> 116768 bytes webpack.config.js | 21 + yarn.lock | 12457 ++++++++++++++++ 659 files changed, 161725 insertions(+) create mode 100644 .eslintrc.js create mode 100644 .github/ISSUE_TEMPLATE/bug-report.yml create mode 100644 .github/ISSUE_TEMPLATE/config.yml create mode 100644 .github/ISSUE_TEMPLATE/feature-request.yml create mode 100644 .github/PULL_REQUEST_TEMPLATE.md create mode 100644 .github/dependabot.yml create mode 100644 .github/label-configuration-files/labels.yml create mode 100644 .github/workflows/assets/linux.Dockerfile create mode 100644 .github/workflows/build.yml create mode 100644 .github/workflows/check-certificates.yml create mode 100644 .github/workflows/check-containers.yml create mode 100644 .github/workflows/check-i18n-task.yml create mode 100644 .github/workflows/compose-full-changelog.yml create mode 100644 .github/workflows/i18n-nightly-push.yml create mode 100644 .github/workflows/i18n-weekly-pull.yml create mode 100644 .github/workflows/push-container-images.yml create mode 100644 .github/workflows/sync-labels.yml create mode 100644 .github/workflows/themes-weekly-pull.yml create mode 100644 .gitignore create mode 100644 .prettierignore create mode 100644 .prettierrc.json create mode 100644 .vscode/launch.json create mode 100644 .vscode/settings.json create mode 100644 .vscode/tasks.json create mode 100644 BUILDING.md create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 arduino-ide-extension/README.md create mode 100644 arduino-ide-extension/arduino-icons.json create mode 100644 arduino-ide-extension/package.json create mode 100644 arduino-ide-extension/scripts/compose-changelog.js create mode 100644 arduino-ide-extension/scripts/download-cli.js create mode 100644 arduino-ide-extension/scripts/download-examples.js create mode 100644 arduino-ide-extension/scripts/download-fwuploader.js create mode 100644 arduino-ide-extension/scripts/download-ls.js create mode 100644 arduino-ide-extension/scripts/downloader.js create mode 100644 arduino-ide-extension/scripts/generate-protocol.js create mode 100644 arduino-ide-extension/scripts/utils.js create mode 100644 arduino-ide-extension/src/browser/app-service.ts create mode 100644 arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx create mode 100644 arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts create mode 100644 arduino-ide-extension/src/browser/arduino-preferences.ts create mode 100644 arduino-ide-extension/src/browser/auth/authentication-client-service.ts create mode 100644 arduino-ide-extension/src/browser/auth/cloud-user-commands.ts create mode 100644 arduino-ide-extension/src/browser/boardImg/boardImg-widget-contribution.ts create mode 100644 arduino-ide-extension/src/browser/boardImg/boardImg-widget.ts create mode 100644 arduino-ide-extension/src/browser/boardImg/icon/diecimila.png create mode 100644 arduino-ide-extension/src/browser/boardImg/icon/lingzhiM4.svg create mode 100644 arduino-ide-extension/src/browser/boardImg/icon/lingzhiMini.svg create mode 100644 arduino-ide-extension/src/browser/boardImg/icon/lingzhistandard.svg create mode 100644 arduino-ide-extension/src/browser/boardImg/icon/lz_ble52.svg create mode 100644 arduino-ide-extension/src/browser/boardImg/icon/lzesp32.svg create mode 100644 arduino-ide-extension/src/browser/boardImg/icon/lzesp8266.png create mode 100644 arduino-ide-extension/src/browser/boardImg/icon/lzesp8266.svg create mode 100644 arduino-ide-extension/src/browser/boardImg/icon/mega.png create mode 100644 arduino-ide-extension/src/browser/boardImg/icon/nano.png create mode 100644 arduino-ide-extension/src/browser/boardImg/icon/uno.png create mode 100644 arduino-ide-extension/src/browser/boardImg/icon/unomini.png create mode 100644 arduino-ide-extension/src/browser/boardImg/icon/yun.png create mode 100644 arduino-ide-extension/src/browser/boards/boards-auto-installer.ts create mode 100644 arduino-ide-extension/src/browser/boards/boards-config-component.tsx create mode 100644 arduino-ide-extension/src/browser/boards/boards-config-dialog.tsx create mode 100644 arduino-ide-extension/src/browser/boards/boards-data-store.ts create mode 100644 arduino-ide-extension/src/browser/boards/boards-list-widget.ts create mode 100644 arduino-ide-extension/src/browser/boards/boards-service-provider.ts create mode 100644 arduino-ide-extension/src/browser/boards/boards-toolbar-item.tsx create mode 100644 arduino-ide-extension/src/browser/boards/boards-widget-frontend-contribution.ts create mode 100644 arduino-ide-extension/src/browser/components/ProgressBar.tsx create mode 100644 arduino-ide-extension/src/browser/config/config-service-client.ts create mode 100644 arduino-ide-extension/src/browser/contributions/about.ts create mode 100644 arduino-ide-extension/src/browser/contributions/account.ts create mode 100644 arduino-ide-extension/src/browser/contributions/add-file.ts create mode 100644 arduino-ide-extension/src/browser/contributions/add-zip-library.ts create mode 100644 arduino-ide-extension/src/browser/contributions/archive-sketch.ts create mode 100644 arduino-ide-extension/src/browser/contributions/auto-select-programmer.ts create mode 100644 arduino-ide-extension/src/browser/contributions/board-selection.ts create mode 100644 arduino-ide-extension/src/browser/contributions/boards-data-menu-updater.ts create mode 100644 arduino-ide-extension/src/browser/contributions/burn-bootloader.ts create mode 100644 arduino-ide-extension/src/browser/contributions/check-for-ide-updates.ts create mode 100644 arduino-ide-extension/src/browser/contributions/check-for-updates.ts create mode 100644 arduino-ide-extension/src/browser/contributions/close.ts create mode 100644 arduino-ide-extension/src/browser/contributions/cloud-contribution.ts create mode 100644 arduino-ide-extension/src/browser/contributions/compiler-errors.ts create mode 100644 arduino-ide-extension/src/browser/contributions/contribution.ts create mode 100644 arduino-ide-extension/src/browser/contributions/core-error-handler.ts create mode 100644 arduino-ide-extension/src/browser/contributions/create-cloud-copy.ts create mode 100644 arduino-ide-extension/src/browser/contributions/daemon.ts create mode 100644 arduino-ide-extension/src/browser/contributions/debug.ts create mode 100644 arduino-ide-extension/src/browser/contributions/delete-sketch.ts create mode 100644 arduino-ide-extension/src/browser/contributions/edit-contributions.ts create mode 100644 arduino-ide-extension/src/browser/contributions/examples.ts create mode 100644 arduino-ide-extension/src/browser/contributions/first-startup-installer.ts create mode 100644 arduino-ide-extension/src/browser/contributions/format.ts create mode 100644 arduino-ide-extension/src/browser/contributions/help.ts create mode 100644 arduino-ide-extension/src/browser/contributions/include-library.ts create mode 100644 arduino-ide-extension/src/browser/contributions/indexes-update-progress.ts create mode 100644 arduino-ide-extension/src/browser/contributions/ino-language.ts create mode 100644 arduino-ide-extension/src/browser/contributions/interface-scale.ts create mode 100644 arduino-ide-extension/src/browser/contributions/new-cloud-sketch.ts create mode 100644 arduino-ide-extension/src/browser/contributions/new-sketch.ts create mode 100644 arduino-ide-extension/src/browser/contributions/open-boards-config.ts create mode 100644 arduino-ide-extension/src/browser/contributions/open-recent-sketch.ts create mode 100644 arduino-ide-extension/src/browser/contributions/open-settings.ts create mode 100644 arduino-ide-extension/src/browser/contributions/open-sketch-external.ts create mode 100644 arduino-ide-extension/src/browser/contributions/open-sketch-files.ts create mode 100644 arduino-ide-extension/src/browser/contributions/open-sketch.ts create mode 100644 arduino-ide-extension/src/browser/contributions/quit-app.ts create mode 100644 arduino-ide-extension/src/browser/contributions/rename-cloud-sketch.ts create mode 100644 arduino-ide-extension/src/browser/contributions/save-as-sketch.ts create mode 100644 arduino-ide-extension/src/browser/contributions/save-sketch.ts create mode 100644 arduino-ide-extension/src/browser/contributions/selected-board.ts create mode 100644 arduino-ide-extension/src/browser/contributions/sketch-control.ts create mode 100644 arduino-ide-extension/src/browser/contributions/sketch-files-tracker.ts create mode 100644 arduino-ide-extension/src/browser/contributions/sketchbook.ts create mode 100644 arduino-ide-extension/src/browser/contributions/startup-tasks-executor.ts create mode 100644 arduino-ide-extension/src/browser/contributions/survey-notification.ts create mode 100644 arduino-ide-extension/src/browser/contributions/update-arduino-state.ts create mode 100644 arduino-ide-extension/src/browser/contributions/update-indexes.ts create mode 100644 arduino-ide-extension/src/browser/contributions/upload-certificate.ts create mode 100644 arduino-ide-extension/src/browser/contributions/upload-firmware.ts create mode 100644 arduino-ide-extension/src/browser/contributions/upload-sketch.ts create mode 100644 arduino-ide-extension/src/browser/contributions/user-fields.ts create mode 100644 arduino-ide-extension/src/browser/contributions/validate-sketch.ts create mode 100644 arduino-ide-extension/src/browser/contributions/verify-sketch.ts create mode 100644 arduino-ide-extension/src/browser/create/create-api.ts create mode 100644 arduino-ide-extension/src/browser/create/create-features.ts create mode 100644 arduino-ide-extension/src/browser/create/create-fs-provider.ts create mode 100644 arduino-ide-extension/src/browser/create/create-paths.ts create mode 100644 arduino-ide-extension/src/browser/create/create-uri.ts create mode 100644 arduino-ide-extension/src/browser/create/typings.ts create mode 100644 arduino-ide-extension/src/browser/data/dark.color-theme.json create mode 100644 arduino-ide-extension/src/browser/data/default.color-theme.json create mode 100644 arduino-ide-extension/src/browser/dialog-service.ts create mode 100644 arduino-ide-extension/src/browser/dialogs/Keymaps/keymaps-dialog.tsx create mode 100644 arduino-ide-extension/src/browser/dialogs/Keymaps/open-keymaps.ts create mode 100644 arduino-ide-extension/src/browser/dialogs/certificate-uploader/certificate-add-new.tsx create mode 100644 arduino-ide-extension/src/browser/dialogs/certificate-uploader/certificate-list.tsx create mode 100644 arduino-ide-extension/src/browser/dialogs/certificate-uploader/certificate-uploader-component.tsx create mode 100644 arduino-ide-extension/src/browser/dialogs/certificate-uploader/certificate-uploader-dialog.tsx create mode 100644 arduino-ide-extension/src/browser/dialogs/certificate-uploader/select-board-components.tsx create mode 100644 arduino-ide-extension/src/browser/dialogs/certificate-uploader/utils.ts create mode 100644 arduino-ide-extension/src/browser/dialogs/cloud-share-sketch-dialog.tsx create mode 100644 arduino-ide-extension/src/browser/dialogs/do-not-ask-again-dialog.ts create mode 100644 arduino-ide-extension/src/browser/dialogs/firmware-uploader/firmware-uploader-component.tsx create mode 100644 arduino-ide-extension/src/browser/dialogs/firmware-uploader/firmware-uploader-dialog.tsx create mode 100644 arduino-ide-extension/src/browser/dialogs/ide-updater/ide-updater-component.tsx create mode 100644 arduino-ide-extension/src/browser/dialogs/ide-updater/ide-updater-dialog.tsx create mode 100644 arduino-ide-extension/src/browser/dialogs/librarys/librarys-dialog.tsx create mode 100644 arduino-ide-extension/src/browser/dialogs/librarys/open-librarys.ts create mode 100644 arduino-ide-extension/src/browser/dialogs/settings/settings-component.tsx create mode 100644 arduino-ide-extension/src/browser/dialogs/settings/settings-dialog.tsx create mode 100644 arduino-ide-extension/src/browser/dialogs/settings/settings-step-input.tsx create mode 100644 arduino-ide-extension/src/browser/dialogs/settings/settings.ts create mode 100644 arduino-ide-extension/src/browser/dialogs/user-fields/user-fields-component.tsx create mode 100644 arduino-ide-extension/src/browser/dialogs/user-fields/user-fields-dialog.tsx create mode 100644 arduino-ide-extension/src/browser/home/home-commands.ts create mode 100644 arduino-ide-extension/src/browser/home/home-widget-contribution.ts create mode 100644 arduino-ide-extension/src/browser/home/home-widget.ts create mode 100644 arduino-ide-extension/src/browser/hosted/hosted-plugin-events.ts create mode 100644 arduino-ide-extension/src/browser/hosted/hosted-plugin-support.ts create mode 100644 arduino-ide-extension/src/browser/icons/arduino-cloud-download.svg 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 create mode 100644 arduino-ide-extension/src/browser/icons/arduino-cloud-upload.svg create mode 100644 arduino-ide-extension/src/browser/icons/arduino-cloud.svg create mode 100644 arduino-ide-extension/src/browser/icons/buttons.svg create mode 100644 arduino-ide-extension/src/browser/icons/debug-dark.svg create mode 100644 arduino-ide-extension/src/browser/icons/library-tab-icon.svg create mode 100644 arduino-ide-extension/src/browser/icons/loading-dark.svg create mode 100644 arduino-ide-extension/src/browser/icons/loading-light.svg create mode 100644 arduino-ide-extension/src/browser/icons/mask-buttons.svg create mode 100644 arduino-ide-extension/src/browser/icons/monitor-tab-icon.svg create mode 100644 arduino-ide-extension/src/browser/icons/monitor.svg create mode 100644 arduino-ide-extension/src/browser/icons/plotter.svg create mode 100644 arduino-ide-extension/src/browser/icons/sketch-tabs-menu.svg create mode 100644 arduino-ide-extension/src/browser/icons/upload.svg create mode 100644 arduino-ide-extension/src/browser/icons/verify.svg create mode 100644 arduino-ide-extension/src/browser/ide-updater/ide-updater-client-impl.ts create mode 100644 arduino-ide-extension/src/browser/ide-updater/ide-updater-commands.ts create mode 100644 arduino-ide-extension/src/browser/library/library-list-widget.ts create mode 100644 arduino-ide-extension/src/browser/library/library-widget-frontend-contribution.ts create mode 100644 arduino-ide-extension/src/browser/library/my-library-list-widget.ts create mode 100644 arduino-ide-extension/src/browser/library/my-library-widget-frontend-contribution.ts create mode 100644 arduino-ide-extension/src/browser/local-cache/local-cache-fs-provider.ts create mode 100644 arduino-ide-extension/src/browser/menu/arduino-menus.ts create mode 100644 arduino-ide-extension/src/browser/monitor-manager-proxy-client-impl.ts create mode 100644 arduino-ide-extension/src/browser/monitor-model.ts create mode 100644 arduino-ide-extension/src/browser/notification-center.ts create mode 100644 arduino-ide-extension/src/browser/response-service-impl.ts create mode 100644 arduino-ide-extension/src/browser/selectors.ts create mode 100644 arduino-ide-extension/src/browser/serial/monitor/monitor-utils.ts create mode 100644 arduino-ide-extension/src/browser/serial/monitor/monitor-view-contribution.tsx create mode 100644 arduino-ide-extension/src/browser/serial/monitor/monitor-widget.tsx create mode 100644 arduino-ide-extension/src/browser/serial/monitor/serial-monitor-send-input.tsx create mode 100644 arduino-ide-extension/src/browser/serial/monitor/serial-monitor-send-output.tsx create mode 100644 arduino-ide-extension/src/browser/serial/plotter/plotter-frontend-contribution.ts create mode 100644 arduino-ide-extension/src/browser/sketches-service-client-impl.ts create mode 100644 arduino-ide-extension/src/browser/style/arduino-select.css create mode 100644 arduino-ide-extension/src/browser/style/boards-config-dialog.css create mode 100644 arduino-ide-extension/src/browser/style/browser-menu.css create mode 100644 arduino-ide-extension/src/browser/style/certificate-uploader-dialog.css create mode 100644 arduino-ide-extension/src/browser/style/cloud-sketchbook-tree-icon-filled.svg create mode 100644 arduino-ide-extension/src/browser/style/cloud-sketchbook-tree-icon.svg create mode 100644 arduino-ide-extension/src/browser/style/cloud-sketchbook.css create mode 100644 arduino-ide-extension/src/browser/style/connected-status-icon.svg create mode 100644 arduino-ide-extension/src/browser/style/custom-codicon.css create mode 100644 arduino-ide-extension/src/browser/style/debug.css create mode 100644 arduino-ide-extension/src/browser/style/dialogs.css create mode 100644 arduino-ide-extension/src/browser/style/editor.css create mode 100644 arduino-ide-extension/src/browser/style/firmware-uploader-dialog.css create mode 100644 arduino-ide-extension/src/browser/style/fonts.css create mode 100644 arduino-ide-extension/src/browser/style/fonts/FontAwesome.svg create mode 100644 arduino-ide-extension/src/browser/style/fonts/FontAwesome.ttf create mode 100644 arduino-ide-extension/src/browser/style/fonts/FontAwesome.woff create mode 100644 arduino-ide-extension/src/browser/style/fonts/OpenSans-Bold-webfont.woff create mode 100644 arduino-ide-extension/src/browser/style/fonts/OpenSans-Regular-webfont.woff create mode 100644 arduino-ide-extension/src/browser/style/ide-logo.png create mode 100644 arduino-ide-extension/src/browser/style/ide-updater-dialog.css create mode 100644 arduino-ide-extension/src/browser/style/index.css create mode 100644 arduino-ide-extension/src/browser/style/library-widget.css create mode 100644 arduino-ide-extension/src/browser/style/librarys-dialog.css create mode 100644 arduino-ide-extension/src/browser/style/list-widget.css create mode 100644 arduino-ide-extension/src/browser/style/main.css create mode 100644 arduino-ide-extension/src/browser/style/monitor.css create mode 100644 arduino-ide-extension/src/browser/style/offline-status-icon.svg create mode 100644 arduino-ide-extension/src/browser/style/progress-bar.css create mode 100644 arduino-ide-extension/src/browser/style/refresh-icon.svg create mode 100644 arduino-ide-extension/src/browser/style/resources/fonts/icon/down.png create mode 100644 arduino-ide-extension/src/browser/style/resources/fonts/iconfont.css create mode 100644 arduino-ide-extension/src/browser/style/resources/fonts/iconfont.js create mode 100644 arduino-ide-extension/src/browser/style/resources/fonts/iconfont.json create mode 100644 arduino-ide-extension/src/browser/style/resources/fonts/iconfont.svg create mode 100644 arduino-ide-extension/src/browser/style/resources/fonts/iconfont.ttf create mode 100644 arduino-ide-extension/src/browser/style/resources/fonts/iconfont.woff create mode 100644 arduino-ide-extension/src/browser/style/resources/fonts/iconfont.woff2 create mode 100644 arduino-ide-extension/src/browser/style/settings-dialog.css create mode 100644 arduino-ide-extension/src/browser/style/settings-step-input.css create mode 100644 arduino-ide-extension/src/browser/style/sketchbook-opts-icon.svg create mode 100644 arduino-ide-extension/src/browser/style/sketchbook-tree-icon-filled.svg create mode 100644 arduino-ide-extension/src/browser/style/sketchbook-tree-icon.svg create mode 100644 arduino-ide-extension/src/browser/style/sketchbook.css create mode 100644 arduino-ide-extension/src/browser/style/sketchbook.svg create mode 100644 arduino-ide-extension/src/browser/style/status-bar.css create mode 100644 arduino-ide-extension/src/browser/style/terminal.css create mode 100644 arduino-ide-extension/src/browser/style/user-fields-dialog.css create mode 100644 arduino-ide-extension/src/browser/theia/core/about-dialog.ts create mode 100644 arduino-ide-extension/src/browser/theia/core/application-shell.ts create mode 100644 arduino-ide-extension/src/browser/theia/core/browser-menu-plugin.ts create mode 100644 arduino-ide-extension/src/browser/theia/core/common-frontend-contribution.ts create mode 100644 arduino-ide-extension/src/browser/theia/core/connection-status-service.ts create mode 100644 arduino-ide-extension/src/browser/theia/core/frontend-application.ts create mode 100644 arduino-ide-extension/src/browser/theia/core/json-schema-store.ts create mode 100644 arduino-ide-extension/src/browser/theia/core/shell-layout-restorer.ts create mode 100644 arduino-ide-extension/src/browser/theia/core/sidebar-bottom-menu-widget copy.tsx create mode 100644 arduino-ide-extension/src/browser/theia/core/sidebar-bottom-menu-widget.tsx create mode 100644 arduino-ide-extension/src/browser/theia/core/tab-bar-decorator.ts create mode 100644 arduino-ide-extension/src/browser/theia/core/tab-bars.ts create mode 100644 arduino-ide-extension/src/browser/theia/core/theming.ts create mode 100644 arduino-ide-extension/src/browser/theia/core/widget-manager.ts create mode 100644 arduino-ide-extension/src/browser/theia/core/window-contribution.ts create mode 100644 arduino-ide-extension/src/browser/theia/core/window-service-ext.ts create mode 100644 arduino-ide-extension/src/browser/theia/core/window-title-updater.ts create mode 100644 arduino-ide-extension/src/browser/theia/debug/debug-configuration-manager.ts create mode 100644 arduino-ide-extension/src/browser/theia/debug/debug-configuration-model.ts create mode 100644 arduino-ide-extension/src/browser/theia/debug/debug-configuration-widget.tsx create mode 100644 arduino-ide-extension/src/browser/theia/debug/debug-frontend-application-contribution.ts create mode 100644 arduino-ide-extension/src/browser/theia/debug/debug-session-contribution.ts create mode 100644 arduino-ide-extension/src/browser/theia/debug/debug-session-manager.ts create mode 100644 arduino-ide-extension/src/browser/theia/debug/debug-session.ts create mode 100644 arduino-ide-extension/src/browser/theia/debug/debug-widget.ts create mode 100644 arduino-ide-extension/src/browser/theia/dialogs/dialogs.tsx create mode 100644 arduino-ide-extension/src/browser/theia/dialogs/theiaDialogs/dialogs.ts create mode 100644 arduino-ide-extension/src/browser/theia/dialogs/theiaDialogs/react-dialog.tsx create mode 100644 arduino-ide-extension/src/browser/theia/dialogs/widgets.ts create mode 100644 arduino-ide-extension/src/browser/theia/editor/editor-command.ts create mode 100644 arduino-ide-extension/src/browser/theia/editor/editor-contribution.ts create mode 100644 arduino-ide-extension/src/browser/theia/editor/editor-file.ts create mode 100644 arduino-ide-extension/src/browser/theia/editor/editor-manager.ts create mode 100644 arduino-ide-extension/src/browser/theia/editor/editor-navigation-contribution.ts create mode 100644 arduino-ide-extension/src/browser/theia/editor/editor-widget-factory.ts create mode 100644 arduino-ide-extension/src/browser/theia/filesystem/file-resource.ts create mode 100644 arduino-ide-extension/src/browser/theia/filesystem/filesystem-watcher-error-handler.ts create mode 100644 arduino-ide-extension/src/browser/theia/keymaps/keymaps-frontend-contribution.ts create mode 100644 arduino-ide-extension/src/browser/theia/keymaps/keymaps-frontend-widget.tsx create mode 100644 arduino-ide-extension/src/browser/theia/markers/problem-contribution.ts create mode 100644 arduino-ide-extension/src/browser/theia/markers/problem-manager.ts create mode 100644 arduino-ide-extension/src/browser/theia/messages/notification-center-component.tsx create mode 100644 arduino-ide-extension/src/browser/theia/messages/notification-component.tsx create mode 100644 arduino-ide-extension/src/browser/theia/messages/notification-toasts-component.tsx create mode 100644 arduino-ide-extension/src/browser/theia/messages/notifications-contribution.ts create mode 100644 arduino-ide-extension/src/browser/theia/messages/notifications-manager.ts create mode 100644 arduino-ide-extension/src/browser/theia/messages/notifications-renderer.tsx create mode 100644 arduino-ide-extension/src/browser/theia/monaco/monaco-editor-provider.ts create mode 100644 arduino-ide-extension/src/browser/theia/monaco/monaco-formatting-conflicts.ts create mode 100644 arduino-ide-extension/src/browser/theia/monaco/monaco-menu.ts create mode 100644 arduino-ide-extension/src/browser/theia/monaco/monaco-status-bar-contribution.ts create mode 100644 arduino-ide-extension/src/browser/theia/monaco/monaco-text-model-service.ts create mode 100644 arduino-ide-extension/src/browser/theia/monaco/monaco-theming-service.ts create mode 100644 arduino-ide-extension/src/browser/theia/navigator/navigator-contribution.ts create mode 100644 arduino-ide-extension/src/browser/theia/navigator/navigator-tab-bar-decorator.ts create mode 100644 arduino-ide-extension/src/browser/theia/out-put/out-put-widget.ts create mode 100644 arduino-ide-extension/src/browser/theia/out-put/output-contribution.ts create mode 100644 arduino-ide-extension/src/browser/theia/outline/outline-contribution.ts create mode 100644 arduino-ide-extension/src/browser/theia/output/output-channel.ts create mode 100644 arduino-ide-extension/src/browser/theia/output/output-editor-factory.ts create mode 100644 arduino-ide-extension/src/browser/theia/output/output-toolbar-contribution.ts create mode 100644 arduino-ide-extension/src/browser/theia/plugin-ext/hosted-plugin.ts create mode 100644 arduino-ide-extension/src/browser/theia/plugin-ext/output-channel-registry-main.ts create mode 100644 arduino-ide-extension/src/browser/theia/preferences/preference-editor-widget.ts create mode 100644 arduino-ide-extension/src/browser/theia/preferences/preference-tree-generator.ts create mode 100644 arduino-ide-extension/src/browser/theia/preferences/preferences-contribution.ts create mode 100644 arduino-ide-extension/src/browser/theia/scm/scm-contribution.ts create mode 100644 arduino-ide-extension/src/browser/theia/search-in-workspace/search-in-workspace-factory.ts create mode 100644 arduino-ide-extension/src/browser/theia/search-in-workspace/search-in-workspace-frontend-contribution.ts create mode 100644 arduino-ide-extension/src/browser/theia/search-in-workspace/search-in-workspace-widget.tsx create mode 100644 arduino-ide-extension/src/browser/theia/terminal/terminal-frontend-contribution.ts create mode 100644 arduino-ide-extension/src/browser/theia/typehierarchy/type-hierarchy-contribution.ts create mode 100644 arduino-ide-extension/src/browser/theia/typehierarchy/type-hierarchy-service.ts create mode 100644 arduino-ide-extension/src/browser/theia/workspace/workspace-commands.ts create mode 100644 arduino-ide-extension/src/browser/theia/workspace/workspace-delete-handler.ts create mode 100644 arduino-ide-extension/src/browser/theia/workspace/workspace-frontend-contribution.ts create mode 100644 arduino-ide-extension/src/browser/theia/workspace/workspace-input-dialog.ts create mode 100644 arduino-ide-extension/src/browser/theia/workspace/workspace-service.ts create mode 100644 arduino-ide-extension/src/browser/theia/workspace/workspace-variable-contribution.ts create mode 100644 arduino-ide-extension/src/browser/toolbar/arduino-toolbar-contribution.ts create mode 100644 arduino-ide-extension/src/browser/toolbar/arduino-toolbar.tsx create mode 100644 arduino-ide-extension/src/browser/toolbar/icon/close_normal.png create mode 100644 arduino-ide-extension/src/browser/toolbar/icon/icon.ico create mode 100644 arduino-ide-extension/src/browser/toolbar/icon/max_normal.png create mode 100644 arduino-ide-extension/src/browser/toolbar/icon/menu_normal.png create mode 100644 arduino-ide-extension/src/browser/toolbar/icon/min_normal.png create mode 100644 arduino-ide-extension/src/browser/utils/constants.ts create mode 100644 arduino-ide-extension/src/browser/utils/dom.ts create mode 100644 arduino-ide-extension/src/browser/utils/window.ts create mode 100644 arduino-ide-extension/src/browser/widgets/arduino-select.tsx create mode 100644 arduino-ide-extension/src/browser/widgets/cloud-sketchbook/README.md create mode 100644 arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketch-cache.ts create mode 100644 arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-commands.ts create mode 100644 arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-composite-widget.tsx create mode 100644 arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-contributions.ts create mode 100644 arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-tree-container.ts create mode 100644 arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-tree-model.ts create mode 100644 arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-tree-widget.tsx create mode 100644 arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-tree.ts create mode 100644 arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-sketchbook-widget.ts create mode 100644 arduino-ide-extension/src/browser/widgets/cloud-sketchbook/cloud-status.tsx create mode 100644 arduino-ide-extension/src/browser/widgets/component-list/component-list-item.tsx create mode 100644 arduino-ide-extension/src/browser/widgets/component-list/component-list.tsx create mode 100644 arduino-ide-extension/src/browser/widgets/component-list/filter-renderer.tsx create mode 100644 arduino-ide-extension/src/browser/widgets/component-list/filterable-list-container.tsx create mode 100644 arduino-ide-extension/src/browser/widgets/component-list/list-item-renderer.tsx create mode 100644 arduino-ide-extension/src/browser/widgets/component-list/list-widget-frontend-contribution.ts create mode 100644 arduino-ide-extension/src/browser/widgets/component-list/list-widget.tsx create mode 100644 arduino-ide-extension/src/browser/widgets/component-list/search-bar.tsx create mode 100644 arduino-ide-extension/src/browser/widgets/sketchbook/create-new.tsx create mode 100644 arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-commands.ts create mode 100644 arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-composite-widget.tsx create mode 100644 arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-tree-container.ts create mode 100644 arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-tree-model.ts create mode 100644 arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-tree-widget.tsx create mode 100644 arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-tree.ts create mode 100644 arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-widget-contribution.ts create mode 100644 arduino-ide-extension/src/browser/widgets/sketchbook/sketchbook-widget.tsx create mode 100644 arduino-ide-extension/src/common/decorators.ts create mode 100644 arduino-ide-extension/src/common/main-menu-manager.ts create mode 100644 arduino-ide-extension/src/common/nls.ts create mode 100644 arduino-ide-extension/src/common/protocol/arduino-component.ts create mode 100644 arduino-ide-extension/src/common/protocol/arduino-context-mapper.ts create mode 100644 arduino-ide-extension/src/common/protocol/arduino-daemon.ts create mode 100644 arduino-ide-extension/src/common/protocol/arduino-firmware-uploader.ts create mode 100644 arduino-ide-extension/src/common/protocol/authentication-service.ts create mode 100644 arduino-ide-extension/src/common/protocol/board-list.ts create mode 100644 arduino-ide-extension/src/common/protocol/boards-service.ts create mode 100644 arduino-ide-extension/src/common/protocol/config-service.ts create mode 100644 arduino-ide-extension/src/common/protocol/core-service.ts create mode 100644 arduino-ide-extension/src/common/protocol/examples-service.ts create mode 100644 arduino-ide-extension/src/common/protocol/executable-service.ts create mode 100644 arduino-ide-extension/src/common/protocol/filesystem-ext.ts create mode 100644 arduino-ide-extension/src/common/protocol/formatter.ts create mode 100644 arduino-ide-extension/src/common/protocol/ide-updater.ts create mode 100644 arduino-ide-extension/src/common/protocol/index.ts create mode 100644 arduino-ide-extension/src/common/protocol/installable.ts create mode 100644 arduino-ide-extension/src/common/protocol/library-service.ts create mode 100644 arduino-ide-extension/src/common/protocol/monitor-service.ts create mode 100644 arduino-ide-extension/src/common/protocol/notification-service.ts create mode 100644 arduino-ide-extension/src/common/protocol/progressible.ts create mode 100644 arduino-ide-extension/src/common/protocol/response-service.ts create mode 100644 arduino-ide-extension/src/common/protocol/searchable.ts create mode 100644 arduino-ide-extension/src/common/protocol/sketches-service.ts create mode 100644 arduino-ide-extension/src/common/protocol/survey-service.ts create mode 100644 arduino-ide-extension/src/common/types.ts create mode 100644 arduino-ide-extension/src/common/utils.ts create mode 100644 arduino-ide-extension/src/electron-browser/electron-app-service.ts create mode 100644 arduino-ide-extension/src/electron-browser/electron-arduino-module.ts create mode 100644 arduino-ide-extension/src/electron-browser/electron-dialog-service.ts create mode 100644 arduino-ide-extension/src/electron-browser/preload.ts create mode 100644 arduino-ide-extension/src/electron-browser/theia/core/electron-context-menu-renderer.ts create mode 100644 arduino-ide-extension/src/electron-browser/theia/core/electron-main-menu-factory.ts create mode 100644 arduino-ide-extension/src/electron-browser/theia/core/electron-menu-contribution.ts create mode 100644 arduino-ide-extension/src/electron-browser/theia/core/electron-menu-module.ts create mode 100644 arduino-ide-extension/src/electron-browser/theia/core/electron-window-module.ts create mode 100644 arduino-ide-extension/src/electron-browser/theia/core/electron-window-service.ts create mode 100644 arduino-ide-extension/src/electron-common/electron-arduino.ts create mode 100644 arduino-ide-extension/src/electron-common/startup-task.ts create mode 100644 arduino-ide-extension/src/electron-main/arduino-electron-main-module.ts create mode 100644 arduino-ide-extension/src/electron-main/electron-arduino.ts create mode 100644 arduino-ide-extension/src/electron-main/fix-app-image-icon.ts create mode 100644 arduino-ide-extension/src/electron-main/ide-updater/ide-updater-impl.ts create mode 100644 arduino-ide-extension/src/electron-main/theia/electron-main-application.ts create mode 100644 arduino-ide-extension/src/electron-main/theia/electron-main-window-service.ts create mode 100644 arduino-ide-extension/src/electron-main/theia/theia-api-main.ts create mode 100644 arduino-ide-extension/src/electron-main/theia/theia-electron-window.ts create mode 100644 arduino-ide-extension/src/node/arduino-daemon-impl.ts create mode 100644 arduino-ide-extension/src/node/arduino-firmware-uploader-impl.ts create mode 100644 arduino-ide-extension/src/node/arduino-ide-backend-module.ts create mode 100644 arduino-ide-extension/src/node/auth/arduino-auth-provider.ts create mode 100644 arduino-ide-extension/src/node/auth/authentication-server.ts create mode 100644 arduino-ide-extension/src/node/auth/authentication-service-impl.ts create mode 100644 arduino-ide-extension/src/node/auth/body.ts create mode 100644 arduino-ide-extension/src/node/auth/keychain.ts create mode 100644 arduino-ide-extension/src/node/auth/types.ts create mode 100644 arduino-ide-extension/src/node/auth/utils.ts create mode 100644 arduino-ide-extension/src/node/board-discovery.ts create mode 100644 arduino-ide-extension/src/node/boards-service-impl.ts create mode 100644 arduino-ide-extension/src/node/clang-formatter.ts create mode 100644 arduino-ide-extension/src/node/cli-config.ts create mode 100644 arduino-ide-extension/src/node/cli-error-parser.ts create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/board_grpc_pb.js create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/board_pb.d.ts create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/board_pb.js create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/commands_grpc_pb.d.ts create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/commands_grpc_pb.js create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/commands_pb.d.ts create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/commands_pb.js create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/common_grpc_pb.js create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/common_pb.d.ts create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/common_pb.js create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/compile_grpc_pb.js create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/compile_pb.d.ts create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/compile_pb.js create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/core_grpc_pb.js create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/core_pb.d.ts create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/core_pb.js create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/debug_grpc_pb.js create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/debug_pb.d.ts create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/debug_pb.js create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/lib_grpc_pb.js create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/lib_pb.d.ts create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/lib_pb.js create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/monitor_grpc_pb.js create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/monitor_pb.d.ts create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/monitor_pb.js create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/port_grpc_pb.js create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/port_pb.d.ts create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/port_pb.js create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/upload_grpc_pb.js create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/upload_pb.d.ts create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/commands/v1/upload_pb.js create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/settings/v1/settings_grpc_pb.d.ts create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/settings/v1/settings_grpc_pb.js create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/settings/v1/settings_pb.d.ts create mode 100644 arduino-ide-extension/src/node/cli-protocol/cc/arduino/cli/settings/v1/settings_pb.js create mode 100644 arduino-ide-extension/src/node/cli-protocol/google/rpc/status_grpc_pb.js create mode 100644 arduino-ide-extension/src/node/cli-protocol/google/rpc/status_pb.d.ts create mode 100644 arduino-ide-extension/src/node/cli-protocol/google/rpc/status_pb.js create mode 100644 arduino-ide-extension/src/node/config-service-impl.ts create mode 100644 arduino-ide-extension/src/node/core-client-provider.ts create mode 100644 arduino-ide-extension/src/node/core-service-impl.ts create mode 100644 arduino-ide-extension/src/node/default-formatter-config.json create mode 100644 arduino-ide-extension/src/node/examples-service-impl.ts create mode 100644 arduino-ide-extension/src/node/exec-util.ts create mode 100644 arduino-ide-extension/src/node/executable-service-impl.ts create mode 100644 arduino-ide-extension/src/node/grpc-progressible.ts create mode 100644 arduino-ide-extension/src/node/i18n/arduino-localization-contribution.ts create mode 100644 arduino-ide-extension/src/node/is-temp-sketch.ts create mode 100644 arduino-ide-extension/src/node/library-service-impl.ts create mode 100644 arduino-ide-extension/src/node/monitor-manager-proxy-impl.ts create mode 100644 arduino-ide-extension/src/node/monitor-manager.ts create mode 100644 arduino-ide-extension/src/node/monitor-service-factory.ts create mode 100644 arduino-ide-extension/src/node/monitor-service.ts create mode 100644 arduino-ide-extension/src/node/monitor-settings/monitor-settings-provider-impl.ts create mode 100644 arduino-ide-extension/src/node/monitor-settings/monitor-settings-provider.ts create mode 100644 arduino-ide-extension/src/node/monitor-settings/monitor-settings-utils.ts create mode 100644 arduino-ide-extension/src/node/node-filesystem-ext.ts create mode 100644 arduino-ide-extension/src/node/notification-service-server.ts create mode 100644 arduino-ide-extension/src/node/plotter/plotter-backend-contribution.ts create mode 100644 arduino-ide-extension/src/node/resources.ts create mode 100644 arduino-ide-extension/src/node/service-error.ts create mode 100644 arduino-ide-extension/src/node/settings-reader.ts create mode 100644 arduino-ide-extension/src/node/sketches-service-impl.ts create mode 100644 arduino-ide-extension/src/node/survey-service-impl.ts create mode 100644 arduino-ide-extension/src/node/theia/core/backend-application.ts create mode 100644 arduino-ide-extension/src/node/theia/core/messaging-contribution.ts create mode 100644 arduino-ide-extension/src/node/theia/env-variables/env-variables-server.ts create mode 100644 arduino-ide-extension/src/node/theia/filesystem/nsfw-bindings.ts create mode 100644 arduino-ide-extension/src/node/theia/filesystem/nsfw-watcher/index.ts create mode 100644 arduino-ide-extension/src/node/theia/filesystem/nsfw-watcher/nsfw-filesystem-service.ts create mode 100644 arduino-ide-extension/src/node/theia/plugin-ext/hosted-plugin-localization-service.ts create mode 100644 arduino-ide-extension/src/node/theia/plugin-ext/plugin-deployer.ts create mode 100644 arduino-ide-extension/src/node/theia/plugin-ext/plugin-reader.ts create mode 100644 arduino-ide-extension/src/node/theia/workspace/default-workspace-server.ts create mode 100644 arduino-ide-extension/src/node/utils/buffers.ts create mode 100644 arduino-ide-extension/src/node/utils/errors.ts create mode 100644 arduino-ide-extension/src/node/web-socket/web-socket-provider-impl.ts create mode 100644 arduino-ide-extension/src/node/web-socket/web-socket-provider.ts create mode 100644 arduino-ide-extension/src/test/browser/auto-select-programmer.test.ts create mode 100644 arduino-ide-extension/src/test/browser/board-service-provider.test.ts create mode 100644 arduino-ide-extension/src/test/browser/boards-data-store.test.ts create mode 100644 arduino-ide-extension/src/test/browser/browser-test-bindings.ts create mode 100644 arduino-ide-extension/src/test/browser/connection-status-service.test.ts create mode 100644 arduino-ide-extension/src/test/browser/create-api.slow-test.ts create mode 100644 arduino-ide-extension/src/test/browser/debug.test.ts create mode 100644 arduino-ide-extension/src/test/browser/dom.test.ts create mode 100644 arduino-ide-extension/src/test/browser/fixtures/boards.ts create mode 100644 arduino-ide-extension/src/test/browser/monitor-utils.test.ts create mode 100644 arduino-ide-extension/src/test/browser/theming.test.ts create mode 100644 arduino-ide-extension/src/test/browser/update-arduino-state.test.ts create mode 100644 arduino-ide-extension/src/test/browser/widgets.test.ts create mode 100644 arduino-ide-extension/src/test/browser/workspace-commands.test.ts create mode 100644 arduino-ide-extension/src/test/common/arduino-context-mapper.test.ts create mode 100644 arduino-ide-extension/src/test/common/board-list.test.ts create mode 100644 arduino-ide-extension/src/test/common/boards-service.test.ts create mode 100644 arduino-ide-extension/src/test/common/common-test-bindings.ts create mode 100644 arduino-ide-extension/src/test/common/config-service.test.ts create mode 100644 arduino-ide-extension/src/test/common/fixtures.ts create mode 100644 arduino-ide-extension/src/test/common/installable.test.ts create mode 100644 arduino-ide-extension/src/test/common/searchable.test.ts create mode 100644 arduino-ide-extension/src/test/common/sketches-service.test.ts create mode 100644 arduino-ide-extension/src/test/node/__test_sketchbook__/a_sketch/a_sketch.ino create mode 100644 arduino-ide-extension/src/test/node/__test_sketchbook__/bar++ 2/bar++ 2.ino create mode 100644 arduino-ide-extension/src/test/node/__test_sketchbook__/bar++/bar++.ino create mode 100644 arduino-ide-extension/src/test/node/__test_sketchbook__/bar++/foo++/foo++.ino create mode 100644 arduino-ide-extension/src/test/node/__test_sketchbook__/defaultIno.ino create mode 100644 arduino-ide-extension/src/test/node/__test_sketchbook__/empty/.gitkeep create mode 100644 arduino-ide-extension/src/test/node/__test_sketchbook__/libraries/my_library/examples/Ethernet/Example_1/Example_1.ino create mode 100644 arduino-ide-extension/src/test/node/__test_sketchbook__/libraries/my_library/examples/WiFi/Example_2/Example_2.ino create mode 100644 arduino-ide-extension/src/test/node/__test_sketchbook__/mismatchingName/MismatchingName.ino create mode 100644 arduino-ide-extension/src/test/node/__test_sketchbook__/nested_4/nested_3/nested_2/nested_1/nested_1.ino create mode 100644 arduino-ide-extension/src/test/node/__test_sketchbook__/nested_4/nested_3/nested_2/nested_2.ino create mode 100644 arduino-ide-extension/src/test/node/__test_sketchbook__/project1/CodeA/version1A/version1A.ino create mode 100644 arduino-ide-extension/src/test/node/__test_sketchbook__/project1/CodeA/version2A/version2A.ino create mode 100644 arduino-ide-extension/src/test/node/__test_sketchbook__/project1/CodeB/version1B/version1B.ino create mode 100644 arduino-ide-extension/src/test/node/__test_sketchbook__/project1/CodeB/version2B/version2B.pde create mode 100644 arduino-ide-extension/src/test/node/arduino-daemon-impl.test.ts create mode 100644 arduino-ide-extension/src/test/node/boards-service-impl.slow-test.ts create mode 100644 arduino-ide-extension/src/test/node/clang-formatter.test.ts create mode 100644 arduino-ide-extension/src/test/node/cli-config.test.ts create mode 100644 arduino-ide-extension/src/test/node/core-client-provider.slow-test.ts create mode 100644 arduino-ide-extension/src/test/node/core-service-impl.slow-test.ts create mode 100644 arduino-ide-extension/src/test/node/core-service-impl.test.ts create mode 100644 arduino-ide-extension/src/test/node/exec-util.test.ts create mode 100644 arduino-ide-extension/src/test/node/library-service-impl.slow-test.ts create mode 100644 arduino-ide-extension/src/test/node/monitor-settings-utils.test.ts create mode 100644 arduino-ide-extension/src/test/node/node-test-bindings.ts create mode 100644 arduino-ide-extension/src/test/node/settings.reader.test.ts create mode 100644 arduino-ide-extension/src/test/node/sketches-service-impl.slow-test.ts create mode 100644 arduino-ide-extension/src/test/node/sketches-service-impl.test.ts create mode 100644 arduino-ide-extension/src/test/utils.ts create mode 100644 arduino-ide-extension/tsconfig.json create mode 100644 docs/CONTRIBUTING.md create mode 100644 docs/README.md create mode 100644 docs/advanced-usage.md create mode 100644 docs/assets/preferences.png create mode 100644 docs/assets/remote.png create mode 100644 docs/contributor-guide/assets/checks-tab.png create mode 100644 docs/contributor-guide/assets/checks.png create mode 100644 docs/contributor-guide/assets/tester-build-artifacts.png create mode 100644 docs/contributor-guide/assets/tester-build-link.png create mode 100644 docs/contributor-guide/beta-testing.md create mode 100644 docs/contributor-guide/issues.md create mode 100644 docs/contributor-guide/pull-requests.md create mode 100644 docs/contributor-guide/translation.md create mode 100644 docs/development.md create mode 100644 docs/internal/Ubuntu.md create mode 100644 docs/internal/release-procedure.md create mode 100644 electron-app/arduino-ide-backend-main.js create mode 100644 electron-app/arduino-ide-electron-main.js create mode 100644 electron-app/lingzhi-backend-main.js create mode 100644 electron-app/lingzhi-electron-main.js create mode 100644 electron-app/ninni/packages/ctags-5.8-arduino11-pm-i686-mingw32.zip create mode 100644 electron-app/ninni/packages/dfu-discovery_v0.1.2_Windows_64bit.zip create mode 100644 electron-app/ninni/packages/mdns-discovery_v1.0.9_Windows_64bit.zip create mode 100644 electron-app/ninni/packages/serial-discovery_v1.4.1_Windows_64bit.zip create mode 100644 electron-app/ninni/packages/serial-monitor_v0.14.1_Windows_64bit.zip create mode 100644 electron-app/package.json create mode 100644 electron-app/resources/akte3-p5rt0.svg create mode 100644 electron-app/resources/entitlements.mac.plist create mode 100644 electron-app/resources/eula.txt create mode 100644 electron-app/resources/icon.icns create mode 100644 electron-app/resources/icon.ico create mode 100644 electron-app/resources/icons/512x512.png create mode 100644 electron-app/resources/installerSidebar.bmp create mode 100644 electron-app/resources/logoR.ico create mode 100644 electron-app/resources/preload.html create mode 100644 electron-app/scripts/archive.js create mode 100644 electron-app/scripts/notarize.js create mode 100644 electron-app/scripts/package.js create mode 100644 electron-app/scripts/post-package.js create mode 100644 electron-app/scripts/utils.js create mode 100644 electron-app/test/archive.test.js create mode 100644 electron-app/test/test-resources/not-a-zip.dmg create mode 100644 electron-app/test/test-resources/zip with whitespace.zip create mode 100644 electron-app/test/test-resources/zip-with-base-folder.zip create mode 100644 electron-app/test/test-resources/zip-with-symlink.zip create mode 100644 electron-app/test/test-resources/zip-without-symlink.zip create mode 100644 electron-app/webpack.base.js create mode 100644 electron-app/webpack.config.js create mode 100644 electron-app/webpack.dev.js create mode 100644 i18n/README.md create mode 100644 i18n/af.json create mode 100644 i18n/ar.json create mode 100644 i18n/az.json create mode 100644 i18n/bg.json create mode 100644 i18n/ca_ES.json create mode 100644 i18n/cs.json create mode 100644 i18n/de.json create mode 100644 i18n/el.json create mode 100644 i18n/en.json create mode 100644 i18n/es.json create mode 100644 i18n/eu.json create mode 100644 i18n/fa.json create mode 100644 i18n/fil.json create mode 100644 i18n/fr.json create mode 100644 i18n/he.json create mode 100644 i18n/hu.json create mode 100644 i18n/id.json create mode 100644 i18n/it.json create mode 100644 i18n/ja.json create mode 100644 i18n/ko.json create mode 100644 i18n/my_MM.json create mode 100644 i18n/ne.json create mode 100644 i18n/nl.json create mode 100644 i18n/pl.json create mode 100644 i18n/pt.json create mode 100644 i18n/ro.json create mode 100644 i18n/ru.json create mode 100644 i18n/sr.json create mode 100644 i18n/th.json create mode 100644 i18n/tr.json create mode 100644 i18n/uk.json create mode 100644 i18n/vi.json create mode 100644 i18n/zh-Hant.json create mode 100644 i18n/zh.json create mode 100644 i18n/zh_TW.json create mode 100644 lerna.json create mode 100644 package.json create mode 100644 scripts/i18n/transifex-pull.js create mode 100644 scripts/i18n/transifex-push.js create mode 100644 scripts/i18n/transifex.js create mode 100644 scripts/merge-channel-files.js create mode 100644 scripts/package.sh create mode 100644 scripts/sort-dependencies create mode 100644 scripts/themes/theme-generator.js create mode 100644 scripts/themes/theme-tokens-pull.js create mode 100644 scripts/update-version.js create mode 100644 static/screenshot.png create mode 100644 webpack.config.js create mode 100644 yarn.lock diff --git a/.eslintrc.js b/.eslintrc.js new file mode 100644 index 000000000..d3d4646f0 --- /dev/null +++ b/.eslintrc.js @@ -0,0 +1,67 @@ +module.exports = { + parser: '@typescript-eslint/parser', // Specifies the ESLint parser + parserOptions: { + ecmaVersion: 2020, // Allows for the parsing of modern ECMAScript features + sourceType: 'module', // Allows for the use of imports + ecmaFeatures: { + jsx: true, // Allows for the parsing of JSX + }, + }, + ignorePatterns: [ + 'node_modules/*', + '**/node_modules/*', + '.github/*', + '.browser_modules/*', + 'docs/*', + 'scripts/*', + 'electron-app/lib/*', + 'electron-app/src-gen/*', + 'electron-app/gen-webpack*.js', + '!electron-app/webpack.config.js', + 'electron-app/plugins/*', + 'arduino-ide-extension/src/node/cli-protocol', + '**/lib/*', + ], + settings: { + react: { + version: 'detect', // Tells eslint-plugin-react to automatically detect the version of React to use + }, + }, + extends: [ + 'plugin:@typescript-eslint/recommended', // Uses the recommended rules from the @typescript-eslint/eslint-plugin + 'plugin:react/recommended', // Uses the recommended rules from @eslint-plugin-react + 'plugin:react-hooks/recommended', // Uses recommended rules from react hooks + 'plugin:prettier/recommended', + 'prettier', // Uses eslint-config-prettier to disable ESLint rules from @typescript-eslint/eslint-plugin that would conflict with prettier + ], + plugins: ['prettier', 'unused-imports'], + rules: { + 'prefer-const': 'off', + '@typescript-eslint/no-unused-expressions': 'off', + '@typescript-eslint/no-namespace': 'off', + '@typescript-eslint/no-var-requires': 'off', + '@typescript-eslint/no-empty-function': 'warn', + '@typescript-eslint/no-empty-interface': 'warn', + 'no-unused-vars': 'off', + 'unused-imports/no-unused-imports': 'error', + 'unused-imports/no-unused-vars': [ + 'warn', + { + vars: 'all', + varsIgnorePattern: '^_', + args: 'after-used', + argsIgnorePattern: '^_', + }, + ], + 'react/display-name': 'warn', + eqeqeq: ['error', 'smart'], + 'guard-for-in': 'off', + 'id-blacklist': 'off', + 'id-match': 'off', + 'no-underscore-dangle': 'off', + 'no-unused-expressions': 'off', + 'no-var': 'error', + radix: 'error', + 'prettier/prettier': 'warn', + }, +}; diff --git a/.github/ISSUE_TEMPLATE/bug-report.yml b/.github/ISSUE_TEMPLATE/bug-report.yml new file mode 100644 index 000000000..4e647d8da --- /dev/null +++ b/.github/ISSUE_TEMPLATE/bug-report.yml @@ -0,0 +1,74 @@ +name: Bug report +description: Report a problem with the code or documentation in this repository. +labels: + - 'type: imperfection' +body: + - type: textarea + id: description + attributes: + label: Describe the problem + validations: + required: true + - type: textarea + id: reproduce + attributes: + label: To reproduce + description: Provide the specific set of steps we can follow to reproduce the problem. + validations: + required: true + - type: textarea + id: expected + attributes: + label: Expected behavior + description: What would you expect to happen after following those instructions? + validations: + required: true + - type: input + id: project-version + attributes: + label: Arduino IDE version + description: | + Which version of the Arduino IDE are you using? + See **Help > About Arduino IDE** in the Arduino IDE menus (**Arduino IDE > About Arduino IDE** on macOS). + This should be the latest [nightly build](https://www.arduino.cc/en/software#nightly-builds). + validations: + required: true + - type: dropdown + id: os + attributes: + label: Operating system + description: Which operating system(s) are you using on your computer? + multiple: true + options: + - Windows + - Linux + - macOS + - N/A + validations: + required: true + - type: input + id: os-version + attributes: + label: Operating system version + description: Which version of the operating system are you using on your computer? + validations: + required: true + - type: textarea + id: additional + attributes: + label: Additional context + description: Add any additional information here. + validations: + required: false + - type: checkboxes + id: checklist + attributes: + label: Issue checklist + description: Please double-check that you have done each of the following things before submitting the issue. + options: + - label: I searched for previous reports in [the issue tracker](https://github.com/arduino/arduino-ide/issues?q=) + required: true + - label: I verified the problem still occurs when using the latest [nightly build](https://www.arduino.cc/en/software#nightly-builds) + required: true + - label: My report contains all necessary details + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 000000000..7c038ddf4 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,19 @@ +# Source: +# https://github.com/arduino/tooling-project-assets/blob/main/issue-templates/template-choosers/general/config.yml +blank_issues_enabled: false +contact_links: + - name: Learn about using this project + url: https://github.com/arduino/arduino-ide#readme + about: Detailed usage documentation is available here. + - name: Support request + url: https://forum.arduino.cc/ + about: We can help you out on the Arduino Forum! + - name: Issue report guide + url: https://github.com/arduino/arduino-ide/blob/main/docs/contributor-guide/issues.md#issue-report-guide + about: Learn about submitting issue reports to this repository. + - name: Contributor guide + url: https://github.com/arduino/arduino-ide/blob/main/docs/CONTRIBUTING.md#contributor-guide + about: Learn about contributing to this project. + - name: Discuss development work on the project + url: https://groups.google.com/a/arduino.cc/g/developers + about: Arduino Developers Mailing List diff --git a/.github/ISSUE_TEMPLATE/feature-request.yml b/.github/ISSUE_TEMPLATE/feature-request.yml new file mode 100644 index 000000000..955315a05 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/feature-request.yml @@ -0,0 +1,69 @@ +name: Feature request +description: Suggest an enhancement to this project. +labels: + - 'type: enhancement' +body: + - type: textarea + id: description + attributes: + label: Describe the request + validations: + required: true + - type: textarea + id: current + attributes: + label: Describe the current behavior + description: | + What is the current behavior of the Arduino IDE in relation to your request? + How can we reproduce that behavior? + validations: + required: true + - type: input + id: project-version + attributes: + label: Arduino IDE version + description: | + Which version of the Arduino IDE are you using? + See **Help > About Arduino IDE** in the Arduino IDE menus (**Arduino IDE > About Arduino IDE** on macOS). + This should be the latest [nightly build](https://www.arduino.cc/en/software#nightly-builds). + validations: + required: true + - type: dropdown + id: os + attributes: + label: Operating system + description: Which operating system(s) are you using on your computer? + multiple: true + options: + - Windows + - Linux + - macOS + - N/A + validations: + required: true + - type: input + id: os-version + attributes: + label: Operating system version + description: Which version of the operating system are you using on your computer? + validations: + required: true + - type: textarea + id: additional + attributes: + label: Additional context + description: Add any additional information here. + validations: + required: false + - type: checkboxes + id: checklist + attributes: + label: Issue checklist + description: Please double-check that you have done each of the following things before submitting the issue. + options: + - label: I searched for previous requests in [the issue tracker](https://github.com/arduino/arduino-ide/issues?q=) + required: true + - label: I verified the feature was still missing when using the latest [nightly build](https://www.arduino.cc/en/software#nightly-builds) + required: true + - label: My request contains all necessary details + required: true diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100644 index 000000000..b9e9f9102 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,18 @@ +### Motivation + + + +### Change description + + + +### Other information + + + +### Reviewer checklist + +- [ ] PR addresses a single concern. +- [ ] The PR has no duplicates (please search among the [Pull Requests](https://github.com/arduino/arduino-ide/pulls) before creating one) +- [ ] PR title and description are properly filled. +- [ ] Docs have been added / updated (for bug fixes / features) diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 000000000..06f3449ea --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,15 @@ +# See: https://docs.github.com/code-security/dependabot/dependabot-version-updates/configuration-options-for-the-dependabot.yml-file#about-the-dependabotyml-file +version: 2 + +updates: + # Configure check for outdated GitHub Actions actions in workflows. + # Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/dependabot/README.md + # See: https://docs.github.com/code-security/dependabot/working-with-dependabot/keeping-your-actions-up-to-date-with-dependabot + - package-ecosystem: github-actions + directory: / # Check the repository's workflows under /.github/workflows/ + assignees: + - per1234 + schedule: + interval: daily + labels: + - 'topic: infrastructure' diff --git a/.github/label-configuration-files/labels.yml b/.github/label-configuration-files/labels.yml new file mode 100644 index 000000000..3b3e27853 --- /dev/null +++ b/.github/label-configuration-files/labels.yml @@ -0,0 +1,27 @@ +# Used by the "Sync Labels" workflow +# See: https://github.com/Financial-Times/github-label-sync#label-config-file + +- name: 'topic: accessibility' + color: '00ffff' + description: Enabling the use of the software by everyone +- 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 +- name: 'topic: language server' + color: '00ffff' + description: Related to the Arduino Language Server +- name: 'topic: serial monitor' + color: '00ffff' + description: Related to the Serial Monitor +- name: 'topic: theia' + color: '00ffff' + description: Related to the Theia IDE framework +- name: 'topic: theme' + color: '00ffff' + description: Related to GUI theming diff --git a/.github/workflows/assets/linux.Dockerfile b/.github/workflows/assets/linux.Dockerfile new file mode 100644 index 000000000..35d546ca0 --- /dev/null +++ b/.github/workflows/assets/linux.Dockerfile @@ -0,0 +1,112 @@ +# The Arduino IDE Linux build workflow job runs in this container. +# syntax=docker/dockerfile:1 + +FROM ubuntu:18.04 + +# See: https://unofficial-builds.nodejs.org/download/release/ +ARG node_version="18.17.1" + +RUN \ + apt-get \ + --yes \ + update + +# This is required to get add-apt-repository +RUN \ + apt-get \ + --yes \ + install \ + "software-properties-common=0.96.24.32.22" + +# Install Git +# The PPA is required to get a modern version of Git. The version in the Ubuntu 18.04 package repository is 2.17.1, +# while action/checkout@v3 requires 2.18 or higher. +RUN \ + add-apt-repository \ + --yes \ + "ppa:git-core/ppa" && \ + apt-get \ + --yes \ + update && \ + \ + apt-get \ + --yes \ + install \ + "git" && \ + \ + apt-get \ + --yes \ + purge \ + "software-properties-common" + +# The repository path must be added to safe.directory, otherwise any Git operations on it would fail with a +# "dubious ownership" error. actions/checkout configures this, but it is not applied to containers. +RUN \ + git config \ + --add \ + --global \ + "safe.directory" "/__w/arduino-ide/arduino-ide" +ENV \ + GIT_CONFIG_GLOBAL="/root/.gitconfig" + +# Install Python +# The Python installed by actions/setup-python has dependency on a higher version of glibc than available in the +# ubuntu:18.04 container. +RUN \ + apt-get \ + --yes \ + install \ + "python3.8-minimal=3.8.0-3ubuntu1~18.04.2" && \ + \ + ln \ + --symbolic \ + --force \ + "$(which python3.8)" \ + "/usr/bin/python3" + +# Install Theia's package dependencies +# These are pre-installed in the GitHub Actions hosted runner machines. +RUN \ + apt-get \ + --yes \ + install \ + "libsecret-1-dev=0.18.6-1" \ + "libx11-dev=2:1.6.4-3ubuntu0.4" \ + "libxkbfile-dev=1:1.0.9-2" + +# Install Node.js +# It is necessary to use the "unofficial" linux-x64-glibc-217 build because the official Node.js 18.x is dynamically +# linked against glibc 2.28, while Ubuntu 18.04 has glibc 2.27. +ARG node_installation_path="/tmp/node-installation" +ARG artifact_name="node-v${node_version}-linux-x64-glibc-217" +RUN \ + mkdir "$node_installation_path" && \ + cd "$node_installation_path" && \ + \ + apt-get \ + --yes \ + install \ + "wget=1.19.4-1ubuntu2.2" && \ + \ + archive_name="${artifact_name}.tar.xz" && \ + wget \ + "https://unofficial-builds.nodejs.org/download/release/v${node_version}/${archive_name}" && \ + \ + apt-get \ + --yes \ + purge \ + "wget" && \ + \ + tar \ + --file="$archive_name" \ + --extract && \ + rm "$archive_name" +ENV PATH="${PATH}:${node_installation_path}/${artifact_name}/bin" + +# Install Yarn +# Yarn is pre-installed in the GitHub Actions hosted runner machines. +RUN \ + npm \ + install \ + --global \ + "yarn@1.22.19" diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 000000000..54cdcdbbd --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,641 @@ +name: Arduino IDE + +on: + create: + push: + branches: + - main + - '[0-9]+.[0-9]+.x' + paths-ignore: + - '.github/**' + - '!.github/workflows/build.yml' + - '.vscode/**' + - 'docs/**' + - 'scripts/**' + - '!scripts/merge-channel-files.js' + - 'static/**' + - '*.md' + tags: + - '[0-9]+.[0-9]+.[0-9]+*' + workflow_dispatch: + inputs: + paid-runners: + description: Include builds on non-free runners + type: boolean + default: false + pull_request: + paths-ignore: + - '.github/**' + - '!.github/workflows/build.yml' + - '.vscode/**' + - 'docs/**' + - 'scripts/**' + - '!scripts/merge-channel-files.js' + - 'static/**' + - '*.md' + schedule: + - cron: '0 3 * * *' # run every day at 3AM (https://docs.github.com/en/actions/reference/events-that-trigger-workflows#scheduled-events-schedule) + workflow_run: + workflows: + - Push Container Images + branches: + - main + types: + - completed + +env: + # See vars.GO_VERSION field of https://github.com/arduino/arduino-cli/blob/master/DistTasks.yml + GO_VERSION: '1.21' + # See: https://github.com/actions/setup-node/#readme + NODE_VERSION: '18.17' + JOB_TRANSFER_ARTIFACT: build-artifacts + CHANGELOG_ARTIFACTS: changelog + STAGED_CHANNEL_FILES_ARTIFACT: staged-channel-files + BASE_BUILD_DATA: | + - config: + # Human identifier for the job. + name: Windows + runs-on: windows-2019 + # The value is a string representing a JSON document. + # Setting this to null causes the job to run directly in the runner machine instead of in a container. + container: | + null + # Name of the secret that contains the certificate. + certificate-secret: WINDOWS_SIGNING_CERTIFICATE_PFX + # Name of the secret that contains the certificate password. + certificate-password-secret: WINDOWS_SIGNING_CERTIFICATE_PASSWORD + # File extension for the certificate. + certificate-extension: pfx + # Quoting on the value is required here to allow the same comparison expression syntax to be used for this + # and the companion needs.select-targets.outputs.merge-channel-files property (output values always have string + # type). + mergeable-channel-file: 'false' + artifacts: + - path: '*Windows_64bit.exe' + name: Windows_X86-64_interactive_installer + - path: '*Windows_64bit.msi' + name: Windows_X86-64_MSI + - path: '*Windows_64bit.zip' + name: Windows_X86-64_zip + - config: + name: Linux + runs-on: ubuntu-latest + container: | + { + \"image\": \"ghcr.io/arduino/arduino-ide/linux:main\" + } + mergeable-channel-file: 'false' + artifacts: + - path: '*Linux_64bit.zip' + name: Linux_X86-64_zip + - path: '*Linux_64bit.AppImage' + name: Linux_X86-64_app_image + - config: + name: macOS x86 + runs-on: macos-latest + container: | + null + # 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 + certificate-secret: APPLE_SIGNING_CERTIFICATE_P12 + certificate-password-secret: KEYCHAIN_PASSWORD + certificate-extension: p12 + mergeable-channel-file: 'true' + artifacts: + - path: '*macOS_64bit.dmg' + name: macOS_X86-64_dmg + - path: '*macOS_64bit.zip' + name: macOS_X86-64_zip + PAID_RUNNER_BUILD_DATA: | + - config: + name: macOS ARM + runs-on: macos-latest-xlarge + container: | + null + certificate-secret: APPLE_SIGNING_CERTIFICATE_P12 + certificate-password-secret: KEYCHAIN_PASSWORD + certificate-extension: p12 + mergeable-channel-file: 'true' + artifacts: + - path: '*macOS_arm64.dmg' + name: macOS_arm64_dmg + - path: '*macOS_arm64.zip' + name: macOS_arm64_zip + +jobs: + run-determination: + runs-on: ubuntu-latest + outputs: + result: ${{ steps.determination.outputs.result }} + permissions: {} + steps: + - name: Determine if the rest of the workflow should run + id: determination + run: | + RELEASE_BRANCH_REGEX="refs/heads/[0-9]+.[0-9]+.x" + # The `create` event trigger doesn't support `branches` filters, so it's necessary to use Bash instead. + if [[ + "${{ github.event_name }}" != "create" || + "${{ github.ref }}" =~ $RELEASE_BRANCH_REGEX + ]]; then + # Run the other jobs. + RESULT="true" + else + # There is no need to run the other jobs. + RESULT="false" + fi + + echo "result=$RESULT" >> $GITHUB_OUTPUT + + build-type-determination: + needs: run-determination + if: needs.run-determination.outputs.result == 'true' + runs-on: ubuntu-latest + outputs: + is-release: ${{ steps.determination.outputs.is-release }} + is-nightly: ${{ steps.determination.outputs.is-nightly }} + channel-name: ${{ steps.determination.outputs.channel-name }} + publish-to-s3: ${{ steps.determination.outputs.publish-to-s3 }} + permissions: {} + steps: + - name: Determine the type of build + id: determination + run: | + if [[ + "${{ startsWith(github.ref, 'refs/tags/') }}" == "true" + ]]; then + is_release="true" + is_nightly="false" + channel_name="stable" + elif [[ + "${{ github.event_name }}" == "schedule" || + ( + "${{ github.event_name }}" == "workflow_dispatch" && + "${{ github.ref }}" == "refs/heads/main" + ) + ]]; then + is_release="false" + is_nightly="true" + channel_name="nightly" + else + is_release="false" + is_nightly="false" + channel_name="nightly" + fi + + echo "is-release=$is_release" >> $GITHUB_OUTPUT + echo "is-nightly=$is_nightly" >> $GITHUB_OUTPUT + echo "channel-name=$channel_name" >> $GITHUB_OUTPUT + # Only attempt upload to Amazon S3 if the credentials are available. + echo "publish-to-s3=${{ secrets.AWS_SECRET_ACCESS_KEY != '' }}" >> $GITHUB_OUTPUT + + select-targets: + needs: build-type-determination + runs-on: ubuntu-latest + outputs: + artifact-matrix: ${{ steps.assemble.outputs.artifact-matrix }} + build-matrix: ${{ steps.assemble.outputs.build-matrix }} + merge-channel-files: ${{ steps.assemble.outputs.merge-channel-files }} + permissions: {} + steps: + - name: Assemble target data + id: assemble + run: | + # Only run the builds that incur runner charges on release or select manually triggered runs. + if [[ + "${{ needs.build-type-determination.outputs.is-release }}" == "true" || + "${{ github.event.inputs.paid-runners }}" == "true" + ]]; then + build_matrix="$( + ( + echo "${{ env.BASE_BUILD_DATA }}"; + echo "${{ env.PAID_RUNNER_BUILD_DATA }}" + ) | \ + yq \ + --output-format json \ + '[.[].config]' + )" + + artifact_matrix="$( + ( + echo "${{ env.BASE_BUILD_DATA }}"; + echo "${{ env.PAID_RUNNER_BUILD_DATA }}" + ) | \ + yq \ + --output-format json \ + '[.[].artifacts.[]]' + )" + + # The build matrix produces two macOS jobs (x86 and ARM) so the "channel update info files" + # generated by each must be merged. + merge_channel_files="true" + + else + build_matrix="$( + echo "${{ env.BASE_BUILD_DATA }}" | \ + yq \ + --output-format json \ + '[.[].config]' + )" + + artifact_matrix="$( + echo "${{ env.BASE_BUILD_DATA }}" | \ + yq \ + --output-format json \ + '[.[].artifacts.[]]' + )" + + merge_channel_files="false" + fi + + # Set workflow step outputs. + # See: https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#multiline-strings + delimiter="$RANDOM" + echo "build-matrix<<$delimiter" >> $GITHUB_OUTPUT + echo "$build_matrix" >> $GITHUB_OUTPUT + echo "$delimiter" >> $GITHUB_OUTPUT + + delimiter="$RANDOM" + echo "artifact-matrix<<$delimiter" >> $GITHUB_OUTPUT + echo "$artifact_matrix" >> $GITHUB_OUTPUT + echo "$delimiter" >> $GITHUB_OUTPUT + + echo "merge-channel-files=$merge_channel_files" >> $GITHUB_OUTPUT + + build: + name: build (${{ matrix.config.name }}) + needs: + - build-type-determination + - select-targets + env: + # Location of artifacts generated by build. + BUILD_ARTIFACTS_PATH: electron-app/dist/build-artifacts + strategy: + matrix: + config: ${{ fromJson(needs.select-targets.outputs.build-matrix) }} + runs-on: ${{ matrix.config.runs-on }} + container: ${{ fromJSON(matrix.config.container) }} + defaults: + run: + # Avoid problems caused by different default shell for container jobs (sh) vs non-container jobs (bash). + shell: bash + + timeout-minutes: 90 + + steps: + - name: Checkout + if: fromJSON(matrix.config.container) == null + uses: actions/checkout@v4 + + - name: Checkout + # actions/checkout@v4 has dependency on a higher version of glibc than available in the Linux container. + if: fromJSON(matrix.config.container) != null + uses: actions/checkout@v3 + + - name: Install Node.js + if: fromJSON(matrix.config.container) == null + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + registry-url: 'https://registry.npmjs.org' + cache: 'yarn' + + - name: Install Python 3.x + if: fromJSON(matrix.config.container) == null + uses: actions/setup-python@v5 + with: + python-version: '3.11.x' + + - name: Install Go + if: fromJSON(matrix.config.container) == null + uses: actions/setup-go@v5 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Install Go + # actions/setup-go@v5 has dependency on a higher version of glibc than available in the Linux container. + if: fromJSON(matrix.config.container) != null + uses: actions/setup-go@v4 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Install Taskfile + if: fromJSON(matrix.config.container) == null + uses: arduino/setup-task@v2 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + version: 3.x + + - name: Install Taskfile + # actions/setup-task@v2 has dependency on a higher version of glibc than available in the Linux container. + if: fromJSON(matrix.config.container) != null + uses: arduino/setup-task@v1 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + version: 3.x + + - name: Package + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + AC_USERNAME: ${{ secrets.AC_USERNAME }} + AC_PASSWORD: ${{ secrets.AC_PASSWORD }} + AC_TEAM_ID: ${{ secrets.AC_TEAM_ID }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + IS_NIGHTLY: ${{ needs.build-type-determination.outputs.is-nightly }} + IS_RELEASE: ${{ needs.build-type-determination.outputs.is-release }} + CAN_SIGN: ${{ secrets[matrix.config.certificate-secret] != '' }} + # The CREATE_* environment vars are only used to run tests. These secrets are optional. Dependent tests will + # be skipped if not available. + CREATE_USERNAME: ${{ secrets.CREATE_USERNAME }} + CREATE_PASSWORD: ${{ secrets.CREATE_PASSWORD }} + CREATE_CLIENT_SECRET: ${{ secrets.CREATE_CLIENT_SECRET }} + run: | + # See: https://www.electron.build/code-signing + if [ $CAN_SIGN = false ]; then + echo "Skipping the app signing: certificate not provided." + else + 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 + + npx node-gyp install + yarn install --immutable + + yarn --cwd arduino-ide-extension build + yarn test + yarn --cwd arduino-ide-extension test:slow + yarn --cwd arduino-ide-extension lint + + yarn --cwd electron-app rebuild + yarn --cwd electron-app build + yarn --cwd electron-app package + + # Both macOS jobs generate a "channel update info file" with same path and name. The second job to complete would + # overwrite the file generated by the first in the workflow artifact. + - name: Stage channel file for merge + if: > + needs.select-targets.outputs.merge-channel-files == 'true' && + matrix.config.mergeable-channel-file == 'true' + run: | + staged_channel_files_path="${{ runner.temp }}/staged-channel-files" + mkdir "$staged_channel_files_path" + mv \ + "${{ env.BUILD_ARTIFACTS_PATH }}/${{ needs.build-type-determination.outputs.channel-name }}-mac.yml" \ + "${staged_channel_files_path}/${{ needs.build-type-determination.outputs.channel-name }}-mac-${{ runner.arch }}.yml" + + # Set workflow environment variable for use in other steps. + # See: https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#setting-an-environment-variable + echo "STAGED_CHANNEL_FILES_PATH=$staged_channel_files_path" >> "$GITHUB_ENV" + + - name: Upload staged-for-merge channel file artifact + uses: actions/upload-artifact@v3 + if: > + needs.select-targets.outputs.merge-channel-files == 'true' && + matrix.config.mergeable-channel-file == 'true' + with: + if-no-files-found: error + name: ${{ env.STAGED_CHANNEL_FILES_ARTIFACT }} + path: ${{ env.STAGED_CHANNEL_FILES_PATH }} + + - name: Upload [GitHub Actions] + uses: actions/upload-artifact@v3 + with: + name: ${{ env.JOB_TRANSFER_ARTIFACT }} + path: ${{ env.BUILD_ARTIFACTS_PATH }} + + merge-channel-files: + needs: + - build-type-determination + - select-targets + - build + if: needs.select-targets.outputs.merge-channel-files == 'true' + runs-on: ubuntu-latest + permissions: {} + steps: + - name: Set environment variables + run: | + # See: https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#setting-an-environment-variable + echo "CHANNEL_FILES_PATH=${{ runner.temp }}/channel-files" >> "$GITHUB_ENV" + + - name: Checkout + uses: actions/checkout@v4 + + - name: Download staged-for-merge channel files artifact + uses: actions/download-artifact@v3 + with: + name: ${{ env.STAGED_CHANNEL_FILES_ARTIFACT }} + path: ${{ env.CHANNEL_FILES_PATH }} + + - name: Remove no longer needed artifact + uses: geekyeggo/delete-artifact@v2 + with: + name: ${{ env.STAGED_CHANNEL_FILES_ARTIFACT }} + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + registry-url: 'https://registry.npmjs.org' + cache: 'yarn' + + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Install Task + uses: arduino/setup-task@v2 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + version: 3.x + + - name: Install dependencies + run: yarn + + - name: Merge "channel update info files" + run: | + node \ + ./scripts/merge-channel-files.js \ + --channel "${{ needs.build-type-determination.outputs.channel-name }}" \ + --input "${{ env.CHANNEL_FILES_PATH }}" + + - name: Upload merged channel files to job transfer artifact + uses: actions/upload-artifact@v3 + with: + if-no-files-found: error + name: ${{ env.JOB_TRANSFER_ARTIFACT }} + path: ${{ env.CHANNEL_FILES_PATH }} + + artifacts: + name: ${{ matrix.artifact.name }} artifact + needs: + - select-targets + - build + if: always() && needs.build.result != 'skipped' + runs-on: ubuntu-latest + + strategy: + matrix: + artifact: ${{ fromJson(needs.select-targets.outputs.artifact-matrix) }} + + steps: + - name: Download job transfer artifact + uses: actions/download-artifact@v3 + with: + name: ${{ env.JOB_TRANSFER_ARTIFACT }} + path: ${{ env.JOB_TRANSFER_ARTIFACT }} + + - name: Upload tester build artifact + uses: actions/upload-artifact@v3 + with: + name: ${{ matrix.artifact.name }} + path: ${{ env.JOB_TRANSFER_ARTIFACT }}/${{ matrix.artifact.path }} + + changelog: + needs: + - build-type-determination + - build + runs-on: ubuntu-latest + outputs: + BODY: ${{ steps.changelog.outputs.BODY }} + steps: + - name: Checkout + uses: actions/checkout@v4 + with: + fetch-depth: 0 # To fetch all history for all branches and tags. + + - name: Generate Changelog + id: changelog + env: + IS_RELEASE: ${{ needs.build-type-determination.outputs.is-release }} + run: | + export LATEST_TAG=$(git describe --abbrev=0) + export GIT_LOG=$(git log --pretty=" - %s [%h]" $LATEST_TAG..HEAD | sed 's/ *$//g') + if [ "$IS_RELEASE" = true ]; then + export BODY=$(echo -e "$GIT_LOG") + else + export LATEST_TAG_WITH_LINK=$(echo "[$LATEST_TAG](https://github.com/arduino/arduino-ide/releases/tag/$LATEST_TAG)") + if [ -z "$GIT_LOG" ]; then + export BODY="There were no changes since version $LATEST_TAG_WITH_LINK." + else + export BODY=$(echo -e "Changes since version $LATEST_TAG_WITH_LINK:\n$GIT_LOG") + fi + fi + echo -e "$BODY" + + # Set workflow step output + # See: https://docs.github.com/actions/using-workflows/workflow-commands-for-github-actions#multiline-strings + DELIMITER="$RANDOM" + echo "BODY<<$DELIMITER" >> $GITHUB_OUTPUT + echo "$BODY" >> $GITHUB_OUTPUT + echo "$DELIMITER" >> $GITHUB_OUTPUT + + echo "$BODY" > CHANGELOG.txt + + - name: Upload Changelog [GitHub Actions] + if: needs.build-type-determination.outputs.is-nightly == 'true' + uses: actions/upload-artifact@v3 + with: + name: ${{ env.JOB_TRANSFER_ARTIFACT }} + path: CHANGELOG.txt + + publish: + needs: + - build-type-determination + - merge-channel-files + - changelog + if: > + always() && + needs.build-type-determination.result == 'success' && + ( + needs.merge-channel-files.result == 'skipped' || + needs.merge-channel-files.result == 'success' + ) && + needs.changelog.result == 'success' && + needs.build-type-determination.outputs.publish-to-s3 == 'true' && + needs.build-type-determination.outputs.is-nightly == 'true' + runs-on: ubuntu-latest + steps: + - name: Download [GitHub Actions] + uses: actions/download-artifact@v3 + with: + name: ${{ env.JOB_TRANSFER_ARTIFACT }} + path: ${{ env.JOB_TRANSFER_ARTIFACT }} + + - name: Publish Nightly [S3] + uses: docker://plugins/s3 + env: + PLUGIN_SOURCE: '${{ env.JOB_TRANSFER_ARTIFACT }}/*' + PLUGIN_STRIP_PREFIX: '${{ env.JOB_TRANSFER_ARTIFACT }}/' + PLUGIN_TARGET: '/arduino-ide/nightly' + PLUGIN_BUCKET: ${{ secrets.DOWNLOADS_BUCKET }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + + release: + needs: + - build-type-determination + - merge-channel-files + - changelog + if: > + always() && + needs.build-type-determination.result == 'success' && + ( + needs.merge-channel-files.result == 'skipped' || + needs.merge-channel-files.result == 'success' + ) && + needs.changelog.result == 'success' && + needs.build-type-determination.outputs.is-release == 'true' + runs-on: ubuntu-latest + steps: + - name: Download [GitHub Actions] + uses: actions/download-artifact@v3 + with: + name: ${{ env.JOB_TRANSFER_ARTIFACT }} + path: ${{ env.JOB_TRANSFER_ARTIFACT }} + + - name: Get Tag + id: tag_name + run: | + echo "TAG_NAME=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT + + - name: Publish Release [GitHub] + uses: svenstaro/upload-release-action@2.7.0 + with: + repo_token: ${{ secrets.GITHUB_TOKEN }} + release_name: ${{ steps.tag_name.outputs.TAG_NAME }} + file: ${{ env.JOB_TRANSFER_ARTIFACT }}/* + tag: ${{ github.ref }} + file_glob: true + body: ${{ needs.changelog.outputs.BODY }} + + - name: Publish Release [S3] + if: needs.build-type-determination.outputs.publish-to-s3 == 'true' + uses: docker://plugins/s3 + env: + PLUGIN_SOURCE: '${{ env.JOB_TRANSFER_ARTIFACT }}/*' + PLUGIN_STRIP_PREFIX: '${{ env.JOB_TRANSFER_ARTIFACT }}/' + PLUGIN_TARGET: '/arduino-ide' + PLUGIN_BUCKET: ${{ secrets.DOWNLOADS_BUCKET }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} + + clean: + # This job must run after all jobs that use the transfer artifact. + needs: + - build + - merge-channel-files + - publish + - release + - artifacts + if: always() && needs.build.result != 'skipped' + runs-on: ubuntu-latest + + steps: + - name: Remove unneeded job transfer artifact + uses: geekyeggo/delete-artifact@v2 + with: + name: ${{ env.JOB_TRANSFER_ARTIFACT }} diff --git a/.github/workflows/check-certificates.yml b/.github/workflows/check-certificates.yml new file mode 100644 index 000000000..db5ffc09b --- /dev/null +++ b/.github/workflows/check-certificates.yml @@ -0,0 +1,173 @@ +# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/check-certificates.md +name: Check Certificates + +# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows +on: + create: + push: + paths: + - '.github/workflows/check-certificates.ya?ml' + pull_request: + paths: + - '.github/workflows/check-certificates.ya?ml' + schedule: + # Run every 10 hours. + - cron: '0 */10 * * *' + workflow_dispatch: + repository_dispatch: + +env: + # Begin notifications when there are less than this many days remaining before expiration. + EXPIRATION_WARNING_PERIOD: 30 + +jobs: + run-determination: + runs-on: ubuntu-latest + outputs: + result: ${{ steps.determination.outputs.result }} + steps: + - name: Determine if the rest of the workflow should run + id: determination + run: | + RELEASE_BRANCH_REGEX="refs/heads/[0-9]+.[0-9]+.x" + REPO_SLUG="arduino/arduino-ide" + if [[ + ( + # Only run on branch creation when it is a release branch. + # The `create` event trigger doesn't support `branches` filters, so it's necessary to use Bash instead. + "${{ github.event_name }}" != "create" || + "${{ github.ref }}" =~ $RELEASE_BRANCH_REGEX + ) && + ( + # Only run when the workflow will have access to the certificate secrets. + # This could be done via a GitHub Actions workflow conditional, but makes more sense to do it here as well. + ( + "${{ github.event_name }}" != "pull_request" && + "${{ github.repository }}" == "$REPO_SLUG" + ) || + ( + "${{ github.event_name }}" == "pull_request" && + "${{ github.event.pull_request.head.repo.full_name }}" == "$REPO_SLUG" + ) + ) + ]]; then + # Run the other jobs. + RESULT="true" + else + # There is no need to run the other jobs. + RESULT="false" + fi + + echo "result=$RESULT" >> $GITHUB_OUTPUT + + check-certificates: + name: ${{ matrix.certificate.identifier }} + needs: run-determination + if: needs.run-determination.outputs.result == 'true' + runs-on: ubuntu-latest + strategy: + fail-fast: false + + matrix: + certificate: + # Additional certificate definitions can be added to this list. + - identifier: macOS signing certificate # Text used to identify certificate in notifications. + certificate-secret: APPLE_SIGNING_CERTIFICATE_P12 # Name of the secret that contains the certificate. + password-secret: KEYCHAIN_PASSWORD # Name of the secret that contains the certificate password. + - identifier: Windows signing certificate + certificate-secret: WINDOWS_SIGNING_CERTIFICATE_PFX + password-secret: WINDOWS_SIGNING_CERTIFICATE_PASSWORD + + steps: + - name: Set certificate path environment variable + run: | + # See: https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable + echo "CERTIFICATE_PATH=${{ runner.temp }}/certificate.p12" >> "$GITHUB_ENV" + + - name: Decode certificate + env: + CERTIFICATE: ${{ secrets[matrix.certificate.certificate-secret] }} + run: | + echo "${{ env.CERTIFICATE }}" | base64 --decode > "${{ env.CERTIFICATE_PATH }}" + + - name: Verify certificate + env: + CERTIFICATE_PASSWORD: ${{ secrets[matrix.certificate.password-secret] }} + run: | + ( + openssl pkcs12 \ + -in "${{ env.CERTIFICATE_PATH }}" \ + -legacy \ + -noout \ + -passin env:CERTIFICATE_PASSWORD + ) || ( + echo "::error::Verification of ${{ matrix.certificate.identifier }} failed!!!" + exit 1 + ) + + - name: Slack notification of certificate verification failure + if: failure() + env: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + SLACK_MESSAGE: | + :warning::warning::warning::warning: + WARNING: ${{ github.repository }} ${{ matrix.certificate.identifier }} verification failed!!! + :warning::warning::warning::warning: + SLACK_COLOR: danger + MSG_MINIMAL: true + uses: rtCamp/action-slack-notify@v2 + + - name: Get days remaining before certificate expiration date + env: + CERTIFICATE_PASSWORD: ${{ secrets[matrix.certificate.password-secret] }} + id: get-days-before-expiration + run: | + EXPIRATION_DATE="$( + ( + openssl pkcs12 \ + -in "${{ env.CERTIFICATE_PATH }}" \ + -clcerts \ + -legacy \ + -nodes \ + -passin env:CERTIFICATE_PASSWORD + ) | ( + openssl x509 \ + -noout \ + -enddate + ) | ( + grep \ + --max-count=1 \ + --only-matching \ + --perl-regexp \ + 'notAfter=(\K.*)' + ) + )" + + DAYS_BEFORE_EXPIRATION="$((($(date --utc --date="$EXPIRATION_DATE" +%s) - $(date --utc +%s)) / 60 / 60 / 24))" + + # Display the expiration information in the log. + echo "Certificate expiration date: $EXPIRATION_DATE" + echo "Days remaining before expiration: $DAYS_BEFORE_EXPIRATION" + + echo "days=$DAYS_BEFORE_EXPIRATION" >> $GITHUB_OUTPUT + + - name: Check if expiration notification period has been reached + id: check-expiration + run: | + if [[ ${{ steps.get-days-before-expiration.outputs.days }} -lt ${{ env.EXPIRATION_WARNING_PERIOD }} ]]; then + echo "::error::${{ matrix.certificate.identifier }} will expire in ${{ steps.get-days-before-expiration.outputs.days }} days!!!" + exit 1 + fi + + - name: Slack notification of pending certificate expiration + # Don't send spurious expiration notification if verification fails. + if: failure() && steps.check-expiration.outcome == 'failure' + env: + SLACK_WEBHOOK: ${{ secrets.SLACK_WEBHOOK }} + SLACK_MESSAGE: | + :warning::warning::warning::warning: + WARNING: ${{ github.repository }} ${{ matrix.certificate.identifier }} will expire in ${{ steps.get-days-before-expiration.outputs.days }} days!!! + :warning::warning::warning::warning: + SLACK_COLOR: danger + MSG_MINIMAL: true + uses: rtCamp/action-slack-notify@v2 diff --git a/.github/workflows/check-containers.yml b/.github/workflows/check-containers.yml new file mode 100644 index 000000000..21e9c74ee --- /dev/null +++ b/.github/workflows/check-containers.yml @@ -0,0 +1,58 @@ +name: Check Containers + +on: + pull_request: + paths: + - ".github/workflows/check-containers.ya?ml" + - "**.Dockerfile" + - "**/Dockerfile" + push: + paths: + - ".github/workflows/check-containers.ya?ml" + - "**.Dockerfile" + - "**/Dockerfile" + repository_dispatch: + schedule: + # Run periodically to catch breakage caused by external changes. + - cron: "0 7 * * MON" + workflow_dispatch: + +jobs: + run: + name: Run (${{ matrix.image.path }}) + runs-on: ubuntu-latest + permissions: {} + services: + registry: + image: registry:2 + ports: + - 5000:5000 + + env: + IMAGE_NAME: name/app:latest + REGISTRY: localhost:5000 + + strategy: + fail-fast: false + matrix: + image: + - path: .github/workflows/assets/linux.Dockerfile + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Build and push to local registry + uses: docker/build-push-action@v5 + with: + context: . + file: ${{ matrix.image.path }} + push: true + tags: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} + + - name: Run container + run: | + docker \ + run \ + --rm \ + ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }} diff --git a/.github/workflows/check-i18n-task.yml b/.github/workflows/check-i18n-task.yml new file mode 100644 index 000000000..22426313a --- /dev/null +++ b/.github/workflows/check-i18n-task.yml @@ -0,0 +1,85 @@ +name: Check Internationalization + +env: + # See vars.GO_VERSION field of https://github.com/arduino/arduino-cli/blob/master/DistTasks.yml + GO_VERSION: '1.21' + +# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows +on: + create: + push: + paths: + - '.github/workflows/check-i18n-task.ya?ml' + - '**/package.json' + - '**.ts' + - 'i18n/**' + pull_request: + paths: + - '.github/workflows/check-i18n-task.ya?ml' + - '**/package.json' + - '**.ts' + - 'i18n/**' + workflow_dispatch: + repository_dispatch: + +jobs: + run-determination: + runs-on: ubuntu-latest + outputs: + result: ${{ steps.determination.outputs.result }} + permissions: {} + steps: + - name: Determine if the rest of the workflow should run + id: determination + run: | + RELEASE_BRANCH_REGEX="refs/heads/[0-9]+.[0-9]+.x" + TAG_REGEX="refs/tags/.*" + # The `create` event trigger doesn't support `branches` filters, so it's necessary to use Bash instead. + if [[ + ("${{ github.event_name }}" != "create" || + "${{ github.ref }}" =~ $RELEASE_BRANCH_REGEX) && + ! "${{ github.ref }}" =~ $TAG_REGEX + ]]; then + # Run the other jobs. + RESULT="true" + else + # There is no need to run the other jobs. + RESULT="false" + fi + + echo "result=$RESULT" >> $GITHUB_OUTPUT + + check: + needs: run-determination + if: needs.run-determination.outputs.result == 'true' + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Install Node.js 18.17 + uses: actions/setup-node@v4 + with: + node-version: '18.17' + registry-url: 'https://registry.npmjs.org' + cache: 'yarn' + + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Install Taskfile + uses: arduino/setup-task@v2 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + version: 3.x + + - name: Install dependencies + run: yarn install --immutable + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + + - name: Check for errors + run: yarn i18n:check diff --git a/.github/workflows/compose-full-changelog.yml b/.github/workflows/compose-full-changelog.yml new file mode 100644 index 000000000..d126f37f4 --- /dev/null +++ b/.github/workflows/compose-full-changelog.yml @@ -0,0 +1,55 @@ +name: Compose full changelog + +on: + release: + types: + - edited + +env: + CHANGELOG_ARTIFACTS: changelog + # See: https://github.com/actions/setup-node/#readme + NODE_VERSION: '18.17' + +jobs: + create-changelog: + if: github.repository == 'arduino/arduino-ide' + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + registry-url: 'https://registry.npmjs.org' + + - name: Get Tag + id: tag_name + run: | + echo "TAG_NAME=${GITHUB_REF#refs/tags/}" >> $GITHUB_OUTPUT + + - name: Create full changelog + id: full-changelog + run: | + yarn add @octokit/rest@19.0.13 --ignore-workspace-root-check + mkdir "${{ github.workspace }}/${{ env.CHANGELOG_ARTIFACTS }}" + + # Get the changelog file name to build + CHANGELOG_FILE_NAME="${{ steps.tag_name.outputs.TAG_NAME }}-$(date +%s).md" + + # Create manifest file pointing to latest changelog file name + echo "$CHANGELOG_FILE_NAME" >> "${{ github.workspace }}/${{ env.CHANGELOG_ARTIFACTS }}/latest.txt" + + # Compose changelog + yarn run compose-changelog "${{ github.workspace }}/${{ env.CHANGELOG_ARTIFACTS }}/$CHANGELOG_FILE_NAME" + + - name: Publish Changelog [S3] + uses: docker://plugins/s3 + env: + PLUGIN_SOURCE: '${{ env.CHANGELOG_ARTIFACTS }}/*' + PLUGIN_STRIP_PREFIX: '${{ env.CHANGELOG_ARTIFACTS }}/' + PLUGIN_TARGET: '/arduino-ide/changelog' + PLUGIN_BUCKET: ${{ secrets.DOWNLOADS_BUCKET }} + AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }} + AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }} diff --git a/.github/workflows/i18n-nightly-push.yml b/.github/workflows/i18n-nightly-push.yml new file mode 100644 index 000000000..6f401a526 --- /dev/null +++ b/.github/workflows/i18n-nightly-push.yml @@ -0,0 +1,46 @@ +name: i18n-nightly-push + +env: + # See vars.GO_VERSION field of https://github.com/arduino/arduino-cli/blob/master/DistTasks.yml + GO_VERSION: '1.21' + +on: + schedule: + # run every day at 1AM + - cron: '0 1 * * *' + +jobs: + push-to-transifex: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Node.js 18.17 + uses: actions/setup-node@v4 + with: + node-version: '18.17' + registry-url: 'https://registry.npmjs.org' + cache: 'yarn' + + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Install Task + uses: arduino/setup-task@v2 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + version: 3.x + + - name: Install dependencies + run: yarn install --immutable + + - name: Run i18n:push script + run: yarn run i18n:push + env: + TRANSIFEX_ORGANIZATION: ${{ secrets.TRANSIFEX_ORGANIZATION }} + TRANSIFEX_PROJECT: ${{ secrets.TRANSIFEX_PROJECT }} + TRANSIFEX_RESOURCE: ${{ secrets.TRANSIFEX_RESOURCE }} + TRANSIFEX_API_KEY: ${{ secrets.TRANSIFEX_API_KEY }} diff --git a/.github/workflows/i18n-weekly-pull.yml b/.github/workflows/i18n-weekly-pull.yml new file mode 100644 index 000000000..88157a7fa --- /dev/null +++ b/.github/workflows/i18n-weekly-pull.yml @@ -0,0 +1,54 @@ +name: i18n-weekly-pull + +env: + # See vars.GO_VERSION field of https://github.com/arduino/arduino-cli/blob/master/DistTasks.yml + GO_VERSION: '1.21' + +on: + schedule: + # run every monday at 2AM + - cron: '0 2 * * 1' + +jobs: + pull-from-transifex: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Node.js 18.17 + uses: actions/setup-node@v4 + with: + node-version: '18.17' + registry-url: 'https://registry.npmjs.org' + cache: 'yarn' + + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Install Task + uses: arduino/setup-task@v2 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + version: 3.x + + - name: Install dependencies + run: yarn install --immutable + + - name: Run i18n:pull script + run: yarn run i18n:pull + env: + TRANSIFEX_ORGANIZATION: ${{ secrets.TRANSIFEX_ORGANIZATION }} + TRANSIFEX_PROJECT: ${{ secrets.TRANSIFEX_PROJECT }} + TRANSIFEX_RESOURCE: ${{ secrets.TRANSIFEX_RESOURCE }} + TRANSIFEX_API_KEY: ${{ secrets.TRANSIFEX_API_KEY }} + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v5 + with: + commit-message: Updated translation files + title: Update translation files + branch: i18n/translations-update + author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> diff --git a/.github/workflows/push-container-images.yml b/.github/workflows/push-container-images.yml new file mode 100644 index 000000000..52f638bd2 --- /dev/null +++ b/.github/workflows/push-container-images.yml @@ -0,0 +1,70 @@ +name: Push Container Images + +on: + pull_request: + paths: + - ".github/workflows/push-container-images.ya?ml" + push: + paths: + - ".github/workflows/push-container-images.ya?ml" + - "**.Dockerfile" + - "**/Dockerfile" + repository_dispatch: + schedule: + # Run periodically to catch breakage caused by external changes. + - cron: "0 8 * * MON" + workflow_dispatch: + +jobs: + push: + name: Push (${{ matrix.image.name }}) + # Only run the job when GITHUB_TOKEN has the privileges required for Container registry login. + if: > + ( + github.event_name != 'pull_request' && + github.repository == 'arduino/arduino-ide' + ) || + ( + github.event_name == 'pull_request' && + github.event.pull_request.head.repo.full_name == 'arduino/arduino-ide' + ) + runs-on: ubuntu-latest + permissions: + contents: read + packages: write + + strategy: + fail-fast: false + matrix: + image: + - path: .github/workflows/assets/linux.Dockerfile + name: ${{ github.repository }}/linux + registry: ghcr.io + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Log in to the Container registry + uses: docker/login-action@v3 + with: + password: ${{ secrets.GITHUB_TOKEN }} + registry: ${{ matrix.image.registry }} + username: ${{ github.repository_owner }} + + - name: Extract metadata for image + id: metadata + uses: docker/metadata-action@v5 + with: + images: ${{ matrix.image.registry }}/${{ matrix.image.name }} + + - name: Build and push image + uses: docker/build-push-action@v5 + with: + context: . + file: ${{ matrix.image.path }} + labels: ${{ steps.metadata.outputs.labels }} + # Workflow is triggered on relevant events for the sake of a "dry run" validation but image is only pushed to + # registry on commit to the main branch. + push: ${{ github.ref == 'refs/heads/main' }} + tags: ${{ steps.metadata.outputs.tags }} diff --git a/.github/workflows/sync-labels.yml b/.github/workflows/sync-labels.yml new file mode 100644 index 000000000..0ec11e7f3 --- /dev/null +++ b/.github/workflows/sync-labels.yml @@ -0,0 +1,139 @@ +# Source: https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/sync-labels.md +name: Sync Labels + +# See: https://docs.github.com/en/actions/reference/events-that-trigger-workflows +on: + push: + paths: + - '.github/workflows/sync-labels.ya?ml' + - '.github/label-configuration-files/*.ya?ml' + pull_request: + paths: + - '.github/workflows/sync-labels.ya?ml' + - '.github/label-configuration-files/*.ya?ml' + schedule: + # Run daily at 8 AM UTC to sync with changes to shared label configurations. + - cron: '0 8 * * *' + workflow_dispatch: + repository_dispatch: + +env: + CONFIGURATIONS_FOLDER: .github/label-configuration-files + CONFIGURATIONS_ARTIFACT: label-configuration-files + +jobs: + check: + runs-on: ubuntu-latest + + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Download JSON schema for labels configuration file + id: download-schema + uses: carlosperate/download-file-action@v2 + with: + file-url: https://raw.githubusercontent.com/arduino/tooling-project-assets/main/workflow-templates/assets/sync-labels/arduino-tooling-gh-label-configuration-schema.json + location: ${{ runner.temp }}/label-configuration-schema + + - name: Install JSON schema validator + run: | + sudo npm install \ + --global \ + ajv-cli \ + ajv-formats + + - name: Validate local labels configuration + run: | + # See: https://github.com/ajv-validator/ajv-cli#readme + ajv validate \ + --all-errors \ + -c ajv-formats \ + -s "${{ steps.download-schema.outputs.file-path }}" \ + -d "${{ env.CONFIGURATIONS_FOLDER }}/*.{yml,yaml}" + + download: + needs: check + runs-on: ubuntu-latest + + strategy: + matrix: + filename: + # Filenames of the shared configurations to apply to the repository in addition to the local configuration. + # https://github.com/arduino/tooling-project-assets/blob/main/workflow-templates/assets/sync-labels + - universal.yml + - tooling.yml + + steps: + - name: Download + uses: carlosperate/download-file-action@v2 + with: + file-url: https://raw.githubusercontent.com/arduino/tooling-project-assets/main/workflow-templates/assets/sync-labels/${{ matrix.filename }} + + - name: Pass configuration files to next job via workflow artifact + uses: actions/upload-artifact@v3 + with: + path: | + *.yaml + *.yml + if-no-files-found: error + name: ${{ env.CONFIGURATIONS_ARTIFACT }} + + sync: + needs: download + runs-on: ubuntu-latest + + steps: + - name: Set environment variables + run: | + # See: https://docs.github.com/en/actions/reference/workflow-commands-for-github-actions#setting-an-environment-variable + echo "MERGED_CONFIGURATION_PATH=${{ runner.temp }}/labels.yml" >> "$GITHUB_ENV" + + - name: Determine whether to dry run + id: dry-run + if: > + github.event_name == 'pull_request' || + ( + ( + github.event_name == 'push' || + github.event_name == 'workflow_dispatch' + ) && + github.ref != format('refs/heads/{0}', github.event.repository.default_branch) + ) + run: | + # Use of this flag in the github-label-sync command will cause it to only check the validity of the + # configuration. + echo "flag=--dry-run" >> $GITHUB_OUTPUT + + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Download configuration files artifact + uses: actions/download-artifact@v3 + with: + name: ${{ env.CONFIGURATIONS_ARTIFACT }} + path: ${{ env.CONFIGURATIONS_FOLDER }} + + - name: Remove unneeded artifact + uses: geekyeggo/delete-artifact@v2 + with: + name: ${{ env.CONFIGURATIONS_ARTIFACT }} + + - name: Merge label configuration files + run: | + # Merge all configuration files + shopt -s extglob + cat "${{ env.CONFIGURATIONS_FOLDER }}"/*.@(yml|yaml) > "${{ env.MERGED_CONFIGURATION_PATH }}" + + - name: Install github-label-sync + run: sudo npm install --global github-label-sync + + - name: Sync labels + env: + GITHUB_ACCESS_TOKEN: ${{ secrets.GITHUB_TOKEN }} + run: | + # See: https://github.com/Financial-Times/github-label-sync + github-label-sync \ + --labels "${{ env.MERGED_CONFIGURATION_PATH }}" \ + ${{ steps.dry-run.outputs.flag }} \ + ${{ github.repository }} diff --git a/.github/workflows/themes-weekly-pull.yml b/.github/workflows/themes-weekly-pull.yml new file mode 100644 index 000000000..08cc8a41b --- /dev/null +++ b/.github/workflows/themes-weekly-pull.yml @@ -0,0 +1,63 @@ +name: themes-weekly-pull + +on: + schedule: + # run every friday at 5AM + - cron: '0 5 * * 5' + workflow_dispatch: + +env: + # See vars.GO_VERSION field of https://github.com/arduino/arduino-cli/blob/master/DistTasks.yml + GO_VERSION: '1.21' + NODE_VERSION: '18.17' + +jobs: + pull-from-jsonbin: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v4 + + - name: Install Node.js + uses: actions/setup-node@v4 + with: + node-version: ${{ env.NODE_VERSION }} + registry-url: 'https://registry.npmjs.org' + cache: 'yarn' + + - name: Install Go + uses: actions/setup-go@v5 + with: + go-version: ${{ env.GO_VERSION }} + + - name: Install Task + uses: arduino/setup-task@v2 + with: + repo-token: ${{ secrets.GITHUB_TOKEN }} + version: 3.x + + - name: Install dependencies + run: yarn install --immutable + + - name: Run themes:pull script + run: yarn run themes:pull + env: + JSONBIN_MASTER_KEY: ${{ secrets.JSONBIN_MASTER_KEY }} + JSONBIN_ID: ${{ secrets.JSONBIN_ID }} + + - name: Generate dark tokens + run: npx token-transformer scripts/themes/tokens/arduino-tokens.json scripts/themes/tokens/dark.json core,ide-default,ide-dark,theia core,ide-default,ide-dark + + - name: Generate default tokens + run: npx token-transformer scripts/themes/tokens/arduino-tokens.json scripts/themes/tokens/default.json core,ide-default,theia core,ide-default + + - name: Run themes:generate script + run: yarn run themes:generate + + - name: Create Pull Request + uses: peter-evans/create-pull-request@v5 + with: + commit-message: Updated themes + title: Update themes + branch: themes/themes-update + author: github-actions[bot] <41898282+github-actions[bot]@users.noreply.github.com> diff --git a/.gitignore b/.gitignore new file mode 100644 index 000000000..570b7df39 --- /dev/null +++ b/.gitignore @@ -0,0 +1,22 @@ +node_modules/ +lib/ +downloads/ +arduino-ide-extension/src/node/resources +arduino-ide-extension/Examples/ +src-gen/ +gen-webpack.config.js +gen-webpack.node.config.js +.DS_Store +# switching from `electron` to `browser` in dev mode. +.browser_modules +yarn*.log +# For the VS Code extensions used by Theia. +electron-app/plugins +# the tokens folder for the themes +scripts/themes/tokens +# content trace files for electron +electron-app/traces +# any Arduino LS generated log files +inols*.log +# The electron-builder output. +electron-app/dist diff --git a/.prettierignore b/.prettierignore new file mode 100644 index 000000000..0f7b8aa47 --- /dev/null +++ b/.prettierignore @@ -0,0 +1,11 @@ +lib +dist +plugins +src-gen +i18n +gen-webpack* +.browser_modules +arduino-ide-extension/src/node/resources +cli-protocol +*color-theme.json +arduino-icons.json diff --git a/.prettierrc.json b/.prettierrc.json new file mode 100644 index 000000000..686348c10 --- /dev/null +++ b/.prettierrc.json @@ -0,0 +1,28 @@ +{ + "singleQuote": true, + "tabWidth": 2, + "useTabs": false, + "printWidth": 80, + "endOfLine": "auto", + "overrides": [ + { + "files": "*.json", + "options": { + "tabWidth": 2 + } + }, + { + "files": "*.css", + "options": { + "tabWidth": 4, + "singleQuote": false + } + }, + { + "files": "*.html", + "options": { + "tabWidth": 4 + } + } + ] +} diff --git a/.vscode/launch.json b/.vscode/launch.json new file mode 100644 index 000000000..2a8081fb8 --- /dev/null +++ b/.vscode/launch.json @@ -0,0 +1,126 @@ +{ + "version": "0.2.0", + "configurations": [ + { + "type": "node", + "request": "launch", + "name": "App", + "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron", + "windows": { + "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd" + }, + "cwd": "${workspaceFolder}/electron-app", + "args": [ + ".", + "--log-level=debug", + "--hostname=localhost", + "--app-project-path=${workspaceFolder}/electron-app", + "--remote-debugging-port=9222", + "--no-app-auto-install", + "--plugins=local-dir:./plugins", + "--hosted-plugin-inspect=9339", + "--no-ping-timeout" + ], + "env": { + "NODE_ENV": "development" + }, + "sourceMaps": true, + "outFiles": [ + "${workspaceFolder}/electron-app/lib/backend/electron-main.js", + "${workspaceFolder}/electron-app/lib/backend/main.js", + "${workspaceFolder}/electron-app/lib/**/*.js", + "${workspaceFolder}/arduino-ide-extension/lib/**/*.js", + "${workspaceFolder}/node_modules/@theia/**/*.js" + ], + "smartStep": true, + "internalConsoleOptions": "openOnSessionStart", + "outputCapture": "std" + }, + { + "type": "node", + "request": "launch", + "name": "App [Dev]", + "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron", + "windows": { + "runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd" + }, + "cwd": "${workspaceFolder}/electron-app", + "args": [ + ".", + "--log-level=debug", + "--hostname=localhost", + "--app-project-path=${workspaceFolder}/electron-app", + "--remote-debugging-port=9222", + "--no-app-auto-install", + "--plugins=local-dir:./plugins", + "--hosted-plugin-inspect=9339", + "--content-trace", + "--open-devtools", + "--no-ping-timeout" + ], + "env": { + "NODE_ENV": "development" + }, + "sourceMaps": true, + "outFiles": [ + "${workspaceFolder}/electron-app/lib/backend/electron-main.js", + "${workspaceFolder}/electron-app/lib/backend/main.js", + "${workspaceFolder}/electron-app/lib/**/*.js", + "${workspaceFolder}/arduino-ide-extension/lib/**/*.js", + "${workspaceFolder}/node_modules/@theia/**/*.js" + ], + "smartStep": true, + "internalConsoleOptions": "openOnSessionStart", + "outputCapture": "std" + }, + { + "type": "chrome", + "request": "attach", + "name": "Attach to Electron Frontend", + "port": 9222, + "webRoot": "${workspaceFolder}/electron-app" + }, + { + "type": "node", + "request": "launch", + "name": "Run Test [current]", + "program": "${workspaceFolder}/node_modules/mocha/bin/_mocha", + "args": [ + "--require", + "reflect-metadata/Reflect", + "--require", + "ignore-styles", + "--no-timeouts", + "--colors", + "**/${fileBasenameNoExtension}.js" + ], + "outFiles": [ + "${workspaceRoot}/electron-app/src-gen/backend/*.js", + "${workspaceRoot}/electron-app/src-gen/frontend/*.js", + "${workspaceRoot}/electron-app/lib/**/*.js", + "${workspaceRoot}/arduino-ide-extension/lib/**/*.js", + "${workspaceRoot}/node_modules/@theia/**/*.js" + ], + "env": { + "TS_NODE_PROJECT": "${workspaceFolder}/tsconfig.json", + "IDE2_TEST": "true" + }, + "sourceMaps": true, + "smartStep": true, + "internalConsoleOptions": "openOnSessionStart", + "outputCapture": "std" + }, + { + "type": "node", + "request": "attach", + "name": "Attach by Process ID", + "processId": "${command:PickProcess}" + } + ], + "compounds": [ + { + "name": "Launch Electron Backend & Frontend", + "configurations": ["App", "Attach to Electron Frontend"] + } + ] +} diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 000000000..e69e89f6d --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,12 @@ +{ + "files.exclude": { + "**/lib": false + }, + "search.exclude": { + "arduino-ide-extension/src/test/node/__test_sketchbook__": true + }, + "typescript.tsdk": "node_modules/typescript/lib", + "editor.codeActionsOnSave": { + "source.fixAll.eslint": "explicit" + } +} diff --git a/.vscode/tasks.json b/.vscode/tasks.json new file mode 100644 index 000000000..b182867be --- /dev/null +++ b/.vscode/tasks.json @@ -0,0 +1,50 @@ +{ + "version": "2.0.0", + "tasks": [ + { + "label": "Rebuild App", + "type": "shell", + "command": "yarn rebuild", + "group": "build", + "options": { + "cwd": "${workspaceFolder}/electron-app" + }, + "presentation": { + "reveal": "always", + "panel": "new", + "clear": false + } + }, + { + "label": "Watch Extension", + "type": "shell", + "command": "yarn --cwd ./arduino-ide-extension watch", + "group": "build", + "presentation": { + "reveal": "always", + "panel": "new", + "clear": false + } + }, + { + "label": "Watch App", + "type": "shell", + "command": "yarn --cwd ./electron-app watch", + "group": "build", + "presentation": { + "reveal": "always", + "panel": "new", + "clear": false + } + }, + { + "label": "Watch All", + "type": "shell", + "dependsOn": [ + "Watch Extension", + "Watch App" + ], + "problemMatcher": [] + } + ] +} diff --git a/BUILDING.md b/BUILDING.md new file mode 100644 index 000000000..95c05f8f6 --- /dev/null +++ b/BUILDING.md @@ -0,0 +1,3 @@ +# Development Guide + +This documentation has been moved [**here**](docs/development.md#development-guide). diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 000000000..be3f7b28e --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,661 @@ + GNU AFFERO GENERAL PUBLIC LICENSE + Version 3, 19 November 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + + A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + + The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + + An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing under +this license. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU Affero General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Remote Network Interaction; Use with the GNU General Public License. + + Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your version +supports such interaction) an opportunity to receive the Corresponding +Source of your version by providing access to the Corresponding Source +from a network server at no charge, through some standard or customary +means of facilitating copying of software. This Corresponding Source +shall include the Corresponding Source for any work covered by version 3 +of the GNU General Public License that is incorporated pursuant to the +following paragraph. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU Affero General Public License from time to time. Such new versions +will be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for the +specific requirements. + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU AGPL, see +. diff --git a/README.md b/README.md new file mode 100644 index 000000000..68d635a94 --- /dev/null +++ b/README.md @@ -0,0 +1,53 @@ + + +# Arduino IDE 2.x + +[![Arduino IDE](https://github.com/arduino/arduino-ide/workflows/Arduino%20IDE/badge.svg)](https://github.com/arduino/arduino-ide/actions?query=workflow%3A%22Arduino+IDE%22) + +This repository contains the source code of the Arduino IDE 2.x. If you're looking for the old IDE, go to the [repository of the 1.x version](https://github.com/arduino/Arduino). + +The Arduino IDE 2.x is a major rewrite, sharing no code with the IDE 1.x. It is based on the [Theia IDE](https://theia-ide.org/) framework and built with [Electron](https://www.electronjs.org/). The backend operations such as compilation and uploading are offloaded to an [arduino-cli](https://github.com/arduino/arduino-cli) instance running in daemon mode. This new IDE was developed with the goal of preserving the same interface and user experience of the previous major version in order to provide a frictionless upgrade. + +![](static/screenshot.png) + +## Download + +You can download the latest release version and nightly builds from the [software download page on the Arduino website](https://www.arduino.cc/en/software). + +## Support + +If you need assistance, see the [Help Center](https://support.arduino.cc/hc/en-us/categories/360002212660-Software-and-Downloads) and browse the [forum](https://forum.arduino.cc/index.php?board=150.0). + +## Bugs & Issues + +If you want to report an issue, you can submit it to the [issue tracker](https://github.com/arduino/arduino-ide/issues) of this repository. + +See [**the issue report guide**](docs/contributor-guide/issues.md#issue-report-guide) for instructions. + +### Security + +If you think you found a vulnerability or other security-related bug in this project, please read our +[security policy](https://github.com/arduino/arduino-ide/security/policy) and report the bug to our Security Team 🛡️ +Thank you! + +e-mail contact: security@arduino.cc + +## Contributions and development + +Contributions are very welcome! There are several ways to participate in this project, including: + +- Fixing bugs +- Beta testing +- Translation + +See [**the contributor guide**](docs/CONTRIBUTING.md#contributor-guide) for more information. + +See the [**development guide**](docs/development.md) for a technical overview of the application and instructions for building the code. + +## Donations + +This open source code was written by the Arduino team and is maintained on a daily basis with the help of the community. We invest a considerable amount of time in development, testing and optimization. Please consider [donating](https://www.arduino.cc/en/donate/) or [sponsoring](https://github.com/sponsors/arduino) to support our work, as well as [buying original Arduino boards](https://store.arduino.cc/) which is the best way to make sure our effort can continue in the long term. + +## License + +The code contained in this repository and the executable distributions are licensed under the terms of the GNU AGPLv3. The executable distributions contain third-party code licensed under other compatible licenses such as GPLv2, MIT and BSD-3. If you have questions about licensing please contact us at [license@arduino.cc](mailto:license@arduino.cc). diff --git a/arduino-ide-extension/README.md b/arduino-ide-extension/README.md new file mode 100644 index 000000000..e6cd0f8bd --- /dev/null +++ b/arduino-ide-extension/README.md @@ -0,0 +1,86 @@ +## Arduino IDE Extension + +Arduino IDE is based on Theia, and most of its IDE features, UIs and customizations are implemented in this Theia extension. + +### IDE Services + +IDE services typically have a backend part in [src/node/](./src/node/) and a front-end part in [src/browser/](./src/browser/). + +#### Boards Service + +The Boards Service continuously checks the computer's ports, in order to detect when you connect or disconnect an Arduino board. + +The Boards Manager lists all the known board types, and allows downloading new cores to get additional board types. + +- [src/common/protocol/boards-service.ts](./src/common/protocol/boards-service.ts) implements the common classes and interfaces +- [src/node/boards-service-impl.ts](./src/node/boards-service-impl.ts) implements the service backend: + - discovering ports & boards + - searching for compatible board types + - installing new board types +- [src/browser/boards/boards-list-widget.ts](./src/browser/boards/boards-service-client-impl.ts) implements the Boards Manager front-end: + - browsing/searching available board types + - installing new board types + +#### Core Service + +The Core Service is responsible for building your sketches and uploading them to a board. + +- [src/common/protocol/core-service.ts](./src/common/protocol/core-service.ts) implements the common classes and interfaces +- [src/node/core-service-impl.ts](./src/node/core-service-impl.ts) implements the service backend: + - compiling a sketch for a selected board type + - uploading a sketch to a connected board + +#### Serial Service + +The Serial Service allows getting information back from sketches running on your Arduino boards. + +- [src/common/protocol/serial-service.ts](./src/common/protocol/serial-service.ts) implements the common classes and interfaces +- [src/node/serial/serial-service-impl.ts](./src/node/serial/serial-service-impl.ts) implements the service backend: + - connecting to / disconnecting from a board + - receiving and sending data +- [src/browser/serial/serial-connection-manager.ts](./src/browser/serial/serial-connection-manager.ts) handles the serial connection in the frontend +- [src/browser/serial/monitor/monitor-widget.tsx](./src/browser/serial/monitor/monitor-widget.tsx) implements the serial monitor front-end: + - viewing the output from a connected board + - entering data to send to the board +- [src/browser/serial/plotter/plotter-frontend-contribution.ts](./src/browser/serial/plotter/plotter-frontend-contribution.ts) implements the serial plotter front-end: + - opening a new window running the [Serial Plotter Web App](https://github.com/arduino/arduino-serial-plotter-webapp) + +#### Config Service + +The Config Service knows about your system, like for example the default sketch locations. + +- [src/common/protocol/config-service.ts](./src/common/protocol/config-service.ts) implements the common classes and interfaces +- [src/node/config-service-impl.ts](./src/node/config-service-impl.ts) implements the service backend: + - getting the `arduino-cli` version and configuration + - checking whether a file is in a data or sketch directory + +### `"arduino"` configuration in the `package.json`: + +- `"cli"`: + - `"version"` type `string` | `{ owner: string, repo: string, commitish?: string }`: if the type is a `string` and is a valid semver, it will get the corresponding [released](https://github.com/arduino/arduino-cli/releases) CLI. If the type is `string` and is a [date in `YYYYMMDD`](https://arduino.github.io/arduino-cli/latest/installation/#nightly-builds) format, it will get a nightly CLI. If the type is an object, a CLI, build from the sources in the `owner/repo` will be used. If `commitish` is not defined, the HEAD of the default branch will be used. In any other cases an error is thrown. + +#### Rebuild gRPC protocol interfaces + +- Some CLI updates can bring changes to the gRPC interfaces, as the API might change. gRPC interfaces can be updated running the command + `yarn --cwd arduino-ide-extension generate-protocol` + +### Update **clangd** and **ClangFormat** + +The [**clangd** C++ language server](https://clangd.llvm.org/) and the [**ClangFormat** code formatter](https://clang.llvm.org/docs/ClangFormat.html) tool dependencies are managed in parallel. Updating them to a different version is done by the following procedure: + +1. If the target version is not already [available from the `arduino/clang-static-binaries` repository](https://github.com/arduino/clang-static-binaries/releases), submit [an issue there](https://github.com/arduino/clang-static-binaries/issues) requesting a build and wait for that to be completed. +1. Validate the **ClangFormat** configuration for the target version by following the instructions [**here**](https://github.com/arduino/tooling-project-assets/tree/main/other/clang-format-configuration#clangformat-version-updates) +1. Submit a pull request in the `arduino/arduino-ide` repository to update the version in the `arduino.clangd.version` key of [`package.json`](package.json). +1. Submit a pull request in [the `arduino/tooling-project-assets` repository](https://github.com/arduino/tooling-project-assets) to update the version in the `vars.DEFAULT_CLANG_FORMAT_VERSION` field of [`Taskfile.yml`](https://github.com/arduino/tooling-project-assets/blob/main/Taskfile.yml). + +### Customize Icons + +ArduinoIde uses a customized version of FontAwesome. +In order to update/replace icons follow the following steps: + +- import the file `arduino-icons.json` in [Icomoon](https://icomoon.io/app/#/projects) +- load it +- edit the icons as needed +- !! download the **new** `arduino-icons.json` file and put it in this repo +- Click on "Generate Font" in Icomoon, then download +- place the updated fonts in the `src/style/fonts` directory diff --git a/arduino-ide-extension/arduino-icons.json b/arduino-ide-extension/arduino-icons.json new file mode 100644 index 000000000..7c510e9cf --- /dev/null +++ b/arduino-ide-extension/arduino-icons.json @@ -0,0 +1 @@ +{"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 new file mode 100644 index 000000000..d0177911f --- /dev/null +++ b/arduino-ide-extension/package.json @@ -0,0 +1,184 @@ +{ + "name": "arduino-ide-extension", + "version": "3.6.0", + "description": "An extension for Theia building the Arduino IDE", + "license": "AGPL-3.0-or-later", + "scripts": { + "prepare": "yarn download-cli && yarn download-fwuploader && yarn download-ls && yarn copy-i18n && yarn download-examples", + "clean": "rimraf lib", + "compose-changelog": "node ./scripts/compose-changelog.js", + "download-cli": "node ./scripts/download-cli.js", + "download-fwuploader": "node ./scripts/download-fwuploader.js", + "copy-i18n": "ncp ../i18n ./src/node/resources/i18n", + "download-ls": "node ./scripts/download-ls.js", + "download-examples": "node ./scripts/download-examples.js", + "generate-protocol": "node ./scripts/generate-protocol.js", + "lint": "eslint", + "prebuild": "rimraf lib", + "build": "tsc", + "build:dev": "yarn build", + "postbuild": "ncp ./src/node/cli-protocol/ ./lib/node/cli-protocol/", + "watch": "tsc -w", + "test": "cross-env IDE2_TEST=true mocha \"./lib/test/**/*.test.js\"", + "test:slow": "cross-env IDE2_TEST=true mocha \"./lib/test/**/*.slow-test.js\" --slow 5000" + }, + "dependencies": { + "@grpc/grpc-js": "^1.8.14", + "@theia/application-package": "1.41.0", + "@theia/core": "1.41.0", + "@theia/debug": "1.41.0", + "@theia/editor": "1.41.0", + "@theia/electron": "1.41.0", + "@theia/filesystem": "1.41.0", + "@theia/keymaps": "1.41.0", + "@theia/markers": "1.41.0", + "@theia/messages": "1.41.0", + "@theia/monaco": "1.41.0", + "@theia/monaco-editor-core": "1.72.3", + "@theia/navigator": "1.41.0", + "@theia/outline-view": "1.41.0", + "@theia/output": "1.41.0", + "@theia/plugin-ext": "1.41.0", + "@theia/preferences": "1.41.0", + "@theia/scm": "1.41.0", + "@theia/search-in-workspace": "1.41.0", + "@theia/terminal": "1.41.0", + "@theia/typehierarchy": "1.41.0", + "@theia/workspace": "1.41.0", + "@tippyjs/react": "^4.2.5", + "@types/auth0-js": "^9.21.3", + "@types/btoa": "^1.2.3", + "@types/dateformat": "^3.0.1", + "@types/google-protobuf": "^3.7.2", + "@types/js-yaml": "^3.12.2", + "@types/jsdom": "^21.1.1", + "@types/lodash.debounce": "^4.0.6", + "@types/node-fetch": "^2.5.7", + "@types/p-queue": "^2.3.1", + "@types/ps-tree": "^1.1.0", + "@types/react-tabs": "^2.3.2", + "@types/temp": "^0.8.34", + "arduino-serial-plotter-webapp": "0.2.0", + "async-mutex": "^0.3.0", + "auth0-js": "^9.23.2", + "btoa": "^1.2.1", + "classnames": "^2.3.1", + "cross-fetch": "^3.1.5", + "dateformat": "^3.0.3", + "deepmerge": "^4.2.2", + "drivelist": "^9.2.4", + "electron-updater": "^4.6.5", + "fast-deep-equal": "^3.1.3", + "fast-json-stable-stringify": "^2.1.0", + "fast-safe-stringify": "^2.1.1", + "filename-reserved-regex": "^2.0.0", + "glob": "^7.1.6", + "google-protobuf": "^3.20.1", + "hash.js": "^1.1.7", + "is-online": "^10.0.0", + "js-yaml": "^3.13.1", + "jsdom": "^21.1.1", + "jsonc-parser": "^2.2.0", + "just-diff": "^5.1.1", + "jwt-decode": "^3.1.2", + "keytar": "7.2.0", + "lodash.debounce": "^4.0.8", + "minimatch": "^3.1.2", + "node-fetch": "^2.6.1", + "node-log-rotate": "^0.1.5", + "open": "^8.0.6", + "p-debounce": "^2.1.0", + "p-queue": "^2.4.2", + "process": "^0.11.10", + "ps-tree": "^1.2.0", + "query-string": "^7.0.1", + "react-disable": "^0.1.1", + "react-markdown": "^8.0.0", + "react-perfect-scrollbar": "^1.5.8", + "react-select": "^5.6.0", + "react-tabs": "^3.1.2", + "react-window": "^1.8.6", + "semver": "^7.3.2", + "string-natural-compare": "^2.0.3", + "temp": "^0.9.1", + "temp-dir": "^2.0.0", + "tree-kill": "^1.2.1", + "util": "^0.12.5", + "vscode-arduino-api": "^0.1.2" + }, + "devDependencies": { + "@octokit/rest": "^18.12.0", + "@types/chai": "^4.2.7", + "@types/mocha": "^10.0.0", + "@types/react-window": "^1.8.5", + "@xhmikosr/downloader": "^13.0.1", + "chai": "^4.2.0", + "cross-env": "^7.0.3", + "decompress": "^4.2.0", + "decompress-tarbz2": "^4.1.1", + "decompress-targz": "^4.1.1", + "decompress-unzip": "^4.0.1", + "grpc_tools_node_protoc_ts": "^5.3.3", + "mocha": "^10.2.0", + "mockdate": "^3.0.5", + "moment": "^2.24.0", + "ncp": "^2.0.0", + "rimraf": "^2.6.1" + }, + "optionalDependencies": { + "grpc-tools": "^1.12.4", + "protoc": "^1.0.4" + }, + "mocha": { + "require": [ + "reflect-metadata/Reflect", + "ignore-styles" + ], + "reporter": "spec", + "colors": true, + "watch-extensions": "js", + "timeout": 10000 + }, + "files": [ + "lib", + "src", + "build", + "data", + "examples" + ], + "theiaExtensions": [ + { + "preload": "lib/electron-browser/preload" + }, + { + "backend": "lib/node/arduino-ide-backend-module", + "frontend": "lib/browser/arduino-ide-frontend-module" + }, + { + "frontendElectron": "lib/electron-browser/theia/core/electron-menu-module" + }, + { + "frontendElectron": "lib/electron-browser/theia/core/electron-window-module" + }, + { + "frontendElectron": "lib/electron-browser/electron-arduino-module" + }, + { + "electronMain": "lib/electron-main/arduino-electron-main-module" + } + ], + "arduino": { + "arduino-cli": { + "version": "0.35.3" + }, + "arduino-fwuploader": { + "version": "2.4.1" + }, + "arduino-language-server": { + "version": "0.7.6" + }, + "clangd": { + "version": "14.0.0" + } + } +} \ No newline at end of file diff --git a/arduino-ide-extension/scripts/compose-changelog.js b/arduino-ide-extension/scripts/compose-changelog.js new file mode 100644 index 000000000..83095b532 --- /dev/null +++ b/arduino-ide-extension/scripts/compose-changelog.js @@ -0,0 +1,115 @@ +// @ts-check + +(async () => { + const { Octokit } = require('@octokit/rest'); + const fs = require('fs'); + const path = require('path'); + + const octokit = new Octokit({ + userAgent: 'Arduino IDE compose-changelog.js', + }); + + const response = await octokit.rest.repos + .listReleases({ + owner: 'arduino', + repo: 'arduino-ide', + }) + .catch((err) => { + console.error(err); + process.exit(1); + }); + + const releases = response.data; + + let fullChangelog = releases.reduce((acc, item, index) => { + // Process each line separately + const body = item.body.split('\n').map(processLine).join('\n'); + // item.name is the name of the release changelog + return ( + acc + + `## ${item.name}\n\n${body}${index !== releases.length - 1 ? '\n\n---\n\n' : '\n' + }` + ); + }, ''); + + const args = process.argv.slice(2); + if (args.length === 0) { + console.error('Missing argument to destination file'); + process.exit(1); + } + const changelogFile = path.resolve(args[0]); + + await fs.writeFile( + changelogFile, + fullChangelog, + { + flag: 'w+', + }, + (err) => { + if (err) { + console.error(err); + process.exit(1); + } + console.log('Changelog written to', changelogFile); + } + ); +})(); + +// processLine applies different substitutions to line string. +// We're assuming that there are no more than one substitution +// per line to be applied. +const processLine = (line) => { + // Check if a link with one of the following format exists: + // * [#123](https://github.com/arduino/arduino-ide/pull/123) + // * [#123](https://github.com/arduino/arduino-ide/issues/123) + // * [#123](https://github.com/arduino/arduino-ide/pull/123/) + // * [#123](https://github.com/arduino/arduino-ide/issues/123/) + // If it does return the line as is. + let r = + /(\(|\[)#\d+(\)|\])(\(|\[)https:\/\/github\.com\/arduino\/arduino-ide\/(pull|issues)\/(\d+)\/?(\)|\])/gm; + if (r.test(line)) { + return line; + } + + // Check if a issue or PR link with the following format exists: + // * #123 + // If it does it's changed to: + // * [#123](https://github.com/arduino/arduino-ide/pull/123) + r = /(? { + const path = require('path'); + const semver = require('semver'); + const moment = require('moment'); + const downloader = require('./downloader'); + const { taskBuildFromGit } = require('./utils'); + + const version = (() => { + const pkg = require(path.join(__dirname, '..', 'package.json')); + if (!pkg) { + return undefined; + } + + const { arduino } = pkg; + if (!arduino) { + return undefined; + } + + const cli = arduino['arduino-cli']; + if (!cli) { + return undefined; + } + + const { version } = cli; + return version; + })(); + + if (!version) { + console.log(`Could not retrieve CLI version info from the 'package.json'.`); + process.exit(1); + } + + const { platform, arch } = process; + const resourcesFolder = path.join( + __dirname, + '..', + 'src', + 'node', + 'resources' + ); + const cliName = `arduino-cli${platform === 'win32' ? '.exe' : ''}`; + const destinationPath = path.join(resourcesFolder, cliName); + + if (typeof version === 'string') { + const suffix = (() => { + switch (platform) { + case 'darwin': + if (arch === 'arm64') { + return 'macOS_ARM64.tar.gz'; + } + return 'macOS_64bit.tar.gz'; + case 'win32': + return 'Windows_64bit.zip'; + case 'linux': { + switch (arch) { + case 'arm': + return 'Linux_ARMv7.tar.gz'; + case 'arm64': + return 'Linux_ARM64.tar.gz'; + case 'x64': + return 'Linux_64bit.tar.gz'; + default: + return undefined; + } + } + default: + return undefined; + } + })(); + if (!suffix) { + console.log(`The CLI is not available for ${platform} ${arch}.`); + process.exit(1); + } + if (semver.valid(version)) { + const url = `https://downloads.arduino.cc/arduino-cli/arduino-cli_${version}_${suffix}`; + console.log( + `📦 Identified released version of the CLI. Downloading version ${version} from '${url}'` + ); + await downloader.downloadUnzipFile(url, destinationPath, 'arduino-cli'); + } else if (moment(version, 'YYYYMMDD', true).isValid()) { + const url = `https://downloads.arduino.cc/arduino-cli/nightly/arduino-cli_nightly-${version}_${suffix}`; + console.log( + `🌙 Identified nightly version of the CLI. Downloading version ${version} from '${url}'` + ); + await downloader.downloadUnzipFile(url, destinationPath, 'arduino-cli'); + } else { + console.log(`🔥 Could not interpret 'version': ${version}`); + process.exit(1); + } + } else { + taskBuildFromGit(version, destinationPath, 'CLI'); + } +})(); diff --git a/arduino-ide-extension/scripts/download-examples.js b/arduino-ide-extension/scripts/download-examples.js new file mode 100644 index 000000000..557c34089 --- /dev/null +++ b/arduino-ide-extension/scripts/download-examples.js @@ -0,0 +1,119 @@ +// @ts-check + +// The version to use. +const version = '1.10.1'; + +(async () => { + const os = require('node:os'); + const { + existsSync, + promises: fs, + mkdirSync, + readdirSync, + cpSync, + } = require('node:fs'); + const path = require('node:path'); + const { exec } = require('./utils'); + + const destination = path.join( + __dirname, + '..', + 'src', + 'node', + 'resources', + 'Examples' + ); + if (existsSync(destination)) { + console.log( + `Skipping Git checkout of the examples because the repository already exists: ${destination}` + ); + return; + } + + const repository = await fs.mkdtemp( + path.join(os.tmpdir(), 'arduino-examples-') + ); + + exec( + 'git', + ['clone', 'https://github.com/arduino/arduino-examples.git', repository], + { logStdout: true } + ); + + exec( + 'git', + ['-C', repository, 'checkout', `tags/${version}`, '-b', version], + { logStdout: true } + ); + + mkdirSync(destination, { recursive: true }); + const examplesPath = path.join(repository, 'examples'); + const exampleResources = readdirSync(examplesPath); + for (const exampleResource of exampleResources) { + cpSync( + path.join(examplesPath, exampleResource), + path.join(destination, exampleResource), + { recursive: true } + ); + } + + const isSketch = async (pathLike) => { + try { + const names = await fs.readdir(pathLike); + const dirName = path.basename(pathLike); + return names.indexOf(`${dirName}.ino`) !== -1; + } catch (e) { + if (e.code === 'ENOTDIR') { + return false; + } + throw e; + } + }; + const examples = []; + const categories = await fs.readdir(destination); + const visit = async (pathLike, container) => { + const stat = await fs.lstat(pathLike); + if (stat.isDirectory()) { + if (await isSketch(pathLike)) { + container.sketches.push({ + name: path.basename(pathLike), + relativePath: path.relative(destination, pathLike), + }); + } else { + const names = await fs.readdir(pathLike); + for (const name of names) { + const childPath = path.join(pathLike, name); + if (await isSketch(childPath)) { + container.sketches.push({ + name, + relativePath: path.relative(destination, childPath), + }); + } else { + const child = { + label: name, + children: [], + sketches: [], + }; + container.children.push(child); + await visit(childPath, child); + } + } + } + } + }; + for (const category of categories) { + const example = { + label: category, + children: [], + sketches: [], + }; + await visit(path.join(destination, category), example); + examples.push(example); + } + await fs.writeFile( + path.join(destination, 'examples.json'), + JSON.stringify(examples, null, 2), + { encoding: 'utf8' } + ); + console.log(`Generated output to ${path.join(destination, 'examples.json')}`); +})(); diff --git a/arduino-ide-extension/scripts/download-fwuploader.js b/arduino-ide-extension/scripts/download-fwuploader.js new file mode 100644 index 000000000..54b527b1d --- /dev/null +++ b/arduino-ide-extension/scripts/download-fwuploader.js @@ -0,0 +1,102 @@ +// @ts-check + +(async () => { + const path = require('node:path'); + const semver = require('semver'); + const downloader = require('./downloader'); + const { taskBuildFromGit } = require('./utils'); + + const version = (() => { + const pkg = require(path.join(__dirname, '..', 'package.json')); + if (!pkg) { + return undefined; + } + + const { arduino } = pkg; + if (!arduino) { + return undefined; + } + + const fwuploader = arduino['arduino-fwuploader']; + if (!fwuploader) { + return undefined; + } + + const { version } = fwuploader; + return version; + })(); + + if (!version) { + console.log( + `Could not retrieve Firmware Uploader version info from the 'package.json'.` + ); + process.exit(1); + } + + const { platform, arch } = process; + const resourcesFolder = path.join( + __dirname, + '..', + 'src', + 'node', + 'resources' + ); + const fwuploderName = `arduino-fwuploader${ + platform === 'win32' ? '.exe' : '' + }`; + const destinationPath = path.join(resourcesFolder, fwuploderName); + + if (typeof version === 'string') { + const suffix = (() => { + switch (platform) { + case 'darwin': + switch (arch) { + case 'arm64': + return 'macOS_ARM64.tar.gz'; + case 'x64': + return 'macOS_64bit.tar.gz'; + default: + return undefined; + } + case 'win32': + return 'Windows_64bit.zip'; + case 'linux': { + switch (arch) { + case 'arm': + return 'Linux_ARMv7.tar.gz'; + case 'arm64': + return 'Linux_ARM64.tar.gz'; + case 'x64': + return 'Linux_64bit.tar.gz'; + default: + return undefined; + } + } + default: + return undefined; + } + })(); + if (!suffix) { + console.log( + `The Firmware Uploader is not available for ${platform} ${arch}.` + ); + process.exit(1); + } + if (semver.valid(version)) { + const url = `https://downloads.arduino.cc/arduino-fwuploader/arduino-fwuploader_${version}_${suffix}`; + console.log( + `📦 Identified released version of the Firmware Uploader. Downloading version ${version} from '${url}'` + ); + await downloader.downloadUnzipFile( + url, + destinationPath, + 'arduino-fwuploader' + ); + } else { + console.log(`🔥 Could not interpret 'version': ${version}`); + process.exit(1); + } + } else { + taskBuildFromGit(version, destinationPath, 'Firmware Uploader'); + } +})(); diff --git a/arduino-ide-extension/scripts/download-ls.js b/arduino-ide-extension/scripts/download-ls.js new file mode 100644 index 000000000..65aac00e9 --- /dev/null +++ b/arduino-ide-extension/scripts/download-ls.js @@ -0,0 +1,158 @@ +// @ts-check +// The links to the downloads as of today (28.08.2019) are the following: +// - https://downloads.arduino.cc/arduino-language-server/nightly/arduino-language-server_${SUFFIX} +// - https://downloads.arduino.cc/arduino-language-server/clangd/clangd_${VERSION}_${SUFFIX} + +(() => { + const path = require('path'); + const downloader = require('./downloader'); + const { goBuildFromGit } = require('./utils'); + + const [DEFAULT_LS_VERSION, DEFAULT_CLANGD_VERSION] = (() => { + const pkg = require(path.join(__dirname, '..', 'package.json')); + if (!pkg) return [undefined, undefined]; + + const { arduino } = pkg; + if (!arduino) return [undefined, undefined]; + + const { clangd } = arduino; + const languageServer = arduino['arduino-language-server']; + if (!languageServer) return [undefined, undefined]; + if (!clangd) return [undefined, undefined]; + + return [languageServer.version, clangd.version]; + })(); + + if (!DEFAULT_LS_VERSION) { + console.log( + `Could not retrieve Arduino Language Server version info from the 'package.json'.` + ); + process.exit(1); + } + + if (!DEFAULT_CLANGD_VERSION) { + console.log( + `Could not retrieve clangd version info from the 'package.json'.` + ); + process.exit(1); + } + + const yargs = require('@theia/core/shared/yargs') + .option('ls-version', { + alias: 'lv', + default: DEFAULT_LS_VERSION, + describe: `The version of the 'arduino-language-server' to download. Defaults to ${DEFAULT_LS_VERSION}.`, + }) + .option('clangd-version', { + alias: 'cv', + default: DEFAULT_CLANGD_VERSION, + choices: [DEFAULT_CLANGD_VERSION, 'snapshot_20210124'], + describe: `The version of 'clangd' to download. Defaults to ${DEFAULT_CLANGD_VERSION}.`, + }) + .option('force-download', { + alias: 'fd', + default: false, + describe: `If set, this script force downloads the 'arduino-language-server' even if it already exists on the file system.`, + }) + .version(false) + .parse(); + + const lsVersion = yargs['ls-version']; + const clangdVersion = yargs['clangd-version']; + const force = yargs['force-download']; + const { platform, arch } = process; + const platformArch = platform + '-' + arch; + const resourcesFolder = path.join( + __dirname, + '..', + 'src', + 'node', + 'resources' + ); + const lsExecutablePath = path.join( + resourcesFolder, + `arduino-language-server${platform === 'win32' ? '.exe' : ''}` + ); + let clangdExecutablePath, clangFormatExecutablePath, lsSuffix, clangdSuffix; + + switch (platformArch) { + case 'darwin-x64': + clangdExecutablePath = path.join(resourcesFolder, 'clangd'); + clangFormatExecutablePath = path.join(resourcesFolder, 'clang-format'); + lsSuffix = 'macOS_64bit.tar.gz'; + clangdSuffix = 'macOS_64bit'; + break; + case 'darwin-arm64': + clangdExecutablePath = path.join(resourcesFolder, 'clangd'); + clangFormatExecutablePath = path.join(resourcesFolder, 'clang-format'); + lsSuffix = 'macOS_ARM64.tar.gz'; + clangdSuffix = 'macOS_ARM64'; + break; + case 'linux-x64': + clangdExecutablePath = path.join(resourcesFolder, 'clangd'); + clangFormatExecutablePath = path.join(resourcesFolder, 'clang-format'); + lsSuffix = 'Linux_64bit.tar.gz'; + clangdSuffix = 'Linux_64bit'; + break; + case 'linux-arm64': + clangdExecutablePath = path.join(resourcesFolder, 'clangd'); + clangFormatExecutablePath = path.join(resourcesFolder, 'clang-format'); + lsSuffix = 'Linux_ARM64.tar.gz'; + clangdSuffix = 'Linux_ARM64'; + break; + case 'win32-x64': + clangdExecutablePath = path.join(resourcesFolder, 'clangd.exe'); + clangFormatExecutablePath = path.join( + resourcesFolder, + 'clang-format.exe' + ); + lsSuffix = 'Windows_64bit.zip'; + clangdSuffix = 'Windows_64bit'; + break; + default: + throw new Error(`Unsupported platform/arch: ${platformArch}.`); + } + if (!lsSuffix || !clangdSuffix) { + console.log( + `The arduino-language-server is not available for ${platform} ${arch}.` + ); + process.exit(1); + } + + if (typeof lsVersion === 'string') { + const lsUrl = `https://downloads.arduino.cc/arduino-language-server/${lsVersion === 'nightly' + ? 'nightly/arduino-language-server' + : 'arduino-language-server_' + lsVersion + }_${lsSuffix}`; + downloader.downloadUnzipAll( + lsUrl, + resourcesFolder, + lsExecutablePath, + force + ); + } else { + goBuildFromGit(lsVersion, lsExecutablePath, 'language-server'); + } + + const clangdUrl = `https://downloads.arduino.cc/tools/clangd_${clangdVersion}_${clangdSuffix}.tar.bz2`; + downloader.downloadUnzipAll( + clangdUrl, + resourcesFolder, + clangdExecutablePath, + force, + { + strip: 1, + } + ); // `strip`: the new clangd (12.x) is zipped into a folder, so we have to strip the outmost folder. + + const clangdFormatUrl = `https://downloads.arduino.cc/tools/clang-format_${clangdVersion}_${clangdSuffix}.tar.bz2`; + downloader.downloadUnzipAll( + clangdFormatUrl, + resourcesFolder, + clangFormatExecutablePath, + force, + { + strip: 1, + } + ); +})(); diff --git a/arduino-ide-extension/scripts/downloader.js b/arduino-ide-extension/scripts/downloader.js new file mode 100644 index 000000000..dc1939ccc --- /dev/null +++ b/arduino-ide-extension/scripts/downloader.js @@ -0,0 +1,126 @@ +// @ts-check + +const fs = require('fs'); +const path = require('path'); +const decompress = require('decompress'); +const unzip = require('decompress-unzip'); +const untargz = require('decompress-targz'); +const untarbz2 = require('decompress-tarbz2'); + +process.on('unhandledRejection', (reason) => { + console.log(String(reason)); + process.exit(1); +}); +process.on('uncaughtException', (error) => { + console.log(String(error)); + process.exit(1); +}); + +/** + * @param url {string} Download URL + * @param targetFile {string} Path to the file to copy from the decompressed archive + * @param filePrefix {string} Prefix of the file name found in the archive + * @param force {boolean} Whether to download even if the target file exists. `false` by default. + */ +exports.downloadUnzipFile = async ( + url, + targetFile, + filePrefix, + force = false +) => { + if (fs.existsSync(targetFile) && !force) { + console.log(`Skipping download because file already exists: ${targetFile}`); + return; + } + fs.mkdirSync(path.dirname(targetFile), { recursive: true }); + + const downloads = path.join(__dirname, '..', 'downloads'); + fs.rmSync(targetFile, { recursive: true, force: true }); + fs.rmSync(downloads, { recursive: true, force: true }); + + console.log(`>>> Downloading from '${url}'...`); + const data = await download(url); + console.log(`<<< Download succeeded.`); + + console.log('>>> Decompressing...'); + const files = await decompress(data, downloads, { + plugins: [unzip(), untargz(), untarbz2()], + }); + if (files.length === 0) { + console.log('Error ocurred while decompressing the archive.'); + process.exit(1); + } + const fileIndex = files.findIndex((f) => f.path.startsWith(filePrefix)); + if (fileIndex === -1) { + console.log( + `The downloaded artifact does not contain any file with prefix ${filePrefix}.` + ); + process.exit(1); + } + console.log('<<< Decompressing succeeded.'); + + fs.renameSync(path.join(downloads, files[fileIndex].path), targetFile); + if (!fs.existsSync(targetFile)) { + console.log(`Could not find file: ${targetFile}`); + process.exit(1); + } + console.log(`Done: ${targetFile}`); +}; + +/** + * @param url {string} Download URL + * @param targetDir {string} Directory into which to decompress the archive + * @param targetFile {string} Path to the main file expected after decompressing + * @param force {boolean} Whether to download even if the target file exists + * @param decompressOptions {import('decompress').DecompressOptions|undefined} [decompressOptions] + */ +exports.downloadUnzipAll = async ( + url, + targetDir, + targetFile, + force, + decompressOptions = undefined +) => { + if (fs.existsSync(targetFile) && !force) { + console.log(`Skipping download because file already exists: ${targetFile}`); + return; + } + fs.mkdirSync(targetDir, { recursive: true }); + + console.log(`>>> Downloading from '${url}'...`); + const data = await download(url); + console.log(`<<< Download succeeded.`); + + console.log('>>> Decompressing...'); + let options = { + plugins: [unzip(), untargz(), untarbz2()], + }; + if (decompressOptions) { + options = Object.assign(options, decompressOptions); + } + const files = await decompress(data, targetDir, options); + if (files.length === 0) { + console.log('Error ocurred while decompressing the archive.'); + process.exit(1); + } + console.log('<<< Decompressing succeeded.'); + + if (!fs.existsSync(targetFile)) { + console.log(`Could not find file: ${targetFile}`); + process.exit(1); + } + console.log(`Done: ${targetFile}`); +}; + +/** + * @param {string} url + * @returns {Promise} + */ +async function download(url) { + const { default: download } = await import('@xhmikosr/downloader'); + /** @type {import('node:buffer').Buffer} */ + // eslint-disable-next-line @typescript-eslint/ban-ts-comment + // @ts-ignore + const data = await download(url); + return data; +} diff --git a/arduino-ide-extension/scripts/generate-protocol.js b/arduino-ide-extension/scripts/generate-protocol.js new file mode 100644 index 000000000..ec15850b3 --- /dev/null +++ b/arduino-ide-extension/scripts/generate-protocol.js @@ -0,0 +1,193 @@ +// @ts-check + +(async () => { + const os = require('node:os'); + const path = require('node:path'); + const { mkdirSync, promises: fs } = require('node:fs'); + const { exec } = require('./utils'); + const glob = require('glob'); + const { SemVer, gte, valid: validSemVer } = require('semver'); + const protoc = path.dirname(require('protoc/protoc')); + + const repository = await fs.mkdtemp(path.join(os.tmpdir(), 'arduino-cli-')); + + const { owner, repo, commitish } = (() => { + const pkg = require(path.join(__dirname, '..', 'package.json')); + if (!pkg) { + console.log(`Could not parse the 'package.json'.`); + process.exit(1); + } + + const defaultVersion = { + owner: 'arduino', + repo: 'arduino-cli', + commitish: undefined, + }; + const { arduino } = pkg; + if (!arduino) { + return defaultVersion; + } + + const cli = arduino['arduino-cli']; + if (!cli) { + return defaultVersion; + } + + const { version } = cli; + if (!version) { + return defaultVersion; + } + + if (typeof version === 'string') { + return defaultVersion; + } + + // We assume an object with `owner`, `repo`, commitish?` properties. + const { owner, repo, commitish } = version; + if (!owner) { + console.log(`Could not retrieve 'owner' from ${JSON.stringify(version)}`); + process.exit(1); + } + if (!repo) { + console.log(`Could not retrieve 'repo' from ${JSON.stringify(version)}`); + process.exit(1); + } + + return { owner, repo, commitish }; + })(); + + const url = `https://github.com/${owner}/${repo}.git`; + console.log(`>>> Cloning repository from '${url}'...`); + exec('git', ['clone', url, repository], { logStdout: true }); + console.log(`<<< Repository cloned.`); + + const { platform } = process; + const resourcesFolder = path.join( + __dirname, + '..', + 'src', + 'node', + 'resources' + ); + const cli = path.join( + resourcesFolder, + `arduino-cli${platform === 'win32' ? '.exe' : ''}` + ); + const versionJson = exec(cli, ['version', '--format', 'json'], { + logStdout: true, + }).trim(); + if (!versionJson) { + console.log(`Could not retrieve the CLI version from ${cli}.`); + process.exit(1); + } + // As of today (28.01.2021), the `VersionString` can be one of the followings: + // - `nightly-YYYYMMDD` stands for the nightly build, we use the , the `commitish` from the `package.json` to check out the code. + // - `0.0.0-git` for local builds, we use the `commitish` from the `package.json` to check out the code and generate the APIs. + // - `git-snapshot` for local build executed via `task build`. We do not do this. + // - rest, we assume it is a valid semver and has the corresponding tagged code, we use the tag to generate the APIs from the `proto` files. + /* + { + "Application": "arduino-cli", + "VersionString": "nightly-20210126", + "Commit": "079bb6c6", + "Status": "alpha", + "Date": "2021-01-26T01:46:31Z" + } + */ + const versionObject = JSON.parse(versionJson); + let version = versionObject.VersionString; + if (validSemVer(version)) { + // https://github.com/arduino/arduino-cli/pull/2374 + if (gte(new SemVer(version, { loose: true }), new SemVer('0.35.0-rc.1'))) { + version = `v${version}`; + } + console.log(`>>> Checking out tagged version: '${version}'...`); + exec('git', ['-C', repository, 'fetch', '--all', '--tags'], { + logStdout: true, + }); + exec( + 'git', + ['-C', repository, 'checkout', `tags/${version}`, '-b', version], + { logStdout: true } + ); + console.log(`<<< Checked out tagged version: '${version}'.`); + } else if (commitish) { + console.log( + `>>> Checking out commitish from 'package.json': '${commitish}'...` + ); + exec('git', ['-C', repository, 'checkout', commitish], { logStdout: true }); + console.log( + `<<< Checked out commitish from 'package.json': '${commitish}'.` + ); + } else if (versionObject.Commit) { + console.log( + `>>> Checking out commitish from the CLI: '${versionObject.Commit}'...` + ); + exec('git', ['-C', repository, 'checkout', versionObject.Commit], { + logStdout: true, + }); + console.log( + `<<< Checked out commitish from the CLI: '${versionObject.Commit}'.` + ); + } else { + console.log(`WARN: no 'git checkout'. Generating from the HEAD revision.`); + } + + console.log('>>> Generating TS/JS API from:'); + exec('git', ['-C', repository, 'rev-parse', '--abbrev-ref', 'HEAD'], { + logStdout: true, + }); + + const rpc = path.join(repository, 'rpc'); + const out = path.join(__dirname, '..', 'src', 'node', 'cli-protocol'); + mkdirSync(out, { recursive: true }); + + const protos = await new Promise((resolve) => + glob('**/*.proto', { cwd: rpc }, (error, matches) => { + if (error) { + console.log(error.stack ?? error.message); + resolve([]); + return; + } + resolve(matches.map((filename) => path.join(rpc, filename))); + }) + ); + if (!protos || protos.length === 0) { + console.log(`Could not find any .proto files under ${rpc}.`); + process.exit(1); + } + + // Generate JS code from the `.proto` files. + exec( + 'grpc_tools_node_protoc', + [ + `--js_out=import_style=commonjs,binary:${out}`, + `--grpc_out=generate_package_definition:${out}`, + '-I', + rpc, + ...protos, + ], + { logStdout: true } + ); + + // Generate the `.d.ts` files for JS. + exec( + path.join(protoc, `protoc${platform === 'win32' ? '.exe' : ''}`), + [ + `--plugin=protoc-gen-ts=${path.resolve( + __dirname, + '..', + 'node_modules', + '.bin', + `protoc-gen-ts${platform === 'win32' ? '.cmd' : ''}` + )}`, + `--ts_out=generate_package_definition:${out}`, + '-I', + rpc, + ...protos, + ], + { logStdout: true } + ); + + console.log('<<< Generation was successful.'); +})(); diff --git a/arduino-ide-extension/scripts/utils.js b/arduino-ide-extension/scripts/utils.js new file mode 100644 index 000000000..8b06a3cb1 --- /dev/null +++ b/arduino-ide-extension/scripts/utils.js @@ -0,0 +1,143 @@ +// @ts-check + +const exec = ( + /** @type {string} */ command, + /** @type {readonly string[]} */ args, + /** @type {Partial & { logStdout?: boolean }|undefined} */ options = undefined +) => { + try { + const stdout = require('node:child_process').execFileSync(command, args, { + encoding: 'utf8', + ...(options ?? {}), + }); + if (options?.logStdout) { + console.log(stdout.trim()); + } + return stdout; + } catch (err) { + console.log( + `Failed to execute ${command} with args: ${JSON.stringify(args)}` + ); + throw err; + } +}; +exports.exec = exec; + +/** + * Clones something from GitHub and builds it with [`Task`](https://taskfile.dev/). + * + * @param version {object} the version object. + * @param destinationPath {string} the absolute path of the output binary. For example, `C:\\folder\\arduino-cli.exe` or `/path/to/arduino-language-server` + * @param taskName {string} for the CLI logging . Can be `'CLI'` or `'language-server'`, etc. + */ +exports.taskBuildFromGit = (version, destinationPath, taskName) => { + return buildFromGit('task', version, destinationPath, taskName); +}; + +/** + * Clones something from GitHub and builds it with `Golang`. + * + * @param version {object} the version object. + * @param destinationPath {string} the absolute path of the output binary. For example, `C:\\folder\\arduino-cli.exe` or `/path/to/arduino-language-server` + * @param taskName {string} for the CLI logging . Can be `'CLI'` or `'language-server'`, etc. + */ +exports.goBuildFromGit = (version, destinationPath, taskName) => { + return buildFromGit('go', version, destinationPath, taskName); +}; + +/** + * The `command` must be either `'go'` or `'task'`. + * @param {string} command + * @param {{ owner: any; repo: any; commitish: any; }} version + * @param {string} destinationPath + * @param {string} taskName + */ +function buildFromGit(command, version, destinationPath, taskName) { + const fs = require('node:fs'); + const path = require('node:path'); + const temp = require('temp'); + + // We assume an object with `owner`, `repo`, commitish?` properties. + if (typeof version !== 'object') { + console.log( + `Expected a \`{ owner, repo, commitish }\` object. Got <${version}> instead.` + ); + } + const { owner, repo, commitish } = version; + if (!owner) { + console.log(`Could not retrieve 'owner' from ${JSON.stringify(version)}`); + process.exit(1); + } + if (!repo) { + console.log(`Could not retrieve 'repo' from ${JSON.stringify(version)}`); + process.exit(1); + } + const url = `https://github.com/${owner}/${repo}.git`; + console.log( + `Building ${taskName} from ${url}. Commitish: ${ + commitish ? commitish : 'HEAD' + }` + ); + + if (fs.existsSync(destinationPath)) { + console.log( + `Skipping the ${taskName} build because it already exists: ${destinationPath}` + ); + return; + } + + const resourcesFolder = path.join( + __dirname, + '..', + 'src', + 'node', + 'resources' + ); + fs.mkdirSync(resourcesFolder, { recursive: true }); + + const tempRepoPath = temp.mkdirSync(); + console.log(`>>> Cloning ${taskName} source to ${tempRepoPath}...`); + exec('git', ['clone', url, tempRepoPath], { logStdout: true }); + console.log(`<<< Cloned ${taskName} repo.`); + + if (commitish) { + console.log(`>>> Checking out ${commitish}...`); + exec('git', ['-C', tempRepoPath, 'checkout', commitish], { + logStdout: true, + }); + console.log(`<<< Checked out ${commitish}.`); + } + + exec('git', ['-C', tempRepoPath, 'rev-parse', '--short', 'HEAD'], { + logStdout: true, + }); + + console.log(`>>> Building the ${taskName}...`); + exec(command, ['build'], { + cwd: tempRepoPath, + encoding: 'utf8', + logStdout: true, + }); + console.log(`<<< Done ${taskName} build.`); + + const binName = path.basename(destinationPath); + if (!fs.existsSync(path.join(tempRepoPath, binName))) { + console.log( + `Could not find the ${taskName} at ${path.join(tempRepoPath, binName)}.` + ); + process.exit(1); + } + + const binPath = path.join(tempRepoPath, binName); + console.log( + `>>> Copying ${taskName} from ${binPath} to ${destinationPath}...` + ); + fs.copyFileSync(binPath, destinationPath); + console.log(`<<< Copied the ${taskName}.`); + + console.log(`<<< Verifying ${taskName}...`); + if (!fs.existsSync(destinationPath)) { + process.exit(1); + } + console.log(`>>> Verified ${taskName}.`); +} diff --git a/arduino-ide-extension/src/browser/app-service.ts b/arduino-ide-extension/src/browser/app-service.ts new file mode 100644 index 000000000..4598b9fd5 --- /dev/null +++ b/arduino-ide-extension/src/browser/app-service.ts @@ -0,0 +1,16 @@ +import type { Disposable } from '@theia/core/lib/common/disposable'; +import type { AppInfo } from '../electron-common/electron-arduino'; +import type { StartupTasks } from '../electron-common/startup-task'; +import type { Sketch } from './contributions/contribution'; + +export type { AppInfo }; + +export const AppService = Symbol('AppService'); +export interface AppService { + quit(): void; + info(): Promise; + registerStartupTasksHandler( + handler: (tasks: StartupTasks) => void + ): Disposable; + scheduleDeletion(sketch: Sketch): void; // TODO: find a better place +} diff --git a/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx b/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx new file mode 100644 index 000000000..96d53effb --- /dev/null +++ b/arduino-ide-extension/src/browser/arduino-frontend-contribution.tsx @@ -0,0 +1,475 @@ +import { ColorContribution } from '@theia/core/lib/browser/color-application-contribution'; +import { ColorRegistry } from '@theia/core/lib/browser/color-registry'; +import { CommonMenus } from '@theia/core/lib/browser/common-frontend-contribution'; +import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application'; +import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state'; +import { + TabBarToolbarContribution, + TabBarToolbarRegistry, +} from '@theia/core/lib/browser/shell/tab-bar-toolbar'; +import { + ColorTheme, + CssStyleCollector, + StylingParticipant, +} from '@theia/core/lib/browser/styling-service'; +import { + CommandContribution, + CommandRegistry, +} from '@theia/core/lib/common/command'; +import { + MAIN_MENU_BAR, + MenuContribution, + MenuModelRegistry, +} from '@theia/core/lib/common/menu'; +import { MessageService } from '@theia/core/lib/common/message-service'; +import { isHighContrast } from '@theia/core/lib/common/theme'; +import { ElectronWindowPreferences } from '@theia/core/lib/electron-browser/window/electron-window-preferences'; +import { + inject, + injectable, + postConstruct, +} from '@theia/core/shared/inversify'; +import React from '@theia/core/shared/react'; +import { EditorCommands } from '@theia/editor/lib/browser/editor-command'; +import { EditorMainMenu } from '@theia/editor/lib/browser/editor-menu'; +import { MonacoMenus } from '@theia/monaco/lib/browser/monaco-menu'; +import { FileNavigatorCommands } from '@theia/navigator/lib/browser/navigator-contribution'; +import { TerminalMenus } from '@theia/terminal/lib/browser/terminal-frontend-contribution'; +import { BoardsServiceProvider } from './boards/boards-service-provider'; +import { BoardsToolBarItem } from './boards/boards-toolbar-item'; +import { ArduinoMenus } from './menu/arduino-menus'; +import { MonitorViewContribution } from './serial/monitor/monitor-view-contribution'; +import { SerialPlotterContribution } from './serial/plotter/plotter-frontend-contribution'; +import { ArduinoToolbar } from './toolbar/arduino-toolbar'; +import { ResponseService } from '../common/protocol'; + +@injectable() +export class ArduinoFrontendContribution + implements + FrontendApplicationContribution, + TabBarToolbarContribution, + CommandContribution, + MenuContribution, + ColorContribution, + StylingParticipant { + @inject(MessageService) + private readonly messageService: MessageService; + + @inject(BoardsServiceProvider) + private readonly boardsServiceProvider: BoardsServiceProvider; + + @inject(CommandRegistry) + private readonly commandRegistry: CommandRegistry; + + @inject(ElectronWindowPreferences) + private readonly electronWindowPreferences: ElectronWindowPreferences; + + @inject(FrontendApplicationStateService) + private readonly appStateService: FrontendApplicationStateService; + + @inject(ResponseService) + private readonly responseService: ResponseService; + + @postConstruct() + protected init(): void { + if (!window.navigator.onLine) { + // tslint:disable-next-line:max-line-length + // this.messageService.warn( + // nls.localize( + // 'arduino/common/offlineIndicator', + // '你好像离线了。如果没有互联网连接,CLI可能无法下载所需的资源,并可能导致故障。请连接到互联网并重新启动应用程序。' + // ) + // ); + const chunk = + '你好像离线了。如果没有互联网连接,CLI可能无法下载所需的资源,并可能导致故障。请连接到互联网并重新启动应用程序\n'; + this.responseService.appendToOutput({ chunk }); + } + } + + onStart(): void { + this.electronWindowPreferences.onPreferenceChanged((event) => { + if (event.newValue !== event.oldValue) { + switch (event.preferenceName) { + case 'window.zoomLevel': + if (typeof event.newValue === 'number') { + window.electronTheiaCore.setZoomLevel(event.newValue || 0); + } + break; + } + } + }); + this.appStateService.reachedState('ready').then(() => + this.electronWindowPreferences.ready.then(() => { + const zoomLevel = + this.electronWindowPreferences.get('window.zoomLevel'); + window.electronTheiaCore.setZoomLevel(zoomLevel); + }) + ); + } + + registerToolbarItems(registry: TabBarToolbarRegistry): void { + registry.registerItem({ + id: BoardsToolBarItem.TOOLBAR_ID, + render: () => ( + + ), + isVisible: (widget) => + ArduinoToolbar.is(widget) && widget.side === 'left', + priority: 7, + }); + registry.registerItem({ + id: 'toggle-serial-plotter', + command: SerialPlotterContribution.Commands.OPEN_TOOLBAR.id, + tooltip: '串口绘图仪', + }); + registry.registerItem({ + id: 'toggle-serial-monitor', + command: MonitorViewContribution.TOGGLE_SERIAL_MONITOR_TOOLBAR, + tooltip: '串口监视器', + }); + } + + registerCommands(registry: CommandRegistry): void { + for (const command of [ + EditorCommands.SPLIT_EDITOR_DOWN, + EditorCommands.SPLIT_EDITOR_LEFT, + EditorCommands.SPLIT_EDITOR_RIGHT, + EditorCommands.SPLIT_EDITOR_UP, + EditorCommands.SPLIT_EDITOR_VERTICAL, + EditorCommands.SPLIT_EDITOR_HORIZONTAL, + FileNavigatorCommands.REVEAL_IN_NAVIGATOR, + ]) { + registry.unregisterCommand(command); + } + } + + registerMenus(registry: MenuModelRegistry): void { + const menuId = (menuPath: string[]): string => { + const index = menuPath.length - 1; + const menuId = menuPath[index]; + return menuId; + }; + registry.getMenu(MAIN_MENU_BAR).removeNode(menuId(MonacoMenus.SELECTION)); + registry.getMenu(MAIN_MENU_BAR).removeNode(menuId(EditorMainMenu.GO)); + registry.getMenu(MAIN_MENU_BAR).removeNode(menuId(TerminalMenus.TERMINAL)); + registry.getMenu(MAIN_MENU_BAR).removeNode(menuId(CommonMenus.VIEW)); + + registry.registerSubmenu(ArduinoMenus.SKETCH, '项目'); + registry.registerSubmenu(ArduinoMenus.TOOLS, '工具'); + } + + registerColors(colors: ColorRegistry): void { + colors.register( + { + id: 'arduino.toolbar.button.background', + defaults: { + dark: 'button.background', + light: 'button.background', + hcDark: 'activityBar.inactiveForeground', + hcLight: 'activityBar.inactiveForeground', + }, + description: + 'Background color of the toolbar items. Such as Upload, Verify, etc.', + }, + { + id: 'arduino.toolbar.button.hoverBackground', + defaults: { + dark: 'button.hoverBackground', + light: 'button.hoverBackground', + hcDark: 'button.background', + hcLight: 'button.background', + }, + description: + 'Background color of the toolbar items when hovering over them. Such as Upload, Verify, etc.', + }, + { + id: 'arduino.toolbar.button.secondary.label', + defaults: { + dark: 'secondaryButton.foreground', + light: 'button.foreground', + hcDark: 'activityBar.inactiveForeground', + hcLight: 'activityBar.inactiveForeground', + }, + description: + 'Foreground color of the toolbar items. Such as Serial Monitor and Serial Plotter', + }, + { + id: 'arduino.toolbar.button.secondary.hoverBackground', + defaults: { + dark: 'secondaryButton.hoverBackground', + light: 'button.hoverBackground', + hcDark: 'textLink.foreground', + hcLight: 'textLink.foreground', + }, + description: + 'Background color of the toolbar items when hovering over them, such as "Serial Monitor" and "Serial Plotter"', + }, + { + id: 'arduino.toolbar.toggleBackground', + defaults: { + dark: 'editor.selectionBackground', + light: 'editor.selectionBackground', + hcDark: 'textPreformat.foreground', + hcLight: 'textPreformat.foreground', + }, + description: + 'Toggle color of the toolbar items when they are currently toggled (the command is in progress)', + }, + { + id: 'arduino.toolbar.dropdown.border', + defaults: { + dark: 'dropdown.border', + light: 'dropdown.border', + hcDark: 'dropdown.border', + hcLight: 'dropdown.border', + }, + description: 'Border color of the Board Selector.', + }, + { + id: 'arduino.toolbar.dropdown.borderActive', + defaults: { + dark: 'focusBorder', + light: 'focusBorder', + hcDark: 'focusBorder', + hcLight: 'focusBorder', + }, + description: "Border color of the Board Selector when it's active", + }, + { + id: 'arduino.toolbar.dropdown.background', + defaults: { + dark: 'tab.unfocusedActiveBackground', + light: 'dropdown.background', + hcDark: 'dropdown.background', + hcLight: 'dropdown.background', + }, + description: 'Background color of the Board Selector.', + }, + { + id: 'arduino.toolbar.dropdown.label', + defaults: { + dark: 'dropdown.foreground', + light: 'dropdown.foreground', + hcDark: 'dropdown.foreground', + hcLight: 'dropdown.foreground', + }, + description: 'Font color of the Board Selector.', + }, + { + id: 'arduino.toolbar.dropdown.iconSelected', + defaults: { + dark: 'list.activeSelectionIconForeground', + light: 'list.activeSelectionIconForeground', + hcDark: 'list.activeSelectionIconForeground', + hcLight: 'list.activeSelectionIconForeground', + }, + description: + 'Color of the selected protocol icon in the Board Selector.', + }, + { + id: 'arduino.toolbar.dropdown.option.backgroundHover', + defaults: { + dark: 'list.hoverBackground', + light: 'list.hoverBackground', + hcDark: 'list.hoverBackground', + hcLight: 'list.hoverBackground', + }, + description: 'Background color on hover of the Board Selector options.', + }, + { + id: 'arduino.toolbar.dropdown.option.backgroundSelected', + defaults: { + dark: 'list.activeSelectionBackground', + light: 'list.activeSelectionBackground', + hcDark: 'list.activeSelectionBackground', + hcLight: 'list.activeSelectionBackground', + }, + description: + 'Background color of the selected board in the Board Selector.', + } + ); + } + + registerThemeStyle(theme: ColorTheme, collector: CssStyleCollector): void { + const warningForeground = theme.getColor('warningForeground'); + const warningBackground = theme.getColor('warningBackground'); + const focusBorder = theme.getColor('focusBorder'); + const contrastBorder = theme.getColor('contrastBorder'); + const notificationsBackground = theme.getColor('notifications.background'); + const buttonBorder = theme.getColor('button.border'); + const buttonBackground = theme.getColor('button.background') || 'none'; + const dropdownBackground = theme.getColor('dropdown.background'); + const arduinoToolbarButtonBackground = theme.getColor( + 'arduino.toolbar.button.background' + ); + if (isHighContrast(theme.type)) { + // toolbar items + collector.addRule(` + .p-TabBar-toolbar .item.arduino-tool-item.enabled:hover > div.toggle-serial-monitor, + .p-TabBar-toolbar .item.arduino-tool-item.enabled:hover > div.toggle-serial-plotter { + background: transparent; + } + `); + if (contrastBorder) { + collector.addRule(` + .quick-input-widget { + outline: 1px solid ${contrastBorder}; + outline-offset: -1px; + } + `); + } + if (focusBorder) { + // customized react-select widget + collector.addRule(` + .arduino-select__option--is-selected { + outline: 1px solid ${focusBorder}; + } + `); + collector.addRule(` + .arduino-select__option--is-focused { + outline: 1px dashed ${focusBorder}; + } + `); + // boards selector dropdown + collector.addRule(` + #select-board-dialog .selectBoardContainer .list .item:hover { + outline: 1px dashed ${focusBorder}; + } + `); + // button hover + collector.addRule(` + .theia-button:hover, + button.theia-button:hover { + outline: 1px dashed ${focusBorder}; + } + `); + collector.addRule(` + .theia-button { + border: 1px solid ${focusBorder}; + } + `); + collector.addRule(` + .component-list-item .header .installed-version:hover:before { + background-color: transparent; + outline: 1px dashed ${focusBorder}; + } + `); + // tree node + collector.addRule(` + .theia-TreeNode:hover { + outline: 1px dashed ${focusBorder}; + } + `); + collector.addRule(` + .quick-input-list .monaco-list-row.focused, + .theia-Tree .theia-TreeNode.theia-mod-selected { + outline: 1px dotted ${focusBorder}; + } + `); + collector.addRule(` + div#select-board-dialog .selectBoardContainer .list .item.selected, + .theia-Tree:focus .theia-TreeNode.theia-mod-selected, + .theia-Tree .ReactVirtualized__List:focus .theia-TreeNode.theia-mod-selected { + outline: 1px solid ${focusBorder}; + } + `); + // quick input + collector.addRule(` + .quick-input-list .monaco-list-row:hover { + outline: 1px dashed ${focusBorder}; + } + `); + // editor tab-bar + collector.addRule(` + .p-TabBar.theia-app-centers .p-TabBar-tab.p-mod-closable > .p-TabBar-tabCloseIcon:hover { + outline: 1px dashed ${focusBorder}; + } + `); + collector.addRule(` + #theia-main-content-panel .p-TabBar .p-TabBar-tab:hover { + outline: 1px dashed ${focusBorder}; + outline-offset: -4px; + } + `); + collector.addRule(` + #theia-main-content-panel .p-TabBar .p-TabBar-tab.p-mod-current { + outline: 1px solid ${focusBorder}; + outline-offset: -4px; + } + `); + // boards selector dropdown + collector.addRule(` + .arduino-boards-dropdown-item:hover { + outline: 1px dashed ${focusBorder}; + outline-offset: -2px; + } + `); + if (notificationsBackground) { + // notification + collector.addRule(` + .theia-notification-list-item:hover:not(:focus) { + background-color: ${notificationsBackground}; + outline: 1px dashed ${focusBorder}; + outline-offset: -2px; + } + `); + } + if (arduinoToolbarButtonBackground) { + // toolbar item + collector.addRule(` + .item.arduino-tool-item.toggled .arduino-upload-sketch--toolbar, + .item.arduino-tool-item.toggled .arduino-verify-sketch--toolbar { + background-color: ${arduinoToolbarButtonBackground} !important; + outline: 1px solid ${focusBorder}; + } + `); + collector.addRule(` + .p-TabBar-toolbar .item.arduino-tool-item.enabled:hover > div { + background: ${arduinoToolbarButtonBackground}; + outline: 1px dashed ${focusBorder}; + } + `); + } + } + if (dropdownBackground) { + // boards selector dropdown + collector.addRule(` + .arduino-boards-dropdown-item:hover { + background: ${dropdownBackground}; + } + `); + } + if (warningForeground && warningBackground) { + // widget with inverted foreground and background colors + collector.addRule(` + .theia-input.warning:focus, + .theia-input.warning::placeholder, + .theia-input.warning { + color: ${warningBackground}; + background-color: ${warningForeground}; + } + `); + } + if (buttonBorder) { + collector.addRule(` + button.theia-button, + button.theia-button.secondary, + .component-list-item .theia-button.secondary.no-border, + .component-list-item .theia-button.secondary.no-border:hover { + border: 1px solid ${buttonBorder}; + } + `); + collector.addRule(` + .component-list-item .header .installed-version:before { + color: ${buttonBackground}; + border: 1px solid ${buttonBorder}; + } + `); + } + } + } +} diff --git a/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts b/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts new file mode 100644 index 000000000..e6d2a9d4a --- /dev/null +++ b/arduino-ide-extension/src/browser/arduino-ide-frontend-module.ts @@ -0,0 +1,1174 @@ +import '../../src/browser/style/index.css'; +import { Container, ContainerModule } from '@theia/core/shared/inversify'; +import { WidgetFactory } from '@theia/core/lib/browser/widget-manager'; +import { CommandContribution } from '@theia/core/lib/common/command'; +import { bindViewContribution } from '@theia/core/lib/browser/shell/view-contribution'; +import { TabBarToolbarContribution } from '@theia/core/lib/browser/shell/tab-bar-toolbar'; +import { WebSocketConnectionProvider } from '@theia/core/lib/browser/messaging/ws-connection-provider'; +import { + FrontendApplicationContribution, + FrontendApplication as TheiaFrontendApplication, +} from '@theia/core/lib/browser/frontend-application'; +import { LibraryListWidget } from './library/library-list-widget'; +import { ArduinoFrontendContribution } from './arduino-frontend-contribution'; +import { + LibraryService, + LibraryServicePath, +} from '../common/protocol/library-service'; +import { + BoardsService, + BoardsServicePath, +} from '../common/protocol/boards-service'; +import { + SketchesService, + SketchesServicePath, +} from '../common/protocol/sketches-service'; +import { SketchesServiceClientImpl } from './sketches-service-client-impl'; +import { CoreService, CoreServicePath } from '../common/protocol/core-service'; +import { BoardsListWidget } from './boards/boards-list-widget'; +import { BoardsListWidgetFrontendContribution } from './boards/boards-widget-frontend-contribution'; +import { + BoardListDumper, + BoardsServiceProvider, +} from './boards/boards-service-provider'; +import { WorkspaceService as TheiaWorkspaceService } from '@theia/workspace/lib/browser/workspace-service'; +import { WorkspaceService } from './theia/workspace/workspace-service'; +import { OutlineViewContribution as TheiaOutlineViewContribution } from '@theia/outline-view/lib/browser/outline-view-contribution'; +import { OutlineViewContribution } from './theia/outline/outline-contribution'; +import { ProblemContribution as TheiaProblemContribution } from '@theia/markers/lib/browser/problem/problem-contribution'; +import { ProblemContribution } from './theia/markers/problem-contribution'; +import { FileNavigatorContribution } from './theia/navigator/navigator-contribution'; +import { FileNavigatorContribution as TheiaFileNavigatorContribution } from '@theia/navigator/lib/browser/navigator-contribution'; +import { KeymapsFrontendContribution } from './theia/keymaps/keymaps-frontend-contribution'; +import { KeymapsFrontendContribution as TheiaKeymapsFrontendContribution } from '@theia/keymaps/lib/browser/keymaps-frontend-contribution'; +import { ArduinoToolbarContribution } from './toolbar/arduino-toolbar-contribution'; +import { EditorContribution as TheiaEditorContribution } from '@theia/editor/lib/browser/editor-contribution'; +import { EditorContribution } from './theia/editor/editor-contribution'; +import { MonacoStatusBarContribution as TheiaMonacoStatusBarContribution } from '@theia/monaco/lib/browser/monaco-status-bar-contribution'; +import { MonacoStatusBarContribution } from './theia/monaco/monaco-status-bar-contribution'; +import { + ApplicationShell as TheiaApplicationShell, + ShellLayoutRestorer as TheiaShellLayoutRestorer, + CommonFrontendContribution as TheiaCommonFrontendContribution, + DockPanelRenderer as TheiaDockPanelRenderer, + TabBarRendererFactory, + ContextMenuRenderer, +} from '@theia/core/lib/browser'; +import { MenuContribution } from '@theia/core/lib/common/menu'; + +import { FrontendApplication } from './theia/core/frontend-application'; +import { + BoardsConfigDialog, + BoardsConfigDialogProps, +} from './boards/boards-config-dialog'; +import { ScmContribution as TheiaScmContribution } from '@theia/scm/lib/browser/scm-contribution'; +import { ScmContribution } from './theia/scm/scm-contribution'; +import { SearchInWorkspaceFrontendContribution as TheiaSearchInWorkspaceFrontendContribution } from '@theia/search-in-workspace/lib/browser/search-in-workspace-frontend-contribution'; +import { SearchInWorkspaceFrontendContribution } from './theia/search-in-workspace/search-in-workspace-frontend-contribution'; +import { LibraryListWidgetFrontendContribution } from './library/library-widget-frontend-contribution'; +import { + ConfigService, + ConfigServicePath, +} from '../common/protocol/config-service'; +import { MonitorWidget } from './serial/monitor/monitor-widget'; +import { MonitorViewContribution } from './serial/monitor/monitor-view-contribution'; +import { TabBarDecoratorService as TheiaTabBarDecoratorService } from '@theia/core/lib/browser/shell/tab-bar-decorator'; +import { TabBarDecoratorService } from './theia/core/tab-bar-decorator'; +import { ProblemManager as TheiaProblemManager } from '@theia/markers/lib/browser'; +import { ProblemManager } from './theia/markers/problem-manager'; +import { BoardsAutoInstaller } from './boards/boards-auto-installer'; +import { ShellLayoutRestorer } from './theia/core/shell-layout-restorer'; +import { + ArduinoComponentContextMenuRenderer, + ListItemRenderer, +} from './widgets/component-list/list-item-renderer'; +import { ColorContribution } from '@theia/core/lib/browser/color-application-contribution'; + +import { + ArduinoDaemonPath, + ArduinoDaemon, +} from '../common/protocol/arduino-daemon'; +import { EditorCommandContribution as TheiaEditorCommandContribution } from '@theia/editor/lib/browser'; +import { + FrontendConnectionStatusService, + ApplicationConnectionStatusContribution, + DaemonPort, + IsOnline, +} from './theia/core/connection-status-service'; +import { + FrontendConnectionStatusService as TheiaFrontendConnectionStatusService, + ApplicationConnectionStatusContribution as TheiaApplicationConnectionStatusContribution, +} from '@theia/core/lib/browser/connection-status-service'; +import { BoardsDataMenuUpdater } from './contributions/boards-data-menu-updater'; +import { BoardsDataStore } from './boards/boards-data-store'; +import { ILogger } from '@theia/core/lib/common/logger'; +import { bindContributionProvider } from '@theia/core/lib/common/contribution-provider'; +import { + FileSystemExt, + FileSystemExtPath, +} from '../common/protocol/filesystem-ext'; +import { + WorkspaceFrontendContribution as TheiaWorkspaceFrontendContribution, + FileMenuContribution as TheiaFileMenuContribution, + WorkspaceCommandContribution as TheiaWorkspaceCommandContribution, +} from '@theia/workspace/lib/browser'; +import { + WorkspaceFrontendContribution, + ArduinoFileMenuContribution, +} from './theia/workspace/workspace-frontend-contribution'; +import { Contribution } from './contributions/contribution'; +import { NewSketch } from './contributions/new-sketch'; +import { OpenSketch } from './contributions/open-sketch'; +import { Close } from './contributions/close'; +import { SaveAsSketch } from './contributions/save-as-sketch'; +import { SaveSketch } from './contributions/save-sketch'; +import { VerifySketch } from './contributions/verify-sketch'; +import { UploadSketch } from './contributions/upload-sketch'; +import { CommonFrontendContribution } from './theia/core/common-frontend-contribution'; +import { EditContributions } from './contributions/edit-contributions'; +import { OpenSketchExternal } from './contributions/open-sketch-external'; +import { PreferencesContribution as TheiaPreferencesContribution } from '@theia/preferences/lib/browser/preferences-contribution'; +import { PreferencesContribution } from './theia/preferences/preferences-contribution'; +import { QuitApp } from './contributions/quit-app'; +import { SketchControl } from './contributions/sketch-control'; +import { OpenSettings } from './contributions/open-settings'; +import { WorkspaceCommandContribution } from './theia/workspace/workspace-commands'; +import { WorkspaceDeleteHandler as TheiaWorkspaceDeleteHandler } from '@theia/workspace/lib/browser/workspace-delete-handler'; +import { WorkspaceDeleteHandler } from './theia/workspace/workspace-delete-handler'; +import { EditorWidgetFactory as TheiaEditorWidgetFactory } from '@theia/editor/lib/browser/editor-widget-factory'; +import { EditorWidgetFactory } from './theia/editor/editor-widget-factory'; +import { BurnBootloader } from './contributions/burn-bootloader'; +import { + ExamplesServicePath, + ExamplesService, +} from '../common/protocol/examples-service'; +import { BuiltInExamples, LibraryExamples } from './contributions/examples'; +import { IncludeLibrary } from './contributions/include-library'; +import { OutputChannelManager as TheiaOutputChannelManager } from '@theia/output/lib/browser/output-channel'; +import { OutputChannelManager } from './theia/output/output-channel'; +import { + OutputChannelRegistryMainImpl as TheiaOutputChannelRegistryMainImpl, + OutputChannelRegistryMainImpl, +} from './theia/plugin-ext/output-channel-registry-main'; +import { + ExecutableService, + ExecutableServicePath, + MonitorManagerProxy, + MonitorManagerProxyClient, + MonitorManagerProxyFactory, + MonitorManagerProxyPath, +} from '../common/protocol'; +import { MonacoTextModelService as TheiaMonacoTextModelService } from '@theia/monaco/lib/browser/monaco-text-model-service'; +import { MonacoTextModelService } from './theia/monaco/monaco-text-model-service'; +import { ResponseServiceImpl } from './response-service-impl'; +import { + ResponseService, + ResponseServiceClient, + ResponseServicePath, +} from '../common/protocol/response-service'; +import { NotificationCenter } from './notification-center'; +import { + NotificationServicePath, + NotificationServiceServer, +} from '../common/protocol'; +import { About } from './contributions/about'; +import { IconThemeService } from '@theia/core/lib/browser/icon-theme-service'; +import { TabBarRenderer } from './theia/core/tab-bars'; +import { EditorCommandContribution } from './theia/editor/editor-command'; +import { NavigatorTabBarDecorator as TheiaNavigatorTabBarDecorator } from '@theia/navigator/lib/browser/navigator-tab-bar-decorator'; +import { NavigatorTabBarDecorator } from './theia/navigator/navigator-tab-bar-decorator'; +import { Debug, DebugDisabledStatusMessageSource } from './contributions/debug'; +import { Sketchbook } from './contributions/sketchbook'; +import { DebugFrontendApplicationContribution } from './theia/debug/debug-frontend-application-contribution'; +import { DebugFrontendApplicationContribution as TheiaDebugFrontendApplicationContribution } from '@theia/debug/lib/browser/debug-frontend-application-contribution'; +import { BoardSelection } from './contributions/board-selection'; +import { OpenRecentSketch } from './contributions/open-recent-sketch'; +import { Help } from './contributions/help'; +import { bindArduinoPreferences } from './arduino-preferences'; +import { SettingsService } from './dialogs/settings/settings'; +import { + SettingsDialog, + SettingsWidget, + SettingsDialogProps, +} from './dialogs/settings/settings-dialog'; +import { AddFile } from './contributions/add-file'; +import { ArchiveSketch } from './contributions/archive-sketch'; +import { OutputToolbarContribution as TheiaOutputToolbarContribution } from '@theia/output/lib/browser/output-toolbar-contribution'; +import { OutputToolbarContribution } from './theia/output/output-toolbar-contribution'; +import { AddZipLibrary } from './contributions/add-zip-library'; +import { WorkspaceVariableContribution as TheiaWorkspaceVariableContribution } from '@theia/workspace/lib/browser/workspace-variable-contribution'; +import { WorkspaceVariableContribution } from './theia/workspace/workspace-variable-contribution'; +import { DebugConfigurationManager } from './theia/debug/debug-configuration-manager'; +import { DebugConfigurationManager as TheiaDebugConfigurationManager } from '@theia/debug/lib/browser/debug-configuration-manager'; +import { SearchInWorkspaceFactory as TheiaSearchInWorkspaceFactory } from '@theia/search-in-workspace/lib/browser/search-in-workspace-factory'; +import { SearchInWorkspaceFactory } from './theia/search-in-workspace/search-in-workspace-factory'; +import { MonacoEditorProvider } from './theia/monaco/monaco-editor-provider'; +import { + MonacoEditorFactory, + MonacoEditorProvider as TheiaMonacoEditorProvider, +} from '@theia/monaco/lib/browser/monaco-editor-provider'; +import { NotificationManager } from './theia/messages/notifications-manager'; +import { NotificationManager as TheiaNotificationManager } from '@theia/messages/lib/browser/notifications-manager'; +import { NotificationsRenderer as TheiaNotificationsRenderer } from '@theia/messages/lib/browser/notifications-renderer'; +import { NotificationsRenderer } from './theia/messages/notifications-renderer'; +import { SketchbookWidgetContribution } from './widgets/sketchbook/sketchbook-widget-contribution'; +import { LocalCacheFsProvider } from './local-cache/local-cache-fs-provider'; +import { CloudSketchbookWidget } from './widgets/cloud-sketchbook/cloud-sketchbook-widget'; +import { CloudSketchbookTreeWidget } from './widgets/cloud-sketchbook/cloud-sketchbook-tree-widget'; +import { createCloudSketchbookTreeWidget } from './widgets/cloud-sketchbook/cloud-sketchbook-tree-container'; +import { CreateApi } from './create/create-api'; +import { ShareSketchDialog } from './dialogs/cloud-share-sketch-dialog'; +import { AuthenticationClientService } from './auth/authentication-client-service'; +import { + AuthenticationService, + AuthenticationServicePath, +} from '../common/protocol/authentication-service'; +import { CreateFsProvider } from './create/create-fs-provider'; +import { FileServiceContribution } from '@theia/filesystem/lib/browser/file-service'; +import { CloudSketchbookContribution } from './widgets/cloud-sketchbook/cloud-sketchbook-contributions'; +import { CloudSketchbookCompositeWidget } from './widgets/cloud-sketchbook/cloud-sketchbook-composite-widget'; +import { SketchbookWidget } from './widgets/sketchbook/sketchbook-widget'; +import { SketchbookTreeWidget } from './widgets/sketchbook/sketchbook-tree-widget'; +import { createSketchbookTreeWidget } from './widgets/sketchbook/sketchbook-tree-container'; +import { SketchCache } from './widgets/cloud-sketchbook/cloud-sketch-cache'; +import { UploadFirmware } from './contributions/upload-firmware'; +import { + UploadFirmwareDialog, + UploadFirmwareDialogProps, +} from './dialogs/firmware-uploader/firmware-uploader-dialog'; +import { UploadCertificate } from './contributions/upload-certificate'; +import { + ArduinoFirmwareUploader, + ArduinoFirmwareUploaderPath, +} from '../common/protocol/arduino-firmware-uploader'; +import { + UploadCertificateDialog, + UploadCertificateDialogProps, + UploadCertificateDialogWidget, +} from './dialogs/certificate-uploader/certificate-uploader-dialog'; +import { PlotterFrontendContribution } from './serial/plotter/plotter-frontend-contribution'; +import { + UserFieldsDialog, + UserFieldsDialogProps, +} from './dialogs/user-fields/user-fields-dialog'; +import { IDEUpdaterCommands } from './ide-updater/ide-updater-commands'; +import { + IDEUpdater, + IDEUpdaterClient, + IDEUpdaterPath, +} from '../common/protocol/ide-updater'; +import { IDEUpdaterClientImpl } from './ide-updater/ide-updater-client-impl'; +import { + IDEUpdaterDialog, + IDEUpdaterDialogProps, +} from './dialogs/ide-updater/ide-updater-dialog'; +import { ElectronIpcConnectionProvider } from '@theia/core/lib/electron-browser/messaging/electron-ipc-connection-provider'; +import { MonitorModel } from './monitor-model'; +import { MonitorManagerProxyClientImpl } from './monitor-manager-proxy-client-impl'; +import { EditorManager as TheiaEditorManager } from '@theia/editor/lib/browser/editor-manager'; +import { EditorManager } from './theia/editor/editor-manager'; +import { HostedPluginEvents } from './hosted/hosted-plugin-events'; +import { HostedPluginSupportImpl } from './theia/plugin-ext/hosted-plugin'; +import { HostedPluginSupport as TheiaHostedPluginSupport } from '@theia/plugin-ext/lib/hosted/browser/hosted-plugin'; +import { Formatter, FormatterPath } from '../common/protocol/formatter'; +import { Format } from './contributions/format'; +import { MonacoFormattingConflictsContribution } from './theia/monaco/monaco-formatting-conflicts'; +import { MonacoFormattingConflictsContribution as TheiaMonacoFormattingConflictsContribution } from '@theia/monaco/lib/browser/monaco-formatting-conflicts'; +import { DefaultJsonSchemaContribution } from './theia/core/json-schema-store'; +import { DefaultJsonSchemaContribution as TheiaDefaultJsonSchemaContribution } from '@theia/core/lib/browser/json-schema-store'; +import { EditorNavigationContribution } from './theia/editor/editor-navigation-contribution'; +import { EditorNavigationContribution as TheiaEditorNavigationContribution } from '@theia/editor/lib/browser/editor-navigation-contribution'; +import { PreferenceTreeGenerator } from './theia/preferences/preference-tree-generator'; +import { PreferenceTreeGenerator as TheiaPreferenceTreeGenerator } from '@theia/preferences/lib/browser/util/preference-tree-generator'; +import { AboutDialog } from './theia/core/about-dialog'; +import { AboutDialog as TheiaAboutDialog } from '@theia/core/lib/browser/about-dialog'; +import { + SurveyNotificationService, + SurveyNotificationServicePath, +} from '../common/protocol/survey-service'; +import { WindowContribution } from './theia/core/window-contribution'; +import { WindowContribution as TheiaWindowContribution } from '@theia/core/lib/browser/window-contribution'; +import { CoreErrorHandler } from './contributions/core-error-handler'; +import { CompilerErrors } from './contributions/compiler-errors'; +import { WidgetManager } from './theia/core/widget-manager'; +import { WidgetManager as TheiaWidgetManager } from '@theia/core/lib/browser/widget-manager'; +import { StartupTasksExecutor } from './contributions/startup-tasks-executor'; +import { IndexesUpdateProgress } from './contributions/indexes-update-progress'; +import { Daemon } from './contributions/daemon'; +import { FirstStartupInstaller } from './contributions/first-startup-installer'; +import { OpenSketchFiles } from './contributions/open-sketch-files'; +import { InoLanguage } from './contributions/ino-language'; +import { SelectedBoard } from './contributions/selected-board'; +import { CheckForIDEUpdates } from './contributions/check-for-ide-updates'; +import { OpenBoardsConfig } from './contributions/open-boards-config'; +import { SketchFilesTracker } from './contributions/sketch-files-tracker'; +import { EditorMenuContribution } from './theia/editor/editor-file'; +import { EditorMenuContribution as TheiaEditorMenuContribution } from '@theia/editor/lib/browser/editor-menu'; +import { PreferencesEditorWidget as TheiaPreferencesEditorWidget } from '@theia/preferences/lib/browser/views/preference-editor-widget'; +import { PreferencesEditorWidget } from './theia/preferences/preference-editor-widget'; +import { PreferencesWidget } from '@theia/preferences/lib/browser/views/preference-widget'; +import { createPreferencesWidgetContainer } from '@theia/preferences/lib/browser/views/preference-widget-bindings'; +import { + BoardsFilterRenderer, + LibraryFilterRenderer, +} from './widgets/component-list/filter-renderer'; +import { CheckForUpdates } from './contributions/check-for-updates'; +import { OutputEditorFactory } from './theia/output/output-editor-factory'; +import { StartupTaskProvider } from '../electron-common/startup-task'; +import { DeleteSketch } from './contributions/delete-sketch'; +import { UserFields } from './contributions/user-fields'; +import { UpdateIndexes } from './contributions/update-indexes'; +import { InterfaceScale } from './contributions/interface-scale'; +import { OpenHandler } from '@theia/core/lib/browser/opener-service'; +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 { + 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'; +import { TypeHierarchyContribution } from './theia/typehierarchy/type-hierarchy-contribution'; +import { TypeHierarchyContribution as TheiaTypeHierarchyContribution } from '@theia/typehierarchy/lib/browser/typehierarchy-contribution'; +import { DefaultDebugSessionFactory } from './theia/debug/debug-session-contribution'; +import { DebugSessionFactory } from '@theia/debug/lib/browser/debug-session-contribution'; +import { ConfigServiceClient } from './config/config-service-client'; +import { ValidateSketch } from './contributions/validate-sketch'; +import { RenameCloudSketch } from './contributions/rename-cloud-sketch'; +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'; +import { FileResourceResolver } from './theia/filesystem/file-resource'; +import { FileResourceResolver as TheiaFileResourceResolver } from '@theia/filesystem/lib/browser/file-resource'; +import { StylingParticipant } from '@theia/core/lib/browser/styling-service'; +import { MonacoEditorMenuContribution } from './theia/monaco/monaco-menu'; +import { MonacoEditorMenuContribution as TheiaMonacoEditorMenuContribution } from '@theia/monaco/lib/browser/monaco-menu'; +import { UpdateArduinoState } from './contributions/update-arduino-state'; +import { TerminalFrontendContribution } from './theia/terminal/terminal-frontend-contribution'; +import { TerminalFrontendContribution as TheiaTerminalFrontendContribution } from '@theia/terminal/lib/browser/terminal-frontend-contribution'; +import { SelectionService } from '@theia/core/lib/common/selection-service'; +import { CommandService } from '@theia/core/lib/common/command'; +import { CorePreferences } from '@theia/core/lib/browser/core-preferences'; +import { AutoSelectProgrammer } from './contributions/auto-select-programmer'; +import { HostedPluginSupport } from './hosted/hosted-plugin-support'; +import { DebugSessionManager as TheiaDebugSessionManager } from '@theia/debug/lib/browser/debug-session-manager'; +import { DebugSessionManager } from './theia/debug/debug-session-manager'; +import { DebugWidget as TheiaDebugWidget } from '@theia/debug/lib/browser/view/debug-widget'; +import { DebugWidget } from './theia/debug/debug-widget'; +import { DebugViewModel } from '@theia/debug/lib/browser/view/debug-view-model'; +import { DebugSessionWidget } from '@theia/debug/lib/browser/view/debug-session-widget'; +import { DebugConfigurationWidget } from './theia/debug/debug-configuration-widget'; +import { DebugConfigurationWidget as TheiaDebugConfigurationWidget } from '@theia/debug/lib/browser/view/debug-configuration-widget'; +import { DebugToolBar } from '@theia/debug/lib/browser/view/debug-toolbar-widget'; +import { HomeWidget } from './home/home-widget'; +import { HomeWidgetContribution } from './home/home-widget-contribution'; +import { BoardImgWidget } from './boardImg/boardImg-widget'; +import { BoardImgWidgetContribution } from './boardImg/boardImg-widget-contribution'; +import { + ApplicationShell, + bindToolbarApplicationShell, + DockPanelRenderer, +} from './theia/core/application-shell'; +import { MySearchInWorkspaceWidget } from './theia/search-in-workspace/search-in-workspace-widget'; +import { SearchInWorkspaceWidget } from '@theia/search-in-workspace/lib/browser/search-in-workspace-widget'; +import { OutputWidget } from '@theia/output/lib/browser/output-widget'; +import { MyOutputWidget } from './theia/out-put/out-put-widget'; +import { KeymapsFrontendWidget } from './theia/keymaps/keymaps-frontend-widget'; +import { KeybindingWidget } from '@theia/keymaps/lib/browser/keybindings-widget'; +import { MyNotificationsContribution } from './theia/messages/notifications-contribution'; +import { NotificationsContribution } from '@theia/messages/lib/browser/notifications-contribution'; +import { MyFileSystemWatcherErrorHandler } from './theia/filesystem/filesystem-watcher-error-handler'; +import { FileSystemWatcherErrorHandler } from '@theia/filesystem/lib/browser/filesystem-watcher-error-handler'; +import { MyLibraryListWidget } from './library/my-library-list-widget'; +import { MyLibraryListWidgetFrontendContribution } from './library/my-library-widget-frontend-contribution'; +import { + LibrarysDialog, + LibrarysDialogProps, +} from './dialogs/librarys/librarys-dialog'; +import { OpenLibrarys } from './dialogs/librarys/open-librarys'; +import { + KeymapsDialog, + KeymapsDialogProps, +} from './dialogs/Keymaps/keymaps-dialog'; +import { OpenKeymaps } from './dialogs/Keymaps/open-keymaps'; +import { OutputContribution } from '@theia/output/lib/browser/output-contribution'; +import { MyOutputContribution } from './theia/out-put/output-contribution'; + +// Hack to fix copy/cut/paste issue after electron version update in Theia. +// https://github.com/eclipse-theia/theia/issues/12487 +import('@theia/core/lib/browser/common-frontend-contribution.js').then( + (theiaCommonContribution) => { + theiaCommonContribution['supportCopy'] = true; + theiaCommonContribution['supportCut'] = true; + theiaCommonContribution['supportPaste'] = true; + } +); + +export default new ContainerModule((bind, unbind, isBound, rebind) => { + // Commands, colors, theme adjustments, and toolbar items + bind(ArduinoFrontendContribution).toSelf().inSingletonScope(); + bind(CommandContribution).toService(ArduinoFrontendContribution); + bind(MenuContribution).toService(ArduinoFrontendContribution); + bind(TabBarToolbarContribution).toService(ArduinoFrontendContribution); + bind(FrontendApplicationContribution).toService(ArduinoFrontendContribution); + bind(ColorContribution).toService(ArduinoFrontendContribution); + bind(StylingParticipant).toService(ArduinoFrontendContribution); + bind(CommandContribution).to(BoardImgWidgetContribution); + bind(CommandContribution).to(HomeWidgetContribution); + + bind(ArduinoToolbarContribution).toSelf().inSingletonScope(); + bind(FrontendApplicationContribution).toService(ArduinoToolbarContribution); + + // Renderer for both the library and the core widgets. + bind(ListItemRenderer).toSelf().inSingletonScope(); + bind(LibraryFilterRenderer).toSelf().inSingletonScope(); + bind(BoardsFilterRenderer).toSelf().inSingletonScope(); + + // Library service + bind(LibraryService) + .toDynamicValue((context) => + WebSocketConnectionProvider.createProxy( + context.container, + LibraryServicePath + ) + ) + .inSingletonScope(); + + // Library list widget + // bind(LibraryListWidget).toSelf(); + bindViewContribution(bind, LibraryListWidgetFrontendContribution); + bind(WidgetFactory).toDynamicValue((context) => ({ + id: LibraryListWidget.WIDGET_ID, + createWidget: () => context.container.get(LibraryListWidget), + })); + bind(FrontendApplicationContribution).toService( + LibraryListWidgetFrontendContribution + ); + bind(OpenHandler).toService(LibraryListWidgetFrontendContribution); + + // Sketch list service + bind(SketchesService) + .toDynamicValue((context) => + WebSocketConnectionProvider.createProxy( + context.container, + SketchesServicePath + ) + ) + .inSingletonScope(); + bind(SketchesServiceClientImpl).toSelf().inSingletonScope(); + bind(FrontendApplicationContribution).toService(SketchesServiceClientImpl); + + // Config service + bind(ConfigService) + .toDynamicValue((context) => + WebSocketConnectionProvider.createProxy( + context.container, + ConfigServicePath + ) + ) + .inSingletonScope(); + bind(ConfigServiceClient).toSelf().inSingletonScope(); + bind(FrontendApplicationContribution).toService(ConfigServiceClient); + + // Boards service + bind(BoardsService) + .toDynamicValue((context) => + WebSocketConnectionProvider.createProxy( + context.container, + BoardsServicePath + ) + ) + .inSingletonScope(); + // Boards service client to receive and delegate notifications from the backend. + bind(BoardsServiceProvider).toSelf().inSingletonScope(); + bind(FrontendApplicationContribution).toService(BoardsServiceProvider); + bind(CommandContribution).toService(BoardsServiceProvider); + bind(BoardListDumper).toSelf().inSingletonScope(); + + // To be able to track, and update the menu based on the core settings (aka. board details) of the currently selected board. + bind(BoardsDataStore).toSelf().inSingletonScope(); + bind(FrontendApplicationContribution).toService(BoardsDataStore); + bind(CommandContribution).toService(BoardsDataStore); + bind(StartupTaskProvider).toService(BoardsDataStore); // to inherit the boards config options, programmer, etc in a new window + + // Logger for the Arduino daemon + bind(ILogger) + .toDynamicValue((ctx) => { + const parentLogger = ctx.container.get(ILogger); + return parentLogger.child('store'); + }) + .inSingletonScope() + .whenTargetNamed('store'); + + // Boards auto-installer + bind(BoardsAutoInstaller).toSelf().inSingletonScope(); + bind(FrontendApplicationContribution).toService(BoardsAutoInstaller); + + // Boards list widget + // bind(BoardsListWidget).toSelf(); + bindViewContribution(bind, BoardsListWidgetFrontendContribution); + bind(WidgetFactory).toDynamicValue((context) => ({ + id: BoardsListWidget.WIDGET_ID, + createWidget: () => context.container.get(BoardsListWidget), + })); + bind(FrontendApplicationContribution).toService( + BoardsListWidgetFrontendContribution + ); + bind(OpenHandler).toService(BoardsListWidgetFrontendContribution); + + // Board select dialog + bind(BoardsConfigDialog).toSelf().inSingletonScope(); + bind(BoardsConfigDialogProps).toConstantValue({ + title: '选择“其他单板和端口”', + }); + + // Core service + bind(CoreService) + .toDynamicValue((context) => + WebSocketConnectionProvider.createProxy( + context.container, + CoreServicePath + ) + ) + .inSingletonScope(); + bind(CoreErrorHandler).toSelf().inSingletonScope(); + + // Serial monitor + bind(MonitorWidget).toSelf(); + bind(FrontendApplicationContribution).toService(MonitorModel); + bind(MonitorModel).toSelf().inSingletonScope(); + bindViewContribution(bind, MonitorViewContribution); + bind(TabBarToolbarContribution).toService(MonitorViewContribution); + bind(WidgetFactory).toDynamicValue((context) => ({ + id: MonitorWidget.ID, + createWidget: () => context.container.get(MonitorWidget), + })); + + bind(MonitorManagerProxyFactory).toFactory( + (context) => () => + context.container.get(MonitorManagerProxy) + ); + + bind(MonitorManagerProxy) + .toDynamicValue((context) => + WebSocketConnectionProvider.createProxy( + context.container, + MonitorManagerProxyPath, + context.container.get(MonitorManagerProxyClient) + ) + ) + .inSingletonScope(); + + // Monitor manager proxy client to receive and delegate pluggable monitors + // notifications from the backend + bind(MonitorManagerProxyClient) + .to(MonitorManagerProxyClientImpl) + .inSingletonScope(); + + bind(WorkspaceService).toSelf().inSingletonScope(); + rebind(TheiaWorkspaceService).toService(WorkspaceService); + bind(WorkspaceVariableContribution).toSelf().inSingletonScope(); + rebind(TheiaWorkspaceVariableContribution).toService( + WorkspaceVariableContribution + ); + + bind(SurveyNotificationService) + .toDynamicValue((context) => { + return ElectronIpcConnectionProvider.createProxy( + context.container, + SurveyNotificationServicePath + ); + }) + .inSingletonScope(); + + // Layout and shell customizations. + rebind(TheiaOutlineViewContribution) + .to(OutlineViewContribution) + .inSingletonScope(); + rebind(TheiaProblemContribution).to(ProblemContribution).inSingletonScope(); + rebind(TheiaFileNavigatorContribution) + .to(FileNavigatorContribution) + .inSingletonScope(); + rebind(TheiaKeymapsFrontendContribution) + .to(KeymapsFrontendContribution) + .inSingletonScope(); + rebind(KeybindingWidget).to(KeymapsFrontendWidget).inSingletonScope(); + rebind(TheiaEditorContribution).to(EditorContribution).inSingletonScope(); + rebind(TheiaMonacoStatusBarContribution) + .to(MonacoStatusBarContribution) + .inSingletonScope(); + rebind(TheiaApplicationShell).to(ApplicationShell).inSingletonScope(); + rebind(TheiaScmContribution).to(ScmContribution).inSingletonScope(); + rebind(TheiaSearchInWorkspaceFrontendContribution) + .to(SearchInWorkspaceFrontendContribution) + .inSingletonScope(); + rebind(TheiaFrontendApplication).to(FrontendApplication).inSingletonScope(); + rebind(TheiaWorkspaceFrontendContribution) + .to(WorkspaceFrontendContribution) + .inSingletonScope(); + rebind(TheiaFileMenuContribution) + .to(ArduinoFileMenuContribution) + .inSingletonScope(); + rebind(TheiaCommonFrontendContribution) + .to(CommonFrontendContribution) + .inSingletonScope(); + rebind(TheiaPreferencesContribution) + .to(PreferencesContribution) + .inSingletonScope(); + rebind(TheiaWorkspaceCommandContribution) + .to(WorkspaceCommandContribution) + .inSingletonScope(); + rebind(TheiaWorkspaceDeleteHandler) + .to(WorkspaceDeleteHandler) + .inSingletonScope(); + rebind(TheiaEditorWidgetFactory).to(EditorWidgetFactory).inSingletonScope(); + bind(OutputChannelManager).toSelf().inSingletonScope(); + rebind(TheiaOutputChannelManager).toService(OutputChannelManager); + bind(OutputChannelRegistryMainImpl).toSelf().inTransientScope(); + rebind(TheiaOutputChannelRegistryMainImpl).toService( + OutputChannelRegistryMainImpl + ); + bind(MonacoTextModelService).toSelf().inSingletonScope(); + rebind(TheiaMonacoTextModelService).toService(MonacoTextModelService); + bind(MonacoEditorProvider).toSelf().inSingletonScope(); + rebind(TheiaMonacoEditorProvider).toService(MonacoEditorProvider); + + // Disabled reference counter in the editor manager to avoid opening the same editor (with different opener options) multiple times. + bind(EditorManager).toSelf().inSingletonScope(); + rebind(TheiaEditorManager).toService(EditorManager); + + // replace search icon + rebind(TheiaSearchInWorkspaceFactory) + .to(SearchInWorkspaceFactory) + .inSingletonScope(); + + // Show a disconnected status bar, when the daemon is not available + bind(ApplicationConnectionStatusContribution).toSelf().inSingletonScope(); + rebind(TheiaApplicationConnectionStatusContribution).toService( + ApplicationConnectionStatusContribution + ); + bind(FrontendConnectionStatusService).toSelf().inSingletonScope(); + rebind(TheiaFrontendConnectionStatusService).toService( + FrontendConnectionStatusService + ); + + // Decorator customizations + bind(TabBarDecoratorService).toSelf().inSingletonScope(); + rebind(TheiaTabBarDecoratorService).toService(TabBarDecoratorService); + + // Problem markers + bind(ProblemManager).toSelf().inSingletonScope(); + rebind(TheiaProblemManager).toService(ProblemManager); + + // Customized layout restorer that can restore the state in async way: https://github.com/eclipse-theia/theia/issues/6579 + bind(ShellLayoutRestorer).toSelf().inSingletonScope(); + rebind(TheiaShellLayoutRestorer).toService(ShellLayoutRestorer); + + // No dropdown for the _Output_ view. + bind(OutputToolbarContribution).toSelf().inSingletonScope(); + rebind(TheiaOutputToolbarContribution).toService(OutputToolbarContribution); + + // To remove `New Window` from the `File` menu + bind(WindowContribution).toSelf().inSingletonScope(); + rebind(TheiaWindowContribution).toService(WindowContribution); + + // To remove `File` > `Close Editor`. + bind(EditorMenuContribution).toSelf().inSingletonScope(); + rebind(TheiaEditorMenuContribution).toService(EditorMenuContribution); + + // To disable the highlighting of non-unicode characters in the _Output_ view + bind(OutputEditorFactory).toSelf().inSingletonScope(); + // Rebind to `TheiaOutputEditorFactory` when https://github.com/eclipse-theia/theia/pull/11615 is available. + rebind(MonacoEditorFactory).toService(OutputEditorFactory); + + bind(ArduinoDaemon) + .toDynamicValue((context) => + WebSocketConnectionProvider.createProxy( + context.container, + ArduinoDaemonPath + ) + ) + .inSingletonScope(); + + bind(Formatter) + .toDynamicValue(({ container }) => + WebSocketConnectionProvider.createProxy(container, FormatterPath) + ) + .inSingletonScope(); + + bind(ArduinoFirmwareUploader) + .toDynamicValue((context) => + WebSocketConnectionProvider.createProxy( + context.container, + ArduinoFirmwareUploaderPath + ) + ) + .inSingletonScope(); + + // File-system extension + bind(FileSystemExt) + .toDynamicValue((context) => + WebSocketConnectionProvider.createProxy( + context.container, + FileSystemExtPath + ) + ) + .inSingletonScope(); + + // Examples service@ + bind(ExamplesService) + .toDynamicValue((context) => + WebSocketConnectionProvider.createProxy( + context.container, + ExamplesServicePath + ) + ) + .inSingletonScope(); + + // Executable URIs known by the backend + bind(ExecutableService) + .toDynamicValue((context) => + WebSocketConnectionProvider.createProxy( + context.container, + ExecutableServicePath + ) + ) + .inSingletonScope(); + + Contribution.configure(bind, NewSketch); + Contribution.configure(bind, OpenSketch); + Contribution.configure(bind, Close); + Contribution.configure(bind, SaveSketch); + Contribution.configure(bind, SaveAsSketch); + Contribution.configure(bind, VerifySketch); + Contribution.configure(bind, UploadSketch); + Contribution.configure(bind, OpenSketchExternal); + Contribution.configure(bind, EditContributions); + Contribution.configure(bind, QuitApp); + Contribution.configure(bind, SketchControl); + Contribution.configure(bind, OpenSettings); + Contribution.configure(bind, BurnBootloader); + Contribution.configure(bind, BuiltInExamples); + Contribution.configure(bind, LibraryExamples); + Contribution.configure(bind, IncludeLibrary); + Contribution.configure(bind, About); + Contribution.configure(bind, Debug); + Contribution.configure(bind, Sketchbook); + Contribution.configure(bind, UploadFirmware); + Contribution.configure(bind, UploadCertificate); + Contribution.configure(bind, BoardSelection); + Contribution.configure(bind, OpenRecentSketch); + Contribution.configure(bind, Help); + Contribution.configure(bind, AddFile); + Contribution.configure(bind, ArchiveSketch); + Contribution.configure(bind, AddZipLibrary); + Contribution.configure(bind, PlotterFrontendContribution); + Contribution.configure(bind, Format); + Contribution.configure(bind, CompilerErrors); + Contribution.configure(bind, StartupTasksExecutor); + Contribution.configure(bind, IndexesUpdateProgress); + Contribution.configure(bind, Daemon); + Contribution.configure(bind, FirstStartupInstaller); + Contribution.configure(bind, OpenSketchFiles); + Contribution.configure(bind, InoLanguage); + Contribution.configure(bind, SelectedBoard); + Contribution.configure(bind, CheckForIDEUpdates); + Contribution.configure(bind, OpenBoardsConfig); + Contribution.configure(bind, SketchFilesTracker); + Contribution.configure(bind, CheckForUpdates); + Contribution.configure(bind, UserFields); + Contribution.configure(bind, DeleteSketch); + Contribution.configure(bind, UpdateIndexes); + Contribution.configure(bind, InterfaceScale); + Contribution.configure(bind, NewCloudSketch); + Contribution.configure(bind, ValidateSketch); + Contribution.configure(bind, RenameCloudSketch); + Contribution.configure(bind, Account); + Contribution.configure(bind, CloudSketchbookContribution); + Contribution.configure(bind, CreateCloudCopy); + Contribution.configure(bind, UpdateArduinoState); + Contribution.configure(bind, BoardsDataMenuUpdater); + Contribution.configure(bind, AutoSelectProgrammer); + Contribution.configure(bind, OpenLibrarys); + Contribution.configure(bind, OpenKeymaps); + + bindContributionProvider(bind, StartupTaskProvider); + bind(StartupTaskProvider).toService(BoardsServiceProvider); // to reuse the boards config in another window + + bind(DebugDisabledStatusMessageSource).toService(Debug); + + // Disabled the quick-pick customization from Theia when multiple formatters are available. + // Use the default VS Code behavior, and pick the first one. In the IDE2, clang-format has `exclusive` selectors. + bind(MonacoFormattingConflictsContribution).toSelf().inSingletonScope(); + rebind(TheiaMonacoFormattingConflictsContribution).toService( + MonacoFormattingConflictsContribution + ); + + bind(ResponseServiceImpl) + .toSelf() + .inSingletonScope() + .onActivation(({ container }, responseService) => { + WebSocketConnectionProvider.createProxy( + container, + ResponseServicePath, + responseService + ); + return responseService; + }); + + bind(ResponseService).toService(ResponseServiceImpl); + bind(ResponseServiceClient).toService(ResponseServiceImpl); + + bind(NotificationCenter).toSelf().inSingletonScope(); + bind(FrontendApplicationContribution).toService(NotificationCenter); + bind(NotificationServiceServer) + .toDynamicValue((context) => + WebSocketConnectionProvider.createProxy( + context.container, + NotificationServicePath + ) + ) + .inSingletonScope(); + + // Enable the dirty indicator on uncloseable widgets. + rebind(TabBarRendererFactory).toFactory((context) => () => { + const contextMenuRenderer = + context.container.get(ContextMenuRenderer); + const decoratorService = context.container.get( + TabBarDecoratorService + ); + const iconThemeService = + context.container.get(IconThemeService); + const selectionService = + context.container.get(SelectionService); + const commandService = + context.container.get(CommandService); + const corePreferences = + context.container.get(CorePreferences); + return new TabBarRenderer( + contextMenuRenderer, + decoratorService, + iconThemeService, + selectionService, + commandService, + corePreferences + ); + }); + + // Workaround for https://github.com/eclipse-theia/theia/issues/8722 + // Do not trigger a save on IDE startup if `"editor.autoSave": "on"` was set as a preference. + // Note: `"editor.autoSave" was renamed to `"files.autoSave" and `"on"` was replaced with three + // different cases, but we treat `!== 'off'` as auto save enabled. (https://github.com/eclipse-theia/theia/issues/10812) + bind(EditorCommandContribution).toSelf().inSingletonScope(); + rebind(TheiaEditorCommandContribution).toService(EditorCommandContribution); + + // Silent the badge decoration in the Explorer view. + bind(NavigatorTabBarDecorator).toSelf().inSingletonScope(); + rebind(TheiaNavigatorTabBarDecorator).toService(NavigatorTabBarDecorator); + + // Do not fetch the `catalog.json` from Azure on FE load. + bind(DefaultJsonSchemaContribution).toSelf().inSingletonScope(); + rebind(TheiaDefaultJsonSchemaContribution).toService( + DefaultJsonSchemaContribution + ); + + // Do not block the app startup when initializing the editor navigation history. + bind(EditorNavigationContribution).toSelf().inSingletonScope(); + rebind(TheiaEditorNavigationContribution).toService( + EditorNavigationContribution + ); + + // IDE2 does not use the Theia preferences widget, no need to create and sync the underlying tree model. + bind(PreferenceTreeGenerator).toSelf().inSingletonScope(); + rebind(TheiaPreferenceTreeGenerator).toService(PreferenceTreeGenerator); + + // IDE2 has a custom about dialog, so there is no need to load the Theia extensions on FE load + bind(AboutDialog).toSelf().inSingletonScope(); + rebind(TheiaAboutDialog).toService(AboutDialog); + + // To remove the `Run` menu item from the application menu. + bind(DebugFrontendApplicationContribution).toSelf().inSingletonScope(); + rebind(TheiaDebugFrontendApplicationContribution).toService( + DebugFrontendApplicationContribution + ); + // To be able to use a `launch.json` from outside of the workspace. + bind(DebugConfigurationManager).toSelf().inSingletonScope(); + rebind(TheiaDebugConfigurationManager).toService(DebugConfigurationManager); + // To update the currently selected debug config to update it programmatically. + bind(WidgetFactory) + .toDynamicValue(({ container }) => ({ + id: TheiaDebugWidget.ID, + createWidget: () => { + const child = new Container({ defaultScope: 'Singleton' }); + child.parent = container; + child.bind(DebugViewModel).toSelf(); + child.bind(DebugToolBar).toSelf(); + child.bind(DebugSessionWidget).toSelf(); + child.bind(DebugConfigurationWidget).toSelf(); // with the patched select + child // use the customized one in the Theia DI + .bind(TheiaDebugConfigurationWidget) + .toService(DebugConfigurationWidget); + child.bind(DebugWidget).toSelf(); + return child.get(DebugWidget); + }, + })) + .inSingletonScope(); + + // To avoid duplicate tabs use deepEqual instead of string equal: https://github.com/eclipse-theia/theia/issues/11309 + bind(WidgetManager).toSelf().inSingletonScope(); + rebind(TheiaWidgetManager).toService(WidgetManager); + + // Debounced update for the tab-bar toolbar when typing in the editor. + bind(DockPanelRenderer).toSelf(); + rebind(TheiaDockPanelRenderer).toService(DockPanelRenderer); + + // Avoid running the "reset scroll" interval tasks until the preference editor opens. + rebind(PreferencesWidget) + .toDynamicValue(({ container }) => { + const child = createPreferencesWidgetContainer(container); + child.bind(PreferencesEditorWidget).toSelf().inSingletonScope(); + child + .rebind(TheiaPreferencesEditorWidget) + .toService(PreferencesEditorWidget); + return child.get(PreferencesWidget); + }) + .inSingletonScope(); + + // Preferences + bindArduinoPreferences(bind); + + // Settings wrapper for the preferences and the CLI config. + bind(SettingsService).toSelf().inSingletonScope(); + // Settings dialog and widget + bind(SettingsWidget).toSelf().inSingletonScope(); + bind(SettingsDialog).toSelf().inSingletonScope(); + bind(SettingsDialogProps).toConstantValue({ + title: '设置', + }); + + bind(LibrarysDialog).toSelf().inSingletonScope(); + bind(LibrarysDialogProps).toConstantValue({ + title: '从本地安装库', + }); + + bind(KeymapsDialog).toSelf().inSingletonScope(); + bind(KeymapsDialogProps).toConstantValue({ + title: '键盘快捷方式参考', + }); + + bind(NotificationManager).toSelf().inSingletonScope(); + rebind(TheiaNotificationManager).toService(NotificationManager); + bind(MyNotificationsContribution).toSelf().inSingletonScope(); + rebind(NotificationsContribution).toService(MyNotificationsContribution); + bind(NotificationsRenderer).toSelf().inSingletonScope(); + rebind(TheiaNotificationsRenderer).toService(NotificationsRenderer); + + //==================== + // bind(YourCustomWidget).toSelf(); + // bind(YourCustomWidgetContribution).toSelf(); + // bind(FrontendApplicationContribution).toService(YourCustomWidgetContribution); + // bind(WidgetFactory).toDynamicValue(({ container }) => ({ + // id: 'your-custom-widget-id',d + // createWidget: () => container.get(YourCustomWidget), + // })); + + //UI for the BoardImg + bind(BoardImgWidget).toSelf(); + bind(BoardImgWidgetContribution).toSelf(); + bind(FrontendApplicationContribution).toService(BoardImgWidgetContribution); + bind(WidgetFactory).toDynamicValue(({ container }) => ({ + id: 'lingzhi-boardImg-widget', + createWidget: () => container.get(BoardImgWidget), + })); + + //UI for the library + bind(MyLibraryListWidget).toSelf(); + bind(MyLibraryListWidgetFrontendContribution).toSelf(); + bind(WidgetFactory).toDynamicValue(({ container }) => ({ + id: 'lingzhi-library-widget', + createWidget: () => container.get(MyLibraryListWidget), + })); + + //UI for the Home + bind(HomeWidget).toSelf(); + bind(HomeWidgetContribution).toSelf(); + // bindViewContribution(bind, HomeWidgetContribution); + bind(FrontendApplicationContribution).toService(HomeWidgetContribution); + bind(WidgetFactory).toDynamicValue(({ container }) => ({ + id: 'lingzhi-home-widget', + createWidget: () => container.get(HomeWidget), + })); + + // UI for the Sketchbook + bind(SketchbookWidget).toSelf(); + bind(SketchbookTreeWidget).toDynamicValue(({ container }) => + createSketchbookTreeWidget(container) + ); + bindViewContribution(bind, SketchbookWidgetContribution); + bind(FrontendApplicationContribution).toService(SketchbookWidgetContribution); + bind(WidgetFactory).toDynamicValue(({ container }) => ({ + id: 'arduino-sketchbook-widget', + createWidget: () => container.get(SketchbookWidget), + })); + bind(SketchbookCompositeWidget).toSelf(); + bind(WidgetFactory).toDynamicValue((ctx) => ({ + id: 'sketchbook-composite-widget', + createWidget: () => ctx.container.get(SketchbookCompositeWidget), + })); + + bind(CloudSketchbookWidget).toSelf(); + rebind(SketchbookWidget).toService(CloudSketchbookWidget); + bind(CloudSketchbookTreeWidget).toDynamicValue(({ container }) => + createCloudSketchbookTreeWidget(container) + ); + bind(CreateApi).toSelf().inSingletonScope(); + bind(SketchCache).toSelf().inSingletonScope(); + bind(CreateFeatures).toSelf().inSingletonScope(); + bind(FrontendApplicationContribution).toService(CreateFeatures); + + bind(ShareSketchDialog).toSelf().inSingletonScope(); + bind(AuthenticationClientService).toSelf().inSingletonScope(); + bind(CommandContribution).toService(AuthenticationClientService); + bind(FrontendApplicationContribution).toService(AuthenticationClientService); + bind(AuthenticationService) + .toDynamicValue((context) => + WebSocketConnectionProvider.createProxy( + context.container, + AuthenticationServicePath + ) + ) + .inSingletonScope(); + bind(CreateFsProvider).toSelf().inSingletonScope(); + bind(FrontendApplicationContribution).toService(CreateFsProvider); + bind(FileServiceContribution).toService(CreateFsProvider); + bind(LocalCacheFsProvider).toSelf().inSingletonScope(); + bind(FileServiceContribution).toService(LocalCacheFsProvider); + bind(CloudSketchbookCompositeWidget).toSelf(); + bind(WidgetFactory).toDynamicValue((ctx) => ({ + id: 'cloud-sketchbook-composite-widget', + createWidget: () => ctx.container.get(CloudSketchbookCompositeWidget), + })); + + bind(UploadFirmwareDialog).toSelf().inSingletonScope(); + bind(UploadFirmwareDialogProps).toConstantValue({ + title: 'UploadFirmware', + }); + bind(UploadCertificateDialogWidget).toSelf().inSingletonScope(); + bind(UploadCertificateDialog).toSelf().inSingletonScope(); + bind(UploadCertificateDialogProps).toConstantValue({ + title: 'UploadCertificate', + }); + + bind(IDEUpdaterDialog).toSelf().inSingletonScope(); + bind(IDEUpdaterDialogProps).toConstantValue({ + title: 'IDEUpdater', + }); + + bind(UserFieldsDialog).toSelf().inSingletonScope(); + bind(UserFieldsDialogProps).toConstantValue({ + title: 'UserFields', + }); + + bind(IDEUpdaterCommands).toSelf().inSingletonScope(); + bind(CommandContribution).toService(IDEUpdaterCommands); + + // Frontend binding for the IDE Updater service + bind(IDEUpdaterClientImpl).toSelf().inSingletonScope(); + bind(IDEUpdaterClient).toService(IDEUpdaterClientImpl); + bind(IDEUpdater) + .toDynamicValue((context) => { + const client = context.container.get(IDEUpdaterClientImpl); + return ElectronIpcConnectionProvider.createProxy( + context.container, + IDEUpdaterPath, + client + ); + }) + .inSingletonScope(); + + bind(HostedPluginSupportImpl).toSelf().inSingletonScope(); + bind(HostedPluginSupport).toService(HostedPluginSupportImpl); + rebind(TheiaHostedPluginSupport).toService(HostedPluginSupportImpl); + bind(HostedPluginEvents).toSelf().inSingletonScope(); + bind(FrontendApplicationContribution).toService(HostedPluginEvents); + + // custom window titles + bind(WindowTitleUpdater).toSelf().inSingletonScope(); + rebind(TheiaWindowTitleUpdater).toService(WindowTitleUpdater); + + // register Arduino themes + 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(); + rebind(TheiaTypeHierarchyServiceProvider).toService( + TypeHierarchyServiceProvider + ); + bind(TypeHierarchyContribution).toSelf().inSingletonScope(); + rebind(TheiaTypeHierarchyContribution).toService(TypeHierarchyContribution); + + bind(DefaultDebugSessionFactory).toSelf().inSingletonScope(); + rebind(DebugSessionFactory).toService(DefaultDebugSessionFactory); + + bind(SidebarBottomMenuWidget).toSelf(); + rebind(TheiaSidebarBottomMenuWidget).toService(SidebarBottomMenuWidget); + + bind(ArduinoComponentContextMenuRenderer).toSelf().inSingletonScope(); + + bind(DaemonPort).toSelf().inSingletonScope(); + 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); + bind(MyFileSystemWatcherErrorHandler).toSelf().inSingletonScope(); + rebind(FileSystemWatcherErrorHandler).toService( + MyFileSystemWatcherErrorHandler + ); + + // Full control over the editor context menu to filter undesired menu items contributed by Theia. + // https://github.com/arduino/arduino-ide/issues/1394 + // https://github.com/arduino/arduino-ide/pull/2027#pullrequestreview-1414246614 + bind(MonacoEditorMenuContribution).toSelf().inSingletonScope(); + rebind(TheiaMonacoEditorMenuContribution).toService( + MonacoEditorMenuContribution + ); + + // Patch terminal issues. + bind(TerminalFrontendContribution).toSelf().inSingletonScope(); + rebind(TheiaTerminalFrontendContribution).toService( + TerminalFrontendContribution + ); + + bindToolbarApplicationShell(bind, rebind); + rebind(SearchInWorkspaceWidget) + .to(MySearchInWorkspaceWidget) + .inSingletonScope(); + + rebind(OutputWidget).to(MyOutputWidget); + + rebind(OutputContribution).to(MyOutputContribution).inSingletonScope(); +}); diff --git a/arduino-ide-extension/src/browser/arduino-preferences.ts b/arduino-ide-extension/src/browser/arduino-preferences.ts new file mode 100644 index 000000000..288193e8f --- /dev/null +++ b/arduino-ide-extension/src/browser/arduino-preferences.ts @@ -0,0 +1,299 @@ +import { + PreferenceContribution, + PreferenceProxy, + PreferenceSchema, + PreferenceService, + createPreferenceProxy, +} from '@theia/core/lib/browser/preferences'; +import { ApplicationShell } from '@theia/core/lib/browser/shell/application-shell'; +import { nls } from '@theia/core/lib/common/nls'; +import { PreferenceSchemaProperty } from '@theia/core/lib/common/preferences/preference-schema'; +import { interfaces } from '@theia/core/shared/inversify'; +import { serialMonitorWidgetLabel } from '../common/nls'; +import { CompilerWarningLiterals, CompilerWarnings } from '../common/protocol'; + +export enum UpdateChannel { + Stable = 'stable', + Nightly = 'nightly', +} +export const ErrorRevealStrategyLiterals = [ + /** + * Scroll vertically as necessary and reveal a line. + */ + 'auto', + /** + * Scroll vertically as necessary and reveal a line centered vertically. + */ + 'center', + /** + * Scroll vertically as necessary and reveal a line close to the top of the viewport, optimized for viewing a code definition. + */ + 'top', + /** + * Scroll vertically as necessary and reveal a line centered vertically only if it lies outside the viewport. + */ + 'centerIfOutsideViewport', +] as const; +export type ErrorRevealStrategy = (typeof ErrorRevealStrategyLiterals)[number]; +export namespace ErrorRevealStrategy { + // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types, @typescript-eslint/no-explicit-any + export function is(arg: any): arg is ErrorRevealStrategy { + return !!arg && ErrorRevealStrategyLiterals.includes(arg); + } + export const Default: ErrorRevealStrategy = 'centerIfOutsideViewport'; +} + +export type MonitorWidgetDockPanel = Extract< + ApplicationShell.Area, + 'bottom' | 'right' +>; +export const defaultMonitorWidgetDockPanel: MonitorWidgetDockPanel = 'bottom'; +export function isMonitorWidgetDockPanel( + arg: unknown +): arg is MonitorWidgetDockPanel { + return arg === 'bottom' || arg === 'right'; +} + +export const defaultAsyncWorkers = 0 as const; +export const minAsyncWorkers = defaultAsyncWorkers; +export const maxAsyncWorkers = 8 as const; + +type StrictPreferenceSchemaProperties = { + [p in keyof T]: PreferenceSchemaProperty; +}; +type ArduinoPreferenceSchemaProperties = + StrictPreferenceSchemaProperties & { + 'arduino.window.zoomLevel': PreferenceSchemaProperty; + }; + +const properties: ArduinoPreferenceSchemaProperties = { + 'arduino.language.log': { + type: 'boolean', + description: + 'True 则 Arduino Language Server 将日志文件生成到项目文件夹中。默认为 False。', + default: false, + }, + 'arduino.language.realTimeDiagnostics': { + type: 'boolean', + description: + 'True 则 language server 在编辑器中输入时提供实时诊断。默认为 False。', + default: false, + }, + 'arduino.language.asyncWorkers': { + type: 'number', + description: + 'Arduino 语言服务器(clangd)使用的异步工作线程数。 后台索引也使用相同数量的工作线程。 最小值为 0,最大值为 8。 当值为 0 时,语言服务器将使用所有可用的核心。 默认值为 0。', + minimum: minAsyncWorkers, + maximum: maxAsyncWorkers, + default: defaultAsyncWorkers, + }, + 'arduino.compile.verbose': { + type: 'boolean', + description: 'True 则输出详细编译信息。默认为 False', + default: true, + }, + 'arduino.compile.experimental': { + type: 'boolean', + description: 'True 则 IDE 处理多个编译器错误。默认为 False。', + default: false, + }, + 'arduino.compile.revealRange': { + enum: [...ErrorRevealStrategyLiterals], + description: + '调整编译器错误在 “验证/上传” 失败后在编辑器中的显示方式。可能的值:‘auto’:根据需要垂直滚动并显示一行。‘center’:必要时垂直滚动并显示垂直居中的一行。‘top’:必要时垂直滚动并显示靠近视口顶部的一行,优化用于查看代码定义。‘centerIfOutsideViewport’:根据需要垂直滚动并显示垂直居中的线,只有当它位于视口之外时。', + default: ErrorRevealStrategy.Default, + }, + 'arduino.compile.warnings': { + enum: [...CompilerWarningLiterals], + description: '设置 gcc 警告级别。默认为 None', + default: 'None', + }, + 'arduino.upload.verbose': { + type: 'boolean', + description: 'True 则输出详细上传信息。默认情况下为 False。', + default: true, + }, + 'arduino.upload.verify': { + type: 'boolean', + default: false, + }, + 'arduino.window.autoScale': { + type: 'boolean', + description: 'True 则用户界面随字体大小自动缩放。', + default: true, + }, + 'arduino.window.zoomLevel': { + type: 'number', + description: '', + default: 0, + deprecationMessage: '已弃用。请改用“window.zoomLevel”。', + }, + 'arduino.ide.updateChannel': { + type: 'string', + enum: Object.values(UpdateChannel) as UpdateChannel[], + default: UpdateChannel.Stable, + description: + '在发布频道中获取更新信息。‘stable’ 是稳定的版本,‘nightly’ 是最新的开发版本。', + }, + 'arduino.ide.updateBaseUrl': { + type: 'string', + default: 'https://www.zxjian.com/api/databook', + description: '下载更新的网址。默认为 ‘https://www.zxjian.com/api/databook’', + }, + 'arduino.board.certificates': { + type: 'string', + description: '可上传到开发板的证书列表', + default: '', + }, + 'arduino.sketchbook.showAllFiles': { + type: 'boolean', + description: 'True 则显示项目中的所有项目文件。默认情况下为 False。', + default: false, + }, + 'arduino.cloud.enabled': { + type: 'boolean', + description: 'True 则启用项目同步功能。默认为 True。', + default: true, + }, + 'arduino.cloud.pull.warn': { + type: 'boolean', + description: 'True 则在拉取 cloud 项目之前警告用户。默认为 True。', + default: true, + }, + 'arduino.cloud.push.warn': { + type: 'boolean', + description: 'True 则在推送 cloud 项目之前警告用户。默认为 True。', + default: true, + }, + 'arduino.cloud.pushpublic.warn': { + type: 'boolean', + description: 'True 则将公开项目推送到 cloud 中之前警告用户。默认为 True。', + default: true, + }, + 'arduino.cloud.sketchSyncEndpoint': { + type: 'string', + description: + '用于从后台推送项目的端点。默认情况下,它指向 Arduino Cloud API。', + default: 'https://api2.arduino.cc/create', + }, + 'arduino.auth.clientID': { + type: 'string', + description: 'OAuth2 客户端 ID', + default: 'C34Ya6ex77jTNxyKWj01lCe1vAHIaPIo', + }, + 'arduino.auth.domain': { + type: 'string', + description: nls.localize( + 'arduino/preferences/auth.domain', + 'The OAuth2 domain.' + ), + default: 'login.arduino.cc', + }, + 'arduino.auth.audience': { + type: 'string', + description: nls.localize( + 'arduino/preferences/auth.audience', + 'The OAuth2 audience.' + ), + default: 'https://api.arduino.cc', + }, + 'arduino.auth.registerUri': { + type: 'string', + description: nls.localize( + 'arduino/preferences/auth.registerUri', + 'The URI used to register a new user.' + ), + default: 'https://auth.arduino.cc/login#/register', + }, + 'arduino.survey.notification': { + type: 'boolean', + description: nls.localize( + 'arduino/preferences/survey.notification', + 'True if users should be notified if a survey is available. True by default.' + ), + default: true, + }, + 'arduino.cli.daemon.debug': { + type: 'boolean', + description: nls.localize( + 'arduino/preferences/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." + ), + default: false, + }, + 'arduino.checkForUpdates': { + type: 'boolean', + description: nls.localize( + 'arduino/preferences/checkForUpdate', + "Receive notifications of available updates for the IDE, boards, and libraries. Requires an IDE restart after change. It's true by default." + ), + default: true, + }, + 'arduino.sketch.inoBlueprint': { + type: 'string', + markdownDescription: nls.localize( + 'arduino/preferences/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.' + ), + default: undefined, + }, + 'arduino.monitor.dockPanel': { + type: 'string', + enum: ['bottom', 'right'], + markdownDescription: nls.localize( + 'arduino/preferences/monitor/dockPanel', + 'The area of the application shell where the _{0}_ widget will reside. It is either "bottom" or "right". It defaults to "{1}".', + serialMonitorWidgetLabel, + defaultMonitorWidgetDockPanel + ), + default: defaultMonitorWidgetDockPanel, + }, +}; +export const ArduinoConfigSchema: PreferenceSchema = { + type: 'object', + properties, +}; + +export interface ArduinoConfiguration { + 'arduino.language.log': boolean; + 'arduino.language.realTimeDiagnostics': boolean; + 'arduino.language.asyncWorkers': number; + 'arduino.compile.verbose': boolean; + 'arduino.compile.experimental': boolean; + 'arduino.compile.revealRange': ErrorRevealStrategy; + 'arduino.compile.warnings': CompilerWarnings; + 'arduino.upload.verbose': boolean; + 'arduino.upload.verify': boolean; + 'arduino.window.autoScale': boolean; + 'arduino.ide.updateChannel': UpdateChannel; + 'arduino.ide.updateBaseUrl': string; + 'arduino.board.certificates': string; + 'arduino.sketchbook.showAllFiles': boolean; + 'arduino.cloud.enabled': boolean; + 'arduino.cloud.pull.warn': boolean; + 'arduino.cloud.push.warn': boolean; + 'arduino.cloud.pushpublic.warn': boolean; + 'arduino.cloud.sketchSyncEndpoint': string; + 'arduino.auth.clientID': string; + 'arduino.auth.domain': string; + 'arduino.auth.audience': string; + 'arduino.auth.registerUri': string; + 'arduino.survey.notification': boolean; + 'arduino.cli.daemon.debug': boolean; + 'arduino.sketch.inoBlueprint': string; + 'arduino.checkForUpdates': boolean; + 'arduino.monitor.dockPanel': MonitorWidgetDockPanel; +} + +export const ArduinoPreferences = Symbol('ArduinoPreferences'); +export type ArduinoPreferences = PreferenceProxy; + +export function bindArduinoPreferences(bind: interfaces.Bind): void { + bind(ArduinoPreferences).toDynamicValue((ctx) => { + const preferences = ctx.container.get(PreferenceService); + return createPreferenceProxy(preferences, ArduinoConfigSchema); + }); + bind(PreferenceContribution).toConstantValue({ + schema: ArduinoConfigSchema, + }); +} diff --git a/arduino-ide-extension/src/browser/auth/authentication-client-service.ts b/arduino-ide-extension/src/browser/auth/authentication-client-service.ts new file mode 100644 index 000000000..bf92eb1c7 --- /dev/null +++ b/arduino-ide-extension/src/browser/auth/authentication-client-service.ts @@ -0,0 +1,99 @@ +import { inject, injectable } from '@theia/core/shared/inversify'; +import { Emitter } from '@theia/core/lib/common/event'; +import { JsonRpcProxy } from '@theia/core/lib/common/messaging/proxy-factory'; +import { WindowService } from '@theia/core/lib/browser/window/window-service'; +import { DisposableCollection } from '@theia/core/lib/common/disposable'; +import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application'; +import { + CommandRegistry, + CommandContribution, +} from '@theia/core/lib/common/command'; +import { + AuthOptions, + AuthenticationService, + AuthenticationServiceClient, + AuthenticationSession, + authServerPort, +} from '../../common/protocol/authentication-service'; +import { CloudUserCommands } from './cloud-user-commands'; +import { ArduinoPreferences } from '../arduino-preferences'; + +@injectable() +export class AuthenticationClientService + implements + FrontendApplicationContribution, + CommandContribution, + AuthenticationServiceClient +{ + @inject(AuthenticationService) + protected readonly service: JsonRpcProxy; + + @inject(WindowService) + protected readonly windowService: WindowService; + + @inject(ArduinoPreferences) + protected readonly arduinoPreferences: ArduinoPreferences; + + protected authOptions: AuthOptions; + protected _session: AuthenticationSession | undefined; + protected readonly toDispose = new DisposableCollection(); + protected readonly onSessionDidChangeEmitter = new Emitter< + AuthenticationSession | undefined + >(); + + readonly onSessionDidChange = this.onSessionDidChangeEmitter.event; + + async onStart(): Promise { + this.toDispose.push(this.onSessionDidChangeEmitter); + this.service.setClient(this); + this.service + .session() + .then((session) => this.notifySessionDidChange(session)); + + this.setOptions().then(() => this.service.initAuthSession()); + + this.arduinoPreferences.onPreferenceChanged((event) => { + if (event.preferenceName.startsWith('arduino.auth.')) { + this.setOptions(); + } + }); + } + + setOptions(): Promise { + return this.service.setOptions({ + redirectUri: `http://localhost:${authServerPort}/callback`, + responseType: 'code', + clientID: this.arduinoPreferences['arduino.auth.clientID'], + domain: this.arduinoPreferences['arduino.auth.domain'], + audience: this.arduinoPreferences['arduino.auth.audience'], + registerUri: this.arduinoPreferences['arduino.auth.registerUri'], + scopes: ['openid', 'profile', 'email', 'offline_access'], + }); + } + + protected updateSession(session?: AuthenticationSession | undefined) { + this._session = session; + this.onSessionDidChangeEmitter.fire(this._session); + } + + get session(): AuthenticationSession | undefined { + return this._session; + } + + registerCommands(registry: CommandRegistry): void { + registry.registerCommand(CloudUserCommands.LOGIN, { + execute: () => this.service.login(), + isEnabled: () => !this._session, + isVisible: () => !this._session, + }); + registry.registerCommand(CloudUserCommands.LOGOUT, { + execute: () => this.service.logout(), + isEnabled: () => !!this._session, + isVisible: () => !!this._session, + }); + } + + notifySessionDidChange(session: AuthenticationSession | undefined): void { + this.updateSession(session); + } +} diff --git a/arduino-ide-extension/src/browser/auth/cloud-user-commands.ts b/arduino-ide-extension/src/browser/auth/cloud-user-commands.ts new file mode 100644 index 000000000..17ac787b9 --- /dev/null +++ b/arduino-ide-extension/src/browser/auth/cloud-user-commands.ts @@ -0,0 +1,22 @@ +import { Command } from '@theia/core/lib/common/command'; + +export const LEARN_MORE_URL = + 'https://docs.arduino.cc/software/ide-v2/tutorials/ide-v2-cloud-sketch-sync'; + +export namespace CloudUserCommands { + export const LOGIN = Command.toLocalizedCommand( + { + id: 'arduino-cloud--login', + label: 'Sign in', + }, + 'arduino/cloud/signIn' + ); + + export const LOGOUT = Command.toLocalizedCommand( + { + id: 'arduino-cloud--logout', + label: 'Sign Out', + }, + 'arduino/cloud/signOut' + ); +} diff --git a/arduino-ide-extension/src/browser/boardImg/boardImg-widget-contribution.ts b/arduino-ide-extension/src/browser/boardImg/boardImg-widget-contribution.ts new file mode 100644 index 000000000..162c76002 --- /dev/null +++ b/arduino-ide-extension/src/browser/boardImg/boardImg-widget-contribution.ts @@ -0,0 +1,131 @@ +/* eslint-disable prettier/prettier */ +import { inject, injectable } from '@theia/core/shared/inversify'; +import { CommandRegistry, CommandService } from '@theia/core/lib/common/command'; +import { AbstractViewContribution } from '@theia/core/lib/browser/shell/view-contribution'; +import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application'; +import { BoardImgWidget } from './boardImg-widget'; +import { MainMenuManager } from '../../common/main-menu-manager'; +import { MenuModelRegistry } from '@theia/core/lib/common/menu/menu-model-registry'; +import { ApplicationShell } from '../theia/core/application-shell'; +import { StorageService } from '@theia/core/lib/browser/storage-service'; +import { toArray } from '@theia/core/shared/@phosphor/algorithm'; +import { WorkspaceService } from '../theia/workspace/workspace-service'; +import { SketchesService } from '../../common/protocol/sketches-service'; + +@injectable() +export class BoardImgWidgetContribution + extends AbstractViewContribution + implements FrontendApplicationContribution { + @inject(MainMenuManager) + protected readonly mainMenuManager: MainMenuManager; + + @inject(ApplicationShell) + protected readonly shelloverride: ApplicationShell; + + @inject(WorkspaceService) + private readonly workspaceService: WorkspaceService; + + @inject(CommandService) + private readonly commandService: CommandService; + + @inject(SketchesService) + private readonly sketchesService: SketchesService; + + @inject(StorageService) protected storageService: StorageService; + constructor() { + super({ + widgetId: 'lingzhi-boardImg-widget', + widgetName: BoardImgWidget.LABEL, + defaultWidgetOptions: { + area: 'right', + rank: 1, + }, + toggleCommandId: BoardImgWidgetCommand.id, + }); + } + + onStart(): void { + // 在应用启动时可以进行一些初始化操作,如果需要的话 + } + + async initializeLayout(): Promise { + return this.openView() as Promise; + } + + override registerCommands(commands: CommandRegistry): void { + commands.registerCommand(BoardImgWidgetCommand, { + execute: () => { + super.openView({ activate: false, reveal: true }); + }, + }); + commands.registerCommand(BoardImgWidgetClose, { + execute: () => { + super.closeView(); + }, + }); + + let toHome = true; + let leftPanelWidth: number | undefined; + commands.registerCommand(MyWidgetCommandHome, { + execute: async () => { + if (!toHome) { + leftPanelWidth = this.shell.leftPanelHandler.getLayoutData().size; + toHome = true; + } + this.shelloverride.mainContainer.hide(); + this.shelloverride.rightPanelCustom.hide(); + this.shell.rightPanelHandler.container.hide(); + } + }); + commands.registerCommand(MyWidgetCommandOther, { + execute: async () => { + this.shell.rightPanelHandler.container.hide(); + this.shell.leftPanelHandler.container.hide(); + this.shell.leftPanelHandler.container.show(); + if (toHome) { + toHome = false; + if (leftPanelWidth) { + this.shell.leftPanelHandler.resize(leftPanelWidth); + } else { + this.shell.leftPanelHandler.resize(160); + } + } + this.shelloverride.mainContainer.show(); + this.shelloverride.rightPanelCustom.show(); + this.shelloverride.rightPanelCustom.node.style.maxWidth = 'none'; + } + }); + + commands.registerCommand(MAIN_WIDGET_CLOSE_AND_OPEN, { + execute: () => { + const currentWidgetInMain = toArray( + this.shell.mainPanel.widgets() + ); + if (currentWidgetInMain) { + currentWidgetInMain.forEach((widget) => { + widget.close(); + }) + } + } + }) + } + + override registerMenus(registry: MenuModelRegistry): void { + registry.unregisterMenuAction({ + commandId: BoardImgWidgetCommand.id, + }); + } +} + +export const BoardImgWidgetCommand = { + id: 'toggle-lingzhi-boardImg-widget', +}; + +export const BoardImgWidgetClose = { + id: 'close-lingzhi-boardImg-widget', +}; + +export const MAIN_WIDGET_CLOSE_AND_OPEN = { id: 'lingzhi-colse-and-open' }; + +export const MyWidgetCommandHome = { id: 'closeMainAndRight:command' }; +export const MyWidgetCommandOther = { id: 'openMainAndRight:command' }; \ No newline at end of file diff --git a/arduino-ide-extension/src/browser/boardImg/boardImg-widget.ts b/arduino-ide-extension/src/browser/boardImg/boardImg-widget.ts new file mode 100644 index 000000000..11a5fd476 --- /dev/null +++ b/arduino-ide-extension/src/browser/boardImg/boardImg-widget.ts @@ -0,0 +1,258 @@ +/* eslint-disable prettier/prettier */ +import { injectable } from '@theia/core/shared/inversify'; +import { BaseWidget } from '@theia/core/lib/browser/widgets/widget'; +import { nls } from '@theia/core/lib/common'; + +@injectable() +export class BoardImgWidget extends BaseWidget { + static readonly LABEL = nls.localize('arduino/home/boardImg', '开发板'); + // 声明一个私有成员变量用于存储滚动容器 + private scrollContainer: HTMLDivElement; + + constructor( + // @inject(BoardsService) private readonly boardsService: BoardsService, + // @inject(CommandService) private commandService: CommandService, + // @inject(BoardsServiceProvider) + // private readonly boardsServiceProvider: BoardsServiceProvider + ) { + super(); + this.id = 'lingzhi-boardImg-widget'; + this.title.caption = BoardImgWidget.LABEL; + this.title.label = BoardImgWidget.LABEL; + this.title.iconClass = 'fa lingzhi-chanpinfenlei-kaifaban'; + this.title.closable = true; + this.node.tabIndex = 0; + + // this.selectExamples(); + + // // 添加一个包含滚动条的容器元素到小部件的节点中 + // this.scrollContainer = document.createElement('div'); + // this.scrollContainer.style.overflowY = 'auto'; + // this.scrollContainer.style.display = 'flex'; + // this.scrollContainer.style.alignItems = 'center'; + // this.scrollContainer.style.justifyContent = 'center'; + // this.scrollContainer.style.height = `calc(100% - 102px)`; + // this.scrollContainer.style.borderTop = '1px solid #dae3e3'; + + // this.node.appendChild(this.scrollContainer); + // this.officialWebsiteInformation(); + + // this.imgDisplay(); + } + + // private officialWebsiteInformation() { + // const container1 = document.createElement('div'); + // container1.style.display = 'flex'; + // container1.style.alignItems = 'center'; + // container1.style.margin = '5px 10px '; + + // // 创建文字 + // const name = document.createElement('span'); + // name.textContent = '名称:'; + // name.style.marginRight = '15px'; + // name.style.whiteSpace = 'nowrap'; + + // const name1 = document.createElement('span'); + // this.boardsServiceProvider.onBoardListDidChange((boardList) => { + // if (boardList.boardsConfig.selectedBoard?.fqbn) { + // const fqbn = boardList.boardsConfig.selectedBoard.fqbn; + // const lastColonIndex = fqbn.lastIndexOf(':'); + // const valueAfterLastColon = fqbn.slice(lastColonIndex + 1); + // switch (valueAfterLastColon) { + // case 'lzesp32': + // name1.textContent = '零知-ESP32'; + // break; + // case 'lzesp8266': + // name1.textContent = '零知-ESP8266'; + // break; + // case 'lingzhistandard': + // name1.textContent = '零知-标准板'; + // break; + // case 'lingzhiMini': + // name1.textContent = '零知-迷你板'; + // break; + // case 'lingzhiM4': + // name1.textContent = '零知-增强板'; + // break; + // case 'lz_ble52': + // name1.textContent = '零知-BLE52'; + // break; + // default: + // if (boardList.boardsConfig.selectedBoard?.name) { + // name1.textContent = boardList.boardsConfig.selectedBoard.name; + // } + // break; + // } + // } + // }); + // name1.style.marginRight = '15px'; + // name1.style.whiteSpace = 'nowrap'; + // name1.style.color = '#5500ff'; + + // container1.appendChild(name); + // container1.appendChild(name1); + // this.node.appendChild(container1); + + // const container2 = document.createElement('div'); + // container2.style.display = 'flex'; + // container2.style.alignItems = 'center'; + // container2.style.margin = '5px 10px '; + + // // 创建文字 + // const brand = document.createElement('span'); + // brand.textContent = '品牌:'; + // brand.style.marginRight = '15px'; + + // const brand1 = document.createElement('span'); + // brand1.textContent = '零知实验室'; + // brand1.style.marginRight = '15px'; + // brand1.style.color = '#5500ff'; + + // container2.appendChild(brand); + // container2.appendChild(brand1); + // this.node.appendChild(container2); + + // const container3 = document.createElement('div'); + // container3.style.display = 'flex'; + // container3.style.alignItems = 'center'; + // container3.style.margin = '5px 10px '; + + // // 创建文字 + // const officialWebsite = document.createElement('span'); + // officialWebsite.textContent = '官网:'; + // officialWebsite.style.marginRight = '15px'; + + // const officialWebsite1 = document.createElement('a'); + // officialWebsite1.textContent = 'www.lingzhilab.com'; + // officialWebsite1.style.textDecoration = 'underline'; + // officialWebsite1.style.marginRight = '15px'; + // officialWebsite1.style.cursor = 'pointer'; + // officialWebsite1.style.color = '#5500ff'; + + // officialWebsite1.addEventListener('click', () => { + // this.commandService.executeCommand('arduino-visit-arduino'); + // }); + + // container3.appendChild(officialWebsite); + // container3.appendChild(officialWebsite1); + // this.node.appendChild(container3); + // } + + // // file:///D:/work/work3/arduino-ide-2.3.2/electron-app/lib/frontend/index.html?port=59791#/d:/work/work3/arduino-ide-2.3.2/arduino-ide-extension/lib/node/resources/Examples/lz-esp32/BLE(%E8%93%9D%E7%89%99)/BLE_notify(%E8%93%9D%E7%89%99%E9%80%9A%E7%9F%A5)/BLE_notify + // private imgDisplay(imgName = '') { + // // 先清除之前的图片 + // while (this.scrollContainer.firstChild) { + // this.scrollContainer.removeChild(this.scrollContainer.firstChild); + // } + + // const img = new Image(); + // let absolutePath = `./icon/${imgName}.svg`; + // if (imgName === 'lzesp8266') { + // absolutePath = `./icon/${imgName}.png`; + // } + // img.src = absolutePath; + // const resizeObserver = new ResizeObserver(() => { + // if (this.scrollContainer.clientWidth === 232) { + // img.style.width = '50%'; + // } else { + // img.style.width = '100%'; + // } + // }); + // resizeObserver.observe(this.scrollContainer); + + // img.style.margin = 'auto'; + // img.style.position = 'relative'; + // this.scrollContainer.appendChild(img); + // } + + // private async selectExamples() { + // // 创建包含文字和下拉框的容器 + // const container = document.createElement('div'); + // container.style.display = 'flex'; + // container.style.alignItems = 'center'; + // container.style.margin = '5px 10px '; + + // // 创建文字 + // const label = document.createElement('span'); + // label.textContent = '开发板:'; + // label.style.marginRight = '15px'; + + // // 创建下拉框 + // const dropdown = document.createElement('select'); + + // const allBoards = await this.boardsService.getInstalledBoards(); + + + // this.boardsServiceProvider.onBoardListDidChange((boardList) => { + // dropdown.value = boardList.boardsConfig.selectedBoard?.fqbn as string; + // const parts = dropdown.value.split(':'); + // const imgName = parts[parts.length - 1]; + // this.imgDisplay(imgName); + // }); + + // this.boardsServiceProvider.onBoardsConfigDidChange(() => { + // this.boardsServiceProvider.ready.then(() => { + // const { selectedBoard } = this.boardsServiceProvider.boardsConfig; + // const name = selectedBoard?.fqbn; + // dropdown.value = name as string; + // }); + // }); + + // allBoards.forEach((board) => { + // const option = document.createElement('option'); + // const fqbn = board.fqbn as string; + // option.value = fqbn; + // const lastColonIndex = fqbn.lastIndexOf(':'); + // const valueAfterLastColon = fqbn.slice(lastColonIndex + 1); + // switch (valueAfterLastColon) { + // case 'lzesp32': + // option.textContent = '零知-ESP32'; + // break; + // case 'lzesp8266': + // option.textContent = '零知-ESP8266'; + // break; + // case 'lingzhistandard': + // option.textContent = '零知-标准板'; + // break; + // case 'lingzhiMini': + // option.textContent = '零知-迷你板'; + // break; + // case 'lingzhiM4': + // option.textContent = '零知-增强板'; + // break; + // case 'lz_ble52': + // option.textContent = '零知-BLE52'; + // break; + // default: + // if (board.name) { + // option.textContent = board.name; + // } + // break; + // } + // dropdown.appendChild(option); + // }); + // dropdown.style.borderColor = 'rgb(172, 172, 172)'; + // dropdown.style.color = 'rgb(0, 0, 0)'; + // dropdown.style.backgroundImage = + // 'linear-gradient(to bottom, rgb(254, 254, 254) 0%, rgb(241, 241, 241) 100%)'; + // dropdown.style.width = '125px'; + // dropdown.addEventListener('change', () => { + // const commandId = `arduino-select-board--${dropdown.value}`; + // this.commandService + // .executeCommand(commandId) + // .then(() => { + // console.log(`Executed command: ${commandId}`); + // }) + // .catch((error) => { + // console.error(`Failed to execute command ${commandId}: ${error}`); + // }); + // }); + + // // 将文字和下拉框添加到容器中 + // container.appendChild(label); + // container.appendChild(dropdown); + + // // 将容器添加到节点中 + // this.node.insertBefore(container, this.scrollContainer); + // } +} diff --git a/arduino-ide-extension/src/browser/boardImg/icon/diecimila.png b/arduino-ide-extension/src/browser/boardImg/icon/diecimila.png new file mode 100644 index 0000000000000000000000000000000000000000..6d121d0b6b10dcaa3451b0d008888fc1d16c4e02 GIT binary patch literal 96196 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≪t%}sJ0_Y`vM21 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

RJIK*+gpBhvU2%dvWt8xA4wBLndn`baUvWE-qGc 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 OKW?etMHJt7jQT(F8ddNB literal 0 HcmV?d00001 diff --git a/arduino-ide-extension/src/browser/boardImg/icon/lingzhiM4.svg b/arduino-ide-extension/src/browser/boardImg/icon/lingzhiM4.svg new file mode 100644 index 000000000..03c2ea7bf --- /dev/null +++ b/arduino-ide-extension/src/browser/boardImg/icon/lingzhiM4.svg @@ -0,0 +1,3014 @@ + + + + +Fritzing breadboard generated by brd2svg + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +layer 21 + + + + + + + + + + + + + + + + 0 + + + + + + + + + 1 + + + + + + + + + 2 + + + + + + + + + 3 + + + + + + + + + 4 + + + + + + + + + 5 + + + + + + + + + 6 + + + + + + + + + 7 + + + + + + + + + 8 + + + + + + + + + 9 + + + + + + + + + 10 + + + + + + + + + 11 + + + + + + + + + 12 + + + + + + + + + 13 + + + + + + text:0 + + + A0 + + + + + text:1 + + + A1 + + + + + text:2 + + + A2 + + + + + text:3 + + + A3 + + + + + text:4 + + + A4 + + + + + text:5 + + + A5 + + + + + text:6 + + + A6 + + + + + text:7 + + + A7 + + + + + text:8 + + + A8 + + + + + text:9 + + + A9 + + + + + text:10 + + + A10 + + + + + text:11 + + + A11 + + + + + text:12 + + + A12 + + + + + text:13 + + + A13 + + + + + text:14 + + + A14 + + + + + text:15 + + + A15 + + + + + text:22 + + 22 + + + text:24 + + 24 + + + text:26 + + 26 + + + text:28 + + 28 + + + text:30 + + 30 + + + text:31 + + 31 + + + text:32 + + 32 + + + text:33 + + 33 + + + text:34 + + 34 + + + text:35 + + 35 + + + text:36 + + 36 + + + text:37 + + 37 + + + text:38 + + 38 + + + text:39 + + 39 + + + text:41 + + 41 + + + text:40 + + 40 + + + text:43 + + 43 + + + text:42 + + 42 + + + text:45 + + 45 + + + text:47 + + 47 + + + text:49 + + 49 + + + text:51 + + 51 + + + text:44 + + 44 + + + text:46 + + 46 + + + text:50 + + 50 + + + text:48 + + 48 + + + text:53 + + 53 + + + text:52 + + 52 + + + element:C1 + + package:C0603-ROUND + + + + element:C2 + + package:C0603-ROUND + + + + element:C3 + + package:C0603-ROUND + + + + element:C4 + + package:C0603-ROUND + + + + element:C5 + + package:C0603-ROUND + + + + element:C6 + + package:C0603-ROUND + + + + element:C7 + + package:C0603-ROUND + + + + element:C8 + + package:C0603-ROUND + + + + element:C9 + + package:C0603-ROUND + + + + element:C10 + + package:C0603-ROUND + + + + element:C11 + + package:C0603-ROUND + + + + element:C12 + + package:C0603-ROUND + + + + element:C13 + + package:C0603-ROUND + + + + element:C14 + + package:C0603-ROUND + + + + element:C15 + + package:C0603-ROUND + + + + element:F1 + + package:L1812 + + + + element:FD1 + + package:FIDUCIA-MOUNT + + + + element:FD2 + + package:FIDUCIA-MOUNT + + + + element:FD3 + + package:FIDUCIA-MOUNT + + + + element:FD4 + + package:FIDUCIA-MOUNT + + + + element:GROUND + + package:SJ + + + + element:L + + text:L + + L + + + + element:R1 + + package:R0603-ROUND + + + + element:R2 + + package:R0603-ROUND + + + + element:RN1 + + package:CAT16 + + + + element:RN2 + + package:CAY16 + + + + element:RN3 + + package:CAY16 + + + + element:RN4 + + package:CAY16 + + + + element:RN5 + + package:CAT16 + + + + element:RX + + text:RX + + RX + + + + element:TX + + text:TX + + TX + + + + element:Z1 + + package:CT/CN0603 + + + + element:Z2 + + package:CT/CN0603 + + +text:ANALOG IN +ANALOG IN + + + COMMUNICATION + +text:ANALOG IN +POWER + + + + NC + + + + + + + GND + + + + + + + TX0 + + + + + + + RX0 + + + + + + + RESET + + + + + + + + 3V3 + + + + + + + 5V + + +text:VIN +VIN +text:GND +GND +text:GND +GND + + + + SDA 20 + + + + + + + SCL 21 + + + + + + + TX3 16 + + + + + + + RX3 17 + + + + + + + RX5 15 + + + +text:TX3 + + + TX5 14 + + + + + + RX2 19 + + + + + + + TX2 18 + + + +text:MADE IN +text:ITALY + + + + PWM + + +text:5V +3V3 +text:GND +GND +text:DIGITAL + + + + DIGITAL + + + +text:MEGA 2560 +text:M.Banzi +text:D.Cuartielles +text:D.Mellis +text:G.Martino +text:T.Igoe +text:SDA +text:SCL +element:C1 + + package:C0603-ROUND + +element:C2 + + package:C0603-ROUND + +element:C3 + + package:C0603-ROUND + +element:C4 + + package:C0603-ROUND + +element:C5 + + package:C0603-ROUND + +element:C6 + + package:C0603-ROUND + +element:C7 + + package:C0603-ROUND + +element:C8 + + package:C0603-ROUND + +element:C9 + + package:C0603-ROUND + +element:C10 + + package:C0603-ROUND + +element:C11 + + package:C0603-ROUND + +element:C12 + + package:C0603-ROUND + +element:C13 + + package:C0603-ROUND + +element:C14 + + package:C0603-ROUND + +element:C15 + + package:C0603-ROUND + +element:D1 + + package:SMB + +element:D2 + + package:MINIMELF + +element:D3 + + package:MINIMELF + +element:F1 + + package:L1812 + +element:FD1 + + package:FIDUCIA-MOUNT + +element:FD2 + + package:FIDUCIA-MOUNT + +element:FD3 + + package:FIDUCIA-MOUNT + +element:FD4 + + package:FIDUCIA-MOUNT + +element:GROUND + + package:SJ + +element:IC3 + + package:TQFP100 + +element:IC4 + + package:MLF32 + +element:IC6 + + package:SOT23-DBV + +element:IC7 + + package:MSOP08 + +element:L + + package:CHIP-LED0805 + +element:L1 + + package:0805 + +element:ON +element:R1 + + package:R0603-ROUND + +element:R2 + + package:R0603-ROUND + +element:RN1 + + package:CAT16 + +element:RN2 + + package:CAY16 + +element:RN3 + + package:CAY16 + +element:RN4 + + package:CAY16 + +element:RN5 + + package:CAT16 + +element:RX + + package:CHIP-LED0805 + +element:T1 + + package:SOT-23 + +element:TX + + package:CHIP-LED0805 + +element:XIO + + package:2X18 + + text:XIO + + +element:Y1 + + package:RESONATOR + +element:Y2 + + package:QS + +element:Z1 + + package:CT/CN0603 + +element:Z2 + + package:CT/CN0603 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +零知-增强板 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text:RESET + + + + + + + + + RESET + + + + + + + + + + + + + + + +LI-PO +USB +UART + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + element:TX + + text:TX + + PWR + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + STM32 + F4 + + + + + Camera + + + + + + + SWD + + + + + + + SDA 20 + + + + + + + SCL 21 + + + + + + + + 3V3 + + + + + + + + + GND + + + + + + + + + + diff --git a/arduino-ide-extension/src/browser/boardImg/icon/lingzhiMini.svg b/arduino-ide-extension/src/browser/boardImg/icon/lingzhiMini.svg new file mode 100644 index 000000000..af295f549 --- /dev/null +++ b/arduino-ide-extension/src/browser/boardImg/icon/lingzhiMini.svg @@ -0,0 +1,911 @@ + + + + + + + + + +Reset +1 +TX +RX +GND +5V + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + STM32 + F1 + + + + + + +3 +2 +4 +6 +5 +7 +9 +8 +10 +RST + + + + + + + + + + + + + + + + + + + + + + + +12 +14 +13 +3.3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +零知-迷你板 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +GND + + + + +3.3 + + + + +0 + + + + +5V +29 + + + + + + + + + + + + + + + + +27 +28 +26 +24 +25 +23 +21 +22 +20 +18 + + + + + + + + + + + + + + + + + + + + + + + +17 +15 +16 +GND +3.3 + + + + +BT0 + + + + +30 + + + + +31 +RST +BT0 + +11 + + +19 + + diff --git a/arduino-ide-extension/src/browser/boardImg/icon/lingzhistandard.svg b/arduino-ide-extension/src/browser/boardImg/icon/lingzhistandard.svg new file mode 100644 index 000000000..acdb78aff --- /dev/null +++ b/arduino-ide-extension/src/browser/boardImg/icon/lingzhistandard.svg @@ -0,0 +1,3982 @@ + + + + + + arduino_Uno_Rev3-02-TH_breadboard.svg + +Fritzing breadboard generated by brd2svg + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +layer 21 + + text:MADE IN + + + text:ITALY + + + text:Prototype + + + text:Limited + + + text:Edition + + + + + + + + + + + + + + + + + + + + + + 13 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 11 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2 + + + + + + + + + + + + + + + + + + + + + element:C1 + + package:C0603-ROUND + + + + element:C2 + + package:C0603-ROUND + + + + element:C3 + + package:C0603-ROUND + + + + element:C4 + + package:C0603-ROUND + + + + element:C5 + + package:C0603-ROUND + + + + element:C6 + + package:C0603-ROUND + + + + element:C7 + + package:C0603-ROUND + + + + element:C8 + + package:C0603-ROUND + + + + element:C9 + + package:C0603-ROUND + + + + element:C11 + + package:C0603-ROUND + + + + element:F1 + + package:L1812 + + + + element:FD1 + + package:FIDUCIA-MOUNT + + + + element:FD2 + + package:FIDUCIA-MOUNT + + + + element:FD3 + + package:FIDUCIA-MOUNT + + + + element:GROUND + + package:SJ + + + + element:L + + text:L + + + + + + + + + L + + + + + + + + + + + element:R1 + + package:R0603-ROUND + + + + element:R2 + + package:R0603-ROUND + + + + element:RN1 + + package:CAY16 + + + + element:RN2 + + package:CAY16 + + + + element:RN3 + + package:CAY16 + + + + element:RN4 + + package:CAY16 + + + + element:Z1 + + package:CT/CN0603 + + + + element:Z2 + + package:CT/CN0603 + + +layer 25 + + + + + + + + 5V + + + + + + + + text:A0 + + + + + + + + + A0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GND + + + + + + + + + + + + + + + + + + + + + text:M.Banzi + + + text:D.Cuartielles + + + text:D.Mellis + + + text:TX + + + + + + + + + TX + + + + + + + + + + text:RX + + + + + + + + + RX + + + + + + + + + + text:G.Martino + + + text:T.Igoe + + + + + + + + + + + + + + + + + + + RESET + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3V3 + + + + + + + + + + + + + + + + + + + + + text:A1 + + + + + + A1 + + + + + + + text:A2 + + + + + + + + + A2 + + + + + + + + + + text:A3 + + + + + + + + + A3 + + + + + + + + + + text:A4 + + + + + + + + + A4 + + + + + + + + + + text:A5 + + + + + + + + + A5 + + + + + + + + + + + + + + + + + + + VIN + + + + + + + + + + + + + + + + + + + + GND + + + + + + + + + + + + + + + + + + + + GND + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text:# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text:SDA + + + text:SCL + + + element:AD + + package:1X06 + + + + element:C1 + + package:C0603-ROUND + + + + element:C2 + + package:C0603-ROUND + + + + element:C3 + + package:C0603-ROUND + + + + element:C4 + + package:C0603-ROUND + + + + element:C5 + + package:C0603-ROUND + + + + element:C6 + + package:C0603-ROUND + + + + element:C7 + + package:C0603-ROUND + + + + element:C8 + + package:C0603-ROUND + + + + element:C9 + + package:C0603-ROUND + + + + element:C11 + + package:C0603-ROUND + + + + element:D1 + + package:SMB + + + + element:D2 + + package:MINIMELF + + + + element:D3 + + package:MINIMELF + + + + element:F1 + + package:L1812 + + + + element:FD1 + + package:FIDUCIA-MOUNT + + + + element:FD2 + + package:FIDUCIA-MOUNT + + + + element:FD3 + + package:FIDUCIA-MOUNT + + + + element:GROUND + + package:SJ + + + + element:ICSP1 + + package:2X03 + + + + element:IOH + + package:1X10@1 + + + + element:IOL + + package:1X08 + + + + element:JP2 + + package:2X02 + + + + element:L + + package:CHIP-LED0805 + + + + element:L1 + + package:0805 + + + + element:PC1 + + package:PANASONIC_D + + + + element:PC2 + + package:PANASONIC_D + + + + element:R1 + + package:R0603-ROUND + + + + element:R2 + + package:R0603-ROUND + + + + element:RESET + + package:TS42 + + + + element:RESET-EN + + package:SJ + + + + element:RN1 + + package:CAY16 + + + + element:RN2 + + package:CAY16 + + + + element:RN3 + + package:CAY16 + + + + element:RN4 + + package:CAY16 + + + + element:RX + + package:CHIP-LED0805 + + + + element:T1 + + package:SOT-23 + + + + element:TX + + package:CHIP-LED0805 + + + + element:U1 + + package:SOT223 + + + + element:U2 + + package:SOT23-DBV + + + + element:U3 + + package:MLF32 + + + + element:U5 + + package:MSOP08 + + + + element:X1 + + package:POWERSUPPLY_DC-21MM + + + + element:X2 + + package:PN61729 + + + + element:Y1 + + package:QS + + + + element:Y2 + + package:RESONATOR + + + + element:Z1 + + package:CT/CN0603 + + + + element:Z2 + + package:CT/CN0603 + + + + element:ZU4 + + package:DIL28-3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + RX + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TX + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text:RESET + + + + + + + + + RESET + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +电源 +模拟输入 +PWR + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text:# + + + + + + + + + + + + + + + + + + + + + + + + + + text:# + + + + + + + + + + + + + + + + + + + + + + + + + + text:# + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +LI-PO +USB +UART + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +21 +22 +23 +25 +27 +29 +31 +24 +26 +28 +30 +32 +34 +36 +GND +33 +35 +37 + + + + + + + + + + + + + + + + + + + + + 14 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +零知-标准板 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + STM32 + F1 + + + +数字引脚(PWM~) + diff --git a/arduino-ide-extension/src/browser/boardImg/icon/lz_ble52.svg b/arduino-ide-extension/src/browser/boardImg/icon/lz_ble52.svg new file mode 100644 index 000000000..b4fdd9d5c --- /dev/null +++ b/arduino-ide-extension/src/browser/boardImg/icon/lz_ble52.svg @@ -0,0 +1,3454 @@ + + + + + + + + arduino_Uno_Rev3-02-TH_breadboard.svg + +Fritzing breadboard generated by brd2svg + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +layer 21 + + text:MADE IN + + + text:ITALY + + + text:Prototype + + + text:Limited + + + text:Edition + + + + + + + + + + + + + + + + + + + + + + 13 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 12 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 11 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 10 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 9 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 8 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 7 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 6 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 5 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 4 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 2 + + + + + + + + + + + + + + + + + + + + + element:C1 + + package:C0603-ROUND + + + + element:C2 + + package:C0603-ROUND + + + + element:C3 + + package:C0603-ROUND + + + + element:C4 + + package:C0603-ROUND + + + + element:C5 + + package:C0603-ROUND + + + + element:C6 + + package:C0603-ROUND + + + + element:C7 + + package:C0603-ROUND + + + + element:C8 + + package:C0603-ROUND + + + + element:C9 + + package:C0603-ROUND + + + + element:C11 + + package:C0603-ROUND + + + + element:F1 + + package:L1812 + + + + element:FD1 + + package:FIDUCIA-MOUNT + + + + element:FD2 + + package:FIDUCIA-MOUNT + + + + element:FD3 + + package:FIDUCIA-MOUNT + + + + element:GROUND + + package:SJ + + + + element:R1 + + package:R0603-ROUND + + + + element:R2 + + package:R0603-ROUND + + + + element:RN1 + + package:CAY16 + + + + element:RN2 + + package:CAY16 + + + + element:RN3 + + package:CAY16 + + + + element:RN4 + + package:CAY16 + + + + element:Z1 + + package:CT/CN0603 + + + + element:Z2 + + package:CT/CN0603 + + +layer 25 + + + + + + + + 5V + + + + + + + + text:A0 + + + + + + + + + A0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + GND + + + + + + + + + + + + + + + + + + + + + text:M.Banzi + + + text:D.Cuartielles + + + text:D.Mellis + + + text:G.Martino + + + text:T.Igoe + + + + + + + + + + + + + + + + + + + RESET + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 3V3 + + + + + + + + + + + + + + + + + + + + + text:A1 + + + + + + A1 + + + + + + + text:A2 + + + + + + + + + A2 + + + + + + + + + + text:A3 + + + + + + + + + A3 + + + + + + + + + + text:A4 + + + + + + + + + A4 + + + + + + + + + + text:A5 + + + + + + + + + A5 + + + + + + + + + + + + + + + + + + + NC + + + + + + + + + + + + + + + + + + + + GND + + + + + + + + + + + + + + + + + + + + GND + + + + + + + + + + + text:SDA + + + text:SCL + + + element:AD + + package:1X06 + + + + element:C1 + + package:C0603-ROUND + + + + element:C2 + + package:C0603-ROUND + + + + element:C3 + + package:C0603-ROUND + + + + element:C4 + + package:C0603-ROUND + + + + element:C5 + + package:C0603-ROUND + + + + element:C6 + + package:C0603-ROUND + + + + element:C7 + + package:C0603-ROUND + + + + element:C8 + + package:C0603-ROUND + + + + element:C9 + + package:C0603-ROUND + + + + element:C11 + + package:C0603-ROUND + + + + element:D1 + + package:SMB + + + + element:D2 + + package:MINIMELF + + + + element:D3 + + package:MINIMELF + + + + element:F1 + + package:L1812 + + + + element:FD1 + + package:FIDUCIA-MOUNT + + + + element:FD2 + + package:FIDUCIA-MOUNT + + + + element:FD3 + + package:FIDUCIA-MOUNT + + + + element:GROUND + + package:SJ + + + + element:ICSP1 + + package:2X03 + + + + element:IOH + + package:1X10@1 + + + + element:IOL + + package:1X08 + + + + element:JP2 + + package:2X02 + + + + element:L + + package:CHIP-LED0805 + + + + element:L1 + + package:0805 + + + + element:PC1 + + package:PANASONIC_D + + + + element:PC2 + + package:PANASONIC_D + + + + element:R1 + + package:R0603-ROUND + + + + element:R2 + + package:R0603-ROUND + + + + element:RESET + + package:TS42 + + + + element:RESET-EN + + package:SJ + + + + element:RN1 + + package:CAY16 + + + + element:RN2 + + package:CAY16 + + + + element:RN3 + + package:CAY16 + + + + element:RN4 + + package:CAY16 + + + + element:RX + + package:CHIP-LED0805 + + + + element:T1 + + package:SOT-23 + + + + element:TX + + package:CHIP-LED0805 + + + + element:U1 + + package:SOT223 + + + + element:U2 + + package:SOT23-DBV + + + + element:U3 + + package:MLF32 + + + + element:U5 + + package:MSOP08 + + + + element:X1 + + package:POWERSUPPLY_DC-21MM + + + + element:X2 + + package:PN61729 + + + + element:Y1 + + package:QS + + + + element:Y2 + + package:RESONATOR + + + + element:Z1 + + package:CT/CN0603 + + + + element:Z2 + + package:CT/CN0603 + + + + element:ZU4 + + package:DIL28-3 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 0 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + RX + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + TX + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text:RESET + + + + + + + + + RESET + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +电源 +模拟输入 + + + + + + + + + + + + + + +LI-PO +UART + + + + + + + + + + + + + + + + + + + + + NC + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +零知-BLE52 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + nRF52 + + + +数字引脚 + + + + + + + + + + + + + + + + + + + + + SCL + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + SDA + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text:A0 + + + + + + + + + SWD + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +L +PWR +RX +TX +STDBY + + + + + + + + + + + + + + + + + + + + + + + + + + text:RESET + + + + + + + + + KEY + + + + + + + + + +BEEP + + + + + + + + +Antenna + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/arduino-ide-extension/src/browser/boardImg/icon/lzesp32.svg b/arduino-ide-extension/src/browser/boardImg/icon/lzesp32.svg new file mode 100644 index 000000000..3d2681606 --- /dev/null +++ b/arduino-ide-extension/src/browser/boardImg/icon/lzesp32.svg @@ -0,0 +1,738 @@ + + + + + + lz-esp8266.svg + + + + + + D23 + + + + + D22 + + + + + TX0 + + + + + RX0 + + + + + D21 + + + + + D19 + + + + + D18 + + + + + D5 + + + + + TX2 + + + + + RX2 + + + + + D4 + + + + + D2 + + + + + D15 + + + + + GND + + + + + 3V3 + + + + + VIN + + + + + GND + + + + + D13 + + + + + D12 + + + + + D14 + + + + + D27 + + + + + VN + + + + + D34 + + + + + D35 + + + + + D32 + + + + + D33 + + + + + VP + + + + + EN + + + + + + + + + FLASH + + + + + + RST + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 零知-ESP32 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + D26 + + + + + D25 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/arduino-ide-extension/src/browser/boardImg/icon/lzesp8266.png b/arduino-ide-extension/src/browser/boardImg/icon/lzesp8266.png new file mode 100644 index 0000000000000000000000000000000000000000..3aedf9a3f5cea3483e3bb22fcaa6b05e9d304cf3 GIT binary patch literal 135160 zcmb5VbyS>9(>^$8aCaRfxVtkr!6CRqAXtLCySqzpcZb0P!AW3nLU4D22j9u_zR&ml zcF+E?d-}}uJu_#zs;lq2tLnO{qtsO7&{0TG0002`J9%jh001Tt0D!$mLWF*kSL6H* z+95m2>$v~`Y&3sgFrKC2?$9rZU1fA#-#dJC^)Pd`1V~som|FtheKxbQ)UY(O@Nycn z6afH$fOpaonx4xixd@(`iwk$N%;!Dlk4A@|9TbCr$jBrGrN#_wp9^*4G?ur{&ah}{ zX{iR&h|Y#k@jN^tfI%Dm`oN`!+W_(`?vyMGI#{ZoUU@fP%(z@W=5w1p-#V917t09? zG8M~i3XI$Aj83c2$a=oa&$`T+`1ytl-#?oPhO8 zu{&2(n*SIvPwn0FsJ>IrX1O&LGgOX`WGx>kpF|ClTyBPQ2OXvj50ahU_&I^L*9n%lp--;A1U+aoakV%20!$6`YDtA6NpVI!ja}9$HX| zd=g;nThYOmz`_s6G-Mv~6S4}~gzQ2NtL#0Hs4?`&Y2Yh|mfPCG zT`1P6@$~JNPKos9g{p(W`O(|lHbMW<>~erL(W*+tAC?^52t5~l6`dTz2qPC`Rct`Q zZtzTZWHhPxW#?3MrP4?)pBjHXE-x6YzVc@^)sZj=mp3zO_WUq^7raDW;m@_{>;iJi(R3h`pFPxnVR5v>refB)HiJ-~@W zmOoI7V1${Axr&Jxh|mT!N2U0(Ryy#ZO;OLr?LWrR0M#VPLGB^XrT|?4oo+~^n`bQf zeYyYh@N*^D;E9E>cg!h)R^&hPXXI$a4o4ya5CkGG0L_2E-lvrBGe9*Tcpl0z^OE=c z?~njiYz_bm0QW0mH33qd^p4Revp_U|3)5CIa5HHNuyu4aF2_%5?yIbl%gtW`s+m=e zHXu05hnJ6+gy&2eF%2>u@Q{_Y22Q^lkhr>_`Qra)dTO^8CyIZSc~DF%MwM2?85=nD z-VBV&s5g@qjZdgC0Nh$18k(M;R|hhV;4DmL#cXXgXlTd3HOku-8rt8uip|eI6q+xN z@idt>*Z9qE)6I?pWJjd_D~h)PCRQ!@hzW$YFp@7DPj;iQdsj?Yq@dn?-xw-)1}m*Y zR5!IRZeeDn<2~{%&er!pc7DyHSXHa?B}mxsiEZI%9OME|tNSR7uc#h}skA>K>a_pi z=M0J`xjKv5IK{3)l${^NvFrBK1w*}W9gPBp!c{SoJ>Fb78Nv-~ImHAa1M-PcJT+o! zxr#}e8IdCD&X6ShKj!0rt%1~FaUU0-Sy7n~xP=`vX|rOb{vQ2|T2fNAr0;8-?f<6; ztyMFjgKC|ZLAifR`~XE9Q(vS%B>hihar+xq{1L$qq6g3ItD&$ijgR8AHQ7Z&h80to zmIv(sOnsh0*nDn&i$)KGXCwrp@BMBBPVR;0Lp?@^^)>H>P3&uM_g}SqRbr-ADjn4c zUwpe37zaDRsPj*wxeJkx9qvsL-Zi=f7B{q*%Q)IeBEsq0eeC?miG(QFZz*sd;XeUr zVznbZImT_iXC|rmJ;XmYEB*xM)>*2r7aCA%K-VyP;E(2swhl^ZFIz)V5yv2ByG3b$ zjQ*J&+XS8V#{RL63%!+DvBf(_I^dM_dBjmMzJ0zivI zvolEVv$6^5{w;*vCixW+YHYR6Kk?4aBx1hTCYr~^l`UdNhK{ zO#^|!&3Ft|_`MXGcewnwtHK|Hz#1lIL8k4otp>sYDo6`Rkj)BRU>$}&u&xGDn8~yI z#o&1GUPoDj70XH|f(6S^Ck}H}>+3GX!DZ9Nxocd5v}_CWK15amcBey+O1U4cKVDqe z%M1PW{khn-v4oDSjh{#WDm)6@MWhU_NGMMIA4xn!u`8XvXwCX6VYoqiRB43Kt7edh zD=PfmkH4SfC)gFlJy78RP8k5`W@@56YHJqOy>%#fIi-T@7cT7g8j>FY-Fx2zb4-=o zP{BYq?>m6Ghyr0c{3vRRWL^;ddi!NHhy4l?J-zsPp$esT9Fg94boS`91vv_s$cxNb z^V26;!gQMGpClk>$)9=#Rw{6Vp5o~r-DB=?o)pS}rK0SPts5o40;aVk} zT#`6V1d`_t&xSjxDkSa&vVOnX-#QmpP*Z2eP?~iO_B}^7DFt)zru!axkZ?_ zu}g*o!YZr;R*xpso_1v4ziuwRVTzssPp-6pehaGosrgE#=TLAdHsQ9Hju3p#Zsv(_ zd90pCcgLm*bFWEv!y;GsJpMjnk1LKJv+PDpTZ%mA@s{#a>4gCK7&_pLflcD@+g3AJ|M6_ed@|mXM7edD-ITGI^mH9Q7;(qZA zON5?5;X78WmAl&?3NEauT+=6d^u`g3+kVV>AqcSTlfxU)bDd5$5BtY#J1oW#cHh?(5cvki>@W*p?eg0bf-lxihO!_OmZd-1iqH7U%cKhS3fq)XyV5ZBur`n=A&CZrj zmeeqp=K6gfknj=J{MN_otKN^zTqy1;kNE(C2EJl+AM;xt#0{_+PNVJSkxQums<^cz zR*LC~tHah6q|hv^neqR|`-T-uvogccsnx&+#Q9f`I!teWg3%1#v}GI*58+<};EXM( zfu_E}_WK1Q1V3t2L^i4X1ggXC$mmf4q5?;)=`S`asLrTZ6Gc7*F;vE`_AwtP;*2-! zNi&E{VPqq0nWYEuerS24GuVuf90Ca1eZP|Af-;1JfGmTIy5j|aUtE_DEU18!N!3S3 zgHBX2P(Bc^Kp=9jQJ)!r^V-$T=!FYx06D_}0V&u(q)A%<;~_Ql0f4r*+>yUI=ijZN zA!GfgG3sH{AGRe!AEAF*G6L#ORtt#szpcdLCu|bGB&_s*S~Ps*e;VGufB%2$8F7IB zX&V0y^VhLLb^NFOSJ1x#|L^^OwS=LDh7*YM|5)OGl=~k={&)8Od-Z=R_dhEAzs>spDH0l9{cHUHk3uh* zKn2j;AQ~3P#ujbfCZ`a?D_9NC6TZKPEdhfa&M<14D^L>WQ}QrD+R7RLSjWw)Q$6~+ za`1oUj84ENmWtso!Dfk71*^H%Z8aN?>UB?21T{UL8?eniK5~5uV!5bGv;*`DWjtzc zY|Ck_9Q>eW^A)|VySkBNyZ#L4(FSTz`9jYR2)^2SY5?`tovYMGO%3h;YF07CtUKQJ zSp8n7^WT}$PU!=)n-Yk0^9CM%v2VhSzqjtYmkuPj%q&32LUc;j zfq+$9qb#C_q1^knxUhn_Z<6Ml{+{SCC4WWsr+K#t|y`2^7 z1*5r9<=^4E@d)Hq6zvUwf*q4kPvETozbpLj6l9G?sh36C4k;_+jtjZuMaxz1T# z3irsMsDtjexS);E=fUF(v2GJ#9s64RJF^}zC72y7Zf}o+gg^>(+VkeeUA3#MHsJuZ z42>M4vZxCMeNj{{HMft_B-^sb5!p9Xz|P>hxF@9bA_Gni8ID%F2>uOgsDhW{RuXw( z#yfQGnF-_@ao8~QfDQ!ig_9;3h2%-*xi1}EDx=;``J{`^<>BJHfew zyF<8>(+48p1NSxp#pYe@I8l30MQaY$Dm4d0`vF;B;G*8UvjK|wH&5?q4kp;2E8cfa z^OUTcl89OW;z&dS6P~>>N+|<~R9lZ#%9`*$R8-her?KQ>N+gfKXh`}l+~ud0nSGv^ z{z^G9Q;S3Q%`)Tu=)4;WF$+b&WgY3Foq)6W zg?G0@!=_6~y!)iuxnyv6*ZXt(Z+a$#xZYi%ok3G|Yi`bD6pflS zny_ircv7pv2?e8pY&FRKiiELd{#gC%uG)3n3;t&4CX zPE@%Sav9jZ#_l$jSLXj@RLKE=qN7#kDt|n0oCh3l+y`!EZ^9AqMm&#`lEcDw!^fs# zk6f}2BrAy;RWbBJkQqk*CzP93Lkk^aPYaL-m8fe}=A2PaLEXc#gp45;kf-Gp$aKmX zrmz?IcB|?|9jp^cxUU2m>X8iodH(jF+}cZz1@l1e;N8K5+K;LRNEf787J4^+s`MbH zm2{8_kV=rsr{PQ1inKt%(z!8@?xKhIP=?L!Ad3p52g#JYk;C*SJDJUcrEf7q&W31r zYiFvU;m;!2oTFp!M-lRuIwY8#WNfpyep=XsQQOchu|Runm#6J97D!HTz)v6ujGiz` z{Ofa|F{czP`K~@&{Ed13**9I)@XXK4%B1dOQuOW?e$@wSZIYNC8;cA%o-T=?f3)gj zzZTk}MyvhO3c|CjWB8>@B3dH;IL)#dg!&a5b!6LXw%g`@fFr&1O3GUQJ5snpgNF}d z6f*TV_I`-otsg3T$UFRfEc6TS_REWF?I>%B6M={BG4{F2UnEBhcI0knz2UtN_Ka!O zB57+3B&GQ}iZbbdB&fTk?HV_}@TFC=A>FbU_}CrAduVv@&7m&~us=MFOQXebJa#oDM{R}U?T-t@aj1cz6z1%|_ ztsLj^WQeIy zp9popZP&E%OJD*ff}xzbSAw_}ra$D}R9QYC^GYxzE@OzJw=Ue&=spg4U??v+ zPOm3Z_TTn)+MxS>LfzS%l}aR-%4Q@`$^LY)P2cS)Loq#Du6pl9=HXyK#a1FEK~_C$eBEufm24S|0) zmN@V_@Ol5%hmREtfE zug~jLco~kNd=5R*^}WP(Im!P)fGo6l&gE`8UG$<}Umj^XvmOHNSN*N&79Cc~-(XT) zZ7ZBBf5^4)+oqU!sK4|{;`!P2MyBclqj>SngUeKW+EKXCbp66L+coDkm%lxVC^;ct z;7wbb7r#E$I*RBNRp@2o&vuZZRz6WAkNE~D8u^IDdVZdT2yXpX<%cdWCrnB)9#;Jx zB;{DbFw~)`@ga4x-|Ac~saH(e^7Ic?9SPo4w|@O-i38Zdm%@jGm73n<5?46W1Ibwf zP|OqcWnD+g`gR4k#a^oEKlh>FZ2%=jA_**TjPP7zyPm*h&uaIs3{{Qc^7e67FaKp} zPe-BSNm$F%stQu;#1~kChsx)$SNv(^xn<4}fdZ1#hw@z6Q5pL%uW@b*`y88}GU8s@ ze`AlxT*7>OhaH00)Vmmb_p=!^KJ2`QUjrk3L__b!xkKhL>*t`FFZQ8%%=sd{=$V2L zjen+t}HQ^r~^ibD{^^uz3_ zKWO>{fLCsJ#BM!;M-j?mlbqnkxVDvwxO2cc`jf?xbkc_;lL{Uk$a*;nW607o+j^P~ z%C$N9?LSbZW~f%@4nKPX>|8?N`P3QNX0KS-Oe9eIa7ZH9p)FWTh3*Y>{4fHOlGU8XOMIEa{ z82C7+X}hwth&8AVC*aQjf5O7xsZwgXM-Zvb!@sbAjw)cHSC6R-ZWp}cF$~=?X#kzt`im|Z6J^zCwp9$!Da2Bf;-6ZxQVjiOjCVo>PlOS z+cWH{pJn}|7E7XBO?`dI7t3ezvqi1NL&!PgN;&&a(;B;$7@HLf7QiAp3;}2FS5^_- zT?wg9$~f(1!NY9L=?N5|Z=OHX93?KP)I3&!u$cOaax25kb}BwYoch7_|p3x5;{pSjcaW zpvT0Gu4j{MYz+fR!_#g)XQULK(c7UxTM%gYw>hoCjg20W&3I(!T)MsADJ~ic&_v&psb?1g})?23T0`EoOx*=l6to@Tll1a7KvOASR*SP2(~d7FP2>DqFPIDBH~ z+f-OS9GFp(fS)mQ)2!yrc%nbw%zR@``6o;8Q2-8+Sbwtay>of)yLf#d{y}?SG*96j$Sfu_?4JXosyan>Vnsn@zyIj)rUpK9>jJ(JdPLoh-jNs*CT)CzSp9OIx-qFXjro6nb(0;z> zv06j!^t_XEnxoEm2fyrfLL+_66MN z_EnLprld-hT>3NP9uR=bUvBG7y<61;(y$-OT!-KvMvl#{+XE1<5Zhap>!-Z$rE4nP z<{&V(_n|gd7=D6QRT+@{gwN^97DUp7;*aiiZ6wkWdG+eT3=u4eO^quWC6`@EJT|_n zJt#)1+e2Zr@r%t>JpAdkG1If2^D**b9$%ChL`CDeq}_MB_w$To9VuF9!a^PO?%$kk zxU|Pk1v}-VBC#8H%JtQXs;)mbe6gGPajM zmeGHE?u5v+Udes5=`JHllJj0z_#(}|uukX6kVpBQD5!T|TjQtlw%fei0v#l9P0F(~ ztuZl?YHL0n<4n&=Ti&|5K*q(0F@bV+fVj8n#*B$}Fw9h7J|k`(6rcMsHODrnz;A5j zp8oJ?Ui{#sL-ik{$X^Ae22$PGT3 zB5qE2zx<7!$8W)jM93L61O1w~A;=(;<@JVT(d?QW9CR%G>FovRT;kOXuNEhOkDWGj z%}`)=s%An?)_YM`-qZAs#65)g22Aiuv}6@o$n1d8#&v(GXws}rN0;%QP%KZ_MZVBX zKl>)x``RifNAdJ$lh>*tbh)Z+F}Le_jh2=x|HKo#M!E?g2D9&_kTj2Z%-9Rj1B1T` z`hWZ(*l$9_f^W5$DMAUCL~W$oiK?gzM8mQP+R;OW--WAyd#C6l$*Rw4HT6b>!aDCy zcr&$iDUZ#iv4TqPgv50$3)X>nf=AJq$<>Q)3s=y~O1C@PG2emK!Qx1`Zi^l&`+91V#}be(xqrZkg+EN76|tK9FfCgTt(4Fly@j zSF=wCZm%z*`j2+h2wv^{JQ_T$1j8jYZM7r6=cG!ROSVr}uuGf?fD#TY@YN6@)9I~Q zG#oraSX#FZ2>tC_7qfRs053s&5BqZ9FTWQ<7TUq#n`#2Z!@VDGx_#IWDJIr1<^n+D zeWGc`>|_#g*{nGA9aFDuX;GyIT$WdBd;6RI@f6DACDyFfdL-blL?6KbFE~|Q+ zl^n&$ZR|bFTd4fZrQp_R73s`EPoMF1eEGN_XV?a-SAo#q*DCUK$8;!O*s1VJW)qQV(f{K(jGOALJWk1TrzK+-38UJQL;ts;4sa z*{Z^9ik@H$ByvufU~rM>mc4BiN`vsA_6S?)6rOkUF~*b=sGOO}if{WGE761=S7qu8 z9Aqn|_P34yTMKaLW~o_S0{%6j_GYW!4Jh?1wG?yRsaT(~QyrZVK~9W=d?F27;m_Mz zX?FD)8HPt^o)6;y{Z>ab)*S9we<)?@ezL@95wY6j_vlX0ecoQ$-{N|!rr&JM@>cq~ zFnNpnQh^)^7|D=$90L{$b2>pyDMa5E-)D+T_G7}>8tK~mH1v9C~4>$abSpcU5{0k?ziAg)EsPOsC z#gKH>Ec~~pA7({aO2d^Q*bp0icEo=)FzT|F&!sV`$kjde9F*lSz~ zZEn~}(bLweGQG z?_)mlHPMi^S_;)S?eH^Odf%=>5zJY$-Z<$NTZo~qF6f%1G7xe)s&DMq>HOdRZ%mC z*io$2o$m28^G(WqJB|A7>N-CF7S-a%R%4697435CWX7#MN)h*nfAOrG&UDiAgje2O zY0Q4;m(m>my4hS|4+JIqW9R*NSc1{quDgSSH7K0BeF$j-=?hs&=fTQP#;CJ1-B9t` zy=nRf=9+)7{E2g5`DvlBobw9KoAiOyTSWM`BNk9LlEDc@`jpfCqFj61GyF}s3e^%W z=}Oi%Nw$)iwd-EN4=f2WywR@~=ChT)VnGpq6Fy>Ci`O#1a_d6Gtpjo~Gb8=sGCoY~ zG2_4hSYol>q?9=$Ok$>~v)r5UBvEebM+ak9PXjd=K%}5_0ehOV z2May9M80Ibt&qhC!WvTj?qwVvot}SiB#mmShS?n8`R#XNpKCxfKI)8JA9lt=bC6O%mx{ES6 z1Dd5|aIw@D2IcwcqY(g>ttQ8}+k3aDLB5WYhmD@H?5eyS<)`eM_8}zH!LC4EAOUe> zIJ(F+!!_eI6BJEgxn_lC-0asJdtY>FDF%2cAhVu5KKDyxzgmPX@67QM84_Z;=r3go zbBfiW7&QKzk_Ba+?6mKPe`+$!bY4d?tRSaT@5ktWntNAT|`w+LkY79vU;a4v=&B?!2C{e z&}n)pxn+4VOo+$5ETC6EG8#{NjYcLK?^vTkjmp{Gy)8E@%>j_yn~VH0t2j5xk~9UU z6!-f^@+=25DpDbkkHUF-aO$yE*8BVb`6>Zd@%q)D$5bug=vM$Bj(9#|LD^1~)T*T% zeKrjW-mM5#lgp?csq{ReW1SyP)kEO{1@A-t0!nmZzRcd2J!U53ZcnjR(D(kJ;Ya|2 zx0zQruJU|Ugxd2I>_PJsedAmWx%9a|QUAFF&Cu4-piVp4Cp##&Oa_2$?zB!S(kwS7 z7xLhYsw*=tOSL0Byo^(Hm60EBRZLAymVB3?F+-kG&s5*x`;60P9F50#xVx2x>U!7z zIXW7-d>{<<>b2u(ZgSN(H5?W`w&?TPN`yh@W5V%})U&yikh*Wh%q02e70!B_?+yMU zICtAsg(6s3Tj^5dURUU#mUpHde06*|1d%T4R#jSE1mq%}`6{`h5+kaVrMOn{ht5o6 zonMrMKHdsJ3+GBQis>=mU#4B*5s`tQ)*dr~E7k3*#5G&R@pMI`!+l6N9+N8KxT3Lj zCY-Hs{06KX4XhLC;ZW(uDE|C-L#9CKOEwG`P)a(H9ApgmDkW&H+tZ8{8}I7tYjLIz z1jwHXwH}T}Nu|1O@<{DmccefozQ$l+q&4bHN;V)MMEREn&=y+GwyyRAr4DMT6U_s% zVlhoZ8#;F^F6N!8_^>uE0)r8;0MX~iA3AH2CLaS*J;fS9Tb_x2^Vu#Hva21}CTI=p z6hHXiG)Ly=XhFGD8HFHtdF|^M(Q`9TB*lI`hDXGF1hvsYdy!#2&HS*sz` zBKn58F>9^c3>ZyasbfOY&XyFB27>P&G7UPwhWT$aIweJV)OnJJRhIg%;L=~c)BQhP zF|R)@qROE(J4Ac_aA{EZ`y4Sg5FlMEjLjtKew$_}TeqwW+4{brUVdf~Zv&FlLXzeX z=;WfMhU;vWR^p1fG{i(5Wsv(qBZh}XJjRI)#n4=uL0hhiNr;ij!4}Iq5-dm-A0!~M zx#?l+HbDhn5Tg{cbgQ0TTuJzBnaKs+Q+~Tp-LolYf>WSikz%{T?`6Yg`G3@K1WeOC zNz{YhXn8vb{R1U8VfmklKKW&2$6wO2Pl{J^en0I zct^jYB!@Vc9;X{%LMn6?vAah}T7x|`()n_9VBYz*Nfh~EJAQz{o2=u!w!9kR zaeLtG^n0XQ4fvf|o1DK~X92-;iy9+Wgl<96sjxOd0$nPF3Dr|&Ddi68N3{{I$G30` zqO$LLZUQau)~a{ZEtw2xh!fBfKHSYfUP7#+NxC=&;0R*_-L7dvmJ~w!%_e zPi?u3dQ+uGFg_Qrr;ogMHDyPPf+fY3CX%hfzjA8DYV224gFEi{7?i0orUur~4BRfR zDx52xK+5LnrB_BiDzQQUna_Rr4p!9|6x^xVMSs6G>XqeI$iduWQNG7r<{I` z*=@01UaDIJdx{LWkSgam#oDiQPc6tJ-+|F4D?hc6^51H~uKUyRry^qN61^`DpE<ONO!^pA@5VJcrRE;k!JkM;DU1txm3v+Kr~{lmi)$bB42rkpzlL?mgw;0C5Gy zVk;&CzS>-=pifbm-x$8vGs`HSeGiL(oa%c!V8GIW;Q6mv=Vwbz*eLtGY zl`cl}m8%u4UT%%+>ul*ahPQv!+kRuuDHi&J^*v>!b=y!@lQHXddF=hmm ze@*oJWV_|Tg-9(E4KJ^v3zRV|s{GjF<$5?HTD9&NlnmZZD#*Yyl`;TZ@c3Olb0I=e z?7`(o_K_y)dOhL9qA+vJtMjrq6I78-gW-z?#E>Yh~c`Cr1KQ)96q@(})3O9apw9>Kebd~FC6$$pwlM<@c< zmpO~*xtL@bP@W$Aeo)1?yrGJ5UN6C&n< z34J?Tee77*#F7@~%GD;MFa#k~CYT=nK^Qi68+*2@SbWHx&^)Fqo!F;#!GMV84rjk> zL6H8JxN{QJ9VHvV67*t9qyB&~v;KlF>5vw=w}iCAS{Sggpx=FscDn2m2Bj=5X%MRq z`k?&am%vak7hduO>ify5J zNUpU9$Ld&~p#`CqECxw|4p+7TISNq&1DO?lZ0RoQH|yPGB7Gh!uD7xnmigqtVo5N= zN`dy?DqJgOCIP#wN)kh%&a}DTjeM~iM23}@sCvH|%y|?v@U3NyUts!r0p!dYX&8pJ zjxIWMP^n=wfHIG4P9j;ZUl34~eLg9+@R51O-jPhvoF7kE27#d4wA*p3N>uZtsKj6N z&z3(^)lJL*v>rX;SSs#y8LQu-uM&n}SOYVt#b6JOb>ecy&MSVn z=Qh={u<+AW&|jumGt3uu(S3K$8%m7FuPygbR48sBt{?uX4N%lkmq_z;%8#o%#x3&n zV-toc{NAJRrn+o)KGo&=_a>Yu+(xDDZ_2*)!uKN{v)zYc=9{Nzzd1UZsS%$4mLQ~I zQiI(G8(q1Ep2MDOeWPAIMV0C$BiNgKccmXxd~J}N@tFu%QISh`1UP`67(ck!jRmKm z??yde6H?gA33*<-TzRuJLJhHAttRR6r>8u&zB`dK;V`hPz7+}taJU}##82k-eS5$R z`+@aDo7*GxS*QkQLEaUy)!M1%wW^y^BBjTt!FUe#0MaU9{MiP|I-&*3*(996Mtlqd z2q0CM5C*uMpkE%F?+pjH&bAy%V`%Mwu#6f33h4wqzQWnFuF7F7hyh9g zR4yL*T>jdPKN(cJO|Oxr6gHyD2(+%RflErJfe5&~;Ck;^*Shk8Z5&V}7X~ z!{s?$JuLh}2rTv|^FjkLyY56G_vbhv*Za6$>nGG#3?Zgs$&abLcpfoOrd%!h4Gr46 zcae;5l&z)S+}WFAl{hWTe|Q5df}e3PR3u1ORz(!Np3i#`qi`6k@l6e|0~-;QJRlaosB!iK?zrGJPI+Te1&u|+>N9>l{Q}qhR4m+ z%*aY{R3^6R?OulRl%K?K*d|0rLcUM#vz4>$sqD%~Gj5dP-U`o%_9X$`6bi4tqOs43 zF&VjquXrenF&NO|lqKk03-eVdkV~AcpwV;4{PGJ&x_;Yz))CLs7YX%RWAdu$0*d*U zE$*s2ODS8(jv`eY5k?z)eSf2UF*}ja{PChC*q3_aQs#y;El{hEHM!Y#vkj6#78hD>NH?3_T7@_t!=h5Y!Gn|j;uIS7at%u?Z;WafN$8!kQYTXufHiA1kDhMl&hXJ6T?aHCw++uO4WL30McPsBtz!dz@$37Y+rca zQ5E*5jBe20Ss zK14J%EWBiAvZ12Zae;QesSeDg)BS`;@^#{{v|T_}^1%M25QRXt+^#+)Gl@izP8b{$ z&e-Z$)~9d0Zp6+ZJ-@rO`8J?G(=k^OsnEz0+rSK8|yo3>9z_O6$|i zjDLM{AY#=^m!8n3eTOO?{e$RDDt2$N1x!4va63dd|KfUg@kf}YT1qXN^3Pwe67GYZ zY(ErWl*I4}FltiHe?1L0rhOa1Y?3LdZ7(pOVHb)c>_j1ut9`htJljVVxT>1mk1lBV z{an=y&Yejr=C3eMt0X4ivWrp_Zzsv9!=S|px<>wNeRqrRja^7XdPlnW9?YLk@CrEw zg|6L@{9G*YnE1#a*X~P}!)4-sSUn=Hgb-wu6{-`8Z)Ov;M8na8Wxw9!FZOs%jZQ0F zuomE}TJ>a4o5t|jM1rauf_%I+(#CvW)^-Sv{>xv7?4`ioIflsmq3pA5ObuACUiapE zYl$WuUD}0`z>YE$Tfq1A!mF81Q%e`dQQ0P4Rz>O?MS=AKat#F-+k7BC{gcgx)F2}m& zk@T_Q;V-512oP%(@BWJxbacG~KVm3~Kjad*{@yo6Y$M&XbHCj-K!9P2%2HCD66ok%5Ef0CnNuvGIRuij2ul0)I32H0;}yv;`W&*$sUpE2&|G zbC-YZuL)qSo>mvarWA{;i~JFizFB42o4td5H#)QRwmM_T8EvSEFrCgi)?lSSzMCB$ zs4p=g0T`^VMFzg;!A0`T5SUQ=#vkxsL1}NYuS}a_VbQ2jiUN|~Hs%rFf_vB6>E>CBOLy<+yCXTSC*=QN9n>sq?EBWc zJI^aj2-7Zj-6mNN8D^Zw6n(CmvViaXiEY_6b{}XYA#+1)W%zmXS-i%5%kTD@*r?kv zcuytQ^dQJ`EsijEW*S*~qSv`3QW(lcPyBQ?D=hJE>p(?SCV=ZqJYO=_Y*fI*U0Oq( zM)CUn_GLXl^6>l>WAj>&butKcAfOL>(!@9o)2hNBS^$janlVr86pG5=ZcFC3P{KJv z(zI2^#pM1$P1MMgyq*&^GazesD#TjPkaDr=op_srlpTNFCeTMh@&1RMo^IB=VK-~1 zqvb76+*N43r}ky~6)076WwJ)9To%0;z1nJ~@!PM1okk|7SB!+`#9UFtrL;!hspxT;euU6N> zoWm&S5(6v!u|+_?!2;&_;TOtsiyzJB<+dcgPkO2`>Fh;%S61qSsq$=OC(GsZem7F6 zh^Sn(016dMZSik;yfzC+3n9R+jC}qPmloIcCyb;gL@YnL&Siw>ZQDXT>W!cu-D9M4 z^EE%Z_~2H%alP+cxu?I)ZE8YVS^MrZTtBN!NqewbaTSJNlYUP@hzko9V5;mUJz=Bu zt?BF(AT?D9%o~`1+oER-3k5TPe~>ZJUPoHR6v^egiDaQ}f65Kx<#KyaU+&pwl2KMi zd^hx#V)y6Z!S@_ym+7}4<7iVsL+#@*>enhuRPCi(__4T+uSvCUF4pMQ{iNW+(aZiE zA{&bO@9da$GPu8H)En)9$7Rm^+~URG9xoIR8*UK|(Ex7wx>< zhf!+KJrV}soLPbUhF;vYz zIt@+x1c=e5+Zv$rx}i<*X!#T2M}S0!`nN0)0r9-J_SbvxXD*i5Be%UvAY*KzbV3aj zRdaNa`6VNQ1H31vP+O^9tSy?#;ol?|-!MxsU-$~M@%8O|r4@g4ev-To#>qksP0_A= z^3uhxUvbcS>V;vy26#h_y0Hon;{TUIaDudo<)|A_(tO8oI z{hl-20QJK`q!+hLskoo3sRPD}wKyP*bFDB=)A!GYSgnEJDu?#8MYIj;YEn#%@=%k` z7)^Q*a;SAG*lonJO_t*dPDXUJ2U=#ddwrC%soAChTRt`BeujWat;W#+4*~y<*;BsB z?dcgOB6wp?{nHgsSFY@^DuCqSR@v{*b@ATl5yr9|7O52TA^*dD~z4&<@j89`W#i~)Yd$dpEOReqCX?RLow z-_yGMBob~gM93M6)Wof@!ubB`oie@M^4tmvXPb+htoG<2M$0ENqFiB@NNC+Hg_P9s z_n7IJh}*jItj1zDPa-P3G6F1>JV?q1wzmqx?h?@mIPX%z5SqN~P@dPTsaDtkDaf2@ zzn@h5_73rB0FIZHwPewXMz(4zaX1y77^7UJ9RH$VuvK}%|!5vl`jwF=y zZ#*qiq8uEoiKOD8Hxpsa+*IU-=P{RhaO#FnY~)i@uzS1G5=HXJu>S|ds0(~axq}3S zEFL~raeF0BOr7dXr!faWR6pxz+z4G&tP!GCNEC;yXct)6=*jCs4?pUQGha77bk5&( zGBY%<`oOgg7ftK@V4!nCd7CT#1B)K0YHH_=(GU&QT9#YG;PgswFD2|N`r zIKE%RgO>5t(rVWsFf)OWedzOc+K8ha49f2%O@IFAwO0W{!jir8dRo5k_EBWV40=Km z2ocjqqidq0zSMn2 zExEW`=(6isL3zhVL`bOHfeG0~cXkqV%`BC1aK>0$b(j!*7kkCR}VmwQu&cLT~7#kYT}@l(z- zjS)T4-Rz`;!jMT8G{&$55-?BYMLT0RbYtAj>hwkt0}W6luH172aGSE1J?`U{V@Bk+ zhp=CVugE)JhP9D`54jMNU*CuufnC$Xz2i6L7Gh!dWHYql9&SR5a!XW+L|%e_l^YO< zOX`_N&aZ{|RJhbr7`h~@2O9Zc$j#+{&*V>O{uZAvmhPaRhesBu+b++Qa?)AV1cL=9 zort`V{?!TPyIjO>LE1M1*_Y3yNjAhVNH1Si7x&6JPg35K#8{q6wgw7#n-y9Dq7l`- zjO9O5nLhEyTU%1o7bAfMwwP2nko%=o*$ou zco_X$4tk2_V|$vtmqiE^uTCt=$=XpskA#=cL&>Izu~{u^t>HOdB4!zJy0{!7vxB(r zd)0ClI^uwTy$LfE#TYRW&kX&{<{ZcQxtMKik{md~QH zs#h}oR5Rm1=y@1MF-@-;JZkr1XmPT00~wG>TLC$9zbxv;PzH7|x`~_VHujjNW!;i@ z(lqw{#!{VPIodXbtS684(_2-N(0Oy@gl>xcO@eD3Hb}|Fn0L6gELIRRCR@*#nZ#4? zlNu#7pw+6LynPnq0_<-J%%U%&8#;NGK%2dltOp+PDl{@YUGO4ZiiF<3FtZHn=%Nv9jb2 zDsr+EBUlqMkSK^H22DUE`bMmD$zE|2*>QFPym}Mk&|{Lx69CR#YP){>K!7PjSy>EK zE!zJDC_&f0N5BP-A#ha{cTZ3&+;cXSOadhD1+O7+BSER*dbjV{MhliKq^P)Pn&9t4 zp5EhVjL&!)<2{~_!I7afYr$+8vt>A@q)}?n3{qON*c4bL`yi@?Oo(14$ zNGsDIVfpWTO#y8OwDqhj@!9={4bCudt|?Fy2nI!jsFugeJ43@PZCM;~uaJTaK-kJW z(;*`6!Sp%P`5wQ_0d)zGml7cMrIzJeU=(nGSexi~F8K_1o9#WQzurm%;Luz}ma{U9 zb1_g9SEu0@TqFmWpy==CPVG69>ZrJHut=;G@tLa4&(o4$7xViw3nW8v4jeI**PJ8u z9e5ws!jFX_PZG*F>8N@%ig@nqF~e(564pp+Jh_Aj{39cwOWpwKg zZGWbj^Jmlfi)YQc%Njv~=ezXo&O2{wgPiI%6350388F}d^aC9@vX9@B<*ICJ&=AK{ z7X*|prO?TgE6P!q%lzD_Msv63z8D&UXU4>M|;# z#QnfLl7mP0bITU3DWn9*%hAq6i#_9rxU(jRIXjn9;?amv=SJ*V0z?8N>pi9}CUKWn zD0P5Cb5rH)9C1@qKv*XDoNrpS{y2QJ3DmjAbt09E4@h4=6w-=o6!kVDCOz}vsjY^NZuMS<*FtjDcP)3 z`T1%!g6W&Dy{SvbQ8cjk5N`L*8L-`l(+}T!@m%%tm1Fcorku1$BtRrUvIGxgSnb-s zlYZ{lj$I%*4-VU-TeXIWnChnm>{kh(AnQu<l|D0Nj_~d__C=?NH}qIN-W6S{i;PuxhyHoP7 zW9U@UQHGHcC&{`sVxH1`fo9B|nQ0#|+|yR=+q|?jA^E)En5GmXZqwOJZu&J z!Syn2&UCtY`>L9{S}SAgL-+Mx(5(-<;emU=@DNJ=!UZ~gYComSX+x==|D#wHo_|sR z0dTPVRe<6zeALAJ-~XdPMI1GlTo0;9XSYoi5E0f0Tw{o*WW%MUUEf*p_tvd%FC8Mb z;EZGkjNsLZ3ty(c(fm9QL{su8-i8(N+2@nUXLKJO4tj4vb+D8!hAtqOLa6mGY}eY8 z3%N0EHoFj!0FeN(Ti_Nsn|zwD;l~bb^-i$%j#@>)R?E6F{=U8;)}ic@?Sly1GI)$} zvS0o1y`Ft#-Ot~EzHZf${rqRtseyLKJ2Zd-9+xgr(w;?hJ)ksO9I1c;tO^T2+{#4w zb>j863^0K;k~-=Yy0owdojQL;eC8>0msS?wf$KzkXt9=^X2S~6+*tjG4tgmI3tu!q zOs$j>>=OHW@tKr6n$5y$Xy3+@EsJP%8lklbgw}cxYHgT!TVia(fK>6c29HH0{Ah(m!!dB!1PO!afB5n3p-yxq zwmzK#JOoIx3K26aB>7B+R*2qcv3WDvv1hxU-YfxP4?L736g&pk{kLc&PervV;&*83 zY7acLqtQP8sC$6MF( z=U((68wCBXkP)D@F3HW5G6|5}bX^_ite(kX!SqqB8kx36*LJml1>9UszWav9!NP?! zZ_#}EZNqQ0b>|k^uyq3$48|nJ(ulF6sa5;dY8r4IyQc1CmL3cNq?)$)mb14UvOaWp z9N~D!`Sn4u1i3XyZ;@k|8DRmTxoXeUeVzfe#a4`3mdF-aL zcE5~nzPRb}+*amga$~({3#5d5ELDDQ8qXvO3f(Vc9|ec)HxoP;C}iZAZB(XWf(nMr zteQ9ud?P@P(HF+f=cd_83NSEtDcHLm1*wAJe#SXX3P`%@9n{g-)_+_ts{C%G+9l+< zSs>Q?Vc}Te?HKyFS}4`36Ub7tb`Vd;a<34prkff2U_D=u7^yG2@jCFI6K;@{bF^yh zO5UZ~I|>#MXx*tjO`AQP_8!{9eXdf}URZFGAP|2c<*eQd3xGO$>If}exs(PDAHvqf zr}gUEHS5CG?;EH}alEfL7a}@heei3}sPNbvO{t>=JcQgt+#(xRheHsFtFOAVPADnE z=T2nFouw&RBt2+J2-e(K_|AF_=u78?1tMc0_6fRsV^nsHy7PEo-K|>>DdqC-boJ^V zCb{+pT}rt}ckiXqojYk%Nx-IrI$GP7M+dGY=*wo!CMxj@Kcid9WN~0{kTpZ?j zIExE>=luw7qBv~8Ao3GL!@{(=ypiH!gMGSlx87b|N6_bA_){5=DJn=5ch~cPhz1Od zvQ@^}%6TA;v?+nK@75*L?zT|acnx;^iL<8i`w_H0s}}6RlCjl|7Xk|baDl8^w~{*d z>dwA-EiU3npq^hVq)wyH+2T2GuUkgDX0hu(dEp!-9sG@Mj(=5H9lFC@^^;FrTLweG~cA7S?W-1Y%+<~GFr1mYq2IJQ>{7e-oK08UZ@F?0Lfg6x&k0` zDLMHrecpH>>zHzt5~-{zb_0SR^q zg^EQ{c;o>J3E$8DNIBBhp8uGN>ndSJB2}%Md24hir_Q~*)1Cvnd9H@`pWAXgt2HHO zbh&7Kt)ThU(&dzZ7MU=?VA@7$DB z!;!6>k+0DCO_6K~oj!9kOEn@&t;`wPveVdT(z+W98-SVfXDOBGFG+u_7Y~qV2FRsL z_o&Wi^XaYPQDRpgt8ZAL>s~JsLCwEi%GO9m08uu!vAj9&(8iN>t8s+5=DrH{Zckg* z&8H`iAMxn!r%#_TKpsDS%mRpLKW9%Lq}b5@=^(-xT9Z4|M929EAri z4j0z2p&yemPMu0<%m}b0#%Y9j-|&Hh=-m&)P2?+^dlm>X9{`O-OU}@OMW^ULg~EB3 zx&%nZJ6Bi)M^7H17Oh)xY$7AK72F^FhYjNQA=Ni4Lzyi5YvG7axzX`40wQ%CvOttI z)uOQIaE739J(<;eC>d8NbaClmx;4~ENx9XtrvCbTAR<0b1ITs%5_J0H9*&2cN>W`} z4t|$fFulisJ~o5tcn)pw(aaLXmc~9|5+JrWr$t<%sb;--l#=p0)%#)r6)QD`pEv5C z!X={V>lVxC+O_-SQN@-ED^9gO;;G_0Q3mV77%cD3F^=sU7cm?FjYp5tbZ{8u(W6I{ zmX^k^yDGlV=%C(gjTi&$N>IHcebwAY(Z%IrbISsWqhi8hz!+Ls5>cvImC-m`TPbDm z=iwZLxxR#vPK4al$xk;q`08Iu0qRj*%<+H~%~ zn+F*Ku|J3otK#zI->H3<-{_yOhjE}>n}CYP|L;GcG*8_a>18~ zU>1Chd^8BYFnp=A=A59}^G-+$#7-rSwRY;!%`BL0t(VfbKcYF|es+`OR5f$DhK-lc z)5vk7^@737AW}oD3)R)=G;0^kEUb@|xouf-Yp$#32@j(HUa6!1L^r+vOJ|O5X1JZo zLW-?6qXqGxjH>n#2Wj|KGup9tJ9k%p8R8%>I*k{gc&%^*Z%`2jsa|I;y;VG#-R6bV z;}=bSq1(3~QfR~h#f4rW-lhctFArLgOyT0cuKFfi%cQz2Ec|EBh^-52@URAv$Bz}z z%%9=Q5Yo;WCe8;dCqQiG-+3>Rlc5w{mTiET=AajGK{kL7yPncp9bFj`I3lP6fv=6l zrvn9gwV_~fj4-B?P3oq*z7RJ-PV(El_^brfQD_rKRX&tn03hB0AZV^CYw)myh~~;V zuxFjn$*uKGz7k&ON-@F;LDsA@yRmZ60zr=Odmn~V@I+xvOtO*I;@!M6i z?g^*USqh%VPr}rr9MF;gv88NInq}=^riZm1zwWx~+gr`pvEeVb*1Zyj+QQuwtao#=W%DNZd`+NvCPcvGNl3J^QYw6|2tD{)5+O-+^niV&z%t)NPFtR4JT}e4h&&c}EqqK)~^xziGRfbg(X@rP>SKSZy`R9}Lc!(okUU5Nx zn2qf^t){k+j;pDSL0WfMr9WTivjtS#ZHlY|$z;b0D0J-6l{1+v6^*92;U>aPRcn8d z&iXL+kve;f-7lPyDqxXx=r>9_uu>?*L);<+K;gFLmg%$x1&AZ=Av(<3vO>Oy7Z$)!;q9r^ z^qVC@UrwQay%A2Y7mlPNC1a?FOAP(ztq3aPksx;WQ&?Bo0tj~g$V`3rgK!G+>8|TW zMc4MAAfanvK`0yIN10k5<`7XVkQ>)7Qq<(06z1F6%mRV_MchRRCFF<&q7?sqQY}P$ zP#4|*W{i2js#w2jhMqE}1$7>)qWoJSC4O$+xJ=WcM^MPb4u(ofC6I&4$Wem_Fu_el zE%pb{i@U{gp#1+{4W(BLMX(PNtpy6H?FA6T!VW=$hpYp!wNq8#frg2VzHZJwaa+^u z&=U)m!RZX#R$40%3{pCMVi#SS--WJEa;2MIuL}7WXBb_c(NX|qjq08;xSK4pxD+eo z0{I5|bGDGy$kDO|yjIU(>V0KT(?ryLoTW1d*U-&z|I2X)hhiTpJW@v~9eJ)v_^fxM&wd03NOj>BPWw)QzP<7_gtaXr9d$@AVruYW_<0}%v=+e*L#*#NLQ6cZ`UB53p2JQLudk_mAA z>P3nU>?Ic6#Vnl+!5jqDIiT*AzyNc!7Y%j-W4v}yw_fY`3oI+XKmcRY=8H6E-bwx< zOXxcQX@S_P{ebTqmW8Hdthui~sa=aE`1@qoUrO&Im7GjxcQ2qDz9p5k*pZ5o<<{qT zj9~TnSB0Vt<=1KhmaHiXRIe{zy+T03dLS4I5OpK%x^*^KMaS)ke;nm3rweQRm0nju z$=@9F7sucsuH~jrAz>xNa%*<(tShePl&~01q+AsM-A$LLHdj0N{tp)n+V93vI`>`+ zt-_5Km3!-0TNbVd5m4B)eWT56Hl+nkefptoYdRyduMmmXhkLxv-MB&51P^R+A>aJZHo$ zyDlv3&QVn2USSH2AJJFs{;0W}y0H%}Cb$pXzI9D3>ZyJ))`+OX#1P2Yw{x{xVs9#H z(NcTcwjSfqMQ8ct>m9Pp%AIf=lSkk&SfI`wg`q@9&1#fT9@rIo`SdmCkLSAs})- z9Yiz*h{s1y9_GPP*4$Veo2g%yy7lR0c%L2hA7>PRT$Hhjfu>s7ZeK9{uj~T5>HQj=KE6ZT*VAfy6UW?G zu*fjZ7yZd>wWi_zVdD3Pjve6Sg}iQsyl4vq0D%Q^_ih?B{%SG(y6POAJ$FYfmY%}Z z=>PAvP-@+N6&Dh^*$AX-L3DSqc^{(%(GB4Oq~OkLyNd18%EX{6^idPD30++-byO*aQp zX1)Bp*~+lyCPG#gDw=oh-LAJONf-OT&L03tzCc&v8nETTO4-naFx4#6=K&<`38b8I- zICIz{<4k=lAax3gUx4L$fIC|h_QqLKg*BwP)BxF2nx*F8cdG&T=Z@`dW?}&>a9?s~ zUNu2N0wiM#q*|>x^v55M=vi*g(!oWA*f8CxmkDkthKm8_-l zq7I~2*WqdpENf}JXU(jTjCAkg$EG0q)2B~p{`86FX}o^jlr&zi9;Qs#?56Q*#Vqw3 z1h8piOeG8Fbh5UTbn1ZWi%YXR6M*HBQhL8~aWq>YTDM4$HhOYrnlQQ#k6;9$UF~pV zX;tQl(~r^0)#o_YQQE^4tQr)#xYvIF`0qlF0-&~?ottW#;96rBVwUo z5Ik?u`X?S~d)iivLF*;8XA$q7Q$58F-P3kK-c5rdKEEMEY29HFC|3Gu9pm8ccmX&q zL(Fo00Nm%zns5hRyLQk3lj_F07FeEAM;PK1nbv8jt|fp^b(iTbGYhC9!;Kp>3JWE9 zqIYPz>cV_)7-n}Xp|~)5Mg&s2)+maWcJ(>EU587?868UhK#T}CI|1M zt=m%g3kGB)K&&enE+FjLO|Se;U#(o1+IQ=0C>lI&#U*rvT|!zr5H83YV?Ah`st1by z&e=+rXMAe{h=m&qf%MDQFL8?Thc&9(w2+_x(Jub1Jv(UC`oN^Y8$NF;*;1Z%)@i6U z8kZKTmEuW9GOQFgt8^dte`b~LnSR!ozw^CJUOr5*bdruZ{M{;p!Ol>>Ap^N0J)>6n z$YMhm<-DHCn-{wAA_ju`jFvyGpu#1iIsWlU_1Uy%?-lmCJbd_s&Yi!*ud{4*lCG7B z(0zI%MJ<8J(7qiT@9mowGZeJYfF(#Ys{>XFeo`);=Gb$n8a%gbsMuUe}YON$KXp<5uxIzV$q^vL2yi*~uN z5;$cJaS!+%k%1T^;Sy-M*@k0`B7qy=JA;385|c+o#b zZTiW*oEfIfHMh?y(AJ#1+M5A#>dcW$tKCmx#>eS{bYqf>0xNsnSY!W}ZVz!{D4)E1 zP28KqSxV)_JweNSTeTos;V1*-C74k7qGKS?FBPjyqyB?7(TCM$F(A-B30*OewA1X{ zCG=Cw&Ks46~YNjLb-?f8D@Z})=02Vd)l&ozJSLAy_uqATtxdhb8;U| z3GPcFJ{{9#zanwTZ)`8IwipiJ+Z#H_*aA@j(nPgDOlDL!&YptOhXuj_amWHO6}0Tx z{wrG``oI&T1@eA`UQ}pr6(|~%-MDd|X3RRy@F=9F@FJDhO}r*7;sEaiP??S|QPzRj zXMtE#Fi4>tIAW--oYP&;StWpu+Kwwzn=0d9GjRziyZQfN_tCZR4;dUM&!sOa)OvKG zNYGYKC(Qy`zh%9H7RWxjG2vBJsoU9R#5Cwrd;kC-07*naR8v{=h2MNR>nhXqT3i>h zs7@WA>j7@;lClRNW){e@A#^gE7RZ2MgEQ=jg$@Jr7tiP7O$iYDvOo(Ji#8hhj}}9#R>`ZHnwx`mad)qoJ21=c6b}zyL+26V$tFR^6~$+C%?^`SjujTj6?Wa(?3Sws)B&plbi=o(-LSH5f#e=Qkcow9kr)6b0b>75 zbmPDE=gY_IX}k8#LRZFSU=!c0=|t|-VQi{sHc)C}2aapRhYg~6(|kBS^2;oLni@4+ zysnEHCg_%~AEB1Ii#blPJa}DYb8MuoQi1+a)lja_Fw4RUP_nR4K&WK`*xQpuad)X% zSdl}lW?_vOI8ZgE?C;F0(H_|k$iJQ(yq7j?x=05ODnTox@qS!=wtz}vYitg!520w9T+J*CUcK1R~EZ_{ZG4`eM-qc|= zhE4!hSpbOU!Wtwj$c$WAGKl`7M`XvT#oP(hr9=9Ww#HUc@Cd=eK+i$AwjidFwms6# zM(2^Xfu@nRinm7_CY1vgh^tVBFv&`LOyL1gS{;a~@T3z>3F$|-Z(Uad>GpMn)Y=N~ z-@Qg5V}SKK5HxReB$#7t=Z-3LTnSfB$y~{qL(G^q)cz?CQ!D>m#3~@j__~ z^&DY!hl<@jcBjo-wlGwBAGe+wD|Xsvj&7lw-mmj4acgbSQ_Zrl{>qd8&hDJeO7@gR znyQwCg?S^RyvEQcHWVONqJQ0-4jntl>$7i!t&$9IE%Y6`v#?S%HY0uV$ zwHfAm7S>@7fTzssXvo5{*IlN3*7=PQ3aqk_g{7rI_a4~K=3EfXf?Kt2RR(oF5+J!J zak?_+nmi$Wx(`!3p?5R&BeZa7MX24-HLs2(ICzwXucBuIyn50HABPDmC&A#l%0UZ6 zsYFlYf$nCN=xQba0I=eh2sM!YSno@ZIES^201X~!XM%uEs9)!F`OWCeTfJ5gQ`g>L zj^=|@rhmmz@BSO;`yW>bSSUUBM~&S^$4=a&MN3Xo^}6#6K`aRnTL3|f0qsK2(blSq z2tih%WHxQv$aMlIl8#$%jjp<}E-voJu9sA;IL~aRxKiJ6bDXl1zmm|1(|@^TxsAq( zc#KJdu!L;2S!vbI)XF{69dwf7Dg(5xBs5ekCOceixAZy?#r2jlr!~hWxKEVenc3^? zz1Lowfn;K8eL`z}m?RO(og#c)X!w9$^lkA#i#|+_AEO;wSdmorM<0P~1}&^fMlGzi zw0+||3oWb^T@y>!#u5O6e>ZPjrkPWRN-Zoe^VW)RsfPCN%^YOM;&Bo=!Ms|&GL}DQ z;EpUP+?J+0!^#ZoBbNW$t^9qC;CN z)EI-nBJvsl5!8Y(kbu_9<7KX;K`i#qzw6we9mFUB@O7S5%C~4Io_AroBk=684ww}XB$(OjN$JNONr0j{E zJ=SmN-bW6)=9!a|{Ty<0xDs8yAN4!U(vWnQT4D`o|KYvQgdSG*1d!C-U{Ty%t=c5= z7}`T`BQAS-m^!{%4!jOY6xoWyoqlUIf-BuW=62%7PO#yb2_WW;qMAm^!n{kSD_g{I-pTksOWZ_@!`peimL9rpg14(r* zBy`q+q^XyLV{Op92^$kzEFI)Q4xc!brjb#7K+ppOhBW@bLb@=&9eX5~L&{O|oEDU@ zD_k1I^YNz8kBtN{z-{30Ay(zc6__A2GjH)c9o+2d1;WP|%N`KA|J~F;#Nj?5cnr<2 zF>li4uqpyHo6^M@4e08WFBn{I40XK6x++)%*e0#$qY(@oZz{!Nib-*_Ve5LE;8CS^ zEe7XSE^VKgwzk!XLSoF2&20V3w!hc;0VsIb7;x&spfI0!tC@U%+u+CXmqlIGL+S>&2Ub_q}>y}vo23!`L~HN zU}|Rzuckt!DfF>fLdSuQgzSL?(&(}KC?Vk%%Lu^RI30DJRWb1xwI4af^N+nFj=o-CQMZYrg`5Y!TQdQURziT)@l z4>K<#4d5_>2l{}hyiDa<)omY-01(;AHqq{0=w>W0O;qvflmhANN|@Pw(Ur*LAc!bV zwyF_kuUDzUlU;iEuu0*S`K|Ke8b)#s$=TBO*#H!4BeMY`eICdc=E)XNztFh~npFsC zDR06*6_}VmR_}q=fyzpBA4IQpsXuQ7k8p>pK$Rk9wOWf=kr$o6(1RFkE9lY0#r@6+ z^d>D=Q?5@#ot5Yg$hr^Ud_x7BY%JB(X~o(VO#h8KYYJs$RC_vs{+U|W(AOs9XKr1ey>g`$V@R+uaX`WUVQfsA3r3nQA3-H0yS1| zSk0=(XfWmk5a-AMfTRWyTSM=3{%N0K?K@YA86V$cn(E4s6t1`D$8U{vY`h8?o?aX_jGYlYP;0{Ce_B4q)^T9v>@i`SPAyIkh)FqiSuuXq`wNp7 z;z)bj%=SJkCGOKu`%P;>fc(ee6^nKHt}PHov#Fyek32Jr9VdW1^#Br)DuIK9H$qSF zB3d*XO#^%Nz-K&r0nj2DC3J<0zw{TD=Fh`J#@rPoLV-g&D%H8#Vbjv>MtI3&PHRe!d56^!xpj| zs(F-k=1@&;af==xJNNF;^B)eMx6um$rFUlp-54U-ST{zz=uqN2Gr;4z(gq8w!u{G~ z;!daQyQA_S0QXVjJ*+a=Ogd+k$-R5$XQm&z6F{CB05Ro4V3<|%<`XUB59yO4-v(2u zGJc#CM|;Ey6{k?~k^xL314977p*YA{5u-DD7DhocrHYv+E59_^3_y%EA#2zRsirfX zY~>%o>;VI6*8JJ*y{IbYGlpcgB~Tb2E2$EMpOC}YwreZ>=H_DZJZyx}Q2PPzW9%eP zPW-0V`!EBuI9WxHnvUO%-4q`Oh%k7dP3{Za3K+dZkUZDh{HDYEU}|>sac%@=t$W_qB-wy#s51=>&;>iF{>wm*E8f_%m|aZ zS0~f$eaP@t0xe&&jLKK9YBhYNLX;J2RHc>cR`ET578qDg0C^?>#5yrB~-pR4DT588g&QcZU8SqAoAjCc6QM@?(KXiV*2YVhd zniykDI>1ADA6yiA`834gTb@lgZ)#}6l&7gF3 za(>whB`KN3Cm&U0X^;0IYd;Rs&rN^PLE2XMs%h(Ax!xu=vq0DhAelOho&+RHKuRi5 zIF!m&@aFd8V8ddxY(APAHW*8lfAZ2BMzM%uK}BGScpO?-&fx?Qb1%e5?Hw^@G&7&7 z*lGAPIylLzc_?6I0X(30Wmn7E%m5Khu@_(xos>ukyQk3=|6=SlFp#JaltH#c2NZ*R zi2@w1?-(l8h_8=&l`brF=Z=Wb2s@hz;9=_Cm`IcTyxH5cMu0GRa}{W!kC(>2ih8EL zpV?lGS7(!kNs^KnWy|@Hdxs%hB7stga7~R@4XE*=lw$Ij&eX3*KdN1O0_FR1Dg#Mo z<)obe;slU%fe5w`DjYj$JcpzZp0X#|oe}V04@L}lKJ7ZX(ZQqp1$e}ofrnk!)k56S z)U)G^-n&CScRH2qic%Klq&D&s;_q`?eCTpuNnLJ)2Y>-yg{9EqFbOs+VLuqXJwB!j z3))lM(X}#Ug&rT88gY8TBSs6osocljLwl%Bf?%1>4aSbsifTXKDz`lJ9 zc@9m~wpfV(>eguxYY3t+8z8~*P!@ea{3di_y+RasPxW@?F?vW3ZkYi|Di&BYgv6Wx z;slV#?umdw1biVJwtzS4z#F(Vqv!7Hw?f4=tml<-O?A)XLl#>-y+dSdsSzKm%I= zAlJr!$X-kG?B-0*JsW*c0td_3pGvJ0mcei%a#jOJ4AEN?Te~k(&#WT#9Ws#br_3Xr zae5%>00gwm&Mk)88V5g@S8g2z50;P;;8C;I1o9r&iB&yJT?RW^m5#C{BLxk@POgKw zrwEF{GXf$xvWgXuTGT5%`_gxxBLJ}k5tUd+!Jk|A&Kw3&ZBp&YkJtkoSRKRb0JV4K z{8`)&T^S9#z{6;a<2B&8kj(966LwD*M!zpzoY{zblUxq1z)i1`Rt})}{qvn+Nf{K@(&Eq>8qj(vyEj8OA4@5Qf zYtd{Jg$gf%MQlCIK_YOHZ6RBJ9j|FXf_>3jeNgW{l)vy)ixwK;j}t&r)5z3waF0GM zAPWdhJ=U|9QsxAZCkG-3d*JWLS<|>xDsmL?7SsyYSaz)`b)JsLe> zEO*gU^wMZ6mF#I21*(pN@HApiQsSzCbaiq*;T`--4=3qE>yikM;fhaDI=_Cb)(q>M zH1;-?g-tT`+<}q3nFQ(Ghy~^St?P#w+yD0D zduVJy>;w?|2Q>Ifmzzro=Wo%SJNN0%-TQR+?%#%SpP#=i#<3GusYo%fqr&V6amfyZ zjT?=ja32@)pXhE?{XEF4lhzvCjr={)FWr@23o`a#GVG`H3kUY@%XZn+$nUXuAQnwc zZ~;G`#_>61`{5E5{w9QFO}_j(ltDx_JyEZlyG`Lv0C|Q%L>Vm(nOr(Yr=m}CSj(le zJ9`fR6BsEa$Y>0mm}^;8qaS{%ta~v{TD73@lPA#b1H1G}c4M7~Js~UeJ|9UGe_#<^ z^)4&{LN$0Y>(8#ne`UgZhy;|&0VOH!$Ql76NqT}i)n{0Oi9SwS{Cy_F3G%c6Jv#0T z1MPregE=&%SMghEzJ=#;k2Y@I$a4A5qWAHn0R%Eh=zvr-~k0#fX-;ov0Si-6*TG>RIVe&Ua!N_uxgrC=eA4{ zpzyL}OmQLLO9sW;7tM$M+<&+}10Zr^)a#V6XGXgFaXc<>5DlXOrv~Xt0Jc0nczS3S zHfZE9S;3!~H8jte2a+pK2=^IEO1w>_geUUq+kUJHj_#-!@8=GomtXgx>a~~9Q3+>-yPrF8&n#aq9-%{^KV7 zA;#4!NpxiY2AUf&N&v}khQ3TD5J5;QbV>)RQq_w+9ch!ZNX}gc5Ah+K#TRZ*-8!B$ zY(Otg&Y-C~Vsud84fb-E1B$#;+_=d*sAaz6J5u*f1F2M5KlWHuZX_d20LPSivrts= zIRucjfCO9QD`3zN9yxaUD0>s=Gl62Y$l23aegyI*TX$`tL&p#DK4@ZuSUjXOFi*50 ztYZIlJ7WNkB$h%)g*OjX{P&2O4f7(umt~Lik*`p~?im~kGm{s2O1enm+AUqRj4IZw zmZn;O^7v{s{Fzx=kdlGt@~nRUp0o#&^Ro~tUu6MZNWM)!)m+34?$Aa%|Ce$UC^C&Z zr8a81k^!Vhu^F69w`!}tkTy2wXVa+3FJmao*F}QIL}S>h6MG#?=S`;T*DjL!_s>5> z55<2EAO6FS@$c`y|E7IASCF4)2liHsAR+<8m4*u&{&_(qlxu%_A%`P8WErvw<7V#P zm-45v0eQ=GSmJG_Ffk9tLb#|vhC zJ#IK4Gs4p92yG3?LD$E=L$N2enbdI;&O8xs#CUB~uk#ICH?SJAqU_rAKD1hzz_4Jw zbK|q>eLNjGkWkKnT)K3JYSvrAeTNDZk#+~8pa76}a|Kb$Hf!ke<+}_n@Gxw(5J%X* zV3AN7JFL4{h`VtMaozB1p2zAXfea1+ijeVL-PofiZkde{1>_nKF36Ppnh66|Z4IotH zn_w%Ar81{42;9VX1!&-gR;jUwX3dGBDZYorb3v4^kkbQsoM2+9#EW7zOGVyvgGMS4 zG0n$Hx@Zc;72l3)SDAyz%bY*C6!w!$ipM<}xpU)Zg3^qT;r2b-sdl6K93D(7bfttY zJ9O!odDr_nXJKJ+o%6F$I(_;&MNB_Q|9iua-p?J(&tbg(aWK99ZUC)Wmq5GsCNr4i zwPAl`?jw?_3WJWtxw4nio_6A##_aGBbno7u^x)w`0URmx;K2g{6b~3I&YZN7qqA88 z$FeUvypb_OyEBL&!Jb|^nKf_Ytq%gJ&{xx_YtJow)9?>2X6GK8_0EJ&0Lg|!>*a9< zZD}`*m-&kk|FPPZ_J*Z|y5(alAfk5&+#V!l)*o{|BvsDiN)me>$RQ!0^r$+ViZ!dV zO#ZgrThrfo%LyQ61EFz%L_60F!Xx;HR;-Gn-(1!UZ)7Re`gxgnypA?+O{A2252$|Q z6~aE*wm&j_HJ#jDhOm9~GkPCli)49h^kKGVDJdyBNMLI@)bq+ax%bzfG;``u@)aPY z7WeQ#kZSN8*_8@^9m1)JJO#rt13*+*DU1`}&|5La&a6?%5NDg>(S}hDZWbP6Yoe4H zlQ`}=ooq2g%*2B;G_wi|{M2Ahm!nCdHdO9UM5&V1b z;2{tEJ9+9lHEFr}5pA_ic?j4<>4BIcJMcc{M2uvwq0JVhq3FH_lqzG3lAk@q3}1;+1uE=?;`#6*WU~p z-Ft7PeFrYl&=I@o<=1_6FU6Te&&HuM&V3|O{GM4dX%3LE7P?a21gN@NZsYoxw`48I z&>UtUVjS0bzJK$4afg;sG*o)yPG@~M&|oZMHKtp{%t)#%Jc>to9*T7Z>3hiOBj=PU zeN&tOVpdFu+{UYK`_nr)gP4`oR4iICK=FNBJcs9z8?j}7@(9}pdy6s%Xj}z*x#{2m zI}01TY0V4<0u{QlcfbpQca(HKnmrI>x$}bJZt8SpRv=m$vV`K$E5%V(%o&z{3e3PmTA%$@AokbYWo!O?Lg|RN!F@ zMP2p!oX&0Y=PL2o)4S;W=E-zzLT&~X_C^dKV(En>t>{P57cR2gdscZMmLV&q+zQWO zn8!%2n|V~zEtU5`ebMa$XaE2p07*naRE>6FJuhxkKpJwrk17 zeIw^NKKvw9l6O81rl!LCC{unOzb7pZ1fl$IiwDw_v7ISMkM_v?2NvOn_scNZ{gnHU z^ghhIko(dDxppOqf+u$|FtR%8iS&B)#%HDnB9$M%5hvp_z7vagnXv)16IwWPJl*>J zn(ndz8I40R1@JE>>Hr1t!MmCz*x}V6l!Zi2?tGCB6}8BmM+miPzmDSLf2TMx!Xi&n z-G-Hq_oOF=hW%Qrsr156wp_1_lF&tu&a_cXp_9EEx_!l>bg6s%D0D4xa zAdgPIOtGhS2oU*%sk_&$CDygtkV}!ZSmIrZGDc-7aKt6Xa$U@-^{eUE_P^OBr*BM} zH)`3O1t^UgV%g<;_@tBQ92ytEFnIVbwsT0N12|;aKsd9sV25tr{EMpBS;C2RYdH|G zQFDt0bg}OPSo11SFCLV+Wp9r*bWAMN0U#;&?FSGEBKOS!#M9LPATp6&x2`7xNTzro zii_O5sRz3^Qh&u=_Z$$9n-w;U?%w%>{vk;vGpCW62HYnVgFAcXF!_yl(LE2{1JN#4 ziPHXj5$$CIC@{cH0>8R<|Lt_-=oPwm?*Sb+bcriJ$4@*!|9!)k-v2m6FW_GXL<0YoKoJ`-bD z|6Y1BM`u$(b7i6%B`2QM*Z}uZ(Z?*A07g35whePR!H$cf)5$b1q-hfm4x8DFg2p5k z66x;<*AX`mNFO=l6f>{x-+w?GHl3%o9oEwqUrpnji4#DwBY;Fny{V{ublu|(mQObt zf0@IOc@Jn|#c0KV#`_V&!iF(op|hW^k9)_e7a{>D2VEQY9>v5Q=J&_Mr(XiyvUUao zQuP21^osWj3E+lM2tz4gcvKTF2_BWHwg8Wf+ct8`Un6*Ar|;mCE+hm4tHCcTxJXdd zeqce1=k_1C#E;+lFp#R%T1?k({G~~mgjvmjz%~^qJe5Wb?#YZ-lLyj~2}#QrcymMt z9)&$gbTzPm2Y{SDu}9e6)*L}H^FV~{tz2cYL$)_ZTE-Awz;`7B$Y*><4qusMf;)2P zYSrQZJ(=^U6EV`s9zJ|XH?Cji5`0F&iRN**zTNw4aX9<=$VM zF~)6(s8a3YQFj~~(*9^~VWL^?r1MgcxeS2s&pn}&%<@cJ(#O2EM*70vj~UeZ3h{~G zJ;b>@d}gZWxCteDNwFedw7QVTxts7zSOc-Ta!$=Q3)@#p&h8}(gzT4O1~r4%H0@Ey zN>;E;=y9|zgqkyagMELR#FYO^Un%KAGb;iOXtodta(~~HWUFl?_7ucb{ag^H8diyX z{BVu~7p1jz{o|wOLjL?OPyL^tEP?w6%f910+qAf<^3*q)0h_sZsB8#GX77dch zJV?0iw}0Ga>@vTIJQn7&Zn~EgC_s=;nmoa^9CVWL zLYz7~a|!=;G)`T`i)LS~sl}Q5SuY#N6Bz*mw46#fx&zjD46=W0)@= zJ~1%penRhkvfp9VlBvpy-vzX~2#hLOQ4=_RIa)R+N0UdFG&6L1qSL_4dlAS!*sN2U zteFjDa-n6p*~pOYR+33LD-7LtNo7P4LE&;nX^o~SVOnswHXPdtiI2IOYfzK1?w<=| z42_I-j--&=4isYAa{jl2n%02kK9@r?ngCvyD6M$XcUAxgor1 z?A3~Hd)1ioT!(edi@sjFax$`qtO~_kDJ92)w3VF?XqOrTxk_zR4G@s0EuV@Y(-y{ zXq9##Y#=nOujh1;8NAJ6xCRamo`N6T{f`&LoS6iTs`^nV_p}pyN5`$_g3L<2c-;<2 z{0hU^h`Gm=CqMlxm1lqS)l=@X6)!%tg`p=2-&f)}6QQv10*w4IXQjgRss8ZO{ZF1i z=bZ}&%}~-YsTES%!#gNKC{v6M#|ByDJZ{liT|CUzd3jo#FnkM~qmul2F|lDzA&k%@ z>cC7N(AXwbOn^ppcB%HVUqmt=oi020X{TnA9wB#Obzd$D`GBJqyXxU^ir9u~Hg)Y) zC9NkqrvxIf=c@enSg&<0el`$#z^4U-koS83o^1)sQ=aqipcSBpc=#P z5heZKn8P7H;RqPNc8&Dq3M<|Z!=3C`V(ykJNSb?IBkm+xzL7A~8#Is*zx|3MR*h-3 zhnVeLa2h`u-(<3;cZHe^US;ye3&6Oa{|(9hSjw&%Z9qTaV2!8*s}#}u5IO(!g-Q14rl8Wg|%#Bl)FzbNUfovlP(5=Q)?~*(`?0<+$+~cGYBg@Nz6e z5M%*IyIL%T|LfgPKktsv+JG?FZrufuRH;}9TT|pUFL)Q308Jf`KOJY!ywX}=jk1C= z@A)ZE;m0qx(NlowjVN_sAleAL|3{A*EE64;DB7h_-SBQKS)_nh!nwkhzoTH5OlJbZ zmp2s?vd+kok+TB~yc=@I0D>VNv|KwJ++CL}X{!|29hgKbQqgv_eR1}-xC4HSBQ2d8 zVA7i~v(!>KWXwT#s4p1NJ0peh7x5G9)37=g?UiUPnorb4!jzbr!L8cyiQ7-zJR%ZH zRrh&l|c()+b`P5IYR(d>METTIF9Dd1`QGVrHZwg>jPXPqZa zpm{dj7L6{lo}lLNZ(8W0P8*lC%K@|u~X{G3UX-w8Nf@rOs=rnZB?U$3Kb%GKE@EL$Bv zq;}Fs@cOWh6pF3PNErcR9X0-QK*INAoln0u-bLazU$J~B$1?O0pOn0rO5T<0$U96Z ztOgPy-bBzs{t{g~p3F7lq}5Qw2GpGVe2J~Phz7tn6?Grd8kage>czO#YzG&Q)y1QLmfvqne@9v_sa13#+y;Ru6X}(LhRt1!fL`Ea0j$R(jS*}>f*o13I&fKqi_GN zlh7_>%X}XDj1ja`fXN=YNUD)mB2<}JnThc&nLW#_0(hO;Eeee!PeOvBGH?^B7s4ph@e%KiJ`)goaX9`&sNF0am!t= z+w#eqzX!YIi&kHUZ?z)2W$8+s6TyyB6|Rs#x)eadgbo6k^mZQ}qPuMC-pyA zP7z(%6hX(Wx-)ptj<=p(VpL&r%v2~nxoH*4FLjYiyYgU%S|M8elZ_+g71!p&?U_Y< zlVeKURc7kY9m~(@HInhAHy0~i+q16h8bHd;5F(7Dm1!j6sm7s^e2U6kGXAId)Oj!i z&N$iF5FPw+U(s(8D@m7(%imM8GUMcj>=LHW6TI0%EYWU_^#zbapA);#4kIM8NX3(a zd^V2agWdMC8;6j@SEBJXJ7bf!npNP=Jz1vt#5xe$}Ke+^ycm8Ug>YXX{NeNuxdY=jHZ~~z_IZto?%ql7+sdMM18g48@r^IJ3k@T10Q~0+ zX|uUuIMGZbQutTYjd5L0$kC*<2k3DWu*U{RwrpP?EBwBpBl{%iDk)g?rIUu~e59zF zI6B!@s$59%3ggv)_{H(X#T*UkTq9mi{il)zL%JETj;7^YA)dHEE!Cg}J$cuHLCdri zuPbh;_IzAmCd2)FeVhzFP$HT^TIdn7Y*3(`@bBq%ZZT3qchCZzsE1SaCeRSfdyL!+ zvsU^DhbNxIBrrF0!})v-+Y^mBi5ACl=_{MiXhv&pr!>tVl-Bcjj870P%aDHj-@Fu_ zroo8$BEM5wzGFs6eart}SNqNXmVUTENIGX(!R(}Ndc~c46;L5Moq*&DuPh6tc+q8Y z=TK|xeXK$5ef}3viyUM=9D%cGuV5Nb-k|6x}r6 z516}?j;(WI*eK%5tVwJ4rX>}|R%BRWEKAxGs)(zKS;(!_mGVS7;G2ZG7GH1yotYEv zss;c_5=Wnk!>?zQdS1=u8!PXZq#` zIfs)x3~l2?7Ve}Jr|38*Lm`dXDC`XMDdAi!=X8vk_;=rdHRyW2%r4KQeoH3y5d6nW zidv@riIxCawn9R@(Cd`zEDc1??!6&g{#a{JAPVV_PYzf%W{w^QnZK%}n_Aew21nV- z%*B1J`{F2RruT)_Ydlqb)a+hxMF&{ub&r;}zB`C}at$t~W8=$56+l^@@)NLr2*hMsuRz83WegM-B+3+!#Ae7rQ0Dy z(kZK=`Bj_(CHr!JWCciy_fCo_ex#Qpr2o_}lh*1mw)?QOQm%8d-_bF|Dgxu7*HIioR4pj0x<0qHuE4 z!N;8vEkUEegLdH)TxQu=p$>yU8TN>w)Sfi@1&JLpYB^@Z?n3bA_lp@YQ!04yfJxBx0+a_UfMDcv!i}`jW4YNE-YiAMB*Z1XK*D4 zg(s?J-RJw^#(ua_yPh{EUHpB`A^vhOMbnLb2c0E+%Nfx!6T{1Y2nP#8elQ?mMX_@W zPl*BmWAn0LdAKrtV!D*bDAz1!5SD5WKp4R-D0Zdm;{Q}jID&hkdP1H5C{%UVh(Z}l z-)ye%ZI2A7%~~h}YuwNKF*w}~+;EnwZ^Jx(o1;n7?=h@+(p(hdot*z9|VZMa+_O0WihARF0&BAfH2Wj0FJ^9W@!%_i{%XxHM zaMa%Sr6Ar27hb6S)oH(dF6wb6nN9Jm>8=S-AVG}YB>K(#zvLVg-7F{C8Gr<+PD5Js zaEx|vutMFQ;&+n8Zp@F|ck8z-oc%r-_RXRAB z_?U!vr4S!s zm4@~%I5l*w3qp`Db*h?Ges&5bxuZ^CMqw?Rcws-ihoD~B`s$(BqSfQs5N^+S9P1g2 zCh&i58+FVuj>xiWec{5_rb9`*JXkTrNlhKCuj7nt4i5aC3)BY z2Mi@&t^)M`fAjwFgWxus@%8DNLj`ko1yV;EN$StTDeVv|LtTnA5q;~)nG5xX#xq5bUyD8b^$%-JFRPFnbP(LPrk$3Hzm3{M2?Dy`nye|C|^J=)H8K~dc3;prX4&r zWOJi|Jud)56>#y;mb4~?o>^^pdj^W1sO%{deqvLc(Vv_Q_z7s^*2D4^O2J8+8;j`n z^yO$WAr_{^{IgaXLYVRbsNl>HbYo6NT!eh` zHSvTzpAu&VFLy*fzMo$G#>ck4{gqW6&8!!>?y#T1K^phZ**sJ(JmoaFR$G*v6UskT!44@p<+p}m-w8fG%io=M z2}H0%R$OKiPeuwN`_pk}CB-)3N}R$Z3yOowqfh&_TNJ{VpJ%}}P>dv9C@ zL;bWN1 z`=95F5cmxr!hBmX^-L_{pM1lY?iLPhBjVN(8^^z#$=E977u*P+h`19@M9XAvJXEo3u`%z|hr9Wogfo55f3VRex-SRQ-LyM37O(N`V+uA5>ys zTTvGp*TUAyW+#mp^~t_r!3HauI!oDu@sQ7(@3=g zBd@~x$qgD6hy9H&1_mu3J`yAo+{>VzYYM;|bpXA1i&p+!zhos9@=tR_>5BE$)!-Mz z-cT9q+}j!&hvyqFTfz9BM+?HwN=r{oi&yxj!JZkY*Y-r($CtrFOI^VY06U!TmFfR6 ziEA$jVWbIOE;(VaEWCZrbS8sZ+mj!^zMB^LK)9qFruWnaVggVH3}V0vIG_bhqm@?< z)()q4BAX~>?K5sh4uIq-6r~a^*y=NPpbm{Vklpk*PGf^TEbo|mYhij3`LF4AccQIDszN+sQ3Hv?h~f5o{a%I7S97YldXdaVB$7-y{+m<5CG-!vU*GCb zT0szI@b`Eyca-7L>9OlqK%^}=?haCNvsw3X(|MJBbnnOyN}m_GfE}ZTohvk6Q)FTW z_OZD=Ao?@!LE!_YK>HT!bQ)j~o4N(6AOw#$2F~!gTQjVirwDO-QQ*@54DJe787ZW|Q={b$_fA3MBvsmfO;m zJ*fH3`(d7+j2{l9xrIt_;3H*%?`M-vbPFDzu-^|Mw=V<2^9?`jiGlI_vqI$?&)VlUNP zCl!CWpDXLu(}pAArPT!qgVp!k{`)JJwbUx6YP>GH5{F;|<~i_(i{(sUo7;3reu$o| zK<^i&=6p-z`>Iz9tPf(5r;sh&a2SbxUi#GjjHX_*dbD-Ch*+eFHv;82+j_TXszr9yFI&V`Ma=K)S zz<}PZc5z6}XiHHO567<~LgZ!H>7jm4)s)VTxYXnd$>eZIdL}EAlfnnELXtEBOc_nJrYs_Bn zbb^|-3$a9dxS%7I6iy&*9v&!A4s~EDFC3`;cLJ*DjrDkLu2(q+{_4J;wX~5Lu-cHw zyf~Sn$V_&PV9#Zx+*%&gK-mPpd znh@Rz4NMjC!l>ltvb5wNTA4U61UR0>04LO6_b-l!W8W7iMwArrMX1qER zk^%Y~dsfAI%z?EYr~IkDMtni)z%dL>XVq$E7gNH4O10&bMe!R;-cSvd33xDzU>X-# zf;Y>o*#9~1vM+a6uh$418qZH?8(9&8NaIW$36O#k9Vy0R?F6Wwuc3g^^gdIJ$lOUT z(>ha0U(Pb00XH{09|KE`s6YOG=n0b(xd%fMUGuStE=yu1T=j8=^J9uUuZIWl0;(P> zMz5n9UYv-*^N)%O-7LL47buqz%ZsmzR#l@3xdP)O8`oK^9;PGU){SM}wre6H@Q7_f z_WGJr8J|aPOUJbN#D*m}*Hg2%EkV~@(9tyd8Chm-og5BnS|Zt9DX&Kww~85O8&d%` zT9Ds2e-vb9s!+@zkwEQmEK<{lE^N12r zkAapg4LJkaShQZS{ro=`;O-)vC_yQAc&pLjGr0;q|5M<5mro8Q@Rb8Y z=hs)D_dRZHp`d^5A}+hfB1!q;kc_9I8AW{Lh&@E)DVictJ5wjM@xw6}r z9#8T^NJJ5&o#CDc<_lm8D&8BmGP{T=@3_uyJ{)NzAYL>7!=rnMoohR@m=XD>G-}xU#UMEJuw+mkT3pFdHtDZxbf|81+A440j z_qQr=`E@~=r$^(1uKS^J9mD#Wudb6{^5qL&eNh7N4u!4x+E%pwgmon3^G*hs5r9Xo zO}6IQeoV#_>-~$H7No6>`XzmmZEUEIzcE^}`zu#I-Gvzc(-Pp(32Jam&=x7t;7Jk;L7J&31K-e<}^l-|rfr zBT+aFFYqa|>LI_H$*pb1a5i0)nPuNvzMQQQ{4|HsM_f(EGKEAullWu-ZX~I(YW3LC zx-rV|qO{35n@7-2l^|WnMJz=V_btId==P<;neJzQkRPr7mwiFj%@!*pHJOVZn9n^g3Ib|nfN=L#gHgE5no~Vc!h$r14r|qjurQEdi6?9Sx4s>} z1xHb%P4w5!Uv3zqzr>CFSaez=*II0U*DXQ}CgISC`rwF1VX2O}EU*e}|MI(4=ron% z;9ynM)jyK14T8sAVqDxWkK}BZ>kiFEtXT9L1J_z#Cxg~F)hY^ibdhJ#%ByyGeU z&t+`n9!-aebc~eh1wNNSe-}!uJo52xJsK3)F!aKh<)wV>+nH!=m0y2{KzR*W?U-xi4L6fSL2G=a*1#+J`rq4yOv2 zY61@S21v-vWagtP%(_^5GR#K3BB$-fT-vNxg9lJuSd3cKJGI=N+B@AY#q~VwFzXN< z;kH<={RZ^gN06w=ag%>Lm`2yrAe4PvqKd3FoI?M}#+G8~*_ALGxh(0u6v25s!2u#b zj0u7eZqN(o#Cb4~zoo$M*0LF{&&_$ItUl%#c zTlQOS01>VDwYq=pwWP4(HMJv_Y-Ode9h(3_&mnJU7dnG%LU{=&)Hs`H6OR^(k!EY! z?G&=A_h+4PYt0#m46IE6M%!f?71Na0L@_ zRzo1KG*(Iu@MNLPPODlaNG^j}YTi<^ zp2BXqr)G7-Vj{I1vN;=^HfT}U9~d6@5?)T*4gFs4O@Q31qcI<~>R$6bGeISIu-fEcvEm{9+%yj;<(NpI@YixV)*Snd-h+2&0jJgNJXA zXJ&!w2Kss%B7P3neA=$Y4qcnQ0Y-3YxyTo&egAT=kgiFaaT|XtfV_wVF=m{Tj9{^C zx87rRiH7F2w*Hv^ts?Vlo$dAsn6LedUtu@wHSk$caS)iKZg|HQp@p$uCKVX_Yz0Nx z*~+}cSxloahS4PcE>c!%XUgr;h~qHI9sFB5E8{>+yRl$&^TbpDc<2xPRkAd7mx>QXKH%~ zg<8VxtzM`t;(qP zjx@6nC#*qN8zpwt(}asjn==8Gc0t#pW_@sS;Ct@$QE9scoQyl|wHUQL z*(_n`)iR<@Ws>KzT`bJ=X}uK(<}>y^UR_IgSFkm8C()pSApKD}i-~EoEUZ)v5PHlt zxFEoV8ILmB<3d)#|7i?2K6)itm0hl*&0Z)tu5%0KAV?O3xKJ#r$1^$Gjf_A;WM6}& zGbB=RAMWkJQHr9lDKloSh1V`s;I`OBzsHAxDtdB4CM$!CUW)AlLII(9fy#r^ft^}S z@WniWU&$g3RUHf9i=z?rT6G3T=QsU;TPk~~!DyO)yyb_jL`sE$ZS$QS`9e&L@{ST{ zh-6>ce!y6Je{U~W`n%ReG?aiSVi>9iAYw&(x*m))b|Yu!%7kzX{nP#JeOD&Pz{YQX z<%E?yiCJqsQAfz@lr#6~G;h8%JIw3mBZuc3;p-8M;tp&Z4-3xzPI>I7We9{VSncr> zm?F-N<)0cscDX$j3?R%t6N&;Gc34VP?p4yE5CEVJhj<%^+H#3a7(;(x$o0z^k+zXo z4BuZJc4X9Qi)&Q94FSpzrM2OA$OyV-&7`k82*A=6bo|`WaUc|a%}2pHPtt8HjD4D^ zXJ{tf*2I39JnYTKrgj>=u%a*z4%7YbUP>1G_d^>7o$iM|kyoa-hksVIt2&^N`qe^0 z+cFvZY(M+Rdy>`d`P~ouZFX1@6Ca3$z-LY~8OqS2QB?bxeho^@%qFfIq(V%{mCJC{ zFC}a$R|~s2xVKf6Bk?fUQS8eZe5{dx$M2}yX^KE#mGMX1;^AP$-{R0uIjBmXE!u-8 zFy^iP9G=t3Q1iDv8=rul$1H0y01pZ#W{xFVX;0Aho?pKG!fd)HMqPd-x4gHu+_Gj# zrNojU3pP5~k}w}#Sq*j{I|Lt^JH4@g1lnOmIaLb8>2`X^#ry;C-T0r^BN}9!revEA zmvYIAuL+NM$DWj)nn($#^nY_oJ#A7*b(#L1d_F%cCvhnHPw?*_7m(T7P5&3+Mu_e| zYKWKZ=eTJ;P^{Nb7C8hqeKei~p~9u&Ht_JhoGA)Yi@(@tP=8i5an-z~G z-XZg3(x&r9QZD@n^yl;+&|Yh`MXtkf%H`eMo&lkipb&Cr;zf6;(?S=q12DQWp@6Tm zyweS5i`!mlK03|jP(IjWVW4H`y?8KN{kI47JF^7il`D#7&s9pHsCa57(-&T{Ng>0@ zZhJ7^;0D{7&DF;4O5&i(G9D1|d#|Vw5p66)aVDS6vIG`pIUJcFq@c*XrLIFHQB`vp z%@>fr#hcnOBN8-E1gwD`j&LLpt89z{$oU?}Oq%TuR5!Iqd1|3<5HpE4p>D`L^DfIW z&8Gh82(rWz=R=7q|B0jKiUrjo3Q`8LO_Q=j0d1G+C=;AYhBy595<-0Agxd%>tfnzs z(9M-mcfK$(@_tZ?!i?Y238y@_%Xr0>rrBy8jmDjSYp@1*?s}Ug)mwcq^Jm~pFJp^h zk`U3xSBU^eV^`<-e8XUoZrA~Gu-ORsl(DeEKtbZr&pXeQsgY99T?+f7PlliJ4=&jQ ze(cT_(0J(*$x-w|tvQU=<{U#X=CC|Ob4Lly(ui*w$3+PUMYalzvcGJ(bV6_NQ#P-pH6U!$)u1KHQ-0qpUXi}3*9K$G}Yfot3se# zh^t25z)dn^^&i{vQw4wzmk#g7{Z-KS+xJ99#_0vdYB9eT)|a(YxdSGgalzAP=gqSQcN$#gM7cqBT$>KmJ3BP+_?MBxSq6IF0 zzZ?by3;-c^`(97WW;pvGmox0^fZRWbSly2EYH$#*$|?}Cb)tf{egGZY3$c3hnk)?? zEu3b_&WP$%rXlA_@RH@Q-}i*;cgMBiUPrl`K7nWcV=v`nTdv-R{-ht_WQf8ASiN#bsu zXsyHv`sCTS6i>bxhZKNaj7-bFM!_wk3#pc(`7u0UD$yjv8vYIUhk1MaAYNv1IXnOA z%3e~4KMM6&vplGk?gpv}ARXV0d-&{%(S_UWrBNRyOLC>XmQfwXT>lmG}kqhYmBHzgI(M)@~`n}~TX;Q1L zjd+r_PqdXx5B(k}hGac4^wg13id+8Ot0h7BWzNhX4~456PCXdG7&p)eY}Gfqq>I)a zI7gU=s;XCzra1b{fg(!O{TI?deUfyAdeO_3nnd+Y)|9Y~bECPoXus{yhf>FmXB;ZN zyD`$wwzx+#;5~gOkgvO*xgl91fIvLN7=yy;}1S@3>Vu zNKX#fP@?$QHp^9!F@!0$xb(-FjIEyCd$5tGvKWc{g@p%^mWvD=ANl#J@Ns!@qqQ1_e{aLWo^?WGUmjpEPHTo3H1ZXw;P1^@pt3Y(Q8&R;z;3FBAh+eDXoK3HdUqlm2U}gxy8RZ!p-lN;8 zr*n_?VZ6a=lW6Z}F3RC86H{aeHVI5M4y{fk1BfA(5lMfafJT?}rVy>Xl!N;&g7I_0 zHh&0;pknR`7uk=u7t`+r0HL)Kr*b!CI$Ie_b<`q`9={yEiGm0ni!Z_j^d&3E zdT&}q-YykI6rb61bugcZCm9y$&TP_Lw1xv|r@npiSBWGK(L#Trj_y2U&isRTHB*nl zyfT=eXhX~=Ho%u3R#f`+fqadjXS9F+6s$OJB|Ue1l#HV<;Kc3h0UeFPG_ZxeCy`Vm0Kp|Lgbc=S2CLKtEx zQl?(;D!HfvvTX`a@tGm@Iv8CfXX>1%etR?!WDg1cJNVBsYVu?(dr)|g_SpP;o^A`l zcmpTL=RhfC*Du5=#wPD=d}*;&ATIai1l+DL4-6aGqfmiK-$2RNa78e$`I5&r+R_ja z&ko?D+k90A&E{|WHGUeih;r`lg&zYzw)aAH#nG0nx|#4lr^9m9BxwvEB?|1CwL^0PX0Isq^bCa| z4@z3^BFfx{m|*F{6ZqGvcvkwcpK3eviqj0jMvN`jF-bd(Auc8zc9|o~tx~%zr4yzp zl$>6wL#cDW1~* z0ntY&y!z?xZ+z+%$q$gN*p$K~j-F1u3>*zI=d1Mm+6SAaK?Tc0RV7NZ%{w{|O;3Lb zAICj2oyI7a!(G!}h!d7e`!IAV^Am=+w|5#pur$w_Cw>w^&0+)CU=Hmo90wtI`$ot& zWfL*OOz39(AQL;HEKdhykL^f9^x1W%Cn@PWn#q(#(lYqaw1I zpsp}e3CG^SW)~0k?jZ4jAB9*39XC0x_Qq}+I64{&n#P7|pPhs7O^0clgFObi33f@~ z0l($kWkiP>c_OiWbE&EXv3*C2Gy}b9aEQfc=FKK))8)l#5MacwM*dAjuTzc(S)W*k)R+Ti;OTX1tS0f$2f^Iw5=%gFh}@IhyCng=64VPDdncN_@e0Kvv0~IHxk3+B8p)ghC?F#!q%kN%+8An(}r| zJ7W9kOwOd&YD{0!&;tYnQ!)}AqvsobRQd@d|=_VPW!?)c$WV}TVJzoTnH8NC9w>m5b5gx#bL79 zg9b9#l++mgg8k99`$s#PufD)g%RhPJ(xd~vmJ-#IGvub@(NdPvC0R4O2Qd}Hb$^b- z0^VX`T0!YnlRvbfgLkih6>umgG9UgsuqQl)%Jgra%q%)vSTigvx=T!0^@OHLNfRn3 zTdS9N@=IDY`;LXmo2Lx!_1o?^?e9M+pYjuSE9-%iH2oQCrrW^6e2sN2m!x<~V~Eh4 zDlEn7;d(7EX)Zz90K#rt)?bYxf!fN240=e!C_evef@GV9d*1UEluE&41iM*Q{~Cr7 zeFr$%rD$?SXi7z?7zm&$u}HBl4yqUnVPj0&gVbZVZ3$^Xw$2c!iBt$81mV`7dQPH| z+Jg-=hDE1>l87A<5Tk&?;S|rwMNVP=%E{a01ZTbhJq~-YP>tH)WF1Yl1GLIb0 z7d{gEXw2v8TJm~wTD(yQ{MLGN-|&yjwSCY9qesFBt@W7hlD)}PHwvLrgK=u`s6nh>lkmsn(QD1Vbv3T1t}r*ZX|VC9 zArgDs2;KGNu8x&ebx}uD45zv{UBmXa6{EjuwphG2q@6FmlPUQFn!{beZ7BC#ros2B|BVJQJ9`x2Y4yqW9k^o395LyUOZlZ`|e@Z#D}Vo)$6k>oJn z1k{z0LThFU`c)AZpF&{C$)siJei(MSi#c%NE(*{EsPqQC4f%fJOD!{3T<~EwQa<#X z0YZx?`Np4-;HOQ1ByIhELs^ms{KJ$VG!y=(eJ#95i(s#Py~;}P)F3mQZ>mWcLOQj` zI&({TZ5k}Gcs*hpIIT2Yk4Ag$ip}e+_Cw$HR)3prc)9-&`RF55E0QAUFS3ovfsV^ea7lBl%D0E7CZo z?_vDk^~|B7TI^nt3x%~&=FQPZqQ4Zw?@v<_@$k30`E7siDc3v*Z$4zp_u7J0>Z)wv zd!$dE8f`!Qvf$#!@zx0P*poKjxV9w*(jSAEEKkm}Pyo>Vu&x#oj_q9W(I&1aIR$jB1@;U2x~`Dc40_*RY=br+z*8 z>_N{$n}vtJdaI&(^u+@zMM-MYn?e=pKd~&oxcsh%HVjE35O$`;XEOZQ`$m7S`7h4> z#}V+xzQM5_GnIX0BIRW92Tk|;i|vNb?#Q|AKK`}@bM5(YsV8app5%g44T8eM<Mz1pLc7 zXXB-l%=$b|FX%P~X5D54a)HBs59oYgZOMU`2$JM?eO{KCHOv8VN`oj?@xTW8WhH)5 zVH*G&vqD+Ek!7Gv=!KB6k|(xE>TOZJK_T7B7b=<#_OEoFjl|%BknU1eCTgVtE8hH%iE? zd3D+QNapt4WoP=AHcf$la#TW%TJaAI%z?I@+NRcM24RR5Wk&nA8cBG@7mtBLSvGzJOLd=1E2sf-#nRQNk;de`VjyIl< ze?6WEHhphVg@pw+3Ml-1)S}q^Rb8%PVuNJkMa(ZZf2i5`XmB2}PX`Cdn<1Ti@hF92 zEdp!Px5Nh}gp{tr{7dIIwvUoRa3Rrik==P@7@-*(fqFs`Av1HC~xj*l(Z@We08b0Thd z!#aZ>cqurHgTZd6i#sl2o@iCBuCqWVsE*>GkXH`t0jlS_dF2&^T`zs?z3%>JDilPC zxHSF;F%Fi!K9~0Jt8c>3)I1>w@4{Y(nLXdMmOFi>9qhVX0&dtIK?Rg3y9<#RCkv~2 zr~|B@ybT6tS6OMS`Zy{vfhgx5_V$>kbLro zWVMD)--kSIS(%~FBw%dPO%a#IB#693g2~yw5k#!u5LB_M#iajvT5%HEfqI7XRI~O( zXnC&TD&RR}V(#K>Cav$ne+Xrrh3oK1aM;M#iDKQ|WX2wiTi#hUqqy6NAQzquSG^1% zF)e?pF$8kpP`IxY3A!`H$zO@KS6Vk16D`%XWno1k(r&2XIx&pX&TFa(70d-8ci1jw z_kjlNIp%aiGN_vR#nY!Fj-Sy5r%s%`_fUr(x)Xwrt1c~7Z#8Wz$*hwqhq!Ta<$U49tQ01&V8C!wI{t4-2f5@bBaz8wLJ$a90B0pM3a zu*SJ$9iknlN#FU;Ahz)5dLwOf+G$`3LIUb0!W25V+F7bS-#H>Rp$MSt1B5q4UDc~Mu3PJ;>5rb=Gw`LtstiPvh(=GVrfLN0zyEuFYM+rI9gXqD zMWM>{MnLW7H8Ub`BB@)$M~)0O!ZB8^sN^kxn73YaEB&H%E8l)zs?dpx^9%}pCY;1( zwnk2C=culOs|OYi{MKpkCJgvI-#hGqjEo*SyPf3w__vKe@XL9tpvT#pmd%8k==#pz(``YUr z_JvA+xjDRO>NG6@+tz;_NYkpi0&)Av?L!p!LpO-u){Son=0b!JBB#qwWLf=MQaNb|t5;Arqyi!@u&KCFY{OatvePO?MOEZKrzZ`k z>42aEGq>FmeS!;T)4nLZL&<0Nb%%P~tO#M41WsttPKyw6`au66)#7bE2dWw-rC$Qj}-UN7ty3dQ{RYd!^;V9X2>SA79Q&Z?e(d`LxZRU!`L9RbJVms#{s;;z%;*k%iixdx}@fZdecq+GeIds8Y6>wS%0EH5=MXPZrqoc(J9{X$R=awS2s<{+^q(a3hoLBig z9bE}?WW?)GnS6XWsJl?pMYEIoKaZmp%|_90tw&Ik#$#A&81*3ezYJqg$(=V+r=ew} z0^Krs4%XGo*-`ZOgNNib9}j?h_+d@~ z8r6mIT*SbEM4-xjps@}>#2PaPKR&eo{8{`!0Sss=1+QiJ$YC@V)Lrqz!5BSeB!{N( z!$;nsM2X_kctoG1h#6rN8XnA{5DYxVaR5||pk+*2!q^QRK7{)+z)-^|T)laj!x;bp zV?B!k5cWW{5EjS+MoO;&BzPdpRxZ^!{2B2;U=)o7mX8|h^RQ2qpDJ@W21S)=3G|&y zif5Hr81Z_cv2SDI8cvS6Nexv{W_rFZcFn+%3rLOWd06XL-+=Z8* zI{yJ|I(ByF&&I+-5hRS^Ox(*IySMYbMRMFfz?aVj&u`qaf%94b7PO^>$6>rL3c$K{ z?@XWN`IH(qsxQ7z$L(%GV7!L-Ja}8kfs_`%8~m0qKvckQAW(R~AAIomLs;-IikF#9 zfBbQediLGMQ4rXdqQz#=_hshrd$71gbGxI*uL=MONyFxuybst`3 zC%rRlh<7(yvA~yhZeBo#_phhDJC@V>m0>hJcpw7``lIV@G>l5VE$F|B3Y=w9 zCT8IAg=7N&9T7|G-E{y{$G`wUV-wZfB+}o7-7bG|;Am>%+I|?7F6+xI0Mv(M1`_}- zBI1kn8ZBq9qjB?<^y)iO4@=g8Or_Vv-)JaxFXaKXbKStT4Sc_5ez9tdldS*x+ot|3P*I{cv7s)g3+Rdw}l^ie*t$hyp`XtAp~?y3McbfjsUIR$k6~1XF`1 zE9lbYyZkqZJ6NbTY`T(;9=pQo-%!h_R%Uw_`EQ^$5vWMDsTu@Ptlk%_VwQ@F6z9oi1l8&x^th2(JD zRg+;NoLsf)6KV9|9vn-PI#{L{o8`bo2%aqUumZ$mG>C_g;zyd0Vn#p&Nhzr728AA@ z-FuSh_4fi;`$_=>wgrkz-f_aHz&**edWut_U<*fKR2$mGtYZ7h`HQ9Prxk8qa}TMmh^I@%cE9Uw>^uB}<8uzsN51oKX?{=%aO_3lA&(MNcGfQM`+o}#r8PoclX_Tj^a{Q4ia zuG7L<<2lR~G|AXXT;@jn1(1AKB7jp3oK(*WHC|cyC>uVxwI9mBp*MH8ppKbN);%?) zOgsniMelK)#SdWuhqXS>0G$i~0k+kmB{4L6ZWN0qBG+LIQ2{KV#ye@sA=!v~ zF?JM#695A=TU4UM2;uX9T$K)^ zfc;^3!R87G@}s*cxA_O0)gFk-fjHuUSk}s*N*~GSPe0Ag;l7!(r<)l*4r|3mrK*jw zEShs9goRuZt^>RTB;65)LUJdoKYzN|g4K?J{%^#K@>}qqvx(GQXRW!r)jzR$x>RU4`$f@E8rZuJho}^AFblv6jZDSp%=?0v`hh4W zK+|75%smkYb0RF~E<6x#zaw<`$Yu6M3Kosj_}H=zq+ro$tiZcsb({d2v-IW%fsa*8 z5pH#rpQ>>38A(d_j&9UhtlW@OP?f^=sN>=_7$F!>Rf&$(9SjVN7ig=9*Mq`}xse2h zq33FJt!f?nT2s|!@DM9#FpXBMUQTN_tYM}YsKsFAAlVEf0RRC2;yEORkre%Z|Nb|7 zHYg|rcxAN*;yH0V8#4f=q7&O1#?Rr$!oVFDt60=;fRzNp`LQsdpi&PSJb-gU@aC9F zbR|g-V_AA6$^$V1h&2|LA`&34g!&Jx_5p(bpS`aDkLr5f=6k;X|NHf4b;Sv8r7c#W zf|QmTlu}A@hXi*gxCRp9uDH_z#hv0#ad#Y2SaSYJgUpadg20*x0A5ma2r)_@I$=m7<5$8=|UT3gnr5@}Mr zE^1hK{}6rPy2d8NaO8ts`?`&5C@MCR$pz0o`z)Uq{s#38fE%Pl@HeUkgj*cvfByY% z>d~_sM+e{3`@;QYepZ^f1-|o;`q9i zGZ;Kl4Dh&r|Gs&vOaTaf2FT#wxid$E-}Yuxei=~+Y9Yf0^fXgguGWV$A8D)D0L3LT zqBS1i;fzXVn?5KW!$ES6&c+n5qMl*`;Af1_3uf!}3l>+*MK3DUzxm*MB>9mUe z^Lz-`MQ}gR9>0Irc(Dv8n=CeY+7B}VK?2)$7Ufg$w9&?tPdoOKANH> zDD{QJ?_YlTIa6%08^cZzyT6dIV5VWJG?dl3Iny)(fB@vsHH~J$!9xaePXuU~Lx%Zs z|Hbxb zl3K8EzDeT+2%=BI8byGy1du_hu}s<03?zs~UJ)P%hm7|Yvi~UTJL?8_rfka*m)JO9 z_IO^S0rPtt=Y>=J*|~V-Jl8Ou2*M(0JUu5sf=oW4SjO6AIx zsa2~M)PF!f?h^voK8ijNfCvicCCer9rWO7NkNxL`Q2M|B3ZyC@&7`3tHdER1lX-$_ zdbMVh2>NvE%NuOl2yvvYyeT@c8~t|e5 zoyXd`S;&!Hp7H#~1qAKli|JYp{?Sw^%|U;WFGyoN|D{!;|!3R{*47!GbJH z0S5vKuj-~n0T6W%NK{z0f?N?5gmZvn!>$is;&SC)r%mFEg%k}tBmo%c3`XZUQc$V` z*jbL>F@=R&%v(UZ4G{|r#dky-0E-m5$B_?m;3%#m0=k`igCbo_VV%8n+OEi}j?2+Z z*%bpo;OKEJ;at(PkWm*pobJE=^)F7{sd|YWD2eL^sp||da#QX|-;L$_OO%bFk%N11_qdtmnb?v2>%zGqybfv{si_%*ht&{; zV1s?+;C7B;Y&{|}3PH3}qh*|3d>3*tNw9-JQ+VnHb4iSaULiDVtV{=+Oc^F zUAl0RZr!?0cW&RL>wo-8Cy(u;HA|-mqJazmvv}zu1{~!GRl(Sq zod^UeHfz1bzV>p`lrm8f2pkc1#$ZsP zFXGFuoEy}GYkpFL2?vgXh}OYc0K%<1HnZX@L zSa7I#K08PO4$cf<#_}s-9e@c6*Q$>O*A}%1yqAcoP+-S(LR||R3pAagfwRWP)ws}& zbpU8e1k!#pU@wXY06@x7p3lq7qEk_iicau4I7UPbcwW+!1p4j9Riog2)Kn=(r#?Up zAOf}>HVpt704L5J=ZFmpURQ~0;_pHKMh^LS7im^=yqv1Uz>@c_&7{c5vlQt&Q1ckU+pAdHjf*>@dBAL(aVWSzNO`3RagvNNao z!~8m!86IrJw{Bd>K!AwC72r@&2%;7I-4*d&V*hJNV<9L&p9vZZ^9ledTq@fD5@$B% zA)G;eEIP2g88O(Z_}&yUt{rV!H(wm!J(E5LR=@-CpOsnmtJpcrpW!c=0RA>60Mp6* zWFeM6wIQ)ts;dGLL|FhWyhn*s;>o*1J5J*ur;do=MX`I171#CrCHp=Q zL?FoVWA~2t!)k~ga0@|4=!L<716-|)J5}U{SRztKc&)_A@m#-BUDi0Z{oIzW_bD&m?!$I2?lk7Jh+$S{te@cF=JNhvN{(_k#CEC@2<5B1j!tMq`CnjGKKZ4_})hbbmkI+H3C7p3_W{XkM>Lv zT|^&ViDJj#FTkUnS+kHQqbm6A=$GB=jorS?v!!7I7_>6^ocpwRUKodB;r{k?GDJ9I zhIFIiDhes-UK$I)fbP$CKb%RGt4!w*62Jj^-N-RpsZ+N#_mT<5r|@89XToG zw&4s>FPJlLmWUX3+bP9nl(K@8$F32Dczh8tHyvMi_4qYNne^$&Tz||JQPBp#0?r*y z4!c-1(hVKv%j_5w&7oOk6>)S{v;^>=(26213hP!!qXtj83m~vhYkk7Id^jMi4};@H z$_1|lsrl@5qNgDW2eSFitA?Wt*{o+(IB^D?>2Eg zx3EDO00w$3HVJr-;YjVBzRca{AdmL*+PM}g zSxTDfzxC%7<|Y40ckkSyX>mg-cw8G3jKU3ZFq}lqPyEf+dY5Y;26zng-N>&2zG*HADo00yP*|?^mh9`RsS!d50;RD^@SJ zQ^R#O2LlcbP9Ax7^pIfZuC$a?DoHxE1DsNTjuj#m)%1sELO3++9^r)1S&c6=Km}p7P@(a&76?S#>r@Xx27V&{osGz<>u zsee4h4S(z~JQ#t1HVqaMq8w-4|JKfNq}TAi0Oatx#fukZrjj~0$09n8Qx(ru4~3e$ zq8z+EL+TKNJPPc5ZZFI9l=a-KX+^x3NP(hjyi@0ncBwhrJaOT?S~N2w4}dVDMXQFF zIu>kZ5LMy10B7#~xpX?saVq*bn1lcQ&wuD`5mBjOTu71Pcpwj>A{=`fv3&m_KZ4I1 zis_I=xnhtz+$y3QYb{>3h^2Vy)%%8}O#1fk%iZmuIzI{kLB`{q52n+tTgi0k(k<#Y za08WkBaugEBl57S^k%HQ5z8InrQe96u|vC2Bu0WyuuoyFUOGiGuq>PP%t6GK!a95U zFqaZ+b!=M->+{bi7-XjGMj$2RiJ--O{ID)uHq$hnlx=>?)cU5 zGkCOY#z2JY1jS)QFRC8q*dKzOJU~OuKtYu0s8eR`qK7&GD7yfCX0wUw(6I6M^zVQD zi`rRIWcKMo`TnDxgVzAq28l=kn-X^-5G7@@b;lN-!Gb12bkJ9?R*foFs6ah?b?0>- zb{~l9T|?I7y^m&cJHgefcZ5%TK+9L2W-(Vh59zBs77Z+CDJ(CubP!L2`t;^`9#+4L z9u922?ZG28)9AzMdr@u(a44cnim*42A$Mot+#&#Hdi*c}L~ZQya7dN;_U&bIkzLWvSDol#k$Y+D_Df9J1$cmS{ildVTC`b4 zFN!zsX%UemO+82}#G8tqkcZic4rdD~4A4TM;e&bzzyP-uD^z5ftjY;H_8Oq}06Hxw zoS18YhQ6PcFXk_7FX81?k z*#!_Q7@(0-$)1BDgbsSgl#OHKVUQstC;?=;>118$M9;V=EI|#*vib8#x+~I(=Pua~ zUQ*Wzw;&DxK(GN&@0*Gy@Seyy9ItTwBR%l2I%Gt}sBNIYkJ_0^Em^OF0vn{)5P=}- zP#RuHnWB*p-SN)V4P=ys4Gqo@(N4SoOh;y%tFr!B2T~@AfrUPlYE`S!_un_*##*F{ zA9f?50usn3p(hQ|2D;EUZNA96egF#mQ;k}4I7SN%001BWNkl*`EUd)9+3I3${It8`jmPiIv?x z5N>AiN)jQBpG^gFqAlbJ7AJB3%n^eP;Ce1jo{U7o)k`OHNG8=H<+?Z#jAAVFh7$LR zb-5EA9iLOC9pwHG=+N})yPocfh~urdr}7&Eny-JL>_msG$;0YIx6T8>Oas3Oart7gAYj3@?sJMIh%a z5r|U1<>NYb(9~VBs^fY>&Rwm8F8qQ83h+AEJzuma@j9llaE@@2*mOs^?JXkH^PHaIR8&HYnYQ}igDSLZ?{;?R zR<@j#RcDJ74l~$5jInF?E_ROHI(Q1#;-jh`FiQ;cNdO7}6_&;q;99Cw3D!_^+>9ul zG}KxEQYFRn@R?N+x2wf-W$4T4(9wsbOc1>TOmK^yr*Kos%GJ^2W zcnLYapEv$cw2n4oj%^BLh<1!1KVI2r6 zZrFHU>>v+6^iFiuNT_C8gF%Cu0~kkgK-ACtWtTg+!)ZFt;Vi9RW;_o&cdUiSRo-2F zso~&IR75v9fCCD!ppH7Sy`0rt9F=*I67%+H$DPw^j)N+|g7pQ*)1y~6o-q<(6zY+F zf_iZG9$ncm6%i>gJZ4RkWL3%psX#EntP&pSnW{mUqJjdT6txuvX}^i%7$lSoh&BBL z3hK(W%USpkP7<{ccf}Mlc8-QZ@bLq@4$@@UQ6m)vp+l^XYpv9f(G-bj7DaDF3;ekd z&jUzfbS$C|q?b^XN6HCPAFU})Ww`z(dro|g&=`u^M7eTh`Ll@UFz_5ZXo4t)OQD$% z=|A<_SOcHsH<XX;0g&Ad`{IssfQhbSSO)kql#WLL?O5jWFDliauMrj5E?< z@M|$N+P52zqgDP_)t|v+T`}JVRSGCQ_0K^ z$Wrd4uQHB63;_A+tMN{{A=@(z3;@CnEvYG4;v?_dwT5YFprWMGIaPg%@ zE*CUJ$hvp$0V#+*Jeo9Z9{G?{Dk^T_4B%Xl(m_9g8uGJ502A0u7)6V5pU%{GGwXQA z7ah%ZXtYDF+*-87c|eZ5V1fMfZT)(51k-Brv_wvK zWmU=q4h$MdU`Vamu$qhW85xS+pqrYFXiRqwWM}JDxDcnZpxcCoJBSFX?r}U9L;(;7 zRG$Ny_{@~oX-@!%N|T*uCyqutfEv30@xJ1Iyq5q2)UnXChmp1KRe6^|Ma^k}N-%c! zI2WX`AeITIYNbXi!$2lQFgAj?XDx6Ympl(M*WqJ+4_5@!CoWSY1y} zXFmHZzrUCjg1=ErHXMKd0eu;;aSbu|#GQds)^r;p+Q6Uyj@t44fx0!05!VX0kA9$3 z6gLfGke#Y`07w89%~~zxY=}&sryqgHNG6tNDSh|dXl`$i86XD`8QqfRP91OhVY7YW z!Jl@skU(1cdF?!I^bYlFZzn4SpNsa4A^m#VBuqS_##<_m>0DoN1cDQ=>0F@!1zqKr z#ha#5SnlwV6`gF$h979sDEkx^A`mptl&cWIbT(H`M1_vXE%qCVbB1oef2qyrRkk=I9u zFPhQtZ`1t$+; zz*xW0Ot&36VhE?rRC)~eSx4F`gC@E?nGiK8?fUCN*SQ~Sk@*3l9y*x1w1UrA^!?19S*#lzZBjbP$AJ{4zS}cVe zSBmHW9Q<22CzvmQ?PTPDlaYhFQ}MF07sShzaLS_Ki=1PbHdFM*R5g)4z7Q(V#T}0X)&&=@r|NYx614F+Mfmm5luIBd@qY1Sn%&5otq2B`MfYcd^<^VfLx!}E4 zUFi6m)$3OB@#9=^yqQV7poW23j^h+ctchkkoG)rDcpk0^(oT4704WF=RtBB5>m4#W z*d*ckD751`s@FsB5da1o9CvFUYSc5BgV4T0-B5jJumQt31W>c_`9pN`C?XKhcq_d( zjVBIv?YWj~vTC3ddeZP5L?QEkIL4dVJT45BQnio|J__XNfngTuClf@(<{Qo2@W+TS zFjy)sq!+~mcW1vEFtRz{AMWos+SW(h-+`s6+O!RQU=gxEv*@f=|I>l1j${iefi_ zHw+CvFm$Iw&K+Qa=UM;mVFC!`yYU4=^B!0<*hzix!3QjB0`We45v=u&jCN}5#7;@6 z38W0*lrajmdiARO#YLVU#dk+)WoD@>#rX%@1x;ehRxL5Ri=EXg!rq+t+^U<50o4v-j3iT5;3atD}l3=u)3k*qZ)cN^psh#-2yt{Tw@A}kya7;sIS zH{sNi(vjjwN?aEJGp-8;DuKeA*)@SS7a}spUJnH#i1Z+)3AuSh6No4gUGb<~@@%@aWg0FOSVdw3C&LOs6p2;?&V@)ZC za^dnh{*sOyGn{viNIOVc=ozQtd(NB~a_X2lf-ke z4nF2n?m1ZN-)F_F^&dy4iN|q{_!%`F?jGO0)tna&$K-5Uq57SBaW0>+o9W`N%B(eA z!vqQAcy{dBZi*VJb8$Qtq|MyD9;%4$?0Tr00vKPo7Lc|_3Q^UqoH6#yV?Qg&9r!$; zI~>Q(eMI7XTpd~9n7+dGRfGt1o};GMu;KUAq)B5MIchi`AD)ZjLlON^L?Ap+s>W=N zK)$TIfJr=0JrisWlxoy$2`lnO$L*H`rHtmnj3>Ytrm|T0bjkG+qDWs$^s_Xh`iV3_IZhJ6Kl+BjCuvZ4N?SHbq|4T6%Wr zZ-9sELrqi>9rX{O{y&91m4Shuog;#ZE=C|K&7pGpiIWq!{-Nfi!_ch`sfrUu6If>H zEN4y;jvSNcuq$&V0#Qx_z_DK(CwA4&8qi#MZCC!r-5t6o038ZcV%A`Ga&NaQ^ zQP~9$XF!nNYiIY^T~1pH-~tUD8!Mzzt5*GpQ@tQJV2G4ew2>PrA5jEi9Vi9Af+zz6 zrI7U)>$ja=&J#%unk?oXv`@dBN3Ru#PPY?1y@7r<5J{xh--@74?FVs22qVHl^R)s+ zh-H*G6O;U<&K1~J!}|ARWp%6r0Lcz`xF+XbN`_A@n-5E$P9`FexX|9rGe&cZ<3H3q zu8N)ZswGJx@@VS-9@ePFn}^8fE8^ZbY#vqrbS_o3{bdD2tcttt?Dny9bf$^rj^pzb zcxd~3m}74e$O&gIo~E(m#xQtbSQ@?;D42ir;fJg)ZP(jlq+TCY3d?bzREe^Q+@B^% zJ5u5ub=cenwO7(*-JuBE8obdThvNF%?}bq77DJhIg!YH1N!}tdX;1MX?HE`97*G)j z7~P3_bnY*%-vlEamSh4_cEH2sk+$dv$0%ELh(j^g5kwG)pdJE7RbqHQTDCBTwr>29 zc5Pio8&=KYh8IK~fyNXpD|o0$SO6zn4Ew2saW26N{sX4aVLnJ?^gb@AKdKst0uZwhd-MQHnXs;pFbE|!ZQ7W-z7^Bw^o3Jq8pEBP zpsT=>5eR4?(3a!iaq6&L9Yysvp?3)133Qty0zrzG2Yf|_vR>HZ0w7ip0dN3Fu)|k! zNva=2frtA99z)v6aQH0yUNn*YWzo{H3?^TE>Bn`F7EOoqINZ8*$5GYllc?;QQJhJ_ zb0y_C&Q8NCJLjCsm4i0vWK{#rNWnT6#L5I;#ZvO_w2I~2ao-np7KkV(=8;DrRu&V$ zVa4iYT!aQ)as9@%Tp;|uVFUW^yZT%>+`N60-L6YV1ls;erfP88c5S7p($|&3T@Mo&l8%;DJV&vTsHj z1)bO|AtTVf%v(v+wB=HoGW`%8I(&@|3QI^jz$0xT-~P{MgN23AYXzepX${0N0#QHn zB)7|Ql3SZLt$7HMib}BSYSE%O|Gi3oX>ic?Bu5>NEJCDfQ6R5f`zww#Kye3E7qf4e z{(C|W%91Hr`_KI20w5319DzUr1PmK-^>Y!+r&cr1lwLs23$0 z0W7M$7V$+}@x6m74u-VV;J&>WJW%&=H+AJK{|F&PNVTJZr=8DATD;^WGaz6X^3tmP za(cbOWMdx4;}L;aB`xq6gyv9C=h^9>S!SodFK4HNxrHyAs#9nX(e|X(I;<&Hm1f0v zqiM4y3>=>spL^5?nv9x39N=GyV4_N#34YXQS&9VdFw?^am6P5 zLNDYFf8;fgjJ{mZ#lmP>wG+eqXWWO-9lAtn3LAE28a%W;X_1HOcL9k6X<2-ZVHjC} zqB(#A>??GdqiBw1PcwQ%nA{Nn2c6cDtNwr#&e zr%qpI5NX|Rx!quw#|1#FH4!{7JR+2O_3p_tJ)kkQW!ol}-hiqpzFc2^^#zTeFpfq2 z%sJmq`W7^}XnP!@4J*qEpn*9zm>}4%E6)^lRP+JK68v1J-j5U%x|^pFUca79yLMlp@e{Yx$DhsRG#4m!k3$V4qr5Oc z1Qc9FsRbitunAt_;pJ>8Z9hWA`nLkuIlXNS?c18W))yWQ&m(<1dj(@yJ0nl`WuX)K1w#; z8lC9EyS9fBWjHdcK+DDF5uZ!wwm~HUBWcmsp=x~C5Y_+gTmGzrP=d{nW8|SDkiP_g z*g!-Ty#WeEEfEFixS)^WRz)l-;_x&h0Cf-ab)eG|{~#9ty_x+7ex(y9|6naF^oE>% zOti2v0uW~m6(v6odT*UNlA)q%Bbdy#eb-j%KcJtPH^vvTU;nG?KQd5J645A)AyYZN13{r#YFaQIeVbnSBGgycC9OG})-@Cfu z(E#$q0Z7J_GH2#V{;^{O0_DqZ8!n=VsC{BbzKoua_y_<`MBL(8*AcmyoPmTYMQk#WMl11 zXPi!Xyl7q9VbGU#Z8cxS`u^ko^w!2_0_(!m+zl&8U>3c(_L=n8hDKYO&w;qcO4%6f zDLh~GZ=m=+a?}VWeE1F>#L+V5$v^~AN|AiQpFi9JOmII^S*(D(eusa(j@}ZL zHo(jWI0FBG3Eb(9(YoJ%{~fbptgi>>fPyCOkB*C?jhok-jtP(9d>~058Xh7dz9gPZ zr;7M^9-fcC!z^!%#KpO*DTTPjeONmtK8k0yTi1qi@${Kf`Ehh6!^v3JMjC|Ijtu2F z87hjxx-dx6<8Nc*V|a3-b!{Byl<7%)Tr*}*W4Raw1bE)MpVv}!Y$Qu&AO(ZR)Y`aR z@Z&sQ8=`&~2aCT^gO&D(C=bL2tc@X92L*^L85%r}S{3S6;gMnV)AGgQu@fe70=M&j zm`fpIZFF2C;x|3nK#S)45+nNuU|!xV(rN2a9X}2 z!o&|uI0UOoMIm@U)oZKIM0SWD8bCCFJo%Qx5lDJbiE`xAW=>(JG-K8@{vEr>cJ15n zmzfLiMq}bT@4Q1vQxZ58hEx|o1$k)I@g5x;W$tbs-(j)0+!c)Pp*w(?R0Tn@VCgpH)`~~9E&O*$7`U= zfAjXA`EiVp#d-4Dh6WSTD|p{{fK=}u=Gt(U*j3N{VGduD<*Sxa{rcZBvq&9x+qSLQ zStGK5W5=~t$Bp#P=&_^NQU7vyKlSL<-EM6}i~vHcjT!fl=EvWv<8If!Ezb-=j|7}2 z-b?G+eiO%;V2nuAdOa~g5u^)596v2vBz~`Bw|0k4K5`a_hz$HEP2_$Itcw9?Aa68i z@Ey-(A2V(=|89*kus)>MaXkS_=; zT8?W&G6RnM3vnF)rgm!!hlXX*0(n8D6V=)PX+$G9FI+?G+K38q z9vio;7aM@7?7YpjKa*?Y{ledN>e7*S?`my12DuW2inZa$)kZ))rZxqLP!Vy!$*ad; zaPrWX0{CEb0M5&NT%1>>iWMnQY&0-f3de|JRSZCY1V27Go|cFxN`VfJp<30d+ysk3 zX#h=(qs8YDAcoJYHI?b9LjU6gAlB>#vLe=6tJhx)v^0P`;Sq?l!ARD;w@M?0MTF7> z|M46ZAYB8nS-f-+JA^7mbOFbQR2CdOzKjregcHI}Ru$*5BX8WKF*^k~Mbugp`wO>_ zrN>-ttPfcVI2QG{N@;lA#x?Bd@v~Z6Nmev((Tvv)3=W{TD^)hvW@3PNEf5BdZ8&OW{)~(oi`T6^?Q@3BcG6jbQ@%5@#?;A7Pg28#> zI=~Slodw4WN2%5Z(D`)q=5)^Ju_NuS3C85&n!wQloa%^OK7h`;HX1__p#b<~k=cIj zuHCxureMIp{`PCvtig^N=`y_6c<$ByfPdJ7^#L>Jfqv})agQ-4;O5taVS>QJ#K z1wd3P9cgmt^I=vx4EI~rcym${D}D0PV+|mW_C(x$Q=X(6NOn_PCygnA*21gG^+Q{0 zVt^mZ$>UblI8brR5%=xi$DI3)96UgzW=-jk zYJc?=r`S%OInK@$bpSX$Jchr;yl#LN&(=P$n|JeSUAzV&oBhI>oj!kpj{)g2^|wg% zV7=qw+T!}+XWXa$zE$g%3|gv2(YsGC`lP0@cCAln$S_~t#p7`}MNEWLjufdKI7l2b zoFKsM3$X)Nk0U*Ux#YMe=&nW@$~#lZPX~bcJE@IGu9q8dW892&HG_4_fdQzKnp0MNJJe#5Vg=OBHB+Lxl- zs?Qao3^gX$mBCwor3eH*rD$o{(2SWNsJDLj@oajp>P!X`X!NO}Q`z%B);0(wplIJF zVQsC*srCsE0EqJwaRd%$C+Nu&QE!Ht;qHp%2#7pJ0Alw=Jz){8vy8{JvW=MekRA4wu&!QHcUI zRaoV3PZQIDeapKHTxweQ>a4c(#wE+rNCYD@#CqIUQxEhqD*2ZxnZG^Q|fn61H z@wdG8`c(`%d&LeO*GFBKGZ#*B-NA0{bM|Y45U^s+GTORxGat8gZA5@-?R^LK@VTh9 zxtP6s8?Oy;S40L?EXVq&F|Ay^oV&E~eCvk5x;C6SUe9*irc55>r*2B7BTp=n^^Eec(SrGxGLw~qR2#>=+DQ;-?il*{!Poo*Lj?nGfDU_P} zfRa=0b8~ZG$Sx}VW|9Dym@I;b!%UD;wyCj@Z_ig)O1CS+ybyJNA=Qg#CypEUr~t&K zNv|3N(J%;YD|Dk{Viuo-(M-r)>f%IjLXNuho;nfr1|m!>o`K=OPi5lCj>;>hhk zaw0AFAIGcagsZ=?t^?4q&d#>3EuG?tG);_-Ys0xaTU+%LNcNSpwe9DZJ3DT*yH9Uz z1)6THeb&Xb&!$~lby_oMIa%8}i#%IvTWHVD*0%NmWoPZIj==pZ0f>}RilOrFOr_&S z^Rl1+4(iZlm9W(m8nK6N+(@QFhkv88Nm`Zpr`F(~G$y=!b>J>A-<&?AS5F7CmQB1%LLHFdi{+>C!E3W_}@e zgt3uzS2{`#_bXN=hU$JjmWK4}$tvd%t5ssQF+uJ57OLkMZ;P?EwLLLUmBFh^-X^<0h1aI_F(yhfzIR7A%dr0PB>OPAM@2QmthkP~H)| zBz}MDnPB?g{{+$h{yRwQ1j4yv{jXjF(WXrU$io2;fWfQzBdK=19~m6VRh(iL%K;o} z%mnHqAJ&-7>8vE* zuY3zXlvnsBjFhm7Q(+AQ&Vv`gRt-w0oYIZD{9+cxBC(yQY*acSWbGae;AVMG`9 z<@S+CoTmXq&Hs?#QQ_@SPFJbnP|jwe0|*B@weg@n|Ne{P#byutw?^2!X@1YkzB5YP_g_1<;q8p zpLoG&BYX-sQO(EhKyl!F5@TBN2{e6WR9sEd?cnb2?hxE?;A;93006~I7 za0%`n+zA#SxCM9T9-jApKUvILbNWnmch#=FcZEOr71sIaoFUT}r+CJ(I7XDy$qumr)xq8pCPpYW{Brq)Isx9&-|J zdU~(c`5Z}zimyCpK_9&8SGkk#^E<<>nE^I>{cfS|REYk$&{#Twn_H}ed!bZRMHVhc1?9gjQkBq_^tV{LRM3YmxuBPO29m%k4F`H{e=i|2;TME^^gsOt z3|zMkF70{0ibYM_87wvQXLXP<>5+1TMFRz%e_Fw;HV4LOXlm@g4XMk>Q1m)oE3W&2 zF+D?306SElf)&+;Cfyq=4_k!D(R#6XZvwyT}?6KVSm-*D( zd2X>vv42@jpjKJEs~NR`;{y}lE5z85UTUiM?D%iDkC9JLhC)nsUhYBF+-JTrOM+?m z*1G^T2&K#KHL%R(F?gMGYC0D@2iXn8+IVLD`fqngJDlhWJr$mS(ecXX`bxaK!0Vcr= z9<3HOG)16D%*kroq>sE3ZGTsz7z@#Ld5}c?tH0cRM&AfJf>;CyT|ToG{o5EIpR{Q(H~omcH&u|^v8wW0=a5!$T2Ic zZi@{D?)v#w1z07C%ECg~uvEG2;o~YWcd+2=v)}ytzjmf05y;Nb_|>yrRuoPDrdqhn zKqeBbq$4>i21SnEUHCkB^|hF zcPMYD_jwe8ccG{J9eF2)2K`-=-y|Nh4tPtrkH}i0jtL-j|4B-T7<>ytnW_3M`JtmyWJqf%@pq{wU=0h9 z(M@i?*7}1>OPN%9`j(>BKf7!aOpvMenaXNX2bUQRhNP;Eh+;ye5Ol$;sw>IKF;+}8 ziEHfK{&3@5MHPO(k0|~BL#k)5-{s*cJ*{{DUbpYyfIy0AK^$6uOTYGlXSF?jjCYaC zshA?bI~}z`fOxr!f!nCoMK_ROx-W}qtA*8M{7m4oCB9R)=%=THp#)SxMrHtY*)ZmK z6on4jHg>3-Eu|hJitM?~|uQchq^xE9x@`H6+%@9ib1Xi`}0rbIB=U`F3JmWYsa9S6Lw0GO(lw4tBi%kv)TcSd<+F! zT9F3K2k0vncj=>ik${3xTnGGWxtnp>GrvIv5B=%^6i?q$%G|5weu+A3yoO9QOM?2&G{;z6J}&%I+~Y9z(jGR{_j6g$HyMKSUI7p(#9X(?90}?6Qj(ON!F$WdauQEkmm;{7sPdBg%l>dSNc8!9P}HDlBP$Ct zH9SJ*e<_E86HKPDz0&)Rq#=();U-P%rRZ6$ja8egpzMtPim5##w7n~Q$Jtv^mkM5M z=%LT`pr2lQ85L0S(Xff-X_JbebH83F^T~K^8z}QoIB;|`JY^Y9$B7q;&&N68vj_=4 z_^Xc~_%(sEy3;k~B2O|Mt_Iz@n*WaJQfi@@ZOStai<=p?49uD@+TH56-*DUCOH;Qo zQd$$BQ8Wx3p((J3hog?cGBC07pgZdEvOF?XxE#;S<+#y?U+<&^s%YxvW%UZBRN~^l z>!$@i^`UuTRL-EJJ^eN$w-XDmErIXFKfB@f9G)q-n=Mc-1Z6xz{GC{jC{=5c+JAc> z|Ge{dS_z7>>l|FlZB@33kW?GS{yl+|q-Ig;e7HzdI~>6*u*QmoZDK zmyATmTy{OP0$$vF)W1-5OXl@s6FSV1b-QWwFBV63gTu*pv)-D8Iq)Djp}UV)>k?c$ zq1xIdV7w z$%q)YC%{#NxF#>ysk4@f*#*NBXy6-NfVoZO@s{}$gGE-Ovb!KknNsup6a4{-;rui$ zm;eczxOsfMZ8{wNZ=1CvVhGLGWE&dOvX3;tu;yHa65mt%>x7%RE?o*35s`U$Ms4rB zc?f|T=o4HLj2}O7+-EOt2ipGOGLaRGI$#v+k@ZkIqq-Q&pPko1 zZN$s-2gC(IHND6SxmQo0Xx zOL^#=3tUcgE`Q})HR#)Y5_rOKkFOBWFqdvFsWqt;nF7pdEnIhIh;-1^xlTPb=zAOv zGM!xIM+zqvBC^iB|HLpeeJN4+c<{7T;HZ#pzjQ_u!z?SnC`BEcAyCHcmW$F#WkKy0 zp~33%)PMX$T(?V_r?RS}*=H%PUVbym#P>qbDK6wFZZ~J{@wosV(_xt>xG+hB`Lj(} zU9&!B>DADF$4VS}7fcL}c%;lpo=lADOoN?QI$6e=5;a{hA~p{E2@|JG`Kio2d{Te0 z$EAFuk@HLvs6+2M0&R5_^BBpM=+_LVGmt#`ay{KJo~} z=_|n@`}4FLEwwkrk#-KKoFG36R|*Kh6WJXScx&m3ucuuSmbyZkUdF(9I43|Ia*zy> zSL{kRg8h`@rkcyoB3&bvTS?Jx)B!_F`xQH$bVatwX*Kah=T7AA10rj_R?XoL*mnfr z8BuC7!P|%HUuq|kg0y?tB(5hOgBJoaKU`0?{?xJ=6G~aBkQD+GTb+|go1rjUe6}zi zEGB*DE9JJab~!AQ*keIIf;n~AQU#hay%YVUN22MJjAAfNH_cDrm|kzRPC(BKZd4V? zNQu)l4sXTFW+@`AS03ZT{??Mak-e7qvn#nAfwh4wn-1PQXF*9|-$2$(sFPw4bJ;VP z>A>$#2KUr4f})2xFNS;@P474H0BE)h5=9g%gxRnA5+asnGbQ-H{(98UWzl)(%9yF0 zu33KkH9AY<(82oiq$Ipwh=kE%s)wEkrU;wnVKy`!>P?F}o-GpLvH#m$@&`;2DsKOF zrHDQuW0Ch_?liAM%h!ws1KDu{_5%30pnTuI?3?_RKu3Mo41~w?{C~GLF}-%tp;A@Q z+|#FbJ9s8g7xBKNl=;QQMlHUPP;^^}{i$%h5v@{>J-7tP_|kLohIb}+Mj)g^nzN>F zv$Pba=6i0HG!7Dpy~Uz~a?7sj2oJ1%ZO#&+--=d+3&m$VV@0q8XBs<16c}h6YSAs9 zeVeX%i4n|JRoL-Z$W+;P;&QRf8eLnFv+TBsrjs0>(`-@oqT*NOfNuYf{MP>!RjM4d zu_5XVs>XXlN3Smo5N@(&jEI~ZUm*xKJw-0y%z6Qdid7JCDdygzQr&FSO$$6?NvcKS zHDo^0G}!pH@7$o?#C&HE@QxY-cb}z;fI6PdF4HrO8q-c7JYQwUOKQltox^+~?0asW zko6x00dXu3EbM-`gT+8hIe|mi6&VQ-)D&6Wl%@vx)M?jWv$A&)f6U0w|4@wO0yTco zr0wL7nLlMO^&9joJKui_I3&d_%#iU%D?K*8!6xd%&M8@DB@zJ@TaCT)#&; zd+ZP5kwjslz?x@eWX)+D^4V^$@BU|We9MZ;@!p5FxGI(a4n-^)1dkucPLabK0d!_{ zSrd~xD&L{lzcx8TcW5(Zz2P|4LmP?42yHOq08D_5n3H=JgIVSglXtO+J4x)l$XVN; z3E{ULyK|_w_$SlK*sGvKOUmhs(qZgC&rcFMQO?-j3jbeKHyOn=V)HpH(jlLO|BL<< zFWruqldYyE1)$=X?EJUS>-OzCOErbnf>o&XM%^U+RCC^Ha~6oA?5T`fvs19w7=+-f z__-@$l1+y=fC&j*=CU~pI#Hl4zjY)HAStYr7}uLc==d^VZ!YxMNAw^StZ@Qzkl#=J zIanO!Ns(q)AC1-tvtL6ph8T>;3f8Aq-PfmhTLZVqCnYJk{JHHu6&ZKW{8xV_R*>YQ zj6GRTTMFKz|CR29Rs(c;zd9(qD^OV(wt$JWH0H3&{q8)2r5?2Ito zCSMZ9g?`GCEu$5Ct)Xm?3)?SG*H~x9eC@+R>;fZ&y^Bdy{NRt=(vUqJg;8VoC?!_^W5*pNtrY$rE<;0^9}G*PPglBqBzO`A z>3AKO1ck4JCo>u+NlT@@HwgKJw1SBKT0tF8oob)V;Je{!u_tZ6Y5a323`dPYV@LpL z1sK7DorBmd%lEVtJcPrLKM(S5*Y;t4pFZ}wL5SfVGH&P`YtUrevzlWf?o3!}_aA6A z9D=Jek*WRueW>KLhD)(=L&nx~Hgvo_w7d|5#>jmXu8V69gX-r<1-#gNpd{Q+&J(X& zAKV)2^{t!1O*N4HLWRpU-3?>;ncSxQEyHKP0nbb#3v#QPd%GfnXV|Yq#=bCG$~Po% zyVrF4H@ohj*O8yly=TH(T=gp*iw#ym%dY8M{+SYFVp&NpG~W4gPPp;6(HnrfaHJMYTLZ#b+|uWsSCMo zVunEgr1Pg!WIS2!rS61=i8BaBp7`u;6a)!?{~-#a z%qTmcm`_D!2XPlzTIb)@PJXkf^F`!@W$+wM391LZyaz!l<>=PTMa|6xHNak+&`W+M zO%SpE_=A0@mnpm1Vzx)m^`Sr^w{u)&-xh;?CNn&_Jdp+GAgT&(T8NX4iehNv7)t!RmULW}ZXIfXVU>+`LQ7uFhUn55<`SWLh5 zU~>g>sa34GT7w39wXjoJ_43`mp&ym(ymlg?DEz<4s}9C!!{-exgBoD-P2|a^#I375bh{d=o5!nV8fULghb!M$(VB6+c%0=+0#9 z%zDRq*MM;UiMYd2t0^R)TC3v7d05sCKo7X`gr_uGkat5>xvaLD*_c$XDUre8fDYR@ zvfM*mNH$K#>wiv&h3)s1g^;G=F&+}p2ftmo^`gum^-L396=>xVBBJas`mKm{X}LNt z>cBv2VX0^P17_wrS1#%1J`;lh15 z>Q>k|w_R@~dp5#?vbwBA0^(Dqjs=pR8!AgbPBsW+~Q&ADQ2(epUp;rI!Su61Arjn%IB%%wVW1#*Sih6!o{u`)7 z@$|F7uV_E-+^<>kj0o)oR7Hk^P^j<_f#6Sh2P$;#d^)u-uWTije~0k zKwLo1&F2ur4U#Zd2a>(kn?Gdpf8OJHzP{vmrY1iGQwY0UU@#ksF@3LH=JJ4(d%5wW zvfMU}BmR0R?hq{JdLgQ)tgO6nCSV7()}dUNEK8CEiEAm!Pux|G)O4(t=4RRMN#Exx zgr=s}Z7AP9CER(2^+&y4S5i*F`8>Y99 zD3Q$GA^9!`6$FE##BrSzO#I7%e6LYLzY5ja4)z)@kGi)2V0pKa3y$)RsFd}o&HLr^ zwD6|GgGDfI^g$oO4aZ(V+sM#J3X`|qB52>_>X@ac4;aTZGidIOE7U0(secHjD;h)Q zX@n=_XT(mnJoLogLJ(bNpV!4u z!(Ua(0#;+i&8+g$TLuY~F0(hWT6kMFk!xjyT%?O4J(88)5~g`<+}|VL zHcb+mY8oG`s*PH%!C*l~22ItKh_%*DC*c#;!Y^nwCNs@{z*B|{wPN|^A3b}9l9*&GM{I12YKokB#DAwrRg2*&M6@z=tFNY7jr zo`(P90{j$jw1_ar4YfuPBV;3#5lQMz_DIm%MGU$q6&Jp*w+H!<2o%!+^-t=}v4K>V zQ3n|4BINnqp17XxuB6k{17&GQR!9G(fxf_SqdY8u?a`FuN?8KRH@vfTeho^|z;{OU zJ!8tLK5ksRb`4)+^cL~FcNkwu>=;Jm-%hoJbmh^cMyS}Kst*=IA6wmHY!@CwjIc;_ zP-`?n8X8YepH7@@mplc<>2 zM8<+O?oO*d2+=%O)5V4F!%VAu7ux!^sMW012t_*~|8dxH2rJCjIeRP{EttS@GHD=w zT>M;OGeXt^7cYRdPMkL=+c>ts(}BhpTI8dA&3(!OmzC8Yp{ zEfL}nc~4uBuwN&uy53ng-0YF(h)634ej5$WzI0Bs4$J-_I+cQb34)n&pTCPE@9(gL zs{>7yBN7KJc?M+Mq`uCNc0`EDg3vB#U|Pr!?tFFHq=q@zN+nXC1`{NIyu5{GS%Clu zqFtmZ8pJZ?r$dg%P6jye9`1a&y-8mzP$=|lZKDh01#3XT{)jojbfC1In9b(v{=uR zQ}!_us6tb1UP5mSs;;QW#lNVqBNYbe6Iy$emSU9HCGcKdy*Iu3OCV{p7HU?%{{!bL z3!=h-tQ&L(VL2Db_+RM53r_ObT5X(l<*f069VP zL2XJK3!-RR`NT9`5<>guej#=oaKmvs#MJcZqhGY8ls6rKZz!4+%P~nz|49<^wdVWK zo#{sbp&GytC;T!8TlCw>YRBj}b9yZl>47;z{K+n_xm96OBsa3)ezcYit1b=My zEu(U}XJQY`YPQ&S-E)%LlSuBnabG%PTIH$!=v|VO>MdGV_^%48Z zU%tbvVruJD#60U$hfEPZ1Os>No{1QjEnH)SaC7oKA{>vW3QakVtQRfptZk;c*pfIv zFW~eSuUi~-YupqqQ}5c<+GEeJT~WSAUQAZ4ojyt zfe_T?Yp}vgL`adZr5>;Ak@#9cl-{#O-fW?7(18VuN(?`Tv@~fRkK2u@koz6~$Ui*g z0a!he=T9XNF_oF#0SLI)0~V-{`4U1A{gr`2xb$y#+|^V0#?|y-U8!HS2dU53K$@s@ z-NhjTI<+ibY-(idKemu*giSNkDo^v`e?8Bc<6{YC#e+oNC1_&u%19dl`Xr-=UNq_b zK>N0Xe0*J7pe=wB(GdXB zh0Gt(`_;P%h3hq|M`4n^x6aG{Q&Y-Mk8zp9?#~aR%Z*#u07xEg(|J(MB!f!@CUL+_ zvv)lrTfAqGMb9}kfm^c0JIC7_JY0dYA|k~N$vkUZfnpq%M@jqX1|f()I+$AQ zAb9v;xqb)wJv=3Qi~o*I=jq_UV7k5zBZHnE5I2v8#LIAr%v~PB>3}_?&Cd!G68?|5 zrZkOeF?^%er!VD7hZ4pHzB2B0E`|aZZ<_G0%oKWulZo~@+!m~>EpD?FkwY2s(NN?} z^v)(UaY1d3Yh|j%lLcVE72z&QHcIgYb!O{RvxS z($&xd8)Pupu+QY~BBk%!#4hspv9gFL(yfJS0-!1L9#vL~wLsJpzT=^iz)6V}j}gCI z{OT>>31LudN`2AHzvL2os6UJklZGp0dnOhu2?I_X_bz@=%cxq!ECo!TeURy97K{_P zJzy$TDD+9L=Ejvs6@VsOo#y&LF`%V5ZE}2(uuD_5no0g-#Ds~&33(s(c*T`jjp8RA z*Q7-{+XABG3b&YTkrai!S{)@&O=n{Dx*LjCY4mvxI7e3DqV z!mR;sG>FAR&v#{`n1a<;49AjnZxAujf&V*p~4Ka7%3Gogso$afQTDAWh*FUm(>UhkgE7FTk9 z0Lb!m#P7Q1-5whjVP(kz@A!wvF8+i?wdu$-hTRZc&fNg5a?W80SZFbNA4k{~?{(^B z{AXTxAMHZSK4}Q$cOGGR&teiK))V=hxolbV!wJo1LadL7KX3`btJr*>uJ8eF7w_zj z8ijkJXy`d~VNavh0ulojFRlp~UjiS4L3O!#qsh1lJ_ZA+x$&&w*(cD&P|& zq(908?5mrIw9mv9iq)g~`zEsCu2idkW`-PKuu`M3K~NkLL2`42RX^3Iszp^9Khx(q zd~tklERoDih0EOD$JnHs{DT4e7cp6qweJ8VU#b>W5r;pSk`AH9rAeaD z6w>qOh>qd~=yzi0F=XFaMfFWR0Hb9V{6UmCdsBW(EGlBqcH2Y2s;#9dzRnt=?P{Rl z`yX>o^@|`3L*%2Sw7&hY!@6coV1yREFQ@8frV60D%IA>14-?WQ(JB&zmChV_LwoKh;m?SUd) zEMYdL4f1M$w~L*v36}qT2*nfVtxFz)Ws2J)#juER>1Ju`4nKmm|IcpPoe)M25Pi~d z%IHK?U`m9@o8{#>hsLS=QVO1~^mcx1FlHZ0eMZ1gTE!DI;vB%$@9zQ{RIcMRbLKFM z@a-^#m>LSAz6&;uGVke}r8&)ROfxwDag1i*vfE*xgK&>fp~JjfjIgm3ILSh+0o+86 zIw|(lO>Wh2++0$Y-grZrS^r&hCTiF(4|6C3^T@Gj!azRFPCRDnv&s^7n#`*nxe!!Y zBl2(1nJrmht@l!k+%F$aJ(1g^cm2+vTnrw}c;wjf zJhgtJrzXXTec*8QddH4QZjS&-`!3?~9Yt%1b2E@v9{D;6sA9H=98G1noouWe;}tL7O|hxXo4p`>nwdBNU=iVs49_ znlWrAo-%cf0|N##uOC)>Ss%tqp`x3ZO6XyI6?`Hmu1(9dnG+V>oT62~s;OvgE9;8CeA$G>JyO7T1))*aLWjUYcr1NZ%0F9y`;Ku_ zQ@+IBQvz&OXD9gzP8w-Edo9J$dFRER_%M45SdcV`{Mq-);%vy6M{Klis**A^L+&NN zc5DPXg`nL&7~YmV+8`38`aihm4S4*7LG6M{jVXMzT1he6t5&0q_U^{y6DT5_40NcU zC4uA!VA0i4LsAi+T*#45fiY1YMa>HUNviR_I|DKQ}b>Q-GcVcDR=ad`&t}D~=C*q&vyp9`}%7OOOP}+m1d}H zPZr}Lu&dre7aKf-?~IEG!lWG1uK5NF51|5@oe|L~ss3hDL*2+AIz2qEc17Fuskcve z5xuDbi*iATfGSXiO7GlzOYoeYg_3~?3b^cnM~MO@#xhw9jXW;7XSA6PmJ~$ zp0jyzs3XY}gNy@Kt@LG~B*j}6T$ON!h=wDwNlqUuU5e<$UATFCqESp3MDj^Gaqicd0GEMQn^pVm(k@jx!PI#Rl8|_R}67jFC#Zy>6l|l^q8G9V$ZGHFH>AocY3O z`7*$AqvO>Sb9My8aj)LZc~w{69tA{0wtHVqE5Ok&Vw%O6&d*Vq*`#AQ_)+xZ2=#WO zwq!9t>*oh*7?sv^GG4`YXXpk8-p?o-5D_h0(@fAmsV}f<(g>bKGHz1Vmk)6D4zr(@ zA1r7?2g6(9}V@>@_yJB#1eZsTz>8gN9gz+;-su08j6ZGXsGgyjv(elY8XB zsaf{$nKX}}+?X^+^#lItr?lyHVL@sbt&b`n?*Wc08I!vR{H;fxS)>=28c0|}QH4co*UViSmOKhYcT=eD8AxS1D8zS(zMjdgvjf( z(Xk^<%0Y&1Boc{cuPgmC>Fy4oT)U~N5iln=4t~o!A1dum6D_-<`*VH z#IYb!6TgY+4INInqmWw% z?R>TwR_GMB8IeF|vRIXoqXN$R(M~F5qY5QxIZDxoih>{6NPI*F%yidtvl2XOLBeD} zgQu>6%Qmh%qE)piFl#628l!IsC5ISi?)%H#F)}djqFYH*Ff_75fl`4JY<_^D{=pmL z4eX_g)807ds8Ssr_iu!frc!4W_B!S3B=uQb1nDsA%OR65=#c86z$Y)RljD-i#N-bQ zheCnoU=Ibkpd?#*1|kiQ^A?huoJ0S(bA68Xma;|OmZK^)OZ$B_2Ea{Eb{kipvJrh> zemnc_?r_*nZ8HS68-<0V^37vv0y)LMJ0BmuFqWx?}4!mAre#@pV z&-K{VhtT*_9KDW*G~zC=Vk%Yar9bDwmyRgFZwVGNy)}AA(km|G<-(lR+S&px*iD4@ zSDL5eM_Gc2oZLT6PE#FzUI!1?cJ3F8pekR`e^WCbHh3J#+ zU-0KhP?RYR|7?#`*EC8CjliB>yFK(Na&%f!6DZ}HWI`P%4+HCBZ2!9vBbADNS&fTQ zqbxwnqm#GFMxwvU@;lOA25`DOG6ijXL;cC>@?j{jz#sNL;ZO++@ERSPoM(g#nF7v) zM2NJ(=BVU4m=g7&U2U!hu~%K5HWlck$GJPuFP+Y%_Aro+z^ADfQDC-7hx%oW3^{~Z zQhK}A;u$)`*-QChF$^Kd6>{Az$p*lTK3|a5V^!c`pE`ROn>6)7p#(-Txe7gP)?39W zsFc7sl{0iO5g1lkgxiWDkEjk~)(zSjmj$4AJ1mP#3kCmKK$cd&R^4+h#L7HF8R$R# zfdvS00B*$><h7CzfOiKJqIx|p&Gd#eMNyJuoL|1Eu{B3j`PE! zq%BI558UDF-o09e*d>Q@jt3;$k1jU);EiAGKn{&*uca;`Ckkr<5K8ep4r)_duMOUN zbQ#Li8L1Wm0|1sn;w}+sLjWgul`p^CHxZ?=QUt z5iY^b%u};W3*TsO)&OTk2&u3JGeik-QNr)mxCm(O6jpcMhlo|zb=R{WzI3xj;gwHJ z%@IWk>}V^=y)hdu!D!OFI67FJR+HJ~?mLHMLVhRkkH7u`K0knxIYshIs3&K4Va~^> z9UUb1h=OzC4mX`jmckkxHU%y_N}bn?^itgUbWMbouO@iLT11pQ;ZnY3@{O8$bem&1 z66M1AFm}&0^3vph^n>X>8x;Ron*I~2BAoO|*u|ZnU=0cAaU{iMQQm0s=dds ziev42eYkfvgxifB8ux3|*Q?!KPnHjQ+!QntFwt^bZgj~jO4{i}VKB>?&%hV{8ZyKg z8){x#*3qokAfq|)_}fxrv~e^YYP#b3Cr`wqA!N{QE@PCbs%tlLN!|Epxc;aN+j{nf z1I;7hjf-X1wVKDzth}Lx2N51}KU#AO2gu*xmX}FsfVT{z88Dk5S?Dj!H)YZ>B8Ev3 zBjP9bj)YXSzVE7|%6?@BUOeSwrA0;|3Fe6J^sEgL6O-}lJ1gr?&p|hx&>|ythM8`Y z9j}77D{j8Fq|t_6Gdh)E9*mMf#^4J`h@ECQnG_q*BA8y+^ zoq{gMrN1Ha5P4=>iT*X`Nv|s5M)vV&dh)=xM9i;fbCoJmHYX|8UN5!gEqV{9uPEchuTxd8r#Yrq;?&t} zWPRaYgD0}8%)5Dfba(?laL62>0*u!ryNo-eJcwiakDp9sxfLZ*^SxTQ)a}oYld$SQlMGk72hW6>Q&1cmjTRy3 z2Q?N}f3R-fW3BS33of;!Dycc6ez>_FZ%l{Nei|j1bXKRQNw5Xs27yG3gId1CNP2T> zC`ROCSw8UD;*TFc-PqG-q<}>_Ugr4}6@(=fO8;t({G^dBth@`+7~o|-;gA_1FIIOH zZmBu>7C@Qtg+b*krTm9_(I#2)9+$Y(!jFO&m6Q$(J9;TXBBf z<%T62F{4XLSjEvbyu*R73Ns{4UlvR7E75)i^nM814NUadkaeTmHNyB9zDBCnxK?*5TlLNfrZhBp3pbAwfx>!NjMKD7}C_g+bwAbc92fmzpf2wb4 zSkW$c0E`&Trq5qw$r{U*k3rau@@zSW?;lO8{|?`GEZp;_a6{6xcYlkGRX><5Gm57o zfh8y)X86+s6cognwgVb}=FLi_4Bv9;j~`+@t?k^4<}2wTw;~cykmygk(sIkls9Q~L z{0G3;i|FS)`k08Pu+D9*`5!so3vd{!)ki(cTa1!tp>$NJSZNl!S*pD=xxlH)#`tp! z)mH^5dn$x}BU6s7 znRq#9J@#(tHa%&bmXgeuj2+vjM)z7seXiP%-M7e#!M8=1z=dr>v3~k?wHSBN)^r z@bTC85pXSNt-{z zOg>|`1sDEQcT5rShTWY2mldl2nCQ_bgnT`FxqIF-kb2+x%y#_&W_Zk`aHXBT-Gm-YBnP4q`z%u)950kyVv%3(E{5nL$UF1urBzIJyA74xAT!COKXwy1>$ z$JVt(7=gvCg4I15EQzD!#w8HSu3Xz#jCrK-|ET0)83Tu>hi1ta zM=X}Gq(Y@it7NWONzZ;rmPBvo`OP^*tfPraak5JRKKWiv9A5;#{^T$Pf7#w-D^ye6M2>QC2$NX{q^^YT1fkPAv$`fs14b{0fBzGpzMP%ITEc8XB|Lj`%6;x zQyu*c)(GDl9+9c^`13FE<6zw25;gTF?XRsBX@<-ii?yUQ*3;EV9VEUJW<0F( zn#&So#m%$yDrUiDdTfG!XYR3E$}_Q-(q6`?Vt7P<=3IYD3^GjONO1hyYPzGG^K60> z^Yv(tqSHLms4`^AmkU2oc6K+Z6?(K&R?>!Qs`3{8VfRetg-F=*yZPDv;xSq3!Umtv zjElpxV*|{>e^0aFE&7od=U`bhF*GeUudrr%InaiCi2a9YpsObi1f=!xTb)r+1S#gX z*Us|D45pvl=CjtC#G_getRt#9KiZDEm9(ml9fg^UYgYH)EGqKn9oc1|!~1IwAp9m^M5|$8f(WnaZhEa^a~Jl8oH%rXt-hcduE)R(qr=?^hex!l|D>D6MZe zO4Y8EX#Y7ALF3^RnuaT|p7!KL^LY#)=DG^-wd?on6uo16-~O`8_pZ=u|3ak-<`^%S z5u~1%FCPM-BAC~M0j&?DV)3{x`WtXr<@dZx%utM)qo$fmxwT#FHEZ;3atx6T%BhcH z-hW-{W5AxDD#n_xAW#*%9OQl;R{0Y96_?agGylgdg5lavg0r?g=(k4#N}G|0=}I}v3ar1{&=a-n0U;j z)B3%=vdIFPFdWYKCR6R&u-8XK;4q`}-6TT7$e3Qg$M`(0Hi@irJtRr|Yulce!J}+> z2*p}s0An3&%s@>`;Knc|lqVD=lF?Hmxl|lH{-vJb#4McN^1dl4yjH~rnjl+Hi&1bN zZFRslrz5{A&4-$8O&zmQWJbup8dL83SZ*-D>#oYa*bvup>s+(*# zB_LgQ1bA(GLkr{SLNW*mxB#Dvu^ z_1X+J?`?-I=iLyE=}-%Qxg3Ab)NEfdjbIt%gvQn8dqRiBCzLQGTgvi<7kP>!5ee0_ zXxFKv#EM$T`i#+RO0E#{Buj(QW04}+ zmOpc2+DxW>bvjE701B~R7aWf%FBLtTY14R$zwYuNjS8sJ{qhmt#k*;kPi}&A;8SbKdoA01>FTSU-COjDRx81$P zLn8LFVNZ8aXJRNwR8?{VqqGkD?}MNOK z*37p0--+^bK=fM2zbvLSDa7Ep|I>kQ@jlvgPyJFB^55oc2CBpx&5|nSg&NYU?+(ZZ z;ez#*(h|m>D+|Y{aq7@ZV99@@aF*Asy{^N4?C^~g`4u34oxy4*#jS+sXSV-%G~~Cw z^|wUwH!RB*H{Ab%nXlVas2zrNL`Qk6PuOv*8=c|u&;vU*O!U{5&fKaf^5wb_7&J^0 z=S%9299tm!tYy%!D`!dlZ8q>aK{z6O_~tvqVu~&wcA1JhkdUUq)^m{I9)@J%h;e(`}kQepse4abUeoE0?g+<{SOR{YP0YN=Q;pc*<&>|YAox`ZC z3EKr5HVk(pL@{ZUH2+^Pr<{v$lv~?Vms5Db0KP@ccWFM%U}8nyWlNqV%oxSj{v9)?Qd!749N98d9op3P77tkj^U>8&n9#sa{*dLURT~}C9FI$q)TL)g zT*}#>5aDBDDc7)!#G`Nj0*XJXSaHZ~uCrTDomUTu8Ps@;ry8?lJ)sCfh8Z?^O@#As z6R8q{Aj46{fBKddfW{e;Wm}!EVX=Df`rL(mm6NQhIe=VL`l0338DMHN50>cF@@SW7 z$$l_i|1+Prs+-q~BD;O_VduO~T0mI0cz3)^a}{2*|A5e*aYMB{M2OkDJD|znJ8TB0 z4|7=LF$a?!36tu$B64R~Yq*x@EF$3HaqDqNS{Nc<+3){b3b~?}3r5yrb?&{QFBZpL z8KqdY7F)QR13m|nh!i^>GMF^M#@bb>GozsOPOcgbL?lJ0_!aY<;LWo-pP1KH~9$H)Na%P4|sKJ+D_$C2?}cCkOX;@C*A^2o<5Sw#sJQT)-KoS^ESG48`*Q1%Ebb@ z6WPlReo2ROIkI?VmAH0F^+wf9q_gc;)8$oXewP^>qK0RQxji@^1LQPIZV|J?(D&TF zEqHfF=d zPGj4AC)fS_->>uG{LMbG_gV+mvC+vRxib_CrNkXwK?x8+ICDAs4ccp!GFi=>R2o9JaiA%*A_I-<#|~gSDbs;%M@@$|uhv*Jh8T!**bfF&&V##~U;H z-gcXWZ@3W^p^;*64N^N3+->Dc-Z~bi^N8pyXOD$sV6z7d!GXOdW-_wDu<&OH7V_I0 z{DfMd{rzWJlGXexru8Ceimv2@*%K}{E?oi=RQ3R~ramx%aeO%0Trsy#;O#N#Ik#qP>q=0}8IX$i&#O@PEV{XG@QO6WZ^fm4MI=!1YaIRW2p3B$k zbJ2fG;JO~SqvvY0*$Ac`u}}L)TlMO6d7u-bu;_I772T(n8_Z;(OSv`)$rg?k8*LY9 zjTdYg_9qbv7Kn@or5CR@G}{8yjY8Er|M@4Xrc@^x!bDIue1k#WJtf68taQkLxiYGG zY>8!Y-JetB1G^8hN+2oge|Ne=_iGOz9}JBvckES4SZK%{gmmqrU(GKGdg&h&*M;PC;-mZp0Vch$qzF2R6Fp>uV5*}|gWk&p?r>Qzdh z^;LqR^wgTI=WX*9H^KoBVAMz?0>L7pAzpggi&f%|^-OMugyi?Jn11+qCS4wvP&LY2 zq270!VxKsIAGG~`HP5c!`it$jIufnw%ibUpqkM=~OS9bWaLU-BG^5R23k`KqVipoXVV&o+H z3F=FIqx~dfClBv+SVzLtE8Mt#k3>zPVo(Hl0#$ZUj4NF67SQ1O{+`Of;NVE;2@RF){el&}1sx~ZtY$tP6tL+jq7`AX{U5(8=xX{vX z)tW~GkMW0Q-91R_btfdf4*zswKF^-m@ukiS!FniNrrRf-#N%!ZDi4?7{Ogz@(2#Rnq)%ej zCL|4?z62F70*WuNp;h5BM|w2)UhGJ4O|Eu43UHDMJl9BK^(A2+^+dxRj0pCb2Ok+# z1AWaD(A&poGKv2LR*v{bc)=n3sOjl5uo-kraUc?dZc`!A03oKtfJB*8T9%iDI}{gM z`maKL>Z}Q9mXuBB5Yozipt>Lm3Bt=y z3UX1f%oA#6&MNIPD+(6-SC`f8;fy;QDr5#s4@9;=k#ezw8YmveoEU(T`5U}`>t)wv z9}>_)2+~G{u0>?{jGMsVFQ>YKpvsf;xdj8TV$Kc?cN=@Nt^+TpTWZW5*nqG zQc0-z@n8#icl;}oQMYq2O=cMa6htZDG%h!JDfajcd5=157&^XC7AL?&17bgs$TLG& zOhQ6}m#tvpM8xZ~RoQ;)Z7DVzgP_!FNqzA{M>3F^s<%VouH)=+e1Q{#7D zW|S&;XRrb>-LN#&t6l3VhCK-C2URD=WAO|J+~ zi$Ss08slHM09NzuM9p@qDaV{Sl$--tZTCTHESNdc$iqToYH`KLdJ8iS77j}3c_+&b zip08T^CxAj1)Z-e8tv4868jyq<+A#!Lv7p)G7%yyl2hvxnEC)?lJzFa41`@NMQO(o zWIo$W*d=(t?n^%mwb<$GQuGAJ$#*3j?@HDB4P7l*#F8k5>O!=kP88eQ{fW(-I`CSV zs9R&WWhO!5B3T>-m&vnVs)84>TGl-lm&aCvrJ9ZPu-A`aBR@$t6W-wDQ z+AY`Ag99XGiFIG`_{Ji*l)a2-05r&Bd8gohK=n41fmuKTC@1|#=h13eO#?zb@~DVo zEhvE=B3#a3zCyYG*vlEB81&^Rop7FkglUv&<-KZET6SMN#txd?CC?#(+*D>Ys=4{+ zKT;X^7{S>hDFO|NXBwHrZUkK4U*(H0^VUC@+9yvqq6z~CcW(I?|58Nw-6#7IMDz$i z0(YSaTR{2N-~gV0b4c;$wuW2H^G!7WdR{#Fx94Z)3;lT=C}`9_R$!qnF+T<=N&Y!h zLpxfit$}*wI)e^lYH+2O0K>m2|MrhCB(2o{iuiZpiJ3A$J^c=X@V%y|O5Otd`oPG) zFneY2Q2_Hm!mQ5cbd0ap=^BloLp5mE*@le@s`>#X-0nr+*iZoxrojE8U#H8=5MaNN zQNbWUqZNhpJ^z9JK}n-+{*Dn1{cR8~V##w9RRf0JNu+GqM@oDt({Db-Re{IUJSL2O zeP3pGalhy%F~55N81np8yoRn((Djq-M4_CYzkqPko`1>MeBkl6hT zUB_sm&BX#c;_XUGVwL|A7{B_fZgxl=Oh@KViS&?*Nz3#0axyNTY465{AZN}vusEde z-wo5`jI7?~zZW5le?6h?ix3XQ+MRz0hi7JN0xVNp}k zU`Dw=%x<@mqNjaSF{5k32hCf!fyA;LY13woJxio>SV^t`PlyjH5V8D6_gX2KRQnsCud)u20B|)0 z4}5!m%A(&y007l*&4ug16c>3Y85%Z5zl3C%;9y*HJ^IP zPy|?$6@sHmf}^(mgy1fy5@7@OfEgNpn;oeeN}RQW0^VB)*AE+#9jDa}AMMw=%1jBJ z{Ucs)O;pJKML63_E|AXdO-5IE%pUV)6Kbc8W|cFv+2Y07Zfc@lFf=rQrl!#%&M9}r zwzI-4P(t-$I zIhktrdh9YMX*K8h1izg0>JfV%Ok|8tEbjZ^yldE~;Mn*acgb}`ANmF=F5-@)=i8e6 zRCP@#Pen)Y@y)(B3hfs%eXdepb{KD3EYkaZRCjV#W!1C;l zlij+dPLeZ)0L26dK9T4E8R+|ZqzxU8f2UH@X#v2dwypI$pwel+r{@1g8&yRET?82D z1wfvPvZAmhWYj8*0}U0&WWXZ)G$=s>A7a&i>J%w&3RQJ>3WyM>=*K&C(2zcT#eUhn z{fG{6!JB*?=X@60C9WiD(mUL}x`-X0>NoAY4x9>gbqWl(z@}Fke_>=51dASudSKC5 z^|8TJ8ls!kT_c)dt2!E%sC)W+@4(oT#=(y<}Ck1r#aQ0Ig_g)jy^ z6rvo9A3?DK17xy9H2nzLJpA#2L%UJH4RM85kOn$RxNCL&)F4oqQ9pb0C`UB@m!Gh3 zySf%%QW*uqe1vSH50#X`*vAnee@$4?`v~>v0}{n=y<^KFyF0LqW8s$TI_fQ)aGHe_ zVH$|_eC!IK<7}j->vow>U@!Hzfm*DBk36bWauzl;_Qe(2u(b3eZ6K0q-r&3VHCE|2 z$YR`N5)MF=;N$O*{H`e;e$n`tJXH23&v>JL@ff`(uF%k|FoS8~Nv_`y??0M6KJZo= zFPhXlyLTYpuEK@3I3%AYYCzF~pw+HewUqI-i6rIq<*xe97t4LQ3OH&4&56nBz=9Ay zhOeSygGdw#X2zLCKoA0*z3SCr+x$00IJ9-xHgXL*KX_tlf+4C%5j2-X}M0;>k>(Y#b};QzpivMtC@BKeq1T`uW~xPWM_%VqY}io{-?`6VaUGDX#!8T zgnrkVGy?~%Bt6?4e%+5I@#^9r_(VJ@$nYl6VXjA$yz(ND`j~4P-48}g=_7ro!r~%x z?T^tPp&oWyJXksO35E91Q6ZfcTX~QKqgXfuM=AgPr*SNr#!2eT$DUNxCVMXcO|m8k zXcr3JUVXqA6)Pww_~x5hr`I8S!ucx40G051M^c#cB?zC63pBs@mof}7t5&0P{4|jl z0|TaxFp)y%;*U3b=Pf_O@3zIQ0r`j7AstUXWQa#~gGi8WY2uAk_{WQ#xBvFWg&_Cn zHN{On{SW5AR{iz_Md+ema{>NadhcHbmY5T^zLmC7e+)F>NJ=}rsAX_VosPH!)w-~`#gWW zh6iFZ)g&78lm6F7kkOAzKJ>}BxAI1&=KAb;VxIuT^*3mOpb@>(-A{Qxjh_@a@p?^; zqZYR(KLU39gycSk=ShuafSXS{cbxFiU}P7A!dZV{@LL51>qCh=95#Q`;7&6*b%|>R zbV~{PzOdM79Zkgy@?i{AK@go5rwgXm>O{DoEAYM2#J0O483S0@P-`Oua{PI`6M}&2 zlW|h98tZJ&2SK~9Z5O%8=b;>9^Tb>mJj>oj|2PrRjYg3#M<&ur3J@tS>^o`PWyPXT zglOjYP#+1K7n96P4(Ca~9o;ZZHO|ASXqDcX@9Q#@xRR=tGxn~Lr{^NT%D@?70npdd z(b;m-sKyJMKur_@Yuwo?nmLn*G~|{Atm@hoG27jWUxF7a}V3>oOLjp}s!AlC+4RAh*O707>9c5XuIl zao7S!5?k85jIgjhcTEq7iHZCETb+og9}#D$nc`MGd?_|=q~FmEg`QI3SN5+|vm-_~ zUX0#Nm0$U3nLE(%^TL=%-N(ZqQ37Yc!H79dhHp;M%6;*d_N)4m7(4qn^m`yAOHwo$ zp}m^#=w4}(wFmtcC|1Wt5*ixpOnE?j?E28agmJWSgVzD+MObP58wV=;VF5Xj8!|QV z`$2x;Ycq&l@XGj8w_aZ1m+tmT$y--g1o|ZP#U#%=%vQON7wEEhJ>m-)`RQlcd@$Y4 zGNsPGDww>Wt&({ws*6OIn6X#Yaet6AQehbzzNtyRHb3Mb8cf;qgM_b=e zaJ%_^pJT$q*8iYx^r-}EV#6!ao?N7bfe@U4|ll{M&0i7&{8+jZsBQ==~usNImlM-U-CE&S2mX_j+B6VEW$>q zXvQUDwV$!b1*>E0X;7H4$MP=P?ymRh`?D<51-U*HaPDC%>j4EsCf#uhV`mTLLi&9S zmTBvCFn{YhTEn{02MzyX))_khw;C;@sq=lyLMk!&T1 z7{>NAnU74D8QsdmI0o(E7cmX8AOm6yxX;x$?!4!RhrMp5(?*>cKAz2FLs>psY*y?AQ!W8~>{as1|KN zOdH!F2%&oxR-)hheM9lFmfNAA65Ue0tOMvFjsEtzSzzu-h){jShf8c9iwxpJ1}MjV zk9Sg#Lz2~i4fhUYxgV3>F~8(8dfSQ0rv3`X!Juy!Mv zybG~3kY$d4x}P;!GjNtWUYpZ8u!OJ32VMSpMbg5*LzqfYue`9hWmfe|v6c!90hrVQ zv!%?aCkVrDC%D)FM>R9M<_?dQKJm=_E3@}3zAo{zCXML!SfwsG2Dd%%2X$w0{Ka5e zqOqdX{xF0mJjVE0wp4{`x&1msCcHS5*3it@N@&f!$n$X_E}*Z3I% z=tcs{J$?u9`6`_JANK0^ZRm(5Lpc!8J5T2?e@-LdY?9wd-Xwe;atqge6lQ+ESy&F8 zLV(Nt$8&*$zUINTV~HOi&&RZ9#J>PSh03+Cpb9O9LC? zvbp2pIbd&o+y~esMLgmR98m_Fc5O;{N)-tuGLf+XLgR4=oIQ|4#YTZ>*^ z^QXlBcHagPf14!Jp!vVcbF0MeIw=OyC+3qO>ujugApVPU3IvoGfv#p7f*0LNh7{I> zWlik3Zbsw`HV^n44UNQ$OARF{xA8;^|NpcA0P!F1*_LZ1UF`1L#Br1i8d3S>ABokU zG#;UC$yvU-SU{5GiomEcnILue1ToJqYd7@PqbY}f+|ZCEEuTD|l5y}Fk8ue553fMz zEKNtBdo?D;X8<=XR&dHVA4bc&Uvtlra` z_UEnQV+<%g1vkm6UeFOQ9rMP^mU1e3x>ouPed@C>O8 z#SK0D#~O}3l{eDRpp?&oxqmY1;s=2fU&;f{9`?IAVZ{yBh@|RzXs$X~c9ebHmu%jq zA*W8at-m?$+>f*2+4?Rk|8V^wuF)6A-25@HH`A6q_HE+4Wi(w|E>=fkqb1g zg`5tgh{c0C?^mlHnkcH&{v-8CPl1(1F_MSy_Gq9fO~;C4M-t1sVEc+3Om3P^;T=V_ zIo+`6{Cc-|Uc5=PwZ1>Hu%Iz}Ld%08D-WXqC<9bdRJ1Ppyxklj<+F*!FsPtrcWKfx z*zwTFjA=m7G5t5T!C^SyME0+O-XADMM{K@>I-)fT*4hrt@>lTN=g-#)w4rz3AtLOG zjgsbX*(dODFxpkL1j200vf*q(YhfL$N|91@y3VQcyxwgqEvx2%sij>(q~X-SN8qBw zrI*+(*X?Mz#nI+RBx@G@r&NH3R$oh@9Vd;hv%b%7={qy`{~*%w-Ow**Yb0EO8C~`D zdBC5HtIg0*)@b--UG+`gn7^mXjnM#z(dyiePeMK_XV#3h zyu^HxU&vx|4YfSSQ^Qa=7AgTSJ8i2_bhLWGsBCyh3XPH4rvgwZ!IM(3?-Wl6>LFSZ z;L`u3(=mH1wsM5-vKbH1l18mI8};DARzflXx?9sHIFDb}yRt_&wDzio=sv$u@w6aB zd_rM1bI9X62wAy%c=Sb7G+C?Nkwo!gXx2xLESA}HN|3``Cw$)fPG@A!stWr0K)Rb` z{bG$2AU5V{P=Pz#C}_VqS@J0!GamEU-T8p}gw`(Nb@z`V`4CEi8(cI2DoyHIUa42_ zRt6lC zL4Hb!E*M+m1Sj1~CBQZ{Kk)NP+I~Q<AR1%E| z3c4F@D4=%xj4HPu6dcnr5D-1K?XQ)QQinNZ@GB$o^Cc|eol&Rqc50xT(SpLSH=+wI zR3iEcHM{CSUvfpM#}6jUY- zN00Bx%^Ru#DC(?F!AT?c(F5ZKVIiel;q+t|UORU*Az2u(=Cq?y)8SJ8+#}+tzDYJ) z;S9Zbt}xTQc_CbOYxJ>vj3!;Xc7JZx|LvJ(mw~(}nV8&Z4;Kfrp!WQ#o;px6ZWi{9 zW7y>=D{gogvV8`3aapa}KgY~5|0feAXfcHVkQ@L!p~%^iVd+6DL$dTZ%c7wCgb)dq zd1;F2#q01d7=K6RA#6Q5bNYTQc}0#P8=(A^xQ;}c+(==EzOf2sF0A0cYoHE;q0Z@^ z!9{EJ30#86zeIC|%&~02KynrEP!^NXkm2v&%$coz*&Q&0N%ajrkk?}E??~6Kge@~C zmJCAyIg@|h`r_Bf(sJ7j;ve}9)^*G$*Y28!RzfNj0tV2c4^grs}?GD3nUhE@`LY`dgbQo2Cf<_)ImlQ<$D zj+L$tdZy6o6=R;IQ45qx-dA4XE6egC*-v+16R(7x#?NnZihAr6PR9M@{=9EtOY-<3 zJQ3~xaH8=&h^iu&9J$t9rT}O$1G&e|OAP3E`+eEP2?uJ5byLNhfZyb&Qf{eP-Op=v zxQdROy9S8sWolSh{$!b{)!EllI+p|n(U~LJtz9E@1O?n)Ik;}^G-_NWwgzlUT6hjX zc0SXp%Z|Cl?=8!!s~k0JreCjpVKCdvgW?0=qWvzWVF0=Me+eYDI7k-{lj0;vf3%no5V19QiC3&kbr>kX3N;ZQEdy8hEq~4rN<1UhE`F}cZ#h$JMSv0l#R#Djwq_*$EbLd zovm;`(+S{(uv)Ha=B9Tq5_mgMEx^QlA)#)qIv7O|b8b#%3t$el4|ZyE50S#>VE_Fb%Is z?g{vzSKjRUeCuXCZ-mt0=R#W@jE(F55N|IMa;X6KLMubB`S?4FVFarW(vE+6QE9DWx$=9EnQ2uK|vioct=D6dP& zW@*$+c!hlNO@q;*dOLgRU2R1uN&umZ;pP1j=mc5-HEhDvH$ETqW?Q03a_42kT7WaF z3wdE0{ItD`M>{tWp8@BPbwr9ag&IHwbMq_JI)Y7#4Q?ppOG9#Pe!kn|voYvRZgV;K z8}Oz%SlE^{6dx3{HpzrKVqBtxANx z>ywpnyuzNhO2L4THV&+%UV<3|E8H;g>}J;rndDPCc|4BJMMTcT!%Im_WCVypAh88* zW#!e$o4mb^dC5d&^c~e%^2e6WEAV9iIyo(AFhV*r^wLHUJPT-0kf`m853WI$OeT62 zvSL!a#%Vei$MXqDN+Gq~O~p06HM%S{(!TNtmJIZbM4d!dL7~f4MKT zW-KZQ#8?6VnIJLtKhR^{RWt{B!=IeCWzV$@do!kFumAoB8`lK`aK17=M}+JqvE7A$ zc?20t|K_yAU+*@}-!ohx!UK@mw6?5~y$rmc_55F_B)dx-^OcAEYlu$Qd3@M?jxo)F zUREtF@j-`*TD?4(Ym!riDG|!hJM~b=@*l42;4Mpz9*KBVR=Nx{LAyo^nyzd5Fmdh$G%(q)p5Z z!)-mPL%8o}qYo5+^4NwMlJEqDR0uJ&Vg`o=ukr z`Tz+OsG9;CMqDV5u&c~;u6yPfAr*{vuRgLE&Lk!0Qv=S<2!e!EnPri=X? zvaG&yKdur#IA>8SF9eC!uYS=ETf>ABZSzCdZ7S(VqgHAQrZxhXZY{=ndR`RWZz8G; zFEBPke#eKhQ8l7U-}_otR--jJsRI}JS=rcX{;H!OWR5-GS9f7Hm{Ko_m}Y{#ICcW6 zk(ol7J+X|DC=xmPlyt<8C#VzOwcSR9nwGYHHksI<6FuDna(SM}aqJa{KjM)6e&=%5 zAR6j9w{BXBDq!0sB?nbawxauru7h$AFT-Jbu3|27GTIzepsho8J5& zlHfQlofgcGE@}PlppA9agl`4ffnfi5CJyyomO67Px3F3#R39B3tVhRz5MJ^sjX(d_ zjHj4Quo7wy(Xo-HR((;4TJmVR{mak$enLX%ac+9;$GwzRO_+c3!88VWhd-#)v+d;l z*5AKm;lwR?`H%PPX?FGu97Ia?2muUnCUbW~{8A#9#U6!s*|VPSZb}=}XHON_(&~p@ zh%2irG0Lt$9HGSopO#FEDX!fruDmAWn*@&^fF=Iz7OQk<(vTC~gpO(!;o9%{5igX` zM^#Qq3yl3W1oo+z#2!(=H^z&@wuY6DFrL)$dEu9 zsY2PX*?*!wxUhfOSWnGK@FOe{A^++V-jl!S)`EUC^Lu$dD*Y~E1dLo$-T-OZAA{<= zkH^SnW05aSFCRTGpphtW-PpL`e=+;dRFm-m|X)=h3#mkClpvV05CgyXTJ={QUc z5Gb+R?dY3^i7f;5;$B0q1dmV(B_FwGBxB^|2p`QR6q?xgcMf9I7$T19q77q-Yfy#n zVT&@YM2g8Av*J`x7b(F?edOu<-fqI|*2Qdj(9MEVrL=ck!J1`Ku}ufVFOY2h3^4e*dh(K^@^~Pj8dvhdd%`Y}Svh z(_v6k*IEm(x}jvyREg{kot9c8T2l#RPv;vkPk-tK^R8K?=fByp-|Ga;6qPAge777F zabEEO89#N>sB<;S>9^5?y*5+V4>NQt&bpvduB<2Mt>$XK0aXc(_?ZHzm-wI%hNt1}AaA9W5y;wokoCX5$6lCZ__9=iGF*UwAm| znv*`6_9w|@tm7pBxREgX-8rw4?Kpp>!NbP3P7{O;;dC*~-QjB%w_hb$JHFMoPTm=V z3RGE;{7O#Kzq|ihk5DHO4v*cGPOrl~{g_jKXl(kEz6R_f&sU^pncyS%FqJfcTA-Vt zmBY4KS(rlO8-wn@n^oQY_ks2Z#FwLe!;1#zMG2+-a*U*DAuk|}td^4v=Qx8B5~Nz0 zgMq=Dct)1?>$(=2a6pQ7&%xT#3VR~1^yiOK3Wduc3fGKkV^)Z#g-H+RIF{X!O zvj40ynm!&S8|%*q(CFo|0vP#*Wr=S|Rr7Kw>hEmpJNkJ&S573%0RN%ug4 zjns=V2>Rn%Dh0jb-6nEhf;_E!KmRzN8TWGmaTBWZLXbCqcE!WrxKv}3EKf{;ZwEDY zG=$~!@t?gl#T={9i+dd_UwuLz>qDqk&zIZ>3jw8%=MZGvIt?}v(<32T!<*}XbUFyI zz%A)oB~*kY;lp%>jFT#0u$eV?PA;qEJfrz494$b`-*D5ha`qc1m1}aSpO()P`zkobTVmnFhIc=gWB5Z?fxr0Z=;s2)zmGBz1@!;FHj)}3cRPA7-BDv`yR+GPqYWlLZZ*vMjlfYav< z!{=IM#Lc~PVEUEhh?RD!#Fh~V7Y6Qk^8+7bo1o!|Na9hvLKTU!sw}O!aV{6F`l|F$gjLv-}2rL~A>8I;BaIM-rkF$*w$3B$ZsFB~|n9 ztL1FSFIU{s!O3lNyNoXzT`t)tWQG)|+;7geKsz0b0mEXJ_?(xEF*O>ouO6AxJmW>1hStFPlODsIp+v z)X)o(Puq&eiBr4Z*W}OGib6C4<&!v@JFXcPt_oU?WS0q1oOn-kRn16S0@I~7$;bM5 zHOG24NT??zPfunB{mvz3)z`+Z`o4Zq&;KNrmKC>sGNZ}u4cx)7Do4653?w#dRH-`m zk)Aa$GDgh#ZrCI1V^EMH6acs}`0Awn*{^^6v@26_1tQhInQziT_=3|{(#7l=B2@a; z_oJgUGFvUMs<7RRNrX1re2ZGArGMg>m_8vcHgPV&i8pFeH=4-cn;#HJI`!Y#8ja_w zbqnXfMD@Tg;uA_<2FZuEZ{mvL$aQ z1~m}+na{Mge<46=QhZoHy5GC@IT%Y_b~JrL?%WT^3(uIvK@&~P6MO>PX-%*Ub7P+xPQ*&2=T zRF;VMD<^~(`#p79+hHAfGYkF_lZ&%xI*hMueE8D|_N5g1OU+d0m0GuSjJ}P+xaP`Z zVeX+>Rmn`nznjK0F&GXJf27#&mY9$cmR40h+H(N&OYVSs&92mqi9?ZeD6*JtyLnEz z^yKA-@F73oo^h)(Oe`M;)M^FY67&*m4+KrE%Cj2t@CAhOKUl=wTBCnWo<9XAG6|$^ z_O*@ch;I&FX1>E=L_tD$-Ar&<&TI$L+w9#<&Kti61FUCzukfS_qiN-U!R)gMz0qyN z!4Q7m1qv>VLS9WRRgu;`nIzN7?fbbmEEu*DA3Q5?(sH~Q{pxGN+ilJhzHZ8LmKftb zyV4&;maZ=>!3i+td=(y5R+UHk{ue>E5n~9UT8*D4UV}VqQvg#FkQBg=Gg_dmK|()Y zd_kEd@B+xD0~e#EyHqNC7E&XTVu3*8k?GV6SIXkDgGULHnFfVaf20H&BWGTV1Q0DD zK+1d?7|gB#6y@OU-3J@p+ zT>8+cK~=dOkb7Rdg&-|~Jcs3okL%;=pW7QI%{BtRvD-I#yM9b&#I#^=1Sr?xyFQhF zu)C^_qHeZm&^3keM(_xsIsmv`^ZnzX(#B*DU+I}xP$?F0?tmVQ^ z1Yv^sCj!|+k+?jz0!X-9qIRp{NsSwt!Ny)jIwz}KiAw3ocgJTxrVib>f+D`;e#!pU zBUJ$21E2xOf>ft`BkOz%8vBO;V&&bI=s{U!IY9T z`@0;30hfKed2r8HV{s z$V4oo*eyw?L1ZQ=cOyiz)E=MR8ZIfTkkualuBu;J4^ml!Q047Jh=^Kr0KKcmyV+^=U)r{pM{U|#@QaHeK6WkL=xD(aE{7;V*q zhXyvf-dcH}#a*Urf~&v~zi13{@3cU|N%^uU9S<&4yECl`N82eXE!O`)qC??< z(?^;1=aN88UT8{r{n-tQ!lp1j=_S`f6p@v_FRiY!_pv z>7P?$9^jx8Y+XkYDQMckfuVcGAnZZ8niEYIS8~pQ&}L+EOr3)c9DdVn9uW~6ReJ3H z1mwUHhYk+Wu6B2tD^_H812OUI-r7YrQ`E-`UxRqv^B9GSC-W!&lMeCwxR&`t94My~ z!x_gaYn+@ds79Z66<699L;BlA1@T=0lK2xwrV`UY1`lgUfW&b+R;qd-8H#=9Wg>h- zT!9b?JOVKei{k-F5rH;1aulBocN<0tVC*b0VkWAm^U?-0*e4* zp;2TReb=}IB0pI+F!8r#{~0ZyVIRxS%#d!IUVNia(IS_OE2^kK{qH;qa$S?vQ-`mv zSNC3vtn*BKnxn>Bc7I3W^^%=Y$;)|Z;)zG@? z>E#>=YBANTsAi%W$hDymE~?@3*tC(pTAj*WJ7)GzlAe7HQ;Kbed-YuAyvpdT2e~A# zEJi#@eHc{X%B4=I^=Kl;H1tFj`A_ssO*?CKI4BOXKxpN*_0ORadYd$58WI5yTH8UH zNQoV{ZvWq(2%bA2(Z17hQ(Td_F2gWl^{_W&aVw$_p<*;zdCj}9nQv)9{?o+$50xe= zC;N&%_Pdlpr9>Z9HFunvI>@=-nv?uiM1n1rV9uly863%=IhMGhToA4v9g3@uGk6 zxvL>mdqh-tfE~?!?$RrTtVgsxp8(N?EbOtasDb_wP=bLzc6VR@Aj7;;^p>=4f<)6J=Nw~xvtI5vosJ@Bd%w$NYY*8jRWNgDC=`m9bIpI_Qtr~aHq@WL1I3yU5 zt`<;2jXA>s(C*c1l|cW0S^)8Ps+m}D#1e^h%;RMTj61y6%;&Do&=n7TNsuYO1f&*H zDnCD|bcw&)tT_~P3E&SId#u>we-Gx_N}FNv24=u?*pS=X za7C1&i5{rdKj4b;LXT#c@0=SId^ufLzWw(j`Xq@515f=5K?G9`t^j1e-=A-c9-AMm zY+j(HRbOZv8Sz|gvJ!E_m&5w_^Zz%w_#CJ|uhRZ`OY(gUFiCMAyC!dPzEk!-ev*3j z7?nDn55NGK0J5#Q#zAP*0Jaak_tzeDvfC_}i)!9%Sd4;thXa{U+0u{~q~ltLM?46B zA5_$*gR{rouF*knBspR+B}$?Hj{*Xl`!1DH7` zPR&WK%rhhrmL0l&ryUNu86qiRiI0D<2c;!hnwFHG6gW*CXC)?*ipW;yzTUwOLdVZ! zMubiPa)4K7tBZ;zq##U;+K8mKWp|G@V&XlvH#+8@GTM7fpiwpaC9^VRGI|fL)z>tg z7Pv);6>K4eGSG9-$^>qO-aQkbvD>%? z+|5wXD&@+P9H^rL38lTe8ky}$h!k@^kf7F7n9R|;|Oy=UY>vY;`N!P4~>{_ zHwS{#BIQ671pmE{WuGfb1v(N{n6JIXBG78<}yY-gN{e z)K_b1aiCaaF#lwTfN)oKV*^{(6;D9G9}`vScFpsD=k8|jx~H<(4-Kl!h2J+A4yOi$ ze2QlsH5fu@iZI>nLMX(11&tOCmy2bSYoJi=VSJ>}1r5$fZxF?>Kb2F%ftZC4`SVBJ zw{!A9;4C0)t*0M7GdR?;vIb=Aknc5CjN`mFi48R*vEO7-`vZ+d3^Aj#LBJVp&H)nq zZP^d&yO4XPSI)4Otvl`KX9r2$dH@RRultmsX(ozN?%~F$l7oi59 zoZEBge^3D|tG{_@{h28%c56E6jI*M!=dx_iA^E{ck0qWO)XBr1gUxV@Lr1zEx<7$Zz)3`y9t6O|=P(eC z{Z>=b&5vcTm37&x5jf&fstggi=UFJC%V_mXAyCg{jW18SVF+ta2~Bpt@}+-J;F%Oc z*xNfS_f!--Vn~Sbf2O2Z<91Wv2xD)-PgFc9vJjZ4wHaZ1iFTPPFk^5Iu~$QvoS&`Z z1eIfYWwl9Pr;t1A~M@Q@QYd?6h5x zF(41k{5<*Ux*JY+J5>L0)W*uv86b@+oX$(ETC5LWUXRcIO#v$xqd`DZUcO=uB$*C< zh6S)#PeibQ3x(kUg8ev{07;ooT3}*-`g@-}Fq=lG_a8IWHSj%c^)ZY?9b4c5H|n%t zpsrrpiFBt8*OUhNs2MY;)ovw}#nH+-mZC$!UP`w4tSL>G&tv9t=Bs7NiGuUhlDGr% zN1#4YL+ZxzBiqL*o#y#8Y&wxzyGo8S3TQlwC)kJ#7|@d96=8Vu{l0tmRCgVH-kNU( zRj_}wG7FF-u^rG%-fXj|3m9Pso!WU)0AZjyR08+qsP=}12>EYg4Hbz%XrbMw29_K! zp68v5+u`Pp*QFfOPAMbdK7x8n-4>dfcmdr%x#wQeMxgxTz=PLigSM0eJ^1L-PW9P= zO)W4m$N*Sf+^XE3*Z`-~cgy!6Mnv#Kf3X#Ks4U%i!1Eir*zZ?UI-ErlIr{H5q~H}G zah=lZ_Squ2Y#F#2#0IsJ7-r@B{SRi4$}HAxDWTKO>w&x3vLnmP9e|<^p{)EG)m$%Y zApSwKBN2dhy7TdVwRwBm_)%by_hjI`f7ETWIE?l@RRx-1(6uxkdCZw1g0(zG@h_4? zb$}Gx4dv5D7XS5m2kUsogS`63KI7x}j(#v;7ql%l%D>vvMThzz%qM6#{j;!4fNCe`6zkCO0LuK%r?^OR@*Uq{O1pzk* zF5oLTLA}59B63;uGjp@mKQ*bSle&+KE;ftDtjhj8^_K{*5ZH)*FHPc100<>{To4vr$XiaeI5_7J1QTO7Tk_ z)ASa%<=!y1`*VB8-{yYK?V3)H^T(Ys{CB(1XVgyD%hYu4*Gy1UJ%jp>nkl`V1H*kBJef`&4$a=*fU@|jk?r)jF-PwuFEYgwD z9HSCyI#b`faoiW2hr!`*JmnSuSbQDu^#MOhig5@CVHUs1*Z8BqrK_%|k0iE*uWF;z zv@}AcAWhYMrLaPSZyhTysQGMHk+s)~6sOE{wXlQB`Jf^Bqn$8s6R_Lml-gQE>~nnU zW=@LHb+23r|Ff+^DA|>K5VI~M5UU>j4`_lFL1oPpN@q2~ch=elq5U5H>^ji4cc9cO z(npuwwmc^GBcPLSy8N<6F2@zX@@rNWI{28s>QO5}O@FU6BY6@aa=X6hqpc2nJJznF z)K|)gr{eHuiJFJK-`(z^6(TsGe;g3<-NpCt^Nh;&1Pw~W~)nnqgi_8LMOM2jyTJ2F*P!!TBs{p+(iS$EMGGC159=I(8Fup5dpe=ivJPi24hL zI=ZH57{%Qkf^1xa6WraM;O_43?jBr%LvVrzcPChIcYs8!b>^!le`J4S5g9X-nvP!3)BK6DhD%CVU?mty1gcXYC zUto}N<-N_)d-N*ONwK3mPA3Sn?6ia=;3?OvqkQ4O`tUqQ1UYK}?-is4BOTTA25*DW zdbZK-6!&-B_K*>RvGZ^`ivJ>HzpA|f8ub_of_zZ8ma&9&O(-LyjD1hk8dNb~{YwLq zg)NaLS0tC~O)t+Hgri-uAk^#-b?BQXXH>81P*yvM zyCFYAvGeFCGo=@%&Jm{F7+=SZmc>I>(6{o-1p4E<+rFO1(6AL^L|wtc7VE2vgRRlD z$9EeJSpg=qa9U`>Ykxoz%{n6;0Xt0n zz2|`b*MuEv`8CT@L}FLNFubS&oS4OvX3H`kPd^gbK^~u2Xg)p3sS`~E;I^}=Q_TnG zhMmsdfUL`x_IDD1DX;gFb;()=MWNL@6(Bz6@&;uF85P3ux*Om!j_7u~hgqrG*CeJD zPVpCgcL7|?UPLBS>4M8l+I|CY#P!~AaQwA}LFBadpeo zK}^&5A-MU}^3tdOI#`5BbRn7rHoqT6{B7WdZcC}4koj!Qh0~@9=38+@G-YdjUHgzk zsX~VRyeL`qgst7$@4FHE*v|>Gmvg#;AHHz7Iuef6*~qpx1>fnDeC&jal+KF|wLJ=9 ztwrS%16JScgQXQpLqQkpngTbRbM+-cj5{5wfTIdJ-{Seb|{8;qF7sNdw{rl&Af)0+a^oR|O%cWE~ zqS^k|Iv<6-&Vm!Ll3aus?#a_TUg$cjP>nF!L1kM=omF{n1nyk@8!oGeQtAE4nW8`9 zFh2Rfeqh&#E`-ToFHhZOI|AAdeNO%SZne6NTnyAQGilv~3|9a44eU&}CyX2o- z@3C#XdAK3zu>Vu^Ut*en8S9=UMtF(XKWaOylO~b&=BB4v<^oT^OUVcd^CJp4 zvqu&!!hAN$rlt9s0-Zq-+SX9ST{<{MF9g%VLa;dJhSIqtBdZlOgN4O+Y6!xS#e6X& zJ|*7DtIk0JVSM6?2RwBO$v6GwEEL|PaHsPNF^9W~MDqiL{(k-Eq#O}*Agr|jrhUbC zq0o`zQT1&i5DW%lHL&}IKa^M42X#rToA5b=j)!uVjY(|g{l$Rhv(6PHB%C#9YVdnx z{FCJKm%ItWr-vhXNbh?(M=&w{^Yt)&Yg91l5AQ(ndT?~RUCC|CiK|T+p8CG+z*J1k4^ghas|gd2!1I@;YDn=HH3r1pckE_$h>RFc<#tmfB*;5t z%LJz|GBA0jWo)-SF7enVyIDS&uaJ9Z;w+G~n4)jOu*VOT9v=e$VdDPs*)7CHt1WD_ zq{qC`v5(;p(4yQ<*8~aQ7zF;$SFND|eH5f*4wj+j7~by?jebN*Nv|q zdK}l|YddfXkLB6D+ssd{`wzUgzu?va&e!CxQD2guMX>(!TO$XHGR1B-dRr-~%c4z6 z4=bF3njZ~Y{VVwisgFR4ud1hC10CcbOT;>BoFPKbZ)YR7y>Qq$t1*Jt_3na%Wf4BfBbv+Y zNQfhPmUI5+D@TYV)IbN$Tu}!gsq97*axiFM(z15U^5Xz7&>1Ab%LXmD3Pz)e#Ok zF{k^1Ec1ACpF-`>Q>*Ic1^$l`|fS z`0}v7gY5a9`m6^TRiyT6F4JqIqVB-R7lVeGksOI_<__)#pHiqV4t($rw4Sz1Sj=I6 zdHl6T3VaGNWuRuUDFzZAGZZ$&U@)c6A*1koZ9a))ewRPQzDR|C3f`N5QmM>B^3S9c zY+FeBuarR_HdOtR7ifaydCS0K`d?|k^$;)o=qJ!Vd4N{0%^vFtZab@2c*2V#4Z;1i zWyA|f#CQl6Lj#UgnT$IND2*GRU(FhAbm;7Kv4sFb9*aM$XNk91rVD?`zW))DJGDn)?s>dLU0$ihrxRWuSQ~__y>&O={JUs5J zl}{Hl)vNewWizbiEO3oT16~3@AM>p*GN3TIn<`TT|-=vT78A}F9IMI1?(Km0VWE8)xc_>D=@%l z3|KUNm%nQav6$2%0btES*9_G3mS90vE}0Lg?)yGe_i>W)dq@(}IU3ilnI8fSt z7fR2Jf2)dq;(Q=PG7JBiUy5%--46mxiq+-n#hebg0Kg6feAm14^x1Rwe!Q!0G#s^X z)dvGKpZ8#e@_~cIt94q9OPBm!TY0@aw@;EEo?d`D8Hf}k#>YQ)RRkLX+^$?f^=k@> z-Qx+r-0v_-#1wb6r5p2xlEvMMM-qwXOil;GhJ+@z3SJ9`ye5pndSaqeM>53G4e6;} zS|Bh%bhA4DIy@W%gPLhyV#ZPF!2%8Ywq6GFlle(#tt5}ySn&W6^8c0+bV9?o-3maN z^D(M%!2&?Uhgiv!#F5Ca0s&{Y$A8sYt{MpOBh7`AWokQ4Cr?Gs>pNOtyqx7t7JWtu zJd4Y8f}m>-5+9_|xZiFTv9@_v)MRHg;qG_1=SnZ%;`x_0{FVe@3I$0UM*vJ$IT|bh z?mb6hCB7cZ27-Mr^#NZ9!!k1>p8kZ=a=7IW1@(Sh&=K2Az|$k$osStJGD&Cd2F!If zL|O1QBQF%MR&80m8iMS{mJY3GWVBnY&l%Q!yCwwK!WG+ha$c)TBy?q$Ps-X@6)p<= z!h=(J2D*bSB*oC~eWiF~FWXDacGoLT7|ObYoF1T|hpWT#olbKrz@ih95}>{}ip4>_ zyDuIJzU$#2vY~+jtJi?+AYA}^Bi2IT0gD2#RRk^8*b>uvQWIK6Q@#M?2Vq(erG@#I z!XP;F@YWkw5v+sCKNHzGNIxgd5NxKq*lqzOxJu@j6GQq>gkBYyX!?1ygSC?X+dw2p ziF^=Gh;$vQO{1LEF^>$UB~@zuvyXrQ2JSyXKj!63nS)8m=9SSX#7}(eoin29e z*(#IV;sNNG@c5X3_vt+Q)mV{utO-rayhi}3?qrEJ6uT))rdbIu@(V|udbVS(ovAvc zAt|YBgtGB~>B>(N=-2CAQXarHN{=rfYbx(8GoJ7*azhW7N~rH!pRXi72*WNdC2BB4 zWPjKh4{0w`Wd;k|Cj%wGBQp=%P^D7%hd8)0b(rF~8arAb zJNBaO53xf2zaR~&NsDj{I|y`cRiekPw^zTLHT{d?LlA7|6|sC~SH6}6;IQf~plrj; zp!Fr~8+vmC?|&^1jVC(4GNJZdc{ALpAXn?kIUCwJyM0&i2626EciuYjUNP#C%^E|r zh_aAm?lM^7|1+OT4+8O%_uJnW1pSBf_FL6S2`(}q6+0LR>f!6qAWXCvt#sHz@2W{CvwLBqqx%S-#5KvGYYDame$QQ29 zE4vp8s42u@Pi5X}at<9Y1tgebEI#fBy5Bte6UE5U92+d2-@h)DvPU@`Ej_Xt#}3IcBij#ExsHW#y#+4!yx z_Eg$7mb+;tNFV|sKwSLMXdn=mTg;bdi;$f2Pd<~*9xqvpsYUO0RuqG!#_Mqewz;1% z%KE$f2>Om&WZ$oO4fqV4Nlef(V0Ay(8yL~lU8nRto!v4qKz{keZ0sP3P^m~FNGzmo z2%}OWL8jO$@-rXM&{4tc82zgeQuVzV;^^f&=hsCx92sTDdf8r8q`}HfD%Fm@C)4%h zLKxa!sgyjx3?+_GV!?mWvZ-gTuHjV{8j*%_ppf5(pnlU86FZ$XPYLr}R~BhczyErj^3XtA z`0Ivvv)NB`o8_ZA<&?P7>s8T*$$q}K+uHg{?eU@a9cYgkA9Ts}zhw#4n9L6e`^C`>|Gb^>#eO=$i}j9+e${)apBc4g*WeknoiESA8pK{b!opE z>8ye_lI)i~dR-xK5=y+|jN1;7A(TO2NjI*)+)z!eP0k>WdpTlNcf|Lo|5Ll$%NxtU zcxCx+EE#fMXA0&4=UEf9itG2~XN1f08n?5z>41yZi?+iYAMX{FwUA%GaF}X7e{Qsd zgQ8a=jJ8Q^r9VdlaY1>c3qe46EP`I&?)-gfGx;&IL!qc#DW{)LGnd(X5>A^o?)6x|ZKca*sp1o-XSx zcW`xYYYfgmaSi$qQAD11%af~y3J7n=hx|i(k)7~P!^_v9KLe?@NPs4)P~))xxvvw zkw{k}b~~OFzYW@Y35p6KA&}z_&ARVFLg(vkX~qynU*>bU%Mvd3>ewAR_4y+zox-Fo z=)R7|^e+?Ik|i3xDJKTScYh=mUXZ(Aoz3jt*YgMyk8ByOm_#OzMxZ6ItOoaseG`^@39EY0ViQtEEmLr9p6U#v095cGx|E> zkG`s@q|emSj`qu{1c3^QOVmJY40Fd<;6S*29uKBQPMS)9$&M;U z7_{Wmo)zq|+Zyj1L^@ tY%a6<0!zZ*n8%1Bxvxg6nqaXCWPC^YGi%YL4RO$CdojWX762iZS@slU9BflBdrVe706()=4P#bX}XMqFr! zmWUKQ><4Fofx+Xuzh7^!_gxtG{mA;mJss?72`^3k`t( z<;<~j-qYln`Q<#sP2ISJr(m9{{!gcSHb!e+r#1x|I#?=j)Ffb+DSnw*d}?o5`PBLoBl ze9G7sq55K3O0DE*JHHuaWFo{9171bLL69FVyt-&QqHoa-^95(iY>yLF+*@39`W46L zKdN)TFJg-OO`1IS?Dd9p*j+ifol0GI8z>yy)X^=}vp3|Z96pci4mDZ&^XKsBm&&>7 zB~OZ|>wAPi)PGJwTVON-rqG^<^xB?M|A_1UAv|G2VTrO`b`QI7SR))Sk;h;p2cF$` zLqYV6A;voHft;o0Gc_uRW$J-63IBsG62De1a(&+NO*lFgRv}b11UWaYGE*C)%;)R- zKa-lBpT{%hged|OGFlC?R_Ml7zM2oP^lqUpctNhiCJnnvB4+2f9w0s2;ZZjf4-muZ zkoS3_JGmX6BWmC%&J;ABDNztKc81s1m?Sq5%>dBk*~ zeh7CJ#ev-MFr{KJKVha41+&38x6ezY@O;-g7M=de*YUgGqHd}t%`!m{GrQS{;f{XZ zp^MhipRdTli+9bJJFIkTfrMp6l1=epREL7ezri%~K3tX96}qv_-1x}9YaeJ-uMK64 zlgt!dr&t9&W5}y7ycy)9J65Derk+eLr-Em=GAaa>G$yF*vpK14&UQz3pNMsfG-@Ypd z$`_kYnyc(v6Kk7Y`x?pdWjQ?dkM_erutcP6PZn0ePsknUA4$N*{iK~F77O}pV$G>R zLwxF*u=xjP5Bxrd)g6TWc|ZM!B^V8wnBJrluLQ4$LD~CrOWWl#4Vel?Y*-%EeiVf$gCq`X)jq&XKAyc(NN#4Vkndgr1yGo<)+2 zBZ&O~?;srkjgaTPRHsHFQHNwkyYT*N_TP-=GNr*Efh>`w)3}pU=haDpnDHqr(%aiA z;I*1)_1in}%3%{RS|Q+e2i)Sj6X?yF->o|TF}$@~iEOKa59D)~2?82sg~Mr*GLzx> z-&ebmM*~qs(h$?!ZYNx48*OnismO*p_9{@pSr(h7H$_P%UzAVxRbBT+woRwOw_e4> zbHDG8b4Krin519L5$?;RD7Z6}#3Hu+wJ{|T;0CUd`~CkkPqJU<&capX(A(16+C zJ;)v^)cGiC5Px&M{@spNst{y4wLcCxUGw>hC**e=5QB~ooi8?Iy`LE3fmGRGCB9C@ zIt*GRHND7u4CuR;oV-rX-*X zk*THxsZP-rMXNwzH=}u?d50@alkIjO)i z%^i?vW#OC!bM||L4wGz~pU|$EvqYlP5K5fYahxv_Sg~=HGG!3UZTG`E2L1T-HP$5b z2wWy{-Ozotp?4(tbI1n7{E`Z%@^Mq{y{M9k9rgJxc1rMgTphbXiGik*d6ARvRN1vk z-&c>%*T-GYb=4XU6A#5fB2vA>iYw(;E&^OGE}Cj}GHgEQdnh zsHVH$b*Zm&k%!yy{euk+e~5^I!&4v3HmhnJ>Pk57AMIWXvnEgAnN<^`t+ltBvG|O2LHM5ru`iSLPPSg#m^75a1bmx zyCQvu5J}s7i?zeEPj|n*!OH^uB-{WU#&=6J)N>fi{&iNdE%vlhBeD+T*`6DTkogwG994p8FuZQXMvza}SGrUQ zY`KuDZERFG+*FY_2?T5TFflhsN6SfBoF`LvF?&85-Pyr?u;@~KVr0_bMrPWjMKJPD zpYkz_BSnJ<5nz>SAa2TK7NqCfh1IQfi&!~o^n+%K&BdR(%qfGSpG@|>D)}`svlc5v z}|OQr3!bkdj6pl!?RzZvG4ASTxp}x zyHQk+A>ysyVo&T2@eVPA!S+ zPFhs!A`no7uW$}DkEEo&hODI%yIkU)3@iOhg@S;FfH=PN`)sY=-JH>wBKa3)=?^Qq zR99cYCB4~5$&x3ruzuVRmY@uxqi7*4m2(sMPx+NB&T3TX)-~W*oniZB zN>N~RRid)L;O0``MQ159mCz%D$2v%~0aBDQ>EisP2$-&JK&*qb&N`8S_6bJ`p zo}I%IiS>qO>V*3(`^tscof^Yuy5ALEpJNa99Iyty)k-g&mcWS#qeqgVLH|-BDu0U0 z6SZUu(pY_;+L?TfR*@vrFk8O~bN;UKz_`oRr(P-r)qc0bjvz<`{VbH5Pvd&{BS8pA8g3QXmo)A(eqWoR@_^93d%P ztU@)*&PJk7abV?e(EP6yK9Cslh-q*IpE&bo0J`J&!oW+ZV29LrXVDw2H|nh=plvQz zE8^Js6!SiY!eMAu4f*o9XFI%kCp_HW8`^bELXm2*VtvF-<}1vKmFLu{nHI7hHE}sE z)_@!CuxK~h#0*MBdFY$?NmRca3>WvQ6?6=&vNGkyH>|#E$AV+j#Hv+jXMlv z|Gjqp=j>3eb4q0_b5l@yCy=hEW97I^8tZgsZVma5j9aU7kpQ(e7GGX-6>8zgB%;;x zkXNJgw%oM`(a38CJDF26MH0TYkxpuU-`Z!)uDK?hG-bCyF2ig{;oB3Iw9UxV?ie^Q zFm#C4gmz7n2;}XZ7&AK08(he;#I{6ZZ6pPkRTYz^oI5{ps{d89m@=qG4f^N8x(`!@ z>7y5+pL)d*8A7f{8r`Di1O>#V@EW_^ z5%uy|XAkmhi+stQUADuP9 z!E1CQ*EIax|5lZ+CmfU1-d=@Iqx~zTdk&{{bF#4s30u-09h#8fOGnMWy*M7=mp&~Y!S}nMWKx;Q0)qdxA>A3Ezjffl*9tvxU?J) zS;33QsFo#txi>j;D=ef+8FS>4CDU~M=f}M&|IKd9t^Z=Oy!k`l=xfIAaIxk^y7W(x zfXA6L1um~v4cIk5_Ft=^lNA>>#XpwSuSYXB-b@rilNV_!gC{XZiY)J^ksT7^GL$s} z#SZwGUeE5TT7I4c3&XY+S-d6mfGW$D43%8V&?eMZE_q}>Lv@e4e`ZT|Mh$Ka$s`<^ zrAeaBjksAp=qL&7h#&cynb&m(GXjYuq$7A2CLz0jjN!S^#vm3mB9+6QZ#-uyIr@lU zz@Xpj?qop+0f~E3Fp(t|1p|ZB{bHlDYy~;(%34?+=D+oz{#!x7kJt1cTuYX8Oni~CYl5o5B{^S@OaqXS0tz_$RZFtLHb)wS!THlTgx{gveFP{3P% zT-VE=n8UmeFwjN3?z?;yy>%Cv_N_+mPLS>*f(C(NCI#0o)MsW5ro729i6`!4pbk5s z+Px%l1{r0OUStGOJw(ba8@i0&$aGwagCO9G2_Hq5j8O6;yslf=zXnkR^F{owsg4Pg z;}Q0_&@FlnrgYeB6;m#In0vy`tCCtPy<-kbk)FeagGX_v7}HFnYd(X8Lhq3lSbW7h zTlYwDz-7cYmS!Ck)r@1%^AAd65M=UKVxrSz7efXU2LVMAz-vQ<`e?jIIJdAS4P4_7 zKJ!W5;7VM5u?=$HWV&R3HZGgwn=r2ml@^mFWKf@qFqc26oos7|AGb&|@A}a18CNa& znjtz#VM8=QKs!I&t2@aNF7gHVOdNflR{&;roq5crNz!l>T>Z$Hs!C=O2(NkBQfZS0 z(Nqq2Nj{-C32by2LZKE5+A*{Tv*hi5htLrx#y-HYsNL&^dr;SR;0Jhs zVm^=y$yyLj%r<1h5!vrCu6|3lXf<{Ez)YXmwMU0@LY*MaiayZkW%Bdsx0IMF=;1=2 ze3Sci#6_ak69LN0N88jkizZP>0PiWIUvZmzPKuDgFpJ0A5VO19V+S!f_biS!Rt}MN zj(Be4rSj{v)nH$y9FGKLu*vhW^k?X3n3Gf6Y@+yaIJjdjn{(xrfJ+>|?74*KbmSs3 zN>O4QR@AQkPqiAyBdu>tX%2+?YK;1Q?+(V z@b`ruk=5E|FT34~CBdVP0fE5p%$#3tWWx$X<+9Idx2iEiYe{v=cR%)&mQ=rjf~51y zwjh4!o1ryT807g|FQ*a)*eiZp}b zYtls&mDO3m)FV9}!(~n%XSn?$SXB~}&ORO+@c^&iXg;-{UXDp5fTrmylX_Kxj|t=0 zq<75P6Z{GBp2&Ghz6Ad7!5tpTK1VxM{5 z%h+3D8*y6Ct`e=_YlHAOggWjUHHse=eRGHK{116%yJ$@SW+f_)!8M_|mtoLra}KM~ z|3%ka?<@G_p7ny)?HY<`sU_Xrc2y3s??6@A$?rhA6iO7_DUYEoq+F*3v{G+INyO(E z2ml97yVq?KhpoPkthu~C;qgTLa=+XqRQ8(P*xh46pa?JkpGgLaHl@?(iU$pqf6#XR zFY4EP$DOr5;WWLPNF`#1CRW-lc#$(KofqDr9u&=Il+0osuZ@*Gv6eg^)N?&ammTgI zpBqAhqBNZqS~RZd%0G^a7+U58vM{_qaRVOiOJ2fvT&WuOLwc&hR%;D9zdybeWkyz+ zVewdHQip-E{rNIsuUnY-kGkLY6@bLas~}_Zck+9SvGdBqpz_fzRR{z$blT1*dmMx- zoI%|VDO|>!vZEu!j{Vgqzo?jW#@Q0t^rNRc8`pzVXgV#%Q1bI+z64G5z5#BdF?;X( zmv}A(B+N+ni5r-sLo_kB<7>+LPB~QKHLU16(Eh|>nLk??g}kO00;yY1g#VLUNNX4I z%y_zkTNBS8c$VvKG^i{XKc^?7d}KBA??a43VI@s&V-k}*?Wvl8j(=QYZiK(Qs% z&ygeS7ty;S$E|Xwl9c054VWYlJ0WmlvgYu+FGy0K9!dA4mA~#=pK?#)q>EU@-$sD& zVUi~-njc$fVju=ps~SmU+kC%dA=Qag%^Bj~owvjh=C&lOZrYhg4toQH1bdE3O ze&Xs7>`R3-Zg@FDaaDT}ClHs3UZpA$5~&c6Iev;@rbpv4*a{6|lc?;yrZQ`8<(kCt zINhQ`kxfyN8HYcXuTgz=Cg`?>au^p&l^*E_vJ-wLP%@qqN%D2f6%lWAcugmv!uj=+ zw1?1=M82X)J?NujeflJ7F%U|GjV*o%okRi6cNmG|?lXgF&Nw#={CL#sXmCsvy~QM|N^z=Sx=&x>ii^1e z;`>jW#~)@z@3aSPTvJjl>^7r&y`0`jKs-ad6CHFidK|WhX-Y-uq_@3w>z}\-ue4N8Ig?Zj6j=(HT`?P7ZQ`5``U>}iJ=Hq(z~+Rk-EK>=KLMOB zNS!b>HbjDQR%dEmHj5{r~fHN}!+` zerT%<{(Joi!>M4QnzE@-?6Q*iq6ucK$OPAeBduc>s)wRkY~NPbXgdM4%n8g9dT_NZ z@y^Ns-!o}>otn})i}QMd%w2am`qqqL#YdsjVt=&A4*UKRTYUl+Z~8dApWh_nm(wUN zbCgY5=C+Ko%ax+G#D03m9ggO425L8IN$*mN&tA@q=0o<}48?B>cf0DOn4XbAi-S%f z(HBQHyRS_R=zZ%uICf<1Vq`i;^?o+QeGV2Y%~p#vE6^tCWYnlzRN|@gL0)f*f}Y0o zzPpC*^u3BD-sl#$P&h5zzbRu`mfAO(*iJbqlEzHO!c~#e4~m5R@~!OTX+yY6QFRe>%Q0V)YBW%xxRY!EksX<36L(zTep4}9tt!>oUV z=@KjdaQ^stzGISLEOk91KOO6t-uGn$8%@C3gZ1!M5&UJ~;?!a8f+jzt^~J#@@@B8$ zmCw@vL~`dtOOYEzOf!GU2Vmm0O6?IC!?B|5rb~=@Wf;^+piZC4G>IS>zc&}6Drg&H^z z#`(}6Rmy5UwNc@i5@L9wy#`9b#VtT04^GU7IWSQ`2#Q-<5mgcYKP^C_r*eBJE?xz9 zgi0mCD823^?6t&1$Op45nPA}LkVviQ8o7!}(zRn;i%Q%fGX!glbhscRUEl{3y_BT~ zf3><|U4a%)xJ-A$XG*H`*ZSz(du-reQV3vx0T$mOBOf?|D~;UR!Go9;?LEn!26jFu z=KQQ-+fdK}FAjMcqdQtPO0q_W3T2=nldM(j8;VLnamtYHBIvw_!eP}FeZ!BIqE~pz zw?QVV7tH8aSkTDhUp?*EFCbLf_KV_=ME`Q)uF+a;%WU8^nrWz4rzNeRfV=fm0kzIp=x)-W z*v8%BRe1P04E5B!eWUFLyL+Li`heC#DQ8Ml+B@m!?#efs6tefh`1Ccrv3Q~PhbXmRhvDVBBrQn^G93kz!&YWez+C1|bn zDi#14hNMF@=S9rG>bybMKh=LZ=0(_&qm47x!C70+nG+oDjS7%9vtP3@Jv}>i!5&=q zzDh)fxdsxKV`ZG6-BIKoHLz)fjpf1PDBu366s<8hrYv4YRMipJLLHCgQYEeb`*k{{ zd)489l`7m4ETcC3^$WwGynJhh)*INpi(H<2Vo+bSW7agzR+X#A8csr#-C@lqE$1I{ zt^ilx$ZTYWc?18HyV>y=d%~&J`}W18UgMu0`qJEegd5=yqI$CK?RSnSM?=*vr60Nr zA(JmO&roFGw4MY!UD}X0U-A%lGPnx_ajOP9P=0>vhi%4qC-eGMe=y>7!ZP$5alkNO z?%9t4?j>Y5wtyYuNwgfF47$UuETN?!u`pfV3B$aB$L)~dskm$+KAr^G&HRls1y_;> zv`gq0`M!IhZTI$$_HWanW8e_JZrQ!&gYC8@W6L?(KXf`&Wl(zOOrgeRMDGLgZl!)J zA-K!{99EkKiT2uxzLFT5koT^g za#i6fxWSrrsVFH)6*22i@LS?wcb#M4Dl&XEBTb(cUU0~$sS8Va?d|`Hh36cepWWb& zAsl{G1yU{K9D&-GM60+Hji84dqCnhXRTHQCplHU`HGPh9f5_!-s+8@FI=4^;nzjD$tm&K(b1WI$@(%De5UiT)Te(AL!eJ;|G1lR0uHQ@0u zY|bJ}h0VF0y-3PJt+*3=DAjUFP*R&0ePaE|`OZ~7+--hF$!G$>+WU(9iD_<(gXPwN zJyoTt?qkVkh@t7-#cezjQn`V(T;a({=d0?^;L?7RSAts(#i&pp{#F`2NF&BK3?5t%uLVkSA62h8KSrUJ*+Uo8;;+!l3lLzeE;=~c44Mpq{x3$X@<8Z^ zsN?qIL;l}^&>gm4E%5$30)@g;ZC8~#_d)TQ^gc`jC7M5pEvVd3& zc0>y0ViFe^8U?AzD2?DpFF9(JV=)1z8sHK@2^vU%63SLAN9XGP#OYoD5PDWSN5bqj zDgjx%O||frlU&|M7xN`IP#TP&xDP&$#5#M|d0j;B_P9G26IK};a~lxcZo9yhh#DA+ z8R&Ii#Y!Zsj!%CTK!XOhqyz~Nyd*@Rl=IO>z{pRPeZLA{GY2|@(d;pJtk3(3ZHS>q zMiu}ux5e&!3S||BJJ@EzC{SuLe4)~`BFohVYYhd@S3*BkHmOs?9298SNI{GpRsy`j zmr3vxMr17E-}VpWB$2%k2LlweC7>*$r4j~ybjMCf@c$;z$ZeHfC9j>?CikE@pX6m^ z3ye3kq^;m?n1}vY14%}i6?tg0KT{5H^T%P6(9u|>e|z<~$M^8~-lEv8`hOdW-5d_X zDv(igQwM%XtUSS$s3(W4Tpj%E0_dS+nDAxr@ODrJqZcRl91M$N7p?tNKm-}O!9Xl2 z0{GYsQKI}5hs7aog-K+FbEW}gClP|!3^#{x&5IOG8G3S9ZAe07H6U%XL7do@hzzZQL?;MfaVEFgm;c;)7eFW^>vayCON zRsyL*&|><#hQH|4tSY-~nFTE>`TT2D$??BL44; z0>Ir)gDc^Q%SOyj>P*wvzHy&(jZjq=_ImHHgPv+;oZHb}6Un{|v9?jHqc8B)_U(lx zE2c=G7J>?Rs-pVWrv5C?L#|6QncGld{Ew-MwVC z+U0nQ(3{pMQ#W!?cxf%R>2z|6LY(458im{NO)RE)+x6m2RzWR16Tx!E9Qm`JQxNuW zH=B>@-}~(~%wkI`9hr7mr`0H5ksu@zzEp^HqRCt%byadkJUtML&kdt)8AqK~v4A~X znWJmmSN>xi`+B{@G}Mr2Tt|iulnv>xSi~5Y{|@8XdO*sLMJDd5yGd`S$CrVgRV0uqg9#oD$)B z+arPCNHQ?_YD(`^VQ9*!IZrEA8K3$j+9ieTWqF3)lzeUyj>5v}k-uvS=s5LFJUYp0 zpKk>|G(>dzLyN!P`TW=xus=Qob5ZdsGM3sNCxAij>(l2>zvuX7`);~}Hs-8d_ta77 zFx{UA_lMl<$GXj+FRu?C1d~SX|3@%c@UVdA@HQ=q;Q*X+8SvEaQwjKQjKui%a}fh;Sh2sux}6zS5AvAfDqKn<;bx4?9tb zoR-OnL~Mt(UXU|g@yr84|Bltv^5vhH(sFs-?#)xw%Nm@#-KSa;AW+{KFb*3xS!X9zF z$kGI`C;R3Ay1V&wggfo<&+^pi9H3eb0KxwMXrOPh7EARgH|cFN1`aq70Z1gaGQN%f zqk-^H=tjx6l~}9a+YYLnSVtMo>i_x8a4gJbQxeQxO(ubjRRB$9;*|_d!2{X>BiF*V zRIR!Lew#O8(W;03B~<)Q&5=&(Kf*HF#2jNr!r1_>LtD=Yb{$vdvZpo_AdK8$CjVm7 z#{7raNWT;rm>R;5)LNbGQDtpsr-V?^jC$QN?wMEs=>#b6JcG`~%lA1BWo5NO%LbEL16-q86pI@7ZMY&1)KXEmdxp)tiH ziKIX;M|Kr-bKQ_h;;pSWdA`p*+&lA0{%GVoqb_p>H2yuhatashfU`TzgIEIYci{E2 zd7taZeJ54EK4A)=3KL7Xs5?i-%)#xQR`9cXIOFPH%5p*;7$ssu6gGAwva5m&`_X=A z4S(AWpG@gCgFuuboA7`-TWw1=n|<}+gp%DT{nb*dblcY7XcWgJxM=5%O7-c+h65ug zlz{X9YwIij;%K5SVSonjcJE1!(1B6hZJwBJ)Gb=a2NipCr5<-p5k98DMsOLy4~zcX;q5`+#YuhmRpU)#Cp3gp}#Jnh;Lt54gC~Z)StQiT~O;+yx!| z`cltlsW5SL8L7>dF`+&#OUcJG33KX43h_z8d`w;@SA)lOlUX171Qlq+%lLOLzCpSe z3VwEZ829zMy5qJ7h^=0H_B;&Wag}xbLXTNAM3L}%{7(MHMZ1084_>k4tAz~l$vDIB zxL^U%Las=Zq(=}iJ$U@yrVwhr-`X%|t&N=dz%Dp`ZjvvQPS~I2ofRN4WL*@5ang17 z3xy8-l9VC#z#2`7OB!JwfMRlFn=QWz9;#uH3d*FDXlB&ks{(A2mpU|ht$!reNfB^- zcy#OU4fl7)>#l~17pI30F;=^K&Vk*wo!Rw!=SAcE&p0_tzYxR%xt(^+O`Fr?VAjqj zH!+uuXB)ibTqcG+Ua%_YASgP0&E&_YMLSyF{D+T7i8Ws!Wz9vP-9|@*H)xWA1&@un ziXgUJ(LLUDgZBXml4tHOf5l$F(#DZD6eQ(3w{^)Z4(Su;!}Ri@+vXB7CyU|>)gpWS zq_Xl)`KmN`y~&JfKt?u2&)lXP(jer_YFq)p#GW2``QEoi7wax((=0~2`z(0r)_AEd zq|u~2!AUhSm#q8a0~ENPWGPXXyPDyy^ryYTwl*ib##PyeT_ZZ<=iHy#N^(HGunGXR zC*>bZ?4A5Ou=%b{oL6Ch=AFD{x%AK3KTB*jV&8S0@_tg~MiUEPxlaUJG;nQ@w5$VV z0<;|eSTYeWsng9@xvUnW0^<&cLLXDtGgoc$s_6RPieG^d#-s*;M)m?Eze8_^DC^F$ z>_oEpmYWVNClSP0z7=0WL7wm%9S4L_%r0%yp=-aK#^tj1jWl8b=eb{=yk}T_+lF*l z979vt%X#uBdkAzQi2cae;i=;|(lJ@%rZ!X)Iv2&V5k17-tXj>jyzMNXZ6#3@ID^YZ zb|~Axk!2n>qNz^zc4t9^eTU$q0P;6`2oIR+Vvm^XrbM2{4_ujl{GuxsjDGC1mWcm5 z69po`_v9(ItN_=-7NZ0W55t5UMHY$XC&%qa(Q$(ai$b%Lf$c7}9lcbv{$g>jS~Sn+ zhZLSXV%h#xUr0-h>vbJq*rtI}vvN_yvW|RBPBHl|QM*L35o@M!z(u50O}f_`i|ysP zV@ZiySKT}+YR=Aa2-AL%NlxHTtP6GH6~N~4Ew__$5H6shAHcyWWlWZz%pOx=Zxf}v zRLpP;SI%u8Qg;H16M9CphH=JXz-DlxuM3IG>#ze?{4(qeRX_9nOAxh!TXv!zQGdy& zuu)*W-K+409FO5hWp2QfIO@}Qk9x@6;mTpw;)63MMWLZdE+;aZ++6D0@4=Y{cY@wd zya&Ja%1pl?rm6}6fd7nlX_*)U?nvM;cnPIgMF<4r73BuR|ANlSi-a;3zj09+Pm&(4#KhAKE_ z(orwdZbz?Gw&fJreiqMT-m+m5o|zqP!fLQ6d^5Dh*2sD8r=Mkp@>43MuC_IU-6x zz6s_^dXTl6RAedfyV>>AZ12Q!-AQ}M&xTg<{ppnwf{a!LcZD_;EHwWa=#VG5o!;58>aYCN9@VzZ2u`vI>xf3 zHQw|BO_Bsm(X@yrDKJx1glUV)!ec3!Xp|a)sd2H=}Y+MOpwF}oW`S!SW`>#s3V|St-ooC1G_?J0|P|q z#~tvd%BwZn9rF|Gm*5=Y_F?Rk7OADeek%Xot)aD=75~YQg>e2VE?^$Ut z*u+YqIzR2r?Lhy_KavjKcm&p|1%3$k-xd?Q?)rrcs;otK+~4A%W26F3S^vF>Ev6K= z_hIrIU&n+68i*&!Z3A1Ks%#D}DdW!axuDChUn~{p8|pk+Zu3mY&F)xklG~_5Lshg7x zPm$7<(q~A?5BK)DsRK9zV0P11PE5O9cW&mJGZCirLA?qfrvR@!CMh2LckydSuyS_i z5Jn03xy|AaJ|n;rFxV$4kO*^_JDcfP>9qLsM1>CziWGPiN;r@?T~Q`keb+y!h2&B75V!R{Gm9RyoGQoZxqyQOfAfTtj@!c;C^orC`Dhh5;2zpfPJN{OEt?j zW`@QwhtOfR*0}cx4Mjvr zA*aVO|7d_+IJ^yY6=GD+GLy`_;P zD0Na*j4Hkb$490gs6@@UL?vB%N9O?fL-k!&CG-qgOH^exf>qEgrRMKI;!t6DVR^P3 zFPibbC1Wv)M(Ve)Yw5*a9H=?mOEucXnftq8Z1}f&hwWSkxA1+g(v4l^sD;(>)Q9u# z?|5w)SY#1Jwew!qJn+9f{Pn$w5b}QsZI&@=2#=PX`le~1x+r`2gF~bzVBs=RKwEuC zQ?)j1{BLpfhaKm{_E3Az-0S=3IGSrOGu*FOq!N~YLM_#0lrwD%2++4Y>GmvA#;GaS zJ^^;uBbU^PuYrj+G?V4n4c^Wa2Jx6qe=~WrdeL2WSNMHC5-hVNzKS>U#*po!hW^v6 zTt3On-8UdB(lY)Ly%V}QF(?;w@XGk>G^lIN7x`()m7BU@`Gx}RE!I8?GBu`%Cyorw z=)?~B@5v1U0C>;7?TtnEjjEcpL zzd9HOi)CzNPIF8kNGTbh-AGZky0KL2JZGk8!|7t$aUT)pS&>++l7N2<{kRjW&mBi= zA&Wze!S5UrLYlLDLv%S)9JkX);Qk*DLj}ukn7*q)dET6LCVxRsx?oPL5}&NN_)i%v zV@(a2f__SxCr^>IihYSk)|L5Lo))9^F$;B3%dTKb_;{l!SN%Y`FLgCkkG#`$5+4qy zf4VmMl@K6#zOgJ!7#*UsYxhADz|1;BGjvX2~3hju>{v zho4_pHzeCzLg%A!Ke9~g9Z@;ZgsPMnlj9t zA6jw;PeM-&2f6(IvS$$UWDXeq#}U?76FvQLqJ<=xR_U?3HsoG$%N)bfIgEMi3#Xaj z2P;gXBvO>#z z($N53(9u7hL*)-M>zz_v0IW?LU=*z~`?2;?n|i78PyD$?*BSEA_GJs3z&E%rMk4Og zddok29lEBVc_Nvf=kT3@ky?ZxHiUim9dF)T$ugbKIFnB9?=?Du!V=fVCLa>y6up{{ zbkI6z@O;r*(rO!f66+oKTWp#Ph7PQ2{HX3r0v-|p&ZT+D<4zHZk?{(Iz{eKcH4 zTwO5R_d(@lnY!&e-hpK?+GV?{ZZ>xCQy7N1|jv1PcYEy@j6}N-@K^9B*tpZ!i zx9;!E)#V@{xZ;3&ewi0`T71;|bQjcO8pmQ;n6+rKG-Z{((hh1Koj()J4{W%G3E!EC za1{~=S&WdE<3SZr30I1}O!kA)gOg=n>NF6Ivmpt#OL?;m2M(>s9BA~Zm7M|mY_p%- zpRdOL>!zREF@L@!{{`=48 zy%J)=FYz!oWdEqNoP&e>YUP8^@5<%Iv`D}KqQT5&s#~qP3p6>&#rbD-Tn*fF%y0SL z@eZjsELN5m5xR?pb3~pmoea6!Nt5wgvV}FL*0jgdUEU3#26+lqMYWEjGsmNRlG|!? zGTwx(c`E*^UI98yW!HDCWwrMQcXi|fRb~Db7lolpIv3B%J)eKIiSy+4ImVNc0mYQK zrf7{E%Hh$*6vW74VaMVCD09y5+B^!J?*Q#q!dncKiz@j)NWU~DV#jUqITdooSSp^9 z;roE(+*WJskPwt`iaxj5A2bJ^IHB40XU}K?-Y4+aZ(NPhVR zSHIOW{&yl0fr-wbn7s<=zr2Firw%4p*Y#o=;s~*G<5w3m%DW+*-1mML@SkHMqP2o4 zt;YVyyq;s}h{-095C)(>SAP3x%DrbxiM1!IQ%jCisHCq-n%hlxc=~$7et#E0V*2LC z-}j1N9T8iSE9)U*NP(GZTDEKjX>6Mpg?|A)(R=3`>}J02PuD$xB+Ygm^8ZNuulN4W zdQu-9!<|X_-NM#|;^stqZg!;z2dTXNGw~@Lrl{}@f-2{B106sH*oheM^H>p0&DmHQ zTfCHbGv7b(-Wc9ZIM$y%j7@WBpkzcj=A|-+55q)a&8}4I=aXc7a8P$q2|UR+e-k8) z3n4q2FHYzkA<=_lpge~}U!xBF`+xO@JeRZ{+Ae$;wa^+=TA#|OP$kiYRq2vSaQ|ku zIEuTCy+sq`FrEexGJE*!E(@>U*L_pf^t@uVjugWCn*yyi@*aFlp}r>jb7$h%-4 zzVHMA_U-+W0;#X9eJ!d3Mb{(O}f%m@1b3I7#F@#0f zDC64U)@n?&NZvHyXtDG#RwFM(bOM=~i?L8gFK5cp6Y|GA{<(0u`~xnEUCX~}(dkQ;kAL-=TJ;K22?bSc zZ9OByy!6!14~U+UGflSo$}wfSZ5B&8$Ar-U8JCk7_FXJiju`(FL2q&A6$s$PnSkyY zQ9-?um{#rpk74C1SW0^gXvI)CLEKLAnEqqQ&|E6^5BVpAQj6i@#K{ulVGZCM= z$RNEhWa+i%$VsVYc~$Sfe4)N3Zw&IfU6aeK-}+RMofP@c!b0kC&E>qgUP5ee_Q~#fT|zu6`i=3OSf`K5Y>prs;0IM==N&Rt zYCq&UUk+@MQx-b)wwAofBHzjFT2|U*&A(EDL*Cf_c)$umMW^_U>2=8B14;kOr1@c( zmL>xQ<)Zg;YuyhJB2s--J-|dG^SIdM)&ds?Ia9o%A6JU;(Wj$v!j8~HrZlWh9EU{) zv0pOLK@U^@t>G=qWG+whh7-Xh`a(X;Ah~o|^K{)@af;-Qe4>A4tH}dtk_i5p zKLE%V3uTpxXA7uC4^voBiS6r0YhHGe6%;9vcKx)1?E?&%$uKG($WU zA-^fLYjr@q-2ddLVZ)}baZ>TA9|?ZE#5mMv8b#Ed4!&=WeLtgdYo;!bMKD?LSpfsV+zqyTicd(ymn+@Kr{vLrzCzP8uM*%fFLvwpK7-f4o7;`}4g=y8o zaT=L(XbO*nyST=C3K&H-X;!{)J}5`0Nl)lFDtx-S@VvjkkfAii9xSHb$D&8OT86F^ zvJKb=pKd#>7e9ZK2S=2gLBQ1s76u%Sb8W4xfYi;PGY5vY>AU!hRE zxR7ya1FuD)mv+$H_M(YHm(M+i)zP+yrgU;^IJvNwQkq%bmvpvKDDS6=j2iO~in1qS zeQp;OXq6oQ)Vll$;I%m`^4iVbb{8i+G`-8aIt1)W>N{oPaF)Nl zi9+UsEXgRNtk9<6A+2X7BySdrK-&iW92)&$&(7_VRlZ(Iw1U67);`8XC$Ls2Q`g+FL~>HW8$vlY_Fkweer9z^#3=bX8kt-)-f)ue*)^2wKV zd~OBXFntQq_lis;!=7pkFWGJ)=S0u%h-|)nv@?rlG7hJVe=ig315n(1L7D8Hq%kD# zl#5<;Z8yQEj^lStnr)@eVUME`Y*sH&vf-7BaQGaVwbK7Q(I{tWqq`@zhK63AZ&Bx~ zvZ$^PSHipmZc5R#)(0eEvqUDECHvyU++H}YN2_y7FAnGu`4Gb1rGobZf< z&a(4^+elyL>n_y=T)o(iR~wRUPBtx;mKz-CNQD}sx*giW>kpbXgC%x8H920=Tq(3@ zU0v2xe$^nb)0tK2p$@~3j?GEqI?F`UDn(sjkM%q5j?I4fjEDOK{j^Yl)a0N%wU#V15s?J`xO+_}un)c?anfrRa+`CS4= z10Otm1`hR3zxPe{x9^_k>#A&C-LKpK43RO!3P-lP98umhmAW0Ts)u17mzT{6{oZel zVARTzzDIvnj>)>$D66hKk~#mmXC;S5dd(tI_T(qvj-S`|TS#Nf+@Ws$cSO)dZk;2JCSH01_uIMMYM3aaJmC3lXfZ9SdPqgk2(zsqh;3;7JA z56UNOIcI)5bqcA>a`=pz#YuE=(@_L*!HoAABqUBVe^=(Ld(uC)e2(}vmB8F=yEZ&L z@uYWqvLQD^fH`+4N=fg`>K`?Is#3M=c)Ug2-(-FI|K^_tj}auNffN{3(Kn?q5c#Qv z5S-9xKcw6-xOkj^*JfL$yTG>HYgdCHPG#j^AoPRb_d0_ZNN@m=;ivcRq-330SZI!* zyP9PGfBJ1sDX6wf)kTX{YpTx=81y_hXog*0F{{n?l`6mRzxv!?L_6&hY;zP^jF=@xm^rWyi z(#_1|#-Ukl7Wt6hpWcL7_(V07;&`JS+rM`kR|k1DN4*jXAkV8qY{MSEoX_j6CZH1p zNP_R<4F@bhC>n9L)9%j=6T?R&WH1YqRTQOp-Aw4zx) zG^Y>G%4QBe-u*Q(G1=YP5;HO~+C4s&bKdt-&xnLi?)bQTxeh;x7%1tuVuxOB3t(XO`jBgE$SeEC~6L_|tdE{g5smNZtwQN-d*L~@-Thd( zy7~mzFtj=NFf(G4aJUmq@WPcL{))>=lIQp++Q-rtaJ#|L3w+}m>55{MOxoY_fyO1A zp7USTf~pPLek5_{+WI_~1*-8spY>rS(Iv!+dj zVZ&S3hc?`aZ2qXl>P_h50AHU+($0W3<^N0ZYBPz&D-XKG z#1)IhRCb7y)s&d0^FAkqd-GpYf6JeFR0`S^+9ixJL|myn4lB|f!RDKtu2~b6mC=e2 zNL(>W|5sU7qt0Ow7|>pwqp+~h`f`7w(WLLcIYhhX2Nk59$5563g5A%4i3#|>2>Jg9 z*Rtn~^RRxW$UXwIHZU~QgWZ{b1l1YY^-3av2u1xs3l-WyPL>m;F$5f}P7&uO97g?j zy?lv}b&z+{4sdMq>?i7l(*K0__q&Lu_8kLKe^0jLv>3Gu$Bq5_5WZ8W7~x(VOyXh< zKJz0*nBUXlR;B>xF&;+b6u^(6)BLu7y5436(mpuLg1eCw^F@THWzORntF3bNU!wa9GOPscnm4^)7t37^ zq7&&`;vpA;?4E>jRBh*`KA3|$9S%$=V^4`*i5tNpW@g}3gQ$(h1@rcT}0o| z>QSX5Qy${u`_rH;U9xm4eT2H+W~^B<=XYKZ2%cS!5me_=+-HYujQT_liH|OYD()bS zN-#I?PrB|P;ha%KRe9_vk)TJl!Vvy*dY`6wf*SKb`=dxXsCOVDCDtFBKQfZ`cGpCh z9$2NyQs{3BX%x~Lgj5tG%w0e*G#Ch`0>ut50rkE`jd*!^$wuBzgU3g?-~qcusjkls zDAcYnunhNkb?)NsfQQ`NZ{H_`t3&cAV7h6S(iyg_p7vBEk%%Q9JpTZzy0LJk#npCc zKRmvX!B6uS%7R*@{goj6u)N8o+D=sKRdRcouJ*kdP2pGU}MPZ#Zh#J?F=v zKQy_yXox}ZrIidCrKRsYb*sNQIS;d$?wWvPt+i5SP$g42U~SUavOY4MinK27x5Hm( znadZ00woxFPX5SFod=$WTT9U)X5s zi9!m~i*yR(8%4YnCd^_di$}Gf2mk4Lq7T+L>&Ndc*DV?K1>R4fjnR}rn-4AC68q@H z)mu$wvm*2gxL_j``mWv3g6<9Q!@EMa{p88RIWndvCUTy*(m@I6)yg>n4RMrp;EhJa z%J_0**XIdG^EeX9*$NU% zYic|BaOm_GsU6QdCGgqztK+r&e6yP2r;U8K!tZ`Ur*T^nhrgTt0Om%yZYKgtG-F}D zcu0Zh*i9axSnqn}6v@rFX;9HBD{SU0`xV%qvQelD63P5sb?I;|sp;AczVw#oaM>=t z$9ONN-gGb_lhHFvS#J)gx8tW|VFA!}p_bW&${CkEz~Z5uJ(_swE7bnoQV9=+Egfdv z>tklhu*HRk7-Z>iy9B+_dx}UK0*SxUhH#$ll#%-v+HIEh+>fqCFRYbg9gDj3??Qm* zBd+Yq!`2mfGQdr>>s)X!*-QN29T*Sx@eC$sW-&zRX&-nTdiT`7U5ewue54UUG}zrv zMBEi>xvMl15c_uvCLl-Wj8R0VBU~_wqU`l=AFENqR}aJsj3$S*SRGAHx?N`~uoSTz z9j=$Br`1=}$W~=6GLcbKzs;9NCXJBLI1ZzFs}XVT3QcZoAfy2QBspbRBfhnMB`4CO zC+eP43ah_4D8U!4Lc8JzZAn~P;pokA%Y3H|R}xk~AH4`NNUV##1d8KU+!qmRE}qPJ zKJpO_k(N2QKtjxa{5+A#mZ#dI%de02rjH)!BI6!vAl$5K_ZKO$%PB^i)le~}QfJ;5 z;))}cCCzT4MSHu#wS0w-d+F#4QHN<(8fekSt0+M7vOr=KQhTqmo#E7psLxMNBSS+` z>l>ZNxzJroWb|swOv$6qIPr8=}nC_an?A7;2(5iPWDtPt- zFP584)MeEO^iBsht39vGRl2Ux^2tFU)F*m0M4p9xQ>kk;Ur0FP{e$giWml+sq5o$z zNqlw1OsF|$L0Oq#oA;e1AvsE*NVeDYi?v#mC7svXPpUQD7cigLjKg7)A#?RcO~N8o zR7F++d1`oH|K4pe&DLTM-y`-q4DJ+8xl=`#47`Oh_q;gUIsAi>RDLcDauLqnzxq-T z{~U91EG*uOVWL{JvWL8G5y-D@2sgK)z3Hsy5X5El3CSaf=8Gcy718pVNJO_3i zaM4Dp?wf41kjH32*to4@-&RWh<2xc<`m7j@_6AL^*5LX83PI7*LQM4GEa>Q{gkaOh z2fRs;MM0|lII|s>>S4=l#c8u`{+X@n0xHsH8hK8RB~M|;Z@KyiHMe9TaUrK_(5A&+ ztT2*zGkjbsLVZ&K-9636AHn;85Sffp;81UacmdqEndLL6wMT^k-%6*zrlC-EX^^ZO zS9!1|3X1uk#VSPzyGcqV$#7ITNGgcA+w8upY_ITlP$a|emBZ_{tEnN5$NiDqphyB% z@v+pJ`9Nh&23)Pl4WrSvvE8q^8{XEI-(0>je=<;_a3eb);<4k)TUvcJQ9-0s3I~iA z)E0$c$t*QcGA^e*tim4OBPp}NV^buj*Iu(Mg|;zkYTI9~BTb>t^VF1^R3Cj#o8!Z% ziRl|RI@}wu5S6bAOF)Nf*)WnB>xbCuQ^7QeReXZyX&{D;95<8+MHA{R2}oyjwmQ#ii`KN3BkT?%D#yE_OWB@)62b$$bf2S6>roZ0FNBa(?DD*-OT zvlUvEt-E1e4B(YFXp^UaV0A8*RPauCr;A+3BfhYx$i4!~45(H6H#TBAJAKMGze{aD z4!GMsld|D2_4?2{daFWa*CQi3^;0TJpUST&vD3XAeXc&FVMkS@7gB;BKhcML4o1du zt|HYWWQkXP#`v=SZPQ0#XGo=X7}}zP6nJ{FmJPp4Pg~y?#xt8bf!*l)_}^f&J$9q* zlC*xE6E{)_Nj{)ooh_1yOJdn$oe*7)b0Ygf4aj+N0S4`m2)vAp%pRw+piiX%ac+$ z25?-9w~A8hI2ly0=9s`mTpI%xJV1(A>8}i54ZG%+@f{)7t)MCZzQ@+amL7Mb*2tHY zD>0Rt5*fktz#rHG+)h{W%=4_gDZtsh&ec!=7fGk2qUxt^Q&znCLu9*T`Xdg^)R%$> zZp{1H<1dAUfkw>%Nv>u4W7rL)D>dK4&RKfe2Wy+-OPJ5At*SIiB@y}z` zh8&LhVkLVY8W;(`Q?QV*a9h{$?*&`M&B~|PzP_ay zH!=F4FxHa4o--cDbGYG15q|}th8-?@@kabcv!>(2=ZP$HEt+MP_DL&@6iwAA)Dk%1 zZ|bDz!~oYBxWI`a24Zu^+$&AU;I}I++eP)1$dtQnmUOmPWGTy$rMgXtH}#>{#M7Zl zAC^%Wkb{J8C5PORK}SDrBhvYJ!$<6er6eWU*;gEXcEa8=8%V)=k>7(j=;QmxRT804 zOx+2yZ44|dE1X`(wPt&T7-DWt1~4#oMJwf|1Cg4AlBk*QZ4y;6v(lfSlQ^a1#a>5gU83;9hoR9zk-jhh;+EiVtFmW0@^Hkw?5 zQTlW7P(;uH^R{B3-Hv9b$2lTuzcy0fK`%0p!{-#B^k+%}*1AisNzyTG-wPF!l~5CQ z$Lz`2IERbvMrHw{lABjqyH0x0NB|nOO7BO22^24lahacyv|+P~sFNu&l4jZZx0I*> zYkGX;5eaiSn5d!O`GBO5NaJ8;9@W`qAJ3hbA@)PDIXG#4NEITD1Jm$5e!!TokYcL7 zM;L0M#<6uxnD%`G5fZgZ{bomX^5kr_+Um)44Bkyx|9D4&C#znvjt^UZ@9S5UU&xzP z%ZUTijU$LhIk`Pt40;T%HI^ht;E5r~;Zr?Dlkc)gIf{AD<}a8UyKZr5Df^eG8%sAy1P1;32@tTMC5;@9}JS9+(CjS z}bD>dqA>-Xv$1{=qte4YX_O_l+^?;i1pCM0Z5Z}1sZrr*H`+2x6jw^;xB=Li9;S@g}axR;ejQsG9GrI|m)~F$NI6pgFf+Yn7 z1(Ei@1yn@b`vZLkZl_l%ItrUg`hxH1&w5&m#DA~K4FI$df=-~ZJ1MM4LTELpYWQL3 z-3^9J$!Fs6u8sj#l@mT=urr+8v+k3F&o?ey3Q&&;w;p(4`6!Li=$GRC9$q z<)?Cc3cv1*S-++-xLn}k%9>U(*>I5;u;bpc~Ky_isTMTa04g-aeHsi z;^B!X0gCgEjZ==d{5&vqcJMqU69A#8`*6e2NmqGtVoz_1!>~@m<#t0<@um(}8VOt$bUP|Lhb<%gWl5;5q#AXT z43BUkO+pEvZozm*NpF|SpK#VIAq8p13HO;yq)`~2!$qTBzv>!2C5*^gYnGnQ-#lhY znEsg$q{ED0NfWJ#eKx%CD9azK0wJb_H>g?^^Fv88pmfFD^mECzQN=yr!Z3UMLFdS6 zoTJ^#QPi-}v|Mo&H*JjQ@Ws2sf)QQ0xH2Dl9lS%mFz`G0kvP zeV~MhHWqT@kSnidQ=hL$0qfyMJ<6J8GSEm^E zla$LkO}hUtnBITFHPeJcbx5sSSuMIyb*kd}`(CX}8ohtiB7_iSjHoq-FEuNdE^qDE zW63rj{8bL0(S!iJ!Q`%lLWV5TY)~_We-XsRiK0v zI469RLgqGvw&D(K{!648{|_n7D%Jmj!dXXL$o=`D>Ah|0JA4*W*$k&&-Wat{xdXSk zmsF|FX=sQ`WYuB@Q8yw+?4=yd9D^w!IU?B8efipoBlNc_9gE%MtEy;0v&10^!P85jq3XA;NQEf7 zp%aFvEp{uCtPKVOO+<>GXj|SGk+;HS7D3z}K4|W&_Hn0U526jeALJS28*HZxqo&~B zQR$#B{c3n7hH7+I9(3Tya*op9PVC@x`a$~^C`oX&wYEk^sL~4yTHDwf@R>KBQ;zItu(on$ zg4$}j!{?jVwN8br0Q~2FMvWW5_lrR`8|~ao@ypB09@q*u(?cYHxvTm&T@G9r)E5o{ zE_#rUl$==bb)WsVa-!L+9&dOhsk5`kRs^j^0ig<5CR6_&Q>#TrN}S%c+0b};ZE


~52TOmEN8C&guBDzQ{KEtZyHnA-0n7~t-xEw)R#Xz7C5L4 zOX!8c&vSp8{kHLK-W|izHDJb2vLk%3KCpA#6xWdZ&Fz(t)&4JwQ48r1qWTvlGAoy* zt@V+K%Z{nn>`PG(bs1Fj1DFSGJaGSydaV}DW>5tuh!W6nGb;_HlW3;tCc+N~5l%o!VnDQ?d-ikSdpM8z>vg>(sUbiy5a|3Wt7=FPe z4di`)BOGD<}LiVwyB`IzV0LsDNe}kc#9g`C!u6$NLa;e*i0ALS2Q5J z^0%1tEkiBb(TqKijNl3QJ~VoKN&{RQL3(XYC2+E)rj$|9(dH>BDTN(uv^fX~P}O$v zih5mU5E)+#@K_e;7Z$>v;Nc7|tA`pbEJ`P$)9XKO@bPz&j3x=v%|1xd!7_Tfvbq*) zP8o>!P%!;agU*T~SD{Lp0 zH<@b8Kk0Y4Rnb>b_E(8u)Q9wk*Na)zO z+o#RnX>}7-GM9wU|HX&n7IuCJFNwAkHsXc~?n2xKF(MEDdB;vTG)Uns8hjsH00$}xH8nFE z!0lo-yMG4>AXC>+S5G8F&*#B|ej&Z%N`3rv;CF?U^2y}!CPf_te9wIaR`joLU+mVC z9~WiNaF`F8iamjz0OugS z5-DJQVZoEdq^YUNnf|AlWkbrqWC5Z$aotrxAjU^TU3g1#bHbn$ptT-7N)3ne`0JT0 z1tNChCT_S9le^8Jhp_AK16%jhhto1Y!k3e0R4JS@~5)(8vhiny`N)$O`jVKrB6ff?lMc9XW8J#qEl!;#O zE@AgH=TNwP0?KdxLn~4yV<4mB*%YqZRSu{r}?>h)m$)JrY7xmn-_V&jCpF3qCKy45_f^b^LzyU6) z?9HcB&^wsS!QFZHEl03=r~x_EJ-xZEFDwoy+wTC0 zm`P_al`}fwNv_}TCepuWHVsWzJ*5hde?p4?EEA_vwQj+na4Hm^oSf_jMrzL}v^r&k z{%8oMfe*BdTpjUqK<&TIz*;`v$*VoQduEQtL9t2y1%HZ+@EtT6j9A;N)jsONC6NR* zXBhkVWguxcgvM6<$2Vrm(QQ@>Y)M%vjCi{7Esw+NH&|0{C(F2$7=-0!BZ)M2z|<7x zbUb~VnVvMv-E=(Pmf{c%LiKy^^R2ub8{EGh)|}H(Q-U!qyEe>an10Vd};4HkJ zuNQ7Ia6z9(*5eIa_*?31_Fg?b5=wM=5yFGO@T5eP5jND~j-fwEEzQEi3za$poydvE z0+*()Z}md~B7s42bYqT(Odm`=9U1;=`ZJl}9B|c}n9LPs8jSq|1^!=MA_)7OUJuq@O_I>{@XVYu)!l!grdd}5A1N?NV=GW|HRvVED* z_I8q2_lsYu#N(Rhh&94*-5OEN`tKl~MyS-AJ;PQbh)%!fJ#|o{XlLYr+V<8laPhlV zKDqaI=`)Ka6Z#J+TtqT5tqWiO=u4i-&p!#$DAd$>G*elF_t$fURey&lSOdQPb`Izq zXQVU!#i_r`Kbc1AZ2QMIceQ=F%{guP8{!g)>|MZV=11{agrUoMc$Fb<524$KJZ}Xu z2~a;SrQTQn^IIERG|C^8V=BsTT0oSXF<@C)HfBHax@i>jET9y7C5_5uZiqwkEjIQ9 zUS)~ecjWYIM@N!j>z9m)XeJBY8gd@|O?!TH=ROHgmgEH@vJi<8rb<{#-_F*xp2&AI z*#K*bZKDEiODng~`aP8uu@O;*7hyUr!EH{z)+{4s{VJ&oZrFHu<;RAkij~d~ndSLI zv{aohderf;m^$R&m~^Vc7v%W(BHyd(-b8g#PwAMr)=!DnSjnM}1GB;(m7~$Sy{`{! z14e!Hu=xK{E6#ogTlIBpZJjxJ2y~K?ovzX!l9Cz0Z=)u>3F4sl4ijU(-77|m$grOz z7F}88fz6?pen$?b-*xFLR&j1dfe)EyTW=(Px@NDeYN~r}ys0hCs`?wn_Bzr1d{d`e z5WzRMxUSlx}O&Ru;3=8-#ctG_{F2-qSSl`&z(V3e^XU*9eDkLbS5lVk0AvQ0k#Pr7V zkyOLWBY8l?n^*E+beAAb`0l0gl^ueplKJ=b9=5GG-y7pF$>) z^jZr&S@rH?-dRo(%@%|y>m)kA&q~a%XW`Bjsh+}2WK7Q{?ScZA8$1E@fdJM8EwJUIU+PV1}wJ{t+q0(dVuO2iyF_%>=VPzDhmq4d{k7uy*rKp zCK^w}iX9UxYrDRoq3?CWl(LbiYO{lz@}zOHPy4BnLa+B;kT5WtZ{qy4tgWv_vGE>j UUg$Ej;DDc;l(J;C_{YHi1>v`}xBvhE literal 0 HcmV?d00001 diff --git a/arduino-ide-extension/src/browser/boardImg/icon/lzesp8266.svg b/arduino-ide-extension/src/browser/boardImg/icon/lzesp8266.svg new file mode 100644 index 000000000..8f0c26692 --- /dev/null +++ b/arduino-ide-extension/src/browser/boardImg/icon/lzesp8266.svg @@ -0,0 +1,585 @@ + + + + + +D0 +D1 +D2 +D3 +D4 +3V3 +GND +D5 +D6 +D7 +D8 +RX +TX +GND +3V3 +5V +GND +RST +EN +3V3 +GND +RSV +RSV +RSV +RSV +RSV +RSV +A0 + + + + +FLASH + +RST + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +零知-ESP8266 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +3V3 +GND + diff --git a/arduino-ide-extension/src/browser/boardImg/icon/mega.png b/arduino-ide-extension/src/browser/boardImg/icon/mega.png new file mode 100644 index 0000000000000000000000000000000000000000..0360da4cc158318a82f5baea2a1b53b6e961569f GIT binary patch literal 38613 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 CqTZ1J literal 0 HcmV?d00001 diff --git a/arduino-ide-extension/src/browser/boardImg/icon/nano.png b/arduino-ide-extension/src/browser/boardImg/icon/nano.png new file mode 100644 index 0000000000000000000000000000000000000000..2d51c20f23fd80d559569adf65e73e9e699f93e8 GIT binary patch literal 201372 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 literal 0 HcmV?d00001 diff --git a/arduino-ide-extension/src/browser/boardImg/icon/uno.png b/arduino-ide-extension/src/browser/boardImg/icon/uno.png new file mode 100644 index 0000000000000000000000000000000000000000..f4293e39ae39d6adc239a8450080ff76992d0bc3 GIT binary patch literal 157574 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 EKV6)MNdN!< literal 0 HcmV?d00001 diff --git a/arduino-ide-extension/src/browser/boardImg/icon/unomini.png b/arduino-ide-extension/src/browser/boardImg/icon/unomini.png new file mode 100644 index 0000000000000000000000000000000000000000..5d1e966abd2034920ef06c4308c4d8b4a9cf6571 GIT binary patch literal 55595 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 Z)E@&eN4m(!GXMYp002ovPDHLkV1oLMHiG~F literal 0 HcmV?d00001 diff --git a/arduino-ide-extension/src/browser/boardImg/icon/yun.png b/arduino-ide-extension/src/browser/boardImg/icon/yun.png new file mode 100644 index 0000000000000000000000000000000000000000..3aedf9a3f5cea3483e3bb22fcaa6b05e9d304cf3 GIT binary patch literal 135160 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 UUg$Ej;DDc;l(J;C_{YHi1>v`}xBvhE literal 0 HcmV?d00001 diff --git a/arduino-ide-extension/src/browser/boards/boards-auto-installer.ts b/arduino-ide-extension/src/browser/boards/boards-auto-installer.ts new file mode 100644 index 000000000..6c8684248 --- /dev/null +++ b/arduino-ide-extension/src/browser/boards/boards-auto-installer.ts @@ -0,0 +1,229 @@ +import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application'; +import { DisposableCollection } from '@theia/core/lib/common/disposable'; +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 { notEmpty } from '@theia/core/lib/common/objects'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { NotificationManager } from '@theia/messages/lib/browser/notifications-manager'; +import { InstallManually } from '../../common/nls'; +import { Installable, ResponseServiceClient } from '../../common/protocol'; +import { + BoardIdentifier, + BoardsPackage, + BoardsService, + createPlatformIdentifier, + isBoardIdentifierChangeEvent, + PlatformIdentifier, + platformIdentifierEquals, + serializePlatformIdentifier, +} from '../../common/protocol/boards-service'; +import { NotificationCenter } from '../notification-center'; +import { BoardsServiceProvider } from './boards-service-provider'; +import { BoardsListWidgetFrontendContribution } from './boards-widget-frontend-contribution'; + +/** + * Listens on `BoardsConfigChangeEvent`s, if a board is selected which does not + * have the corresponding core installed, it proposes the user to install the core. + */ +@injectable() +export class BoardsAutoInstaller implements FrontendApplicationContribution { + @inject(NotificationCenter) + private readonly notificationCenter: NotificationCenter; + @inject(MessageService) + private readonly messageService: MessageService; + @inject(NotificationManager) + private readonly notificationManager: NotificationManager; + @inject(BoardsService) + private readonly boardsService: BoardsService; + @inject(BoardsServiceProvider) + private readonly boardsServiceProvider: BoardsServiceProvider; + @inject(ResponseServiceClient) + private readonly responseService: ResponseServiceClient; + @inject(BoardsListWidgetFrontendContribution) + private readonly boardsManagerWidgetContribution: BoardsListWidgetFrontendContribution; + + // Workaround for https://github.com/eclipse-theia/theia/issues/9349 + private readonly installNotificationInfos: Readonly<{ + boardName: string; + platformId: string; + notificationId: string; + }>[] = []; + private readonly toDispose = new DisposableCollection(); + + onStart(): void { + this.toDispose.pushAll([ + this.boardsServiceProvider.onBoardsConfigDidChange((event) => { + if (isBoardIdentifierChangeEvent(event)) { + this.ensureCoreExists(event.selectedBoard); + } + }), + this.notificationCenter.onPlatformDidInstall((event) => + this.clearAllNotificationForPlatform(event.item.id) + ), + ]); + this.boardsServiceProvider.ready.then(() => { + const { selectedBoard } = this.boardsServiceProvider.boardsConfig; + this.ensureCoreExists(selectedBoard); + }); + } + + private async findPlatformToInstall( + selectedBoard: BoardIdentifier + ): Promise { + const platformId = await this.findPlatformIdToInstall(selectedBoard); + if (!platformId) { + return undefined; + } + const id = serializePlatformIdentifier(platformId); + const platform = await this.boardsService.getBoardPackage({ id }); + if (!platform) { + console.warn(`Could not resolve platform for ID: ${id}`); + return undefined; + } + if (platform.installedVersion) { + return undefined; + } + return platform; + } + + private async findPlatformIdToInstall( + selectedBoard: BoardIdentifier + ): Promise { + const selectedBoardPlatformId = createPlatformIdentifier(selectedBoard); + // The board is installed or the FQBN is available from the `board list watch` for Arduino boards. The latter might change! + if (selectedBoardPlatformId) { + const installedPlatforms = + await this.boardsService.getInstalledPlatforms(); + const installedPlatformIds = installedPlatforms + .map((platform) => createPlatformIdentifier(platform.id)) + .filter(notEmpty); + if ( + installedPlatformIds.every( + (installedPlatformId) => + !platformIdentifierEquals( + installedPlatformId, + selectedBoardPlatformId + ) + ) + ) { + return selectedBoardPlatformId; + } + } else { + // IDE2 knows that selected board is not installed. Look for board `name` match in not yet installed platforms. + // The order should be correct when there is a board name collision (e.g. Arduino Nano RP2040 from Arduino Mbed OS Nano Boards, [DEPRECATED] Arduino Mbed OS Nano Boards). The CLI boosts the platforms, so picking the first name match should be fine. + const platforms = await this.boardsService.search({}); + for (const platform of platforms) { + // Ignore installed platforms + if (platform.installedVersion) { + continue; + } + if ( + platform.boards.some((board) => board.name === selectedBoard.name) + ) { + const platformId = createPlatformIdentifier(platform.id); + if (platformId) { + return platformId; + } + } + } + } + return undefined; + } + + private async ensureCoreExists( + selectedBoard: BoardIdentifier | undefined + ): Promise { + if (!selectedBoard) { + return; + } + const candidate = await this.findPlatformToInstall(selectedBoard); + if (!candidate) { + return; + } + const platformIdToInstall = candidate.id; + const selectedBoardName = selectedBoard.name; + if ( + this.installNotificationInfos.some( + ({ boardName, platformId }) => + platformIdToInstall === platformId && selectedBoardName === boardName + ) + ) { + // Already has a notification for the board with the same platform. Nothing to do. + return; + } + this.clearAllNotificationForPlatform(platformIdToInstall); + + const version = candidate.availableVersions[0] + ? `[v ${candidate.availableVersions[0]}]` + : ''; + const yes = nls.localize('vscode/extensionsUtils/yes', 'Yes'); + const message = nls.localize( + 'arduino/board/installNow', + '必须为当前选择的“{2}”板安装“{0}{1}”核心。您想现在安装吗?', + candidate.name, + version, + selectedBoard.name + ); + const notificationId = this.notificationId(message, InstallManually, yes); + this.installNotificationInfos.push({ + boardName: selectedBoardName, + platformId: platformIdToInstall, + notificationId, + }); + const answer = await this.messageService.info( + message, + InstallManually, + yes + ); + if (answer) { + const index = this.installNotificationInfos.findIndex( + ({ boardName, platformId }) => + platformIdToInstall === platformId && selectedBoardName === boardName + ); + if (index !== -1) { + this.installNotificationInfos.splice(index, 1); + } + if (answer === yes) { + await Installable.installWithProgress({ + installable: this.boardsService, + item: candidate, + messageService: this.messageService, + responseService: this.responseService, + version: candidate.availableVersions[0], + }); + return; + } + if (answer === InstallManually) { + this.boardsManagerWidgetContribution + .openView({ reveal: true }) + .then((widget) => + widget.refresh({ + query: candidate.name.toLocaleLowerCase(), + type: 'All', + }) + ); + } + } + } + + private clearAllNotificationForPlatform(predicatePlatformId: string): void { + // Discard all install notifications for the same platform. + const notificationsLength = this.installNotificationInfos.length; + for (let i = notificationsLength - 1; i >= 0; i--) { + const { notificationId, platformId } = this.installNotificationInfos[i]; + if (platformId === predicatePlatformId) { + this.installNotificationInfos.splice(i, 1); + this.notificationManager.clear(notificationId); + } + } + } + + private notificationId(message: string, ...actions: string[]): string { + return this.notificationManager['getMessageId']({ + text: message, + actions, + type: MessageType.Info, + }); + } +} diff --git a/arduino-ide-extension/src/browser/boards/boards-config-component.tsx b/arduino-ide-extension/src/browser/boards/boards-config-component.tsx new file mode 100644 index 000000000..e3a637d9c --- /dev/null +++ b/arduino-ide-extension/src/browser/boards/boards-config-component.tsx @@ -0,0 +1,345 @@ +import { DisposableCollection } from '@theia/core/lib/common/disposable'; +import { Event } from '@theia/core/lib/common/event'; +import { FrontendApplicationState } from '@theia/core/lib/common/frontend-application-state'; +import { nls } from '@theia/core/lib/common/nls'; +import React from '@theia/core/shared/react'; +import { EditBoardsConfigActionParams } from '../../common/protocol/board-list'; +import { + Board, + BoardIdentifier, + BoardWithPackage, + DetectedPort, + findMatchingPortIndex, + Port, + PortIdentifier, +} from '../../common/protocol/boards-service'; +import type { Defined } from '../../common/types'; +import { NotificationCenter } from '../notification-center'; +import { BoardsConfigDialogState } from './boards-config-dialog'; + +namespace BoardsConfigComponent { + export interface Props { + /** + * This is not the real config, it's only living in the dialog. Users can change it without update and can cancel any modifications. + */ + readonly boardsConfig: BoardsConfigDialogState; + readonly searchSet: BoardIdentifier[] | undefined; + readonly notificationCenter: NotificationCenter; + readonly appState: FrontendApplicationState; + readonly onFocusNodeSet: (element: HTMLElement | undefined) => void; + readonly onFilteredTextDidChangeEvent: Event< + Defined + >; + readonly onAppStateDidChange: Event; + readonly onBoardSelected: (board: BoardIdentifier) => void; + readonly onPortSelected: (port: PortIdentifier) => void; + readonly searchBoards: (query?: { + query?: string; + }) => Promise; + readonly ports: ( + predicate?: (port: DetectedPort) => boolean + ) => readonly DetectedPort[]; + } + + export interface State { + searchResults: Array; + showAllPorts: boolean; + query: string; + } +} + +class Item extends React.Component<{ + item: T; + label: string; + selected: boolean; + onClick: (item: T) => void; + missing?: boolean; + details?: string; + title?: string | ((item: T) => string); +}> { + override render(): React.ReactNode { + const { selected, label, missing, details, item } = this.props; + const classNames = ['item']; + if (selected) { + classNames.push('selected'); + } + if (missing === true) { + classNames.push('missing'); + } + let title = this.props.title ?? `${label}${!details ? '' : details}`; + if (typeof title === 'function') { + title = title(item); + } + return ( +
+
{label}
+ {!details ? '' :
{details}
} + {!selected ? ( + '' + ) : ( +
+ +
+ )} +
+ ); + } + + private readonly onClick = () => { + this.props.onClick(this.props.item); + }; +} + +export class BoardsConfigComponent extends React.Component< + BoardsConfigComponent.Props, + BoardsConfigComponent.State +> { + private readonly toDispose: DisposableCollection; + + constructor(props: BoardsConfigComponent.Props) { + super(props); + this.state = { + searchResults: [], + showAllPorts: false, + query: '', + }; + this.toDispose = new DisposableCollection(); + } + + override componentDidMount(): void { + this.toDispose.pushAll([ + this.props.onAppStateDidChange(async (state) => { + if (state === 'ready') { + const searchResults = await this.queryBoards({}); + this.setState({ searchResults }); + } + }), + this.props.notificationCenter.onPlatformDidInstall(() => + this.updateBoards(this.state.query) + ), + this.props.notificationCenter.onPlatformDidUninstall(() => + this.updateBoards(this.state.query) + ), + this.props.notificationCenter.onIndexUpdateDidComplete(() => + this.updateBoards(this.state.query) + ), + this.props.notificationCenter.onDaemonDidStart(() => + this.updateBoards(this.state.query) + ), + this.props.notificationCenter.onDaemonDidStop(() => + this.setState({ searchResults: [] }) + ), + this.props.onFilteredTextDidChangeEvent((query) => { + if (typeof query === 'string') { + this.setState({ query }, () => this.updateBoards(this.state.query)); + } + }), + ]); + } + + override componentWillUnmount(): void { + this.toDispose.dispose(); + } + + private readonly updateBoards = ( + eventOrQuery: React.ChangeEvent | string = '' + ) => { + const query = + typeof eventOrQuery === 'string' + ? eventOrQuery + : eventOrQuery.target.value.toLowerCase(); + this.setState({ query }); + this.queryBoards({ query }).then((searchResults) => + this.setState({ searchResults }) + ); + }; + + private readonly queryBoards = async ( + options: { query?: string } = {} + ): Promise> => { + const result = await this.props.searchBoards(options); + const { searchSet } = this.props; + if (searchSet) { + return result.filter((board) => + searchSet.some( + (restriction) => + restriction.fqbn === board.fqbn || restriction.name === board.fqbn + ) + ); + } + return result; + }; + + private readonly toggleFilterPorts = () => { + this.setState({ showAllPorts: !this.state.showAllPorts }); + }; + + private readonly selectPort = (selectedPort: PortIdentifier) => { + this.props.onPortSelected(selectedPort); + }; + + private readonly selectBoard = (selectedBoard: BoardWithPackage) => { + this.props.onBoardSelected(selectedBoard); + }; + + private readonly focusNodeSet = (element: HTMLElement | null) => { + this.props.onFocusNodeSet(element || undefined); + }; + + override render(): React.ReactNode { + return ( + <> + {this.renderContainer( + nls.localize('arduino/board/boards', 'boards'), + this.renderBoards.bind(this) + )} + {this.renderContainer( + nls.localize('arduino/board/ports', 'ports'), + this.renderPorts.bind(this), + this.renderPortsFooter.bind(this) + )} + + ); + } + + private renderContainer( + title: string, + contentRenderer: () => React.ReactNode, + footerRenderer?: () => React.ReactNode + ): React.ReactNode { + return ( +
+
+
{title}
+ {contentRenderer()} +
{footerRenderer ? footerRenderer() : ''}
+
+
+ ); + } + + private renderBoards(): React.ReactNode { + const { boardsConfig } = this.props; + const { searchResults, query } = this.state; + // Board names are not unique per core https://github.com/arduino/arduino-pro-ide/issues/262#issuecomment-661019560 + // It is tricky when the core is not yet installed, no FQBNs are available. + const distinctBoards = new Map(); + const toKey = ({ name, packageName, fqbn }: Board.Detailed) => + !!fqbn ? `${name}-${packageName}-${fqbn}` : `${name}-${packageName}`; + for (const board of Board.decorateBoards( + boardsConfig.selectedBoard, + searchResults + )) { + const key = toKey(board); + if (!distinctBoards.has(key)) { + distinctBoards.set(key, board); + } + } + const title = (board: Board.Detailed): string => { + const { details, manuallyInstalled } = board; + let label = board.name; + if (details) { + label += details; + } + if (manuallyInstalled) { + label += '(在项目文件夹中)'; + } + return label; + }; + + const boardsList = Array.from(distinctBoards.values()).map((board) => ( + + key={toKey(board)} + item={board} + label={board.name} + details={board.details} + selected={board.selected} + onClick={this.selectBoard} + missing={board.missing} + title={title} + /> + )); + + return ( + +
+ + +
+ {boardsList.length > 0 ? ( +
{boardsList}
+ ) : ( +
+ {nls.localize( + 'arduino/board/noBoardsFound', + 'No boards found for "{0}"', + query + )} +
+ )} +
+ ); + } + + private renderPorts(): React.ReactNode { + const predicate = this.state.showAllPorts ? undefined : Port.isVisiblePort; + const detectedPorts = this.props.ports(predicate); + const matchingIndex = findMatchingPortIndex( + this.props.boardsConfig.selectedPort, + detectedPorts + ); + return !detectedPorts.length ? ( +
+ {nls.localize('arduino/board/noPortsDiscovered', 'No ports discovered')} +
+ ) : ( +
+ {detectedPorts.map((detectedPort, index) => ( + + key={`${Port.keyOf(detectedPort.port)}`} + item={detectedPort.port} + label={Port.toString(detectedPort.port)} + selected={index === matchingIndex} + onClick={this.selectPort} + /> + ))} +
+ ); + } + + private renderPortsFooter(): React.ReactNode { + return ( +
+ +
+ ); + } +} diff --git a/arduino-ide-extension/src/browser/boards/boards-config-dialog.tsx b/arduino-ide-extension/src/browser/boards/boards-config-dialog.tsx new file mode 100644 index 000000000..9e2a90c91 --- /dev/null +++ b/arduino-ide-extension/src/browser/boards/boards-config-dialog.tsx @@ -0,0 +1,197 @@ +import { DialogError, DialogProps } from '@theia/core/lib/browser/dialogs'; +import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state'; +import { Emitter } from '@theia/core/lib/common/event'; +import { nls } from '@theia/core/lib/common/nls'; +import { deepClone } from '@theia/core/lib/common/objects'; +import type { Message } from '@theia/core/shared/@phosphor/messaging'; +import { + inject, + injectable, + postConstruct, +} from '@theia/core/shared/inversify'; +import React from '@theia/core/shared/react'; +import type { ReactNode } from '@theia/core/shared/react/index'; +import { EditBoardsConfigActionParams } from '../../common/protocol/board-list'; +import { + BoardIdentifier, + BoardsConfig, + BoardWithPackage, + DetectedPort, + emptyBoardsConfig, + PortIdentifier, +} from '../../common/protocol/boards-service'; +import type { Defined } from '../../common/types'; +import { NotificationCenter } from '../notification-center'; +import { ReactDialog } from '../theia/dialogs/dialogs'; +import { BoardsConfigComponent } from './boards-config-component'; +import { BoardsServiceProvider } from './boards-service-provider'; + +@injectable() +export class BoardsConfigDialogProps extends DialogProps { } + +export type BoardsConfigDialogState = Omit & { + selectedBoard: BoardsConfig['selectedBoard'] | BoardWithPackage; +}; + +@injectable() +export class BoardsConfigDialog extends ReactDialog { + @inject(BoardsServiceProvider) + private readonly boardsServiceProvider: BoardsServiceProvider; + @inject(NotificationCenter) + private readonly notificationCenter: NotificationCenter; + @inject(FrontendApplicationStateService) + private readonly appStateService: FrontendApplicationStateService; + + private readonly onFilterTextDidChangeEmitter: Emitter< + Defined + >; + private readonly onBoardSelected = (board: BoardWithPackage): void => { + this._boardsConfig.selectedBoard = board; + this.update(); + }; + private readonly onPortSelected = (port: PortIdentifier): void => { + this._boardsConfig.selectedPort = port; + this.update(); + }; + private readonly setFocusNode = (element: HTMLElement | undefined): void => { + this.focusNode = element; + }; + private readonly searchBoards = (options: { + query?: string; + }): Promise => { + return this.boardsServiceProvider.searchBoards(options); + }; + private readonly ports = ( + predicate?: (port: DetectedPort) => boolean + ): readonly DetectedPort[] => { + return this.boardsServiceProvider.boardList.ports(predicate); + }; + private _boardsConfig: BoardsConfigDialogState; + /** + * When the dialog's boards result set is limited to a subset of boards when searching, this field is set. + */ + private _searchSet: BoardIdentifier[] | undefined; + private focusNode: HTMLElement | undefined; + + constructor( + @inject(BoardsConfigDialogProps) + protected override readonly props: BoardsConfigDialogProps + ) { + super({ ...props, maxWidth: 500 }); + this.node.id = 'select-board-dialog-container'; + this.contentNode.classList.add('select-board-dialog'); + this.appendCloseButton( + nls.localize('vscode/issueMainService/cancel', '取消') + ); + this.appendAcceptButton(nls.localize('vscode/issueMainService/ok', '确定')); + this._boardsConfig = emptyBoardsConfig(); + this.onFilterTextDidChangeEmitter = new Emitter(); + } + + @postConstruct() + protected init(): void { + this.boardsServiceProvider.onBoardListDidChange(() => { + this._boardsConfig = deepClone(this.boardsServiceProvider.boardsConfig); + this.update(); + }); + this._boardsConfig = deepClone(this.boardsServiceProvider.boardsConfig); + } + + override async open( + params?: EditBoardsConfigActionParams + ): Promise { + this._searchSet = undefined; + this._boardsConfig.selectedBoard = + this.boardsServiceProvider.boardsConfig.selectedBoard; + this._boardsConfig.selectedPort = + this.boardsServiceProvider.boardsConfig.selectedPort; + if (params) { + if (typeof params.query === 'string') { + this.onFilterTextDidChangeEmitter.fire(params.query); + } + if (params.portToSelect) { + this._boardsConfig.selectedPort = params.portToSelect; + } + if (params.boardToSelect) { + this._boardsConfig.selectedBoard = params.boardToSelect; + } + if (params.searchSet) { + this._searchSet = params.searchSet.slice(); + } + } + return super.open(); + } + + protected override onAfterAttach(msg: Message): void { + super.onAfterAttach(msg); + this.update(); + } + + protected override render(): ReactNode { + return ( + <> +
+
+
{'如果要上传项目,请选择开发板和端口。'}
+
+ {nls.localize( + 'arduino/board/configDialog2', + 'If you only select a Board you will be able to compile, but not to upload your sketch.' + )} +
+
+
+
+
+ +
+
+ + ); + } + + protected override onActivateRequest(msg: Message): void { + super.onActivateRequest(msg); + if (this.focusNode instanceof HTMLInputElement) { + this.focusNode.select(); + } + (this.focusNode || this.node).focus(); + } + + protected override handleEnter(event: KeyboardEvent): boolean | void { + if (event.target instanceof HTMLTextAreaElement) { + return false; + } + } + + protected override isValid(value: BoardsConfig): DialogError { + if (!value.selectedBoard) { + if (value.selectedPort) { + return nls.localize( + 'arduino/board/pleasePickBoard', + 'Please pick a board connected to the port you have selected.' + ); + } + return false; + } + return ''; + } + + get value(): BoardsConfigDialogState { + return this._boardsConfig; + } +} diff --git a/arduino-ide-extension/src/browser/boards/boards-data-store.ts b/arduino-ide-extension/src/browser/boards/boards-data-store.ts new file mode 100644 index 000000000..28ebd917f --- /dev/null +++ b/arduino-ide-extension/src/browser/boards/boards-data-store.ts @@ -0,0 +1,373 @@ +import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application'; +import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state'; +import { StorageService } from '@theia/core/lib/browser/storage-service'; +import type { + Command, + CommandContribution, + CommandRegistry, +} from '@theia/core/lib/common/command'; +import { DisposableCollection } from '@theia/core/lib/common/disposable'; +import { Emitter, Event } from '@theia/core/lib/common/event'; +import { ILogger } from '@theia/core/lib/common/logger'; +import { deepClone, deepFreeze } from '@theia/core/lib/common/objects'; +import type { Mutable } from '@theia/core/lib/common/types'; +import { inject, injectable, named } from '@theia/core/shared/inversify'; +import { + BoardDetails, + BoardsService, + ConfigOption, + ConfigValue, + Programmer, + isBoardIdentifierChangeEvent, + isProgrammer, +} from '../../common/protocol'; +import { notEmpty } from '../../common/utils'; +import type { + StartupTask, + StartupTaskProvider, +} from '../../electron-common/startup-task'; +import { NotificationCenter } from '../notification-center'; +import { BoardsServiceProvider } from './boards-service-provider'; + +@injectable() +export class BoardsDataStore + implements + FrontendApplicationContribution, + StartupTaskProvider, + CommandContribution { + @inject(ILogger) + @named('store') + private readonly logger: ILogger; + @inject(BoardsService) + private readonly boardsService: BoardsService; + @inject(NotificationCenter) + private readonly notificationCenter: NotificationCenter; + // When `@theia/workspace` is part of the application, the workspace-scoped storage service is the default implementation, and the `StorageService` symbol must be used for the injection. + // https://github.com/eclipse-theia/theia/blob/ba3722b04ff91eb6a4af6a571c9e263c77cdd8b5/packages/workspace/src/browser/workspace-frontend-module.ts#L97-L98 + // In other words, store the data (such as the board configs) per sketch, not per IDE2 installation. https://github.com/arduino/arduino-ide/issues/2240 + @inject(StorageService) + private readonly storageService: StorageService; + @inject(BoardsServiceProvider) + private readonly boardsServiceProvider: BoardsServiceProvider; + @inject(FrontendApplicationStateService) + private readonly appStateService: FrontendApplicationStateService; + + private readonly onDidChangeEmitter = + new Emitter(); + private readonly toDispose = new DisposableCollection( + this.onDidChangeEmitter + ); + private _selectedBoardData: BoardsDataStoreChange | undefined; + + onStart(): void { + this.toDispose.pushAll([ + this.boardsServiceProvider.onBoardsConfigDidChange((event) => { + if (isBoardIdentifierChangeEvent(event)) { + this.updateSelectedBoardData(event.selectedBoard?.fqbn); + } + }), + this.notificationCenter.onPlatformDidInstall(async ({ item }) => { + const boardsWithFqbn = item.boards + .map(({ fqbn }) => fqbn) + .filter(notEmpty); + const changes: BoardsDataStoreChange[] = []; + for (const fqbn of boardsWithFqbn) { + const key = this.getStorageKey(fqbn); + const storedData = + await this.storageService.getData(key); + if (!storedData) { + // if no previously value is available for the board, do not update the cache + continue; + } + const details = await this.loadBoardDetails(fqbn); + if (details) { + const data = createDataStoreEntry(details); + await this.storageService.setData(key, data); + changes.push({ fqbn, data }); + } + } + if (changes.length) { + this.fireChanged(...changes); + } + }), + this.onDidChange((event) => { + const selectedFqbn = + this.boardsServiceProvider.boardsConfig.selectedBoard?.fqbn; + if (event.changes.find((change) => change.fqbn === selectedFqbn)) { + this.updateSelectedBoardData(selectedFqbn); + } + }), + ]); + + Promise.all([ + this.boardsServiceProvider.ready, + this.appStateService.reachedState('ready'), + ]).then(() => + this.updateSelectedBoardData( + this.boardsServiceProvider.boardsConfig.selectedBoard?.fqbn + ) + ); + } + + private async getSelectedBoardData( + fqbn: string | undefined + ): Promise { + if (!fqbn) { + return undefined; + } else { + const data = await this.getData(fqbn); + if (data === BoardsDataStore.Data.EMPTY) { + return undefined; + } + return { fqbn, data }; + } + } + + private async updateSelectedBoardData( + fqbn: string | undefined + ): Promise { + this._selectedBoardData = await this.getSelectedBoardData(fqbn); + } + + onStop(): void { + this.toDispose.dispose(); + } + + registerCommands(registry: CommandRegistry): void { + registry.registerCommand(USE_INHERITED_DATA, { + execute: async (arg: unknown) => { + if (isBoardsDataStoreChange(arg)) { + await this.setData(arg); + this.fireChanged(arg); + } + }, + }); + } + + tasks(): StartupTask[] { + if (!this._selectedBoardData) { + return []; + } + return [ + { + command: USE_INHERITED_DATA.id, + args: [this._selectedBoardData], + }, + ]; + } + + get onDidChange(): Event { + return this.onDidChangeEmitter.event; + } + + async appendConfigToFqbn( + fqbn: string | undefined + ): Promise { + if (!fqbn) { + return undefined; + } + const { configOptions } = await this.getData(fqbn); + return ConfigOption.decorate(fqbn, configOptions); + } + + async getData(fqbn: string | undefined): Promise { + if (!fqbn) { + return BoardsDataStore.Data.EMPTY; + } + + const key = this.getStorageKey(fqbn); + const storedData = await this.storageService.getData< + BoardsDataStore.Data | undefined + >(key, undefined); + if (BoardsDataStore.Data.is(storedData)) { + return storedData; + } + + const boardDetails = await this.loadBoardDetails(fqbn); + if (!boardDetails) { + return BoardsDataStore.Data.EMPTY; + } + + const data = createDataStoreEntry(boardDetails); + await this.storageService.setData(key, data); + return data; + } + + async selectProgrammer({ + fqbn, + selectedProgrammer, + }: { + fqbn: string; + selectedProgrammer: Programmer; + }): Promise { + const storedData = deepClone(await this.getData(fqbn)); + const { programmers } = storedData; + if (!programmers.find((p) => Programmer.equals(selectedProgrammer, p))) { + return false; + } + + const data = { ...storedData, selectedProgrammer }; + await this.setData({ fqbn, data }); + this.fireChanged({ fqbn, data }); + return true; + } + + async selectConfigOption({ + fqbn, + option, + selectedValue, + }: { + fqbn: string; + option: string; + selectedValue: string; + }): Promise { + const data = deepClone(await this.getData(fqbn)); + const { configOptions } = data; + const configOption = configOptions.find((c) => c.option === option); + if (!configOption) { + return false; + } + let updated = false; + for (const value of configOption.values) { + const mutable: Mutable = value; + if (mutable.value === selectedValue) { + mutable.selected = true; + updated = true; + } else { + mutable.selected = false; + } + } + if (!updated) { + return false; + } + await this.setData({ fqbn, data }); + this.fireChanged({ fqbn, data }); + return true; + } + + protected async setData(change: BoardsDataStoreChange): Promise { + const { fqbn, data } = change; + const key = this.getStorageKey(fqbn); + return this.storageService.setData(key, data); + } + + protected getStorageKey(fqbn: string): string { + return `.arduinoIDE-configOptions-${fqbn}`; + } + + async loadBoardDetails(fqbn: string): Promise { + try { + const details = await this.boardsService.getBoardDetails({ fqbn }); + return details; + } catch (err) { + if ( + err instanceof Error && + err.message.includes('loading board data') && + err.message.includes('is not installed') + ) { + this.logger.warn( + `The boards package is not installed for board with FQBN: ${fqbn}` + ); + } else { + this.logger.error( + `An unexpected error occurred while retrieving the board details for ${fqbn}.`, + err + ); + } + return undefined; + } + } + + protected fireChanged(...changes: BoardsDataStoreChange[]): void { + this.onDidChangeEmitter.fire({ changes }); + } +} + +export namespace BoardsDataStore { + export interface Data { + readonly configOptions: ConfigOption[]; + readonly programmers: Programmer[]; + readonly selectedProgrammer?: Programmer; + readonly defaultProgrammerId?: string; + } + export namespace Data { + export const EMPTY: Data = deepFreeze({ + configOptions: [], + programmers: [], + }); + + export function is(arg: unknown): arg is Data { + return ( + typeof arg === 'object' && + arg !== null && + Array.isArray((arg).configOptions) && + Array.isArray((arg).programmers) && + ((arg).selectedProgrammer === undefined || + isProgrammer((arg).selectedProgrammer)) && + ((arg).defaultProgrammerId === undefined || + typeof (arg).defaultProgrammerId === 'string') + ); + } + } +} + +export function isEmptyData(data: BoardsDataStore.Data): boolean { + return ( + Boolean(!data.configOptions.length) && + Boolean(!data.programmers.length) && + Boolean(!data.selectedProgrammer) && + Boolean(!data.defaultProgrammerId) + ); +} + +export function findDefaultProgrammer( + programmers: readonly Programmer[], + defaultProgrammerId: string | undefined | BoardsDataStore.Data +): Programmer | undefined { + if (!defaultProgrammerId) { + return undefined; + } + const id = + typeof defaultProgrammerId === 'string' + ? defaultProgrammerId + : defaultProgrammerId.defaultProgrammerId; + return programmers.find((p) => p.id === id); +} +function createDataStoreEntry(details: BoardDetails): BoardsDataStore.Data { + const configOptions = details.configOptions.slice(); + const programmers = details.programmers.slice(); + const { defaultProgrammerId } = details; + const selectedProgrammer = findDefaultProgrammer( + programmers, + defaultProgrammerId + ); + const data = { + configOptions, + programmers, + ...(selectedProgrammer ? { selectedProgrammer } : {}), + ...(defaultProgrammerId ? { defaultProgrammerId } : {}), + }; + return data; +} + +export interface BoardsDataStoreChange { + readonly fqbn: string; + readonly data: BoardsDataStore.Data; +} + +function isBoardsDataStoreChange(arg: unknown): arg is BoardsDataStoreChange { + return ( + typeof arg === 'object' && + arg !== null && + typeof (arg).fqbn === 'string' && + BoardsDataStore.Data.is((arg).data) + ); +} + +export interface BoardsDataStoreChangeEvent { + readonly changes: readonly BoardsDataStoreChange[]; +} + +const USE_INHERITED_DATA: Command = { + id: 'lingzhi-use-inherited-boards-data', +}; diff --git a/arduino-ide-extension/src/browser/boards/boards-list-widget.ts b/arduino-ide-extension/src/browser/boards/boards-list-widget.ts new file mode 100644 index 000000000..d64e77e4c --- /dev/null +++ b/arduino-ide-extension/src/browser/boards/boards-list-widget.ts @@ -0,0 +1,91 @@ +import { + inject, + injectable, + postConstruct, +} from '@theia/core/shared/inversify'; +import { + BoardSearch, + BoardsPackage, + BoardsService, +} from '../../common/protocol/boards-service'; +import { ListWidget } from '../widgets/component-list/list-widget'; +import { ListItemRenderer } from '../widgets/component-list/list-item-renderer'; +import { nls } from '@theia/core/lib/common'; +import { BoardsFilterRenderer } from '../widgets/component-list/filter-renderer'; + +@injectable() +export class BoardsListWidget extends ListWidget { + static WIDGET_ID = 'boards-list-widget'; + static WIDGET_LABEL = nls.localize('arduino/boardsManager', 'Boards Manager'); + + constructor( + @inject(BoardsService) service: BoardsService, + @inject(ListItemRenderer) itemRenderer: ListItemRenderer, + @inject(BoardsFilterRenderer) filterRenderer: BoardsFilterRenderer + ) { + super({ + id: BoardsListWidget.WIDGET_ID, + label: BoardsListWidget.WIDGET_LABEL, + iconClass: 'fa lingzhi-circuitcomposer', + searchable: service, + installable: service, + itemLabel: (item: BoardsPackage) => item.name, + itemRenderer, + filterRenderer, + defaultSearchOptions: { query: '', type: 'All' }, + }); + } + + @postConstruct() + protected override init(): void { + super.init(); + this.toDispose.pushAll([ + this.notificationCenter.onPlatformDidInstall(() => + this.refresh(undefined) + ), + this.notificationCenter.onPlatformDidUninstall(() => + this.refresh(undefined) + ), + ]); + } + + protected override async install({ + item, + progressId, + version, + }: { + item: BoardsPackage; + progressId: string; + version: string; + }): Promise { + await super.install({ item, progressId, version }); + this.messageService.info( + nls.localize( + 'arduino/board/succesfullyInstalledPlatform', + '成功安装平台{0}:{1}', + item.name, + version + ), + { timeout: 3000 } + ); + } + + protected override async uninstall({ + item, + progressId, + }: { + item: BoardsPackage; + progressId: string; + }): Promise { + await super.uninstall({ item, progressId }); + this.messageService.info( + nls.localize( + 'arduino/board/succesfullyUninstalledPlatform', + '成功卸载平台{0}:{1}', + item.name, + item.installedVersion! + ), + { timeout: 3000 } + ); + } +} diff --git a/arduino-ide-extension/src/browser/boards/boards-service-provider.ts b/arduino-ide-extension/src/browser/boards/boards-service-provider.ts new file mode 100644 index 000000000..bba86711d --- /dev/null +++ b/arduino-ide-extension/src/browser/boards/boards-service-provider.ts @@ -0,0 +1,655 @@ +import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application'; +import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state'; +import { StorageService } from '@theia/core/lib/browser/storage-service'; +import { + Command, + CommandContribution, + CommandRegistry, + CommandService, +} from '@theia/core/lib/common/command'; +import type { Disposable } from '@theia/core/lib/common/disposable'; +import { Emitter } from '@theia/core/lib/common/event'; +import { ILogger } from '@theia/core/lib/common/logger'; +import { MessageService } from '@theia/core/lib/common/message-service'; +import { nls } from '@theia/core/lib/common/nls'; +import { Deferred } from '@theia/core/lib/common/promise-util'; +import type { Mutable } from '@theia/core/lib/common/types'; +import { inject, injectable, optional } from '@theia/core/shared/inversify'; +import { + OutputChannel, + OutputChannelManager, +} from '@theia/output/lib/browser/output-channel'; +import { + BoardIdentifier, + boardIdentifierEquals, + BoardsConfig, + BoardsConfigChangeEvent, + BoardsPackage, + BoardsService, + BoardUserField, + BoardWithPackage, + DetectedPorts, + emptyBoardsConfig, + isBoardIdentifier, + isBoardIdentifierChangeEvent, + isPortIdentifier, + isPortIdentifierChangeEvent, + Port, + PortIdentifier, + portIdentifierEquals, + serializePlatformIdentifier, +} from '../../common/protocol'; +import { + BoardList, + BoardListHistory, + createBoardList, + EditBoardsConfigActionParams, + isBoardListHistory, + SelectBoardsConfigActionParams, +} from '../../common/protocol/board-list'; +import type { Defined } from '../../common/types'; +import type { + StartupTask, + StartupTaskProvider, +} from '../../electron-common/startup-task'; +import { NotificationCenter } from '../notification-center'; + +const boardListHistoryStorageKey = 'arduino-ide:boardListHistory'; +const selectedPortStorageKey = 'arduino-ide:selectedPort'; +const selectedBoardStorageKey = 'arduino-ide:selectedBoard'; + +type UpdateBoardsConfigReason = + /** + * Restore previous state at IDE startup. + */ + | 'restore' + /** + * The board and the optional port were changed from the dialog. + */ + | 'dialog' + /** + * The board and the port were updated from the board select toolbar. + */ + | 'toolbar' + /** + * The board and port configuration was inherited from another window. + */ + | 'inherit'; + +interface RefreshBoardListParams { + detectedPorts?: DetectedPorts; + boardsConfig?: BoardsConfig; + boardListHistory?: BoardListHistory; +} + +export type UpdateBoardsConfigParams = + | BoardIdentifier + /** + * `'unset-board'` is special case when a non installed board is selected (no FQBN), the platform is installed, + * but there is no way to determine the FQBN from the previous partial data, and IDE2 unsets the board. + */ + | 'unset-board' + | PortIdentifier + | (Readonly> & + Readonly<{ reason?: UpdateBoardsConfigReason }>); + +type HistoryDidNotChange = undefined; +type HistoryDidDelete = Readonly<{ [portKey: string]: undefined }>; +type HistoryDidUpdate = Readonly<{ [portKey: string]: BoardIdentifier }>; +type BoardListHistoryUpdateResult = + | HistoryDidNotChange + | HistoryDidDelete + | HistoryDidUpdate; + +type BoardToSelect = BoardIdentifier | undefined | 'ignore-board'; +type PortToSelect = PortIdentifier | undefined | 'ignore-port'; + +interface UpdateBoardListHistoryParams { + readonly portToSelect: PortToSelect; + readonly boardToSelect: BoardToSelect; +} + +interface UpdateBoardsDataParams { + readonly boardToSelect: BoardToSelect; + readonly reason?: UpdateBoardsConfigReason; +} + +export interface SelectBoardsConfigAction { + (params: SelectBoardsConfigActionParams): void; +} + +export interface EditBoardsConfigAction { + (params?: EditBoardsConfigActionParams): void; +} + +export interface BoardListUIActions { + /** + * Sets the frontend's port and board configuration according to the params. + */ + readonly select: SelectBoardsConfigAction; + /** + * Opens up the boards config dialog with the port and (optional) board to select in the dialog. + * Calling this function does not immediately change the frontend's port and board config, but + * preselects items in the dialog. + */ + readonly edit: EditBoardsConfigAction; +} +export type BoardListUI = BoardList & BoardListUIActions; + +@injectable() +export class BoardListDumper implements Disposable { + @inject(OutputChannelManager) + private readonly outputChannelManager: OutputChannelManager; + + private outputChannel: OutputChannel | undefined; + + dump(boardList: BoardList): void { + if (!this.outputChannel) { + this.outputChannel = + this.outputChannelManager.getChannel('Developer (LinZhi)'); + } + this.outputChannel.show({ preserveFocus: true }); + this.outputChannel.append(boardList.toString() + '\n'); + } + + dispose(): void { + this.outputChannel?.dispose(); + } +} + +@injectable() +export class BoardsServiceProvider + implements + FrontendApplicationContribution, + StartupTaskProvider, + CommandContribution { + @inject(ILogger) + private readonly logger: ILogger; + @inject(MessageService) + private readonly messageService: MessageService; + @inject(BoardsService) + private readonly boardsService: BoardsService; + @inject(CommandService) + private readonly commandService: CommandService; + @inject(StorageService) + private readonly storageService: StorageService; + @inject(NotificationCenter) + private readonly notificationCenter: NotificationCenter; + @inject(FrontendApplicationStateService) + private readonly appStateService: FrontendApplicationStateService; + @optional() + @inject(BoardListDumper) + private readonly boardListDumper?: BoardListDumper; + + private _boardsConfig = emptyBoardsConfig(); + private _detectedPorts: DetectedPorts = {}; + private _boardList = this.createBoardListUI(createBoardList({})); + private _boardListHistory: Mutable = {}; + private _ready = new Deferred(); + + private readonly boardsConfigDidChangeEmitter = + new Emitter(); + readonly onBoardsConfigDidChange = this.boardsConfigDidChangeEmitter.event; + + private readonly boardListDidChangeEmitter = new Emitter(); + /** + * Emits an event on board config (port or board) change, and when the discovery (`board list --watch`) detected any changes. + */ + readonly onBoardListDidChange = this.boardListDidChangeEmitter.event; + + onStart(): void { + this.notificationCenter.onDetectedPortsDidChange(({ detectedPorts }) => + this.refreshBoardList({ detectedPorts }) + ); + this.notificationCenter.onPlatformDidInstall((event) => + this.maybeUpdateSelectedBoard(event) + ); + this.appStateService + .reachedState('ready') + .then(async () => { + const [detectedPorts, storedState] = await Promise.all([ + this.boardsService.getDetectedPorts(), + this.restoreState(), + ]); + const { selectedBoard, selectedPort, boardListHistory } = storedState; + const options: RefreshBoardListParams = { + boardListHistory, + detectedPorts, + }; + // If either the port or the board is set, restore it. Otherwise, do not restore nothing. + // It might override the inherited boards config from the other window on File > New Sketch + if (selectedBoard || selectedPort) { + options.boardsConfig = { selectedBoard, selectedPort }; + } + this.refreshBoardList(options); + this._ready.resolve(); + }) + .finally(() => this._ready.resolve()); + } + + onStop(): void { + this.boardListDumper?.dispose(); + } + + registerCommands(registry: CommandRegistry): void { + registry.registerCommand(USE_INHERITED_CONFIG, { + execute: ( + boardsConfig: BoardsConfig, + boardListHistory: BoardListHistory + ) => { + if (boardListHistory) { + this._boardListHistory = boardListHistory; + } + this.update({ boardsConfig }, 'inherit'); + }, + }); + if (this.boardListDumper) { + registry.registerCommand(DUMP_BOARD_LIST, { + execute: () => this.boardListDumper?.dump(this._boardList), + }); + } + registry.registerCommand(CLEAR_BOARD_LIST_HISTORY, { + execute: () => { + this.refreshBoardList({ boardListHistory: {} }); + this.setData(boardListHistoryStorageKey, undefined); + }, + }); + registry.registerCommand(CLEAR_BOARDS_CONFIG, { + execute: () => { + this.refreshBoardList({ boardsConfig: emptyBoardsConfig() }); + Promise.all([ + this.setData(selectedPortStorageKey, undefined), + this.setData(selectedBoardStorageKey, undefined), + ]); + }, + }); + } + + tasks(): StartupTask[] { + return [ + { + command: USE_INHERITED_CONFIG.id, + args: [this._boardsConfig, this._boardListHistory], + }, + ]; + } + + private refreshBoardList(params?: RefreshBoardListParams): void { + if (params?.detectedPorts) { + this._detectedPorts = params.detectedPorts; + } + if (params?.boardsConfig) { + this._boardsConfig = params.boardsConfig; + } + if (params?.boardListHistory) { + this._boardListHistory = params.boardListHistory; + } + const boardList = createBoardList( + this._detectedPorts, + this._boardsConfig, + this._boardListHistory + ); + this._boardList = this.createBoardListUI(boardList); + this.boardListDidChangeEmitter.fire(this._boardList); + } + + private createBoardListUI(boardList: BoardList): BoardListUI { + return Object.assign(boardList, { + select: this.onBoardsConfigSelect.bind(this), + edit: this.onBoardsConfigEdit.bind(this), + }); + } + + private onBoardsConfigSelect(params: SelectBoardsConfigActionParams): void { + this.updateConfig({ ...params, reason: 'toolbar' }); + } + + private async onBoardsConfigEdit( + params?: EditBoardsConfigActionParams + ): Promise { + const boardsConfig = await this.commandService.executeCommand< + BoardsConfig | undefined + >('lingzhi-open-boards-dialog', params); + if (boardsConfig) { + this.update({ boardsConfig }, 'dialog'); + } + } + + private update( + params: RefreshBoardListParams, + reason?: UpdateBoardsConfigReason + ): void { + const { boardsConfig } = params; + if (!boardsConfig) { + return; + } + const { selectedBoard, selectedPort } = boardsConfig; + if (selectedBoard && selectedPort) { + this.updateConfig({ + selectedBoard, + selectedPort, + reason, + }); + } else if (selectedBoard) { + this.updateConfig(selectedBoard); + } else if (selectedPort) { + this.updateConfig(selectedPort); + } + } + + updateConfig(params: UpdateBoardsConfigParams): boolean { + const previousSelectedBoard = this._boardsConfig.selectedBoard; + const previousSelectedPort = this._boardsConfig.selectedPort; + const boardToSelect = this.getBoardToSelect(params); + const portToSelect = this.getPortToSelect(params); + const reason = this.getUpdateReason(params); + + const boardDidChange = + boardToSelect !== 'ignore-board' && + !boardIdentifierEquals(boardToSelect, previousSelectedBoard); + const portDidChange = + portToSelect !== 'ignore-port' && + !portIdentifierEquals(portToSelect, previousSelectedPort); + const boardDidChangeEvent = boardDidChange + ? { selectedBoard: boardToSelect, previousSelectedBoard } + : undefined; + const portDidChangeEvent = portDidChange + ? { selectedPort: portToSelect, previousSelectedPort } + : undefined; + + let event: BoardsConfigChangeEvent | undefined = boardDidChangeEvent; + if (portDidChangeEvent) { + if (event) { + event = { + ...event, + ...portDidChangeEvent, + }; + } else { + event = portDidChangeEvent; + } + } + if (!event) { + return false; + } + + this.maybeUpdateBoardListHistory({ portToSelect, boardToSelect }); + this.maybeUpdateBoardsData({ boardToSelect, reason }); + + if (isBoardIdentifierChangeEvent(event)) { + this._boardsConfig.selectedBoard = event.selectedBoard; + } + if (isPortIdentifierChangeEvent(event)) { + this._boardsConfig.selectedPort = event.selectedPort; + } + + this.boardsConfigDidChangeEmitter.fire(event); + this.refreshBoardList(); + this.saveState(); + return true; + } + + private getBoardToSelect(params: UpdateBoardsConfigParams): BoardToSelect { + if (isPortIdentifier(params)) { + return 'ignore-board'; + } + if (params === 'unset-board') { + return undefined; + } + return isBoardIdentifier(params) ? params : params.selectedBoard; + } + + private getPortToSelect( + params: UpdateBoardsConfigParams + ): Exclude { + if (isBoardIdentifier(params) || params === 'unset-board') { + return 'ignore-port'; + } + return isPortIdentifier(params) ? params : params.selectedPort; + } + + private getUpdateReason( + params: UpdateBoardsConfigParams + ): UpdateBoardsConfigReason | undefined { + if ( + isBoardIdentifier(params) || + isPortIdentifier(params) || + params === 'unset-board' + ) { + return undefined; + } + return params.reason; + } + + get ready(): Promise { + return this._ready.promise; + } + + get boardsConfig(): BoardsConfig { + return this._boardsConfig; + } + + get boardList(): BoardListUI { + return this._boardList; + } + + get detectedPorts(): DetectedPorts { + return this._detectedPorts; + } + + async searchBoards({ + query, + }: { + query?: string; + cores?: string[]; + }): Promise { + const boards = await this.boardsService.searchBoards({ query }); + return boards; + } + + async selectedBoardUserFields(): Promise { + if (!this._boardsConfig.selectedBoard) { + return []; + } + const fqbn = this._boardsConfig.selectedBoard.fqbn; + if (!fqbn) { + return []; + } + // Protocol must be set to `default` when uploading without a port selected: + // https://arduino.github.io/arduino-cli/dev/platform-specification/#sketch-upload-configuration + const protocol = this._boardsConfig.selectedPort?.protocol || 'default'; + return await this.boardsService.getBoardUserFields({ fqbn, protocol }); + } + + private async maybeUpdateSelectedBoard(platformDidInstallEvent: { + item: BoardsPackage; + }): Promise { + const { selectedBoard } = this._boardsConfig; + if ( + selectedBoard && + !selectedBoard.fqbn && + BoardWithPackage.is(selectedBoard) + ) { + const selectedBoardPlatformId = serializePlatformIdentifier( + selectedBoard.packageId + ); + if (selectedBoardPlatformId === platformDidInstallEvent.item.id) { + const installedSelectedBoard = platformDidInstallEvent.item.boards.find( + (board) => board.name === selectedBoard.name + ); + // if the board can be found by its name after the install event select it. otherwise unselect it + // historical hint: https://github.com/arduino/arduino-ide/blob/144df893d0dafec64a26565cf912a98f32572da9/arduino-ide-extension/src/browser/boards/boards-service-provider.ts#L289-L320 + this.updateConfig( + installedSelectedBoard ? installedSelectedBoard : 'unset-board' + ); + if (!installedSelectedBoard) { + // const yes = nls.localize('vscode/extensionsUtils/yes', 'Yes'); + // const answer = await this.messageService.warn( + // nls.localize( + // 'arduino/board/couldNotFindPreviouslySelected', + // '无法在安装的平台‘{1}’中找到先前选择的‘{0}’板。请手动重新选择要使用的单板。您现在要重新选择吗?', + // selectedBoard.name, + // platformDidInstallEvent.item.name + // ), + // nls.localize('arduino/board/reselectLater', '重新选择'), + // yes + // ); + // if (answer === yes) { + // this.onBoardsConfigEdit({ + // query: selectedBoard.name, + // portToSelect: this._boardsConfig.selectedPort, + // }); + // } + } + } + } + } + + private maybeUpdateBoardListHistory( + params: UpdateBoardListHistoryParams + ): BoardListHistoryUpdateResult { + const { portToSelect, boardToSelect } = params; + const selectedPort = isPortIdentifier(portToSelect) + ? portToSelect + : portToSelect === 'ignore-port' + ? this._boardsConfig.selectedPort + : undefined; + const selectedBoard = isBoardIdentifier(boardToSelect) + ? boardToSelect + : boardToSelect === 'ignore-board' + ? this._boardsConfig.selectedBoard + : undefined; + if (selectedBoard && selectedPort) { + const match = this.boardList.items.find( + (item) => + portIdentifierEquals(item.port, selectedPort) && + item.board && + boardIdentifierEquals(item.board, selectedBoard) + ); + const portKey = Port.keyOf(selectedPort); + if (match) { + // When board `B` is detected on port `P` and saving `B` on `P`, remove the entry instead! + delete this._boardListHistory[portKey]; + } else { + this._boardListHistory[portKey] = selectedBoard; + } + if (match) { + return { [portKey]: undefined }; + } + return { [portKey]: selectedBoard }; + } + return undefined; + } + + private maybeUpdateBoardsData(params: UpdateBoardsDataParams): void { + const { boardToSelect, reason } = params; + if ( + boardToSelect && + boardToSelect !== 'ignore-board' && + boardToSelect.fqbn && + (reason === 'toolbar' || reason === 'inherit') + ) { + const [, , , ...rest] = boardToSelect.fqbn.split(':'); + if (rest.length) { + // https://github.com/arduino/arduino-ide/pull/2113 + // TODO: save update data store if reason is toolbar and the FQBN has options + } + } + } + + private async saveState(): Promise { + const { selectedBoard, selectedPort } = this.boardsConfig; + await Promise.all([ + this.setData( + selectedBoardStorageKey, + selectedBoard ? JSON.stringify(selectedBoard) : undefined + ), + this.setData( + selectedPortStorageKey, + selectedPort ? JSON.stringify(selectedPort) : undefined + ), + this.setData( + boardListHistoryStorageKey, + JSON.stringify(this._boardListHistory) + ), + ]); + } + + private async restoreState(): Promise< + Readonly & { boardListHistory: BoardListHistory | undefined } + > { + const [maybeSelectedBoard, maybeSelectedPort, maybeBoardHistory] = + await Promise.all([ + this.getData(selectedBoardStorageKey), + this.getData(selectedPortStorageKey), + this.getData(boardListHistoryStorageKey), + ]); + const selectedBoard = this.tryParse(maybeSelectedBoard, isBoardIdentifier); + const selectedPort = this.tryParse(maybeSelectedPort, isPortIdentifier); + const boardListHistory = this.tryParse( + maybeBoardHistory, + isBoardListHistory + ); + return { selectedBoard, selectedPort, boardListHistory }; + } + + private tryParse( + raw: string | undefined, + typeGuard: (object: unknown) => object is T + ): T | undefined { + if (!raw) { + return undefined; + } + try { + const object = JSON.parse(raw); + if (typeGuard(object)) { + return object; + } + } catch { + this.logger.error(`Failed to parse raw: '${raw}'`); + } + return undefined; + } + + private setData(key: string, value: T): Promise { + return this.storageService.setData(key, value); + } + + private getData(key: string): Promise { + return this.storageService.getData(key); + } +} + +/** + * It should be neither visible nor called from outside. + * + * This service creates a startup task with the current board config and + * passes the task to the electron-main process so that the new window + * can inherit the boards config state of this service. + * + * Note that the state is always set, but new windows might ignore it. + * For example, the new window already has a valid boards config persisted to the local storage. + */ +const USE_INHERITED_CONFIG: Command = { + id: 'lingzhi-use-inherited-boards-config', +}; + +const DUMP_BOARD_LIST: Command = { + id: 'arduino-dump-board-list', + label: nls.localize('arduino/developer/dumpBoardList', 'Dump the Board List'), + category: 'Developer (LinZhi)', +}; + +const CLEAR_BOARD_LIST_HISTORY: Command = { + id: 'arduino-clear-board-list-history', + label: nls.localize( + 'arduino/developer/clearBoardList', + 'Clear the Board List History' + ), + category: 'Developer (LinZhi)', +}; + +const CLEAR_BOARDS_CONFIG: Command = { + id: 'arduino-clear-boards-config', + label: '清除已经选择的开发板和连接端口s', + category: 'Developer (LinZhi)', +}; diff --git a/arduino-ide-extension/src/browser/boards/boards-toolbar-item.tsx b/arduino-ide-extension/src/browser/boards/boards-toolbar-item.tsx new file mode 100644 index 000000000..942b96f92 --- /dev/null +++ b/arduino-ide-extension/src/browser/boards/boards-toolbar-item.tsx @@ -0,0 +1,349 @@ +import { TabBarToolbar } from '@theia/core/lib/browser/shell/tab-bar-toolbar/tab-bar-toolbar'; +import { codicon } from '@theia/core/lib/browser/widgets/widget'; +import { CommandRegistry } from '@theia/core/lib/common/command'; +import { + Disposable, + DisposableCollection, +} from '@theia/core/lib/common/disposable'; +import { nls } from '@theia/core/lib/common/nls'; +import React from '@theia/core/shared/react'; +import ReactDOM from '@theia/core/shared/react-dom'; +import classNames from 'classnames'; +import { boardIdentifierLabel, Port } from '../../common/protocol'; +import { BoardListItemUI } from '../../common/protocol/board-list'; +import { assertUnreachable } from '../../common/utils'; +import type { + BoardListUI, + BoardsServiceProvider, +} from './boards-service-provider'; + +export interface BoardsDropDownListCoords { + readonly top: number; + readonly left: number; + readonly width: number; + readonly paddingTop: number; +} + +export namespace BoardsDropDown { + export interface Props { + readonly coords: BoardsDropDownListCoords | 'hidden'; + readonly boardList: BoardListUI; + readonly openBoardsConfig: () => void; + readonly hide: () => void; + } +} + +export class BoardListDropDown extends React.Component { + private dropdownElement: HTMLElement; + private listRef: React.RefObject; + + constructor(props: BoardsDropDown.Props) { + super(props); + this.listRef = React.createRef(); + let list = document.getElementById('boards-dropdown-container'); + if (!list) { + list = document.createElement('div'); + list.id = 'boards-dropdown-container'; + document.body.appendChild(list); + this.dropdownElement = list; + } + } + + override componentDidUpdate(prevProps: BoardsDropDown.Props): void { + if (prevProps.coords === 'hidden' && this.listRef.current) { + this.listRef.current.focus(); + } + } + + override render(): React.ReactNode { + return ReactDOM.createPortal( + this.renderBoardListItems(), + this.dropdownElement + ); + } + + private renderBoardListItems(): React.ReactNode { + const { coords, boardList } = this.props; + if (coords === 'hidden') { + return ''; + } + const footerLabel = nls.localize( + 'arduino/board/openBoardsConfig', + 'Select other board and port…' + ); + return ( +
+
+ {boardList.items.map((item, index) => + this.renderBoardListItem({ + item, + selected: index === boardList.selectedIndex, + }) + )} +
+
this.props.openBoardsConfig()} + > +
{footerLabel}
+
+
+ ); + } + + private readonly onDefaultAction = (item: BoardListItemUI): unknown => { + const { boardList, hide } = this.props; + const { type, params } = item.defaultAction; + hide(); + switch (type) { + case 'select-boards-config': { + return boardList.select(params); + } + case 'edit-boards-config': { + return boardList.edit(params); + } + default: + return assertUnreachable(type); + } + }; + + private renderBoardListItem({ + item, + selected, + }: { + item: BoardListItemUI; + selected: boolean; + }): React.ReactNode { + const { boardLabel, portLabel, portProtocol, tooltip } = item.labels; + const port = item.port; + const onKeyUp = (e: React.KeyboardEvent) => { + if (e.key === 'Enter') { + this.onDefaultAction(item); + } + }; + return ( +
this.onDefaultAction(item)} + onKeyUp={onKeyUp} + tabIndex={0} + > +
+
+
+
+ {boardLabel} +
+
+
+ {portLabel} +
+
+ {this.renderActions(item)} +
+ ); + } + + private renderActions(item: BoardListItemUI): React.ReactNode { + const { boardList, hide } = this.props; + const { revert, edit } = item.otherActions; + if (!edit && !revert) { + return undefined; + } + const handleOnClick = ( + event: React.MouseEvent, + callback: () => void + ) => { + event.preventDefault(); + event.stopPropagation(); + hide(); + callback(); + }; + return ( +
+ {edit && ( +
+ { +
+ handleOnClick(event, () => boardList.edit(edit.params)) + } + /> + } +
+ )} + {revert && ( +
+ { +
+ handleOnClick(event, () => boardList.select(revert.params)) + } + /> + } +
+ )} +
+ ); + } +} + +export class BoardsToolBarItem extends React.Component< + BoardsToolBarItem.Props, + BoardsToolBarItem.State +> { + static TOOLBAR_ID: 'boards-toolbar'; + + private readonly toDispose: DisposableCollection; + + constructor(props: BoardsToolBarItem.Props) { + super(props); + const { boardList } = props.boardsServiceProvider; + this.state = { + boardList, + coords: 'hidden', + }; + const listener = () => this.setState({ coords: 'hidden' }); + document.addEventListener('click', listener); + this.toDispose = new DisposableCollection( + Disposable.create(() => document.removeEventListener('click', listener)) + ); + } + + override componentDidMount(): void { + this.toDispose.push( + this.props.boardsServiceProvider.onBoardListDidChange((boardList) => + this.setState({ boardList }) + ) + ); + } + + override componentWillUnmount(): void { + this.toDispose.dispose(); + } + + private readonly show = (event: React.MouseEvent): void => { + const { currentTarget: element } = event; + if (element instanceof HTMLElement) { + if (this.state.coords === 'hidden') { + const rect = element.getBoundingClientRect(); + this.setState({ + coords: { + top: rect.top, + left: rect.left, + width: rect.width, + paddingTop: rect.height, + }, + }); + } else { + this.setState({ coords: 'hidden' }); + } + } + event.stopPropagation(); + event.nativeEvent.stopImmediatePropagation(); + }; + + private readonly hide = () => { + this.setState({ coords: 'hidden' }); + }; + + override render(): React.ReactNode { + const { coords, boardList } = this.state; + const { boardLabel, selected, portProtocol, tooltip } = boardList.labels; + const protocolIcon = portProtocol + ? iconNameFromProtocol(portProtocol) + : null; + const protocolIconClassNames = classNames( + 'arduino-boards-toolbar-item--protocol', + 'fa', + protocolIcon + ); + return ( + +
+ {protocolIcon &&
} +
+ {boardLabel} +
+
+
+ boardList.edit({ query: '' })} + hide={this.hide} + /> + + ); + } +} +export namespace BoardsToolBarItem { + export interface Props { + readonly boardsServiceProvider: BoardsServiceProvider; + readonly commands: CommandRegistry; + } + + export interface State { + boardList: BoardListUI; + coords: BoardsDropDownListCoords | 'hidden'; + } +} + +function iconNameFromProtocol(protocol: string): string { + switch (protocol) { + case 'serial': + return 'fa-arduino-technology-usb'; + case 'network': + return 'fa-arduino-technology-connection'; + // it is fine to assign dedicated icons to the protocols used by the official boards, + // but other than that it is best to avoid implementing any special handling + // for specific protocols in the IDE codebase. + default: + return 'fa-arduino-technology-3dimensionscube'; + } +} diff --git a/arduino-ide-extension/src/browser/boards/boards-widget-frontend-contribution.ts b/arduino-ide-extension/src/browser/boards/boards-widget-frontend-contribution.ts new file mode 100644 index 000000000..32ce058ba --- /dev/null +++ b/arduino-ide-extension/src/browser/boards/boards-widget-frontend-contribution.ts @@ -0,0 +1,40 @@ +import { injectable } from '@theia/core/shared/inversify'; +import { + BoardSearch, + BoardsPackage, +} from '../../common/protocol/boards-service'; +import { URI } from '../contributions/contribution'; +import { ListWidgetFrontendContribution } from '../widgets/component-list/list-widget-frontend-contribution'; +import { BoardsListWidget } from './boards-list-widget'; + +@injectable() +export class BoardsListWidgetFrontendContribution extends ListWidgetFrontendContribution< + BoardsPackage, + BoardSearch +> { + constructor() { + super({ + widgetId: BoardsListWidget.WIDGET_ID, + widgetName: BoardsListWidget.WIDGET_LABEL, + defaultWidgetOptions: { + area: 'left', + rank: 3, + }, + toggleCommandId: `${BoardsListWidget.WIDGET_ID}:toggle`, + toggleKeybinding: 'CtrlCmd+Shift+B', + }); + } + + protected canParse(uri: URI): boolean { + try { + BoardSearch.UriParser.parse(uri); + return true; + } catch { + return false; + } + } + + protected parse(uri: URI): BoardSearch | undefined { + return BoardSearch.UriParser.parse(uri); + } +} diff --git a/arduino-ide-extension/src/browser/components/ProgressBar.tsx b/arduino-ide-extension/src/browser/components/ProgressBar.tsx new file mode 100644 index 000000000..c531cde7e --- /dev/null +++ b/arduino-ide-extension/src/browser/components/ProgressBar.tsx @@ -0,0 +1,28 @@ +import React from '@theia/core/shared/react'; + +export type ProgressBarProps = { + percent?: number; + showPercentage?: boolean; +}; + +export default function ProgressBar({ + percent = 0, + showPercentage = false, +}: ProgressBarProps): React.ReactElement { + const roundedPercent = Math.round(percent); + return ( +
+
+
+
+ {showPercentage && ( +
+
{roundedPercent}%
+
+ )} +
+ ); +} diff --git a/arduino-ide-extension/src/browser/config/config-service-client.ts b/arduino-ide-extension/src/browser/config/config-service-client.ts new file mode 100644 index 000000000..e77479d2d --- /dev/null +++ b/arduino-ide-extension/src/browser/config/config-service-client.ts @@ -0,0 +1,103 @@ +import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application'; +import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state'; +import { DisposableCollection } 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 { deepClone } from '@theia/core/lib/common/objects'; +import URI from '@theia/core/lib/common/uri'; +import { + inject, + injectable, + postConstruct, +} from '@theia/core/shared/inversify'; +import { ConfigService, ConfigState } from '../../common/protocol'; +import { NotificationCenter } from '../notification-center'; + +@injectable() +export class ConfigServiceClient implements FrontendApplicationContribution { + @inject(ConfigService) + private readonly delegate: ConfigService; + @inject(NotificationCenter) + private readonly notificationCenter: NotificationCenter; + @inject(FrontendApplicationStateService) + private readonly appStateService: FrontendApplicationStateService; + @inject(MessageService) + private readonly messageService: MessageService; + + private readonly didChangeSketchDirUriEmitter = new Emitter< + URI | undefined + >(); + private readonly didChangeDataDirUriEmitter = new Emitter(); + private readonly toDispose = new DisposableCollection( + this.didChangeSketchDirUriEmitter, + this.didChangeDataDirUriEmitter + ); + + private config: ConfigState | undefined; + + @postConstruct() + protected init(): void { + this.appStateService.reachedState('ready').then(async () => { + const config = await this.delegate.getConfiguration(); + this.use(config); + }); + } + + onStart(): void { + this.notificationCenter.onConfigDidChange((config) => this.use(config)); + } + + onStop(): void { + this.toDispose.dispose(); + } + + get onDidChangeSketchDirUri(): Event { + return this.didChangeSketchDirUriEmitter.event; + } + + get onDidChangeDataDirUri(): Event { + return this.didChangeDataDirUriEmitter.event; + } + + /** + * CLI config related error messages if any. + */ + tryGetMessages(): string[] | undefined { + return this.config?.messages; + } + + /** + * `directories.user` + */ + tryGetSketchDirUri(): URI | undefined { + return this.config?.config?.sketchDirUri + ? new URI(this.config?.config?.sketchDirUri) + : undefined; + } + + /** + * `directories.data` + */ + tryGetDataDirUri(): URI | undefined { + return this.config?.config?.dataDirUri + ? new URI(this.config?.config?.dataDirUri) + : undefined; + } + + private use(config: ConfigState): void { + const oldConfig = deepClone(this.config); + this.config = config; + if (oldConfig?.config?.sketchDirUri !== this.config?.config?.sketchDirUri) { + this.didChangeSketchDirUriEmitter.fire(this.tryGetSketchDirUri()); + } + if (oldConfig?.config?.dataDirUri !== this.config?.config?.dataDirUri) { + this.didChangeDataDirUriEmitter.fire(this.tryGetDataDirUri()); + } + if (this.config.messages?.length) { + const message = this.config.messages.join(' '); + // toast the error later otherwise it might not show up in IDE2 + // setTimeout(() => this.messageService.error(message), 1_000); + setTimeout(() => console.error(message), 1_000); + } + } +} diff --git a/arduino-ide-extension/src/browser/contributions/about.ts b/arduino-ide-extension/src/browser/contributions/about.ts new file mode 100644 index 000000000..1954bf342 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/about.ts @@ -0,0 +1,184 @@ +import { ClipboardService } from '@theia/core/lib/browser/clipboard-service'; +import { FrontendApplicationConfigProvider } from '@theia/core/lib/browser/frontend-application-config-provider'; +import { nls } from '@theia/core/lib/common/nls'; +import { isOSX, isWindows } from '@theia/core/lib/common/os'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import moment from 'moment'; +import { AppService } from '../app-service'; +import { ArduinoMenus } from '../menu/arduino-menus'; +import { + Command, + CommandRegistry, + Contribution, + MenuModelRegistry, +} from './contribution'; + +@injectable() +export class About extends Contribution { + @inject(ClipboardService) + private readonly clipboardService: ClipboardService; + @inject(AppService) + private readonly appService: AppService; + + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(About.Commands.ABOUT_APP, { + execute: () => this.showAbout(), + }); + } + + override registerMenus(registry: MenuModelRegistry): void { + registry.registerMenuAction(ArduinoMenus.HELP__ABOUT_GROUP, { + commandId: About.Commands.ABOUT_APP.id, + label: nls.localize( + 'arduino/about/label', + '关于 {0}', + this.applicationName + ), + order: '0', + }); + } + + // 定义一个异步方法,用于显示关于信息 + private async showAbout(): Promise { + // 获取应用程序信息 + const appInfo = await this.appService.info(); + // 解构赋值,获取应用程序版本、CLI版本、构建日期 + const { appVersion, cliVersion, buildDate } = appInfo; + + // 定义一个函数,用于生成详细信息 + const detail = (showAll: boolean) => + nls.localize( + 'arduino/about/detail', + '版本 : {0}\nDate: {1}{2}\nCLI Version: {3}\n\n{4}', + appVersion, + buildDate ? buildDate : nls.localize('', 'dev build'), + buildDate && showAll ? ` (${this.ago(buildDate)})` : '', + cliVersion, + nls.localize( + 'arduino/about/copyright', + '版权 © {0} 零知实验室', + new Date().getFullYear().toString() + ) + ); + // 定义确定按钮和复制按钮的文本 + const ok = nls.localize('vscode/issueMainService/ok', '确定'); + const copy = nls.localize('vscode/textInputActions/copy', '复制'); + // 根据操作系统,确定按钮的顺序 + const buttons = !isWindows && !isOSX ? [copy, ok] : [ok, copy]; + // 显示消息框,包含应用程序名称、详细信息、按钮等 + const { response } = await this.dialogService.showMessageBox({ + message: `${this.applicationName}`, + title: `${this.applicationName}`, + type: 'info', + detail: detail(true), + buttons, + noLink: true, + defaultId: buttons.indexOf(ok), + cancelId: buttons.indexOf(ok), + }); + + // 如果点击了复制按钮,则将详细信息复制到剪贴板 + if (buttons[response] === copy) { + await this.clipboardService.writeText(detail(false).trim()); + } + } + + private get applicationName(): string { + return FrontendApplicationConfigProvider.get().applicationName; + } + + private ago(isoTime: string): string { + const now = moment(Date.now()); + const other = moment(isoTime); + let result = now.diff(other, 'minute'); + if (result < 60) { + return result === 1 + ? nls.localize( + 'vscode/date/date.fromNow.minutes.singular.ago', + '{0} minute ago', + result.toString() + ) + : nls.localize( + 'vscode/date/date.fromNow.minutes.plural.ago', + '{0} minutes ago', + result.toString() + ); + } + result = now.diff(other, 'hour'); + if (result < 25) { + return result === 1 + ? nls.localize( + 'vscode/date/date.fromNow.hours.singular.ago', + '{0} hour ago', + result.toString() + ) + : nls.localize( + 'vscode/date/date.fromNow.hours.plural.ago', + '{0} hours ago', + result.toString() + ); + } + result = now.diff(other, 'day'); + if (result < 8) { + return result === 1 + ? nls.localize( + 'vscode/date/date.fromNow.days.singular.ago', + '{0} day ago', + result.toString() + ) + : nls.localize( + 'vscode/date/date.fromNow.days.plural.ago', + '{0} days ago', + result.toString() + ); + } + result = now.diff(other, 'week'); + if (result < 5) { + return result === 1 + ? nls.localize( + 'vscode/date/date.fromNow.weeks.singular.ago', + '{0} week ago', + result.toString() + ) + : nls.localize( + 'vscode/date/date.fromNow.weeks.plural.ago', + '{0} weeks ago', + result.toString() + ); + } + result = now.diff(other, 'month'); + if (result < 13) { + return result === 1 + ? nls.localize( + 'vscode/date/date.fromNow.months.singular.ago', + '{0} month ago', + result.toString() + ) + : nls.localize( + 'vscode/date/date.fromNow.months.plural.ago', + '{0} months ago', + result.toString() + ); + } + result = now.diff(other, 'year'); + return result === 1 + ? nls.localize( + 'vscode/date/date.fromNow.years.singular.ago', + '{0} year ago', + result.toString() + ) + : nls.localize( + 'vscode/date/date.fromNow.years.plural.ago', + '{0} years ago', + result.toString() + ); + } +} + +export namespace About { + export namespace Commands { + export const ABOUT_APP: Command = { + id: 'lingzhi-about', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/account.ts b/arduino-ide-extension/src/browser/contributions/account.ts new file mode 100644 index 000000000..fe16650bc --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/account.ts @@ -0,0 +1,148 @@ +import { SidebarMenu } from '@theia/core/lib/browser/shell/sidebar-menu-widget'; +import { WindowService } from '@theia/core/lib/browser/window/window-service'; +import { DisposableCollection } from '@theia/core/lib/common/disposable'; +import { nls } from '@theia/core/lib/common/nls'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { 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, Contribution } from './contribution'; + +export const accountMenu: SidebarMenu = { + id: 'arduino-accounts-menu', + iconClass: 'fa lingzhi-account', + title: nls.localize('arduino/account/menuTitle', 'Arduino Cloud'), + menuPath: ArduinoMenus.ARDUINO_ACCOUNT__CONTEXT, + order: 0, +}; + +@injectable() +export class Account extends Contribution { + @inject(WindowService) + private readonly windowService: WindowService; + @inject(CreateFeatures) + private readonly createFeatures: CreateFeatures; + @inject(ApplicationConnectionStatusContribution) + private readonly connectionStatus: ApplicationConnectionStatusContribution; + + private readonly toDispose = new DisposableCollection(); + // private app: FrontendApplication; + + // override onStart(app: FrontendApplication): void { + // this.app = app; + // this.updateSidebarCommand(); + // this.toDispose.push( + // this.createFeatures.onDidChangeEnabled((enabled) => + // this.updateSidebarCommand(enabled) + // ) + // ); + // } + + onStop(): void { + this.toDispose.dispose(); + } + + 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: () => !loggedIn(), + isVisible: () => !loggedIn(), + }); + registry.registerCommand(Account.Commands.GO_TO_PROFILE, { + execute: () => openExternal('https://id.arduino.cc/'), + isEnabled: () => loggedInWithInternetConnection(), + isVisible: () => loggedIn(), + }); + registry.registerCommand(Account.Commands.GO_TO_CLOUD_EDITOR, { + execute: () => openExternal('https://create.arduino.cc/editor'), + isEnabled: () => loggedInWithInternetConnection(), + isVisible: () => loggedIn(), + }); + registry.registerCommand(Account.Commands.GO_TO_IOT_CLOUD, { + execute: () => openExternal('https://create.arduino.cc/iot/'), + isEnabled: () => loggedInWithInternetConnection(), + isVisible: () => loggedIn(), + }); + } + + // override registerMenus(registry: MenuModelRegistry): void { + // const register = ( + // menuPath: MenuPath, + // ...commands: (Command | [command: Command, menuLabel: string])[] + // ) => + // commands.forEach((command, index) => { + // const commandId = Array.isArray(command) ? command[0].id : command.id; + // const label = Array.isArray(command) ? command[1] : command.label; + // registry.registerMenuAction(menuPath, { + // label, + // commandId, + // order: String(index), + // }); + // }); + + // register(ArduinoMenus.ARDUINO_ACCOUNT__CONTEXT__SIGN_IN_GROUP, [ + // CloudUserCommands.LOGIN, + // nls.localize('arduino/cloud/signInToCloud', 'Sign in to Arduino Cloud'), + // ]); + // register(ArduinoMenus.ARDUINO_ACCOUNT__CONTEXT__LEARN_MORE_GROUP, [ + // Account.Commands.LEARN_MORE, + // nls.localize('arduino/cloud/learnMore', 'Learn more'), + // ]); + // register( + // ArduinoMenus.ARDUINO_ACCOUNT__CONTEXT__GO_TO_GROUP, + // [ + // Account.Commands.GO_TO_PROFILE, + // nls.localize('arduino/account/goToProfile', 'Go to Profile'), + // ], + // [ + // Account.Commands.GO_TO_CLOUD_EDITOR, + // nls.localize('arduino/account/goToCloudEditor', 'Go to Cloud Editor'), + // ], + // [ + // Account.Commands.GO_TO_IOT_CLOUD, + // nls.localize('arduino/account/goToIoTCloud', 'Go to IoT Cloud'), + // ] + // ); + // register( + // ArduinoMenus.ARDUINO_ACCOUNT__CONTEXT__SIGN_OUT_GROUP, + // CloudUserCommands.LOGOUT + // ); + // } + + // private updateSidebarCommand( + // visible: boolean = this.preferences['arduino.cloud.enabled'] + // ): void { + // if (!this.app) { + // return; + // } + // const handler = this.app.shell.leftPanelHandler; + // if (visible) { + // handler.addBottomMenu(accountMenu); + // } else { + // handler.removeBottomMenu(accountMenu.id); + // } + // } +} + +export namespace Account { + export namespace Commands { + export const GO_TO_PROFILE: Command = { + id: 'lingzhi-go-to-profile', + }; + export const GO_TO_CLOUD_EDITOR: Command = { + id: 'lingzhi-go-to-cloud-editor', + }; + export const GO_TO_IOT_CLOUD: Command = { + id: 'lingzhi-go-to-iot-cloud', + }; + export const LEARN_MORE: Command = { + id: 'lingzhi-learn-more', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/add-file.ts b/arduino-ide-extension/src/browser/contributions/add-file.ts new file mode 100644 index 000000000..9dcc7d981 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/add-file.ts @@ -0,0 +1,106 @@ +import { nls } from '@theia/core/lib/common/nls'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { FileDialogService } from '@theia/filesystem/lib/browser'; +import { ArduinoMenus } from '../menu/arduino-menus'; +import { CurrentSketch } from '../sketches-service-client-impl'; +import { + Command, + CommandRegistry, + MenuModelRegistry, + Sketch, + SketchContribution, + URI, +} from './contribution'; + +@injectable() +export class AddFile extends SketchContribution { + @inject(FileDialogService) + private readonly fileDialogService: FileDialogService; // TODO: use dialogService + + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(AddFile.Commands.ADD_FILE, { + execute: () => this.addFile(), + }); + } + + override registerMenus(registry: MenuModelRegistry): void { + registry.registerMenuAction(ArduinoMenus.SKETCH__UTILS_GROUP, { + commandId: AddFile.Commands.ADD_FILE.id, + + label: '添加文件...', + order: '2', + }); + } + + private async addFile(): Promise { + const sketch = await this.sketchServiceClient.currentSketch(); + if (!CurrentSketch.isValid(sketch)) { + return; + } + const toAddUri = await this.fileDialogService.showOpenDialog({ + title: '添加文件', + canSelectFiles: true, + canSelectFolders: false, + canSelectMany: false, + modal: true, + }); + if (!toAddUri) { + return; + } + const { uri: targetUri, filename } = this.resolveTarget(sketch, toAddUri); + const exists = await this.fileService.exists(targetUri); + if (exists) { + const { response } = await this.dialogService.showMessageBox({ + type: 'question', + title: nls.localize('arduino/contributions/replaceTitle', '替换'), + buttons: [ + nls.localize('vscode/issueMainService/cancel', '取消'), + nls.localize('vscode/issueMainService/ok', '确定'), + ], + message: nls.localize( + 'arduino/replaceMsg', + 'Replace the existing version of {0}?', + filename + ), + }); + if (response === 0) { + // Cancel + return; + } + } + await this.fileService.copy(toAddUri, targetUri, { overwrite: true }); + this.messageService.info( + nls.localize( + 'arduino/contributions/fileAdded', + '在草图中添加了一个文件。' + ), + { + timeout: 2000, + } + ); + } + + // https://github.com/arduino/arduino-ide/issues/284#issuecomment-1364533662 + // File the file to add has one of the following extension, it goes to the sketch folder root: .ino, .h, .cpp, .c, .S + // Otherwise, the files goes to the `data` folder inside the sketch folder root. + private resolveTarget( + sketch: Sketch, + toAddUri: URI + ): { uri: URI; filename: string } { + const path = toAddUri.path; + const filename = path.base; + let root = new URI(sketch.uri); + if (!Sketch.Extensions.CODE_FILES.includes(path.ext)) { + root = root.resolve('data'); + } + return { uri: root.resolve(filename), filename: filename }; + } +} + +export namespace AddFile { + export namespace Commands { + export const ADD_FILE: Command = { + id: 'lingzhi-add-file', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/add-zip-library.ts b/arduino-ide-extension/src/browser/contributions/add-zip-library.ts new file mode 100644 index 000000000..7b9b9cf1c --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/add-zip-library.ts @@ -0,0 +1,138 @@ +import { inject, injectable } from '@theia/core/shared/inversify'; +import URI from '@theia/core/lib/common/uri'; +import { ConfirmDialog } from '@theia/core/lib/browser/dialogs'; +import { LibraryService, ResponseServiceClient } from '../../common/protocol'; +import { ExecuteWithProgress } from '../../common/protocol/progressible'; +import { SketchContribution, Command, CommandRegistry } from './contribution'; +import { nls } from '@theia/core/lib/common'; + +@injectable() +export class AddZipLibrary extends SketchContribution { + @inject(ResponseServiceClient) + private readonly responseService: ResponseServiceClient; + + @inject(LibraryService) + private readonly libraryService: LibraryService; + + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(AddZipLibrary.Commands.ADD_ZIP_LIBRARY, { + execute: () => this.addZipLibrary(), + }); + } + + // override registerMenus(registry: MenuModelRegistry): void { + // const includeLibMenuPath = [ + // ...ArduinoMenus.SKETCH__UTILS_GROUP, + // '0_include', + // ]; + // registry.registerMenuAction([...includeLibMenuPath, '1_install'], { + // commandId: AddZipLibrary.Commands.ADD_ZIP_LIBRARY.id, + // label: nls.localize('arduino/library/addZip', 'Add .ZIP Library...'), + // order: '1', + // }); + // } + + private async addZipLibrary(): Promise { + const homeUri = await this.envVariableServer.getHomeDirUri(); + const defaultPath = await this.fileService.fsPath(new URI(homeUri)); + const { canceled, filePaths } = await this.dialogService.showOpenDialog({ + title: nls.localize( + 'arduino/selectZip', + "Select a zip file containing the library you'd like to add" + ), + defaultPath, + properties: ['openFile'], + filters: [ + { + name: nls.localize('arduino/library/zipLibrary', 'Library'), + extensions: ['zip'], + }, + ], + }); + if (!canceled && filePaths.length) { + const zipUri = await this.fileSystemExt.getUri(filePaths[0]); + try { + await this.doInstall(zipUri); + } catch (error) { + if (error instanceof AlreadyInstalledError) { + const result = await new ConfirmDialog({ + msg: error.message, + title: nls.localize( + 'arduino/library/overwriteExistingLibrary', + 'Do you want to overwrite the existing library?' + ), + ok: nls.localize('vscode/extensionsUtils/yes', 'Yes'), + cancel: nls.localize('vscode/extensionsUtils/no', 'No'), + }).open(); + if (result) { + await this.doInstall(zipUri, true); + } + } + } + } + } + + private async doInstall(zipUri: string, overwrite?: boolean): Promise { + try { + await ExecuteWithProgress.doWithProgress({ + messageService: this.messageService, + progressText: + nls.localize('arduino/common/processing', '处理') + + ` ${new URI(zipUri).path.base}`, + responseService: this.responseService, + run: () => this.libraryService.installZip({ zipUri, overwrite }), + }); + this.messageService.info( + nls.localize( + 'arduino/library/successfullyInstalledZipLibrary', + '从{0}存档成功安装库', + new URI(zipUri).path.base + ), + { timeout: 3000 } + ); + } catch (error) { + if (error instanceof Error) { + const match = error.message.match(/library (.*?) already installed/); + if (match && match.length >= 2) { + const name = match[1].trim(); + if (name) { + throw new AlreadyInstalledError( + nls.localize( + 'arduino/library/namedLibraryAlreadyExists', + '已存在名为{0}的库文件夹。您想要覆盖它吗?', + name + ), + name + ); + } else { + throw new AlreadyInstalledError( + nls.localize( + 'arduino/library/libraryAlreadyExists', + '库已经存在。您想要覆盖它吗?' + ) + ); + } + } + } + // this.messageService.error(error.toString()); + const chunk = `${error.toString()}\n`; + this.responseService.appendToOutput({ chunk }); + throw error; + } + } +} + +class AlreadyInstalledError extends Error { + constructor(message: string, readonly libraryName?: string) { + super(message); + Object.setPrototypeOf(this, AlreadyInstalledError.prototype); + } +} + +export namespace AddZipLibrary { + export namespace Commands { + export const ADD_ZIP_LIBRARY: Command = { + id: 'lingzhi-add-zip-library', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/archive-sketch.ts b/arduino-ide-extension/src/browser/contributions/archive-sketch.ts new file mode 100644 index 000000000..abf989c66 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/archive-sketch.ts @@ -0,0 +1,72 @@ +import { injectable } from '@theia/core/shared/inversify'; +import dateFormat from 'dateformat'; +import { ArduinoMenus } from '../menu/arduino-menus'; +import { + SketchContribution, + Command, + CommandRegistry, + MenuModelRegistry, +} from './contribution'; +import { nls } from '@theia/core/lib/common'; +import { CurrentSketch } from '../sketches-service-client-impl'; + +@injectable() +export class ArchiveSketch extends SketchContribution { + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(ArchiveSketch.Commands.ARCHIVE_SKETCH, { + execute: () => this.archiveSketch(), + }); + } + + override registerMenus(registry: MenuModelRegistry): void { + registry.registerMenuAction(ArduinoMenus.TOOLS__MAIN_GROUP, { + commandId: ArchiveSketch.Commands.ARCHIVE_SKETCH.id, + label: '项目存档', + order: '1', + }); + } + + private async archiveSketch(): Promise { + const sketch = await this.sketchServiceClient.currentSketch(); + if (!CurrentSketch.isValid(sketch)) { + return; + } + const archiveBasename = `${sketch.name}-${dateFormat( + new Date(), + 'yymmdd' + )}a.zip`; + const defaultContainerUri = await this.defaultUri(); + const defaultUri = defaultContainerUri.resolve(archiveBasename); + const defaultPath = await this.fileService.fsPath(defaultUri); + const { filePath, canceled } = await this.dialogService.showSaveDialog({ + title: '将项目文件夹另存为…', + defaultPath, + }); + if (!filePath || canceled) { + return; + } + const destinationUri = await this.fileSystemExt.getUri(filePath); + if (!destinationUri) { + return; + } + await this.sketchesService.archive(sketch, destinationUri.toString()); + this.messageService.info( + nls.localize( + 'arduino/sketch/createdArchive', + "创建存档 '{0}'.", + archiveBasename + ), + { + timeout: 2000, + } + ); + } +} + +export namespace ArchiveSketch { + export namespace Commands { + export const ARCHIVE_SKETCH: Command = { + id: 'lingzhi-archive-sketch', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/auto-select-programmer.ts b/arduino-ide-extension/src/browser/contributions/auto-select-programmer.ts new file mode 100644 index 000000000..0bf8e277e --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/auto-select-programmer.ts @@ -0,0 +1,123 @@ +import type { MaybePromise } from '@theia/core/lib/common/types'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { + BoardDetails, + Programmer, + isBoardIdentifierChangeEvent, +} from '../../common/protocol'; +import { + BoardsDataStore, + findDefaultProgrammer, + isEmptyData, +} from '../boards/boards-data-store'; +import { BoardsServiceProvider } from '../boards/boards-service-provider'; +import { Contribution } from './contribution'; + +/** + * Before CLI 0.35.0-rc.3, there was no `programmer#default` property in the `board details` response. + * This method does the programmer migration in the data store. If there is a programmer selected, it's a noop. + * If no programmer is selected, it forcefully reloads the details from the CLI and updates it in the local storage. + */ +@injectable() +export class AutoSelectProgrammer extends Contribution { + @inject(BoardsServiceProvider) + private readonly boardsServiceProvider: BoardsServiceProvider; + @inject(BoardsDataStore) + private readonly boardsDataStore: BoardsDataStore; + + override onStart(): void { + this.boardsServiceProvider.onBoardsConfigDidChange((event) => { + if (isBoardIdentifierChangeEvent(event)) { + this.ensureProgrammerIsSelected(); + } + }); + } + + override onReady(): void { + this.boardsServiceProvider.ready.then(() => + this.ensureProgrammerIsSelected() + ); + } + + private async ensureProgrammerIsSelected(): Promise { + return ensureProgrammerIsSelected({ + fqbn: this.boardsServiceProvider.boardsConfig.selectedBoard?.fqbn, + getData: (fqbn) => this.boardsDataStore.getData(fqbn), + loadBoardDetails: (fqbn) => this.boardsDataStore.loadBoardDetails(fqbn), + selectProgrammer: (arg) => this.boardsDataStore.selectProgrammer(arg), + }); + } +} + +interface EnsureProgrammerIsSelectedParams { + fqbn: string | undefined; + getData: (fqbn: string | undefined) => MaybePromise; + loadBoardDetails: (fqbn: string) => MaybePromise; + selectProgrammer(options: { + fqbn: string; + selectedProgrammer: Programmer; + }): MaybePromise; +} + +export async function ensureProgrammerIsSelected( + params: EnsureProgrammerIsSelectedParams +): Promise { + const { fqbn, getData, loadBoardDetails, selectProgrammer } = params; + if (!fqbn) { + return false; + } + console.debug(`Ensuring a programmer is selected for ${fqbn}...`); + const data = await getData(fqbn); + if (isEmptyData(data)) { + // For example, the platform is not installed. + console.debug(`Skipping. No boards data is available for ${fqbn}.`); + return false; + } + if (data.selectedProgrammer) { + console.debug( + `A programmer is already selected for ${fqbn}: '${data.selectedProgrammer.id}'.` + ); + return true; + } + let programmer = findDefaultProgrammer(data.programmers, data); + if (programmer) { + // select the programmer if the default info is available + const result = await selectProgrammer({ + fqbn, + selectedProgrammer: programmer, + }); + if (result) { + console.debug(`Selected '${programmer.id}' programmer for ${fqbn}.`); + return result; + } + } + console.debug(`Reloading board details for ${fqbn}...`); + const reloadedData = await loadBoardDetails(fqbn); + if (!reloadedData) { + console.debug(`Skipping. No board details found for ${fqbn}.`); + return false; + } + if (!reloadedData.programmers.length) { + console.debug(`Skipping. ${fqbn} does not have programmers.`); + return false; + } + programmer = findDefaultProgrammer(reloadedData.programmers, reloadedData); + if (!programmer) { + console.debug( + `Skipping. Could not find a default programmer for ${fqbn}. Programmers were: ` + ); + return false; + } + const result = await selectProgrammer({ + fqbn, + selectedProgrammer: programmer, + }); + if (result) { + console.debug(`Selected '${programmer.id}' programmer for ${fqbn}.`); + } else { + console.debug( + `Could not select '${programmer.id}' programmer for ${fqbn}.` + ); + } + return result; +} diff --git a/arduino-ide-extension/src/browser/contributions/board-selection.ts b/arduino-ide-extension/src/browser/contributions/board-selection.ts new file mode 100644 index 000000000..24a7c72e3 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/board-selection.ts @@ -0,0 +1,411 @@ +import { + Disposable, + DisposableCollection, +} from '@theia/core/lib/common/disposable'; +import { MenuModelRegistry } from '@theia/core/lib/common/menu/menu-model-registry'; +import type { MenuPath } from '@theia/core/lib/common/menu/menu-types'; +import { nls } from '@theia/core/lib/common/nls'; +import { Deferred } from '@theia/core/lib/common/promise-util'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { MainMenuManager } from '../../common/main-menu-manager'; +import { + BoardsService, + BoardWithPackage, + createPlatformIdentifier, + getBoardInfo, + InstalledBoardWithPackage, + platformIdentifierEquals, + Port, + serializePlatformIdentifier, +} from '../../common/protocol'; +import type { BoardList } from '../../common/protocol/board-list'; +import { BoardsListWidget } from '../boards/boards-list-widget'; +import { BoardsServiceProvider } from '../boards/boards-service-provider'; +import { PlaceholderMenuNode } from '../menu/arduino-menus'; +import { NotificationCenter } from '../notification-center'; +import { Command, CommandRegistry, SketchContribution } from './contribution'; +import { SidebarMenu } from '@theia/core/lib/browser/shell/sidebar-menu-widget'; +import { CreateFeatures } from '../create/create-features'; +import { FrontendApplication } from '@theia/core/lib/browser/frontend-application'; + +export const PortMenu: SidebarMenu = { + id: 'arduino-port-sketch', + iconClass: 'fa lingzhi-connect-left', + title: '连接', + menuPath: ['100_serial'], + order: 3, +}; + +@injectable() +export class BoardSelection extends SketchContribution { + // 注入 CommandRegistry,用于注册命令 + @inject(CommandRegistry) + private readonly commandRegistry: CommandRegistry; + // 注入 MainMenuManager,用于管理主菜单 + @inject(MainMenuManager) + private readonly mainMenuManager: MainMenuManager; + // 注入 MenuModelRegistry,用于管理菜单模型 + @inject(MenuModelRegistry) + private readonly menuModelRegistry: MenuModelRegistry; + // 注入 NotificationCenter,用于接收通知 + @inject(NotificationCenter) + private readonly notificationCenter: NotificationCenter; + // 注入 BoardsService,用于与开发板服务进行交互 + @inject(BoardsService) + private readonly boardsService: BoardsService; + // 注入 BoardsServiceProvider,用于获取开发板列表等信息 + @inject(BoardsServiceProvider) + private readonly boardsServiceProvider: BoardsServiceProvider; + + // 用于在菜单重建前处理可弃用对象的集合 + private readonly toDisposeBeforeMenuRebuild = new DisposableCollection(); + // 不每次改变时都查询已安装的平台 + private _installedBoards: Deferred | undefined; + + // 重写 SketchContribution 的 registerCommands 方法 + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(BoardSelection.Commands.GET_BOARD_INFO, { + // 当执行获取开发板信息的命令时的操作 + execute: async () => { + const boardInfo = await getBoardInfo( + this.boardsServiceProvider.boardList + ); + // 如果返回的是字符串,说明没有获取到具体的开发板信息,显示信息提示 + if (typeof boardInfo === 'string') { + this.messageService.info(boardInfo); + return; + } + const { BN, VID, PID, SN } = boardInfo; + const detail = ` +BN: ${BN} +VID: ${VID} +PID: ${PID} +SN: ${SN} +`.trim(); + await this.dialogService.showMessageBox({ + message: nls.localize('arduino/board/boardInfo', 'Board Info'), + title: nls.localize('arduino/board/boardInfo', 'Board Info'), + type: 'info', + detail, + buttons: [nls.localize('vscode/issueMainService/ok', '确定')], + }); + }, + }); + } + + @inject(CreateFeatures) + private app: FrontendApplication; + + // 重写 SketchContribution 的 onStart 方法 + override onStart(app: FrontendApplication): void { + // 订阅平台安装事件,当平台安装时调用 updateMenus 方法并传入 true + this.notificationCenter.onPlatformDidInstall(() => this.updateMenus(true)); + // 订阅平台卸载事件,当平台卸载时调用 updateMenus 方法并传入 true + this.notificationCenter.onPlatformDidUninstall(() => + this.updateMenus(true) + ); + // 订阅开发板列表变化事件,当开发板列表变化时调用 updateMenus 方法 + this.boardsServiceProvider.onBoardListDidChange(() => this.updateMenus()); + + this.app = app; + // 在 onStart 方法中添加新菜单 + const handler = this.app.shell.leftPanelHandler; + handler.addBottomMenu(PortMenu); + } + + // 重写 SketchContribution 的 onReady 方法 + override async onReady(): Promise { + // 启动时调用 updateMenus 方法进行菜单初始化 + this.updateMenus(); + } + + public async updateMenus(discardCache = false): Promise { + // 如果 discardCache 为 true,则拒绝并重置 _installedBoards 的延迟对象 + if (discardCache) { + this._installedBoards?.reject(); + this._installedBoards = undefined; + } + // 如果 _installedBoards 未定义,则创建一个新的延迟对象 + if (!this._installedBoards) { + this._installedBoards = new Deferred(); + // 获取已安装的开发板列表并在完成时处理延迟对象 + this.installedBoards().then((installedBoards) => + this._installedBoards?.resolve(installedBoards) + ); + } + // 获取已安装的开发板列表的承诺结果 + const installedBoards = await this._installedBoards.promise; + // 根据已安装的开发板列表和当前开发板列表重建菜单 + this.rebuildMenus(installedBoards, this.boardsServiceProvider.boardList); + } + + private rebuildMenus( + installedBoards: InstalledBoardWithPackage[], + boardList: BoardList + ): void { + // 清理在菜单重建前需要处理的可弃用对象集合 + this.toDisposeBeforeMenuRebuild.dispose(); + + // Boards submenu + const boardsSubmenuPath = [ + // ...ArduinoMenus.TOOLS__BOARD_SELECTION_GROUP, + '1_boards', + ]; + const { selectedBoard, selectedPort } = boardList.boardsConfig; + const boardsSubmenuLabel = selectedBoard?.name; + // 注册开发板子菜单,并设置菜单标签和顺序 + this.menuModelRegistry.registerSubmenu( + boardsSubmenuPath, + nls.localize( + 'arduino/board/board', + 'Board{0}', + !!boardsSubmenuLabel ? `: "${boardsSubmenuLabel}"` : '' + ), + { order: '100' } + ); + // 将取消注册开发板子菜单的操作添加到可弃用对象集合中 + // this.toDisposeBeforeMenuRebuild.push( + // Disposable.create(() => + // unregisterSubmenu(boardsSubmenuPath, this.menuModelRegistry) + // ) + // ); + + // Ports submenu + // const portsSubmenuPath = ArduinoMenus.TOOLS__PORTS_SUBMENU; + const portsSubmenuLabel = selectedPort?.address; + console.log('portsSubmenuLabel', portsSubmenuLabel); + // 注册端口子菜单,并设置菜单标签和顺序 + // this.menuModelRegistry.registerSubmenu( + // portsSubmenuPath, + // nls.localize( + // 'arduino/board/port', + // 'Port{0}', + // portsSubmenuLabel ? `: "${portsSubmenuLabel}"` : '' + // ), + // { order: '101' } + // ); + // 将取消注册端口子菜单的操作添加到可弃用对象集合中 + // this.toDisposeBeforeMenuRebuild.push( + // Disposable.create(() => + // unregisterSubmenu(portsSubmenuPath, this.menuModelRegistry) + // ) + // ); + + // const getBoardInfo = { + // commandId: BoardSelection.Commands.GET_BOARD_INFO.id, + // label: '获得开发板信息', + // order: '103', + // }; + // 注册获取开发板信息的菜单动作 + // this.menuModelRegistry.registerMenuAction( + // ArduinoMenus.TOOLS__BOARD_SELECTION_GROUP, + // getBoardInfo + // ); + // // 将取消注册获取开发板信息菜单动作的操作添加到可弃用对象集合中 + // this.toDisposeBeforeMenuRebuild.push( + // Disposable.create(() => + // this.menuModelRegistry.unregisterMenuAction(getBoardInfo) + // ) + // ); + + const boardsManagerGroup = [...boardsSubmenuPath, '0_manager']; + const boardsPackagesGroup = [...boardsSubmenuPath, '1_packages']; //板子 + + // 注册开发板管理的菜单动作 + this.menuModelRegistry.registerMenuAction(boardsManagerGroup, { + commandId: `${BoardsListWidget.WIDGET_ID}:toggle`, + label: `${BoardsListWidget.WIDGET_LABEL}...`, + }); + + const selectedBoardPlatformId = selectedBoard + ? createPlatformIdentifier(selectedBoard) + : undefined; + + // Keys are the vendor IDs + type BoardsPerVendor = Record; + // Group boards by their platform names. The keys are the platform names as menu labels. + // If there is a platform name (menu label) collision, refine the menu label with the vendor ID. + const groupedBoards = new Map(); + for (const board of installedBoards) { + const { packageId, packageName } = board; + console; + const { vendorId } = packageId; + let boardsPerPackageName = groupedBoards.get(packageName); + if (!boardsPerPackageName) { + boardsPerPackageName = {} as BoardsPerVendor; + groupedBoards.set(packageName, boardsPerPackageName); + } + let boardPerVendor: BoardWithPackage[] | undefined = + boardsPerPackageName[vendorId]; + if (!boardPerVendor) { + boardPerVendor = []; + boardsPerPackageName[vendorId] = boardPerVendor; + } + boardPerVendor.push(board); + } + + // Installed boards + Array.from(groupedBoards.entries()).forEach( + ([packageName, boardsPerPackage]) => { + const useVendorSuffix = Object.keys(boardsPerPackage).length > 1; + Object.entries(boardsPerPackage).forEach(([vendorId, boards]) => { + let platformMenuPath: MenuPath | undefined = undefined; + boards.forEach((board, index) => { + const { packageId, fqbn, name, manuallyInstalled } = board; + // create the platform submenu once. + // creating and registering the same submenu twice in Theia is a noop, though. + if (!platformMenuPath) { + let packageLabel = + packageName + + `${manuallyInstalled ? '(在项目文件夹中)' : ''}`; + if ( + selectedBoardPlatformId && + platformIdentifierEquals(packageId, selectedBoardPlatformId) + ) { + packageLabel = `● ${packageLabel}`; + } + if (useVendorSuffix) { + packageLabel += ` (${vendorId})`; + } + // Platform submenu + platformMenuPath = [ + ...boardsPackagesGroup, + serializePlatformIdentifier(packageId), + ]; + this.menuModelRegistry.registerSubmenu( + platformMenuPath, + packageLabel, + { + order: packageName.toLowerCase(), + } + ); + } + + const id = `arduino-select-board--${fqbn}`; + const command = { id }; + const handler = { + execute: () => + this.boardsServiceProvider.updateConfig({ + name: name, + fqbn: fqbn, + }), + isToggled: () => fqbn === selectedBoard?.fqbn, + }; + + // Board menu + const menuAction = { + commandId: id, + label: name, + order: String(index).padStart(4), // pads with leading zeros for alphanumeric sort where order is 1, 2, 11, and NOT 1, 11, 2 + }; + this.commandRegistry.registerCommand(command, handler); + this.toDisposeBeforeMenuRebuild.push( + Disposable.create(() => + this.commandRegistry.unregisterCommand(command) + ) + ); + this.menuModelRegistry.registerMenuAction( + platformMenuPath, + menuAction + ); + // Note: we do not dispose the menu actions individually. Calling `unregisterSubmenu` on the parent will wipe the children menu nodes recursively. + }); + }); + } + ); + + // Detected ports + const registerPorts = ( + protocol: string, + ports: ReturnType, + protocolOrder: number + ) => { + if (!ports.length) { + return; + } + + // Register placeholder for protocol + const menuPath = [ + // ...portsSubmenuPath, + `${protocolOrder.toString()}_${protocol}`, + ]; + + const placeholder = new PlaceholderMenuNode( + menuPath, + // nls.localize( + // 'arduino/board/typeOfPorts', + // '{0} 端口', + // Port.Protocols.protocolLabel(protocol) + // ), + '串口 端口', + { order: protocolOrder.toString().padStart(4) } + ); + // this.menuModelRegistry.registerMenuNode(menuPath, placeholder); + this.toDisposeBeforeMenuRebuild.push( + Disposable.create(() => + this.menuModelRegistry.unregisterMenuNode(placeholder.id) + ) + ); + + for (let i = 0; i < ports.length; i++) { + const { port, boards } = ports[i]; + const portKey = Port.keyOf(port); + + let label = `${port.addressLabel}`; + if (boards?.length) { + const boardsList = boards.map((board) => board.name).join(', '); + label = `${label} (${boardsList})`; + } + const id = `arduino-select-port--${portKey}`; + const command = { id }; + const handler = { + execute: () => { + this.boardsServiceProvider.updateConfig({ + protocol: port.protocol, + address: port.address, + }); + }, + isToggled: () => { + return i === ports.matchingIndex; + }, + }; + const menuAction = { + commandId: id, + label, + order: String(protocolOrder + i + 1).padStart(4), + }; + this.commandRegistry.registerCommand(command, handler); + this.toDisposeBeforeMenuRebuild.push( + Disposable.create(() => + this.commandRegistry.unregisterCommand(command) + ) + ); + this.menuModelRegistry.registerMenuAction(menuPath, menuAction); + this.toDisposeBeforeMenuRebuild.push( + Disposable.create(() => + this.menuModelRegistry.unregisterMenuNode(menuAction.commandId) + ) + ); + } + }; + + const groupedPorts = boardList.portsGroupedByProtocol(); + let protocolOrder = 100; + Object.entries(groupedPorts).forEach(([protocol, ports]) => { + registerPorts(protocol, ports, protocolOrder); + protocolOrder += 100; + }); + // 更新主菜单管理器 + this.mainMenuManager.update(); + } + + protected async installedBoards(): Promise { + const allBoards = await this.boardsService.getInstalledBoards(); + return allBoards.filter(InstalledBoardWithPackage.is); + } +} +export namespace BoardSelection { + export namespace Commands { + export const GET_BOARD_INFO: Command = { id: 'lingzhi-get-board-info' }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/boards-data-menu-updater.ts b/arduino-ide-extension/src/browser/contributions/boards-data-menu-updater.ts new file mode 100644 index 000000000..51007cc72 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/boards-data-menu-updater.ts @@ -0,0 +1,191 @@ +import { + Disposable, + DisposableCollection, +} from '@theia/core/lib/common/disposable'; +import { nls } from '@theia/core/lib/common/nls'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import PQueue from 'p-queue'; +import { + BoardIdentifier, + ConfigOption, + isBoardIdentifierChangeEvent, + Programmer, +} from '../../common/protocol'; +import { BoardsDataStore } from '../boards/boards-data-store'; +import { BoardsServiceProvider } from '../boards/boards-service-provider'; +import { ArduinoMenus, unregisterSubmenu } from '../menu/arduino-menus'; +import { + CommandRegistry, + Contribution, + MenuModelRegistry, +} from './contribution'; + +@injectable() +export class BoardsDataMenuUpdater extends Contribution { + @inject(CommandRegistry) + private readonly commandRegistry: CommandRegistry; + @inject(MenuModelRegistry) + private readonly menuRegistry: MenuModelRegistry; + @inject(BoardsDataStore) + private readonly boardsDataStore: BoardsDataStore; + @inject(BoardsServiceProvider) + private readonly boardsServiceProvider: BoardsServiceProvider; + + private readonly queue = new PQueue({ autoStart: true, concurrency: 1 }); + private readonly toDisposeOnBoardChange = new DisposableCollection(); + + override onStart(): void { + this.boardsDataStore.onDidChange(() => + this.updateMenuActions( + this.boardsServiceProvider.boardsConfig.selectedBoard + ) + ); + this.boardsServiceProvider.onBoardsConfigDidChange((event) => { + if (isBoardIdentifierChangeEvent(event)) { + this.updateMenuActions(event.selectedBoard); + } + }); + } + + override onReady(): void { + this.boardsServiceProvider.ready.then(() => + this.updateMenuActions( + this.boardsServiceProvider.boardsConfig.selectedBoard + ) + ); + } + + private async updateMenuActions( + selectedBoard: BoardIdentifier | undefined + ): Promise { + return this.queue.add(async () => { + this.toDisposeOnBoardChange.dispose(); + this.menuManager.update(); + if (selectedBoard) { + const { fqbn } = selectedBoard; + if (fqbn) { + const { configOptions, programmers, selectedProgrammer } = + await this.boardsDataStore.getData(fqbn); + if (configOptions.length) { + const boardsConfigMenuPath = [ + // ...ArduinoMenus.TOOLS__BOARD_SETTINGS_GROUP, + 'z01_boardsConfig', + ]; // `z_` is for ordering. + for (let { label, option, values } of configOptions.sort( + ConfigOption.LABEL_COMPARATOR + )) { + label = label.replace('Core Debug Level', '核心调试级'); + label = label.replace('CPU Frequency', '处理器外频'); + label = label.replace('Flash Frequency', '闪烁频率'); + label = label.replace('Flash Mode', '闪烁模式'); + label = label.replace('Flash Size', 'Flash大小'); + label = label.replace('Partition Scheme', '分区方案'); + label = label.replace('Upload Speed', '上传速度'); + label = label.replace('Debug Level', '调试级别'); + label = label.replace('Debug port', '调试端口'); + label = label.replace('Erase Flash', '擦除闪存'); + label = label.replace('Exceptions', '异常处理'); + label = label.replace('lwIP Variant', 'lwIP变体'); + const menuPath = [...boardsConfigMenuPath, `${option}`]; + const commands = new Map< + string, + Disposable & { label: string } + >(); + let selectedValue = ''; + for (const value of values) { + const id = `${fqbn}-${option}--${value.value}`; + const command = { id }; + const handler = { + execute: () => + this.boardsDataStore.selectConfigOption({ + fqbn, + option, + selectedValue: value.value, + }), + isToggled: () => value.selected, + }; + commands.set( + id, + Object.assign( + this.commandRegistry.registerCommand(command, handler), + { label: value.label } + ) + ); + if (value.selected) { + selectedValue = value.label; + } + } + this.menuRegistry.registerSubmenu( + menuPath, + `${label}${selectedValue ? `: "${selectedValue}"` : ''}` + ); + this.toDisposeOnBoardChange.pushAll([ + ...commands.values(), + Disposable.create(() => + unregisterSubmenu(menuPath, this.menuRegistry) + ), + ...Array.from(commands.keys()).map((commandId, i) => { + const { label } = commands.get(commandId)!; + this.menuRegistry.registerMenuAction(menuPath, { + commandId, + order: String(i).padStart(4), + label, + }); + return Disposable.create(() => + this.menuRegistry.unregisterMenuAction(commandId) + ); + }), + ]); + } + } + if (programmers.length) { + const programmersMenuPath = [ + ...ArduinoMenus.TOOLS__BOARD_SETTINGS_GROUP, + 'z02_programmers', + ]; + const programmerNls = nls.localize( + 'arduino/board/programmer', + 'Programmer' + ); + const label = selectedProgrammer + ? `${programmerNls}: "${selectedProgrammer.name}"` + : programmerNls; + this.menuRegistry.registerSubmenu(programmersMenuPath, label); + this.toDisposeOnBoardChange.push( + Disposable.create(() => + unregisterSubmenu(programmersMenuPath, this.menuRegistry) + ) + ); + for (const programmer of programmers) { + const { id, name } = programmer; + const command = { id: `${fqbn}-programmer--${id}` }; + const handler = { + execute: () => + this.boardsDataStore.selectProgrammer({ + fqbn, + selectedProgrammer: programmer, + }), + isToggled: () => + Programmer.equals(programmer, selectedProgrammer), + }; + this.menuRegistry.registerMenuAction(programmersMenuPath, { + commandId: command.id, + label: name, + }); + this.commandRegistry.registerCommand(command, handler); + this.toDisposeOnBoardChange.pushAll([ + Disposable.create(() => + this.commandRegistry.unregisterCommand(command) + ), + Disposable.create(() => + this.menuRegistry.unregisterMenuAction(command.id) + ), + ]); + } + } + this.menuManager.update(); + } + } + }); + } +} diff --git a/arduino-ide-extension/src/browser/contributions/burn-bootloader.ts b/arduino-ide-extension/src/browser/contributions/burn-bootloader.ts new file mode 100644 index 000000000..1c0b1d82d --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/burn-bootloader.ts @@ -0,0 +1,83 @@ +import { nls } from '@theia/core/lib/common'; +import { injectable } from '@theia/core/shared/inversify'; +import { CoreService } from '../../common/protocol'; +import { + Command, + CommandRegistry, + CoreServiceContribution, +} from './contribution'; + +@injectable() +export class BurnBootloader extends CoreServiceContribution { + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(BurnBootloader.Commands.BURN_BOOTLOADER, { + execute: () => this.burnBootloader(), + }); + } + + // override registerMenus(registry: MenuModelRegistry): void { + // registry.registerMenuAction(ArduinoMenus.TOOLS__BOARD_SETTINGS_GROUP, { + // commandId: BurnBootloader.Commands.BURN_BOOTLOADER.id, + // label: '烧录引导程序', + // order: 'z99', + // }); + // } + + private async burnBootloader(): Promise { + this.clearVisibleNotification(); + const options = await this.options(); + try { + await this.doWithProgress({ + progressText: nls.localize( + 'arduino/bootloader/burningBootloader', + 'Burning bootloader...' + ), + task: (progressId, coreService) => + coreService.burnBootloader({ + ...options, + progressId, + }), + }); + this.messageService.info( + nls.localize( + 'arduino/bootloader/doneBurningBootloader', + '完成了程序的烧录。' + ), + { + timeout: 3000, + } + ); + } catch (e) { + this.handleError(e); + } + } + + private async options(): Promise { + const { boardsConfig } = this.boardsServiceProvider; + const port = boardsConfig.selectedPort; + const [fqbn, { selectedProgrammer: programmer }, verify, verbose] = + await Promise.all([ + this.boardsDataStore.appendConfigToFqbn( + boardsConfig.selectedBoard?.fqbn + ), + this.boardsDataStore.getData(boardsConfig.selectedBoard?.fqbn), + this.preferences.get('arduino.upload.verify'), + this.preferences.get('arduino.upload.verbose'), + ]); + return { + fqbn, + programmer, + port, + verify, + verbose, + }; + } +} + +export namespace BurnBootloader { + export namespace Commands { + export const BURN_BOOTLOADER: Command = { + id: 'lingzhi-burn-bootloader', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/check-for-ide-updates.ts b/arduino-ide-extension/src/browser/contributions/check-for-ide-updates.ts new file mode 100644 index 000000000..92a47b1d7 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/check-for-ide-updates.ts @@ -0,0 +1,75 @@ +import { LocalStorageService } from '@theia/core/lib/browser/storage-service'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { + IDEUpdater, + SKIP_IDE_VERSION, +} from '../../common/protocol/ide-updater'; +import { Contribution } from './contribution'; +import { ResponseService } from '../../common/protocol'; +import { IDEUpdaterDialog } from '../dialogs/ide-updater/ide-updater-dialog'; +import { nls } from '@theia/core/lib/common/nls'; + +@injectable() +export class CheckForIDEUpdates extends Contribution { + @inject(IDEUpdater) + private readonly updater: IDEUpdater; + + @inject(IDEUpdaterDialog) + private readonly updaterDialog: IDEUpdaterDialog; + + @inject(LocalStorageService) + private readonly localStorage: LocalStorageService; + + @inject(ResponseService) + private readonly responseService: ResponseService; + + override onStart(): void { + this.preferences.onPreferenceChanged( + ({ preferenceName, newValue, oldValue }) => { + if (newValue !== oldValue) { + switch (preferenceName) { + case 'arduino.ide.updateChannel': + case 'arduino.ide.updateBaseUrl': + this.updater.init( + this.preferences.get('arduino.ide.updateChannel'), + this.preferences.get('arduino.ide.updateBaseUrl') + ); + } + } + } + ); + } + + override onReady(): void { + this.updater + .init( + this.preferences.get('arduino.ide.updateChannel'), + this.preferences.get('arduino.ide.updateBaseUrl') + ) + .then(() => { + if (!this.preferences['arduino.checkForUpdates']) { + return; + } + return this.updater.checkForUpdates(true); + }) + .then(async (updateInfo) => { + if (!updateInfo) return; + const versionToSkip = await this.localStorage.getData( + SKIP_IDE_VERSION + ); + if (versionToSkip === updateInfo.version) return; + this.updaterDialog.open(updateInfo); + }) + .catch((e) => { + this.messageService.error( + nls.localize( + 'arduino/ide-updater/errorCheckingForUpdates', + '检查lingzhilab IDE更新时出错。\n{0}', + e.message + ) + ); + const chunk = `${e.message}\n$`; + this.responseService.appendToOutput({ chunk }); + }); + } +} diff --git a/arduino-ide-extension/src/browser/contributions/check-for-updates.ts b/arduino-ide-extension/src/browser/contributions/check-for-updates.ts new file mode 100644 index 000000000..33d35495c --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/check-for-updates.ts @@ -0,0 +1,218 @@ +import type { AbstractViewContribution } from '@theia/core/lib/browser/shell/view-contribution'; +import { nls } from '@theia/core/lib/common/nls'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { InstallManually, Later } from '../../common/nls'; +import { + ArduinoComponent, + BoardsPackage, + BoardsService, + LibraryPackage, + LibraryService, + ResponseServiceClient, + Searchable, +} from '../../common/protocol'; +import { Installable } from '../../common/protocol/installable'; +import { ExecuteWithProgress } from '../../common/protocol/progressible'; +import { BoardsListWidgetFrontendContribution } from '../boards/boards-widget-frontend-contribution'; +import { LibraryListWidgetFrontendContribution } from '../library/library-widget-frontend-contribution'; +import { WindowServiceExt } from '../theia/core/window-service-ext'; +import type { ListWidget } from '../widgets/component-list/list-widget'; +import { Command, CommandRegistry, Contribution } from './contribution'; + +const NoUpdates = nls.localize( + 'arduino/checkForUpdates/noUpdates', + '没有最近可用的更新。' +); +const PromptUpdateBoards = nls.localize( + 'arduino/checkForUpdates/promptUpdateBoards', + '您的一些板可以使用更新。' +); +const PromptUpdateLibraries = nls.localize( + 'arduino/checkForUpdates/promptUpdateLibraries', + '您的一些库可以获得更新。' +); +const UpdatingBoards = nls.localize( + 'arduino/checkForUpdates/updatingBoards', + '更新板……' +); +const UpdatingLibraries = nls.localize( + 'arduino/checkForUpdates/updatingLibraries', + '更新库……' +); +const InstallAll = nls.localize( + 'arduino/checkForUpdates/installAll', + '安装全部' +); + +interface Task { + readonly run: () => Promise; + readonly item: T; +} + +const Updatable = { type: 'Updatable' } as const; + +@injectable() +export class CheckForUpdates extends Contribution { + @inject(WindowServiceExt) + private readonly windowService: WindowServiceExt; + @inject(ResponseServiceClient) + private readonly responseService: ResponseServiceClient; + @inject(BoardsService) + private readonly boardsService: BoardsService; + @inject(LibraryService) + private readonly libraryService: LibraryService; + @inject(BoardsListWidgetFrontendContribution) + private readonly boardsContribution: BoardsListWidgetFrontendContribution; + @inject(LibraryListWidgetFrontendContribution) + private readonly librariesContribution: LibraryListWidgetFrontendContribution; + + override registerCommands(register: CommandRegistry): void { + register.registerCommand(CheckForUpdates.Commands.CHECK_FOR_UPDATES, { + execute: () => this.checkForUpdates(false), + }); + } + + override async onReady(): Promise { + const checkForUpdates = this.preferences['arduino.checkForUpdates']; + if (checkForUpdates) { + this.windowService.isFirstWindow().then((firstWindow) => { + if (firstWindow) { + this.checkForUpdates(); + } + }); + } + } + + private async checkForUpdates(silent = true) { + const [boardsPackages, libraryPackages] = await Promise.all([ + this.boardsService.search(Updatable), + this.libraryService.search(Updatable), + ]); + this.promptUpdateBoards(boardsPackages); + this.promptUpdateLibraries(libraryPackages); + if (!libraryPackages.length && !boardsPackages.length && !silent) { + this.messageService.info(NoUpdates); + } + } + + private promptUpdateBoards(items: BoardsPackage[]): void { + this.prompt({ + items, + installable: this.boardsService, + viewContribution: this.boardsContribution, + viewSearchOptions: { query: '', ...Updatable }, + promptMessage: PromptUpdateBoards, + updatingMessage: UpdatingBoards, + }); + } + + private promptUpdateLibraries(items: LibraryPackage[]): void { + this.prompt({ + items, + installable: this.libraryService, + viewContribution: this.librariesContribution, + viewSearchOptions: { query: '', topic: 'All', ...Updatable }, + promptMessage: PromptUpdateLibraries, + updatingMessage: UpdatingLibraries, + }); + } + + private prompt< + T extends ArduinoComponent, + S extends Searchable.Options + >(options: { + items: T[]; + installable: Installable; + viewContribution: AbstractViewContribution>; + viewSearchOptions: S; + promptMessage: string; + updatingMessage: string; + }): void { + const { + items, + installable, + // viewContribution, + promptMessage: message, + // viewSearchOptions, + updatingMessage, + } = options; + + if (!items.length) { + return; + } + this.messageService + .info(message, Later, InstallManually, InstallAll) + .then((answer) => { + if (answer === InstallAll) { + const tasks = items.map((item) => + this.createInstallTask(item, installable) + ); + this.executeTasks(updatingMessage, tasks); + } else if (answer === InstallManually) { + // viewContribution + // .openView({ reveal: true }) + // .then((widget) => widget.refresh(viewSearchOptions)); + } + }); + } + + private async executeTasks( + message: string, + tasks: Task[] + ): Promise { + if (tasks.length) { + return ExecuteWithProgress.withProgress( + message, + this.messageService, + async (progress) => { + try { + const total = tasks.length; + let count = 0; + for (const { run, item } of tasks) { + try { + await run(); // runs update sequentially. // TODO: is parallel update desired? + } catch (err) { + console.error(err); + // this.messageService.error(`更新失败 ${item.name}. ${err}`); + const chunk = `更新失败 ${item.name}. ${err}\n`; + this.responseService.appendToOutput({ chunk }); + } finally { + progress.report({ work: { total, done: ++count } }); + } + } + } finally { + progress.cancel(); + } + } + ); + } + } + + private createInstallTask( + item: T, + installable: Installable + ): Task { + const latestVersion = item.availableVersions[0]; + return { + item, + run: () => + Installable.installWithProgress({ + installable, + item, + version: latestVersion, + messageService: this.messageService, + responseService: this.responseService, + keepOutput: true, + }), + }; + } +} +export namespace CheckForUpdates { + export namespace Commands { + export const CHECK_FOR_UPDATES: Command = Command.toLocalizedCommand({ + id: 'arduino-check-for-updates', + label: '检查 LingZhiLab 更新', + category: 'LingZhi', + }); + } +} diff --git a/arduino-ide-extension/src/browser/contributions/close.ts b/arduino-ide-extension/src/browser/contributions/close.ts new file mode 100644 index 000000000..7dba84e32 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/close.ts @@ -0,0 +1,244 @@ +import type { + FrontendApplication, + OnWillStopAction, +} from '@theia/core/lib/browser/frontend-application'; +import { ApplicationShell } from '@theia/core/lib/browser/shell/application-shell'; +import { nls } from '@theia/core/lib/common/nls'; +import type { MaybePromise } from '@theia/core/lib/common/types'; +import { toArray } from '@theia/core/shared/@phosphor/algorithm'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { MonacoEditor } from '@theia/monaco/lib/browser/monaco-editor'; +import { CurrentSketch } from '../sketches-service-client-impl'; +import { WindowServiceExt } from '../theia/core/window-service-ext'; +import { + Command, + CommandRegistry, + KeybindingRegistry, + Sketch, + SketchContribution, + URI, +} from './contribution'; +import { SaveAsSketch } from './save-as-sketch'; +import { Dialog } from '../theia/dialogs/theiaDialogs/dialogs'; + +/** + * Closes the `current` closeable editor, or any closeable current widget from the main area, or the current sketch window. + */ +@injectable() +export class Close extends SketchContribution { + @inject(WindowServiceExt) + private readonly windowServiceExt: WindowServiceExt; + + private shell: ApplicationShell | undefined; + + override onStart(app: FrontendApplication): MaybePromise { + this.shell = app.shell; + } + + override registerCommands(registry: CommandRegistry): void { + // 注册关闭命令 + registry.registerCommand(Close.Commands.CLOSE, { + // 执行关闭命令的函数 + execute: () => { + // 尝试关闭当前可关闭的编辑器 + const { currentEditor } = this.editorManager; + if (currentEditor && currentEditor.title.closable) { + currentEditor.close(); + return; + } + + if (this.shell) { + // 获取当前主区域的小部件,如果有可关闭的小部件则关闭它 + const { currentWidget } = this.shell; + if (currentWidget) { + const currentWidgetInMain = toArray( + this.shell.mainPanel.widgets() + ).find((widget) => widget === currentWidget); + if (currentWidgetInMain) { + return currentWidgetInMain.close(); + } + } + } + // 如果没有可关闭的编辑器或小部件,则关闭窗口 + return this.windowServiceExt.close(); + }, + }); + } + + // override registerMenus(registry: MenuModelRegistry): void { + // registry.registerMenuAction(ArduinoMenus.FILE__SKETCH_GROUP, { + // commandId: Close.Commands.CLOSE.id, + // label: nls.localize('vscode/editor.contribution/close', 'Close'), + // order: '6', + // }); + // } + + override registerKeybindings(registry: KeybindingRegistry): void { + registry.registerKeybinding({ + command: Close.Commands.CLOSE.id, + keybinding: 'CtrlCmd+W', + }); + } + + // `FrontendApplicationContribution#onWillStop` + onWillStop(): OnWillStopAction { + return { + reason: 'save-sketch', + action: () => { + return this.showSaveSketchDialog(); + }, + }; + } + + /** + * 如果返回' true ', IDE2将关闭。否则,它不会. + */ + private async showSaveSketchDialog(): Promise { + // 检查当前的草图是否为临时草图,如果不是临时草图,则返回 false,表示无需进行保存草图的对话框展示。 + const sketch = await this.isCurrentSketchTemp(); + if (!sketch) { + // 如果无法获取应用的外壳(shell),则记录错误信息并返回 true,可能表示进行默认的关闭流程。 + if (!this.shell) { + console.error( + `Could not get the application shell. Something went wrong.` + ); + return true; + } + // 如果应用的外壳可以保存所有内容(可能表示有未保存的编辑器等) + if (this.shell.canSaveAll()) { + // 显示提示对话框并等待用户的响应 + const prompt = await this.prompt(false); + // 根据用户的响应进行不同的操作 + switch (prompt) { + case Prompt.DoNotSave: + // 用户选择不保存,直接返回 true,表示可以继续关闭流程 + return true; + case Prompt.Cancel: + // 用户选择取消,返回 false,表示不继续关闭流程 + return false; + case Prompt.Save: { + // 用户选择保存,调用应用外壳的保存所有方法,并返回 true,表示可以继续关闭流程 + await this.shell.saveAll(); + return true; + } + default: + // 如果出现意外的提示响应,抛出错误 + throw new Error(`Unexpected prompt: ${prompt}`); + } + } + // 如果应用外壳不能保存所有内容,直接返回 true,表示进行默认的关闭流程 + return true; + } + + // If non of the sketch files were ever touched, do not prompt the save dialog. (#1274) + const wereTouched = await Promise.all( + Sketch.uris(sketch).map((uri) => this.wasTouched(uri)) + ); + if (wereTouched.every((wasTouched) => !Boolean(wasTouched))) { + return true; + } + + const prompt = await this.prompt(true); + switch (prompt) { + case Prompt.DoNotSave: + return true; + case Prompt.Cancel: + return false; + case Prompt.Save: { + // If `save as` was canceled by user, the result will be `undefined`, otherwise the new URI. + const result = await this.commandService.executeCommand( + SaveAsSketch.Commands.SAVE_AS_SKETCH.id, + { + execOnlyIfTemp: false, + openAfterMove: false, + wipeOriginal: true, + markAsRecentlyOpened: true, + } + ); + return !!result; + } + default: + throw new Error(`Unexpected prompt: ${prompt}`); + } + } + + private async prompt(isTemp: boolean): Promise { + const { response } = await this.dialogService.showMessageBox({ + message: '保存您的草图,以便稍后再次打开它。', + title: '你确定要退出吗?', + type: 'question', + buttons: [ + nls.localizeByDefault('不保存'), + Dialog.CANCEL, + nls.localizeByDefault(isTemp ? '保存于...' : '保存'), + ], + defaultId: 2, // `Save`/`Save As...` button index is the default. + }); + switch (response) { + case 0: + return Prompt.DoNotSave; + case 1: + return Prompt.Cancel; + case 2: + return Prompt.Save; + default: + throw new Error(`Unexpected response: ${response}`); + } + } + + private async isCurrentSketchTemp(): Promise { + // 获取当前的草图对象 + const currentSketch = await this.sketchServiceClient.currentSketch(); + if (CurrentSketch.isValid(currentSketch)) { + // 检查当前草图是否为临时草图 + const isTemp = await this.sketchesService.isTemp(currentSketch); + if (isTemp) { + // 如果是临时草图,返回当前草图对象 + return currentSketch; + } + } + // 如果不是临时草图或者当前草图无效,返回 false + return false; + } + + /** + * If the file was ever touched/modified. We get this based on the `version` of the monaco model. + */ + protected async wasTouched(uri: string): Promise { + // 根据给定的 URI 获取对应的编辑器小部件(editorWidget) + const editorWidget = await this.editorManager.getByUri(new URI(uri)); + if (editorWidget) { + // 解构获取编辑器实例(editor) + const { editor } = editorWidget; + // 如果编辑器是 MonacoEditor 类型 + if (editor instanceof MonacoEditor) { + // 获取编辑器模型的版本 ID + const versionId = editor.getControl().getModel()?.getVersionId(); + // 如果版本 ID 是整数且大于 1,表示编辑器内容有过修改(被触碰过) + if (this.isInteger(versionId) && versionId > 1) { + return true; + } + } + } + // 如果没有满足上述条件,返回 false,表示未被触碰过 + return false; + } + + private isInteger(arg: unknown): arg is number { + return Number.isInteger(arg); + } +} + +enum Prompt { + Save, + DoNotSave, + Cancel, +} + +export namespace Close { + export namespace Commands { + export const CLOSE: Command = { + id: 'lingzhi-close', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/cloud-contribution.ts b/arduino-ide-extension/src/browser/contributions/cloud-contribution.ts new file mode 100644 index 000000000..5cdea8a5e --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/cloud-contribution.ts @@ -0,0 +1,122 @@ +import { CompositeTreeNode } from '@theia/core/lib/browser/tree'; +import { nls } from '@theia/core/lib/common/nls'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { CreateApi } from '../create/create-api'; +import { CreateFeatures } from '../create/create-features'; +import { CreateUri } from '../create/create-uri'; +import { Create, isNotFound } from '../create/typings'; +import { CloudSketchbookTree } from '../widgets/cloud-sketchbook/cloud-sketchbook-tree'; +import { CloudSketchbookTreeModel } from '../widgets/cloud-sketchbook/cloud-sketchbook-tree-model'; +import { CloudSketchbookTreeWidget } from '../widgets/cloud-sketchbook/cloud-sketchbook-tree-widget'; +import { SketchbookWidget } from '../widgets/sketchbook/sketchbook-widget'; +import { SketchbookWidgetContribution } from '../widgets/sketchbook/sketchbook-widget-contribution'; +import { SketchContribution } from './contribution'; +import { ResponseService } from '../../common/protocol'; + +export function sketchAlreadyExists(input: string): string { + return nls.localize( + 'arduino/cloudSketch/alreadyExists', + '云草图“{0}”已经存在。', + input + ); +} +export function sketchNotFound(input: string): string { + return nls.localize( + 'arduino/cloudSketch/notFound', + '无法拖动云素描‘{0}’。它不存在。', + input + ); +} +export const synchronizingSketchbook = nls.localize( + 'arduino/cloudSketch/synchronizingSketchbook', + '同步草图…' +); +export function pullingSketch(input: string): string { + return nls.localize( + 'arduino/cloudSketch/pulling', + "同步草图, 拉取 '{0}'...", + input + ); +} +export function pushingSketch(input: string): string { + return nls.localize( + 'arduino/cloudSketch/pushing', + "同步草图, 推送 '{0}'...", + input + ); +} + +@injectable() +export abstract class CloudSketchContribution extends SketchContribution { + @inject(SketchbookWidgetContribution) + private readonly widgetContribution: SketchbookWidgetContribution; + @inject(CreateApi) + protected readonly createApi: CreateApi; + @inject(CreateFeatures) + protected readonly createFeatures: CreateFeatures; + @inject(ResponseService) + private readonly responseService: ResponseService; + + protected async treeModel(): Promise< + (CloudSketchbookTreeModel & { root: CompositeTreeNode }) | undefined + > { + const { enabled, session } = this.createFeatures; + if (enabled && session) { + const widget = await this.widgetContribution.widget; + const treeModel = this.treeModelFrom(widget); + if (treeModel) { + const root = treeModel.root; + if (CompositeTreeNode.is(root)) { + return treeModel as CloudSketchbookTreeModel & { + root: CompositeTreeNode; + }; + } + } + } + return undefined; + } + + protected async pull( + sketch: Create.Sketch + ): Promise { + const treeModel = await this.treeModel(); + if (!treeModel) { + return undefined; + } + const id = CreateUri.toUri(sketch).path.toString(); + const node = treeModel.getNode(id); + if (!node) { + throw new Error(`找不到具有ID的云草图树节点: ${id}.`); + } + if (!CloudSketchbookTree.CloudSketchDirNode.is(node)) { + throw new Error(`云草图树节点期望表示一个目录,但它没有树节点ID: ${id}.`); + } + try { + await treeModel.sketchbookTree().pull({ node }, true); + return node; + } catch (err) { + if (isNotFound(err)) { + await treeModel.refresh(); + // this.messageService.error(sketchNotFound(sketch.name)); + const chunk = `${sketchNotFound(sketch.name)}\n`; + this.responseService.appendToOutput({ chunk }); + return undefined; + } + throw err; + } + } + + private treeModelFrom( + widget: SketchbookWidget + ): CloudSketchbookTreeModel | undefined { + for (const treeWidget of widget.getTreeWidgets()) { + if (treeWidget instanceof CloudSketchbookTreeWidget) { + const model = treeWidget.model; + if (model instanceof CloudSketchbookTreeModel) { + return model; + } + } + } + return undefined; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/compiler-errors.ts b/arduino-ide-extension/src/browser/contributions/compiler-errors.ts new file mode 100644 index 000000000..46ab8c484 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/compiler-errors.ts @@ -0,0 +1,802 @@ +import { + Command, + CommandRegistry, + Disposable, + DisposableCollection, + Emitter, + MaybeArray, + MaybePromise, + nls, + notEmpty, +} from '@theia/core'; +import { ApplicationShell, FrontendApplication } from '@theia/core/lib/browser'; +import { ITextModel } from '@theia/monaco-editor-core/esm/vs/editor/common/model'; +import URI from '@theia/core/lib/common/uri'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { + Location, + Range, +} from '@theia/core/shared/vscode-languageserver-protocol'; +import { + EditorWidget, + TextDocumentChangeEvent, +} from '@theia/editor/lib/browser'; +import { + EditorDecoration, + TrackedRangeStickiness, +} from '@theia/editor/lib/browser/decorations/editor-decoration'; +import { EditorManager } from '@theia/editor/lib/browser/editor-manager'; +import * as monaco from '@theia/monaco-editor-core'; +import { MonacoEditor } from '@theia/monaco/lib/browser/monaco-editor'; +import { MonacoToProtocolConverter } from '@theia/monaco/lib/browser/monaco-to-protocol-converter'; +import { ProtocolToMonacoConverter } from '@theia/monaco/lib/browser/protocol-to-monaco-converter'; +import { OutputUri } from '@theia/output/lib/common/output-uri'; +import { CoreError } from '../../common/protocol/core-service'; +import { ErrorRevealStrategy } from '../arduino-preferences'; +import { ArduinoOutputSelector, InoSelector } from '../selectors'; +import { Contribution } from './contribution'; +import { CoreErrorHandler } from './core-error-handler'; +import { MonacoEditorModel } from '@theia/monaco/lib/browser/monaco-editor-model'; + +interface ErrorDecorationRef { + /** + * This is the unique ID of the decoration given by `monaco`. + */ + readonly id: string; + /** + * The resource this decoration belongs to. + */ + readonly uri: string; +} +export namespace ErrorDecorationRef { + export function is(arg: unknown): arg is ErrorDecorationRef { + if (typeof arg === 'object') { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const object = arg as any; + return ( + 'uri' in object && + typeof object['uri'] === 'string' && + 'id' in object && + typeof object['id'] === 'string' + ); + } + return false; + } + export function sameAs( + left: ErrorDecorationRef, + right: ErrorDecorationRef + ): boolean { + return left.id === right.id && left.uri === right.uri; + } +} + +interface ErrorDecoration extends ErrorDecorationRef { + /** + * The range of the error location the error in the compiler output from the CLI. + */ + readonly rangesInOutput: monaco.Range[]; +} +namespace ErrorDecoration { + export function rangeOf( + editorOrModel: MonacoEditor | ITextModel | undefined, + decorations: ErrorDecoration + ): monaco.Range | undefined; + export function rangeOf( + editorOrModel: MonacoEditor | ITextModel | undefined, + decorations: ErrorDecoration[] + ): (monaco.Range | undefined)[]; + export function rangeOf( + editorOrModel: MonacoEditor | ITextModel | undefined, + decorations: ErrorDecoration | ErrorDecoration[] + ): MaybePromise> { + if (editorOrModel) { + const allDecorations = getAllDecorations(editorOrModel); + if (allDecorations) { + if (Array.isArray(decorations)) { + return decorations.map(({ id: decorationId }) => + findRangeOf(decorationId, allDecorations) + ); + } else { + return findRangeOf(decorations.id, allDecorations); + } + } + } + return Array.isArray(decorations) + ? decorations.map(() => undefined) + : undefined; + } + function findRangeOf( + decorationId: string, + allDecorations: { id: string; range?: monaco.Range }[] + ): monaco.Range | undefined { + return allDecorations.find( + ({ id: candidateId }) => candidateId === decorationId + )?.range; + } + function getAllDecorations( + editorOrModel: MonacoEditor | ITextModel + ): { id: string; range?: monaco.Range }[] { + if (editorOrModel instanceof MonacoEditor) { + const model = editorOrModel.getControl().getModel(); + if (!model) { + return []; + } + return model.getAllDecorations(); + } + return editorOrModel.getAllDecorations(); + } +} + +@injectable() +export class CompilerErrors + extends Contribution + implements monaco.languages.CodeLensProvider, monaco.languages.LinkProvider { + @inject(EditorManager) + private readonly editorManager: EditorManager; + + @inject(ProtocolToMonacoConverter) + private readonly p2m: ProtocolToMonacoConverter; + + @inject(MonacoToProtocolConverter) + private readonly m2p: MonacoToProtocolConverter; + + @inject(CoreErrorHandler) + private readonly coreErrorHandler: CoreErrorHandler; + + private revealStrategy = ErrorRevealStrategy.Default; + private experimental = false; + + private readonly errors: ErrorDecoration[] = []; + private readonly onDidChangeEmitter = new monaco.Emitter(); + private readonly currentErrorDidChangEmitter = new Emitter(); + private readonly onCurrentErrorDidChange = + this.currentErrorDidChangEmitter.event; + private readonly toDisposeOnCompilerErrorDidChange = + new DisposableCollection(); + + private shell: ApplicationShell | undefined; + private currentError: ErrorDecoration | undefined; + private get currentErrorIndex(): number { + const current = this.currentError; + if (!current) { + return -1; + } + return this.errors.findIndex((error) => + ErrorDecorationRef.sameAs(error, current) + ); + } + + override onStart(app: FrontendApplication): void { + this.shell = app.shell; + monaco.languages.registerCodeLensProvider(InoSelector, this); + monaco.languages.registerLinkProvider(ArduinoOutputSelector, this); + this.coreErrorHandler.onCompilerErrorsDidChange((errors) => + this.handleCompilerErrorsDidChange(errors) + ); + this.onCurrentErrorDidChange(async (error) => { + const monacoEditor = await this.monacoEditor(error.uri); + const monacoRange = ErrorDecoration.rangeOf(monacoEditor, error); + if (!monacoRange) { + console.warn( + 'compiler-errors', + `Could not find range of decoration: ${error.id}` + ); + return; + } + const range = this.m2p.asRange(monacoRange); + const editor = await this.revealLocationInEditor({ + uri: error.uri, + range, + }); + if (!editor) { + console.warn( + 'compiler-errors', + `Failed to mark error ${error.id} as the current one.` + ); + } else { + const monacoEditor = this.monacoEditor(editor); + if (monacoEditor) { + monacoEditor.cursor = range.start; + } + } + }); + } + + override onReady(): MaybePromise { + this.preferences.ready.then(() => { + this.experimental = Boolean( + this.preferences['arduino.compile.experimental'] + ); + const strategy = this.preferences['arduino.compile.revealRange']; + this.revealStrategy = ErrorRevealStrategy.is(strategy) + ? strategy + : ErrorRevealStrategy.Default; + this.preferences.onPreferenceChanged( + ({ preferenceName, newValue, oldValue }) => { + if (newValue === oldValue) { + return; + } + switch (preferenceName) { + case 'arduino.compile.revealRange': { + this.revealStrategy = ErrorRevealStrategy.is(newValue) + ? newValue + : ErrorRevealStrategy.Default; + return; + } + case 'arduino.compile.experimental': { + this.experimental = Boolean(newValue); + this.onDidChangeEmitter.fire(this); + return; + } + } + } + ); + }); + } + + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(CompilerErrors.Commands.NEXT_ERROR, { + execute: () => { + const index = this.currentErrorIndex; + if (index < 0) { + console.warn( + 'compiler-errors', + `Could not advance to next error. Unknown current error.` + ); + return; + } + const nextError = + this.errors[index === this.errors.length - 1 ? 0 : index + 1]; + return this.markAsCurrentError(nextError, { + forceReselect: true, + reveal: true, + }); + }, + isEnabled: () => + this.experimental && !!this.currentError && this.errors.length > 1, + }); + registry.registerCommand(CompilerErrors.Commands.PREVIOUS_ERROR, { + execute: () => { + const index = this.currentErrorIndex; + if (index < 0) { + console.warn( + 'compiler-errors', + `Could not advance to previous error. Unknown current error.` + ); + return; + } + const previousError = + this.errors[index === 0 ? this.errors.length - 1 : index - 1]; + return this.markAsCurrentError(previousError, { + forceReselect: true, + reveal: true, + }); + }, + isEnabled: () => + this.experimental && !!this.currentError && this.errors.length > 1, + }); + registry.registerCommand(CompilerErrors.Commands.MARK_AS_CURRENT, { + execute: (arg: unknown) => { + if (ErrorDecorationRef.is(arg)) { + return this.markAsCurrentError( + { id: arg.id, uri: new URI(arg.uri).toString() }, // Make sure the URI fragments are encoded. On Windows, `C:` is encoded as `C%3A`. + { forceReselect: true, reveal: true } + ); + } + }, + isEnabled: () => !!this.errors.length, + }); + } + + get onDidChange(): monaco.IEvent { + return this.onDidChangeEmitter.event; + } + + async provideCodeLenses( + model: monaco.editor.ITextModel, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _token: monaco.CancellationToken + ): Promise { + const lenses: monaco.languages.CodeLens[] = []; + if ( + this.experimental && + this.currentError && + this.currentError.uri === model.uri.toString() && + this.errors.length > 1 + ) { + const monacoEditor = await this.monacoEditor(model.uri); + const range = ErrorDecoration.rangeOf(monacoEditor, this.currentError); + if (range) { + lenses.push( + { + range, + command: { + id: CompilerErrors.Commands.PREVIOUS_ERROR.id, + title: nls.localize( + 'arduino/editor/previousError', + 'Previous Error' + ), + arguments: [this.currentError], + }, + }, + { + range, + command: { + id: CompilerErrors.Commands.NEXT_ERROR.id, + title: nls.localize('arduino/editor/nextError', 'Next Error'), + arguments: [this.currentError], + }, + } + ); + } + } + return { + lenses, + dispose: () => { + /* NOOP */ + }, + }; + } + + async provideLinks( + model: monaco.editor.ITextModel, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _token: monaco.CancellationToken + ): Promise { + const links: monaco.languages.ILink[] = []; + if ( + model.uri.scheme === OutputUri.SCHEME && + model.uri.path === '/Arduino' + ) { + links.push( + ...this.errors + .filter((decoration) => !!decoration.rangesInOutput.length) + .map(({ rangesInOutput, id, uri }) => + rangesInOutput.map( + (range) => + { + range, + url: monaco.Uri.parse(`command://`).with({ + query: JSON.stringify({ id, uri }), + path: CompilerErrors.Commands.MARK_AS_CURRENT.id, + }), + tooltip: nls.localize( + 'arduino/editor/revealError', + 'Reveal Error' + ), + } + ) + ) + .reduce((acc, curr) => acc.concat(curr), []) + ); + } else { + console.warn('unexpected URI: ' + model.uri.toString()); + } + return { links }; + } + + async resolveLink( + link: monaco.languages.ILink, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _token: monaco.CancellationToken + ): Promise { + if (!this.experimental) { + return undefined; + } + const { url } = link; + if (url) { + const candidateUri = new URI( + typeof url === 'string' ? url : url.toString() + ); + const candidateId = candidateUri.path.toString(); + const error = this.errors.find((error) => error.id === candidateId); + if (error) { + const monacoEditor = await this.monacoEditor(error.uri); + const range = ErrorDecoration.rangeOf(monacoEditor, error); + if (range) { + return { + range, + url: monaco.Uri.parse(error.uri), + }; + } + } + } + return undefined; + } + + private async handleCompilerErrorsDidChange( + errors: CoreError.ErrorLocation[] + ): Promise { + this.toDisposeOnCompilerErrorDidChange.dispose(); + const groupedErrors = this.groupBy( + errors, + (error: CoreError.ErrorLocation) => error.location.uri + ); + const decorations = await this.decorateEditors(groupedErrors); + this.errors.push(...decorations.errors); + this.toDisposeOnCompilerErrorDidChange.pushAll([ + Disposable.create(() => (this.errors.length = 0)), + Disposable.create(() => this.onDidChangeEmitter.fire(this)), + ...(await Promise.all([ + decorations.dispose, + this.trackEditors( + groupedErrors, + (editor) => + editor.onSelectionChanged((selection) => + this.handleSelectionChange(editor, selection) + ), + (editor) => + editor.onDispose(() => + this.handleEditorDidDispose(editor.uri.toString()) + ), + (editor) => + editor.onDocumentContentChanged((event) => + this.handleDocumentContentChange(editor, event) + ) + ), + ])), + ]); + const currentError = this.errors[0]; + if (currentError) { + await this.markAsCurrentError(currentError, { + forceReselect: true, + reveal: true, + }); + } + } + + private async decorateEditors( + errors: Map + ): Promise<{ dispose: Disposable; errors: ErrorDecoration[] }> { + const composite = await Promise.all( + [...errors.entries()].map(([uri, errors]) => + this.decorateEditor(uri, errors) + ) + ); + return { + dispose: new DisposableCollection( + ...composite.map(({ dispose }) => dispose) + ), + errors: composite.reduce( + (acc, { errors }) => acc.concat(errors), + [] as ErrorDecoration[] + ), + }; + } + + private async decorateEditor( + uri: string, + errors: CoreError.ErrorLocation[] + ): Promise<{ dispose: Disposable; errors: ErrorDecoration[] }> { + const editor = await this.monacoEditor(uri); + if (!editor) { + return { dispose: Disposable.NULL, errors: [] }; + } + const oldDecorations = editor.deltaDecorations({ + oldDecorations: [], + newDecorations: errors.map((error) => + this.compilerErrorDecoration(error.location.range) + ), + }); + return { + dispose: Disposable.create(() => { + if (editor) { + editor.deltaDecorations({ + oldDecorations, + newDecorations: [], + }); + } + }), + errors: oldDecorations.map((id, index) => ({ + id, + uri, + rangesInOutput: errors[index].rangesInOutput.map((range) => + this.p2m.asRange(range) + ), + })), + }; + } + + private compilerErrorDecoration(range: Range): EditorDecoration { + return { + range, + options: { + isWholeLine: true, + className: 'compiler-error', + stickiness: TrackedRangeStickiness.NeverGrowsWhenTypingAtEdges, + }, + }; + } + + /** + * Tracks the selection in all editors that have an error. If the editor selection overlaps one of the compiler error's range, mark as current error. + */ + private handleSelectionChange( + monacoEditor: MonacoEditor, + selection: Range + ): void { + const uri = monacoEditor.uri.toString(); + const monacoSelection = this.p2m.asRange(selection); + console.log( + 'compiler-errors', + `Handling selection change in editor ${uri}. New (monaco) selection: ${monacoSelection.toJSON()}` + ); + const calculatePriority = ( + candidateErrorRange: monaco.Range, + currentSelection: monaco.Range + ) => { + console.trace( + 'compiler-errors', + `Candidate error range: ${candidateErrorRange.toJSON()}` + ); + console.trace( + 'compiler-errors', + `Current selection range: ${currentSelection.toJSON()}` + ); + if (candidateErrorRange.intersectRanges(currentSelection)) { + console.trace('Intersects.'); + return { score: 2 }; + } + if ( + candidateErrorRange.startLineNumber <= + currentSelection.startLineNumber && + candidateErrorRange.endLineNumber >= currentSelection.endLineNumber + ) { + console.trace('Same line.'); + return { score: 1 }; + } + + console.trace('No match'); + return undefined; + }; + const errorsPerResource = this.errors.filter((error) => error.uri === uri); + const rangesPerResource = ErrorDecoration.rangeOf( + monacoEditor, + errorsPerResource + ); + const error = rangesPerResource + .map((range, index) => ({ error: errorsPerResource[index], range })) + .map(({ error, range }) => { + if (range) { + const priority = calculatePriority(range, monacoSelection); + if (priority) { + return { ...priority, error }; + } + } + return undefined; + }) + .filter(notEmpty) + .sort((left, right) => right.score - left.score) // highest first + .map(({ error }) => error) + .shift(); + if (error) { + this.markAsCurrentError(error); + } else { + console.info( + 'compiler-errors', + `New (monaco) selection ${monacoSelection.toJSON()} does not intersect any error locations. Skipping.` + ); + } + } + + /** + * This code does not deal with resource deletion, but tracks editor dispose events. It does not matter what was the cause of the editor disposal. + * If editor closes, delete the decorators. + */ + private handleEditorDidDispose(uri: string): void { + let i = this.errors.length; + // `splice` re-indexes the array. It's better to "iterate and modify" from the last element. + while (i--) { + const error = this.errors[i]; + if (error.uri === uri) { + this.errors.splice(i, 1); + } + } + this.onDidChangeEmitter.fire(this); + } + + /** + * If the text document changes in the line where compiler errors are, the compiler errors will be removed. + */ + private handleDocumentContentChange( + monacoEditor: MonacoEditor, + event: TextDocumentChangeEvent + ): void { + const errorsPerResource = this.errors.filter( + (error) => error.uri === event.document.uri + ); + let editorOrModel: MonacoEditor | ITextModel = monacoEditor; + const doc = event.document; + if (doc instanceof MonacoEditorModel) { + editorOrModel = doc.textEditorModel; + } + const rangesPerResource = ErrorDecoration.rangeOf( + editorOrModel, + errorsPerResource + ); + const resolvedDecorations = rangesPerResource.map((range, index) => ({ + error: errorsPerResource[index], + range, + })); + const decoratorsToRemove = event.contentChanges + .map(({ range }) => this.p2m.asRange(range)) + .map((changedRange) => + resolvedDecorations + .filter(({ range: decorationRange }) => { + if (!decorationRange) { + return false; + } + const affects = + changedRange.startLineNumber <= decorationRange.startLineNumber && + changedRange.endLineNumber >= decorationRange.endLineNumber; + console.log( + 'compiler-errors', + `decoration range: ${decorationRange.toString()}, change range: ${changedRange.toString()}, affects: ${affects}` + ); + return affects; + }) + .map(({ error }) => { + const index = this.errors.findIndex((candidate) => + ErrorDecorationRef.sameAs(candidate, error) + ); + return index !== -1 ? { error, index } : undefined; + }) + .filter(notEmpty) + ) + .reduce((acc, curr) => acc.concat(curr), []) + .sort((left, right) => left.index - right.index); // highest index last + + if (decoratorsToRemove.length) { + let i = decoratorsToRemove.length; + while (i--) { + this.errors.splice(decoratorsToRemove[i].index, 1); + } + monacoEditor.getControl().deltaDecorations( + decoratorsToRemove.map(({ error }) => error.id), + [] + ); + this.onDidChangeEmitter.fire(this); + } + } + + private async trackEditors( + errors: Map, + ...track: ((editor: MonacoEditor) => Disposable)[] + ): Promise { + return new DisposableCollection( + ...(await Promise.all( + Array.from(errors.keys()).map(async (uri) => { + const editor = await this.monacoEditor(uri); + if (!editor) { + return Disposable.NULL; + } + return new DisposableCollection(...track.map((t) => t(editor))); + }) + )) + ); + } + + private async markAsCurrentError( + ref: ErrorDecorationRef, + options?: { forceReselect?: boolean; reveal?: boolean } + ): Promise { + const index = this.errors.findIndex((candidate) => + ErrorDecorationRef.sameAs(candidate, ref) + ); + if (index < 0) { + console.warn( + 'compiler-errors', + `Failed to mark error ${ref.id + } as the current one. Error is unknown. Known errors are: ${this.errors.map( + ({ id }) => id + )}` + ); + return; + } + const newError = this.errors[index]; + if ( + options?.forceReselect || + !this.currentError || + !ErrorDecorationRef.sameAs(this.currentError, newError) + ) { + this.currentError = this.errors[index]; + console.log( + 'compiler-errors', + `Current error changed to ${this.currentError.id}` + ); + if (options?.reveal) { + this.currentErrorDidChangEmitter.fire(this.currentError); + } + this.onDidChangeEmitter.fire(this); + } + } + + // The double editor activation logic is required: https://github.com/eclipse-theia/theia/issues/11284 + private async revealLocationInEditor( + location: Location + ): Promise { + const { uri, range } = location; + const editor = await this.editorManager.getByUri(new URI(uri), { + mode: 'activate', + }); + if (editor && this.shell) { + // to avoid flickering, reveal the range here and not with `getByUri`, because it uses `at: 'center'` for the reveal option. + // TODO: check the community reaction whether it is better to set the focus at the error marker. it might cause flickering even if errors are close to each other + editor.editor.revealRange(range, { at: this.revealStrategy }); + const activeWidget = await this.shell.activateWidget(editor.id); + if (!activeWidget) { + console.warn( + 'compiler-errors', + `editor widget activation has failed. editor widget ${editor.id} expected to be the active one.` + ); + return editor; + } + if (editor !== activeWidget) { + console.warn( + 'compiler-errors', + `active widget was not the same as previously activated editor. editor widget ID ${editor.id}, active widget ID: ${activeWidget.id}` + ); + } + return editor; + } + console.warn( + 'compiler-errors', + `could not find editor widget for URI: ${uri}` + ); + return undefined; + } + + private groupBy( + elements: V[], + extractKey: (element: V) => K + ): Map { + return elements.reduce((acc, curr) => { + const key = extractKey(curr); + let values = acc.get(key); + if (!values) { + values = []; + acc.set(key, values); + } + values.push(curr); + return acc; + }, new Map()); + } + + private monacoEditor(widget: EditorWidget): MonacoEditor | undefined; + private monacoEditor( + uri: string | monaco.Uri + ): Promise; + private monacoEditor( + uriOrWidget: string | monaco.Uri | EditorWidget + ): MaybePromise { + if (uriOrWidget instanceof EditorWidget) { + const editor = uriOrWidget.editor; + if (editor instanceof MonacoEditor) { + return editor; + } + return undefined; + } else { + return this.editorManager + .getByUri(new URI(uriOrWidget)) + .then((editor) => { + if (editor) { + return this.monacoEditor(editor); + } + return undefined; + }); + } + } +} +export namespace CompilerErrors { + export namespace Commands { + export const NEXT_ERROR: Command = { + id: 'lingzhi-editor-next-error', + }; + export const PREVIOUS_ERROR: Command = { + id: 'lingzhi-editor-previous-error', + }; + export const MARK_AS_CURRENT: Command = { + id: 'lingzhi-editor-mark-as-current-error', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/contribution.ts b/arduino-ide-extension/src/browser/contributions/contribution.ts new file mode 100644 index 000000000..d9fe56641 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/contribution.ts @@ -0,0 +1,360 @@ +import { + inject, + injectable, + interfaces, + postConstruct, +} 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'; +import { LabelProvider } from '@theia/core/lib/browser/label-provider'; +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, +} from '@theia/core/lib/common/menu'; +import { + KeybindingRegistry, + KeybindingContribution, +} from '@theia/core/lib/browser/keybinding'; +import { + TabBarToolbarContribution, + TabBarToolbarRegistry, +} from '@theia/core/lib/browser/shell/tab-bar-toolbar'; +import { + FrontendApplicationContribution, + FrontendApplication, +} from '@theia/core/lib/browser/frontend-application'; +import { + Command, + CommandRegistry, + CommandContribution, + CommandService, +} from '@theia/core/lib/common/command'; +import { SettingsService } from '../dialogs/settings/settings'; +import { + CurrentSketch, + SketchesServiceClientImpl, +} from '../sketches-service-client-impl'; +import { + SketchesService, + FileSystemExt, + Sketch, + CoreService, + CoreError, + ResponseServiceClient, +} from '../../common/protocol'; +import { ArduinoPreferences } from '../arduino-preferences'; +import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state'; +import { nls } from '@theia/core'; +import { OutputChannelManager } from '../theia/output/output-channel'; +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/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'; +import { ConfigServiceClient } from '../config/config-service-client'; +import { ApplicationShell } from '@theia/core/lib/browser/shell/application-shell'; +import { DialogService } from '../dialog-service'; +import { ApplicationConnectionStatusContribution } from '../theia/core/connection-status-service'; + +export { + Command, + CommandRegistry, + MenuModelRegistry, + KeybindingRegistry, + TabBarToolbarRegistry, + URI, + Sketch, + open, +}; + +@injectable() +export abstract class Contribution + implements + CommandContribution, + MenuContribution, + KeybindingContribution, + TabBarToolbarContribution, + FrontendApplicationContribution { + @inject(ILogger) + protected readonly logger: ILogger; + + @inject(MessageService) + protected readonly messageService: MessageService; + + @inject(CommandService) + protected readonly commandService: CommandService; + + @inject(WorkspaceService) + protected readonly workspaceService: WorkspaceService; + + @inject(LabelProvider) + protected readonly labelProvider: LabelProvider; + + @inject(SettingsService) + protected readonly settingsService: SettingsService; + + @inject(ArduinoPreferences) + protected readonly preferences: ArduinoPreferences; + + @inject(FrontendApplicationStateService) + protected readonly appStateService: FrontendApplicationStateService; + + @inject(MainMenuManager) + protected readonly menuManager: MainMenuManager; + + @inject(DialogService) + protected readonly dialogService: DialogService; + + @postConstruct() + protected init(): void { + this.appStateService.reachedState('ready').then(() => this.onReady()); + } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function, unused-imports/no-unused-vars + onStart(app: FrontendApplication): MaybePromise { } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function, unused-imports/no-unused-vars + registerCommands(registry: CommandRegistry): void { } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function, unused-imports/no-unused-vars + registerMenus(registry: MenuModelRegistry): void { } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function, unused-imports/no-unused-vars + registerKeybindings(registry: KeybindingRegistry): void { } + + // eslint-disable-next-line @typescript-eslint/no-unused-vars, @typescript-eslint/no-empty-function, unused-imports/no-unused-vars + registerToolbarItems(registry: TabBarToolbarRegistry): void { } + + // eslint-disable-next-line @typescript-eslint/no-empty-function + onReady(): MaybePromise { } +} + +@injectable() +export abstract class SketchContribution extends Contribution { + @inject(FileService) + protected readonly fileService: FileService; + + @inject(FileSystemExt) + protected readonly fileSystemExt: FileSystemExt; + + @inject(ConfigServiceClient) + protected readonly configService: ConfigServiceClient; + + @inject(SketchesService) + protected readonly sketchesService: SketchesService; + + @inject(OpenerService) + protected readonly openerService: OpenerService; + + @inject(SketchesServiceClientImpl) + protected readonly sketchServiceClient: SketchesServiceClientImpl; + + @inject(EditorManager) + protected readonly editorManager: EditorManager; + + @inject(OutputChannelManager) + protected readonly outputChannelManager: OutputChannelManager; + + @inject(EnvVariablesServer) + protected readonly envVariableServer: EnvVariablesServer; + + @inject(ApplicationConnectionStatusContribution) + protected readonly connectionStatusService: ApplicationConnectionStatusContribution; + + protected async sourceOverride(): Promise> { + const override: Record = {}; + const sketch = await this.sketchServiceClient.currentSketch(); + if (CurrentSketch.isValid(sketch)) { + for (const editor of this.editorManager.all) { + const uri = editor.editor.uri; + if (Saveable.isDirty(editor) && Sketch.isInSketch(uri, sketch)) { + override[uri.toString()] = editor.editor.document.getText(); + } + } + } + return override; + } + + /** + * Defaults to `directories.user` if defined and not CLI config errors were detected. + * Otherwise, the URI of the user home directory. + */ + protected async defaultUri(): Promise { + // 获取配置服务中的错误信息 + const errors = this.configService.tryGetMessages(); + // 尝试获取 Sketch 目录的 URI + let defaultUri = this.configService.tryGetSketchDirUri(); + if (!defaultUri || errors?.length) { + // 如果默认 URI 未定义或者存在 CLI 配置错误,则回退到用户主目录 + defaultUri = new URI(await this.envVariableServer.getHomeDirUri()); + } + return defaultUri; + } + + /** + * 获取默认路径。 + * 先调用 defaultUri 方法获取默认的 URI,然后将其转换为文件系统路径并返回。 + */ + protected async defaultPath(): Promise { + const defaultUri = await this.defaultUri(); + return this.fileService.fsPath(defaultUri); + } +} + +@injectable() +export abstract class CoreServiceContribution extends SketchContribution { + @inject(BoardsDataStore) + protected readonly boardsDataStore: BoardsDataStore; + + @inject(BoardsServiceProvider) + protected readonly boardsServiceProvider: BoardsServiceProvider; + + @inject(CoreService) + private readonly coreService: CoreService; + + @inject(ClipboardService) + private readonly clipboardService: ClipboardService; + + @inject(ResponseServiceClient) + private readonly responseService: ResponseServiceClient; + + @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.) + */ + private visibleNotificationId: string | undefined; + + protected clearVisibleNotification(): void { + if (this.visibleNotificationId) { + this.notificationManager.clear(this.visibleNotificationId); + this.visibleNotificationId = undefined; + } + } + + protected handleError(error: unknown): void { + this.tryToastErrorMessage(error); + } + + private tryToastErrorMessage(error: unknown): void { + let message: undefined | string = undefined; + if (CoreError.is(error)) { + message = error.message; + } else if (error instanceof Error) { + message = error.message; + } else if (typeof error === 'string') { + message = error; + } else { + try { + message = JSON.stringify(error); + } catch { } + } + if (message) { + if (message.includes('Missing FQBN (Fully Qualified Board Name)')) { + message = '没有选择板。请从代码页面中选择Lingzhi板'; + } + const copyAction = nls.localize( + 'arduino/coreContribution/copyError', + '复制错误信息' + ); + this.visibleNotificationId = this.notificationId(message, copyAction); + // this.messageService.error(message, copyAction).then(async (action) => { + // if (action === copyAction) { + // const content = await this.outputChannelManager.contentOfChannel( + // 'Arduino' + // ); + // if (content) { + // this.clipboardService.writeText(content); + // } + // } + // }); + message = message.includes( + "Cannot read properties of undefined (reading 'board')" + ) + ? '无法读取未定义的属性(读取‘板子’)' + : message; + // const chunk = `${message}\n`; + // this.responseService.appendToOutput({ chunk }); + } else { + throw error; + } + } + + protected async doWithProgress(options: { + progressText: string; + keepOutput?: boolean; + task: (progressId: string, coreService: CoreService) => Promise; + }): Promise { + const toDisposeOnComplete = new DisposableCollection( + this.maybeActivateMonitorWidget() + ); + const { progressText, keepOutput, task } = options; + this.outputChannelManager + .getChannel('Arduino') + .show({ preserveFocus: true }); + const result = await ExecuteWithProgress.doWithProgress({ + messageService: this.messageService, + responseService: this.responseService, + progressText, + 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, + actions, + type: MessageType.Error, + }); + } +} + +export namespace Contribution { + export function configure( + bind: interfaces.Bind, + serviceIdentifier: typeof Contribution + ): void { + bind(serviceIdentifier).toSelf().inSingletonScope(); + bind(CommandContribution).toService(serviceIdentifier); + bind(MenuContribution).toService(serviceIdentifier); + bind(KeybindingContribution).toService(serviceIdentifier); + bind(TabBarToolbarContribution).toService(serviceIdentifier); + bind(FrontendApplicationContribution).toService(serviceIdentifier); + } +} diff --git a/arduino-ide-extension/src/browser/contributions/core-error-handler.ts b/arduino-ide-extension/src/browser/contributions/core-error-handler.ts new file mode 100644 index 000000000..82aba4c00 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/core-error-handler.ts @@ -0,0 +1,32 @@ +import { Emitter, Event } from '@theia/core'; +import { injectable } from '@theia/core/shared/inversify'; +import { CoreError } from '../../common/protocol/core-service'; + +@injectable() +export class CoreErrorHandler { + private readonly errors: CoreError.ErrorLocation[] = []; + private readonly compilerErrorsDidChangeEmitter = new Emitter< + CoreError.ErrorLocation[] + >(); + + tryHandle(error: unknown): void { + if (CoreError.is(error)) { + this.errors.length = 0; + this.errors.push(...error.data); + this.fireCompilerErrorsDidChange(); + } + } + + reset(): void { + this.errors.length = 0; + this.fireCompilerErrorsDidChange(); + } + + get onCompilerErrorsDidChange(): Event { + return this.compilerErrorsDidChangeEmitter.event; + } + + private fireCompilerErrorsDidChange(): void { + this.compilerErrorsDidChangeEmitter.fire(this.errors.slice()); + } +} 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..b7df6acd9 --- /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' && + (arg).model !== undefined && + (arg).model instanceof SketchbookTreeModel && + (arg).node !== undefined && + SketchbookTree.SketchDirNode.is((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 { + 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, + { + initialValue: params.node.fileStat.name, + callback, + skipShowErrorMessageOnOpen: false, + } + ); + } +} + +export namespace CreateCloudCopy { + export namespace Commands { + export const CREATE_CLOUD_COPY: Command = { + id: 'lingzhi-create-cloud-copy', + iconClass: 'fa fa-arduino-cloud-upload', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/daemon.ts b/arduino-ide-extension/src/browser/contributions/daemon.ts new file mode 100644 index 000000000..586350d63 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/daemon.ts @@ -0,0 +1,41 @@ +import { nls } from '@theia/core'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { ArduinoDaemon } from '../../common/protocol'; +import { Contribution, Command, CommandRegistry } from './contribution'; + +@injectable() +export class Daemon extends Contribution { + @inject(ArduinoDaemon) + private readonly daemon: ArduinoDaemon; + + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(Daemon.Commands.START_DAEMON, { + execute: () => this.daemon.start(), + }); + registry.registerCommand(Daemon.Commands.STOP_DAEMON, { + execute: () => this.daemon.stop(), + }); + registry.registerCommand(Daemon.Commands.RESTART_DAEMON, { + execute: () => this.daemon.restart(), + }); + } +} +export namespace Daemon { + export namespace Commands { + export const START_DAEMON: Command = { + id: 'arduino-start-daemon', + label: nls.localize('arduino/daemon/start', 'Start Daemon'), + category: 'LingZhi', + }; + export const STOP_DAEMON: Command = { + id: 'arduino-stop-daemon', + label: nls.localize('arduino/daemon/stop', 'Stop Daemon'), + category: 'LingZhi', + }; + export const RESTART_DAEMON: Command = { + id: 'arduino-restart-daemon', + label: nls.localize('arduino/daemon/restart', 'Restart Daemon'), + category: 'LingZhi', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/debug.ts b/arduino-ide-extension/src/browser/contributions/debug.ts new file mode 100644 index 000000000..233a1e00b --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/debug.ts @@ -0,0 +1,472 @@ +/* eslint-disable prettier/prettier */ +import { Emitter, Event } from '@theia/core/lib/common/event'; +import { MenuModelRegistry } from '@theia/core/lib/common/menu/menu-model-registry'; +import { nls } from '@theia/core/lib/common/nls'; +import { MaybePromise } from '@theia/core/lib/common/types'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { noBoardSelected } from '../../common/nls'; +import { + BoardDetails, + BoardIdentifier, + BoardsService, + CheckDebugEnabledParams, + ExecutableService, + ResponseService, + SketchRef, + isBoardIdentifierChangeEvent, + isCompileSummary, +} from '../../common/protocol'; +import { BoardsDataStore } from '../boards/boards-data-store'; +import { BoardsServiceProvider } from '../boards/boards-service-provider'; +import { HostedPluginSupport } from '../hosted/hosted-plugin-support'; +import { ArduinoMenus } from '../menu/arduino-menus'; +import { NotificationCenter } from '../notification-center'; +import { CurrentSketch } from '../sketches-service-client-impl'; +import { ArduinoToolbar } from '../toolbar/arduino-toolbar'; +import { + Command, + CommandRegistry, + SketchContribution, + TabBarToolbarRegistry, + URI, +} from './contribution'; + +const COMPILE_FOR_DEBUG_KEY = 'arduino-compile-for-debug'; + +interface StartDebugParams { + /** + * Absolute filesystem path to the Arduino CLI executable. + */ + readonly cliPath: string; + /** + * The the board to debug. + */ + readonly board: Readonly<{ fqbn: string; name?: string }>; + /** + * Absolute filesystem path of the sketch to debug. + */ + readonly sketchPath: string; + /** + * Location where the `launch.json` will be created on the fly before starting every debug session. + * If not defined, it falls back to `sketchPath/.vscode/launch.json`. + */ + readonly launchConfigsDirPath?: string; + /** + * Absolute path to the `arduino-cli.yaml` file. If not specified, it falls back to `~/.arduinoIDE/arduino-cli.yaml`. + */ + readonly cliConfigPath?: string; + /** + * Programmer for the debugging. + */ + readonly programmer?: string; + /** + * Custom progress title to use when getting the debug information from the CLI. + */ + readonly title?: string; +} +type StartDebugResult = boolean; + +export const DebugDisabledStatusMessageSource = Symbol( + 'DebugDisabledStatusMessageSource' +); +export interface DebugDisabledStatusMessageSource { + /** + * `undefined` if debugging is enabled (for the currently selected board + programmer + config options). + * Otherwise, it's the human readable message why it's disabled. + */ + get message(): string | undefined; + /** + * Emits an event when {@link message} changes. + */ + get onDidChangeMessage(): Event; +} + +@injectable() +export class Debug + extends SketchContribution + implements DebugDisabledStatusMessageSource { + @inject(HostedPluginSupport) + private readonly hostedPluginSupport: HostedPluginSupport; + @inject(NotificationCenter) + private readonly notificationCenter: NotificationCenter; + @inject(ExecutableService) + private readonly executableService: ExecutableService; + @inject(BoardsService) + private readonly boardService: BoardsService; + @inject(BoardsServiceProvider) + private readonly boardsServiceProvider: BoardsServiceProvider; + @inject(BoardsDataStore) + private readonly boardsDataStore: BoardsDataStore; + @inject(ResponseService) + private readonly responseService: ResponseService; + + /** + * If `undefined`, debugging is enabled. Otherwise, the human-readable reason why it's disabled. + */ + private _message?: string = noBoardSelected; // Initial pessimism. + private readonly didChangeMessageEmitter = new Emitter(); + readonly onDidChangeMessage = this.didChangeMessageEmitter.event; + + get message(): string | undefined { + return this._message; + } + private set message(message: string | undefined) { + this._message = message; + this.didChangeMessageEmitter.fire(this._message); + } + + private readonly debugToolbarItem = { + id: Debug.Commands.START_DEBUGGING.id, + command: Debug.Commands.START_DEBUGGING.id, + tooltip: `${this.message + ? nls.localize( + 'arduino/debug/debugWithMessage', + 'Debug - {0}', + this.message + ) + : Debug.Commands.START_DEBUGGING.label + }`, + priority: 3, + onDidChange: this.onDidChangeMessage as Event, + }; + + override onStart(): void { + this.onDidChangeMessage( + () => + (this.debugToolbarItem.tooltip = `${this.message + ? nls.localize( + 'arduino/debug/debugWithMessage', + 'Debug - {0}', + this.message + ) + : Debug.Commands.START_DEBUGGING.label + }`) + ); + this.boardsServiceProvider.onBoardsConfigDidChange((event) => { + if (isBoardIdentifierChangeEvent(event)) { + this.updateMessage(); + } + }); + this.notificationCenter.onPlatformDidInstall(() => this.updateMessage()); + this.notificationCenter.onPlatformDidUninstall(() => this.updateMessage()); + this.boardsDataStore.onDidChange((event) => { + const selectedFqbn = + this.boardsServiceProvider.boardsConfig.selectedBoard?.fqbn; + if (event.changes.find((change) => change.fqbn === selectedFqbn)) { + this.updateMessage(); + } + }); + this.commandService.onDidExecuteCommand((event) => { + const { commandId, args } = event; + if ( + commandId === 'arduino.languageserver.notifyBuildDidComplete' && + isCompileSummary(args[0]) + ) { + this.updateMessage(); + } + }); + } + + override onReady(): void { + this.boardsServiceProvider.ready.then(() => this.updateMessage()); + } + + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(Debug.Commands.START_DEBUGGING, { + execute: () => this.startDebug(), + isVisible: (widget, showToolbar: boolean) => + showToolbar && ArduinoToolbar.is(widget) && widget.side === 'left', + isEnabled: () => !this.message, + }); + registry.registerCommand(Debug.Commands.TOGGLE_OPTIMIZE_FOR_DEBUG, { + execute: () => this.toggleCompileForDebug(), + isToggled: () => this.compileForDebug, + }); + registry.registerCommand(Debug.Commands.IS_OPTIMIZE_FOR_DEBUG, { + execute: () => this.compileForDebug, + }); + } + + override registerToolbarItems(registry: TabBarToolbarRegistry): void { + registry.registerItem(this.debugToolbarItem); + } + + override registerMenus(registry: MenuModelRegistry): void { + registry.registerMenuAction(ArduinoMenus.SKETCH__MAIN_GROUP, { + commandId: Debug.Commands.TOGGLE_OPTIMIZE_FOR_DEBUG.id, + label: Debug.Commands.TOGGLE_OPTIMIZE_FOR_DEBUG.label, + order: '5', + }); + } + + private async updateMessage(): Promise { + try { + await this.isDebugEnabled(); + this.message = undefined; + } catch (err) { + let message = String(err); + if (err instanceof Error) { + message = err.message; + } + this.message = message; + } + } + + private async isDebugEnabled( + board: BoardIdentifier | undefined = this.boardsServiceProvider.boardsConfig + .selectedBoard + ): Promise { + const debugFqbn = await isDebugEnabled( + board, + (fqbn) => this.boardService.getBoardDetails({ fqbn }), + (fqbn) => this.boardsDataStore.getData(fqbn), + (fqbn) => this.boardsDataStore.appendConfigToFqbn(fqbn), + (params) => this.boardService.checkDebugEnabled(params) + ); + return debugFqbn; + } + + private async startDebug( + board: BoardIdentifier | undefined = this.boardsServiceProvider.boardsConfig + .selectedBoard, + sketch: + | CurrentSketch + | undefined = this.sketchServiceClient.tryGetCurrentSketch() + ): Promise { + if (!CurrentSketch.isValid(sketch)) { + return false; + } + const params = await this.createStartDebugParams(board); + if (!params) { + return false; + } + await this.hostedPluginSupport.didStart; + try { + const result = await this.debug(params); + return Boolean(result); + } catch (err) { + if (await this.isSketchNotVerifiedError(err, sketch)) { + // const yes = nls.localize('vscode/extensionsUtils/yes', 'Yes'); + // const answer = await this.messageService.error( + // sketchIsNotCompiled(sketch.name), + // yes + // ); + // if (answer === yes) { + // this.commandService.executeCommand('lingzhi-verify-sketch'); + // } + const chunk = `在开始调试会话之前,必须验证草图.请验证草图并重新开始调试\n`; + this.responseService.appendToOutput({ chunk }); + } else { + // this.messageService.error( + // err instanceof Error ? err.message : String(err) + // ); + const chunk = `${err instanceof Error ? err.message : String(err)}\n`; + this.responseService.appendToOutput({ chunk }); + } + } + return false; + } + + private async debug( + params: StartDebugParams + ): Promise { + return this.commandService.executeCommand( + 'arduino.debug.start', + params + ); + } + + get compileForDebug(): boolean { + const value = window.localStorage.getItem(COMPILE_FOR_DEBUG_KEY); + return value === 'true'; + } + + private toggleCompileForDebug(): void { + const oldState = this.compileForDebug; + const newState = !oldState; + window.localStorage.setItem(COMPILE_FOR_DEBUG_KEY, String(newState)); + this.menuManager.update(); + } + + private async isSketchNotVerifiedError( + err: unknown, + sketch: SketchRef + ): Promise { + if (err instanceof Error) { + try { + const tempBuildPaths = await this.sketchesService.tempBuildPath(sketch); + return tempBuildPaths.some((tempBuildPath) => + err.message.includes(tempBuildPath) + ); + } catch { + return false; + } + } + return false; + } + + private async createStartDebugParams( + board: BoardIdentifier | undefined + ): Promise { + if (!board || !board.fqbn) { + return undefined; + } + let debugFqbn: string | undefined = undefined; + try { + debugFqbn = await this.isDebugEnabled(board); + } catch { } + if (!debugFqbn) { + return undefined; + } + const [sketch, executables, boardsData] = await Promise.all([ + this.sketchServiceClient.currentSketch(), + this.executableService.list(), + this.boardsDataStore.getData(board.fqbn), + ]); + if (!CurrentSketch.isValid(sketch)) { + return undefined; + } + const ideTempFolderUri = await this.sketchesService.getIdeTempFolderUri( + sketch + ); + const [cliPath, sketchPath, launchConfigsDirPath] = await Promise.all([ + this.fileService.fsPath(new URI(executables.cliUri)), + this.fileService.fsPath(new URI(sketch.uri)), + this.fileService.fsPath(new URI(ideTempFolderUri)), + ]); + return { + board: { fqbn: debugFqbn, name: board.name }, + cliPath, + sketchPath, + launchConfigsDirPath, + programmer: boardsData.selectedProgrammer?.id, + title: nls.localize( + 'arduino/debug/getDebugInfo', + 'Getting debug info...' + ), + }; + } +} +export namespace Debug { + export namespace Commands { + export const START_DEBUGGING = Command.toLocalizedCommand( + { + id: 'arduino-start-debug', + label: 'Start Debugging', + category: 'LingZhi', + }, + 'vscode/debug.contribution/startDebuggingHelp' + ); + export const TOGGLE_OPTIMIZE_FOR_DEBUG = Command.toLocalizedCommand( + { + id: 'arduino-toggle-optimize-for-debug', + label: '调试优化', + category: 'LingZhi', + }, + 'arduino/debug/optimizeForDebugging' + ); + export const IS_OPTIMIZE_FOR_DEBUG: Command = { + id: 'lingzhi-is-optimize-for-debug', + }; + } +} + +/** + * Resolves with the FQBN to use for the `debug --info --programmer p --fqbn $FQBN` command. Otherwise, rejects. + * + * (non-API) + */ +export async function isDebugEnabled( + board: BoardIdentifier | undefined, + getDetails: (fqbn: string) => MaybePromise, + getData: (fqbn: string) => MaybePromise, + appendConfigToFqbn: (fqbn: string) => MaybePromise, + checkDebugEnabled: (params: CheckDebugEnabledParams) => MaybePromise +): Promise { + if (!board) { + throw new Error(noBoardSelected); + } + const { fqbn } = board; + const str = board.fqbn as string; + const lastColonIndex = str.lastIndexOf(':'); + const valueAfterLastColon = str.slice(lastColonIndex + 1); + let name = board.name; + switch (valueAfterLastColon) { + case 'lzesp32': + name = '零知-ESP32'; + break; + case 'lzesp8266': + name = '零知-ESP8266'; + break; + case 'lingzhistandard': + name = '零知-标准板'; + break; + case 'lingzhiMini': + name = '零知-迷你板'; + break; + case 'lingzhiM4': + name = '零知-增强板'; + break; + case 'lz_ble52': + name = '零知-BLE52'; + break; + default: + name = board.name; + break; + } + if (!fqbn) { + throw new Error(noPlatformInstalledFor(name)); + } + const [details, data, fqbnWithConfig] = await Promise.all([ + getDetails(fqbn), + getData(fqbn), + appendConfigToFqbn(fqbn), + ]); + if (!details) { + throw new Error(noPlatformInstalledFor(name)); + } + if (!fqbnWithConfig) { + throw new Error(`日志含义单板配置追加到FQBN失败。原来的FQBN是: ${fqbn}`); + } + const params = { + fqbn: fqbnWithConfig, + programmer: data.selectedProgrammer?.id, + }; + try { + const debugFqbn = await checkDebugEnabled(params); + return debugFqbn; + } catch (err) { + throw new Error(debuggingNotSupported(name)); + } +} + +/** + * (non-API) + */ +export function sketchIsNotCompiled(sketchName: string): string { + return nls.localize( + 'arduino/debug/sketchIsNotCompiled', + '在开始调试会话之前,必须验证草图“{0}”。请验证草图并重新开始调试。你想现在验证一下草图吗?', + sketchName + ); +} +/** + * (non-API) + */ +export function noPlatformInstalledFor(boardName: string): string { + return nls.localize( + 'arduino/debug/noPlatformInstalledFor', + "没有安装平台 '{0}'", + boardName + ); +} +/** + * (non-API) + */ +export function debuggingNotSupported(boardName: string): string { + return nls.localize( + 'arduino/debug/debuggingNotSupported', + "不支持调试 '{0}'", + boardName + ); +} diff --git a/arduino-ide-extension/src/browser/contributions/delete-sketch.ts b/arduino-ide-extension/src/browser/contributions/delete-sketch.ts new file mode 100644 index 000000000..8092231e1 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/delete-sketch.ts @@ -0,0 +1,159 @@ +import { Dialog } from '@theia/core/lib/browser/dialogs'; +import { NavigatableWidget } from '@theia/core/lib/browser/navigatable-types'; +import { ApplicationShell } from '@theia/core/lib/browser/shell/application-shell'; +import { WindowService } from '@theia/core/lib/browser/window/window-service'; +import type { MaybeArray } from '@theia/core/lib/common/types'; +import URI from '@theia/core/lib/common/uri'; +import type { Widget } from '@theia/core/shared/@phosphor/widgets'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { SketchesError } from '../../common/protocol'; +import { Sketch } from '../contributions/contribution'; +import { isNotFound } from '../create/typings'; +import { Command, CommandRegistry } from './contribution'; +import { CloudSketchContribution } from './cloud-contribution'; +import { AppService } from '../app-service'; + +export interface DeleteSketchParams { + /** + * Either the URI of the sketch folder or the sketch to delete. + */ + readonly toDelete: string | Sketch; + /** + * If `true`, the currently opened sketch is expected to be deleted. + * Hence, the editors must be closed, the sketch will be scheduled + * for deletion, and the browser window will close or navigate away. + * If `false`, the sketch will be scheduled for deletion, + * but the current window remains open. If `force`, the window will + * navigate away, but IDE2 won't open any confirmation dialogs. + */ + readonly willNavigateAway?: boolean | 'force'; +} + +@injectable() +export class DeleteSketch extends CloudSketchContribution { + @inject(ApplicationShell) + private readonly shell: ApplicationShell; + @inject(WindowService) + private readonly windowService: WindowService; + @inject(AppService) + private readonly appService: AppService; + + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(DeleteSketch.Commands.DELETE_SKETCH, { + execute: (params: DeleteSketchParams) => this.deleteSketch(params), + }); + } + + private async deleteSketch(params: DeleteSketchParams): Promise { + const { toDelete, willNavigateAway } = params; + let sketch: Sketch; + if (typeof toDelete === 'string') { + const resolvedSketch = await this.loadSketch(toDelete); + if (!resolvedSketch) { + console.info( + `Failed to load the sketch. It was not found at '${toDelete}'. Skipping deletion.` + ); + return; + } + sketch = resolvedSketch; + } else { + sketch = toDelete; + } + if (!willNavigateAway) { + this.scheduleDeletion(sketch); + return; + } + const cloudUri = this.createFeatures.cloudUri(sketch); + if (willNavigateAway !== 'force') { + const { response } = await this.dialogService.showMessageBox({ + title: '删除', + type: 'question', + buttons: [Dialog.CANCEL, Dialog.OK], + message: cloudUri + ? `云草图‘${sketch.name}’将从Arduino服务器和本地缓存中永久删除。这种行为是不可逆转的。是否要删除当前草图?` + : `草图“${sketch.name}”将被永久删除。这种行为是不可逆转的。是否要删除当前草图?`, + }); + // cancel + if (response === 0) { + return; + } + } + if (cloudUri) { + const posixPath = cloudUri.path.toString(); + const cloudSketch = this.createApi.sketchCache.getSketch(posixPath); + if (!cloudSketch) { + throw new Error( + `Cloud sketch with path '${posixPath}' was not cached. Cache: ${this.createApi.sketchCache.toString()}` + ); + } + try { + // IDE2 cannot use DELETE directory as the server responses with HTTP 500 if it's missing. + // https://github.com/arduino/arduino-ide/issues/1825#issuecomment-1406301406 + await this.createApi.deleteSketch(cloudSketch.path); + } catch (err) { + if (!isNotFound(err)) { + throw err; + } else { + console.info( + `Could not delete the cloud sketch with path '${posixPath}'. It does not exist.` + ); + } + } + } + await Promise.all([ + ...Sketch.uris(sketch).map((uri) => + this.closeWithoutSaving(new URI(uri)) + ), + ]); + this.windowService.setSafeToShutDown(); + this.scheduleDeletion(sketch); + return window.close(); + } + + private scheduleDeletion(sketch: Sketch): void { + this.appService.scheduleDeletion(sketch); + } + + private async loadSketch(uri: string): Promise { + try { + const sketch = await this.sketchesService.loadSketch(uri); + return sketch; + } catch (err) { + if (SketchesError.NotFound.is(err)) { + return undefined; + } + throw err; + } + } + + // fix: https://github.com/eclipse-theia/theia/issues/12107 + private async closeWithoutSaving(uri: URI): Promise { + const affected = getAffected(this.shell.widgets, uri); + const toClose = [...affected].map(([, widget]) => widget); + await this.shell.closeMany(toClose, { save: false }); + } +} +export namespace DeleteSketch { + export namespace Commands { + export const DELETE_SKETCH: Command = { + id: 'lingzhi-delete-sketch', + }; + } +} + +function getAffected( + widgets: Iterable, + context: MaybeArray +): [URI, T & NavigatableWidget][] { + const uris = Array.isArray(context) ? context : [context]; + const result: [URI, T & NavigatableWidget][] = []; + for (const widget of widgets) { + if (NavigatableWidget.is(widget)) { + const resourceUri = widget.getResourceUri(); + if (resourceUri && uris.some((uri) => uri.isEqualOrParent(resourceUri))) { + result.push([resourceUri, widget]); + } + } + } + return result; +} diff --git a/arduino-ide-extension/src/browser/contributions/edit-contributions.ts b/arduino-ide-extension/src/browser/contributions/edit-contributions.ts new file mode 100644 index 000000000..b90efe42f --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/edit-contributions.ts @@ -0,0 +1,262 @@ +import { inject, injectable } from '@theia/core/shared/inversify'; +import { CommonCommands } from '@theia/core/lib/browser/common-frontend-contribution'; +import { ClipboardService } from '@theia/core/lib/browser/clipboard-service'; +import { MonacoEditorService } from '@theia/monaco/lib/browser/monaco-editor-service'; +import { + Contribution, + Command, + MenuModelRegistry, + KeybindingRegistry, + CommandRegistry, +} from './contribution'; +import { ArduinoMenus } from '../menu/arduino-menus'; +import type { ICodeEditor } from '@theia/monaco-editor-core/esm/vs/editor/browser/editorBrowser'; +import type { StandaloneCodeEditor } from '@theia/monaco-editor-core/esm/vs/editor/standalone/browser/standaloneCodeEditor'; + +// TODO: [macOS]: to remove `Start Dictation...` and `Emoji & Symbol` see this thread: https://github.com/electron/electron/issues/8283#issuecomment-269522072 +// Depends on https://github.com/eclipse-theia/theia/pull/7964 +@injectable() +export class EditContributions extends Contribution { + @inject(MonacoEditorService) + private readonly codeEditorService: MonacoEditorService; + + @inject(ClipboardService) + private readonly clipboardService: ClipboardService; + + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(EditContributions.Commands.GO_TO_LINE, { + execute: () => this.run('editor.action.gotoLine'), + }); + registry.registerCommand(EditContributions.Commands.TOGGLE_COMMENT, { + execute: () => this.run('editor.action.commentLine'), + }); + registry.registerCommand(EditContributions.Commands.INDENT_LINES, { + execute: () => this.run('editor.action.indentLines'), + }); + registry.registerCommand(EditContributions.Commands.OUTDENT_LINES, { + execute: () => this.run('editor.action.outdentLines'), + }); + registry.registerCommand(EditContributions.Commands.FIND, { + execute: () => this.run('actions.find'), + }); + registry.registerCommand(EditContributions.Commands.FIND_NEXT, { + execute: () => this.run('editor.action.nextMatchFindAction'), + }); + registry.registerCommand(EditContributions.Commands.FIND_PREVIOUS, { + execute: () => this.run('editor.action.previousMatchFindAction'), + }); + registry.registerCommand(EditContributions.Commands.USE_FOR_FIND, { + execute: () => this.run('editor.action.previousSelectionMatchFindAction'), + }); + /* Tools */ registry.registerCommand( + EditContributions.Commands.AUTO_FORMAT, + { execute: () => this.run('editor.action.formatDocument') } + ); + registry.registerCommand(EditContributions.Commands.COPY_FOR_FORUM, { + execute: async () => { + const value = await this.currentValue(); + if (value !== undefined) { + this.clipboardService.writeText(` +\`\`\`cpp +${value} +\`\`\` +`); + } + }, + }); + } + + override registerMenus(registry: MenuModelRegistry): void { + registry.registerMenuAction(ArduinoMenus.EDIT__TEXT_CONTROL_GROUP, { + commandId: CommonCommands.CUT.id, + label: '剪切', + order: '0', + }); + registry.registerMenuAction(ArduinoMenus.EDIT__TEXT_CONTROL_GROUP, { + commandId: CommonCommands.COPY.id, + label: '复制', + order: '1', + }); + // registry.registerMenuAction(ArduinoMenus.EDIT__TEXT_CONTROL_GROUP, { + // commandId: EditContributions.Commands.COPY_FOR_FORUM.id, + // label: nls.localize( + // 'arduino/editor/copyForForum', + // 'Copy for Forum (Markdown)' + // ), + // order: '2', + // }); + registry.registerMenuAction(ArduinoMenus.EDIT__TEXT_CONTROL_GROUP, { + commandId: CommonCommands.PASTE.id, + label: '粘贴', + order: '3', + }); + registry.registerMenuAction(ArduinoMenus.EDIT__TEXT_CONTROL_GROUP, { + commandId: CommonCommands.SELECT_ALL.id, + label: '全选', + order: '4', + }); + registry.registerMenuAction(ArduinoMenus.EDIT__TEXT_CONTROL_GROUP, { + commandId: EditContributions.Commands.GO_TO_LINE.id, + label: '转到行/列...', + order: '5', + }); + + registry.registerMenuAction(ArduinoMenus.EDIT__CODE_CONTROL_GROUP, { + commandId: EditContributions.Commands.TOGGLE_COMMENT.id, + label: '注释/取消注释', + order: '0', + }); + registry.registerMenuAction(ArduinoMenus.EDIT__CODE_CONTROL_GROUP, { + commandId: EditContributions.Commands.INDENT_LINES.id, + label: '增加缩进', + order: '1', + }); + registry.registerMenuAction(ArduinoMenus.EDIT__CODE_CONTROL_GROUP, { + commandId: EditContributions.Commands.OUTDENT_LINES.id, + label: '减少缩进', + order: '2', + }); + registry.registerMenuAction(ArduinoMenus.EDIT__CODE_CONTROL_GROUP, { + commandId: EditContributions.Commands.AUTO_FORMAT.id, + label: '自动格式化', + order: '3', + }); + + registry.registerMenuAction(ArduinoMenus.EDIT__FIND_GROUP, { + commandId: EditContributions.Commands.FIND.id, + label: '查找', + order: '0', + }); + registry.registerMenuAction(ArduinoMenus.EDIT__FIND_GROUP, { + commandId: EditContributions.Commands.FIND_NEXT.id, + label: '查找下一个', + order: '1', + }); + registry.registerMenuAction(ArduinoMenus.EDIT__FIND_GROUP, { + commandId: EditContributions.Commands.FIND_PREVIOUS.id, + label: '查找上一个', + order: '2', + }); + registry.registerMenuAction(ArduinoMenus.EDIT__FIND_GROUP, { + commandId: EditContributions.Commands.USE_FOR_FIND.id, + label: '查找选定内容', // XXX: The Java IDE uses `Use Selection For Find`. + order: '3', + }); + + // `Tools` + registry.registerMenuAction(ArduinoMenus.TOOLS__MAIN_GROUP, { + commandId: EditContributions.Commands.AUTO_FORMAT.id, + label: '自动格式化', // XXX: The Java IDE uses `Use Selection For Find`. + order: '0', + }); + } + + override registerKeybindings(registry: KeybindingRegistry): void { + // registry.registerKeybinding({ + // command: EditContributions.Commands.COPY_FOR_FORUM.id, + // keybinding: 'CtrlCmd+Shift+C', + // when: 'editorFocus', + // }); + registry.registerKeybinding({ + command: EditContributions.Commands.GO_TO_LINE.id, + keybinding: 'CtrlCmd+L', + when: 'editorFocus', + }); + + registry.registerKeybinding({ + command: EditContributions.Commands.TOGGLE_COMMENT.id, + keybinding: 'CtrlCmd+/', + when: 'editorFocus', + }); + + registry.registerKeybinding({ + command: EditContributions.Commands.FIND.id, + keybinding: 'CtrlCmd+F', + }); + registry.registerKeybinding({ + command: EditContributions.Commands.FIND_NEXT.id, + keybinding: 'CtrlCmd+G', + }); + registry.registerKeybinding({ + command: EditContributions.Commands.FIND_PREVIOUS.id, + keybinding: 'CtrlCmd+Shift+G', + }); + registry.registerKeybinding({ + command: EditContributions.Commands.USE_FOR_FIND.id, + keybinding: 'CtrlCmd+E', + }); + + // `Tools` + registry.registerKeybinding({ + command: EditContributions.Commands.AUTO_FORMAT.id, + keybinding: 'CtrlCmd+T', + }); + } + + protected async current(): Promise< + ICodeEditor | StandaloneCodeEditor | undefined + > { + return ( + this.codeEditorService.getFocusedCodeEditor() || + this.codeEditorService.getActiveCodeEditor() || + undefined + ); + } + + protected async currentValue(): Promise { + const currentEditor = await this.current(); + if (currentEditor) { + const selection = currentEditor.getSelection(); + if (!selection || selection.isEmpty()) { + return currentEditor.getValue(); + } + return currentEditor.getModel()?.getValueInRange(selection); + } + return undefined; + } + + protected async run(commandId: string): Promise { + const editor = await this.current(); + if (editor) { + const action = editor.getAction(commandId); + if (action) { + return action.run(); + } + } + } +} + +export namespace EditContributions { + export namespace Commands { + export const COPY_FOR_FORUM: Command = { + id: 'lingzhi-copy-for-forum', + }; + export const GO_TO_LINE: Command = { + id: 'lingzhi-go-to-line', + }; + export const TOGGLE_COMMENT: Command = { + id: 'lingzhi-toggle-comment', + }; + export const INDENT_LINES: Command = { + id: 'lingzhi-indent-lines', + }; + export const OUTDENT_LINES: Command = { + id: 'lingzhi-outdent-lines', + }; + export const FIND: Command = { + id: 'lingzhi-find', + }; + export const FIND_NEXT: Command = { + id: 'lingzhi-find-next', + }; + export const FIND_PREVIOUS: Command = { + id: 'lingzhi-find-previous', + }; + export const USE_FOR_FIND: Command = { + id: 'lingzhi-for-find', + }; + export const AUTO_FORMAT: Command = { + id: 'lingzhi-auto-format', // `Auto Format` should belong to `Tool`. + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/examples.ts b/arduino-ide-extension/src/browser/contributions/examples.ts new file mode 100644 index 000000000..5053931c0 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/examples.ts @@ -0,0 +1,415 @@ +import PQueue from 'p-queue'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { CommandHandler, CommandService } from '@theia/core/lib/common/command'; +import { MenuPath, SubMenuOptions } from '@theia/core/lib/common/menu'; +import { + Disposable, + DisposableCollection, +} from '@theia/core/lib/common/disposable'; +import { OpenSketch } from './open-sketch'; +import { ArduinoMenus, PlaceholderMenuNode } from '../menu/arduino-menus'; +import { BoardsServiceProvider } from '../boards/boards-service-provider'; +import { ExamplesService } from '../../common/protocol/examples-service'; +import { + SketchContribution, + CommandRegistry, + MenuModelRegistry, +} from './contribution'; +import { NotificationCenter } from '../notification-center'; +import { + Board, + SketchRef, + SketchContainer, + SketchesError, + CoreService, + SketchesService, + Sketch, + isBoardIdentifierChangeEvent, + BoardIdentifier, + ResponseService, +} from '../../common/protocol'; +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'; +/** + * 创建示例草图的克隆副本,并在新窗口中打开它。 + */ +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, + uri + ); + } 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 { + @inject(CommandRegistry) + private readonly commandRegistry: CommandRegistry; + + @inject(MenuModelRegistry) + protected readonly menuRegistry: MenuModelRegistry; + + @inject(ExamplesService) + protected readonly examplesService: ExamplesService; + + @inject(CoreService) + protected readonly coreService: CoreService; + + @inject(BoardsServiceProvider) + protected readonly boardsServiceProvider: BoardsServiceProvider; + + @inject(NotificationCenter) + protected readonly notificationCenter: NotificationCenter; + + @inject(ResponseService) + public readonly responseService: ResponseService; + + protected readonly toDispose = new DisposableCollection(); + + protected override init(): void { + super.init(); + // 监听电路板配置变化事件 + this.boardsServiceProvider.onBoardsConfigDidChange((event) => { + if (isBoardIdentifierChangeEvent(event)) { + this.handleBoardChanged(event.selectedBoard); + } + }); + // 监听重新初始化事件,进行更新 + this.notificationCenter.onDidReinitialize(() => + this.update({ + board: this.boardsServiceProvider.boardsConfig.selectedBoard, + // No force refresh. The core client was already refreshed. + }) + ); + } + + // 处理电路板变化的抽象方法,默认不执行任何操作 + // eslint-disable-next-line @typescript-eslint/no-unused-vars, unused-imports/no-unused-vars + protected handleBoardChanged(board: Board | undefined): void { + // NOOP + } + + protected abstract update(options?: { + board?: BoardIdentifier | undefined; + forceRefresh?: boolean; + }): void; + + // override registerMenus(registry: MenuModelRegistry): void { + // // 注册子菜单 + // registry.registerSubmenu( + // ArduinoMenus.FILE__EXAMPLES_SUBMENU, // 注册子菜单的路径 + // examplesLabel, // 子菜单的标签 + // { + // order: '4', // 子菜单的显示顺序 + // } + // ); + // } + + registerRecursively( + sketchContainerOrPlaceholder: + | SketchContainer + | (SketchRef | SketchContainer)[] + | string, + menuPath: MenuPath, + pushToDispose: DisposableCollection = new DisposableCollection(), + subMenuOptions?: SubMenuOptions | undefined + ): void { + if (typeof sketchContainerOrPlaceholder === 'string') { + // 如果传入的是字符串,创建占位节点并注册 + const placeholder = new PlaceholderMenuNode( + menuPath, + sketchContainerOrPlaceholder + ); + this.menuRegistry.registerMenuNode(menuPath, placeholder); + pushToDispose.push( + Disposable.create(() => + this.menuRegistry.unregisterMenuNode(placeholder.id) + ) + ); + } else { + const sketches: SketchRef[] = []; + const children: SketchContainer[] = []; + let submenuPath = menuPath; + + if (SketchContainer.is(sketchContainerOrPlaceholder)) { + // 如果传入的是 SketchContainer 类型,处理并注册子菜单 + const { label } = sketchContainerOrPlaceholder; + submenuPath = [...menuPath, label]; + this.menuRegistry.registerSubmenu(submenuPath, label, subMenuOptions); + this.toDispose.push( + Disposable.create(() => + unregisterSubmenu(submenuPath, this.menuRegistry) + ) + ); + sketches.push(...sketchContainerOrPlaceholder.sketches); + children.push(...sketchContainerOrPlaceholder.children); + } else { + // 如果传入的是数组类型,遍历分类并处理 + for (const sketchOrContainer of sketchContainerOrPlaceholder) { + if (SketchContainer.is(sketchOrContainer)) { + children.push(sketchOrContainer); + } else { + sketches.push(sketchOrContainer); + } + } + } + + // 递归注册子菜单和动作 + children.forEach((child) => + this.registerRecursively(child, submenuPath, pushToDispose) + ); + for (const sketch of sketches) { + const { uri } = sketch; + const commandId = `arduino-open-example-${submenuPath.join( + ':' + )}--${uri}`; + const command = { id: commandId }; + const handler = this.createHandler(uri); + pushToDispose.push( + this.commandRegistry.registerCommand(command, { + execute: () => { + const today = new Date(); + // localStorage.setItem( + // 'arduino-new-sketch-executedB', + // today.toLocaleString() + // ); + localStorage.setItem( + 'lingzhi-open-sketch-view', + today.toLocaleString() + ); + return handler.execute(); + }, + }) + // this.commandRegistry.registerCommand(command, handler) + ); + // 注册菜单动作 + this.menuRegistry.registerMenuAction(submenuPath, { + commandId, + label: sketch.name, + order: sketch.name.toLocaleLowerCase(), + }); + pushToDispose.push( + Disposable.create(() => + this.menuRegistry.unregisterMenuAction(command) + ) + ); + } + } + } + + protected createHandler(uri: string): CommandHandler { + // 定义一个强制更新的函数,用于更新某些状态 + const forceUpdate = () => + this.update({ + board: this.boardsServiceProvider.boardsConfig.selectedBoard, + forceRefresh: true, + }); + return { + // 命令执行函数 + execute: async () => { + // 等待打开克隆后的示例的操作 + await openClonedExample( + uri, + { + sketchesService: this.sketchesService, + commandService: this.commandRegistry, + }, + { + // 当克隆失败时的回调函数 + onDidFailClone: () => { + // 克隆失败处理,不显示错误消息,由打开草图命令处理 + forceUpdate(); + }, + // 当打开失败时的回调函数 + onDidFailOpen: (err) => { + // this.messageService.error(err.message); + const chunk = `${err.message}\n`; + this.responseService.appendToOutput({ chunk }); + forceUpdate(); + }, + } + ); + }, + }; + } +} + +@injectable() +export class BuiltInExamples extends Examples { + override async onReady(): Promise { + this.update(); // no `await` + } + + protected override async update(): Promise { + let sketchContainers: SketchContainer[] | undefined; + try { + // 获取内置示例草图容器 + sketchContainers = await this.examplesService.builtIns(); + } catch (e) { + console.error('Could not initialize built-in examples.', e); + // 显示错误消息 + // this.messageService.error( + // nls.localize( + // 'arduino/examples/couldNotInitializeExamples', + // '无法初始化内置示例。' + // ) + // ); + const chunk = `无法初始化内置示例\n`; + this.responseService.appendToOutput({ chunk }); + return; + } + this.toDispose.dispose(); + for (const container of [ + nls.localize('arduino/examples/builtInExamples', '内置的例子'), + ...sketchContainers, + ]) { + // 递归注册内置示例草图容器 + this.registerRecursively( + container, + ArduinoMenus.EXAMPLES__BUILT_IN_GROUP, + this.toDispose + ); + } + this.menuManager.update(); + } +} + +@injectable() +export class LibraryExamples extends Examples { + private readonly queue = new PQueue({ autoStart: true, concurrency: 1 }); + + override onStart(): void { + // 监听库安装和卸载事件,进行更新 + this.notificationCenter.onLibraryDidInstall(() => this.update()); + this.notificationCenter.onLibraryDidUninstall(() => this.update()); + } + + override onReady(): void { + // 当电路板服务准备好时更新 + this.boardsServiceProvider.ready.then(() => this.update()); + } + + protected override handleBoardChanged(board: Board | undefined): void { + this.update({ board }); + } + + protected override async update( + options: { board?: Board; forceRefresh?: boolean } = { + board: this.boardsServiceProvider.boardsConfig.selectedBoard, + } + ): Promise { + const { board, forceRefresh } = options; + return this.queue.add(async () => { + this.toDispose.dispose(); + if (forceRefresh) { + await this.coreService.refresh(); + } + const fqbn = board?.fqbn; + const name = board?.name; + // 获取不同类型的示例草图容器 + const { user, current, any } = await this.examplesService.installed({ + fqbn, + }); + if (user.length) { + (user as any).unshift( + nls.localize( + 'arduino/examples/customLibrary', + 'Examples from Custom Libraries' + ) + ); + } + if (name && fqbn && current.length) { + (current as any).unshift( + nls.localize('arduino/examples/for', 'Examples for {0}', name) + ); + } + if (any.length) { + (any as any).unshift( + nls.localize('arduino/examples/forAny', 'Examples for any board') + ); + } + for (const container of user) { + // 递归注册用户库示例草图容器 + this.registerRecursively( + container, + ArduinoMenus.EXAMPLES__USER_LIBS_GROUP, + this.toDispose + ); + } + for (const container of current) { + // 递归注册当前电路板示例草图容器 + this.registerRecursively( + container, + ArduinoMenus.EXAMPLES__CURRENT_BOARD_GROUP, + this.toDispose + ); + } + for (const container of any) { + // 递归注册任意电路板示例草图容器 + this.registerRecursively( + container, + ArduinoMenus.EXAMPLES__ANY_BOARD_GROUP, + this.toDispose + ); + } + this.menuManager.update(); + }); + } +} diff --git a/arduino-ide-extension/src/browser/contributions/first-startup-installer.ts b/arduino-ide-extension/src/browser/contributions/first-startup-installer.ts new file mode 100644 index 000000000..459b7734f --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/first-startup-installer.ts @@ -0,0 +1,201 @@ +import { LocalStorageService } from '@theia/core/lib/browser'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { + BoardsService, + LibraryLocation, + LibraryService, + ResponseService, +} from '../../common/protocol'; +import { Contribution } from './contribution'; +import { ApplicationShell } from '../theia/core/application-shell'; +import { BoardSelection } from './board-selection'; +import { Progress } from '@theia/core'; + +const Arduino_BuiltIn = 'Arduino_BuiltIn'; + +// 下载文件的URL +const lanzouUrl = 'https://zxjian.lanzouv.com/iAViV2ggqife'; +const lanzouUrl2 = 'https://zxjian.lanzouv.com/ig9zK2gk43vc'; +const lanzouUrl3 = 'https://zxjian.lanzouv.com/iexqm2ggqlqd'; +// 指定下载后文件的保存路径 +const savePath = 'AppData\\Local\\Lingzhi\\staging\\packages\\lingzhiboard.7z'; +const savePath2 = + 'AppData\\Local\\Lingzhi\\staging\\packages\\lingzhiboard2.7z'; +const savePath3 = + 'AppData\\Local\\Lingzhi\\staging\\packages\\lingzhiboard3.7z'; +// 指定解压缩后的文件存放目录 +const extractPath = 'AppData\\Local\\Lingzhi\\packages'; + +const lingzhiPackagePath = 'AppData\\Local\\Lingzhi\\packages\\lingzhi'; + +@injectable() +export class FirstStartupInstaller extends Contribution { + @inject(LocalStorageService) + private readonly localStorageService: LocalStorageService; + @inject(BoardsService) + private readonly boardsService: BoardsService; + @inject(LibraryService) + private readonly libraryService: LibraryService; + + @inject(ResponseService) + private readonly responseService: ResponseService; + @inject(ApplicationShell) + protected readonly applicationShell: ApplicationShell; + @inject(BoardSelection) + protected readonly boardSelection: BoardSelection; + + private progress: Progress; + localizationProvider: any; + async installLingzhiPackage() { + //=====新增 + const progress = await this.messageService.showProgress({ + text: `正在下载安装零知库(预计3分钟左右),请耐心等待`, + }); + progress.report({ + // message: "正在下载零知库。。。", + work: { done: 5, total: 100 }, + }); + let progressList: number[] = [100, 80, 50]; + const packageInstallPromises = [ + this.boardsService + .installLingzhiPackage(lanzouUrl, savePath, extractPath, 1) + .then(() => { + const poppedValue = progressList.pop(); + if (typeof poppedValue === 'number') { + progress.report({ + // message: "正在下载零知库。。。", + work: { done: poppedValue, total: 100 }, + }); + } + }), + this.boardsService + .installLingzhiPackage(lanzouUrl2, savePath2, extractPath, 2) + .then(() => { + const poppedValue = progressList.pop(); + if (typeof poppedValue === 'number') { + progress.report({ + // message: "正在下载零知库。。。", + work: { done: poppedValue, total: 100 }, + }); + } + }), + this.boardsService + .installLingzhiPackage(lanzouUrl3, savePath3, extractPath, 3) + .then(() => { + const poppedValue = progressList.pop(); + if (typeof poppedValue === 'number') { + progress.report({ + // message: "正在下载零知库。。。", + work: { done: poppedValue, total: 100 }, + }); + } + }), + ]; + try { + await Promise.all(packageInstallPromises); + console.log('所有软件包安装成功'); + } catch (error) { + console.error('软件包安装出现问题:', error); + } + this.applicationShell.refreshContainer(); + this.progress = progress; + } + + override async onReady(): Promise { + const isFirstStartup = !(await this.localStorageService.getData( + FirstStartupInstaller.INIT_LIBS_AND_PACKAGES + )); + if (isFirstStartup) { + await this.installLingzhiPackage(); + + // const avrPackage = await this.boardsService.getBoardPackage({ + // id: 'arduino:avr', + // }); + const builtInLibrary = ( + await this.libraryService.search({ query: Arduino_BuiltIn }) + ).find(({ name }) => name === Arduino_BuiltIn); // Filter by `name` to ensure "exact match". See: https://github.com/arduino/arduino-ide/issues/1526. + + let avrPackageError: Error | undefined; + let builtInLibraryError: Error | undefined; + + // if (avrPackage) { + // try { + // await this.boardsService.install({ + // item: avrPackage, + // noOverwrite: true, // We don't want to automatically replace custom platforms the user might already have in place + // }); + // } catch (e) { + // // There's no error code, I need to parse the error message: https://github.com/arduino/arduino-cli/commit/ffe4232b359fcfa87238d68acf1c3b64a1621f14#diff-10ffbdde46838dd9caa881fd1f2a5326a49f8061f6cfd7c9d430b4875a6b6895R62 + // if ( + // e.message.includes( + // `Platform ${avrPackage.id}@${avrPackage.installedVersion} already installed` + // ) + // ) { + // // If arduino:avr installation fails because it's already installed we don't want to retry on next start-up + // console.error(e); + // } else { + // // But if there is any other error (e.g.: no Internet connection), we want to retry next time + // avrPackageError = e; + // } + // } + // } else { + // avrPackageError = new Error('Could not find platform.'); + // } + + if (builtInLibrary) { + try { + await this.libraryService.install({ + item: builtInLibrary, + installDependencies: true, + noOverwrite: true, // We don't want to automatically replace custom libraries the user might already have in place + installLocation: LibraryLocation.BUILTIN, + }); + } catch (e) { + // There's no error code, I need to parse the error message: https://github.com/arduino/arduino-cli/commit/2ea3608453b17b1157f8a1dc892af2e13e40f4f0#diff-1de7569144d4e260f8dde0e0d00a4e2a218c57966d583da1687a70d518986649R95 + if (/Library (.*) is already installed/.test(e.message)) { + // If Arduino_BuiltIn installation fails because it's already installed we don't want to retry on next start-up + console.log('error installing core', e); + } else { + // But if there is any other error (e.g.: no Internet connection), we want to retry next time + builtInLibraryError = e; + } + } + } else { + builtInLibraryError = new Error('Could not find library'); + } + + if (avrPackageError) { + // this.messageService.error( + // `无法安装Arduino AVR平台: ${avrPackageError}` + // ); + const chunk = `无法安装Arduino AVR平台: ${avrPackageError}\n`; + this.responseService.appendToOutput({ chunk }); + } + if (builtInLibraryError) { + // this.messageService.error( + // `无法安装 ${Arduino_BuiltIn} 库: ${builtInLibraryError}` + // ); + // const chunk = `无法安装 ${Arduino_BuiltIn} 库: ${builtInLibraryError}\n`; + // this.responseService.appendToOutput({ chunk }); + } + + if (!avrPackageError && !builtInLibraryError) { + await this.localStorageService.setData( + FirstStartupInstaller.INIT_LIBS_AND_PACKAGES, + true + ); + } + this.progress.cancel(); + } + + let hasLingZhiPackage = await this.boardsService.hasLingZhiPackage( + lingzhiPackagePath + ); + if (!hasLingZhiPackage) { + await this.installLingzhiPackage(); + } + } +} +export namespace FirstStartupInstaller { + export const INIT_LIBS_AND_PACKAGES = 'initializedLibsAndPackages'; +} diff --git a/arduino-ide-extension/src/browser/contributions/format.ts b/arduino-ide-extension/src/browser/contributions/format.ts new file mode 100644 index 000000000..c92741f1f --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/format.ts @@ -0,0 +1,78 @@ +import { MaybePromise } from '@theia/core'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import * as monaco from '@theia/monaco-editor-core'; +import { Formatter } from '../../common/protocol/formatter'; +import { InoSelector } from '../selectors'; +import { Contribution, URI } from './contribution'; + +@injectable() +export class Format + extends Contribution + implements + monaco.languages.DocumentRangeFormattingEditProvider, + monaco.languages.DocumentFormattingEditProvider +{ + @inject(Formatter) + private readonly formatter: Formatter; + + override onStart(): MaybePromise { + monaco.languages.registerDocumentRangeFormattingEditProvider( + InoSelector, + this + ); + monaco.languages.registerDocumentFormattingEditProvider(InoSelector, this); + } + async provideDocumentRangeFormattingEdits( + model: monaco.editor.ITextModel, + range: monaco.Range, + options: monaco.languages.FormattingOptions, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _token: monaco.CancellationToken + ): Promise { + const text = await this.format(model, range, options); + return [{ range, text }]; + } + + async provideDocumentFormattingEdits( + model: monaco.editor.ITextModel, + options: monaco.languages.FormattingOptions, + // eslint-disable-next-line @typescript-eslint/no-unused-vars + _token: monaco.CancellationToken + ): Promise { + const range = model.getFullModelRange(); + const text = await this.format(model, range, options); + return [{ range, text }]; + } + + /** + * From the currently opened workspaces (IDE2 has always one), it calculates all possible + * folder locations where the `.clang-format` file could be. + */ + private formatterConfigFolderUris(model: monaco.editor.ITextModel): string[] { + const editorUri = new URI(model.uri.toString()); + return this.workspaceService + .tryGetRoots() + .map(({ resource }) => resource) + .filter((workspaceUri) => workspaceUri.isEqualOrParent(editorUri)) + .map((uri) => uri.toString()); + } + + private format( + model: monaco.editor.ITextModel, + range: monaco.Range, + options: monaco.languages.FormattingOptions + ): Promise { + console.info( + `Formatting ${model.uri.toString()} [Range: ${JSON.stringify( + range.toJSON() + )}]` + ); + const content = model.getValueInRange(range); + const formatterConfigFolderUris = this.formatterConfigFolderUris(model); + return this.formatter.format({ + content, + formatterConfigFolderUris, + options, + }); + } +} diff --git a/arduino-ide-extension/src/browser/contributions/help.ts b/arduino-ide-extension/src/browser/contributions/help.ts new file mode 100644 index 000000000..7bb34e2fe --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/help.ts @@ -0,0 +1,196 @@ +import { inject, injectable } from '@theia/core/shared/inversify'; +import { MonacoEditor } from '@theia/monaco/lib/browser/monaco-editor'; +import { EditorManager } from '@theia/editor/lib/browser/editor-manager'; +import { WindowService } from '@theia/core/lib/browser/window/window-service'; +import { CommandHandler } from '@theia/core/lib/common/command'; +import { ArduinoMenus } from '../menu/arduino-menus'; +import { QuickInputService } from '@theia/core/lib/browser/quick-input/quick-input-service'; +import { + Contribution, + Command, + MenuModelRegistry, + CommandRegistry, + KeybindingRegistry, +} from './contribution'; +import { nls } from '@theia/core/lib/common'; +import { ElectronCommands } from '@theia/core/lib/electron-browser/menu/electron-menu-contribution'; +import * as monaco from '@theia/monaco-editor-core'; +import { IDEUpdaterCommands } from '../ide-updater/ide-updater-commands'; + +@injectable() +export class Help extends Contribution { + @inject(EditorManager) + protected readonly editorManager: EditorManager; + + @inject(WindowService) + protected readonly windowService: WindowService; + + @inject(QuickInputService) + protected readonly quickInputService: QuickInputService; + + override registerCommands(registry: CommandRegistry): void { + const open = (url: string) => + this.windowService.openNewWindow(url, { external: true }); + const createOpenHandler = (url: string) => + { + execute: () => open(url), + }; + registry.registerCommand( + Help.Commands.GETTING_STARTED, + createOpenHandler('https://www.arduino.cc/en/Guide') + ); + registry.registerCommand( + Help.Commands.ENVIRONMENT, + createOpenHandler( + 'https://docs.arduino.cc/software/ide-v2/tutorials/getting-started-ide-v2' + ) + ); + registry.registerCommand( + Help.Commands.TROUBLESHOOTING, + createOpenHandler('https://support.arduino.cc/hc/en-us') + ); + registry.registerCommand( + Help.Commands.REFERENCE, + createOpenHandler('http://lingzhilab.com/content.html') + ); + registry.registerCommand(Help.Commands.FIND_IN_REFERENCE, { + execute: async () => { + let searchFor: string | undefined = undefined; + const { currentEditor } = this.editorManager; + if (currentEditor && currentEditor.editor instanceof MonacoEditor) { + const codeEditor = currentEditor.editor.getControl(); + const selection = codeEditor.getSelection(); + const model = codeEditor.getModel(); + if (model && selection && !monaco.Range.isEmpty(selection)) { + searchFor = model.getValueInRange(selection); + } + } + if (!searchFor) { + searchFor = await this.quickInputService.input({ + prompt: nls.localize( + 'arduino/help/search', + 'Search on lingzhilab.com' + ), + placeHolder: nls.localize('arduino/help/keyword', 'Type a keyword'), + }); + } + if (searchFor) { + return open( + `https://www.arduino.cc/search?q=${encodeURIComponent( + searchFor + )}&tab=reference` + ); + } + }, + }); + registry.registerCommand( + Help.Commands.FAQ, + createOpenHandler('https://support.arduino.cc/hc/en-us') + ); + registry.registerCommand( + Help.Commands.VISIT_ARDUINO, + createOpenHandler('https://www.lingzhilab.com/') + ); + registry.registerCommand( + Help.Commands.PRIVACY_POLICY, + createOpenHandler('https://www.arduino.cc/en/privacy-policy') + ); + } + + override registerMenus(registry: MenuModelRegistry): void { + registry.unregisterMenuAction({ + commandId: ElectronCommands.TOGGLE_DEVELOPER_TOOLS.id, + }); + + // registry.registerMenuAction(ArduinoMenus.HELP__MAIN_GROUP, { + // commandId: Help.Commands.GETTING_STARTED.id, + // order: '0', + // }); + // registry.registerMenuAction(ArduinoMenus.HELP__MAIN_GROUP, { + // commandId: Help.Commands.ENVIRONMENT.id, + // order: '1', + // }); + // registry.registerMenuAction(ArduinoMenus.HELP__MAIN_GROUP, { + // commandId: Help.Commands.TROUBLESHOOTING.id, + // order: '2', + // }); + registry.registerMenuAction(ArduinoMenus.HELP__MAIN_GROUP, { + commandId: Help.Commands.REFERENCE.id, + order: '3', + }); + + registry.registerMenuAction(ArduinoMenus.HELP__FIND_GROUP, { + commandId: Help.Commands.FIND_IN_REFERENCE.id, + order: '4', + }); + // registry.registerMenuAction(ArduinoMenus.HELP__FIND_GROUP, { + // commandId: Help.Commands.FAQ.id, + // order: '5', + // }); + registry.registerMenuAction(ArduinoMenus.HELP__FIND_GROUP, { + commandId: Help.Commands.VISIT_ARDUINO.id, + order: '6', + }); + // registry.registerMenuAction(ArduinoMenus.HELP__FIND_GROUP, { + // commandId: Help.Commands.PRIVACY_POLICY.id, + // order: '7', + // }); + registry.registerMenuAction(ArduinoMenus.HELP__FIND_GROUP, { + commandId: IDEUpdaterCommands.CHECK_FOR_UPDATES.id, + order: '8', + }); + } + + override registerKeybindings(registry: KeybindingRegistry): void { + registry.registerKeybinding({ + command: Help.Commands.FIND_IN_REFERENCE.id, + keybinding: 'CtrlCmd+Shift+F', + }); + } +} + +export namespace Help { + export namespace Commands { + export const GETTING_STARTED: Command = { + id: 'arduino-getting-started', + label: nls.localize('arduino/help/gettingStarted', 'Getting Started'), + category: 'LingZhi', + }; + export const ENVIRONMENT: Command = { + id: 'arduino-environment', + label: nls.localize('arduino/help/environment', 'Environment'), + category: 'LingZhi', + }; + export const TROUBLESHOOTING: Command = { + id: 'arduino-troubleshooting', + label: nls.localize('arduino/help/troubleshooting', 'Troubleshooting'), + category: 'LingZhi', + }; + export const REFERENCE: Command = { + id: 'arduino-reference', + label: '参考', + category: 'LingZhi', + }; + export const FIND_IN_REFERENCE: Command = { + id: 'arduino-find-in-reference', + label: '在参考文件寻找', + category: 'LingZhi', + }; + export const FAQ: Command = { + id: 'arduino-faq', + label: nls.localize('arduino/help/faq', 'Frequently Asked Questions'), + category: 'LingZhi', + }; + export const VISIT_ARDUINO: Command = { + id: 'arduino-visit-arduino', + // label: nls.localize('arduino/help/visit', '访问 lingzhilab.com'),//原装 + label: nls.localize('arduino/help/visi', '访问 lingzhilab.com'), + category: 'LingZhi', + }; + export const PRIVACY_POLICY: Command = { + id: 'arduino-privacy-policy', + label: nls.localize('arduino/help/privacyPolicy', 'Privacy Policy'), + category: 'LingZhi', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/include-library.ts b/arduino-ide-extension/src/browser/contributions/include-library.ts new file mode 100644 index 000000000..8abc08d5f --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/include-library.ts @@ -0,0 +1,231 @@ +import PQueue from 'p-queue'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import URI from '@theia/core/lib/common/uri'; +import { MonacoEditor } from '@theia/monaco/lib/browser/monaco-editor'; +import { MenuModelRegistry, MenuPath } from '@theia/core/lib/common/menu'; +import { + Disposable, + DisposableCollection, +} from '@theia/core/lib/common/disposable'; +import { PlaceholderMenuNode } from '../menu/arduino-menus'; +import { LibraryPackage, LibraryService } from '../../common/protocol'; +import { MainMenuManager } from '../../common/main-menu-manager'; +import { BoardsServiceProvider } from '../boards/boards-service-provider'; +import { SketchContribution, Command, CommandRegistry } from './contribution'; +import { NotificationCenter } from '../notification-center'; +import { nls } from '@theia/core/lib/common'; +import * as monaco from '@theia/monaco-editor-core'; +import { CurrentSketch } from '../sketches-service-client-impl'; + +@injectable() +export class IncludeLibrary extends SketchContribution { + @inject(CommandRegistry) + private readonly commandRegistry: CommandRegistry; + + @inject(MenuModelRegistry) + private readonly menuRegistry: MenuModelRegistry; + + @inject(MainMenuManager) + private readonly mainMenuManager: MainMenuManager; + + @inject(NotificationCenter) + private readonly notificationCenter: NotificationCenter; + + @inject(BoardsServiceProvider) + private readonly boardsServiceProvider: BoardsServiceProvider; + + @inject(LibraryService) + private readonly libraryService: LibraryService; + + private readonly queue = new PQueue({ autoStart: true, concurrency: 1 }); + private readonly toDispose = new DisposableCollection(); + + override onStart(): void { + this.boardsServiceProvider.onBoardsConfigDidChange(() => + this.updateMenuActions() + ); + this.notificationCenter.onLibraryDidInstall(() => this.updateMenuActions()); + this.notificationCenter.onLibraryDidUninstall(() => + this.updateMenuActions() + ); + this.notificationCenter.onDidReinitialize(() => this.updateMenuActions()); + } + + override onReady(): void { + this.boardsServiceProvider.ready.then(() => this.updateMenuActions()); + } + + // override registerMenus(registry: MenuModelRegistry): void { + // // `Include Library` submenu + // const includeLibMenuPath = [ + // ...ArduinoMenus.SKETCH__UTILS_GROUP, + // '0_include', + // ]; + // registry.registerSubmenu( + // includeLibMenuPath, + // nls.localize('arduino/library/include', 'Include Library'), + // { + // order: '1', + // } + // ); + // // `Manage Libraries...` group. + // registry.registerMenuAction([...includeLibMenuPath, '0_manage'], { + // commandId: `${LibraryListWidget.WIDGET_ID}:toggle`, + // label: nls.localize( + // 'arduino/library/manageLibraries', + // 'Manage Libraries...' + // ), + // }); + // } + + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(IncludeLibrary.Commands.INCLUDE_LIBRARY, { + execute: async (arg) => { + if (LibraryPackage.is(arg)) { + this.includeLibrary(arg); + } + }, + }); + } + + private async updateMenuActions(): Promise { + return this.queue.add(async () => { + this.toDispose.dispose(); + this.mainMenuManager.update(); + const libraries: LibraryPackage[] = []; + const fqbn = this.boardsServiceProvider.boardsConfig.selectedBoard?.fqbn; + // Show all libraries, when no board is selected. + // Otherwise, show libraries only for the selected board. + libraries.push(...(await this.libraryService.list({ fqbn }))); + + const includeLibMenuPath = [ + // ...ArduinoMenus.SKETCH__UTILS_GROUP, + '0_include', + ]; + // `Add .ZIP Library...` + // TODO: implement it + + // `Arduino libraries` + const packageMenuPath = [...includeLibMenuPath, '2_arduino']; + const userMenuPath = [...includeLibMenuPath, '3_contributed']; + const { user, rest } = LibraryPackage.groupByLocation(libraries); + if (rest.length) { + (rest as any).unshift( + nls.localize('arduino/library/arduinoLibraries', 'Arduino libraries') + ); + } + if (user.length) { + (user as any).unshift( + nls.localize( + 'arduino/library/contributedLibraries', + 'Contributed libraries' + ) + ); + } + + for (const library of user) { + this.toDispose.push(this.registerLibrary(library, userMenuPath)); + } + for (const library of rest) { + this.toDispose.push(this.registerLibrary(library, packageMenuPath)); + } + + this.mainMenuManager.update(); + }); + } + + private registerLibrary( + libraryOrPlaceholder: LibraryPackage | string, + menuPath: MenuPath + ): Disposable { + if (typeof libraryOrPlaceholder === 'string') { + const placeholder = new PlaceholderMenuNode( + menuPath, + libraryOrPlaceholder + ); + this.menuRegistry.registerMenuNode(menuPath, placeholder); + return Disposable.create(() => + this.menuRegistry.unregisterMenuNode(placeholder.id) + ); + } + const commandId = `lingzhi-include-library--${libraryOrPlaceholder.name}:${libraryOrPlaceholder.author}`; + const command = { id: commandId }; + const handler = { + execute: () => + this.commandRegistry.executeCommand( + IncludeLibrary.Commands.INCLUDE_LIBRARY.id, + libraryOrPlaceholder + ), + }; + const menuAction = { commandId, label: libraryOrPlaceholder.name }; + this.menuRegistry.registerMenuAction(menuPath, menuAction); + return new DisposableCollection( + this.commandRegistry.registerCommand(command, handler), + Disposable.create(() => + this.menuRegistry.unregisterMenuAction(menuAction) + ) + ); + } + + private async includeLibrary(library: LibraryPackage): Promise { + const sketch = await this.sketchServiceClient.currentSketch(); + if (!CurrentSketch.isValid(sketch)) { + return; + } + // If the current editor is one of the additional files from the sketch, we use that. + // Otherwise, we pick the editor of the main sketch file. + let codeEditor: monaco.editor.IStandaloneCodeEditor | undefined; + const editor = this.editorManager.currentEditor?.editor; + if (editor instanceof MonacoEditor) { + if ( + sketch.additionalFileUris.some((uri) => uri === editor.uri.toString()) + ) { + codeEditor = editor.getControl(); + } + } + + if (!codeEditor) { + const widget = await this.editorManager.open(new URI(sketch.mainFileUri)); + if (widget.editor instanceof MonacoEditor) { + codeEditor = widget.editor.getControl(); + } + } + + if (!codeEditor) { + return; + } + + const textModel = codeEditor.getModel(); + if (!textModel) { + return; + } + const cursorState = codeEditor.getSelections() || []; + const eol = textModel.getEOL(); + const includes = library.includes.slice(); + includes.push(''); // For the trailing new line. + const text = includes + .map((include) => (include ? `#include <${include}>` : eol)) + .join(eol); + textModel.pushStackElement(); // Start a fresh operation. + textModel.pushEditOperations( + cursorState, + [ + { + range: new monaco.Range(1, 1, 1, 1), + text, + forceMoveMarkers: true, + }, + ], + () => cursorState + ); + textModel.pushStackElement(); // Make it undoable. + } +} + +export namespace IncludeLibrary { + export namespace Commands { + export const INCLUDE_LIBRARY: Command = { + id: 'lingzhi-include-library', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/indexes-update-progress.ts b/arduino-ide-extension/src/browser/contributions/indexes-update-progress.ts new file mode 100644 index 000000000..1eedbe61f --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/indexes-update-progress.ts @@ -0,0 +1,75 @@ +import { Progress } from '@theia/core/lib/common/message-service-protocol'; +import { ProgressService } from '@theia/core/lib/common/progress-service'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { ProgressMessage, ResponseService } from '../../common/protocol'; +import { NotificationCenter } from '../notification-center'; +import { Contribution } from './contribution'; + +@injectable() +export class IndexesUpdateProgress extends Contribution { + @inject(NotificationCenter) + private readonly notificationCenter: NotificationCenter; + @inject(ProgressService) + private readonly progressService: ProgressService; + @inject(ResponseService) + private readonly responseService: ResponseService; + private currentProgress: + | (Progress & Readonly<{ progressId: string }>) + | undefined; + + override onStart(): void { + this.notificationCenter.onIndexUpdateWillStart(({ progressId }) => + this.getOrCreateProgress(progressId) + ); + this.notificationCenter.onIndexUpdateDidProgress((progress) => { + this.getOrCreateProgress(progress).then((delegate) => + delegate.report(progress) + ); + }); + this.notificationCenter.onIndexUpdateDidComplete(({ progressId }) => { + this.cancelProgress(progressId); + }); + this.notificationCenter.onIndexUpdateDidFail(({ progressId, message }) => { + this.cancelProgress(progressId); + // this.messageService.error(message); + const chunk = `${message}\n`; + this.responseService.appendToOutput({ chunk }); + }); + } + + private async getOrCreateProgress( + progressOrId: ProgressMessage | string + ): Promise { + const progressId = ProgressMessage.is(progressOrId) + ? progressOrId.progressId + : progressOrId; + if (this.currentProgress?.progressId === progressId) { + return this.currentProgress; + } + if (this.currentProgress) { + this.currentProgress.cancel(); + } + this.currentProgress = undefined; + const progress = await this.progressService.showProgress({ + text: '', + options: { location: 'notification' }, + }); + if (ProgressMessage.is(progressOrId)) { + progress.report(progressOrId); + } + this.currentProgress = { ...progress, progressId }; + return this.currentProgress; + } + + private cancelProgress(progressId: string) { + if (this.currentProgress) { + if (this.currentProgress.progressId !== progressId) { + console.warn( + `Mismatching progress IDs. Expected ${progressId}, got ${this.currentProgress.progressId}. Canceling anyway.` + ); + } + this.currentProgress.cancel(); + this.currentProgress = undefined; + } + } +} diff --git a/arduino-ide-extension/src/browser/contributions/ino-language.ts b/arduino-ide-extension/src/browser/contributions/ino-language.ts new file mode 100644 index 000000000..b9d3631de --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/ino-language.ts @@ -0,0 +1,328 @@ +import { + Disposable, + DisposableCollection, +} from '@theia/core/lib/common/disposable'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { Mutex } from 'async-mutex'; +import { + ArduinoDaemon, + BoardIdentifier, + BoardsService, + ExecutableService, + assertSanitizedFqbn, + isBoardIdentifierChangeEvent, + sanitizeFqbn, +} from '../../common/protocol'; +import { + defaultAsyncWorkers, + maxAsyncWorkers, + minAsyncWorkers, +} from '../arduino-preferences'; +import { BoardsDataStore } from '../boards/boards-data-store'; +import { BoardsServiceProvider } from '../boards/boards-service-provider'; +import { HostedPluginEvents } from '../hosted/hosted-plugin-events'; +import { NotificationCenter } from '../notification-center'; +import { CurrentSketch } from '../sketches-service-client-impl'; +import { SketchContribution, URI } from './contribution'; + +interface DaemonAddress { + /** + * The host where the Arduino CLI daemon is available. + */ + readonly hostname: string; + /** + * The port where the Arduino CLI daemon is listening. + */ + readonly port: number; + /** + * The [id](https://arduino.github.io/arduino-cli/latest/rpc/commands/#instance) of the initialized core Arduino client instance. + */ + readonly instance: number; +} + +interface StartLanguageServerParams { + /** + * Absolute filesystem path to the Arduino Language Server executable. + */ + readonly lsPath: string; + /** + * The hostname and the port for the gRPC channel connecting to the Arduino CLI daemon. + * The `instance` number is for the initialized core Arduino client. + */ + readonly daemonAddress: DaemonAddress; + /** + * Absolute filesystem path to [`clangd`](https://clangd.llvm.org/). + */ + readonly clangdPath: string; + /** + * The board is relevant to start a specific "flavor" of the language. + */ + readonly board: { fqbn: string; name?: string }; + /** + * `true` if the LS should generate the log files into the default location. The default location is the `cwd` of the process. + * It's very often the same as the workspace root of the IDE, aka the sketch folder. + * When it is a string, it is the absolute filesystem path to the folder to generate the log files. + * If `string`, but the path is inaccessible, the log files will be generated into the default location. + */ + readonly log?: boolean | string; + /** + * Optional `env` for the language server process. + */ + readonly env?: NodeJS.ProcessEnv; + /** + * Additional flags for the Arduino Language server process. + */ + readonly flags?: readonly string[]; + /** + * Set to `true`, to enable `Diagnostics`. + */ + readonly realTimeDiagnostics?: boolean; + /** + * If `true`, the logging is not forwarded to the _Output_ view via the language client. + */ + readonly silentOutput?: boolean; + /** + * Number of async workers used by `clangd`. Background index also uses this many workers. If `0`, `clangd` uses all available cores. It's `0` by default. + */ + readonly jobs?: number; +} + +/** + * The FQBN the language server runs with or `undefined` if it could not start. + */ +type StartLanguageServerResult = string | undefined; + +@injectable() +export class InoLanguage extends SketchContribution { + @inject(HostedPluginEvents) + private readonly hostedPluginEvents: HostedPluginEvents; + @inject(ExecutableService) + private readonly executableService: ExecutableService; + @inject(ArduinoDaemon) + private readonly daemon: ArduinoDaemon; + @inject(BoardsService) + private readonly boardsService: BoardsService; + @inject(BoardsServiceProvider) + private readonly boardsServiceProvider: BoardsServiceProvider; + @inject(NotificationCenter) + private readonly notificationCenter: NotificationCenter; + @inject(BoardsDataStore) + private readonly boardDataStore: BoardsDataStore; + + private readonly toDispose = new DisposableCollection(); + private readonly languageServerStartMutex = new Mutex(); + private languageServerFqbn?: string; + + override onReady(): void { + const start = ( + selectedBoard: BoardIdentifier | undefined, + forceStart = false + ) => { + if (selectedBoard) { + const { name, fqbn } = selectedBoard; + if (fqbn) { + this.startLanguageServer(fqbn, name, forceStart); + } + } + }; + const forceRestart = () => { + start(this.boardsServiceProvider.boardsConfig.selectedBoard, true); + }; + this.toDispose.pushAll([ + this.boardsServiceProvider.onBoardsConfigDidChange((event) => { + if (isBoardIdentifierChangeEvent(event)) { + start(event.selectedBoard); + } + }), + this.hostedPluginEvents.onPluginsDidStart(() => + start(this.boardsServiceProvider.boardsConfig.selectedBoard) + ), + this.hostedPluginEvents.onPluginsWillUnload( + () => (this.languageServerFqbn = undefined) + ), + this.preferences.onPreferenceChanged( + ({ preferenceName, oldValue, newValue }) => { + if (oldValue !== newValue) { + switch (preferenceName) { + case 'arduino.language.log': + case 'arduino.language.realTimeDiagnostics': + case 'arduino.language.asyncWorkers': + forceRestart(); + } + } + } + ), + this.notificationCenter.onLibraryDidInstall(() => forceRestart()), + this.notificationCenter.onLibraryDidUninstall(() => forceRestart()), + this.notificationCenter.onPlatformDidInstall(() => forceRestart()), + this.notificationCenter.onPlatformDidUninstall(() => forceRestart()), + this.notificationCenter.onDidReinitialize(() => forceRestart()), + this.boardDataStore.onDidChange((event) => { + if (this.languageServerFqbn) { + const sanitizedFqbn = sanitizeFqbn(this.languageServerFqbn); + if (!sanitizeFqbn) { + throw new Error( + `Failed to sanitize the FQBN of the running language server. FQBN with the board settings was: ${this.languageServerFqbn}` + ); + } + const matchingChange = event.changes.find( + (change) => change.fqbn === sanitizedFqbn + ); + const { boardsConfig } = this.boardsServiceProvider; + if ( + matchingChange && + boardsConfig.selectedBoard?.fqbn === matchingChange.fqbn + ) { + start(boardsConfig.selectedBoard); + } + } + }), + ]); + Promise.all([ + this.boardsServiceProvider.ready, + this.preferences.ready, + ]).then(() => { + start(this.boardsServiceProvider.boardsConfig.selectedBoard); + }); + } + + onStop(): void { + this.toDispose.dispose(); + } + + private async startLanguageServer( + fqbn: string, + name: string | undefined, + forceStart = false + ): Promise { + const port = await this.daemon.tryGetPort(); + if (!port) { + return; + } + const portNumber = Number.parseInt(port, 10); // TODO: IDE2 APIs should provide a number and not string + if (Number.isNaN(portNumber)) { + return; + } + const release = await this.languageServerStartMutex.acquire(); + const toDisposeOnRelease = new DisposableCollection(); + try { + await this.hostedPluginEvents.didStart; + const details = await this.boardsService.getBoardDetails({ fqbn }); + if (!details) { + // Core is not installed for the selected board. + console.info( + `Could not start language server for ${fqbn}. The core is not installed for the board.` + ); + if (this.languageServerFqbn) { + try { + await this.commandService.executeCommand( + 'arduino.languageserver.stop' + ); + console.info( + `Stopped language server process for ${this.languageServerFqbn}.` + ); + this.languageServerFqbn = undefined; + } catch (e) { + console.error( + `Failed to start language server process for ${this.languageServerFqbn}`, + e + ); + throw e; + } + } + return; + } + assertSanitizedFqbn(fqbn); + const fqbnWithConfig = await this.boardDataStore.appendConfigToFqbn(fqbn); + if (!fqbnWithConfig) { + throw new Error( + `Failed to append boards config to the FQBN. Original FQBN was: ${fqbn}` + ); + } + if (!forceStart && fqbnWithConfig === this.languageServerFqbn) { + // NOOP + return; + } + const log = this.preferences.get('arduino.language.log'); + const realTimeDiagnostics = this.preferences.get( + 'arduino.language.realTimeDiagnostics' + ); + const jobs = this.getAsyncWorkersPreferenceSafe(); + this.logger.info( + `Starting language server: ${fqbnWithConfig}${jobs ? ` (async worker count: ${jobs})` : '' + }` + ); + let currentSketchPath: string | undefined = undefined; + if (log) { + const currentSketch = await this.sketchServiceClient.currentSketch(); + if (CurrentSketch.isValid(currentSketch)) { + currentSketchPath = await this.fileService.fsPath( + new URI(currentSketch.uri) + ); + } + } + const { clangdUri, lsUri } = await this.executableService.list(); + const [clangdPath, lsPath] = await Promise.all([ + this.fileService.fsPath(new URI(clangdUri)), + this.fileService.fsPath(new URI(lsUri)), + ]); + + this.languageServerFqbn = await Promise.race([ + new Promise((_, reject) => { + const timer = setTimeout( + () => reject(new Error(`Timeout after ${20_000} ms.`)), + 20_000 + ); + toDisposeOnRelease.push(Disposable.create(() => clearTimeout(timer))); + }), + this.start({ + lsPath, + daemonAddress: { + hostname: 'localhost', + port: portNumber, + instance: 1, // TODO: get it from the backend + }, + clangdPath, + log: currentSketchPath ? currentSketchPath : log, + board: { + fqbn: fqbnWithConfig, + name, + }, + realTimeDiagnostics, + silentOutput: true, + jobs, + }), + ]); + } catch (e) { + console.log(`Failed to start language server. Original FQBN: ${fqbn}`, e); + this.languageServerFqbn = undefined; + } finally { + toDisposeOnRelease.dispose(); + release(); + } + } + // The Theia preference UI validation is bogus. + // To restrict the number of jobs to a valid value. + private getAsyncWorkersPreferenceSafe(): number { + const jobs = this.preferences.get( + 'arduino.language.asyncWorkers', + defaultAsyncWorkers + ); + if (jobs < minAsyncWorkers) { + return minAsyncWorkers; + } + if (jobs > maxAsyncWorkers) { + return maxAsyncWorkers; + } + return jobs; + } + + private async start( + params: StartLanguageServerParams + ): Promise { + return this.commandService.executeCommand( + 'arduino.languageserver.start', + params + ); + } +} diff --git a/arduino-ide-extension/src/browser/contributions/interface-scale.ts b/arduino-ide-extension/src/browser/contributions/interface-scale.ts new file mode 100644 index 000000000..41a67e68d --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/interface-scale.ts @@ -0,0 +1,167 @@ +import { injectable } from '@theia/core/shared/inversify'; +import { + Contribution, + Command, + MenuModelRegistry, + KeybindingRegistry, +} from './contribution'; +import { ArduinoMenus } from '../menu/arduino-menus'; +import { CommandRegistry, MaybePromise } from '@theia/core/lib/common'; +import { Settings } from '../dialogs/settings/settings'; +import debounce from 'lodash.debounce'; + +@injectable() +export class InterfaceScale extends Contribution { + private fontScalingEnabled: InterfaceScale.FontScalingEnabled = { + increase: true, + decrease: true, + }; + + private currentSettings: Settings; + private updateSettingsDebounced = debounce( + async () => { + await this.settingsService.update(this.currentSettings); + await this.settingsService.save(); + }, + 100, + { maxWait: 200 } + ); + + override onStart(): MaybePromise { + const updateCurrent = (settings: Settings) => { + this.currentSettings = settings; + this.updateFontScalingEnabled(); + }; + this.settingsService.onDidChange((settings) => updateCurrent(settings)); + this.settingsService.settings().then((settings) => updateCurrent(settings)); + } + + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(InterfaceScale.Commands.INCREASE_FONT_SIZE, { + execute: () => this.updateFontSize('increase'), + isEnabled: () => this.fontScalingEnabled.increase, + }); + registry.registerCommand(InterfaceScale.Commands.DECREASE_FONT_SIZE, { + execute: () => this.updateFontSize('decrease'), + isEnabled: () => this.fontScalingEnabled.decrease, + }); + } + + override registerMenus(registry: MenuModelRegistry): void { + registry.registerMenuAction(ArduinoMenus.EDIT__FONT_CONTROL_GROUP, { + commandId: InterfaceScale.Commands.INCREASE_FONT_SIZE.id, + label: '放大字号', + order: '0', + }); + registry.registerMenuAction(ArduinoMenus.EDIT__FONT_CONTROL_GROUP, { + commandId: InterfaceScale.Commands.DECREASE_FONT_SIZE.id, + label: '缩小字号', + order: '1', + }); + } + + private updateFontScalingEnabled(): void { + let fontScalingEnabled = { + increase: true, + decrease: true, + }; + + if (this.currentSettings.autoScaleInterface) { + fontScalingEnabled = { + increase: + this.currentSettings.interfaceScale + InterfaceScale.ZoomLevel.STEP <= + InterfaceScale.ZoomLevel.MAX, + decrease: + this.currentSettings.interfaceScale - InterfaceScale.ZoomLevel.STEP >= + InterfaceScale.ZoomLevel.MIN, + }; + } else { + fontScalingEnabled = { + increase: + this.currentSettings.editorFontSize + InterfaceScale.FontSize.STEP <= + InterfaceScale.FontSize.MAX, + decrease: + this.currentSettings.editorFontSize - InterfaceScale.FontSize.STEP >= + InterfaceScale.FontSize.MIN, + }; + } + + const isChanged = Object.keys(fontScalingEnabled).some( + (key: keyof InterfaceScale.FontScalingEnabled) => + fontScalingEnabled[key] !== this.fontScalingEnabled[key] + ); + if (isChanged) { + this.fontScalingEnabled = fontScalingEnabled; + this.menuManager.update(); + } + } + + private updateFontSize(mode: 'increase' | 'decrease'): void { + if (this.currentSettings.autoScaleInterface) { + mode === 'increase' + ? (this.currentSettings.interfaceScale += InterfaceScale.ZoomLevel.STEP) + : (this.currentSettings.interfaceScale -= + InterfaceScale.ZoomLevel.STEP); + } else { + mode === 'increase' + ? (this.currentSettings.editorFontSize += InterfaceScale.FontSize.STEP) + : (this.currentSettings.editorFontSize -= InterfaceScale.FontSize.STEP); + } + this.updateFontScalingEnabled(); + this.updateSettingsDebounced(); + } + + override registerKeybindings(registry: KeybindingRegistry): void { + registry.registerKeybinding({ + command: InterfaceScale.Commands.INCREASE_FONT_SIZE.id, + keybinding: 'CtrlCmd+=', + }); + registry.registerKeybinding({ + command: InterfaceScale.Commands.DECREASE_FONT_SIZE.id, + keybinding: 'CtrlCmd+-', + }); + } +} + +export namespace InterfaceScale { + export namespace Commands { + export const INCREASE_FONT_SIZE: Command = { + id: 'lingzhi-increase-font-size', + }; + export const DECREASE_FONT_SIZE: Command = { + id: 'lingzhi-decrease-font-size', + }; + } + + export namespace ZoomLevel { + export const MIN = -8; + export const MAX = 9; + export const STEP = 1; + + export function toPercentage(scale: number): number { + return scale * 20 + 100; + } + export function fromPercentage(percentage: number): number { + return (percentage - 100) / 20; + } + export namespace Step { + export function toPercentage(step: number): number { + return step * 20; + } + export function fromPercentage(percentage: number): number { + return percentage / 20; + } + } + } + + export namespace FontSize { + export const MIN = 8; + export const MAX = 72; + export const STEP = 2; + } + + export interface FontScalingEnabled { + increase: boolean; + decrease: boolean; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/new-cloud-sketch.ts b/arduino-ide-extension/src/browser/contributions/new-cloud-sketch.ts new file mode 100644 index 000000000..acaaf7a26 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/new-cloud-sketch.ts @@ -0,0 +1,199 @@ +import { KeybindingRegistry } from '@theia/core/lib/browser/keybinding'; +import { CompositeTreeNode } from '@theia/core/lib/browser/tree'; +import { DisposableCollection } from '@theia/core/lib/common/disposable'; +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 { Create, isConflict } from '../create/typings'; +import { + TaskFactoryImpl, + WorkspaceInputDialogWithProgress, +} from '../theia/workspace/workspace-input-dialog'; +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 { + 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; +} + +export interface NewCloudSketchParams { + /** + * Value to populate the dialog `` 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 { + private readonly toDispose = new DisposableCollection(); + + override onReady(): void { + this.toDispose.pushAll([ + this.createFeatures.onDidChangeEnabled(() => this.menuManager.update()), + this.createFeatures.onDidChangeSession(() => this.menuManager.update()), + ]); + if (this.createFeatures.session) { + this.menuManager.update(); + } + } + + onStop(): void { + this.toDispose.dispose(); + } + + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(NewCloudSketch.Commands.NEW_CLOUD_SKETCH, { + execute: (params: NewCloudSketchParams) => + this.createNewSketch( + params?.skipShowErrorMessageOnOpen === false ? false : true, + params?.initialValue, + params?.callback + ), + isEnabled: () => Boolean(this.createFeatures.session), + isVisible: () => this.createFeatures.enabled, + }); + } + + // override registerMenus(registry: MenuModelRegistry): void { + // registry.registerMenuAction(ArduinoMenus.FILE__SKETCH_GROUP, { + // commandId: NewCloudSketch.Commands.NEW_CLOUD_SKETCH.id, + // label: nls.localize('arduino/cloudSketch/new', 'New Cloud Sketch'), + // order: '1', + // }); + // } + + override registerKeybindings(registry: KeybindingRegistry): void { + registry.registerKeybinding({ + command: NewCloudSketch.Commands.NEW_CLOUD_SKETCH.id, + keybinding: 'CtrlCmd+Alt+N', + }); + } + + private async createNewSketch( + skipShowErrorMessageOnOpen: boolean, + initialValue?: string | undefined, + callback?: CreateNewCloudSketchCallback + ): Promise { + const treeModel = await this.treeModel(); + if (treeModel) { + const rootNode = treeModel.root; + return this.openWizard( + rootNode, + treeModel, + skipShowErrorMessageOnOpen, + initialValue, + callback + ); + } + } + + private async openWizard( + rootNode: CompositeTreeNode, + treeModel: CloudSketchbookTreeModel, + skipShowErrorMessageOnOpen: boolean, + initialValue?: string | undefined, + callback?: CreateNewCloudSketchCallback + ): Promise { + const existingNames = rootNode.children + .filter(CloudSketchbookTree.CloudSketchDirNode.is) + .map(({ fileStat }) => fileStat.name); + const taskFactory = new TaskFactoryImpl((value) => + this.createNewSketchWithProgress(treeModel, value, callback) + ); + try { + const dialog = new WorkspaceInputDialogWithProgress( + { + title: '新云草图的名称', + parentUri: CreateUri.root, + initialValue, + validate: (input) => { + if (existingNames.includes(input)) { + return sketchAlreadyExists(input); + } + return Sketch.validateCloudSketchFolderName(input) ?? ''; + }, + }, + this.labelProvider, + taskFactory + ); + await dialog.open(skipShowErrorMessageOnOpen); + if (dialog.taskResult) { + this.openInNewWindow(dialog.taskResult); + } + } catch (err) { + if (isConflict(err)) { + await treeModel.refresh(); + return this.createNewSketch( + false, + taskFactory.value ?? initialValue, + callback + ); + } + throw err; + } + } + + private createNewSketchWithProgress( + treeModel: CloudSketchbookTreeModel, + value: string, + callback?: CreateNewCloudSketchCallback + ): ( + progress: Progress + ) => Promise { + return async (progress: Progress) => { + progress.report({ + message: nls.localize( + 'arduino/cloudSketch/creating', + "Creating cloud sketch '{0}'...", + value + ), + }); + const sketch = await this.createApi.createSketch(value); + progress.report({ message: synchronizingSketchbook }); + 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; + }; + } + + private openInNewWindow( + node: CloudSketchbookTree.CloudSketchDirNode + ): Promise { + return this.commandService.executeCommand( + SketchbookCommands.OPEN_NEW_WINDOW.id, + { node, treeWidgetId: 'cloud-sketchbook-composite-widget' } + ); + } +} +export namespace NewCloudSketch { + export namespace Commands { + export const NEW_CLOUD_SKETCH: Command = { + id: 'lingzhi-new-cloud-sketch', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/new-sketch.ts b/arduino-ide-extension/src/browser/contributions/new-sketch.ts new file mode 100644 index 000000000..0209a436b --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/new-sketch.ts @@ -0,0 +1,86 @@ +import { inject, injectable } from '@theia/core/shared/inversify'; +import { + SketchContribution, + URI, + Command, + CommandRegistry, + KeybindingRegistry, + MenuModelRegistry, +} from './contribution'; +import { WorkspaceService } from '../theia/workspace/workspace-service'; +import { ResponseService } from '../../common/protocol'; +import { ArduinoMenus } from '../menu/arduino-menus'; +import { LocalStorageService } from '@theia/core/lib/browser/storage-service'; +import { WorkspaceInput } from '@theia/workspace/lib/browser'; + +@injectable() +export class NewSketch extends SketchContribution { + @inject(WorkspaceService) + protected readonly workspaceService1: WorkspaceService; + @inject(ResponseService) + private readonly responseService: ResponseService; + @inject(LocalStorageService) + private readonly localStorageService: LocalStorageService; + + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(NewSketch.Commands.NEW_SKETCH, { + execute: async () => { + const today = new Date(); + localStorage.setItem( + 'arduino-new-sketch-executedB', + today.toLocaleString() + ); + localStorage.setItem( + 'lingzhi-open-sketch-view', + today.toLocaleString() + ); + const isFirstStartup = !(await this.localStorageService.getData( + 'initializedLibsAndPackages' + )); + if (!isFirstStartup) { + this.newSketch(); + } else { + this.messageService.info('请先等待零知库下载安装完成', { + timeout: 3000, + }); + } + }, + }); + } + + override registerMenus(registry: MenuModelRegistry): void { + registry.registerMenuAction(ArduinoMenus.FILE__SKETCH_GROUP, { + commandId: NewSketch.Commands.NEW_SKETCH.id, + label: '新建项目', + order: '0', + }); + } + + override registerKeybindings(registry: KeybindingRegistry): void { + registry.registerKeybinding({ + command: NewSketch.Commands.NEW_SKETCH.id, + keybinding: 'CtrlCmd+N', + }); + } + + async newSketch(): Promise { + try { + const sketch = await this.sketchesService.createNewSketch(); + + const preserveWindow: WorkspaceInput = { preserveWindow: false }; + this.workspaceService.open(new URI(sketch.uri), preserveWindow); + } catch (e) { + // await this.messageService.error(e.toString()); + const chunk = `${e.toString()}\n`; + this.responseService.appendToOutput({ chunk }); + } + } +} + +export namespace NewSketch { + export namespace Commands { + export const NEW_SKETCH: Command = { + id: 'lingzhi-new-sketch', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/open-boards-config.ts b/arduino-ide-extension/src/browser/contributions/open-boards-config.ts new file mode 100644 index 000000000..dde35b416 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/open-boards-config.ts @@ -0,0 +1,25 @@ +import type { Command, CommandRegistry } from '@theia/core/lib/common/command'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import type { EditBoardsConfigActionParams } from '../../common/protocol/board-list'; +import { BoardsConfigDialog } from '../boards/boards-config-dialog'; +import { Contribution } from './contribution'; + +@injectable() +export class OpenBoardsConfig extends Contribution { + @inject(BoardsConfigDialog) + private readonly boardsConfigDialog: BoardsConfigDialog; + + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(OpenBoardsConfig.Commands.OPEN_DIALOG, { + execute: async (params?: EditBoardsConfigActionParams) => + this.boardsConfigDialog.open(params), + }); + } +} +export namespace OpenBoardsConfig { + export namespace Commands { + export const OPEN_DIALOG: Command = { + id: 'lingzhi-open-boards-dialog', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/open-recent-sketch.ts b/arduino-ide-extension/src/browser/contributions/open-recent-sketch.ts new file mode 100644 index 000000000..e154a5d53 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/open-recent-sketch.ts @@ -0,0 +1,128 @@ +import { inject, injectable } from '@theia/core/shared/inversify'; +import { WorkspaceServer } from '@theia/workspace/lib/common/workspace-protocol'; +import { + Disposable, + DisposableCollection, +} from '@theia/core/lib/common/disposable'; +import { + SketchContribution, + CommandRegistry, + MenuModelRegistry, + Sketch, +} from './contribution'; +import { MainMenuManager } from '../../common/main-menu-manager'; +import { OpenSketch } from './open-sketch'; +import { NotificationCenter } from '../notification-center'; +import { SketchesError } from '../../common/protocol'; +import { LocalStorageService } from '@theia/core/lib/browser/storage-service'; +import { ArduinoMenus } from '../menu/arduino-menus'; + +@injectable() +export class OpenRecentSketch extends SketchContribution { + @inject(CommandRegistry) + protected readonly commandRegistry: CommandRegistry; + + @inject(MenuModelRegistry) + protected readonly menuRegistry: MenuModelRegistry; + + @inject(MainMenuManager) + protected readonly mainMenuManager: MainMenuManager; + + @inject(WorkspaceServer) + protected readonly workspaceServer: WorkspaceServer; + + @inject(NotificationCenter) + protected readonly notificationCenter: NotificationCenter; + + @inject(LocalStorageService) + private readonly localStorageService: LocalStorageService; + + protected toDispose = new DisposableCollection(); + + override onStart(): void { + this.notificationCenter.onRecentSketchesDidChange(({ sketches }) => + this.refreshMenu(sketches) + ); + } + + override async onReady(): Promise { + this.update(); + } + + private update(forceUpdate?: boolean): void { + this.sketchesService + .recentlyOpenedSketches(forceUpdate) + .then((sketches) => this.refreshMenu(sketches)); + } + + override registerMenus(registry: MenuModelRegistry): void { + registry.registerSubmenu( + ArduinoMenus.FILE__OPEN_RECENT_SUBMENU, + '打开最近', + { order: '2' } + ); + } + + private refreshMenu(sketches: Sketch[]): void { + this.register(sketches); + this.mainMenuManager.update(); + } + + protected register(sketches: Sketch[]): void { + const order = 0; + this.toDispose.dispose(); + for (const sketch of sketches) { + const { uri } = sketch; + const command = { id: `arduino-open-recent--${uri}` }; + const handler = { + execute: async () => { + try { + const today = new Date(); + localStorage.setItem( + 'arduino-new-sketch-executedB', + today.toLocaleString() + ); + const isFirstStartup = !(await this.localStorageService.getData( + 'initializedLibsAndPackages' + )); + if (!isFirstStartup) { + await this.commandRegistry.executeCommand( + OpenSketch.Commands.OPEN_SKETCH.id, + sketch + ); + } else { + this.messageService.info('请先等待零知库下载安装完成', { + timeout: 3000, + }); + } + } catch (err) { + if (SketchesError.NotFound.is(err)) { + this.update(true); + } else { + throw err; + } + } + }, + }; + this.commandRegistry.registerCommand(command, handler); + this.menuRegistry.registerMenuAction( + ArduinoMenus.FILE__OPEN_RECENT_SUBMENU, + { + commandId: command.id, + label: sketch.name, + order: String(order), + } + ); + this.toDispose.pushAll([ + new DisposableCollection( + Disposable.create(() => + this.commandRegistry.unregisterCommand(command) + ), + Disposable.create(() => + this.menuRegistry.unregisterMenuAction(command) + ) + ), + ]); + } + } +} diff --git a/arduino-ide-extension/src/browser/contributions/open-settings.ts b/arduino-ide-extension/src/browser/contributions/open-settings.ts new file mode 100644 index 000000000..130fa9d67 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/open-settings.ts @@ -0,0 +1,87 @@ +import { nls } from '@theia/core/lib/common/nls'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import type { Settings } from '../dialogs/settings/settings'; +import { SettingsDialog } from '../dialogs/settings/settings-dialog'; +import { ArduinoMenus } from '../menu/arduino-menus'; +import { + Command, + CommandRegistry, + KeybindingRegistry, + MenuModelRegistry, + SketchContribution, +} from './contribution'; + +@injectable() +export class OpenSettings extends SketchContribution { + @inject(SettingsDialog) + private readonly settingsDialog: SettingsDialog; + + private settingsOpened = false; + + override registerCommands(registry: CommandRegistry): void { + // 注册一个命令,命令名为OpenSettings.Commands.OPEN + registry.registerCommand(OpenSettings.Commands.OPEN, { + // 执行命令的方法 + execute: async () => { + // 定义一个变量,用于存储设置 + let settings: Settings | undefined = undefined; + try { + // 设置打开状态为true + this.settingsOpened = true; + // 更新菜单管理器 + this.menuManager.update(); + // 打开设置对话框,并将返回的设置赋值给settings变量 + settings = await this.settingsDialog.open(); + } finally { + // 设置打开状态为false + this.settingsOpened = false; + // 更新菜单管理器 + this.menuManager.update(); + } + // 如果settings不为空,则更新设置并保存 + if (settings) { + await this.settingsService.update(settings); + await this.settingsService.save(); + } else { + // 否则,重置设置 + await this.settingsService.reset(); + } + }, + // 判断命令是否可用的方法 + isEnabled: () => !this.settingsOpened, + }); + } + + override registerMenus(registry: MenuModelRegistry): void { + registry.registerMenuAction(ArduinoMenus.FILE__PREFERENCES_GROUP, { + commandId: OpenSettings.Commands.OPEN.id, + label: '设置', + order: '0', + }); + // registry.registerSubmenu( + // ArduinoMenus.FILE__ADVANCED_SUBMENU, + // nls.localize('arduino/menu/advanced', 'Advanced') + // ); + } + + override registerKeybindings(registry: KeybindingRegistry): void { + registry.registerKeybinding({ + command: OpenSettings.Commands.OPEN.id, + keybinding: 'CtrlCmd+,', + }); + } +} + +export namespace OpenSettings { + export namespace Commands { + export const OPEN: Command = { + id: 'arduino-settings-open', + label: + nls.localize( + 'vscode/preferences.contribution/openSettings2', + 'Open Preferences' + ) + '...', + category: 'LingZhi', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/open-sketch-external.ts b/arduino-ide-extension/src/browser/contributions/open-sketch-external.ts new file mode 100644 index 000000000..36cca8446 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/open-sketch-external.ts @@ -0,0 +1,55 @@ +import { injectable } from '@theia/core/shared/inversify'; +import URI from '@theia/core/lib/common/uri'; +import { ArduinoMenus } from '../menu/arduino-menus'; +import { + SketchContribution, + Command, + CommandRegistry, + MenuModelRegistry, + KeybindingRegistry, +} from './contribution'; + +@injectable() +export class OpenSketchExternal extends SketchContribution { + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(OpenSketchExternal.Commands.OPEN_EXTERNAL, { + execute: () => this.openExternal(), + }); + } + + override registerMenus(registry: MenuModelRegistry): void { + registry.registerMenuAction(ArduinoMenus.SKETCH__UTILS_GROUP, { + commandId: OpenSketchExternal.Commands.OPEN_EXTERNAL.id, + label: '显示项目文件夹', + order: '0', + }); + } + + override registerKeybindings(registry: KeybindingRegistry): void { + registry.registerKeybinding({ + command: OpenSketchExternal.Commands.OPEN_EXTERNAL.id, + keybinding: 'CtrlCmd+Alt+K', + }); + } + + protected async openExternal(): Promise { + const uri = await this.sketchServiceClient.currentSketchFile(); + if (uri) { + const exists = await this.fileService.exists(new URI(uri)); + if (exists) { + const fsPath = await this.fileService.fsPath(new URI(uri)); + if (fsPath) { + window.electronTheiaCore.showItemInFolder(fsPath); + } + } + } + } +} + +export namespace OpenSketchExternal { + export namespace Commands { + export const OPEN_EXTERNAL: Command = { + id: 'lingzhi-open-sketch-external', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/open-sketch-files.ts b/arduino-ide-extension/src/browser/contributions/open-sketch-files.ts new file mode 100644 index 000000000..b42620f7d --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/open-sketch-files.ts @@ -0,0 +1,239 @@ +import { nls } from '@theia/core/lib/common/nls'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import type { EditorOpenerOptions } from '@theia/editor/lib/browser/editor-manager'; +import { Later } from '../../common/nls'; +import { ResponseService, Sketch, SketchesError } from '../../common/protocol'; +import { + Command, + CommandRegistry, + SketchContribution, + URI, +} from './contribution'; +import { SaveAsSketch } from './save-as-sketch'; +import { promptMoveSketch } from './open-sketch'; +import { ApplicationError } from '@theia/core/lib/common/application-error'; +import { Deferred, wait } from '@theia/core/lib/common/promise-util'; +import { EditorWidget } from '@theia/editor/lib/browser/editor-widget'; +import { DisposableCollection } from '@theia/core/lib/common/disposable'; + +@injectable() +export class OpenSketchFiles extends SketchContribution { + @inject(ResponseService) + private readonly responseService: ResponseService; + + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(OpenSketchFiles.Commands.OPEN_SKETCH_FILES, { + execute: (uri: URI, focusMainSketchFile) => + this.openSketchFiles(uri, focusMainSketchFile), + }); + registry.registerCommand(OpenSketchFiles.Commands.ENSURE_OPENED, { + execute: ( + uri: string, + forceOpen?: boolean, + options?: EditorOpenerOptions + ) => { + this.ensureOpened(uri, forceOpen, options); + }, + }); + } + + private async openSketchFiles( + uri: URI, + focusMainSketchFile = false + ): Promise { + try { + const sketch = await this.sketchesService.loadSketch(uri.toString()); + const { mainFileUri, rootFolderFileUris } = sketch; + for (const uri of [mainFileUri, ...rootFolderFileUris]) { + await this.ensureOpened(mainFileUri); + } + if (focusMainSketchFile) { + await this.ensureOpened(mainFileUri, true, { + mode: 'activate', + preview: false, + counter: 0, + }); + } + if (mainFileUri.endsWith('.pde')) { + const message = nls.localize( + 'arduino/common/oldFormat', + "'{0}'仍然使用旧的'.pde'的格式。是否要切换到新的'.ino'的扩展?", + sketch.name + ); + const yes = '是'; + this.messageService.info(message, Later, yes).then((answer) => { + if (answer === yes) { + this.commandService.executeCommand( + SaveAsSketch.Commands.SAVE_AS_SKETCH.id, + { + execOnlyIfTemp: false, + openAfterMove: true, + wipeOriginal: false, + } + ); + } + }); + } + const { workspaceError } = this.workspaceService; + // This happens when the IDE2 has been started (from either a terminal or clicking on an `ino` file) with a /path/to/invalid/sketch. (#964) + if (SketchesError.InvalidName.is(workspaceError)) { + await this.promptMove(workspaceError); + } + } catch (err) { + // This happens when the user gracefully closed IDE2, all went well + // but the main sketch file was renamed outside of IDE2 and when the user restarts the IDE2 + // the workspace path still exists, but the sketch path is not valid anymore. (#964) + if (SketchesError.InvalidName.is(err)) { + const movedSketch = await this.promptMove(err); + if (!movedSketch) { + // If user did not accept the move, or move was not possible, force reload with a fallback. + return this.openFallbackSketch(); + } + } + + if (SketchesError.NotFound.is(err)) { + return this.openFallbackSketch(); + } else { + console.error(err); + const message = + err instanceof Error + ? err.message + : typeof err === 'string' + ? err + : String(err); + // this.messageService.error(message); + const chunk = `${message}\n`; + this.responseService.appendToOutput({ chunk }); + } + } + } + + private async promptMove( + err: ApplicationError< + number, + { + invalidMainSketchUri: string; + } + > + ): Promise { + const { invalidMainSketchUri } = err.data; + // requestAnimationFrame(() => this.messageService.error(err.message)); + requestAnimationFrame(() => { + const chunk = `${err.message}\n`; + this.responseService.appendToOutput({ chunk }); + }); + await wait(250); // let IDE2 open the editor and toast the error message, then open the modal dialog + const movedSketch = await promptMoveSketch(invalidMainSketchUri, { + fileService: this.fileService, + sketchesService: this.sketchesService, + labelProvider: this.labelProvider, + dialogService: this.dialogService, + }); + if (movedSketch) { + this.workspaceService.open(new URI(movedSketch.uri), { + preserveWindow: true, + }); + return movedSketch; + } + return undefined; + } + + private async openFallbackSketch(): Promise { + const sketch = await this.sketchesService.createNewSketch(); + this.workspaceService.open(new URI(sketch.uri), { preserveWindow: true }); + } + + private async ensureOpened( + uri: string, + forceOpen = false, + options?: EditorOpenerOptions + ): Promise { + const widget = this.editorManager.all.find( + (widget) => widget.editor.uri.toString() === uri + ); + if (widget && !forceOpen) { + return widget; + } + + const disposables = new DisposableCollection(); + const deferred = new Deferred(); + // An editor can be in two primary states: + // - The editor is not yet opened. The `widget` is `undefined`. With `editorManager#open`, Theia will create an editor and fire an `editorManager#onCreated` event. + // - The editor is opened. Can be active, current, or open. + // - If the editor has the focus (the cursor blinks in the editor): it's the active editor. + // - If the editor does not have the focus (the focus is on a different widget or the context menu is opened in the editor): it's the current editor. + // - If the editor is not the top editor in the main area, it's opened. + if (!widget) { + // If the widget is `undefined`, IDE2 expects one `onCreate` event. Subscribe to the `onCreated` event + // and resolve the promise with the editor only when the new editor's visibility changes. + disposables.push( + this.editorManager.onCreated((editor) => { + if (editor.editor.uri.toString() === uri) { + if (editor.isAttached && editor.isVisible) { + deferred.resolve(editor); + } else { + disposables.push( + editor.onDidChangeVisibility((visible) => { + if (visible) { + // wait an animation frame. although the visible and attached props are true the editor is not there. + // let the browser render the widget + setTimeout( + () => + requestAnimationFrame(() => deferred.resolve(editor)), + 0 + ); + } + }) + ); + } + } + }) + ); + } + + this.editorManager + .open( + new URI(uri), + options ?? { + mode: 'reveal', + preview: false, + counter: 0, + } + ) + .then((editorWidget) => { + // If the widget was defined, it was already opened. + // The editor is expected to be attached to the shell and visible in the UI. + // The deferred promise does not have to wait for the `editorManager#onCreated` event. + // It can resolve earlier. + if (widget) { + deferred.resolve(editorWidget); + } + }); + + const timeout = 5_000; // number of ms IDE2 waits for the editor to show up in the UI + const result: EditorWidget | undefined | 'timeout' = await Promise.race([ + deferred.promise, + wait(timeout).then(() => { + disposables.dispose(); + return 'timeout' as const; + }), + ]); + if (result === 'timeout') { + console.warn( + `Timeout after ${timeout} millis. The editor has not shown up in time. URI: ${uri}` + ); + return undefined; + } + return result; + } +} +export namespace OpenSketchFiles { + export namespace Commands { + export const OPEN_SKETCH_FILES: Command = { + id: 'lingzhi-open-sketch-files', + }; + export const ENSURE_OPENED: Command = { + id: 'lingzhi-ensure-opened', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/open-sketch.ts b/arduino-ide-extension/src/browser/contributions/open-sketch.ts new file mode 100644 index 000000000..b9c84ab24 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/open-sketch.ts @@ -0,0 +1,260 @@ +import { nls } from '@theia/core/lib/common/nls'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { FileService } from '@theia/filesystem/lib/browser/file-service'; +import { LabelProvider } from '@theia/core/lib/browser/label-provider'; +import { + ResponseService, + SketchesError, + SketchesService, + SketchRef, +} from '../../common/protocol'; +import { + Command, + CommandRegistry, + KeybindingRegistry, + Sketch, + SketchContribution, + URI, +} from './contribution'; +import { DialogService } from '../dialog-service'; +import { FileStat } from '@theia/filesystem/lib/common/files'; +import { WorkspaceService } from '../theia/workspace/workspace-service'; +import { WorkspaceInput } from '@theia/workspace/lib/browser'; +import { OpenSketchFiles } from './open-sketch-files'; +import { + MAIN_WIDGET_CLOSE_AND_OPEN, + MyWidgetCommandHome, +} from '../boardImg/boardImg-widget-contribution'; +import { LINGZHI_OPEN_SKETCHBOOK_WIDGET } from '../widgets/sketchbook/sketchbook-widget-contribution'; + +export type SketchLocation = string | URI | SketchRef; +export namespace SketchLocation { + export function toUri(location: SketchLocation): URI { + if (typeof location === 'string') { + return new URI(location); + } else if (SketchRef.is(location)) { + return toUri(location.uri); + } else { + return location; + } + } + export function is(arg: unknown): arg is SketchLocation { + return typeof arg === 'string' || arg instanceof URI || SketchRef.is(arg); + } +} + +@injectable() +export class OpenSketch extends SketchContribution { + @inject(WorkspaceService) + protected readonly workspaceService1: WorkspaceService; + @inject(ResponseService) + private readonly responseService: ResponseService; + + override registerCommands(registry: CommandRegistry): void { + // 注册 OpenSketch.Commands.OPEN_SKETCH 命令 + registry.registerCommand(OpenSketch.Commands.OPEN_SKETCH, { + // 定义命令的执行逻辑 + execute: async (arg, uri) => { + // 如果参数不是 SketchLocation 类型,则调用 selectSketch 方法获取要打开的草图位置 + let toOpen = !SketchLocation.is(arg) ? await this.selectSketch() : arg; + if (toOpen || uri) { + if (!uri) { + uri = (toOpen as Sketch).uri; + } + const today = new Date(); + localStorage.setItem( + 'arduino-new-sketch-executedB', + today.toLocaleString() + ); + localStorage.setItem( + 'lingzhi-open-sketch-view', + today.toLocaleString() + ); + // 如果有可打开的草图位置,则调用 openSketch 方法打开草图 + const stat = await this.toFileStat(uri); + await this.workspaceService1.reloadSetWorkspace(stat); + await this.sketchServiceClient.init(true); + + this.commandService.executeCommand(MyWidgetCommandHome.id); + this.commandService.executeCommand( + MAIN_WIDGET_CLOSE_AND_OPEN.id, + uri + ); + this.commandService.executeCommand(LINGZHI_OPEN_SKETCHBOOK_WIDGET.id); + + this.workspaceService.roots.then(async (roots) => { + for (const root of roots) { + await this.commandService.executeCommand( + OpenSketchFiles.Commands.OPEN_SKETCH_FILES.id, + root.resource, + true + ); + this.sketchesService.markAsRecentlyOpened( + root.resource.toString() + ); // no await, will get the notification later and rebuild the menu + } + }); + // 重新加载窗口以及工作区 + return this.openSketch(toOpen); + } + }, + }); + } + + // override registerMenus(registry: MenuModelRegistry): void { + // registry.registerMenuAction(ArduinoMenus.FILE__SKETCH_GROUP, { + // commandId: OpenSketch.Commands.OPEN_SKETCH.id, + // label: '打开...', + // order: '2', + // }); + // } + + override registerKeybindings(registry: KeybindingRegistry): void { + registry.registerKeybinding({ + command: OpenSketch.Commands.OPEN_SKETCH.id, + keybinding: 'CtrlCmd+O', + }); + } + + private async openSketch(toOpen: SketchLocation | undefined): Promise { + // 如果没有要打开的草图位置,则直接返回 + if (!toOpen) { + return; + } + // 将草图位置转换为 URI + const uri = SketchLocation.toUri(toOpen); + try { + // 调用 sketchesService 的 loadSketch 方法加载草图 + await this.sketchesService.loadSketch(uri.toString()); + } catch (err) { + // 如果错误是因为草图未找到 + if (SketchesError.NotFound.is(err)) { + // 显示错误消息 + // this.messageService.error(err.message); + const chunk = `${err.message}`; + this.responseService.appendToOutput({ chunk }); + } + // 重新抛出错误 + throw err; + } + + // 调用 workspaceService 的 open 方法打开草图 + // const stat = await this.toFileStat(uri); + // this.workspaceService1.reloadSetWorkspace(stat); + const preserveWindow: WorkspaceInput = { preserveWindow: true }; + this.workspaceService.open(uri, preserveWindow); + } + + /** + * 如果参数URI指向文件或目录,则返回FileStat。否则, `undefined`. + */ + protected async toFileStat( + uri: URI | string | undefined + ): Promise { + // 如果传入的 URI 为 undefined,则直接返回 undefined + if (!uri) { + return undefined; + } + let uriStr = uri.toString(); + try { + // 如果 URI 以 '/' 结尾,去除末尾的 '/' + if (uriStr.endsWith('/')) { + uriStr = uriStr.slice(0, -1); + } + // 创建标准化路径的 URI 对象 + const normalizedUri = new URI(uriStr).normalizePath(); + // 通过文件服务解析该 URI,获取文件状态信息 + return await this.fileService.resolve(normalizedUri); + } catch (error) { + // 如果出现错误,返回 undefined + return undefined; + } + } + + private async selectSketch(): Promise { + const defaultPath = await this.defaultPath(); + const { filePaths } = await this.dialogService.showOpenDialog({ + defaultPath, + properties: ['createDirectory', 'openFile'], + filters: [ + { + name: '草图', + extensions: ['ino', 'pde'], + }, + ], + }); + if (!filePaths.length) { + return undefined; + } + if (filePaths.length > 1) { + this.logger.warn(`多个草图被选中: ${filePaths}. 用第一个。`); + } + const sketchFilePath = filePaths[0]; + const sketchFileUri = await this.fileSystemExt.getUri(sketchFilePath); + const sketch = await this.sketchesService.getSketchFolder(sketchFileUri); + if (sketch) { + return sketch; + } + if (Sketch.isSketchFile(sketchFileUri)) { + return promptMoveSketch(sketchFileUri, { + fileService: this.fileService, + sketchesService: this.sketchesService, + labelProvider: this.labelProvider, + dialogService: this.dialogService, + }); + } + } +} + +export namespace OpenSketch { + export namespace Commands { + export const OPEN_SKETCH: Command = { + id: 'lingzhi-open-sketch', + }; + } +} + +export async function promptMoveSketch( + sketchFileUri: string | URI, + options: { + fileService: FileService; + sketchesService: SketchesService; + labelProvider: LabelProvider; + dialogService: DialogService; + } +): Promise { + const { fileService, sketchesService, labelProvider, dialogService } = + options; + const uri = + sketchFileUri instanceof URI ? sketchFileUri : new URI(sketchFileUri); + const name = uri.path.name; + const nameWithExt = labelProvider.getName(uri); + const { response } = await dialogService.showMessageBox({ + title: nls.localize('arduino/sketch/moving', '移动'), + type: 'question', + buttons: [ + nls.localize('vscode/issueMainService/cancel', '取消'), + nls.localize('vscode/issueMainService/ok', '确定'), + ], + message: `文件“${nameWithExt}”需要在名为“${name}”的草图文件夹中。创建这个文件夹,移动文件,然后继续?`, + }); + if (response === 1) { + // OK + const newSketchUri = uri.parent.resolve(name); + const exists = await fileService.exists(newSketchUri); + if (exists) { + await dialogService.showMessageBox({ + type: 'error', + title: '错误', + message: `已经存在名为“${name}”的文件夹。不能打开草图。`, + }); + return undefined; + } + await fileService.createFolder(newSketchUri); + await fileService.move( + uri, + new URI(newSketchUri.resolve(nameWithExt).toString()) + ); + return sketchesService.getSketchFolder(newSketchUri.toString()); + } +} diff --git a/arduino-ide-extension/src/browser/contributions/quit-app.ts b/arduino-ide-extension/src/browser/contributions/quit-app.ts new file mode 100644 index 000000000..bc71d5e4f --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/quit-app.ts @@ -0,0 +1,53 @@ +import { inject, injectable } from '@theia/core/shared/inversify'; +import { isOSX } from '@theia/core/lib/common/os'; +import { + Contribution, + Command, + MenuModelRegistry, + KeybindingRegistry, + CommandRegistry, +} from './contribution'; +import { ArduinoMenus } from '../menu/arduino-menus'; +import { AppService } from '../app-service'; + +@injectable() +export class QuitApp extends Contribution { + @inject(AppService) + private readonly appService: AppService; + + override registerCommands(registry: CommandRegistry): void { + if (!isOSX) { + registry.registerCommand(QuitApp.Commands.QUIT_APP, { + execute: () => this.appService.quit(), + }); + } + } + + override registerMenus(registry: MenuModelRegistry): void { + // On macOS we will get the `Quit ${YOUR_APP_NAME}` menu item natively, no need to duplicate it. + if (!isOSX) { + registry.registerMenuAction(ArduinoMenus.FILE__QUIT_GROUP, { + commandId: QuitApp.Commands.QUIT_APP.id, + label: '退出', + order: '0', + }); + } + } + + override registerKeybindings(registry: KeybindingRegistry): void { + if (!isOSX) { + registry.registerKeybinding({ + command: QuitApp.Commands.QUIT_APP.id, + keybinding: 'CtrlCmd+Q', + }); + } + } +} + +export namespace QuitApp { + export namespace Commands { + export const QUIT_APP: Command = { + id: 'lingzhi-quit-app', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/rename-cloud-sketch.ts b/arduino-ide-extension/src/browser/contributions/rename-cloud-sketch.ts new file mode 100644 index 000000000..77a0ac0b4 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/rename-cloud-sketch.ts @@ -0,0 +1,163 @@ +import { CompositeTreeNode } from '@theia/core/lib/browser/tree'; +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 { + TaskFactoryImpl, + WorkspaceInputDialogWithProgress, +} from '../theia/workspace/workspace-input-dialog'; +import { CloudSketchbookTree } from '../widgets/cloud-sketchbook/cloud-sketchbook-tree'; +import { CloudSketchbookTreeModel } from '../widgets/cloud-sketchbook/cloud-sketchbook-tree-model'; +import { + CloudSketchContribution, + pullingSketch, + pushingSketch, + sketchAlreadyExists, + synchronizingSketchbook, +} from './cloud-contribution'; +import { Command, CommandRegistry, Sketch, URI } from './contribution'; + +export interface RenameCloudSketchParams { + readonly cloudUri: URI; + readonly sketch: Sketch; +} + +@injectable() +export class RenameCloudSketch extends CloudSketchContribution { + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(RenameCloudSketch.Commands.RENAME_CLOUD_SKETCH, { + execute: (params: RenameCloudSketchParams) => + this.renameSketch(params, true), + }); + } + + private async renameSketch( + params: RenameCloudSketchParams, + skipShowErrorMessageOnOpen: boolean, + initValue: string = params.sketch.name + ): Promise { + const treeModel = await this.treeModel(); + if (treeModel) { + const posixPath = params.cloudUri.path.toString(); + const node = treeModel.getNode(posixPath); + const parentNode = node?.parent; + if ( + CloudSketchbookTree.CloudSketchDirNode.is(node) && + CompositeTreeNode.is(parentNode) + ) { + return this.openWizard( + params, + node, + parentNode, + treeModel, + skipShowErrorMessageOnOpen, + initValue + ); + } + } + return undefined; + } + + private async openWizard( + params: RenameCloudSketchParams, + node: CloudSketchbookTree.CloudSketchDirNode, + parentNode: CompositeTreeNode, + treeModel: CloudSketchbookTreeModel, + skipShowErrorMessageOnOpen: boolean, + initialValue?: string | undefined + ): Promise { + const parentUri = CloudSketchbookTree.CloudSketchDirNode.is(parentNode) + ? parentNode.uri + : CreateUri.root; + const existingNames = parentNode.children + .filter(CloudSketchbookTree.CloudSketchDirNode.is) + .map(({ fileStat }) => fileStat.name); + const taskFactory = new TaskFactoryImpl((value) => + this.renameSketchWithProgress(params, node, treeModel, value) + ); + try { + const dialog = new WorkspaceInputDialogWithProgress( + { + title: '云草图的新名称', + parentUri, + initialValue, + validate: (input) => { + if (existingNames.includes(input)) { + return sketchAlreadyExists(input); + } + return Sketch.validateCloudSketchFolderName(input) ?? ''; + }, + }, + this.labelProvider, + taskFactory + ); + await dialog.open(skipShowErrorMessageOnOpen); + return dialog.taskResult; + } catch (err) { + if (isConflict(err)) { + await treeModel.refresh(); + return this.renameSketch( + params, + false, + taskFactory.value ?? initialValue + ); + } + throw err; + } + } + + private renameSketchWithProgress( + params: RenameCloudSketchParams, + node: CloudSketchbookTree.CloudSketchDirNode, + treeModel: CloudSketchbookTreeModel, + value: string + ): (progress: Progress) => Promise { + return async (progress: Progress) => { + const fromName = params.cloudUri.path.name; + const fromPosixPath = params.cloudUri.path.toString(); + const toPosixPath = params.cloudUri.parent.resolve(value).path.toString(); + // push + progress.report({ message: pushingSketch(params.sketch.name) }); + await treeModel.sketchbookTree().push(node, true); + + // rename + progress.report({ + message: nls.localize( + 'arduino/cloudSketch/renaming', + "Renaming cloud sketch from '{0}' to '{1}'...", + fromName, + value + ), + }); + await this.createApi.rename(fromPosixPath, toPosixPath); + + // sync + progress.report({ + message: synchronizingSketchbook, + }); + this.createApi.sketchCache.init(); // invalidate the cache + await this.createApi.sketches(); // IDE2 must pull all sketches to find the new one + const sketch = this.createApi.sketchCache.getSketch(toPosixPath); + if (!sketch) { + return undefined; + } + await treeModel.refresh(); + + // pull + progress.report({ message: pullingSketch(sketch.name) }); + const pulledNode = await this.pull(sketch); + return pulledNode + ? node.uri.parent.resolve(sketch.name).toString() + : undefined; + }; + } +} +export namespace RenameCloudSketch { + export namespace Commands { + export const RENAME_CLOUD_SKETCH: Command = { + id: 'lingzhi-rename-cloud-sketch', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/save-as-sketch.ts b/arduino-ide-extension/src/browser/contributions/save-as-sketch.ts new file mode 100644 index 000000000..bd65e7a75 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/save-as-sketch.ts @@ -0,0 +1,328 @@ +import { NavigatableWidget } from '@theia/core/lib/browser/navigatable'; +import { Saveable } from '@theia/core/lib/browser/saveable'; +import { ApplicationShell } from '@theia/core/lib/browser/shell/application-shell'; +import { WindowService } from '@theia/core/lib/browser/window/window-service'; +import { ApplicationError } from '@theia/core/lib/common/application-error'; +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 { ResponseService, SketchesError } from '../../common/protocol'; +import { StartupTasks } from '../../electron-common/startup-task'; +import { ArduinoMenus } from '../menu/arduino-menus'; +import { CurrentSketch } from '../sketches-service-client-impl'; +import { CloudSketchContribution } from './cloud-contribution'; +import { + Command, + CommandRegistry, + KeybindingRegistry, + MenuModelRegistry, + Sketch, + URI, +} from './contribution'; +import { DeleteSketch } from './delete-sketch'; +import { + RenameCloudSketch, + RenameCloudSketchParams, +} from './rename-cloud-sketch'; +import { assertConnectedToBackend } from './save-sketch'; +import { Dialog } from '../theia/dialogs/theiaDialogs/dialogs'; + +@injectable() +export class SaveAsSketch extends CloudSketchContribution { + @inject(ApplicationShell) + private readonly shell: ApplicationShell; + @inject(WindowService) + private readonly windowService: WindowService; + @inject(ResponseService) + private readonly responseService1: ResponseService; + + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(SaveAsSketch.Commands.SAVE_AS_SKETCH, { + execute: async (args) => { + try { + return await this.saveAs(args); + } catch (err) { + let message = String(err); + if (ApplicationError.is(err)) { + if (SketchesError.SketchAlreadyContainsThisFile.is(err)) { + message = nls.localize( + 'arduino/sketch/sketchAlreadyContainsThisFileMessage', + '将草图“{0}”保存为“{1}”失败。{2}', + err.data.sourceSketchName, + err.data.targetSketchName, + err.message + ); + } else { + message = err.message; + } + } else if (err instanceof Error) { + message = err.message; + } + // this.messageService.error(message); + const chunk = `${message}\n`; + this.responseService1.appendToOutput({ chunk }); + } + }, + }); + } + + override registerMenus(registry: MenuModelRegistry): void { + registry.registerMenuAction(ArduinoMenus.FILE__SKETCH_GROUP, { + commandId: SaveAsSketch.Commands.SAVE_AS_SKETCH.id, + label: '另存为...', + order: '7', + }); + } + + override registerKeybindings(registry: KeybindingRegistry): void { + registry.registerKeybinding({ + command: SaveAsSketch.Commands.SAVE_AS_SKETCH.id, + keybinding: 'CtrlCmd+Shift+S', + }); + } + + /** + * Resolves `true` if the sketch was successfully saved as something. + */ + private async saveAs( + params = SaveAsSketch.Options.DEFAULT + ): Promise { + const { + execOnlyIfTemp, + openAfterMove, + wipeOriginal, + markAsRecentlyOpened, + } = params; + assertConnectedToBackend({ + connectionStatusService: this.connectionStatusService, + responseService: this.responseService1, + }); + const sketch = await this.sketchServiceClient.currentSketch(); + if (!CurrentSketch.isValid(sketch)) { + return false; + } + + let destinationUri: string | undefined; + const cloudUri = this.createFeatures.cloudUri(sketch); + if (cloudUri) { + destinationUri = await this.createCloudCopy({ cloudUri, sketch }); + } else { + destinationUri = await this.createLocalCopy(sketch, execOnlyIfTemp); + } + if (!destinationUri) { + return false; + } + + const copiedSketch = await this.sketchesService.copy(sketch, { + destinationUri, + }); + const newWorkspaceUri = copiedSketch.uri; + + await saveOntoCopiedSketch( + sketch, + newWorkspaceUri, + this.shell, + this.editorManager + ); + if (markAsRecentlyOpened) { + this.sketchesService.markAsRecentlyOpened(newWorkspaceUri); + } + const options: WorkspaceInput & StartupTasks = { + preserveWindow: true, + tasks: [], + }; + if (openAfterMove) { + this.windowService.setSafeToShutDown(); + if (wipeOriginal || (openAfterMove && execOnlyIfTemp)) { + options.tasks.push({ + command: DeleteSketch.Commands.DELETE_SKETCH.id, + args: [{ toDelete: sketch.uri }], + }); + } + this.workspaceService.open(new URI(newWorkspaceUri), options); + } + return !!newWorkspaceUri; + } + + private async createCloudCopy( + params: RenameCloudSketchParams + ): Promise { + return this.commandService.executeCommand( + RenameCloudSketch.Commands.RENAME_CLOUD_SKETCH.id, + params + ); + } + + private async createLocalCopy( + sketch: Sketch, + execOnlyIfTemp?: boolean + ): Promise { + const isTemp = await this.sketchesService.isTemp(sketch); + if (!isTemp && !!execOnlyIfTemp) { + return undefined; + } + + const sketchUri = new URI(sketch.uri); + const sketchbookDirUri = await this.defaultUri(); + // If the sketch is temp, IDE2 proposes the default sketchbook folder URI. + // If the sketch is not temp, but not contained in the default sketchbook folder, IDE2 proposes the default location. + // Otherwise, it proposes the parent folder of the current sketch. + const containerDirUri = isTemp + ? sketchbookDirUri + : !sketchbookDirUri.isEqualOrParent(sketchUri) + ? sketchbookDirUri + : sketchUri.parent; + const exists = await this.fileService.exists( + containerDirUri.resolve(sketch.name) + ); + + // If target does not exist, propose a `directories.user`/${sketch.name} path + // If target exists, propose `directories.user`/${sketch.name}_copy_${yyyymmddHHMMss} + // IDE2 must never prompt an invalid sketch folder name (https://github.com/arduino/arduino-ide/pull/1833#issuecomment-1412569252) + const defaultUri = containerDirUri.resolve( + Sketch.toValidSketchFolderName(sketch.name, exists) + ); + const defaultPath = await this.fileService.fsPath(defaultUri); + return await this.promptLocalSketchFolderDestination(sketch, defaultPath); + } + + /** + * Prompts for the new sketch folder name until a valid one is give, + * then resolves with the destination sketch folder URI string, + * or `undefined` if the operation was canceled. + */ + private async promptLocalSketchFolderDestination( + sketch: Sketch, + defaultPath: string + ): Promise { + let sketchFolderDestinationUri: string | undefined; + while (!sketchFolderDestinationUri) { + const { filePath } = await this.dialogService.showSaveDialog({ + title: '将项目文件夹另存为…', + defaultPath, + }); + if (!filePath) { + return undefined; + } + const destinationUri = await this.fileSystemExt.getUri(filePath); + // The new location of the sketch cannot be inside the location of current sketch. + // https://github.com/arduino/arduino-ide/issues/1882 + let dialogContent: InvalidSketchFolderDialogContent | undefined; + if (new URI(sketch.uri).isEqualOrParent(new URI(destinationUri))) { + dialogContent = { + message: `无效的草图文件夹位置:‘${filePath}’`, + details: '不能将草图保存到其内部的文件夹中。', + question: '您想尝试将草图保存到其他位置吗?', + }; + } + if (!dialogContent) { + const sketchFolderName = new URI(destinationUri).path.base; + const errorMessage = Sketch.validateSketchFolderName(sketchFolderName); + if (errorMessage) { + dialogContent = { + message: `无效的草图文件夹名称:‘${sketchFolderName}’`, + details: errorMessage, + question: '您想尝试用不同的名称保存草图吗?', + }; + } + } + if (dialogContent) { + const message = ` +${dialogContent.message} + +${dialogContent.details} + +${dialogContent.question}`.trim(); + defaultPath = filePath; + const { response } = await this.dialogService.showMessageBox({ + message, + buttons: [Dialog.CANCEL, Dialog.YES], + }); + // cancel + if (response === 0) { + return undefined; + } + } else { + sketchFolderDestinationUri = destinationUri; + } + } + return sketchFolderDestinationUri; + } +} + +interface InvalidSketchFolderDialogContent { + readonly message: string; + readonly details: string; + readonly question: string; +} + +export namespace SaveAsSketch { + export namespace Commands { + export const SAVE_AS_SKETCH: Command = { + id: 'lingzhi-save-as-sketch', + }; + } + export interface Options { + readonly execOnlyIfTemp?: boolean; + readonly openAfterMove?: boolean; + /** + * Ignored if `openAfterMove` is `false`. + */ + readonly wipeOriginal?: boolean; + readonly markAsRecentlyOpened?: boolean; + } + export namespace Options { + export const DEFAULT: Options = { + execOnlyIfTemp: false, + openAfterMove: true, + wipeOriginal: false, + markAsRecentlyOpened: false, + }; + } +} + +export async function saveOntoCopiedSketch( + sketch: Sketch, + newSketchFolderUri: string, + shell: ApplicationShell, + editorManager: EditorManager +): Promise { + const widgets = shell.widgets; + const snapshots = new Map(); + 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/contributions/save-sketch.ts b/arduino-ide-extension/src/browser/contributions/save-sketch.ts new file mode 100644 index 000000000..ee2abff47 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/save-sketch.ts @@ -0,0 +1,90 @@ +import { CommonCommands } from '@theia/core/lib/browser/common-frontend-contribution'; +import { nls } from '@theia/core/lib/common/nls'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { ArduinoMenus } from '../menu/arduino-menus'; +import { CurrentSketch } from '../sketches-service-client-impl'; +import { ApplicationConnectionStatusContribution } from '../theia/core/connection-status-service'; +import { + Command, + CommandRegistry, + KeybindingRegistry, + MenuModelRegistry, + SketchContribution, +} from './contribution'; +import { SaveAsSketch } from './save-as-sketch'; +import { ResponseService } from '../../common/protocol'; + +@injectable() +export class SaveSketch extends SketchContribution { + @inject(ResponseService) + private readonly responseService: ResponseService; + + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(SaveSketch.Commands.SAVE_SKETCH, { + execute: () => this.saveSketch(), + }); + } + + override registerMenus(registry: MenuModelRegistry): void { + registry.registerMenuAction(ArduinoMenus.FILE__SKETCH_GROUP, { + commandId: SaveSketch.Commands.SAVE_SKETCH.id, + label: nls.localize('vscode/fileCommands/save', '保存'), + order: '7', + }); + } + + override registerKeybindings(registry: KeybindingRegistry): void { + registry.registerKeybinding({ + command: SaveSketch.Commands.SAVE_SKETCH.id, + keybinding: 'CtrlCmd+S', + }); + } + + async saveSketch(): Promise { + assertConnectedToBackend({ + connectionStatusService: this.connectionStatusService, + responseService: this.responseService, + }); + const sketch = await this.sketchServiceClient.currentSketch(); + if (!CurrentSketch.isValid(sketch)) { + return; + } + const isTemp = await this.sketchesService.isTemp(sketch); + if (isTemp) { + return this.commandService.executeCommand( + SaveAsSketch.Commands.SAVE_AS_SKETCH.id, + { + execOnlyIfTemp: false, + openAfterMove: true, + wipeOriginal: true, + } + ); + } + + return this.commandService.executeCommand(CommonCommands.SAVE_ALL.id); + } +} + +export namespace SaveSketch { + export namespace Commands { + export const SAVE_SKETCH: Command = { + id: 'lingzhi-save-sketch', + }; + } +} + +// https://github.com/arduino/arduino-ide/issues/2081 +export function assertConnectedToBackend(param: { + connectionStatusService: ApplicationConnectionStatusContribution; + responseService: ResponseService; +}): void { + if (param.connectionStatusService.offlineStatus === 'backend') { + const message = nls.localize( + 'theia/core/couldNotSave', + '无法保存草图。请将未保存的工作复制到您最喜欢的文本编辑器中,然后重新启动IDE。' + ); + const chunk = `${message}\n`; + param.responseService.appendToOutput({ chunk }); + throw new Error(message); + } +} diff --git a/arduino-ide-extension/src/browser/contributions/selected-board.ts b/arduino-ide-extension/src/browser/contributions/selected-board.ts new file mode 100644 index 000000000..f4ee9fbb5 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/selected-board.ts @@ -0,0 +1,118 @@ +import { + StatusBar, + StatusBarAlignment, +} from '@theia/core/lib/browser/status-bar/status-bar'; +import { nls } from '@theia/core/lib/common/nls'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import type { + BoardList, + BoardListItem, +} from '../../common/protocol/board-list'; +import { BoardsServiceProvider } from '../boards/boards-service-provider'; +import { Contribution } from './contribution'; +import { WindowService } from '@theia/core/lib/browser/window/window-service'; + +@injectable() +export class SelectedBoard extends Contribution { + @inject(StatusBar) + private readonly statusBar: StatusBar; + @inject(BoardsServiceProvider) + private readonly boardsServiceProvider: BoardsServiceProvider; + @inject(WindowService) + protected readonly windowService: WindowService; + + override onStart(): void { + this.boardsServiceProvider.onBoardListDidChange((boardList) => + this.update(boardList) + ); + } + + override onReady(): void { + this.boardsServiceProvider.ready.then(() => this.update()); + } + + private update( + boardList: BoardList = this.boardsServiceProvider.boardList + ): void { + const { selectedBoard, selectedPort } = boardList.boardsConfig; + function name(fqbn: string | undefined, name: string): string { + if (!fqbn) { + return ''; + } + const lastColonIndex = fqbn.lastIndexOf(':'); + const valueAfterLastColon = fqbn.slice(lastColonIndex + 1); + switch (valueAfterLastColon) { + case 'lzesp32': + return '零知-ESP32'; + case 'lzesp8266': + return '零知-ESP8266'; + case 'lingzhistandard': + return '零知-标准板'; + case 'lingzhiMini': + return '零知-迷你板'; + case 'lingzhiM4': + return '零知-增强板'; + case 'lz_ble52': + return '零知-BLE52'; + default: + return name; + } + } + this.statusBar.setElement('arduino-selected-board', { + alignment: StatusBarAlignment.LEFT, + text: + '型号:' + + (selectedBoard + ? `$(microchip) ${name(selectedBoard.fqbn, selectedBoard.name)}` + : `$(close) ${nls.localize( + 'arduino/common/noBoardSelected', + 'No board selected' + )}`), + className: 'arduino-selected-board', + }); + if (selectedBoard) { + const notConnectedLabel = nls.localize( + 'arduino/common/notConnected', + '串口:[未连接]' + ); + let portLabel = notConnectedLabel; + if (selectedPort) { + portLabel = `在${selectedPort.address}上`; + const selectedItem: BoardListItem | undefined = + boardList.items[boardList.selectedIndex]; + if (!selectedItem) { + portLabel += ` ${notConnectedLabel}`; // append ` [not connected]` when the port is selected but it's not detected by the CLI + } + } + this.statusBar.setElement('arduino-selected-port', { + alignment: StatusBarAlignment.LEFT, + text: portLabel, + className: 'arduino-selected-port', + }); + } else { + this.statusBar.removeElement('arduino-selected-port'); + } + this.statusBar.setElement('lingzhi-common-problem', { + alignment: StatusBarAlignment.RIGHT, + text: '常见问题', + className: 'lingzhi-common-problem', + onclick: () => { + this.windowService.openNewWindow( + 'http://www.lingzhilab.com/lzbbs/resources.html?ecid=206', + { external: true } + ); + }, + }); + this.statusBar.setElement('lingzhi-official-website', { + alignment: StatusBarAlignment.RIGHT, + text: '官网: www.lingzhilab.com', + color: '#ff0000', + className: 'lingzhi-official-website', + onclick: () => { + this.windowService.openNewWindow('https://www.lingzhilab.com/', { + external: true, + }); + }, + }); + } +} diff --git a/arduino-ide-extension/src/browser/contributions/sketch-control.ts b/arduino-ide-extension/src/browser/contributions/sketch-control.ts new file mode 100644 index 000000000..073c95614 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/sketch-control.ts @@ -0,0 +1,221 @@ +import { CommonCommands } from '@theia/core/lib/browser/common-frontend-contribution'; +import { ContextMenuRenderer } from '@theia/core/lib/browser/context-menu-renderer'; +import { ApplicationShell } from '@theia/core/lib/browser/shell/application-shell'; +import { + Disposable, + DisposableCollection, +} from '@theia/core/lib/common/disposable'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { WorkspaceCommands } from '@theia/workspace/lib/browser/workspace-commands'; +import { ArduinoMenus } from '../menu/arduino-menus'; +import { CurrentSketch } from '../sketches-service-client-impl'; +import { + Command, + CommandRegistry, + KeybindingRegistry, + MenuModelRegistry, + open, + SketchContribution, + TabBarToolbarRegistry, + URI, +} from './contribution'; + +@injectable() +export class SketchControl extends SketchContribution { + @inject(ApplicationShell) + private readonly shell: ApplicationShell; + @inject(MenuModelRegistry) + private readonly menuRegistry: MenuModelRegistry; + @inject(ContextMenuRenderer) + private readonly contextMenuRenderer: ContextMenuRenderer; + + protected readonly toDisposeBeforeCreateNewContextMenu = + new DisposableCollection(); + public determiningWhetherToExpand = true; + + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand( + SketchControl.Commands.OPEN_SKETCH_CONTROL__TOOLBAR, + { + isVisible: (widget) => + this.shell.getWidgets('main').indexOf(widget) !== -1, + execute: async (b) => { + this.toDisposeBeforeCreateNewContextMenu.dispose(); + + let parentElement: HTMLElement | undefined = undefined; + let target: HTMLElement | null; + if (b === true) { + target = document.getElementById('lingzhi-daima-contextmenu-menu'); + } else { + target = document.getElementById( + SketchControl.Commands.OPEN_SKETCH_CONTROL__TOOLBAR.id + ); + } + if (target instanceof HTMLElement) { + parentElement = target.parentElement ?? undefined; + } + if (!parentElement) { + return; + } + + const sketch = await this.sketchServiceClient.currentSketch(); + if (!CurrentSketch.isValid(sketch)) { + return; + } + + this.menuRegistry.registerMenuAction( + ArduinoMenus.SKETCH_CONTROL__CONTEXT__MAIN_GROUP, + { + commandId: WorkspaceCommands.FILE_RENAME.id, + label: '重命名', + order: '1', + } + ); + this.toDisposeBeforeCreateNewContextMenu.push( + Disposable.create(() => + this.menuRegistry.unregisterMenuAction( + WorkspaceCommands.FILE_RENAME + ) + ) + ); + + this.menuRegistry.registerMenuAction( + ArduinoMenus.SKETCH_CONTROL__CONTEXT__MAIN_GROUP, + { + commandId: WorkspaceCommands.FILE_DELETE.id, + label: '删除', + order: '2', + } + ); + this.toDisposeBeforeCreateNewContextMenu.push( + Disposable.create(() => + this.menuRegistry.unregisterMenuAction( + WorkspaceCommands.FILE_DELETE + ) + ) + ); + if (this.determiningWhetherToExpand) { + this.menuRegistry.registerMenuAction( + ArduinoMenus.SKETCH_CONTROL__CONTEXT__NAVIGATION_GROUP, + { + commandId: CommonCommands.PREVIOUS_TAB.id, + label: '上一个选项卡', + order: '0', + } + ); + this.toDisposeBeforeCreateNewContextMenu.push( + Disposable.create(() => + this.menuRegistry.unregisterMenuAction( + CommonCommands.PREVIOUS_TAB + ) + ) + ); + this.menuRegistry.registerMenuAction( + ArduinoMenus.SKETCH_CONTROL__CONTEXT__NAVIGATION_GROUP, + { + commandId: CommonCommands.NEXT_TAB.id, + label: '下一个选项卡', + order: '0', + } + ); + this.toDisposeBeforeCreateNewContextMenu.push( + Disposable.create(() => + this.menuRegistry.unregisterMenuAction(CommonCommands.NEXT_TAB) + ) + ); + } + + const { mainFileUri, rootFolderFileUris } = sketch; + const uris = [mainFileUri, ...rootFolderFileUris]; + for (let i = 0; i < uris.length; i++) { + const uri = new URI(uris[i]); + + // focus on the opened sketch + const command = { + id: `arduino-focus-file--${uri.toString()}`, + }; + const handler = { + execute: () => open(this.openerService, uri), + }; + this.toDisposeBeforeCreateNewContextMenu.push( + registry.registerCommand(command, handler) + ); + if (this.determiningWhetherToExpand) { + this.menuRegistry.registerMenuAction( + ArduinoMenus.SKETCH_CONTROL__CONTEXT__RESOURCES_GROUP, + { + commandId: command.id, + label: this.labelProvider.getName(uri), + order: String(i).padStart(4), + } + ); + this.toDisposeBeforeCreateNewContextMenu.push( + Disposable.create(() => + this.menuRegistry.unregisterMenuAction(command) + ) + ); + } + } + const options = { + // 定义菜单路径,通常是一个特定的标识符,用于确定要显示的菜单内容 + menuPath: ArduinoMenus.SKETCH_CONTROL__CONTEXT, + anchor: { + // 锚点的 x 坐标,设置为父元素的左边界位置 + x: parentElement.getBoundingClientRect().left, + // 锚点的 y 坐标,设置为父元素的上边界位置加上父元素的高度 + y: + parentElement.getBoundingClientRect().top + + parentElement.offsetHeight, + }, + // 是否显示禁用的菜单项 + showDisabled: true, + }; + // 调用上下文菜单渲染器来渲染菜单,传入配置选项 + this.contextMenuRenderer.render(options); + }, + } + ); + } + + override registerMenus(registry: MenuModelRegistry): void { + registry.registerMenuAction( + ArduinoMenus.SKETCH_CONTROL__CONTEXT__MAIN_GROUP, + { + commandId: WorkspaceCommands.NEW_FILE.id, + label: '新建标签页', + order: '0', + } + ); + } + + override registerKeybindings(registry: KeybindingRegistry): void { + registry.registerKeybinding({ + command: WorkspaceCommands.NEW_FILE.id, + keybinding: 'CtrlCmd+Shift+N', + }); + registry.registerKeybinding({ + command: CommonCommands.PREVIOUS_TAB.id, + keybinding: 'CtrlCmd+Alt+Left', + }); + registry.registerKeybinding({ + command: CommonCommands.NEXT_TAB.id, + keybinding: 'CtrlCmd+Alt+Right', + }); + } + + override registerToolbarItems(registry: TabBarToolbarRegistry): void { + registry.registerItem({ + id: SketchControl.Commands.OPEN_SKETCH_CONTROL__TOOLBAR.id, + command: SketchControl.Commands.OPEN_SKETCH_CONTROL__TOOLBAR.id, + }); + } +} + +export namespace SketchControl { + export namespace Commands { + export const OPEN_SKETCH_CONTROL__TOOLBAR: Command = { + id: 'lingzhi-open-sketch-control--toolbar', + iconClass: 'fa lingzhi-a-24gf-ellipsisVertical', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/sketch-files-tracker.ts b/arduino-ide-extension/src/browser/contributions/sketch-files-tracker.ts new file mode 100644 index 000000000..d7c1c68d6 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/sketch-files-tracker.ts @@ -0,0 +1,65 @@ +import { SaveableWidget } from '@theia/core/lib/browser/saveable'; +import { DisposableCollection } from '@theia/core/lib/common/disposable'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { FileSystemFrontendContribution } from '@theia/filesystem/lib/browser/filesystem-frontend-contribution'; +import { FileChangeType } from '@theia/filesystem/lib/common/files'; +import { CurrentSketch } from '../sketches-service-client-impl'; +import { Sketch, SketchContribution } from './contribution'; +import { OpenSketchFiles } from './open-sketch-files'; + +@injectable() +export class SketchFilesTracker extends SketchContribution { + @inject(FileSystemFrontendContribution) + private readonly fileSystemFrontendContribution: FileSystemFrontendContribution; + private readonly toDisposeOnStop = new DisposableCollection(); + + override onStart(): void { + this.fileSystemFrontendContribution.onDidChangeEditorFile( + ({ type, editor }) => { + if (type === FileChangeType.DELETED) { + const editorWidget = editor; + if (SaveableWidget.is(editorWidget)) { + editorWidget.closeWithoutSaving(); + } else { + editorWidget.close(); + } + } + } + ); + } + + override onReady(): void { + this.sketchServiceClient.currentSketch().then(async (sketch) => { + if (CurrentSketch.isValid(sketch)) { + this.toDisposeOnStop.push( + this.fileService.onDidFilesChange(async (event) => { + for (const { type, resource } of event.changes) { + if ( + type === FileChangeType.ADDED && + resource.parent.toString() === sketch.uri + ) { + const reloadedSketch = await this.sketchesService.loadSketch( + sketch.uri + ); + if (Sketch.isInSketch(resource, reloadedSketch)) { + this.commandService.executeCommand( + OpenSketchFiles.Commands.ENSURE_OPENED.id, + resource.toString(), + true, + { + mode: 'open', + } + ); + } + } + } + }) + ); + } + }); + } + + onStop(): void { + this.toDisposeOnStop.dispose(); + } +} diff --git a/arduino-ide-extension/src/browser/contributions/sketchbook.ts b/arduino-ide-extension/src/browser/contributions/sketchbook.ts new file mode 100644 index 000000000..295c1fb92 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/sketchbook.ts @@ -0,0 +1,63 @@ +import { injectable } from '@theia/core/shared/inversify'; +import { CommandHandler } from '@theia/core/lib/common/command'; +import { MenuModelRegistry } from './contribution'; +import { ArduinoMenus } from '../menu/arduino-menus'; +import { Examples } from './examples'; +import { SketchContainer, SketchesError } from '../../common/protocol'; +import { OpenSketch } from './open-sketch'; + +@injectable() +export class Sketchbook extends Examples { + override onStart(): void { + this.sketchServiceClient.onSketchbookDidChange(() => this.update()); + this.configService.onDidChangeSketchDirUri(() => this.update()); + } + + override async onReady(): Promise { + this.update(); + } + + protected override update(): void { + this.sketchesService.getSketches({}).then((container) => { + this.register(container); + this.menuManager.update(); + }); + } + + override registerMenus(registry: MenuModelRegistry): void { + registry.registerSubmenu( + ArduinoMenus.FILE__SKETCHBOOK_SUBMENU, + '项目文件夹', + { order: '3' } + ); + } + + private register(container: SketchContainer): void { + this.toDispose.dispose(); + this.registerRecursively( + [...container.children, ...container.sketches], + ArduinoMenus.FILE__SKETCHBOOK_SUBMENU, + this.toDispose + ); + } + + protected override createHandler(uri: string): CommandHandler { + return { + execute: async () => { + try { + await this.commandService.executeCommand( + OpenSketch.Commands.OPEN_SKETCH.id, + uri + ); + } catch (err) { + if (SketchesError.NotFound.is(err)) { + // Force update the menu items to remove the absent sketch. + this.update(); + } else { + throw err; + } + } + }, + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/startup-tasks-executor.ts b/arduino-ide-extension/src/browser/contributions/startup-tasks-executor.ts new file mode 100644 index 000000000..6c1836012 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/startup-tasks-executor.ts @@ -0,0 +1,65 @@ +import { DisposableCollection } from '@theia/core/lib/common/disposable'; +import { + inject, + injectable, + postConstruct, +} from '@theia/core/shared/inversify'; +import { + hasStartupTasks, + StartupTasks, +} from '../../electron-common/startup-task'; +import { AppService } from '../app-service'; +import { Contribution } from './contribution'; + +@injectable() +export class StartupTasksExecutor extends Contribution { + @inject(AppService) + private readonly appService: AppService; + + private readonly toDispose = new DisposableCollection(); + + @postConstruct() + protected override init(): void { + super.init(); + this.toDispose.push( + this.appService.registerStartupTasksHandler((tasks) => + this.handleStartupTasks(tasks) + ) + ); + } + + onStop(): void { + this.toDispose.dispose(); + } + + private async handleStartupTasks(tasks: StartupTasks): Promise { + console.debug( + `Received the startup tasks from the electron main process. Args: ${JSON.stringify( + tasks + )}` + ); + if (!hasStartupTasks(tasks)) { + console.warn(`Could not detect 'tasks' from the signal. Skipping.`); + return; + } + await this.appStateService.reachedState('ready'); + console.log(`Executing startup tasks:`); + tasks.tasks.forEach(({ command, args = [] }) => { + console.log( + ` - '${command}' ${ + args.length ? `, args: ${JSON.stringify(args)}` : '' + }` + ); + this.commandService + .executeCommand(command, ...args) + .catch((err) => + console.error( + `Error occurred when executing the startup task '${command}'${ + args?.length ? ` with args: '${JSON.stringify(args)}` : '' + }.`, + err + ) + ); + }); + } +} diff --git a/arduino-ide-extension/src/browser/contributions/survey-notification.ts b/arduino-ide-extension/src/browser/contributions/survey-notification.ts new file mode 100644 index 000000000..56e94f418 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/survey-notification.ts @@ -0,0 +1,75 @@ +import { MessageService } from '@theia/core'; +import { FrontendApplicationContribution } from '@theia/core/lib/browser'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { LocalStorageService } from '@theia/core/lib/browser'; +import { nls } from '@theia/core/lib/common'; +import { WindowService } from '@theia/core/lib/browser/window/window-service'; +import { ArduinoPreferences } from '../arduino-preferences'; +import { SurveyNotificationService } from '../../common/protocol/survey-service'; + +const SURVEY_MESSAGE = nls.localize( + 'arduino/survey/surveyMessage', + '请通过回答这个超级简短的调查来帮助我们改进。我们重视我们的社区,并希望更好地了解我们的支持者。' +); +const DO_NOT_SHOW_AGAIN = nls.localize( + 'arduino/survey/dismissSurvey', + '不再弹出' +); +const GO_TO_SURVEY = nls.localize('arduino/survey/answerSurvey', '回答调查'); + +const SURVEY_BASE_URL = 'https://surveys.hotjar.com/'; +const surveyId = '17887b40-e1f0-4bd6-b9f0-a37f229ccd8b'; + +@injectable() +export class SurveyNotification implements FrontendApplicationContribution { + @inject(MessageService) + private readonly messageService: MessageService; + + @inject(LocalStorageService) + private readonly localStorageService: LocalStorageService; + + @inject(WindowService) + private readonly windowService: WindowService; + + @inject(ArduinoPreferences) + private readonly arduinoPreferences: ArduinoPreferences; + + @inject(SurveyNotificationService) + private readonly surveyNotificationService: SurveyNotificationService; + + onStart(): void { + this.arduinoPreferences.ready.then(async () => { + if ( + (await this.surveyNotificationService.isFirstInstance()) && + this.arduinoPreferences.get('arduino.survey.notification') + ) { + const surveyAnswered = await this.localStorageService.getData( + this.surveyKey(surveyId) + ); + if (surveyAnswered !== undefined) { + return; + } + const answer = await this.messageService.info( + SURVEY_MESSAGE, + DO_NOT_SHOW_AGAIN, + GO_TO_SURVEY + ); + switch (answer) { + case GO_TO_SURVEY: + this.windowService.openNewWindow(SURVEY_BASE_URL + surveyId, { + external: true, + }); + this.localStorageService.setData(this.surveyKey(surveyId), true); + break; + case DO_NOT_SHOW_AGAIN: + this.localStorageService.setData(this.surveyKey(surveyId), false); + break; + } + } + }); + } + + private surveyKey(id: string): string { + return `answered_survey:${id}`; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/update-arduino-state.ts b/arduino-ide-extension/src/browser/contributions/update-arduino-state.ts new file mode 100644 index 000000000..767fbbf8c --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/update-arduino-state.ts @@ -0,0 +1,184 @@ +import { DisposableCollection } from '@theia/core/lib/common/disposable'; +import URI from '@theia/core/lib/common/uri'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { HostedPluginSupport } from '../hosted/hosted-plugin-support'; +import type { ArduinoState } from 'vscode-arduino-api'; +import { + BoardsService, + CompileSummary, + isCompileSummary, + BoardsConfig, + PortIdentifier, + resolveDetectedPort, +} from '../../common/protocol'; +import { + toApiBoardDetails, + toApiCompileSummary, + toApiPort, +} from '../../common/protocol/arduino-context-mapper'; +import { BoardsDataStore } from '../boards/boards-data-store'; +import { BoardsServiceProvider } from '../boards/boards-service-provider'; +import { CurrentSketch } from '../sketches-service-client-impl'; +import { SketchContribution } from './contribution'; + +/** + * (non-API) exported for tests + */ +export interface UpdateStateParams { + readonly key: keyof T; + readonly value: T[keyof T]; +} + +/** + * Contribution for updating the Arduino state, such as the FQBN, selected port, and sketch path changes via commands, so other VS Code extensions can access it. + * See [`vscode-arduino-api`](https://github.com/dankeboy36/vscode-arduino-api#api) for more details. + */ +@injectable() +export class UpdateArduinoState extends SketchContribution { + @inject(BoardsService) + private readonly boardsService: BoardsService; + @inject(BoardsServiceProvider) + private readonly boardsServiceProvider: BoardsServiceProvider; + @inject(BoardsDataStore) + private readonly boardsDataStore: BoardsDataStore; + @inject(HostedPluginSupport) + private readonly hostedPluginSupport: HostedPluginSupport; + + private readonly toDispose = new DisposableCollection(); + + override onStart(): void { + this.toDispose.pushAll([ + this.boardsServiceProvider.onBoardsConfigDidChange(() => + this.updateBoardsConfig(this.boardsServiceProvider.boardsConfig) + ), + this.sketchServiceClient.onCurrentSketchDidChange((sketch) => + this.updateSketchPath(sketch) + ), + this.configService.onDidChangeDataDirUri((dataDirUri) => + this.updateDataDirPath(dataDirUri) + ), + this.configService.onDidChangeSketchDirUri((userDirUri) => + this.updateUserDirPath(userDirUri) + ), + this.commandService.onDidExecuteCommand(({ commandId, args }) => { + if ( + commandId === 'arduino.languageserver.notifyBuildDidComplete' && + isCompileSummary(args[0]) + ) { + this.updateCompileSummary(args[0]); + } + }), + this.boardsDataStore.onDidChange((event) => { + const selectedFqbn = + this.boardsServiceProvider.boardsConfig.selectedBoard?.fqbn; + if ( + selectedFqbn && + event.changes.find((change) => change.fqbn === selectedFqbn) + ) { + this.updateBoardDetails(selectedFqbn); + } + }), + ]); + } + + override onReady(): void { + this.boardsServiceProvider.ready.then(() => { + this.updateBoardsConfig(this.boardsServiceProvider.boardsConfig); + }); + this.updateSketchPath(this.sketchServiceClient.tryGetCurrentSketch()); + this.updateUserDirPath(this.configService.tryGetSketchDirUri()); + this.updateDataDirPath(this.configService.tryGetDataDirUri()); + } + + onStop(): void { + this.toDispose.dispose(); + } + + private async updateSketchPath( + sketch: CurrentSketch | undefined + ): Promise { + const sketchPath = CurrentSketch.isValid(sketch) + ? new URI(sketch.uri).path.fsPath() + : undefined; + return this.updateState({ key: 'sketchPath', value: sketchPath }); + } + + private async updateCompileSummary( + compileSummary: CompileSummary + ): Promise { + const apiCompileSummary = toApiCompileSummary(compileSummary); + return this.updateState({ + key: 'compileSummary', + value: apiCompileSummary, + }); + } + + private async updateBoardsConfig(boardsConfig: BoardsConfig): Promise { + const fqbn = boardsConfig.selectedBoard?.fqbn; + const port = boardsConfig.selectedPort; + await this.updateFqbn(fqbn); + await this.updateBoardDetails(fqbn); + await this.updatePort(port); + } + + private async updateFqbn(fqbn: string | undefined): Promise { + await this.updateState({ key: 'fqbn', value: fqbn }); + } + + private async updateBoardDetails(fqbn: string | undefined): Promise { + const unset = () => + this.updateState({ key: 'boardDetails', value: undefined }); + if (!fqbn) { + return unset(); + } + const [details, persistedData] = await Promise.all([ + this.boardsService.getBoardDetails({ fqbn }), + this.boardsDataStore.getData(fqbn), + ]); + if (!details) { + return unset(); + } + const apiBoardDetails = toApiBoardDetails({ + ...details, + configOptions: + BoardsDataStore.Data.EMPTY === persistedData + ? details.configOptions + : persistedData.configOptions.slice(), + }); + return this.updateState({ + key: 'boardDetails', + value: apiBoardDetails, + }); + } + + private async updatePort(port: PortIdentifier | undefined): Promise { + const resolvedPort = + port && + resolveDetectedPort(port, this.boardsServiceProvider.detectedPorts); + const apiPort = resolvedPort && toApiPort(resolvedPort); + return this.updateState({ key: 'port', value: apiPort }); + } + + private async updateUserDirPath(userDirUri: URI | undefined): Promise { + const userDirPath = userDirUri?.path.fsPath(); + return this.updateState({ + key: 'userDirPath', + value: userDirPath, + }); + } + + private async updateDataDirPath(dataDirUri: URI | undefined): Promise { + const dataDirPath = dataDirUri?.path.fsPath(); + return this.updateState({ + key: 'dataDirPath', + value: dataDirPath, + }); + } + + private async updateState( + params: UpdateStateParams + ): Promise { + await this.hostedPluginSupport.didStart; + return this.commandService.executeCommand('arduinoAPI.updateState', params); + } +} diff --git a/arduino-ide-extension/src/browser/contributions/update-indexes.ts b/arduino-ide-extension/src/browser/contributions/update-indexes.ts new file mode 100644 index 000000000..aeab133ad --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/update-indexes.ts @@ -0,0 +1,193 @@ +import { LocalStorageService } from '@theia/core/lib/browser/storage-service'; +import { nls } from '@theia/core/lib/common/nls'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { CoreService, IndexType, ResponseService } from '../../common/protocol'; +import { NotificationCenter } from '../notification-center'; +import { WindowServiceExt } from '../theia/core/window-service-ext'; +import { Command, CommandRegistry, Contribution } from './contribution'; + +@injectable() +export class UpdateIndexes extends Contribution { + @inject(WindowServiceExt) + private readonly windowService: WindowServiceExt; + @inject(LocalStorageService) + private readonly localStorage: LocalStorageService; + @inject(CoreService) + private readonly coreService: CoreService; + @inject(NotificationCenter) + private readonly notificationCenter: NotificationCenter; + @inject(ResponseService) + private readonly responseService: ResponseService; + + protected override init(): void { + super.init(); + this.notificationCenter.onIndexUpdateDidComplete(({ summary }) => + Promise.all( + Object.entries(summary).map(([type, updatedAt]) => + this.setLastUpdateDateTime(type as IndexType, updatedAt) + ) + ) + ); + } + + override onReady(): void { + this.checkForUpdates(); + } + + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(UpdateIndexes.Commands.UPDATE_INDEXES, { + execute: () => this.updateIndexes(IndexType.All, true), + }); + registry.registerCommand(UpdateIndexes.Commands.UPDATE_PLATFORM_INDEX, { + execute: () => this.updateIndexes(['platform'], true), + }); + registry.registerCommand(UpdateIndexes.Commands.UPDATE_LIBRARY_INDEX, { + execute: () => this.updateIndexes(['library'], true), + }); + } + + private async checkForUpdates(): Promise { + const checkForUpdates = this.preferences['arduino.checkForUpdates']; + if (!checkForUpdates) { + console.debug( + '[update-indexes]: `arduino.checkForUpdates` is `false`. Skipping updating the indexes.' + ); + return; + } + + if (await this.windowService.isFirstWindow()) { + const summary = await this.coreService.indexUpdateSummaryBeforeInit(); + if (summary.message) { + // this.messageService.error(summary.message); + const chunk = `${summary.message}`; + this.responseService.appendToOutput({ chunk }); + } + const typesToCheck = IndexType.All.filter((type) => !(type in summary)); + if (Object.keys(summary).length) { + console.debug( + `[update-indexes]: 在核心gRPC客户端初始化之前检测到索引更新摘要。更新本地存储 ${JSON.stringify( + summary + )}` + ); + } else { + console.debug( + '[update-indexes]: No index update summary was available before the core gRPC client initialization. Checking the status of the all the index types.' + ); + } + await Promise.allSettled([ + ...Object.entries(summary).map(([type, updatedAt]) => + this.setLastUpdateDateTime(type as IndexType, updatedAt) + ), + this.updateIndexes(typesToCheck), + ]); + } + } + + public async updateIndexes(types: IndexType[], force = false): Promise { + const updatedAt = new Date().toISOString(); + return Promise.all( + types.map((type) => this.needsIndexUpdate(type, updatedAt, force)) + ).then((needsIndexUpdateResults) => { + const typesToUpdate = needsIndexUpdateResults.filter(IndexType.is); + if (typesToUpdate.length) { + console.debug( + `[update-indexes]: Requesting the index update of type: ${JSON.stringify( + typesToUpdate + )} with date time: ${updatedAt}.` + ); + return this.coreService.updateIndex({ types: typesToUpdate }); + } + }); + } + + private async needsIndexUpdate( + type: IndexType, + now: string, + force = false + ): Promise { + if (force) { + console.debug( + `[update-indexes]: Update for index type: '${type}' was forcefully requested.` + ); + return type; + } + const lastUpdateIsoDateTime = await this.getLastUpdateDateTime(type); + if (!lastUpdateIsoDateTime) { + console.debug( + `[update-indexes]: No last update date time was persisted for index type: '${type}'. Index update is required.` + ); + return type; + } + const lastUpdateDateTime = Date.parse(lastUpdateIsoDateTime); + if (Number.isNaN(lastUpdateDateTime)) { + console.debug( + `[update-indexes]: Invalid last update date time was persisted for index type: '${type}'. Last update date time was: ${lastUpdateDateTime}. Index update is required.` + ); + return type; + } + const diff = new Date(now).getTime() - lastUpdateDateTime; + const needsIndexUpdate = diff >= this.threshold; + console.debug( + `[update-indexes]: Update for index type '${type}' is ${needsIndexUpdate ? '' : 'not ' + }required. Now: ${now}, Last index update date time: ${new Date( + lastUpdateDateTime + ).toISOString()}, diff: ${diff} ms, threshold: ${this.threshold} ms.` + ); + return needsIndexUpdate ? type : false; + } + + private async getLastUpdateDateTime( + type: IndexType + ): Promise { + const key = this.storageKeyOf(type); + return this.localStorage.getData(key); + } + + private async setLastUpdateDateTime( + type: IndexType, + updatedAt: string + ): Promise { + const key = this.storageKeyOf(type); + return this.localStorage.setData(key, updatedAt).finally(() => { + console.debug( + `[update-indexes]: Updated the last index update date time of '${type}' to ${updatedAt}.` + ); + }); + } + + private storageKeyOf(type: IndexType): string { + return `index-last-update-time--${type}`; + } + + private get threshold(): number { + return 4 * 60 * 60 * 1_000; // four hours in millis + } +} +export namespace UpdateIndexes { + export namespace Commands { + export const UPDATE_INDEXES: Command & { label: string } = { + id: 'lingzhi-update-indexes', + label: nls.localize( + 'arduino/updateIndexes/updateIndexes', + 'Update Indexes' + ), + category: 'LingZhi', + }; + export const UPDATE_PLATFORM_INDEX: Command & { label: string } = { + id: 'lingzhi-update-package-index', + label: nls.localize( + 'arduino/updateIndexes/updatePackageIndex', + 'Update Package Index' + ), + category: 'LingZhi', + }; + export const UPDATE_LIBRARY_INDEX: Command & { label: string } = { + id: 'lingzhi-update-library-index', + label: nls.localize( + 'arduino/updateIndexes/updateLibraryIndex', + 'Update Library Index' + ), + category: 'LingZhi', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/upload-certificate.ts b/arduino-ide-extension/src/browser/contributions/upload-certificate.ts new file mode 100644 index 000000000..e6c2f03b7 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/upload-certificate.ts @@ -0,0 +1,139 @@ +import { inject, injectable } from '@theia/core/shared/inversify'; +import { + Command, + MenuModelRegistry, + CommandRegistry, + Contribution, +} from './contribution'; +import { ArduinoMenus } from '../menu/arduino-menus'; +import { UploadCertificateDialog } from '../dialogs/certificate-uploader/certificate-uploader-dialog'; +import { ContextMenuRenderer } from '@theia/core/lib/browser/context-menu-renderer'; +import { + PreferenceScope, + PreferenceService, +} from '@theia/core/lib/browser/preferences/preference-service'; +import { + arduinoCert, + certificateList, +} from '../dialogs/certificate-uploader/utils'; +import { + ArduinoFirmwareUploader, + UploadCertificateParams, +} from '../../common/protocol/arduino-firmware-uploader'; + +@injectable() +export class UploadCertificate extends Contribution { + @inject(UploadCertificateDialog) + protected readonly dialog: UploadCertificateDialog; + + @inject(ContextMenuRenderer) + protected readonly contextMenuRenderer: ContextMenuRenderer; + + @inject(PreferenceService) + protected readonly preferenceService: PreferenceService; + + @inject(ArduinoFirmwareUploader) + protected readonly arduinoFirmwareUploader: ArduinoFirmwareUploader; + + protected dialogOpened = false; + + override onStart(): void { + this.preferences.onPreferenceChanged(({ preferenceName }) => { + if (preferenceName === 'arduino.board.certificates') { + this.menuManager.update(); + } + }); + } + + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(UploadCertificate.Commands.OPEN, { + execute: async () => { + try { + this.dialogOpened = true; + this.menuManager.update(); + await this.dialog.open(); + } finally { + this.dialogOpened = false; + this.menuManager.update(); + } + }, + isEnabled: () => !this.dialogOpened, + }); + + registry.registerCommand(UploadCertificate.Commands.REMOVE_CERT, { + execute: async (certToRemove) => { + const certs = this.preferences.get('arduino.board.certificates'); + + this.preferenceService.set( + 'arduino.board.certificates', + certificateList(certs) + .filter((c) => c !== certToRemove) + .join(','), + PreferenceScope.User + ); + }, + isEnabled: (certToRemove) => certToRemove !== arduinoCert, + }); + + registry.registerCommand(UploadCertificate.Commands.UPLOAD_CERT, { + execute: async (params: UploadCertificateParams) => { + return this.arduinoFirmwareUploader.uploadCertificates(params); + }, + }); + + registry.registerCommand(UploadCertificate.Commands.OPEN_CERT_CONTEXT, { + execute: async (args: any) => { + this.contextMenuRenderer.render({ + menuPath: ArduinoMenus.ROOT_CERTIFICATES__CONTEXT, + anchor: { + x: args.x, + y: args.y, + }, + args: [args.cert], + }); + }, + }); + } + + override registerMenus(registry: MenuModelRegistry): void { + // registry.registerMenuAction(ArduinoMenus.TOOLS__FIRMWARE_UPLOADER_GROUP, { + // commandId: UploadCertificate.Commands.OPEN.id, + // label: UploadCertificate.Commands.OPEN.label, + // order: '1', + // }); + + registry.registerMenuAction(ArduinoMenus.ROOT_CERTIFICATES__CONTEXT, { + commandId: UploadCertificate.Commands.REMOVE_CERT.id, + label: UploadCertificate.Commands.REMOVE_CERT.label, + order: '1', + }); + } +} + +export namespace UploadCertificate { + export namespace Commands { + export const OPEN: Command = { + id: 'arduino-upload-certificate-open', + label: '上传 SSL 根证书', + category: 'LingZhi', + }; + + export const OPEN_CERT_CONTEXT: Command = { + id: 'arduino-certificate-open-context', + label: '打开上下文', + category: 'LingZhi', + }; + + export const REMOVE_CERT: Command = { + id: 'arduino-certificate-remove', + label: '移除', + category: 'LingZhi', + }; + + export const UPLOAD_CERT: Command = { + id: 'arduino-certificate-upload', + label: '上传', + category: 'LingZhi', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/upload-firmware.ts b/arduino-ide-extension/src/browser/contributions/upload-firmware.ts new file mode 100644 index 000000000..af6cf8f61 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/upload-firmware.ts @@ -0,0 +1,45 @@ +import { inject, injectable } from '@theia/core/shared/inversify'; +import { Command, CommandRegistry, Contribution } from './contribution'; +import { UploadFirmwareDialog } from '../dialogs/firmware-uploader/firmware-uploader-dialog'; + +@injectable() +export class UploadFirmware extends Contribution { + @inject(UploadFirmwareDialog) + protected readonly dialog: UploadFirmwareDialog; + + protected dialogOpened = false; + + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(UploadFirmware.Commands.OPEN, { + execute: async () => { + try { + this.dialogOpened = true; + this.menuManager.update(); + await this.dialog.open(); + } finally { + this.dialogOpened = false; + this.menuManager.update(); + } + }, + isEnabled: () => !this.dialogOpened, + }); + } + + // override registerMenus(registry: MenuModelRegistry): void { + // registry.registerMenuAction(ArduinoMenus.TOOLS__FIRMWARE_UPLOADER_GROUP, { + // commandId: UploadFirmware.Commands.OPEN.id, + // label: UploadFirmware.Commands.OPEN.label, + // order: '0', + // }); + // } +} + +export namespace UploadFirmware { + export namespace Commands { + export const OPEN: Command = { + id: 'arduino-upload-firmware-open', + label: '固件更新', + category: 'LingZhi', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/upload-sketch.ts b/arduino-ide-extension/src/browser/contributions/upload-sketch.ts new file mode 100644 index 000000000..0b14e429a --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/upload-sketch.ts @@ -0,0 +1,310 @@ +import { Emitter } from '@theia/core/lib/common/event'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { + CoreService, + MonitorManagerProxyClient, + Port, + ResponseService, + sanitizeFqbn, +} from '../../common/protocol'; +import { ArduinoMenus } from '../menu/arduino-menus'; +import { CurrentSketch } from '../sketches-service-client-impl'; +import { ArduinoToolbar } from '../toolbar/arduino-toolbar'; +import { + Command, + CommandRegistry, + CoreServiceContribution, + KeybindingRegistry, + MenuModelRegistry, + TabBarToolbarRegistry, +} from './contribution'; +import { UserFields } from './user-fields'; +import type { VerifySketchParams } from './verify-sketch'; +import { SidebarMenu } from '@theia/core/lib/browser/shell/sidebar-menu-widget'; +import { FrontendApplication } from '@theia/core/lib/browser/frontend-application'; +import { CreateFeatures } from '../create/create-features'; +import { ApplicationShell } from '@theia/core/lib/browser'; +import { MonitorWidget } from '../serial/monitor/monitor-widget'; + +export const uploadMenu: SidebarMenu = { + id: 'lingzhi-upload-sketch', + iconClass: 'fa lingzhi-upload', + title: '上传', + menuPath: ArduinoMenus.UPLOAD_SKETCH, + order: 1, +}; + +@injectable() +export class UploadSketch extends CoreServiceContribution { + @inject(UserFields) + private readonly userFields: UserFields; + @inject(ApplicationShell) + private readonly applicationShell: ApplicationShell; + @inject(MonitorManagerProxyClient) + private readonly monitorManagerProxy: MonitorManagerProxyClient; + @inject(CoreService) + private readonly coreService1: CoreService; + @inject(ResponseService) + private readonly responseService1: ResponseService; + + private readonly onDidChangeEmitter = new Emitter(); + private readonly onDidChange = this.onDidChangeEmitter.event; + private uploadInProgress = false; + + @inject(CreateFeatures) + private app: FrontendApplication; + override onStart(app: FrontendApplication): void { + this.app = app; + + // 在 onStart 方法中添加新菜单 + const handler = this.app.shell.leftPanelHandler; + handler.addBottomMenu(uploadMenu); + } + + override registerCommands(registry: CommandRegistry): void { + // 注册一个命令,命令名为UPLOAD_SKETCH + registry.registerCommand(UploadSketch.Commands.UPLOAD_SKETCH, { + // 执行命令的方法 + execute: async () => { + // 检查用户字段对话框 + if (await this.userFields.checkUserFieldsDialog()) { + // 上传草图 + this.uploadSketch(); + } + }, + // 判断命令是否可用的方法 + isEnabled: () => !this.uploadInProgress, + }); + registry.registerCommand(UploadSketch.Commands.UPLOAD_WITH_CONFIGURATION, { + execute: async () => { + if (await this.userFields.checkUserFieldsDialog(true)) { + this.uploadSketch(); + } + }, + isEnabled: () => !this.uploadInProgress && this.userFields.isRequired(), + }); + registry.registerCommand( + UploadSketch.Commands.UPLOAD_SKETCH_USING_PROGRAMMER, + { + execute: () => this.uploadSketch(true), + isEnabled: () => !this.uploadInProgress, + } + ); + registry.registerCommand(UploadSketch.Commands.UPLOAD_SKETCH_TOOLBAR, { + isVisible: (widget, showToolbar: boolean) => + showToolbar && ArduinoToolbar.is(widget) && widget.side === 'left', + isEnabled: () => !this.uploadInProgress, + isToggled: () => this.uploadInProgress, + execute: () => + registry.executeCommand(UploadSketch.Commands.UPLOAD_SKETCH.id), + }); + } + + override registerMenus(registry: MenuModelRegistry): void { + // registry.registerMenuAction(ArduinoMenus.SKETCH__MAIN_GROUP, { + // commandId: UploadSketch.Commands.UPLOAD_SKETCH.id, + // label: nls.localize('arduino/sketch/upload', 'Upload'), + // order: '1', + // }); + + registry.registerMenuAction(ArduinoMenus.UPLOAD_SKETCH, { + commandId: UploadSketch.Commands.UPLOAD_SKETCH.id, + label: '上传', + order: '1', + }); + + registry.registerMenuAction(ArduinoMenus.SKETCH__MAIN_GROUP, { + commandId: UploadSketch.Commands.UPLOAD_SKETCH_USING_PROGRAMMER.id, + label: '使用编程器上传', + order: '2', + }); + } + + override registerKeybindings(registry: KeybindingRegistry): void { + registry.registerKeybinding({ + command: UploadSketch.Commands.UPLOAD_SKETCH.id, + keybinding: 'CtrlCmd+U', + }); + registry.registerKeybinding({ + command: UploadSketch.Commands.UPLOAD_SKETCH_USING_PROGRAMMER.id, + keybinding: 'CtrlCmd+Shift+U', + }); + } + + override registerToolbarItems(registry: TabBarToolbarRegistry): void { + registry.registerItem({ + id: UploadSketch.Commands.UPLOAD_SKETCH_TOOLBAR.id, + command: UploadSketch.Commands.UPLOAD_SKETCH_TOOLBAR.id, + tooltip: '上传', + priority: 1, + onDidChange: this.onDidChange, + }); + } + + async uploadSketch(usingProgrammer = false): Promise { + if (this.uploadInProgress) { + return; + } + + try { + // toggle the toolbar button and menu item state. + // uploadInProgress will be set to false whether the upload fails or not + // 设置上传状态为正在进行 + this.uploadInProgress = true; + // 更新菜单管理器 + this.menuManager.update(); + // 触发onDidChangeEmitter事件 + this.onDidChangeEmitter.fire(); + // 清除可见的通知 + this.clearVisibleNotification(); + + // this.boardsServiceProvider.onBoardListDidChange((boardList) => { + // const { selectedBoard } = boardList.boardsConfig; + // if (selectedBoard) { + // const chunk = '\n未连接开发板\n'; + // this.responseService1.appendToOutput({ chunk }); + // } + // }); + + const boardList = this.boardsServiceProvider.boardList; + + const groupedPorts = boardList.portsGroupedByProtocol(); + + const { selectedBoard } = boardList.boardsConfig; + if (!selectedBoard) { + const chunk = '\n未选择开发板!\n'; + const severity = 0; + this.responseService1.appendToOutput({ chunk, severity }); + return; + } + + let newPort: Port | undefined = undefined; + Object.entries(groupedPorts).forEach(([protocol, ports]) => { + const { port } = ports[0]; + newPort = port; + }); + + if (!newPort) { + const chunk = '\n未连接开发板!\n'; + const severity = 0; + this.responseService1.appendToOutput({ chunk, severity }); + return; + } + + // 调用命令服务执行命令,获取编译选项 + // 执行命令,获取编译选项 + const verifyOptions = + await this.commandService.executeCommand( + 'lingzhi-verify-sketch', + { + // 不导出二进制文件 + exportBinaries: false, + // 静默模式 + silent: true, + } + ); + // 如果没有获取到编译选项,则返回 + if (!verifyOptions) { + return; + } + + // 调用uploadOptions方法,获取上传选项 + const uploadOptions = await this.uploadOptions( + usingProgrammer, + verifyOptions + ); + // 如果没有获取到上传选项,则返回 + if (!uploadOptions) { + return; + } + + // 检查用户字段是否满足上传条件 + if (!this.userFields.checkUserFieldsForUpload()) { + return; + } + + let wiget = this.applicationShell.getWidgetById(MonitorWidget.ID); + if (wiget !== undefined) { + wiget.close(); + } + //关闭串口绘图仪 + await this.monitorManagerProxy.stopLastMonitor(); + + // 调用doWithProgress方法,执行上传操作 + // const uploadResponse = await this.doWithProgress({ + // progressText: nls.localize('arduino/sketch/uploading', 'Uploading...'), + // task: (progressId, coreService) => + // coreService.upload({ ...uploadOptions, progressId }), + // keepOutput: true, + // }); + // this.responseServiceClient.clearOutput(); + await this.coreService1.upload({ ...uploadOptions }); + // the port update is NOOP if nothing has changed + // this.boardsServiceProvider.updateConfig(uploadResponse.portAfterUpload); + + // this.messageService.info( + // nls.localize('arduino/sketch/doneUploading', '完成上传.'), + // { timeout: 3000 } + // ); + const chunk = '\n完成上传.\n'; + this.responseService1.appendToOutput({ chunk }); + } catch (e) { + this.userFields.notifyFailedWithError(e); + this.handleError(e); + } finally { + // TODO: here comes the port change if happened during the upload + // https://github.com/arduino/arduino-cli/issues/2245 + this.uploadInProgress = false; + this.menuManager.update(); + this.onDidChangeEmitter.fire(); + } + } + + private async uploadOptions( + usingProgrammer: boolean, + verifyOptions: CoreService.Options.Compile + ): Promise { + const sketch = await this.sketchServiceClient.currentSketch(); + if (!CurrentSketch.isValid(sketch)) { + return undefined; + } + const userFields = this.userFields.getUserFields(); + const { boardsConfig } = this.boardsServiceProvider; + const [fqbn, { selectedProgrammer: programmer }, verify, verbose] = + await Promise.all([ + verifyOptions.fqbn, // already decorated FQBN + this.boardsDataStore.getData(sanitizeFqbn(verifyOptions.fqbn)), + this.preferences.get('arduino.upload.verify'), + this.preferences.get('arduino.upload.verbose'), + ]); + const port = boardsConfig.selectedPort; + return { + sketch, + fqbn, + ...(usingProgrammer && { programmer }), + port, + verbose, + verify, + userFields, + }; + } +} + +export namespace UploadSketch { + export namespace Commands { + export const UPLOAD_SKETCH: Command = { + id: 'lingzhi-upload-sketch', + }; + export const UPLOAD_WITH_CONFIGURATION: Command & { label: string } = { + id: 'arduino-upload-with-configuration-sketch', + label: '配置并上传', + category: 'LingZhi', + }; + export const UPLOAD_SKETCH_USING_PROGRAMMER: Command = { + id: 'lingzhi-upload-sketch-using-programmer', + }; + export const UPLOAD_SKETCH_TOOLBAR: Command = { + id: 'lingzhi-upload-sketch--toolbar', + }; + } +} diff --git a/arduino-ide-extension/src/browser/contributions/user-fields.ts b/arduino-ide-extension/src/browser/contributions/user-fields.ts new file mode 100644 index 000000000..4f7f5f500 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/user-fields.ts @@ -0,0 +1,137 @@ +import { inject, injectable } from '@theia/core/shared/inversify'; +import { + BoardUserField, + CoreError, + ResponseService, +} from '../../common/protocol'; +import { BoardsServiceProvider } from '../boards/boards-service-provider'; +import { UserFieldsDialog } from '../dialogs/user-fields/user-fields-dialog'; +import { ArduinoMenus } from '../menu/arduino-menus'; +import { Contribution, MenuModelRegistry } from './contribution'; +import { UploadSketch } from './upload-sketch'; + +@injectable() +export class UserFields extends Contribution { + private boardRequiresUserFields = false; + private userFieldsSet = false; + private readonly cachedUserFields: Map = new Map(); + + @inject(UserFieldsDialog) + private readonly userFieldsDialog: UserFieldsDialog; + + @inject(BoardsServiceProvider) + private readonly boardsServiceProvider: BoardsServiceProvider; + + @inject(ResponseService) + private readonly responseService: ResponseService; + + protected override init(): void { + super.init(); + this.boardsServiceProvider.onBoardsConfigDidChange(() => this.refresh()); + } + + override onReady(): void { + this.boardsServiceProvider.ready.then(() => this.refresh()); + } + + override registerMenus(registry: MenuModelRegistry): void { + registry.registerMenuAction(ArduinoMenus.SKETCH__MAIN_GROUP, { + commandId: UploadSketch.Commands.UPLOAD_WITH_CONFIGURATION.id, + label: UploadSketch.Commands.UPLOAD_WITH_CONFIGURATION.label, + order: '3', + }); + } + + private async refresh(): Promise { + const userFields = + await this.boardsServiceProvider.selectedBoardUserFields(); + this.boardRequiresUserFields = userFields.length > 0; + this.menuManager.update(); + } + + private selectedFqbnAddress(): string | undefined { + const { boardsConfig } = this.boardsServiceProvider; + const fqbn = boardsConfig.selectedBoard?.fqbn; + if (!fqbn) { + return undefined; + } + const address = boardsConfig.selectedPort?.address || ''; + return fqbn + '|' + address; + } + + private async showUserFieldsDialog( + key: string + ): Promise { + const cached = this.cachedUserFields.get(key); + // Deep clone the array of board fields to avoid editing the cached ones + this.userFieldsDialog.value = cached + ? cached.slice() + : await this.boardsServiceProvider.selectedBoardUserFields(); + const result = await this.userFieldsDialog.open(); + if (!result) { + return; + } + + this.userFieldsSet = true; + this.cachedUserFields.set(key, result); + return result; + } + + async checkUserFieldsDialog(forceOpen = false): Promise { + const key = this.selectedFqbnAddress(); + if (!key) { + return false; + } + /* + If the board requires to be configured with user fields, we want + to show the user fields dialog, but only if they weren't already + filled in or if they were filled in, but the previous upload failed. + */ + if ( + !forceOpen && + (!this.boardRequiresUserFields || + (this.cachedUserFields.has(key) && this.userFieldsSet)) + ) { + return true; + } + const userFieldsFilledIn = Boolean(await this.showUserFieldsDialog(key)); + return userFieldsFilledIn; + } + + checkUserFieldsForUpload(): boolean { + // TODO: This does not belong here. + // IDE2 should not do any preliminary checks but let the CLI fail and then toast a user consumable error message. + if (!this.boardRequiresUserFields || this.getUserFields().length > 0) { + this.userFieldsSet = true; + return true; + } + // this.messageService.error( + // nls.localize( + // 'arduino/sketch/userFieldsNotFoundError', + // '找不到连接板的用户字段' + // ) + // ); + const chunk = '找不到已连接开发板的用户字段\n'; + this.responseService.appendToOutput({ chunk }); + this.userFieldsSet = false; + return false; + } + + getUserFields(): BoardUserField[] { + const fqbnAddress = this.selectedFqbnAddress(); + if (!fqbnAddress) { + return []; + } + return this.cachedUserFields.get(fqbnAddress) ?? []; + } + + isRequired(): boolean { + return this.boardRequiresUserFields; + } + + notifyFailedWithError(e: Error): void { + if (this.boardRequiresUserFields && CoreError.UploadFailed.is(e)) { + this.userFieldsSet = false; + } + } +} diff --git a/arduino-ide-extension/src/browser/contributions/validate-sketch.ts b/arduino-ide-extension/src/browser/contributions/validate-sketch.ts new file mode 100644 index 000000000..869e13ab2 --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/validate-sketch.ts @@ -0,0 +1,177 @@ +import { Deferred, waitForEvent } from '@theia/core/lib/common/promise-util'; +import { injectable } from '@theia/core/shared/inversify'; +import { WorkspaceCommands } from '@theia/workspace/lib/browser/workspace-commands'; +import { CurrentSketch } from '../sketches-service-client-impl'; +import { CloudSketchContribution } from './cloud-contribution'; +import { Sketch, URI } from './contribution'; +import { SaveAsSketch } from './save-as-sketch'; +import { Dialog } from '../theia/dialogs/theiaDialogs/dialogs'; + +@injectable() +export class ValidateSketch extends CloudSketchContribution { + override onReady(): void { + this.validate(); + } + + private async validate(): Promise { + const result = await this.promptFixActions(); + if (!result) { + const yes = await this.prompt( + '无效的草图', + `草图仍然无效。你想解决剩下的问题吗?点击“${Dialog.NO}”,将打开一个新的草图。`, + [Dialog.NO, Dialog.YES] + ); + if (yes) { + return this.validate(); + } + const sketch = await this.sketchesService.createNewSketch(); + this.workspaceService.open(new URI(sketch.uri), { + preserveWindow: true, + }); + } + } + + /** + * Returns with an array of actions the user has to perform to fix the invalid sketch. + */ + private validateSketch( + sketch: Sketch, + dataDirUri: URI | undefined + ): FixAction[] { + // sketch code file validation errors first as they do not require window reload + const actions = Sketch.uris(sketch) + .filter((uri) => uri !== sketch.mainFileUri) + .map((uri) => new URI(uri)) + .filter((uri) => Sketch.Extensions.CODE_FILES.includes(uri.path.ext)) + .map((uri) => ({ + uri, + error: this.doValidate(sketch, dataDirUri, uri.path.name), + })) + .filter(({ error }) => Boolean(error)) + .map((object) => <{ uri: URI; error: string }>object) + .map(({ uri, error }) => ({ + execute: async () => { + const unknown = + (await this.promptRenameSketchFile(uri, error)) && + (await this.commandService.executeCommand( + WorkspaceCommands.FILE_RENAME.id, + uri + )); + return !!unknown; + }, + })); + + // sketch folder + main sketch file last as it requires a `Save as...` and the window reload + const sketchFolderName = new URI(sketch.uri).path.base; + const sketchFolderNameError = this.doValidate( + sketch, + dataDirUri, + sketchFolderName + ); + if (sketchFolderNameError) { + actions.push({ + execute: async () => { + const unknown = + (await this.promptRenameSketch(sketch, sketchFolderNameError)) && + (await this.commandService.executeCommand( + SaveAsSketch.Commands.SAVE_AS_SKETCH.id, + { + markAsRecentlyOpened: true, + openAfterMove: true, + wipeOriginal: true, + } + )); + return !!unknown; + }, + }); + } + return actions; + } + + private doValidate( + sketch: Sketch, + dataDirUri: URI | undefined, + toValidate: string + ): string | undefined { + const cloudUri = this.createFeatures.isCloud(sketch, dataDirUri); + return cloudUri + ? Sketch.validateCloudSketchFolderName(toValidate) + : Sketch.validateSketchFolderName(toValidate); + } + + private async currentSketch(): Promise { + const sketch = this.sketchServiceClient.tryGetCurrentSketch(); + if (CurrentSketch.isValid(sketch)) { + return sketch; + } + const deferred = new Deferred(); + const disposable = this.sketchServiceClient.onCurrentSketchDidChange( + (sketch) => { + if (CurrentSketch.isValid(sketch)) { + disposable.dispose(); + deferred.resolve(sketch); + } + } + ); + return deferred.promise; + } + + private async promptFixActions(): Promise { + const maybeDataDirUri = this.configService.tryGetDataDirUri(); + const [sketch, dataDirUri] = await Promise.all([ + this.currentSketch(), + maybeDataDirUri ?? + waitForEvent(this.configService.onDidChangeDataDirUri, 5_000), + ]); + const fixActions = this.validateSketch(sketch, dataDirUri); + for (const fixAction of fixActions) { + const result = await fixAction.execute(); + if (!result) { + return false; + } + } + return true; + } + + private async promptRenameSketch( + sketch: Sketch, + error: string + ): Promise { + return this.prompt( + `无效的草图名称`, + `草图“${sketch.name}”不能使用。${error}要删除此消息,请重命名草图。现在要重命名草图吗?` + ); + } + + private async promptRenameSketchFile( + uri: URI, + error: string + ): Promise { + return this.prompt( + '无效的草图文件名', + `不能使用草图文件‘${uri.path.base}’。${error}现在要重命名草图文件吗?` + ); + } + + private async prompt( + title: string, + message: string, + buttons: string[] = [Dialog.CANCEL, Dialog.OK] + ): Promise { + const { response } = await this.dialogService.showMessageBox({ + title, + message, + type: 'warning', + buttons, + }); + // cancel + if (response === 0) { + return false; + } + return true; + } +} + +interface FixAction { + execute(): Promise; +} diff --git a/arduino-ide-extension/src/browser/contributions/verify-sketch.ts b/arduino-ide-extension/src/browser/contributions/verify-sketch.ts new file mode 100644 index 000000000..4f9f1259e --- /dev/null +++ b/arduino-ide-extension/src/browser/contributions/verify-sketch.ts @@ -0,0 +1,247 @@ +import { inject, injectable } from '@theia/core/shared/inversify'; +import { Emitter } from '@theia/core/lib/common/event'; +import { ArduinoMenus } from '../menu/arduino-menus'; +import { ArduinoToolbar } from '../toolbar/arduino-toolbar'; +import { + CoreServiceContribution, + Command, + CommandRegistry, + MenuModelRegistry, + KeybindingRegistry, + TabBarToolbarRegistry, +} from './contribution'; +import { CurrentSketch } from '../sketches-service-client-impl'; +import { + CoreService, + ResponseService, + ResponseServiceClient, +} from '../../common/protocol'; +import { CoreErrorHandler } from './core-error-handler'; +import { SidebarMenu } from '@theia/core/lib/browser/shell/sidebar-menu-widget'; +import { FrontendApplication } from '@theia/core/lib/browser/frontend-application'; +import { CreateFeatures } from '../create/create-features'; + +export interface VerifySketchParams { + /** + * Same as `CoreService.Options.Compile#exportBinaries` + */ + readonly exportBinaries?: boolean; + /** + * If `true`, there won't be any UI indication of the verify command in the toolbar. It's `false` by default. + */ + readonly silent?: boolean; +} + +export const verifyMenu: SidebarMenu = { + id: 'lingzhi-verify-sketch', + iconClass: 'fa lingzhi-build-ok', + title: '验证', + menuPath: ArduinoMenus.SKETCH_COMMAND_ID, + order: 2, +}; + +/** + * - `"idle"` when neither verify, nor upload is running, + * - `"explicit-verify"` when only verify is running triggered by the user, and + * - `"automatic-verify"` is when the automatic verify phase is running as part of an upload triggered by the user. + */ +type VerifyProgress = 'idle' | 'explicit-verify' | 'automatic-verify'; + +@injectable() +export class VerifySketch extends CoreServiceContribution { + @inject(CoreErrorHandler) + private readonly coreErrorHandler: CoreErrorHandler; + @inject(ResponseService) + private readonly responseService1: ResponseService; + @inject(CoreService) + private readonly coreService1: CoreService; + @inject(ResponseServiceClient) + private readonly responseServiceClient: ResponseServiceClient; + + private readonly onDidChangeEmitter = new Emitter(); + private readonly onDidChange = this.onDidChangeEmitter.event; + private verifyProgress: VerifyProgress = 'idle'; + + @inject(CreateFeatures) + private app: FrontendApplication; + override onStart(app: FrontendApplication): void { + this.app = app; + + // 在 onStart 方法中添加新菜单 + const handler = this.app.shell.leftPanelHandler; + handler.addBottomMenu(verifyMenu); + } + + override registerCommands(registry: CommandRegistry): void { + registry.registerCommand(VerifySketch.Commands.VERIFY_SKETCH, { + execute: (params?: VerifySketchParams) => this.verifySketch(params), + isEnabled: () => this.verifyProgress === 'idle', + }); + registry.registerCommand(VerifySketch.Commands.EXPORT_BINARIES, { + execute: () => this.verifySketch({ exportBinaries: true }), + isEnabled: () => this.verifyProgress === 'idle', + }); + registry.registerCommand(VerifySketch.Commands.VERIFY_SKETCH_TOOLBAR, { + isVisible: (widget, showToolbar: boolean) => + showToolbar && ArduinoToolbar.is(widget) && widget.side === 'left', + isEnabled: () => this.verifyProgress !== 'explicit-verify', + // toggled only when verify is running, but not toggled when automatic verify is running before the upload + // https://github.com/arduino/arduino-ide/pull/1750#pullrequestreview-1214762975 + isToggled: () => this.verifyProgress === 'explicit-verify', + execute: () => + registry.executeCommand(VerifySketch.Commands.VERIFY_SKETCH.id), + }); + } + + override registerMenus(registry: MenuModelRegistry): void { + registry.registerMenuAction(ArduinoMenus.SKETCH_COMMAND_ID, { + commandId: verifyMenu.id, + label: verifyMenu.title, + order: '0', + }); + + // registry.registerMenuAction(ArduinoMenus.SKETCH__MAIN_GROUP, { + // commandId: VerifySketch.Commands.VERIFY_SKETCH.id, + // label: nls.localize('arduino/sketch/verify', 'Verify'), + // order: '0', + // }); + + registry.registerMenuAction(ArduinoMenus.SKETCH__MAIN_GROUP, { + commandId: VerifySketch.Commands.EXPORT_BINARIES.id, + label: '导出已编译的二进制文件', + order: '4', + }); + } + + override registerKeybindings(registry: KeybindingRegistry): void { + registry.registerKeybinding({ + command: VerifySketch.Commands.VERIFY_SKETCH.id, + keybinding: 'CtrlCmd+R', + }); + registry.registerKeybinding({ + command: VerifySketch.Commands.EXPORT_BINARIES.id, + keybinding: 'CtrlCmd+Alt+S', + }); + } + + override registerToolbarItems(registry: TabBarToolbarRegistry): void { + registry.registerItem({ + id: VerifySketch.Commands.VERIFY_SKETCH_TOOLBAR.id, + command: VerifySketch.Commands.VERIFY_SKETCH_TOOLBAR.id, + tooltip: '验证', + priority: 0, + onDidChange: this.onDidChange, + }); + } + + protected override handleError(error: unknown): void { + this.coreErrorHandler.tryHandle(error); + super.handleError(error); + } + + private async verifySketch( + params?: VerifySketchParams + ): Promise { + if (this.verifyProgress !== 'idle') { + return undefined; + } + + try { + // 根据params参数的silent属性,设置verifyProgress的值 + this.verifyProgress = params?.silent + ? 'automatic-verify' + : 'explicit-verify'; + // 触发onDidChangeEmitter事件 + this.onDidChangeEmitter.fire(); + // 更新menuManager + this.menuManager.update(); + // 清除可见的通知 + this.clearVisibleNotification(); + // 重置coreErrorHandler + this.coreErrorHandler.reset(); + + // 根据params参数的exportBinaries属性,获取options + const options = await this.options(params?.exportBinaries); + // 如果options为空,则返回undefined + if (!options) { + return undefined; + } + + // 使用doWithProgress方法,执行编译任务 + // await this.doWithProgress({ + // // 设置进度文本 + // progressText: nls.localize( + // 'arduino/sketch/compile', + // 'Compiling sketch...' + // ), + // // 设置任务 + // task: (progressId, coreService) => + // coreService.compile({ + // // 将options和progressId作为参数传递给compile方法 + // ...options, + // progressId, + // }), + // }); + this.responseServiceClient.clearOutput(); + await this.coreService1.compile({ + // 将options和progressId作为参数传递给compile方法 + ...options, + }); + const chunk = '编译完成.\n\n'; + this.responseService1.appendToOutput({ chunk }); + // Returns with the used options for the compilation + // so that follow-up tasks (such as upload) can reuse the compiled code. + // Note that the `fqbn` is already decorated with the board settings, if any. + return options; + } catch (e) { + this.handleError(e); + return undefined; + } finally { + this.verifyProgress = 'idle'; + this.onDidChangeEmitter.fire(); + this.menuManager.update(); + } + } + + private async options( + exportBinaries?: boolean + ): Promise { + const sketch = await this.sketchServiceClient.currentSketch(); + if (!CurrentSketch.isValid(sketch)) { + return undefined; + } + const { boardsConfig } = this.boardsServiceProvider; + const [fqbn, sourceOverride, optimizeForDebug] = await Promise.all([ + this.boardsDataStore.appendConfigToFqbn(boardsConfig.selectedBoard?.fqbn), + this.sourceOverride(), + this.commandService.executeCommand( + 'lingzhi-is-optimize-for-debug' + ), + ]); + const verbose = this.preferences.get('arduino.compile.verbose'); + const compilerWarnings = this.preferences.get('arduino.compile.warnings'); + return { + sketch, + fqbn, + optimizeForDebug: Boolean(optimizeForDebug), + verbose, + exportBinaries, + sourceOverride, + compilerWarnings, + }; + } +} + +export namespace VerifySketch { + export namespace Commands { + export const VERIFY_SKETCH: Command = { + id: 'lingzhi-verify-sketch', + }; + export const EXPORT_BINARIES: Command = { + id: 'lingzhi-export-binaries', + }; + export const VERIFY_SKETCH_TOOLBAR: Command = { + id: 'lingzhi-verify-sketch--toolbar', + }; + } +} diff --git a/arduino-ide-extension/src/browser/create/create-api.ts b/arduino-ide-extension/src/browser/create/create-api.ts new file mode 100644 index 000000000..7f4cfed22 --- /dev/null +++ b/arduino-ide-extension/src/browser/create/create-api.ts @@ -0,0 +1,528 @@ +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 { 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'; +import * as createPaths from './create-paths'; +import { posix } from './create-paths'; +import { Create, CreateError } from './typings'; + +interface ResponseResultProvider { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + (response: Response): Promise; +} +namespace ResponseResultProvider { + export const NOOP: ResponseResultProvider = async () => undefined; + export const TEXT: ResponseResultProvider = (response) => response.text(); + export const JSON: ResponseResultProvider = (response) => response.json(); +} + +type ResourceType = 'f' | 'd'; + +@injectable() +export class CreateApi { + @inject(SketchCache) + readonly sketchCache: SketchCache; + @inject(AuthenticationClientService) + private readonly authenticationService: AuthenticationClientService; + @inject(ArduinoPreferences) + private readonly arduinoPreferences: ArduinoPreferences; + @inject(SketchesService) + private readonly sketchesService: SketchesService; + + getSketchSecretStat(sketch: Create.Sketch): Create.Resource { + return { + href: `${sketch.href}${posix.sep}${Create.arduino_secrets_file}`, + modified_at: sketch.modified_at, + created_at: sketch.created_at, + name: `${Create.arduino_secrets_file}`, + path: `${sketch.path}${posix.sep}${Create.arduino_secrets_file}`, + mimetype: 'text/x-c++src; charset=utf-8', + type: 'file', + }; + } + + async sketch(id: string): Promise { + const url = new URL(`${this.domain()}/sketches/byID/${id}`); + + url.searchParams.set('user_id', 'me'); + const headers = await this.headers(); + const result = await this.run(url, { + method: 'GET', + headers, + }); + 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 { + const url = new URL(`${this.domain()}/sketches/byPath/${sketchPath}`); + const headers = await this.headers(); + const sketch = await this.run(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 { + const url = new URL(`${this.domain()}/sketches`); + url.searchParams.set('user_id', 'me'); + url.searchParams.set('limit', limit.toString()); + const headers = await this.headers(); + const allSketches: Create.Sketch[] = []; + let currentOffset = 0; + while (true) { + url.searchParams.set('offset', currentOffset.toString()); + const { sketches } = await this.run<{ sketches: Create.Sketch[] }>(url, { + method: 'GET', + headers, + }); + allSketches.push(...sketches); + if (sketches.length < limit) { + break; + } + currentOffset += limit; + // The create API doc show that there is `next` and `prev` pages, but it does not work + // https://api2.arduino.cc/create/docs#!/sketches95v2/sketches_v2_search + // IF sketchCount mod limit === 0, an extra fetch must happen to detect the end of the pagination. + } + allSketches.forEach((sketch) => this.sketchCache.addSketch(sketch)); + return allSketches; + } + + async createSketch( + posixPath: string, + contentProvider: MaybePromise = this.sketchesService.defaultInoContent(), + payloadOverride: Record< + string, + string | boolean | number | Record + > = {} + ): Promise { + const url = new URL(`${this.domain()}/sketches`); + const [headers, content] = await Promise.all([ + this.headers(), + contentProvider, + ]); + const payload = { + ino: btoa(content), + path: posixPath, + user_id: 'me', + ...payloadOverride, + }; + const init = { + method: 'PUT', + body: JSON.stringify(payload), + headers, + }; + const result = await this.run(url, init); + return result; + } + + async readDirectory( + posixPath: string, + options: { + recursive?: boolean; + match?: string; + skipSketchCache?: boolean; + } = {} + ): Promise { + const url = new URL( + `${this.domain()}/files/d/$HOME/sketches_v2${posixPath}` + ); + if (options.recursive) { + url.searchParams.set('deep', 'true'); + } + if (options.match) { + url.searchParams.set('name_like', options.match); + } + const headers = await this.headers(); + + const cachedSketch = this.sketchCache.getSketch(posixPath); + + const sketchPromise = options.skipSketchCache + ? (cachedSketch && this.sketch(cachedSketch.id)) || Promise.resolve(null) + : Promise.resolve(this.sketchCache.getSketch(posixPath)); + + return Promise.all([ + sketchPromise, + this.run(url, { + method: 'GET', + headers, + }), + ]) + .then(async ([sketch, result]) => { + if (posixPath.length && posixPath !== posix.sep) { + if (sketch && sketch.secrets && sketch.secrets.length > 0) { + result.push(this.getSketchSecretStat(sketch)); + } + } + + return result.filter( + (res) => !Create.do_not_sync_files.includes(res.name) + ); + }) + .catch((reason) => { + if (reason?.status === 404) + return [] as Create.Resource[]; // TODO: must not swallow 404 + else throw reason; + }); + } + + async createDirectory(posixPath: string): Promise { + const url = new URL( + `${this.domain()}/files/d/$HOME/sketches_v2${posixPath}` + ); + const headers = await this.headers(); + await this.run(url, { + method: 'POST', + headers, + }); + } + + async stat(posixPath: string): Promise { + // The root is a directory read. + if (posixPath === '/') { + throw new Error('Stating the root is not supported'); + } + // The RESTful API has different endpoints for files and directories. + // The RESTful API does not provide specific error codes, only HTP 500. + // We query the parent directory and look for the file with the last segment. + const parentPosixPath = createPaths.parentPosix(posixPath); + const basename = createPaths.basename(posixPath); + + let resources; + if (basename === Create.arduino_secrets_file) { + const sketch = this.sketchCache.getSketch(parentPosixPath); + resources = sketch ? [this.getSketchSecretStat(sketch)] : []; + } else { + resources = await this.readDirectory(parentPosixPath, { + match: basename, + }); + } + const resource = resources.find( + ({ path }) => createPaths.splitSketchPath(path)[1] === posixPath + ); + if (!resource) { + throw new CreateError(`Not found: ${posixPath}.`, 404); + } + return resource; + } + + private async toggleSecretsInclude( + path: string, + data: string, + mode: 'add' | 'remove' + ) { + const includeString = `#include "${Create.arduino_secrets_file}"`; + const includeRegexp = new RegExp(includeString + '\\s*', 'g'); + + const basename = createPaths.basename(path); + if (mode === 'add') { + const doesIncludeSecrets = includeRegexp.test(data); + + if (doesIncludeSecrets) { + return data; + } + + 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 && + (sketch.name + '.ino' === basename || + sketch.name + '.pde' === basename) && + sketch.secrets && + sketch.secrets.length > 0 + ) { + return includeString + '\n' + data; + } + } else if (mode === 'remove') { + return data.replace(includeRegexp, ''); + } + return data; + } + + async readFile(posixPath: string): Promise { + const basename = createPaths.basename(posixPath); + + if (basename === Create.arduino_secrets_file) { + const parentPosixPath = createPaths.parentPosix(posixPath); + + //retrieve the sketch id from the cache + const cacheSketch = this.sketchCache.getSketch(parentPosixPath); + if (!cacheSketch) { + throw new Error(`Unable to find sketch ${parentPosixPath} in cache`); + } + + // get a fresh copy of the sketch in order to guarantee fresh secrets + const sketch = await this.sketch(cacheSketch.id); + if (!sketch) { + throw new Error( + `Unable to get a fresh copy of the sketch ${cacheSketch.id}` + ); + } + this.sketchCache.addSketch(sketch); + + let file = ''; + if (sketch.secrets) { + for (const item of sketch.secrets) { + file += `#define ${item.name} "${item.value}"\r\n`; + } + } + return file; + } + + const url = new URL( + `${this.domain()}/files/f/$HOME/sketches_v2${posixPath}` + ); + const headers = await this.headers(); + const result = await this.run<{ data: string; path: string }>(url, { + method: 'GET', + headers, + }); + let { data } = result; + + // add includes to main arduino file + data = await this.toggleSecretsInclude(posixPath, atob(data), 'add'); + return data; + } + + async writeFile( + posixPath: string, + content: string | Uint8Array + ): Promise { + const basename = createPaths.basename(posixPath); + + if (basename === Create.arduino_secrets_file) { + const parentPosixPath = createPaths.parentPosix(posixPath); + + const sketch = this.sketchCache.getSketch(parentPosixPath); + + 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 : uint8ArrayToString(content) + ) + .split(/\r?\n/) + .reduce((prev, curr) => { + // check if the line contains a secret + const secret = curr.split('SECRET_')[1] || null; + if (!secret) { + return prev; + } + const regexp = /(\S*)\s+([\S\s]*)/g; + const tokens = regexp.exec(secret) || []; + const name = tokens[1].length > 0 ? `SECRET_${tokens[1]}` : ''; + + let value = ''; + if (tokens[2].length > 0) { + value = JSON.parse( + JSON.stringify( + tokens[2].replace(/^['"]?/g, '').replace(/['"]?$/g, '') + ) + ); + } + + if (name.length === 0) { + return prev; + } + + return [...prev, { name, value }]; + }, []); + + const payload = { + id: sketch.id, + libraries: sketch.libraries, + secrets: { data: secrets }, + }; + + // replace the sketch in the cache with the one we are pushing + // TODO: we should do a get after the POST, in order to be sure the cache + // is updated the most recent metadata + this.sketchCache.addSketch(sketch); + + const init = { + method: 'POST', + body: JSON.stringify(payload), + headers, + }; + await this.run(url, init); + } + return; + } + + // do not upload "do_not_sync" files/directories and their descendants + const segments = posixPath.split(posix.sep) || []; + if ( + segments.some((segment) => Create.do_not_sync_files.includes(segment)) + ) { + return; + } + + const url = new URL( + `${this.domain()}/files/f/$HOME/sketches_v2${posixPath}` + ); + const headers = await this.headers(); + + let data: string = + typeof content === 'string' ? content : uint8ArrayToString(content); + data = await this.toggleSecretsInclude(posixPath, data, 'remove'); + + const payload = { data: btoa(data) }; + const init = { + method: 'POST', + body: JSON.stringify(payload), + headers, + }; + await this.run(url, init); + } + + async deleteFile(posixPath: string): Promise { + await this.delete(posixPath, 'f'); + } + + async deleteDirectory(posixPath: string): Promise { + await this.delete(posixPath, 'd'); + } + + /** + * `sketchPath` is not the POSIX path but the path with the user UUID, username, etc. + * See [Create.Resource#path](./typings.ts). Unlike other endpoints, it does not support the `$HOME` + * variable substitution. The DELETE directory endpoint is bogus and responses with HTTP 500 + * instead of 404 when deleting a non-existing resource. + */ + async deleteSketch(sketchPath: string): Promise { + const url = new URL(`${this.domain()}/sketches/byPath/${sketchPath}`); + const headers = await this.headers(); + await this.run(url, { + method: 'DELETE', + headers, + }); + } + + private async delete(posixPath: string, type: ResourceType): Promise { + const url = new URL( + `${this.domain()}/files/${type}/$HOME/sketches_v2${posixPath}` + ); + const headers = await this.headers(); + await this.run(url, { + method: 'DELETE', + headers, + }); + } + + async rename(fromPosixPath: string, toPosixPath: string): Promise { + const url = new URL(`${this.domain('v3')}/files/mv`); + const headers = await this.headers(); + const payload = { + from: `$HOME/sketches_v2${fromPosixPath}`, + to: `$HOME/sketches_v2${toPosixPath}`, + }; + const init = { + method: 'POST', + body: JSON.stringify(payload), + headers, + }; + await this.run(url, init, ResponseResultProvider.NOOP); + } + + async editSketch({ + id, + params, + }: { + id: string; + params: Record; + }): Promise { + const url = new URL(`${this.domain()}/sketches/${id}`); + + const headers = await this.headers(); + const result = await this.run(url, { + method: 'POST', + body: JSON.stringify({ id, ...params }), + headers, + }); + return result; + } + + async copy(fromPosixPath: string, toPosixPath: string): Promise { + const payload = { + from: `$HOME/sketches_v2${fromPosixPath}`, + to: `$HOME/sketches_v2${toPosixPath}`, + }; + const url = new URL(`${this.domain('v3')}/files/cp`); + const headers = await this.headers(); + const init = { + method: 'POST', + body: JSON.stringify(payload), + headers, + }; + await this.run(url, init, ResponseResultProvider.NOOP); + } + + private async run( + requestInfo: URL, + init: RequestInit | undefined, + resultProvider: ResponseResultProvider = ResponseResultProvider.JSON + ): Promise { + const response = await fetch(requestInfo.toString(), init); + if (!response.ok) { + let details: string | undefined = undefined; + try { + details = await response.json(); + } catch (e) { + console.error('Cloud not get the error details.', e); + } + const { statusText, status } = response; + throw new CreateError(statusText, status, details); + } + const result = await resultProvider(response); + return result; + } + + private async headers(): Promise> { + const token = await this.token(); + return { + 'content-type': 'application/json', + accept: 'application/json', + authorization: `Bearer ${token}`, + }; + } + + private domain(apiVersion = 'v2'): string { + const endpoint = + this.arduinoPreferences['arduino.cloud.sketchSyncEndpoint']; + return `${endpoint}/${apiVersion}`; + } + + private async token(): Promise { + return this.authenticationService.session?.accessToken || ''; + } +} diff --git a/arduino-ide-extension/src/browser/create/create-features.ts b/arduino-ide-extension/src/browser/create/create-features.ts new file mode 100644 index 000000000..2bbb32170 --- /dev/null +++ b/arduino-ide-extension/src/browser/create/create-features.ts @@ -0,0 +1,146 @@ +import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application'; +import { DisposableCollection } from '@theia/core/lib/common/disposable'; +import { Emitter, Event } from '@theia/core/lib/common/event'; +import URI from '@theia/core/lib/common/uri'; +import { inject, injectable } from '@theia/core/shared/inversify'; +import { Sketch } from '../../common/protocol'; +import { AuthenticationSession } from '../../common/protocol/authentication-service'; +import { ArduinoPreferences } from '../arduino-preferences'; +import { AuthenticationClientService } from '../auth/authentication-client-service'; +import { LocalCacheFsProvider } from '../local-cache/local-cache-fs-provider'; +import { + ARDUINO_CLOUD_FOLDER, + REMOTE_SKETCHBOOK_FOLDER, +} from '../utils/constants'; +import { CreateUri } from './create-uri'; + +export type CloudSketchState = 'push' | 'pull'; + +@injectable() +export class CreateFeatures implements FrontendApplicationContribution { + @inject(ArduinoPreferences) + private readonly preferences: ArduinoPreferences; + @inject(AuthenticationClientService) + private readonly authenticationService: AuthenticationClientService; + @inject(LocalCacheFsProvider) + private readonly localCacheFsProvider: LocalCacheFsProvider; + + /** + * The keys are the Create URI of the sketches. + */ + private readonly _cloudSketchStates = new Map(); + private readonly onDidChangeSessionEmitter = new Emitter< + AuthenticationSession | undefined + >(); + private readonly onDidChangeEnabledEmitter = new Emitter(); + private readonly onDidChangeCloudSketchStateEmitter = new Emitter<{ + uri: URI; + state: CloudSketchState | undefined; + }>(); + private readonly toDispose = new DisposableCollection( + this.onDidChangeSessionEmitter, + this.onDidChangeEnabledEmitter, + this.onDidChangeCloudSketchStateEmitter + ); + private _enabled: boolean; + private _session: AuthenticationSession | undefined; + + onStart(): void { + this.toDispose.pushAll([ + this.authenticationService.onSessionDidChange((session) => { + const oldSession = this._session; + this._session = session; + if (!!oldSession !== !!this._session) { + this.onDidChangeSessionEmitter.fire(this._session); + } + }), + this.preferences.onPreferenceChanged(({ preferenceName, newValue }) => { + if (preferenceName === 'arduino.cloud.enabled') { + const oldEnabled = this._enabled; + this._enabled = Boolean(newValue); + if (this._enabled !== oldEnabled) { + this.onDidChangeEnabledEmitter.fire(this._enabled); + } + } + }), + ]); + this._enabled = this.preferences['arduino.cloud.enabled']; + this._session = this.authenticationService.session; + } + + onStop(): void { + this.toDispose.dispose(); + } + + get onDidChangeSession(): Event { + return this.onDidChangeSessionEmitter.event; + } + + get onDidChangeEnabled(): Event { + return this.onDidChangeEnabledEmitter.event; + } + + 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`. + */ + isCloud(sketch: Sketch, dataDirUri: URI | undefined): boolean | undefined { + if (!dataDirUri) { + console.warn( + `Could not decide whether the sketch ${sketch.uri} is cloud or local. The 'directories.data' location was not available from the CLI config.` + ); + return undefined; + } + return dataDirUri + .resolve(REMOTE_SKETCHBOOK_FOLDER) + .resolve(ARDUINO_CLOUD_FOLDER) + .isEqualOrParent(new URI(sketch.uri)); + } + + cloudUri(sketch: Sketch): URI | undefined { + if (!this.session) { + return undefined; + } + return this.localCacheFsProvider.from(new URI(sketch.uri)); + } +} diff --git a/arduino-ide-extension/src/browser/create/create-fs-provider.ts b/arduino-ide-extension/src/browser/create/create-fs-provider.ts new file mode 100644 index 000000000..7908d0556 --- /dev/null +++ b/arduino-ide-extension/src/browser/create/create-fs-provider.ts @@ -0,0 +1,195 @@ +import { inject, injectable } from '@theia/core/shared/inversify'; +import URI from '@theia/core/lib/common/uri'; +import { Event } from '@theia/core/lib/common/event'; +import { + Disposable, + DisposableCollection, +} from '@theia/core/lib/common/disposable'; +import { FrontendApplicationContribution } from '@theia/core/lib/browser/frontend-application'; +import { + Stat, + FileType, + FileChange, + FileWriteOptions, + FileDeleteOptions, + FileOverwriteOptions, + FileSystemProvider, + FileSystemProviderError, + FileSystemProviderErrorCode, + FileSystemProviderCapabilities, + WatchOptions, +} from '@theia/filesystem/lib/common/files'; +import { + FileService, + FileServiceContribution, +} from '@theia/filesystem/lib/browser/file-service'; +import { AuthenticationClientService } from '../auth/authentication-client-service'; +import { CreateApi } from './create-api'; +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 + implements + FileSystemProvider, + FrontendApplicationContribution, + FileServiceContribution +{ + @inject(AuthenticationClientService) + protected readonly authenticationService: AuthenticationClientService; + + @inject(CreateApi) + protected readonly createApi: CreateApi; + + @inject(SketchesService) + protected readonly sketchesService: SketchesService; + + @inject(ArduinoPreferences) + protected readonly arduinoPreferences: ArduinoPreferences; + + protected readonly toDispose = new DisposableCollection(); + + readonly onFileWatchError: Event = Event.None; + readonly onDidChangeFile: Event = Event.None; + readonly onDidChangeCapabilities: Event = Event.None; + readonly capabilities: FileSystemProviderCapabilities = + FileSystemProviderCapabilities.FileReadWrite | + FileSystemProviderCapabilities.PathCaseSensitive | + FileSystemProviderCapabilities.Access; + + onStop(): void { + this.toDispose.dispose(); + } + + registerFileSystemProviders(service: FileService): void { + service.onWillActivateFileSystemProvider((event) => { + if (event.scheme === CreateUri.scheme) { + event.waitUntil( + (async () => { + service.registerProvider(CreateUri.scheme, this); + })() + ); + } + }); + } + + watch(uri: URI, opts: WatchOptions): Disposable { + return Disposable.NULL; + } + + async stat(uri: URI): Promise { + if (CreateUri.equals(CreateUri.root, uri)) { + this.getCreateApi; // This will throw when not logged in. + return { + type: FileType.Directory, + ctime: 0, + mtime: 0, + size: 0, + }; + } + const resource = await this.getCreateApi.stat(uri.path.toString()); + const mtime = Date.parse(resource.modified_at); + return { + type: this.toFileType(resource.type), + ctime: mtime, + mtime, + size: 0, + }; + } + + async mkdir(uri: URI): Promise { + await this.getCreateApi.createDirectory(uri.path.toString()); + } + + async readdir(uri: URI): Promise<[string, FileType][]> { + const resources = await this.getCreateApi.readDirectory( + uri.path.toString() + ); + return resources.map(({ name, type }) => [name, this.toFileType(type)]); + } + + async delete(uri: URI, opts: FileDeleteOptions): Promise { + if (!opts.recursive) { + throw new Error( + 'Arduino Create file-system provider does not support non-recursive deletion.' + ); + } + const stat = await this.stat(uri); + if (!stat) { + throw new FileSystemProviderError( + 'File not found.', + FileSystemProviderErrorCode.FileNotFound + ); + } + switch (stat.type) { + case FileType.Directory: { + await this.getCreateApi.deleteDirectory(uri.path.toString()); + break; + } + case FileType.File: { + await this.getCreateApi.deleteFile(uri.path.toString()); + break; + } + default: { + throw new FileSystemProviderError( + `Unexpected file type '${stat.type}' for resource: ${uri.toString()}`, + FileSystemProviderErrorCode.Unknown + ); + } + } + } + + async rename( + oldUri: URI, + newUri: URI, + options: FileOverwriteOptions + ): Promise { + await this.getCreateApi.rename( + oldUri.path.toString(), + newUri.path.toString() + ); + } + + async readFile(uri: URI): Promise { + const content = await this.getCreateApi.readFile(uri.path.toString()); + return stringToUint8Array(content); + } + + async writeFile( + uri: URI, + content: Uint8Array, + options: FileWriteOptions + ): Promise { + await this.getCreateApi.writeFile(uri.path.toString(), content); + } + + async access(uri: URI, mode?: number): Promise { + this.getCreateApi; // Will throw if not logged in. + } + + public toFileType(type: Create.ResourceType): FileType { + switch (type) { + case 'file': + return FileType.File; + case 'sketch': + case 'folder': + return FileType.Directory; + default: + return FileType.Unknown; + } + } + + private get getCreateApi(): CreateApi { + const { session } = this.authenticationService; + if (!session) { + throw new FileSystemProviderError( + 'Not logged in.', + FileSystemProviderErrorCode.NoPermissions + ); + } + return this.createApi; + } +} diff --git a/arduino-ide-extension/src/browser/create/create-paths.ts b/arduino-ide-extension/src/browser/create/create-paths.ts new file mode 100644 index 000000000..03b5ed974 --- /dev/null +++ b/arduino-ide-extension/src/browser/create/create-paths.ts @@ -0,0 +1,59 @@ +export const posix = { sep: '/' }; + +// TODO: poor man's `path.join(path, '..')` in the browser. +export function parentPosix(path: string): string { + const segments = path.split(posix.sep) || []; + segments.pop(); + let modified = segments.join(posix.sep); + if (path.charAt(path.length - 1) === posix.sep) { + modified += posix.sep; + } + return modified; +} + +export function basename(path: string): string { + const segments = path.split(posix.sep) || []; + return segments.pop()!; +} + +export function posixSegments(posixPath: string): string[] { + return posixPath.split(posix.sep).filter((segment) => !!segment); +} + +/** + * Splits the `raw` path into two segments, a root that contains user information and the relevant POSIX path. \ + * For examples: + * ``` + * `29ad0829759028dde9b877343fa3b0e1:testrest/sketches_v2/xxx_folder/xxx_sub_folder/sketch_in_folder/sketch_in_folder.ino` + * ``` + * will be: + * ``` + * ['29ad0829759028dde9b877343fa3b0e1:testrest/sketches_v2', '/xxx_folder/xxx_sub_folder/sketch_in_folder/sketch_in_folder.ino'] + * ``` + */ +export function splitSketchPath( + raw: string, + sep = '/sketches_v2/' +): [string, string] { + if (!sep) { + throw new Error('Invalid separator. Cannot be zero length.'); + } + const index = raw.indexOf(sep); + if (index === -1) { + throw new Error(`Invalid path pattern. Raw path was '${raw}'.`); + } + const createRoot = raw.substring(0, index + sep.length - 1); // TODO: validate the `createRoot` format. + const posixPath = raw.substr(index + sep.length - 1); + if (!posixPath) { + throw new Error(`Could not extract POSIX path from '${raw}'.`); + } + return [createRoot, posixPath]; +} + +export function toPosixPath(raw: string): string { + if (raw === posix.sep) { + return posix.sep; // Handles the root resource case. + } + const [, posixPath] = splitSketchPath(raw); + return posixPath; +} diff --git a/arduino-ide-extension/src/browser/create/create-uri.ts b/arduino-ide-extension/src/browser/create/create-uri.ts new file mode 100644 index 000000000..be1a30e9c --- /dev/null +++ b/arduino-ide-extension/src/browser/create/create-uri.ts @@ -0,0 +1,39 @@ +import { URI as Uri } from '@theia/core/shared/vscode-uri'; +import URI from '@theia/core/lib/common/uri'; +import { toPosixPath, parentPosix, posix } from './create-paths'; +import { Create } from './typings'; + +export namespace CreateUri { + export const scheme = 'arduino-create'; + export const root = toUri(posix.sep); + + export function toUri( + posixPathOrResource: string | Create.Resource | Create.Sketch + ): URI { + const posixPath = + typeof posixPathOrResource === 'string' + ? posixPathOrResource + : toPosixPath(posixPathOrResource.path); + return new URI(Uri.parse(posixPath).with({ scheme, authority: 'create' })); + } + + export function is(uri: URI): boolean { + return uri.scheme === scheme; + } + + export function equals(left: URI, right: URI): boolean { + return is(left) && is(right) && left.toString() === right.toString(); + } + + export function parent(uri: URI): URI { + if (!is(uri)) { + throw new Error( + `Invalid URI scheme. Expected '${scheme}' got '${uri.scheme}' instead.` + ); + } + if (equals(uri, root)) { + return uri; + } + return toUri(parentPosix(uri.path.toString())); + } +} diff --git a/arduino-ide-extension/src/browser/create/typings.ts b/arduino-ide-extension/src/browser/create/typings.ts new file mode 100644 index 000000000..b5dcf6f59 --- /dev/null +++ b/arduino-ide-extension/src/browser/create/typings.ts @@ -0,0 +1,100 @@ +export namespace Create { + export interface Sketch { + readonly name: string; + readonly path: string; + readonly modified_at: string; + readonly created_at: string; + + readonly secrets?: { name: string; value: string }[]; + + readonly id: string; + readonly is_public: boolean; + readonly board_fqbn: ''; + readonly board_name: ''; + readonly board_type: 'serial' | 'network' | 'cloud' | ''; + readonly href?: string; + readonly libraries: string[]; + readonly tutorials: string[] | null; + readonly types: string[] | null; + readonly user_id: string; + } + + export type ResourceType = 'sketch' | 'folder' | 'file'; + export const arduino_secrets_file = 'arduino_secrets.h'; + export const do_not_sync_files = ['.theia', 'sketch.json']; + export interface Resource { + readonly name: string; + /** + * Note: this path is **not** the POSIX path we use. It has the leading segments with the `user_id`. + */ + readonly path: string; + readonly type: ResourceType; + readonly sketchId?: string; + readonly modified_at: string; // As an ISO-8601 formatted string: `YYYY-MM-DDTHH:mm:ss.sssZ` + readonly created_at: string; // As an ISO-8601 formatted string: `YYYY-MM-DDTHH:mm:ss.sssZ` + readonly children?: number; // For 'sketch' and 'folder' types. + readonly size?: number; // For 'sketch' type only. + readonly isPublic?: boolean; // For 'sketch' type only. + + readonly mimetype?: string; // For 'file' type. + readonly href?: string; + } + export namespace Resource { + export function is(arg: any): arg is Resource { + return ( + !!arg && + 'name' in arg && + typeof arg['name'] === 'string' && + 'path' in arg && + typeof arg['path'] === 'string' && + 'type' in arg && + typeof arg['type'] === 'string' && + 'modified_at' in arg && + typeof arg['modified_at'] === 'string' && + (arg['type'] === 'sketch' || + arg['type'] === 'folder' || + arg['type'] === 'file') + ); + } + } + + export type RawResource = Omit; +} + +export class CreateError extends Error { + constructor( + message: string, + readonly status: number, + readonly details?: string + ) { + super(message); + Object.setPrototypeOf(this, CreateError.prototype); + } +} + +export type ConflictError = CreateError & { status: 409 }; +export function isConflict(err: unknown): err is ConflictError { + return isErrorWithStatusOf(err, 409); +} + +export type NotFoundError = CreateError & { status: 404 }; +export function isNotFound(err: unknown): err is NotFoundError { + return isErrorWithStatusOf(err, 404); +} + +export type UnprocessableContentError = CreateError & { status: 422 }; +export function isUnprocessableContent( + err: unknown +): err is UnprocessableContentError { + return isErrorWithStatusOf(err, 422); +} + +function isErrorWithStatusOf( + err: unknown, + status: number +): err is CreateError & { status: number } { + if (err instanceof CreateError) { + return err.status === status; + } + return false; +} diff --git a/arduino-ide-extension/src/browser/data/dark.color-theme.json b/arduino-ide-extension/src/browser/data/dark.color-theme.json new file mode 100644 index 000000000..9e9d15718 --- /dev/null +++ b/arduino-ide-extension/src/browser/data/dark.color-theme.json @@ -0,0 +1,167 @@ +{ + "name": "Arduino dark", + "type": "dark", + "colors": { + "list.highlightForeground": "#0ca1a6", + "list.activeSelectionForeground": "#dae3e3", + "list.activeSelectionBackground": "#0ca1a64d", + "list.inactiveSelectionForeground": "#dae3e3", + "list.inactiveSelectionBackground": "#434f54", + "list.hoverBackground": "#1f272a", + "list.activeSelectionIconForeground": "#0ca1a6", + "progressBar.background": "#005c5f", + "editor.background": "#1f272a", + "editor.foreground": "#dae3e3", + "editor.lineHighlightBackground": "#434f5410", + "editor.selectionBackground": "#00818480", + "editorCursor.foreground": "#dae3e3", + "editorWhitespace.foreground": "#bfbfbf", + "editorWidget.background": "#171e21", + "editorWidget.foreground": "#dae3e3", + "focusBorder": "#dae3e3", + "menubar.selectionBackground": "#ffffff", + "menubar.selectionForeground": "#212121", + "menu.selectionBackground": "#dae3e3", + "menu.selectionForeground": "#212121", + "editorGroupHeader.tabsBackground": "#171e21", + "button.background": "#0ca1a6", + "button.foreground": "#101618", + "button.hoverBackground": "#7fcbcd", + "titleBar.activeBackground": "#171e21", + "titleBar.activeForeground": "#dae3e3", + "terminal.background": "#000000", + "terminal.foreground": "#ffffff", + "dropdown.border": "#7fcbcd", + "dropdown.background": "#2c353a", + "dropdown.foreground": "#dae3e3", + "activityBar.background": "#171e21", + "activityBar.foreground": "#dae3e3", + "activityBar.inactiveForeground": "#4e5b61", + "activityBar.activeBorder": "#0ca1a6", + "statusBar.background": "#171e21", + "secondaryButton.background": "#ff000000", + "secondaryButton.foreground": "#dae3e3", + "secondaryButton.hoverBackground": "#ffffff1a", + "arduino.branding.primary": "#0ca1a6", + "arduino.branding.secondary": "#b5c8c9", + "arduino.foreground": "#edf1f1", + "arduino.output.foreground": "#ffffff", + "arduino.output.background": "#000000", + "arduino.toolbar.button.hoverBackground": "#dae3e3", + "arduino.toolbar.button.secondary.label": "#dae3e3", + "arduino.toolbar.button.secondary.hoverBackground": "#dae3e366", + "arduino.toolbar.button.background": "#0ca1a6", + "arduino.toolbar.dropdown.border": "#7fcbcd", + "arduino.toolbar.dropdown.borderActive": "#0ca1a6", + "arduino.toolbar.dropdown.background": "#2c353a", + "arduino.toolbar.dropdown.label": "#dae3e3", + "arduino.toolbar.dropdown.iconSelected": "#3fae98", + "arduino.toolbar.dropdown.option.backgroundHover": "#374146", + "arduino.toolbar.dropdown.option.backgroundSelected": "#4e5b61", + "arduino.toolbar.toggleBackground": "#f1c40f", + "sideBar.background": "#101618", + "sideBar.foreground": "#dae3e3", + "input.background": "#000000", + "foreground": "#dae3e3", + "settings.headerForeground": "#dae3e3", + "tree.indentGuidesStroke": "#374146", + "tab.unfocusedActiveForeground": "#dae3e3", + "tab.inactiveBackground": "#171e21", + "textLink.foreground": "#0ca1a6", + "errorForeground": "#df7365" + }, + "tokenColors": [ + { + "name": "", + "settings": { + "foreground": "#dae3e3" + } + }, + { + "name": "Comments", + "scope": "comment", + "settings": { + "foreground": "#7f8c8d" + } + }, + { + "name": "Keywords Attributes", + "scope": [ + "storage", + "support", + "string.quoted.single.c" + ], + "settings": { + "foreground": "#0ca1a6" + } + }, + { + "name": "literal", + "scope": [ + "meta.function.c", + "entity.name.function", + "meta.function-call.c", + "variable.other" + ], + "settings": { + "foreground": "#F39C12" + } + }, + { + "name": "punctuation", + "scope": [ + "punctuation.section", + "meta.function-call.c", + "meta.block.c", + "meta.function.c", + "variable", + "variable.name" + ], + "settings": { + "foreground": "#dae3e3" + } + }, + { + "name": "function preprocessor", + "scope": [ + "entity.name.function.preprocessor.c", + "meta.preprocessor.macro.c" + ], + "settings": { + "foreground": "#569CD6" + } + }, + { + "name": "constants", + "scope": [ + "string.quoted.double", + "string.quoted.other.lt-gt", + "constant" + ], + "settings": { + "foreground": "#7fcbcd" + } + }, + { + "name": "meta keywords", + "scope": [ + "keyword.control", + "meta.preprocessor.c" + ], + "settings": { + "foreground": "#C586C0" + } + }, + { + "name": "numeric preprocessor", + "scope": [ + "meta.preprocessor.macro.c", + "constant.numeric.preprocessor.c", + "meta.preprocessor.c" + ], + "settings": { + "foreground": "#434f54" + } + } + ] +} \ No newline at end of file diff --git a/arduino-ide-extension/src/browser/data/default.color-theme.json b/arduino-ide-extension/src/browser/data/default.color-theme.json new file mode 100644 index 000000000..e2ce858e5 --- /dev/null +++ b/arduino-ide-extension/src/browser/data/default.color-theme.json @@ -0,0 +1,169 @@ +{ + "name": "Arduino default", + "type": "default", + "colors": { + "list.highlightForeground": "#008184", + "list.activeSelectionForeground": "#4e5b61", + "list.activeSelectionBackground": "#00818433", + "list.inactiveSelectionForeground": "#4e5b61", + "list.inactiveSelectionBackground": "#dae3e3", + "list.hoverBackground": "#f0f0f0", + "list.activeSelectionIconForeground": "#008184", + "progressBar.background": "#1dbef9", + "editor.background": "#ffffff", + "editor.foreground": "#4e5b61", + "editor.lineHighlightBackground": "#434f5410", + "editor.selectionBackground": "#7fcbcdb3", + "editorCursor.foreground": "#4e5b61", + "editorWhitespace.foreground": "#bfbfbf", + "editorWidget.background": "#f0f0f0", + "editorWidget.foreground": "#4e5b61", + "focusBorder": "#bbd9f2", + "menubar.selectionBackground": "#ffffff", + "menubar.selectionForeground": "#212121", + "menu.selectionBackground": "#dae3e3", + "menu.selectionForeground": "#212121", + "editorGroupHeader.tabsBackground": "#f0f0f0", + "button.background": "#f7f7f7", + "button.foreground": "#000000", + "button.hoverBackground": "#fbfbfb", + "titleBar.activeBackground": "#f0f0f0", + "titleBar.activeForeground": "#f7f9f9", + "terminal.background": "#ffffff", + "terminal.foreground": "#000000", + "dropdown.border": "#dae3e3", + "dropdown.background": "#ffffff", + "dropdown.foreground": "#4e5b61", + "activityBar.background": "#aeabab", + "activityBar.foreground": "#1dbef9", + "activityBar.inactiveForeground": "#1dbef9", + "activityBar.activeBorder": "#a0a0a0", + "activityBar.activeBackground": "#cdcccc", + "statusBar.background": "#d7d7d7", + "statusBar.foreground": "#6471fa", + "secondaryButton.background": "#f7f7f7", + "secondaryButton.foreground": "#bbd9f2", + "secondaryButton.hoverBackground": "#ffffff", + "arduino.branding.primary": "#008184", + "arduino.branding.secondary": "#b5c8c9", + "arduino.foreground": "#edf1f1", + "arduino.output.foreground": "#ffffff", + "arduino.output.background": "#000000", + "arduino.toolbar.button.hoverBackground": "#f7f9f9", + "arduino.toolbar.button.secondary.label": "#dae3e3", + "arduino.toolbar.button.secondary.hoverBackground": "#dae3e366", + "arduino.toolbar.button.background": "#7fcbcd", + "arduino.toolbar.dropdown.border": "#dae3e3", + "arduino.toolbar.dropdown.borderActive": "#7fcbcd", + "arduino.toolbar.dropdown.background": "#ffffff", + "arduino.toolbar.dropdown.label": "#4e5b61", + "arduino.toolbar.dropdown.iconSelected": "#1da086", + "arduino.toolbar.dropdown.option.backgroundHover": "#ecf1f1", + "arduino.toolbar.dropdown.option.backgroundSelected": "#dae3e3", + "arduino.toolbar.toggleBackground": "#f1c40f", + "sideBar.background": "#f0f0f0", + "sideBar.foreground": "#000000", + "input.background": "#ffffff", + "foreground": "#000000", + "settings.headerForeground": "#4e5b61", + "tree.indentGuidesStroke": "#dae3e3", + "tab.unfocusedActiveForeground": "#4e5b61", + "tab.inactiveBackground": "#ecf1f1", + "textLink.foreground": "#5500ff", + "errorForeground": "#df7365" + }, + "tokenColors": [ + { + "name": "", + "settings": { + "foreground": "#434f54" + } + }, + { + "name": "Comments", + "scope": "comment", + "settings": { + "foreground": "#95a5a6cc" + } + }, + { + "name": "Keywords Attributes", + "scope": [ + "storage", + "support", + "string.quoted.single.c" + ], + "settings": { + "foreground": "#00979D" + } + }, + { + "name": "literal", + "scope": [ + "meta.function.c", + "entity.name.function", + "meta.function-call.c", + "variable.other" + ], + "settings": { + "foreground": "#D35400" + } + }, + { + "name": "punctuation", + "scope": [ + "punctuation.section", + "meta.function-call.c", + "meta.block.c", + "meta.function.c", + "variable", + "variable.name" + ], + "settings": { + "foreground": "#434f54" + } + }, + { + "name": "function preprocessor", + "scope": [ + "entity.name.function.preprocessor.c", + "meta.preprocessor.macro.c" + ], + "settings": { + "foreground": "#9e846d" + } + }, + { + "name": "constants", + "scope": [ + "string.quoted.double", + "string.quoted.other.lt-gt", + "constant" + ], + "settings": { + "foreground": "#005C5F" + } + }, + { + "name": "meta keywords", + "scope": [ + "keyword.control", + "meta.preprocessor.c" + ], + "settings": { + "foreground": "#728E00" + } + }, + { + "name": "numeric preprocessor", + "scope": [ + "meta.preprocessor.macro.c", + "constant.numeric.preprocessor.c", + "meta.preprocessor.c" + ], + "settings": { + "foreground": "#434f54" + } + } + ] +} \ No newline at end of file diff --git a/arduino-ide-extension/src/browser/dialog-service.ts b/arduino-ide-extension/src/browser/dialog-service.ts new file mode 100644 index 000000000..f5c8aa593 --- /dev/null +++ b/arduino-ide-extension/src/browser/dialog-service.ts @@ -0,0 +1,15 @@ +import type { + MessageBoxOptions, + MessageBoxReturnValue, + OpenDialogOptions, + OpenDialogReturnValue, + SaveDialogOptions, + SaveDialogReturnValue, +} from '../electron-common/electron-arduino'; + +export const DialogService = Symbol('DialogService'); +export interface DialogService { + showMessageBox(options: MessageBoxOptions): Promise; + showOpenDialog(options: OpenDialogOptions): Promise; + showSaveDialog(options: SaveDialogOptions): Promise; +} diff --git a/arduino-ide-extension/src/browser/dialogs/Keymaps/keymaps-dialog.tsx b/arduino-ide-extension/src/browser/dialogs/Keymaps/keymaps-dialog.tsx new file mode 100644 index 000000000..6116ba871 --- /dev/null +++ b/arduino-ide-extension/src/browser/dialogs/Keymaps/keymaps-dialog.tsx @@ -0,0 +1,158 @@ +/* eslint-disable prettier/prettier */ +import { inject, injectable } from '@theia/core/shared/inversify'; +import { AbstractDialog } from '../../theia/dialogs/dialogs'; +import { DialogProps } from '@theia/core/lib/browser/dialogs'; +import { ThemeService } from '@theia/core/lib/browser/theming'; + +@injectable() +export class KeymapsDialogProps extends DialogProps { } + +@injectable() +export class KeymapsDialog extends AbstractDialog> { + private mainDiv: HTMLDivElement; + + @inject(ThemeService) + private readonly themeService: ThemeService; + + constructor( + @inject(KeymapsDialogProps) + protected override readonly props: KeymapsDialogProps + ) { + super(props); + this.node.id = 'lingzhi-keymaps-dialog-container'; + this.contentNode.classList.add('lingzhi-keymaps-dialog'); + + this.contentNode.style.width = '100%'; + this.contentNode.style.height = '260px'; + + this.initLayout(); + } + + private initLayout() { + const topDiv = document.createElement('div'); + topDiv.className = 'lingzhi-ide-keymaps-top' + this.contentNode.appendChild(topDiv); + + const titleDiv = document.createElement('div'); + titleDiv.style.width = '100%'; + titleDiv.style.height = '30px'; + titleDiv.style.display = 'flex'; + titleDiv.style.alignItems = 'center'; + titleDiv.style.justifyContent = 'center'; + topDiv.appendChild(titleDiv); + + const nameDiv = document.createElement('div'); + nameDiv.className = 'lingzhi-ide-keymaps-title' + nameDiv.textContent = '功能' + titleDiv.appendChild(nameDiv); + + const shortcutKeyDiv = document.createElement('div'); + shortcutKeyDiv.className = 'lingzhi-ide-keymaps-title' + shortcutKeyDiv.textContent = '快捷键' + titleDiv.appendChild(shortcutKeyDiv); + + const spring = document.createElement('div'); + spring.style.width = '10px'; + titleDiv.appendChild(spring); + + const mainDiv = document.createElement('div'); + mainDiv.className = 'lingzhi-ide-keymaps-main'; + topDiv.appendChild(mainDiv); + this.mainDiv = mainDiv; + + const keymapsData = [ + ['撤销', 'Ctrl+Z'], ['恢复', 'Ctrl+Shift+Z'], ['剪切', 'Ctrl+X'], ['复制', 'Ctrl+C'], + ['粘贴', 'Ctrl+V'], ['全选', 'Ctrl+A'], ['转到行/列...', 'Ctrl+L'], ['注释/取消注释', 'Ctrl+/'], + ['自动格式化', 'Ctrl+T'], ['放大字号', 'Ctrl+='], ['缩小字号', 'Ctrl+-'], ['查找', 'Ctrl+F'], + ['查找上一个', 'Ctrl+G'], ['查找下一个', 'Ctrl+Shift+G'], ['查找选定内容', 'Ctrl+E'], + ['设置', 'Ctrl+逗号'], ['保存', 'Ctrl+S'], ['另存为...', 'Ctrl+Shift+S'], + ['键盘快捷方式参考', 'Alt+Shift+逗号'], ['退出', 'Ctrl+Q'], ['串口监视器', 'Ctrl+Shift+M'], + ['使用编程器上传', 'Ctrl+Shift+U'], ['导出以编译的二进制文件', 'Alt+Ctrl+S'], ['显示项目文件', 'Alt+Ctrl+K'], + ['在参考文件寻找', 'Ctrl+Shift+F'], ['转到定义', 'Ctrl+F12'], ['转到编辑器的符号...', 'Ctrl+Shift+O'], + ['查看定义', 'Alt+F12'], ['重命名符号', 'F2'], ['更改所有事件', 'Ctrl+F2'], + ['格式化文件', 'Alt+Shift+F'] + ] + + keymapsData.forEach((raw) => { + const keymapsRawDiv = document.createElement('div'); + keymapsRawDiv.style.width = '100%'; + keymapsRawDiv.style.height = '30px'; + keymapsRawDiv.style.display = 'flex'; + keymapsRawDiv.style.alignItems = 'center'; + keymapsRawDiv.style.justifyContent = 'center'; + keymapsRawDiv.style.backgroundColor = '#ffffff'; + mainDiv.appendChild(keymapsRawDiv); + + this.onclickKeymapsRawDiv(keymapsRawDiv); + + const keymapsNameDiv = document.createElement('div'); + keymapsNameDiv.className = 'lingzhi-ide-keymaps-raw' + keymapsNameDiv.textContent = raw[0]; + keymapsRawDiv.appendChild(keymapsNameDiv); + + const keymapsShortcutKeyDiv = document.createElement('div'); + keymapsShortcutKeyDiv.className = 'lingzhi-ide-keymaps-raw' + keymapsShortcutKeyDiv.textContent = raw[1]; + keymapsRawDiv.appendChild(keymapsShortcutKeyDiv); + + }) + } + + private onclickKeymapsRawDiv(keymapsRawDiv: HTMLDivElement) { + keymapsRawDiv.addEventListener('click', () => { + keymapsRawDiv.style.backgroundColor = '#1283dc'; + const childs = this.mainDiv.children; + for (let i = 0; i < childs.length; i++) { + const child = childs[i] as HTMLDivElement; + if (child !== keymapsRawDiv) { + child.style.backgroundColor = '#ffffff'; + } + } + }); + } + + override get value(): Promise { + throw new Error('Method not implemented.'); + } + + override close(): void { + if (this.resolve) { + if (this.activeElement) { + this.activeElement.focus({ preventScroll: true }); + } + this.resolve(undefined); + } + + const childs = this.mainDiv.children; + for (let i = 0; i < childs.length; i++) { + const child = childs[i] as HTMLDivElement; + child.style.backgroundColor = '#ffffff'; + } + + this.activeElement = undefined; + super.close(); + } + + override async open(): Promise | undefined> { + // 获取打开前主题的id + const themeIdBeforeOpen = this.themeService.getCurrentTheme().id; + // 调用父类open方法 + const result = await super.open(); + // 如果打开失败 + if (!result) { + // 如果当前主题id与打开前主题id不同 + if (this.themeService.getCurrentTheme().id !== themeIdBeforeOpen) { + // 将当前主题设置为打开前主题 + this.themeService.setCurrentTheme(themeIdBeforeOpen); + } + } + // 返回结果 + return result; + } + +} + +export interface Keymaps { + path: string; + model: string; +} diff --git a/arduino-ide-extension/src/browser/dialogs/Keymaps/open-keymaps.ts b/arduino-ide-extension/src/browser/dialogs/Keymaps/open-keymaps.ts new file mode 100644 index 000000000..b540bd00e --- /dev/null +++ b/arduino-ide-extension/src/browser/dialogs/Keymaps/open-keymaps.ts @@ -0,0 +1,24 @@ +/* eslint-disable prettier/prettier */ +import { inject, injectable } from '@theia/core/shared/inversify'; +import { + Command, + CommandRegistry, + SketchContribution, +} from '../../contributions/contribution'; +import { KeymapsDialog } from './keymaps-dialog'; + +@injectable() +export class OpenKeymaps extends SketchContribution { + @inject(KeymapsDialog) + private readonly keymapsDialog: KeymapsDialog; + + override registerCommands(command: CommandRegistry): void { + command.registerCommand(KEYMAPS_OPEN, { + execute: async () => { await this.keymapsDialog.open() }, + }) + } +} + +export const KEYMAPS_OPEN: Command = { + id: 'lingzhi-keymaps-open', +} diff --git a/arduino-ide-extension/src/browser/dialogs/certificate-uploader/certificate-add-new.tsx b/arduino-ide-extension/src/browser/dialogs/certificate-uploader/certificate-add-new.tsx new file mode 100644 index 000000000..6a06d36b5 --- /dev/null +++ b/arduino-ide-extension/src/browser/dialogs/certificate-uploader/certificate-add-new.tsx @@ -0,0 +1,49 @@ +import { nls } from '@theia/core/lib/common'; +import React from '@theia/core/shared/react'; + +export const CertificateAddComponent = ({ + addCertificate, +}: { + addCertificate: (cert: string) => void; +}): React.ReactElement => { + const [value, setValue] = React.useState(''); + + const handleChange = React.useCallback( + (event: React.ChangeEvent) => { + setValue(event.target.value); + }, + [] + ); + + return ( +
{ + event.preventDefault(); + event.stopPropagation(); + addCertificate(value); + setValue(''); + }} + > + +
+ ); +}; diff --git a/arduino-ide-extension/src/browser/dialogs/certificate-uploader/certificate-list.tsx b/arduino-ide-extension/src/browser/dialogs/certificate-uploader/certificate-list.tsx new file mode 100644 index 000000000..283f97a0a --- /dev/null +++ b/arduino-ide-extension/src/browser/dialogs/certificate-uploader/certificate-list.tsx @@ -0,0 +1,51 @@ +import React from '@theia/core/shared/react'; + +export const CertificateListComponent = ({ + certificates, + selectedCerts, + setSelectedCerts, + openContextMenu, +}: { + certificates: string[]; + selectedCerts: string[]; + setSelectedCerts: React.Dispatch>; + openContextMenu: (x: number, y: number, cert: string) => void; +}): React.ReactElement => { + const handleOnChange = (event: any) => { + const target = event.target; + + const newSelectedCerts = selectedCerts.filter( + (cert) => cert !== target.name + ); + + if (target.checked) { + newSelectedCerts.push(target.name); + } + + setSelectedCerts(newSelectedCerts); + }; + + const handleContextMenu = (event: React.MouseEvent, cert: string) => { + openContextMenu(event.clientX, event.clientY, cert); + }; + + return ( +
+ {certificates.map((certificate, i) => ( + + ))} +
+ ); +}; diff --git a/arduino-ide-extension/src/browser/dialogs/certificate-uploader/certificate-uploader-component.tsx b/arduino-ide-extension/src/browser/dialogs/certificate-uploader/certificate-uploader-component.tsx new file mode 100644 index 000000000..3abb4f2d7 --- /dev/null +++ b/arduino-ide-extension/src/browser/dialogs/certificate-uploader/certificate-uploader-component.tsx @@ -0,0 +1,195 @@ +import { nls } from '@theia/core/lib/common/nls'; +import React from '@theia/core/shared/react'; +import Tippy from '@tippyjs/react'; +import type { BoardList } from '../../../common/protocol/board-list'; +import { + boardIdentifierEquals, + portIdentifierEquals, +} from '../../../common/protocol/boards-service'; +import { CertificateAddComponent } from './certificate-add-new'; +import { CertificateListComponent } from './certificate-list'; +import { + BoardOptionValue, + SelectBoardComponent, +} from './select-board-components'; + +export const CertificateUploaderComponent = ({ + boardList, + certificates, + addCertificate, + updatableFqbns, + uploadCertificates, + openContextMenu, +}: { + boardList: BoardList; + certificates: string[]; + addCertificate: (cert: string) => void; + updatableFqbns: string[]; + uploadCertificates: ( + fqbn: string, + address: string, + urls: string[] + ) => Promise; + openContextMenu: (x: number, y: number, cert: string) => void; +}): React.ReactElement => { + const [installFeedback, setInstallFeedback] = React.useState< + 'ok' | 'fail' | 'installing' | null + >(null); + + const [showAdd, setShowAdd] = React.useState(false); + + const [selectedCerts, setSelectedCerts] = React.useState([]); + + const [selectedItem, setSelectedItem] = + React.useState(null); + + const installCertificates = async () => { + if (!selectedItem) { + return; + } + const board = selectedItem.board; + if (!board.fqbn) { + return; + } + + setInstallFeedback('installing'); + + try { + await uploadCertificates( + board.fqbn, + selectedItem.port.address, + selectedCerts + ); + setInstallFeedback('ok'); + } catch { + setInstallFeedback('fail'); + } + }; + + const onItemSelect = React.useCallback( + (item: BoardOptionValue | null) => { + if (!item) { + setSelectedItem(null); + return; + } + const board = item.board; + const port = item.port; + const selectedBoard = selectedItem?.board; + const selectedPort = selectedItem?.port; + + if ( + !boardIdentifierEquals(board, selectedBoard) || + !portIdentifierEquals(port, selectedPort) + ) { + setInstallFeedback(null); + setSelectedItem(item); + } + }, + [selectedItem] + ); + + return ( + <> +
+
+ + {nls.localize( + 'arduino/certificate/selectCertificateToUpload', + '1. Select certificate to upload' + )} + + { + addCertificate(cert); + setShowAdd(false); + }} + /> + } + placement="bottom-end" + onClickOutside={() => setShowAdd(false)} + visible={showAdd} + interactive={true} + > + + +
+
+ +
+
+
+
+ + {nls.localize( + 'arduino/certificate/selectDestinationBoardToUpload', + '2. Select destination board and upload certificate' + )} + +
+
+
+ +
+
+
+
+ {installFeedback === 'installing' && ( +
+
+ {nls.localize( + 'arduino/certificate/uploadingCertificates', + 'Uploading certificates.' + )} +
+ )} + {installFeedback === 'ok' && ( +
+ + {nls.localize( + 'arduino/certificate/certificatesUploaded', + 'Certificates uploaded.' + )} +
+ )} + {installFeedback === 'fail' && ( +
+ + {'上传失败。请再试一次。'} +
+ )} +
+ +
+
+ + ); +}; diff --git a/arduino-ide-extension/src/browser/dialogs/certificate-uploader/certificate-uploader-dialog.tsx b/arduino-ide-extension/src/browser/dialogs/certificate-uploader/certificate-uploader-dialog.tsx new file mode 100644 index 000000000..8ac173984 --- /dev/null +++ b/arduino-ide-extension/src/browser/dialogs/certificate-uploader/certificate-uploader-dialog.tsx @@ -0,0 +1,200 @@ +import { DialogProps } from '@theia/core/lib/browser/dialogs'; +import { FrontendApplicationStateService } from '@theia/core/lib/browser/frontend-application-state'; +import { + PreferenceScope, + PreferenceService, +} from '@theia/core/lib/browser/preferences/preference-service'; +import { ReactWidget } from '@theia/core/lib/browser/widgets/react-widget'; +import { CommandRegistry } from '@theia/core/lib/common/command'; +import type { Message } from '@theia/core/shared/@phosphor/messaging'; +import { Widget } from '@theia/core/shared/@phosphor/widgets'; +import { + inject, + injectable, + postConstruct, +} from '@theia/core/shared/inversify'; +import React from '@theia/core/shared/react'; +import { ArduinoFirmwareUploader } from '../../../common/protocol/arduino-firmware-uploader'; +import { createBoardList } from '../../../common/protocol/board-list'; +import { ArduinoPreferences } from '../../arduino-preferences'; +import { BoardsServiceProvider } from '../../boards/boards-service-provider'; +import { AbstractDialog } from '../../theia/dialogs/dialogs'; +import { CertificateUploaderComponent } from './certificate-uploader-component'; +import { certificateList, sanifyCertString } from './utils'; + +@injectable() +export class UploadCertificateDialogWidget extends ReactWidget { + @inject(BoardsServiceProvider) + private readonly boardsServiceProvider: BoardsServiceProvider; + @inject(ArduinoPreferences) + private readonly arduinoPreferences: ArduinoPreferences; + @inject(PreferenceService) + private readonly preferenceService: PreferenceService; + @inject(CommandRegistry) + private readonly commandRegistry: CommandRegistry; + @inject(ArduinoFirmwareUploader) + private readonly arduinoFirmwareUploader: ArduinoFirmwareUploader; + @inject(FrontendApplicationStateService) + private readonly appStateService: FrontendApplicationStateService; + + private certificates: string[] = []; + private updatableFqbns: string[] = []; + private boardList = createBoardList({}); + + busyCallback = (busy: boolean) => { + return; + }; + + @postConstruct() + protected init(): void { + this.arduinoPreferences.ready.then(() => { + this.certificates = certificateList( + this.arduinoPreferences.get('arduino.board.certificates') + ); + }); + this.arduinoPreferences.onPreferenceChanged((event) => { + if ( + event.preferenceName === 'arduino.board.certificates' && + event.newValue !== event.oldValue + ) { + this.certificates = certificateList(event.newValue); + this.update(); + } + }); + + this.appStateService.reachedState('ready').then(() => + this.arduinoFirmwareUploader.updatableBoards().then((fqbns) => { + this.updatableFqbns = fqbns; + this.update(); + }) + ); + + this.boardsServiceProvider.onBoardListDidChange((boardList) => { + this.boardList = boardList; + this.update(); + }); + } + + private addCertificate(certificate: string) { + const certString = sanifyCertString(certificate); + + if (certString.length > 0) { + this.certificates.push(sanifyCertString(certificate)); + } + + this.preferenceService.set( + 'arduino.board.certificates', + this.certificates.join(','), + PreferenceScope.User + ); + } + + protected openContextMenu(x: number, y: number, cert: string): void { + this.commandRegistry.executeCommand( + 'arduino-certificate-open-context', + Object.assign({}, { x, y, cert }) + ); + } + + protected uploadCertificates( + fqbn: string, + address: string, + urls: string[] + ): Promise { + this.busyCallback(true); + return this.commandRegistry + .executeCommand('arduino-certificate-upload', { + fqbn, + address, + urls, + }) + .finally(() => this.busyCallback(false)); + } + + protected render(): React.ReactNode { + return ( + + ); + } +} + +@injectable() +export class UploadCertificateDialogProps extends DialogProps { } + +@injectable() +export class UploadCertificateDialog extends AbstractDialog { + @inject(UploadCertificateDialogWidget) + private readonly widget: UploadCertificateDialogWidget; + + private busy = false; + + constructor( + @inject(UploadCertificateDialogProps) + protected override readonly props: UploadCertificateDialogProps + ) { + super({ + title: '上传 SSL 根证书', + }); + this.node.id = 'certificate-uploader-dialog-container'; + this.contentNode.classList.add('certificate-uploader-dialog'); + this.acceptButton = undefined; + } + + get value(): void { + return; + } + + public accept1() { + this.accept(); + } + + protected override onAfterAttach(msg: Message): void { + if (this.widget.isAttached) { + Widget.detach(this.widget); + } + Widget.attach(this.widget, this.contentNode); + const firstButton = this.widget.node.querySelector('button'); + firstButton?.focus(); + + this.widget.busyCallback = this.busyCallback.bind(this); + super.onAfterAttach(msg); + this.update(); + } + + protected override onUpdateRequest(msg: Message): void { + super.onUpdateRequest(msg); + this.widget.update(); + } + + protected override onActivateRequest(msg: Message): void { + super.onActivateRequest(msg); + this.widget.activate(); + } + + protected override handleEnter(event: KeyboardEvent): boolean | void { + return false; + } + + override close(): void { + if (this.busy) { + return; + } + super.close(); + } + + busyCallback(busy: boolean): void { + this.busy = busy; + if (busy) { + this.closeCrossNode.classList.add('disabled'); + } else { + this.closeCrossNode.classList.remove('disabled'); + } + } +} diff --git a/arduino-ide-extension/src/browser/dialogs/certificate-uploader/select-board-components.tsx b/arduino-ide-extension/src/browser/dialogs/certificate-uploader/select-board-components.tsx new file mode 100644 index 000000000..d20bf1f87 --- /dev/null +++ b/arduino-ide-extension/src/browser/dialogs/certificate-uploader/select-board-components.tsx @@ -0,0 +1,109 @@ +import { nls } from '@theia/core/lib/common'; +import React from '@theia/core/shared/react'; +import { + boardListItemEquals, + type BoardList, + type BoardListItemWithBoard, +} from '../../../common/protocol/board-list'; +import { ArduinoSelect } from '../../widgets/arduino-select'; + +export type BoardOptionValue = BoardListItemWithBoard; +type BoardOption = { value: BoardOptionValue | undefined; label: string }; + +export const SelectBoardComponent = ({ + boardList, + updatableFqbns, + onItemSelect, + selectedItem, + busy, +}: { + boardList: BoardList; + updatableFqbns: string[]; + onItemSelect: (item: BoardOptionValue | null) => void; + selectedItem: BoardOptionValue | null; + busy: boolean; +}): React.ReactElement => { + const [selectOptions, setSelectOptions] = React.useState([]); + + const [selectItemPlaceholder, setSelectBoardPlaceholder] = React.useState(''); + + const selectOption = React.useCallback( + (boardOpt: BoardOption | null) => { + onItemSelect(boardOpt?.value ?? null); + }, + [onItemSelect] + ); + + React.useEffect(() => { + // if there is activity going on, skip updating the boards (avoid flickering) + if (busy) { + return; + } + + let placeholderTxt = nls.localize( + 'arduino/certificate/selectBoard', + 'Select a board...' + ); + const updatableBoards = boardList.boards.filter((item) => { + const fqbn = item.board.fqbn; + return fqbn && updatableFqbns.includes(fqbn); + }); + let selBoard = -1; + + const boardOptions: BoardOption[] = updatableBoards.map((item, i) => { + if (selectedItem === item) { + selBoard = i; + } + return { + label: nls.localize( + 'arduino/certificate/boardAtPort', + '{0} at {1}', + item.board.name, + item.port.address ?? '' + ), + value: item, + }; + }); + + if (boardOptions.length === 0) { + placeholderTxt = nls.localize( + 'arduino/certificate/noSupportedBoardConnected', + 'No supported board connected' + ); + } + + setSelectBoardPlaceholder(placeholderTxt); + setSelectOptions(boardOptions); + + if (selectedItem) { + selBoard = updatableBoards.findIndex((board) => + boardListItemEquals(board, selectedItem) + ); + } + + selectOption(boardOptions[selBoard] || null); + }, [busy, boardList, selectOption, updatableFqbns, selectedItem]); + return ( + + ); +}; diff --git a/arduino-ide-extension/src/browser/dialogs/certificate-uploader/utils.ts b/arduino-ide-extension/src/browser/dialogs/certificate-uploader/utils.ts new file mode 100644 index 000000000..87ff9830d --- /dev/null +++ b/arduino-ide-extension/src/browser/dialogs/certificate-uploader/utils.ts @@ -0,0 +1,38 @@ +export const arduinoCert = 'arduino.cc:443'; + +export function sanifyCertString(cert: string): string { + const regex = /^(?:.*:\/\/)*(\S+\.+[^:]*):*(\d*)*$/gm; + + const m = regex.exec(cert); + + if (!m) { + return ''; + } + + const domain = m[1] || ''; + const port = m[2] || '443'; + + if (domain.length === 0 || port.length === 0) { + return ''; + } + + return `${domain}:${port}`; +} + +export function certificateList(certificates: string): string[] { + let certs = certificates + .split(',') + .map((cert) => sanifyCertString(cert.trim())) + .filter((cert) => { + // remove empty certificates + if (!cert || cert.length === 0) { + return false; + } + return true; + }); + + // add arduino certificate at the top of the list + certs = certs.filter((cert) => cert !== arduinoCert); + certs.unshift(arduinoCert); + return certs; +} diff --git a/arduino-ide-extension/src/browser/dialogs/cloud-share-sketch-dialog.tsx b/arduino-ide-extension/src/browser/dialogs/cloud-share-sketch-dialog.tsx new file mode 100644 index 000000000..133cf249a --- /dev/null +++ b/arduino-ide-extension/src/browser/dialogs/cloud-share-sketch-dialog.tsx @@ -0,0 +1,193 @@ +import { ClipboardService } from '@theia/core/lib/browser/clipboard-service'; +import { DialogProps } from '@theia/core/lib/browser/dialogs'; +import { TreeNode } from '@theia/core/lib/browser/tree/tree'; +import { ReactWidget } from '@theia/core/lib/browser/widgets/react-widget'; +import { nls } from '@theia/core/lib/common/nls'; +import { MaybePromise } from '@theia/core/lib/common/types'; +import { Message } from '@theia/core/shared/@phosphor/messaging'; +import { Widget } from '@theia/core/shared/@phosphor/widgets'; +import React from '@theia/core/shared/react'; +import { CreateApi } from '../create/create-api'; +import { AbstractDialog } from '../theia/dialogs/dialogs'; + +const RadioButton = (props: { + id: string; + changed: (evt: React.BaseSyntheticEvent) => void; + value: string; + isSelected: boolean; + isDisabled: boolean; + label: string; +}) => { + return ( +

+ + +

+ ); +}; + +export const ShareSketchComponent = ({ + treeNode, + createApi, + domain = 'https://create.arduino.cc', + writeClipboard, +}: { + // eslint-disable-next-line @typescript-eslint/no-explicit-any + treeNode: any; + createApi: CreateApi; + domain?: string; + writeClipboard: (text: string) => MaybePromise; +}): React.ReactElement => { + const [loading, setLoading] = React.useState(false); + + const radioChangeHandler = async (event: React.BaseSyntheticEvent) => { + setLoading(true); + const sketch = await createApi.editSketch({ + id: treeNode.sketchId, + params: { + is_public: event.target.value === 'private' ? false : true, + }, + }); + // setPublicVisibility(sketch.is_public); + treeNode.isPublic = sketch.is_public; + setLoading(false); + }; + + const sketchLink = `${domain}/editor/_/${treeNode.sketchId}/preview`; + const embedLink = ``; + + return ( +
+

+ {nls.localize( + 'arduino/cloud/chooseSketchVisibility', + 'Choose visibility of your Sketch:' + )} +

+ + + + {treeNode.isPublic && ( +
+

{nls.localize('arduino/cloud/link', 'Link:')}

+
+ + +
+

{nls.localize('arduino/cloud/embed', 'Embed:')}

+
+