From 4054e822ed8bd96183de24213eabf18ca8cfce8e Mon Sep 17 00:00:00 2001 From: lsileoni Date: Tue, 2 Apr 2024 18:25:21 +0300 Subject: [PATCH 0001/2119] Barebones x86emu skeleton --- incubator/x86emu/LICENSE | 22 + incubator/x86emu/imagegen/Dockerfile | 91 ++ .../x86emu/imagegen/config/networking.sh | 5 + incubator/x86emu/make_container/Dockerfile | 20 + incubator/x86emu/sandbox/.clang-format | 208 +++ incubator/x86emu/sandbox/canva.html | 110 ++ incubator/x86emu/sandbox/fifotest.cpp | 82 + incubator/x86emu/sandbox/sound.c | 2 + incubator/x86emu/v86starter.sh | 40 + incubator/x86emu/www/index.html | 96 ++ incubator/x86emu/www/js/Instance.mjs | 73 + incubator/x86emu/www/js/InstanceManager.mjs | 136 ++ incubator/x86emu/www/main.js | 44 + incubator/x86emu/www/static/.gitkeep | 0 incubator/x86emu/www/third-party/libv86.js | 626 ++++++++ incubator/x86emu/www/third-party/starter.js | 1417 +++++++++++++++++ incubator/x86emu/www/third-party/xterm.css | 218 +++ incubator/x86emu/www/third-party/xterm.js | 2 + 18 files changed, 3192 insertions(+) create mode 100644 incubator/x86emu/LICENSE create mode 100644 incubator/x86emu/imagegen/Dockerfile create mode 100644 incubator/x86emu/imagegen/config/networking.sh create mode 100644 incubator/x86emu/make_container/Dockerfile create mode 100644 incubator/x86emu/sandbox/.clang-format create mode 100644 incubator/x86emu/sandbox/canva.html create mode 100644 incubator/x86emu/sandbox/fifotest.cpp create mode 100644 incubator/x86emu/sandbox/sound.c create mode 100755 incubator/x86emu/v86starter.sh create mode 100644 incubator/x86emu/www/index.html create mode 100644 incubator/x86emu/www/js/Instance.mjs create mode 100644 incubator/x86emu/www/js/InstanceManager.mjs create mode 100755 incubator/x86emu/www/main.js create mode 100644 incubator/x86emu/www/static/.gitkeep create mode 100644 incubator/x86emu/www/third-party/libv86.js create mode 100644 incubator/x86emu/www/third-party/starter.js create mode 100644 incubator/x86emu/www/third-party/xterm.css create mode 100644 incubator/x86emu/www/third-party/xterm.js diff --git a/incubator/x86emu/LICENSE b/incubator/x86emu/LICENSE new file mode 100644 index 0000000000..5033d6de0b --- /dev/null +++ b/incubator/x86emu/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2012, The v86 contributors +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/incubator/x86emu/imagegen/Dockerfile b/incubator/x86emu/imagegen/Dockerfile new file mode 100644 index 0000000000..8ad5475742 --- /dev/null +++ b/incubator/x86emu/imagegen/Dockerfile @@ -0,0 +1,91 @@ +FROM i386/debian:buster + +ENV DEBIAN_FRONTEND noninteractive + +# Update and install necessary packages +RUN apt update && \ + apt --yes --no-install-recommends install \ + linux-image-686 grub2 systemd \ + libterm-readline-perl-perl \ + gcc make libc6-dev \ + unzip bzip2 xz-utils \ + fluxbox \ + i3-wm \ + cmake \ + fuse \ + xorg xserver-xorg-input-kbd xserver-xorg-input-mouse xserver-xorg-input-evdev \ + xserver-xorg-video-fbdev xserver-xorg-video-vesa \ + xserver-xorg x11-xserver-utils xinit dbus-x11 \ + libgdk-pixbuf2.0 libpango-1.0 libpangocairo-1.0 libgtk2.0-bin \ + libc-l10n locales \ + fonts-noto fonts-droid-fallback \ + strace file xterm vim apt-file \ + dhcpcd5 \ + ca-certificates \ + git \ + wget curl \ + net-tools netcat \ + wmctrl xdotool \ + libssl-dev \ + mesa-utils libgl1-mesa-dri \ + && \ + touch /root/.Xdefaults && \ + echo "en_US.UTF-8 UTF-8" >> /etc/locale.gen && \ + locale-gen && \ + echo 'LANG="en_US.UTF-8"' > /etc/default/locale && \ + chsh -s /bin/bash && \ + echo "root:root" | chpasswd && \ + mkdir -p /etc/systemd/system/serial-getty@ttyS0.service.d/ && \ + systemctl enable serial-getty@ttyS0.service && \ + rm /lib/systemd/system/getty.target.wants/getty-static.service && \ + rm /etc/motd /etc/issue && \ + systemctl disable systemd-timesyncd.service && \ + systemctl disable apt-daily.timer && \ + systemctl disable apt-daily-upgrade.timer && \ + systemctl disable dhcpcd.service && \ + echo "tmpfs /tmp tmpfs nodev,nosuid 0 0" >> /etc/fstab && \ + cd /root/ && \ + wget http://www.math.utah.edu/~mayer/linux/nbench-byte-2.2.3.tar.gz && \ + tar xfv nbench-byte-2.2.3.tar.gz && \ + rm nbench-byte-2.2.3.tar.gz && \ + mv nbench-byte-2.2.3 bench && \ + cd bench && \ + make + +# Copy necessary configuration files +COPY getty-noclear.conf getty-override.conf /etc/systemd/system/getty@tty1.service.d/ +COPY getty-autologin-serial.conf /etc/systemd/system/serial-getty@ttyS0.service.d/ +COPY logind.conf /etc/systemd/logind.conf +# COPY xinitrc /root/.xinitrc +COPY xorg.conf /etc/X11/ +COPY networking.sh /root/ +COPY boot-9p /etc/initramfs-tools/scripts/boot-9p + +# this needs to be commented out in order to boot from hdd +RUN printf '%s\n' 9p 9pnet 9pnet_virtio virtio virtio_ring virtio_pci | tee -a /etc/initramfs-tools/modules && \ + echo 'BOOT=boot-9p' | tee -a /etc/initramfs-tools/initramfs.conf && \ + update-initramfs -u + +# Clean up unnecessary files +RUN apt-get --yes clean && \ + rm -r /var/lib/apt/lists/* && \ + rm -r /usr/share/doc/* && \ + rm -r /usr/share/man/* && \ + rm -r /usr/share/locale/?? && \ + rm /var/log/*.log /var/log/lastlog /var/log/wtmp /var/log/apt/*.log /var/log/apt/*.xz + +# Install Tailscale +RUN curl -fsSL https://tailscale.com/install.sh | sh +RUN chmod +x /root/networking.sh + +# Install Go and puter-fuse +RUN wget https://go.dev/dl/go1.22.1.linux-386.tar.gz && \ + tar -C /usr/local -xzf go1.22.1.linux-386.tar.gz && \ + rm go1.22.1.linux-386.tar.gz && \ + export PATH=$PATH:/usr/local/go/bin && \ + go install github.com/HeyPuter/puter-fuse@v1.0.0 && \ + mv /root/go/bin/puter-fuse /usr/local/bin && \ + rm -rf /root/go && \ + rm -f /go1.22.1.linux-386.tar.gz + +RUN echo "kernel.printk = 3 4 1 3" >>/etc/sysctl.conf diff --git a/incubator/x86emu/imagegen/config/networking.sh b/incubator/x86emu/imagegen/config/networking.sh new file mode 100644 index 0000000000..a1f4fcd26e --- /dev/null +++ b/incubator/x86emu/imagegen/config/networking.sh @@ -0,0 +1,5 @@ +rmmod ne2k-pci && modprobe ne2k-pci +ifconfig enp0s5 192.168.1.5 netmask 255.255.255.0 up +route add default gw 192.168.1.1 +echo "nameserver 1.1.1.1" > /etc/resolv.conf +dhcpcd -w4 enp0s5 diff --git a/incubator/x86emu/make_container/Dockerfile b/incubator/x86emu/make_container/Dockerfile new file mode 100644 index 0000000000..dbd9bdcb45 --- /dev/null +++ b/incubator/x86emu/make_container/Dockerfile @@ -0,0 +1,20 @@ +FROM library/node:lts-bookworm + +WORKDIR /app + +RUN apt-get update && \ + apt-get install -y nodejs nasm gdb unzip p7zip-full openjdk-17-jre wget python3 qemu-system-x86 git git-core build-essential libc6-dev-i386-cross libc6-dev-i386 clang curl time + +RUN curl https://sh.rustup.rs -sSf | sh -s -- -y +RUN /root/.cargo/bin/rustup toolchain install stable && \ + /root/.cargo/bin/rustup target add wasm32-unknown-unknown && \ + /root/.cargo/bin/rustup component add rustfmt-preview && \ + /root/.cargo/bin/rustup update && /root/.cargo/bin/rustup update nightly + +RUN git clone https://github.com/copy/v86 + +WORKDIR /app/v86 + +ENV PATH="$PATH:/root/.cargo/bin" + +RUN make all diff --git a/incubator/x86emu/sandbox/.clang-format b/incubator/x86emu/sandbox/.clang-format new file mode 100644 index 0000000000..a0349196cc --- /dev/null +++ b/incubator/x86emu/sandbox/.clang-format @@ -0,0 +1,208 @@ +--- +Language: Cpp +# BasedOnStyle: LLVM +AccessModifierOffset: 0 +AlignAfterOpenBracket: Align +AlignArrayOfStructures: None +AlignConsecutiveAssignments: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: true +AlignConsecutiveBitFields: + Enabled: false + AcrossEmptyLines: false + AcrossComments: false + AlignCompound: false + PadOperators: false +AlignConsecutiveDeclarations: + Enabled: true + AcrossEmptyLines: true + AcrossComments: true + AlignCompound: true + PadOperators: true +AlignConsecutiveMacros: + Enabled: true + AcrossEmptyLines: true + AcrossComments: true + AlignCompound: true + PadOperators: true +AlignEscapedNewlines: Right +AlignOperands: Align +AlignTrailingComments: + Kind: Always + OverEmptyLines: 0 +AllowAllArgumentsOnNextLine: true +AllowAllParametersOfDeclarationOnNextLine: true +AllowShortBlocksOnASingleLine: Never +AllowShortCaseLabelsOnASingleLine: false +AllowShortEnumsOnASingleLine: true +AllowShortFunctionsOnASingleLine: Empty +AllowShortIfStatementsOnASingleLine: Never +AllowShortLambdasOnASingleLine: All +AllowShortLoopsOnASingleLine: false +AlwaysBreakAfterDefinitionReturnType: None +AlwaysBreakAfterReturnType: None +AlwaysBreakBeforeMultilineStrings: false +AlwaysBreakTemplateDeclarations: MultiLine +AttributeMacros: + - __capability +BinPackArguments: true +BinPackParameters: true +BitFieldColonSpacing: Both +BraceWrapping: + AfterCaseLabel: false + AfterClass: false + AfterControlStatement: Never + AfterEnum: false + AfterExternBlock: false + AfterFunction: false + AfterNamespace: false + AfterObjCDeclaration: false + AfterStruct: false + AfterUnion: false + BeforeCatch: false + BeforeElse: false + BeforeLambdaBody: false + BeforeWhile: false + IndentBraces: false + SplitEmptyFunction: true + SplitEmptyRecord: true + SplitEmptyNamespace: true +BreakAfterAttributes: Never +BreakAfterJavaFieldAnnotations: false +BreakArrays: true +BreakBeforeBinaryOperators: None +BreakBeforeConceptDeclarations: Always +BreakBeforeBraces: Allman +BreakBeforeInlineASMColon: OnlyMultiline +BreakBeforeTernaryOperators: true +BreakConstructorInitializers: BeforeColon +BreakInheritanceList: BeforeColon +BreakStringLiterals: true +ColumnLimit: 100 +CommentPragmas: '^ IWYU pragma:' +CompactNamespaces: false +ConstructorInitializerIndentWidth: 4 +ContinuationIndentWidth: 4 +Cpp11BracedListStyle: true +DerivePointerAlignment: false +DisableFormat: false +EmptyLineAfterAccessModifier: Never +EmptyLineBeforeAccessModifier: Always +ExperimentalAutoDetectBinPacking: false +FixNamespaceComments: true +ForEachMacros: + - foreach + - Q_FOREACH + - BOOST_FOREACH +IfMacros: + - KJ_IF_MAYBE +IncludeBlocks: Merge +IncludeIsMainRegex: '(Test)?$' +IncludeIsMainSourceRegex: '' +IndentAccessModifiers: true +IndentCaseBlocks: false +IndentCaseLabels: true +IndentExternBlock: AfterExternBlock +IndentGotoLabels: true +IndentPPDirectives: None +IndentRequiresClause: true +IndentWidth: 4 +IndentWrappedFunctionNames: false +InsertBraces: false +InsertNewlineAtEOF: true +InsertTrailingCommas: None +IntegerLiteralSeparator: + Binary: 0 + BinaryMinDigits: 0 + Decimal: 0 + DecimalMinDigits: 0 + Hex: 0 + HexMinDigits: 0 +JavaScriptQuotes: Leave +JavaScriptWrapImports: true +KeepEmptyLinesAtTheStartOfBlocks: false +LambdaBodyIndentation: Signature +LineEnding: DeriveLF +MacroBlockBegin: '' +MacroBlockEnd: '' +MaxEmptyLinesToKeep: 1 +NamespaceIndentation: All +ObjCBinPackProtocolList: Auto +ObjCBlockIndentWidth: 2 +ObjCBreakBeforeNestedBlockParam: true +ObjCSpaceAfterProperty: false +ObjCSpaceBeforeProtocolList: true +PackConstructorInitializers: BinPack +PenaltyBreakAssignment: 2 +PenaltyBreakBeforeFirstCallParameter: 19 +PenaltyBreakComment: 300 +PenaltyBreakFirstLessLess: 120 +PenaltyBreakOpenParenthesis: 0 +PenaltyBreakString: 1000 +PenaltyBreakTemplateDeclaration: 10 +PenaltyExcessCharacter: 1000000 +PenaltyIndentedWhitespace: 0 +PenaltyReturnTypeOnItsOwnLine: 60 +PointerAlignment: Left +PPIndentWidth: 1 +QualifierAlignment: Left +ReferenceAlignment: Pointer +ReflowComments: true +RemoveBracesLLVM: false +RemoveSemicolon: false +RequiresClausePosition: OwnLine +RequiresExpressionIndentation: OuterScope +SeparateDefinitionBlocks: Leave +ShortNamespaceLines: 1 +SortIncludes: Never +SortJavaStaticImport: Before +SortUsingDeclarations: LexicographicNumeric +SpaceAfterCStyleCast: false +SpaceAfterLogicalNot: false +SpaceAfterTemplateKeyword: true +SpaceAroundPointerQualifiers: Default +SpaceBeforeAssignmentOperators: true +SpaceBeforeCaseColon: false +SpaceBeforeCpp11BracedList: false +SpaceBeforeCtorInitializerColon: true +SpaceBeforeInheritanceColon: true +SpaceBeforeParens: ControlStatements +SpaceBeforeParensOptions: + AfterControlStatements: true + AfterForeachMacros: true + AfterFunctionDefinitionName: false + AfterFunctionDeclarationName: false + AfterIfMacros: true + AfterOverloadedOperator: false + AfterRequiresInClause: false + AfterRequiresInExpression: false + BeforeNonEmptyParentheses: false +SpaceBeforeRangeBasedForLoopColon: true +SpaceBeforeSquareBrackets: false +SpaceInEmptyBlock: false +SpacesBeforeTrailingComments: 1 +SpacesInAngles: Never +SpacesInContainerLiterals: true +SpacesInLineCommentPrefix: + Minimum: 1 + Maximum: -1 +SpacesInSquareBrackets: false +Standard: Latest +StatementAttributeLikeMacros: + - Q_EMIT +StatementMacros: + - Q_UNUSED + - QT_REQUIRE_VERSION +TabWidth: 4 +UseTab: Never +WhitespaceSensitiveMacros: + - BOOST_PP_STRINGIZE + - CF_SWIFT_NAME + - NS_SWIFT_NAME + - PP_STRINGIZE + - STRINGIZE +... + diff --git a/incubator/x86emu/sandbox/canva.html b/incubator/x86emu/sandbox/canva.html new file mode 100644 index 0000000000..9a7738d852 --- /dev/null +++ b/incubator/x86emu/sandbox/canva.html @@ -0,0 +1,110 @@ + + + + + +Canvas Manipulation + + + +
+ + + + + +
+
+
+ + + + diff --git a/incubator/x86emu/sandbox/fifotest.cpp b/incubator/x86emu/sandbox/fifotest.cpp new file mode 100644 index 0000000000..1885f88282 --- /dev/null +++ b/incubator/x86emu/sandbox/fifotest.cpp @@ -0,0 +1,82 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +const char* PIPE_NAME = "/tmp/bash_pipe"; + +int main() +{ + mkfifo(PIPE_NAME, 0666); + + while (true) + { + int pipe_fd = open(PIPE_NAME, O_RDONLY); + if (pipe_fd == -1) + { + perror("open"); + exit(EXIT_FAILURE); + } + + std::string command; + char buffer[128]; + ssize_t bytes_read; + while ((bytes_read = read(pipe_fd, buffer, sizeof(buffer))) > 0) + { + command.append(buffer, bytes_read); + } + close(pipe_fd); + + int pipe_to_child[2]; + int pipe_from_child[2]; + + if (pipe(pipe_to_child) == -1 || pipe(pipe_from_child) == -1) + { + std::cerr << "Failed to create pipes\n"; + exit(EXIT_FAILURE); + } + + pid_t pid = fork(); + + if (pid < 0) + { + std::cerr << "Fork failed\n"; + exit(EXIT_FAILURE); + } + else if (pid == 0) + { + close(pipe_to_child[1]); + close(pipe_from_child[0]); + dup2(pipe_to_child[0], STDIN_FILENO); + dup2(pipe_from_child[1], STDOUT_FILENO); + execl("/bin/bash", "/bin/bash", "-i", nullptr); + perror("exec"); + exit(EXIT_FAILURE); + } + else + { + close(pipe_to_child[0]); + close(pipe_from_child[1]); + write(pipe_to_child[1], command.c_str(), command.size()); + close(pipe_to_child[1]); + char output_buffer[128]; + ssize_t output_bytes_read; + std::ofstream pipe_out(PIPE_NAME, std::ofstream::trunc); + while ((output_bytes_read = + read(pipe_from_child[0], output_buffer, sizeof(output_buffer))) > 0) + { + pipe_out.write(output_buffer, output_bytes_read); + } + close(pipe_from_child[0]); + pipe_out.close(); + } + } + unlink(PIPE_NAME); + + return 0; +} diff --git a/incubator/x86emu/sandbox/sound.c b/incubator/x86emu/sandbox/sound.c new file mode 100644 index 0000000000..bd15651221 --- /dev/null +++ b/incubator/x86emu/sandbox/sound.c @@ -0,0 +1,2 @@ +// Compile and pipe into aplay in emu for sound check +main(i){for(i=0;;++i)putchar((i+(i>>2)|(i>>8)|(i>>6)));} diff --git a/incubator/x86emu/v86starter.sh b/incubator/x86emu/v86starter.sh new file mode 100755 index 0000000000..84b4cda6ef --- /dev/null +++ b/incubator/x86emu/v86starter.sh @@ -0,0 +1,40 @@ +#!/usr/bin/env bash + +ROOT_DIR="$(pwd)" + +mkdir -p "$ROOT_DIR/vm" +cd "$ROOT_DIR/vm" || exit +docker build . -t v86builder +docker run --name v86build v86builder +mkdir -p "$ROOT_DIR/vm/v86" +docker cp v86build:/app/v86 "$ROOT_DIR/vm/" +docker rm v86build + +# Overwrite v86'd debian Dockerfile with our own +cat "$ROOT_DIR/imagegen/Dockerfile" > "$ROOT_DIR/vm/v86/tools/docker/debian/Dockerfile" + +# Navigate to the Dockerfile directory +cd "$ROOT_DIR/vm/v86/tools/docker/debian" || exit + +# Build the container which will be used to serve v86 +chmod +x build-container.sh +./build-container.sh + +# Build the state of the VM +chmod +x build-state.js +./build-state.js + +# Make project directories +mkdir -p "$ROOT_DIR/www/third-party" +mkdir -p "$ROOT_DIR/www/static" + +# Copy necessary files to deployment directory +cp "$ROOT_DIR/vm/v86/build/libv86.js" "$ROOT_DIR/www/third-party/libv86.js" +cp "$ROOT_DIR/vm/v86/build/v86.wasm" "$ROOT_DIR/www/third-party/v86.wasm" +cp "$ROOT_DIR/vm/v86/static/debian-state-base.bin" "$ROOT_DIR/www/images/image.bin" +cp -r "$ROOT_DIR/vm/v86/static/debian-9p-rootfs-flat/" "$ROOT_DIR/www/images/9p-rootfs/" + +# Start a HTTP server +cd "$ROOT_DIR/www/" || exit +echo "Opening a server on port 8080" +python3 -m http.server 8080 diff --git a/incubator/x86emu/www/index.html b/incubator/x86emu/www/index.html new file mode 100644 index 0000000000..68cab0f7c4 --- /dev/null +++ b/incubator/x86emu/www/index.html @@ -0,0 +1,96 @@ + + + + + + + + + + + +
+
+ + + diff --git a/incubator/x86emu/www/js/Instance.mjs b/incubator/x86emu/www/js/Instance.mjs new file mode 100644 index 0000000000..cbb75e4682 --- /dev/null +++ b/incubator/x86emu/www/js/Instance.mjs @@ -0,0 +1,73 @@ +import * as libv86 from '../third-party/libv86.js'; +/** + * Class representing an Instance of an emulator machine. + */ +class Instance { + /** + * Create an Instance. + * @param {Object} options - Options for configuring the instance. + * @param {boolean} [options.term=true] - Terminal option. + * @param {boolean} [options.screen=false] - Screen option. + * @param {number} [options.memory=1024] - Memory size for the instance; must be power of two. + * @param {HTMLElement} [options.spawnRoot=undefined] - Html element where instance should be spawned. + * @param {boolean} [options.autoStart=true] - Whether to automatically start the instance. + * @param {string} [options.remote="./"] - Remote URL, defaults to origin. + * @param {string} [options.wsUrl=""] - Websocket URL option for communication with the outside world. + * @throws Will throw an error if remote URL does not end with a slash. @throws Will throw an error if the amount of memory provided is not a power of two. + */ + constructor(options) { + const defaultOptions = { + term: true, + screen: false, + memory: 1024, + spawnRoot: undefined, + autoStart: true, + remote: "./", + instanceName: [...Array(10)].map(() => Math.random().toString(36)[2]).join(''), + wsUrl: "", + }; + const instanceOptions = { ...defaultOptions, ...options }; + + if (!instanceOptions.remote.endsWith('/')) + throw new Error("Remote URL must end with a slash"); + if (typeof self !== 'undefined' && self.crypto) { + this.instanceID = self.crypto.randomUUID(); + } else { + this.instanceID = "Node"; + } + this.terminals = []; + let v86Options = { + wasm_path: instanceOptions.remote + "third-party/v86.wasm", + preserve_mac_from_state_image: true, + memory_size: instanceOptions.memory * 1024 * 1024, + vga_memory_size: 8 * 1024 * 1024, + initial_state: { url: instanceOptions.remote + "static/image.bin" }, + filesystem: { baseurl: instanceOptions.remote + "static/9p-rootfs/" }, + autostart: instanceOptions.autoStart, + }; + if (!(instanceOptions.wsUrl === "")) + v86Options.network_relay_url = instanceOptions.wsUrl; + if (!((Math.log(v86Options.memory_size) / Math.log(2)) % 1 === 0)) + throw new Error("Amount of memory provided isn't a power of two"); + if (instanceOptions.screen === true) { + instanceOptions.spawnRoot.appendChild((() => { + const div = document.createElement("div"); + div.setAttribute("id", instanceOptions.instanceName + '-screen'); + + const child_div = document.createElement("div"); + child_div.setAttribute("style", "white-space: pre; font: 14px monospace; line-height: 14px"); + + const canvas = document.createElement("canvas"); + canvas.setAttribute("style", "display: none"); + + div.appendChild(child_div); + div.appendChild(canvas); + return div; + })()); + v86Options.screen_container = document.getElementById(instanceOptions.instanceName + '-screen'); + } + this.vm = new libv86.V86(v86Options); + } +} + +export default Instance diff --git a/incubator/x86emu/www/js/InstanceManager.mjs b/incubator/x86emu/www/js/InstanceManager.mjs new file mode 100644 index 0000000000..577d068395 --- /dev/null +++ b/incubator/x86emu/www/js/InstanceManager.mjs @@ -0,0 +1,136 @@ +import Instance from "./Instance.mjs" + +/** + * Class representing the basic interface for managing instances of emulated machines. + */ +class InstanceManager { + /** + * Create an Instance Manager. + * @param {Object} [options] - Options for configuring the instance manager. + * @param {boolean} [options.screen=true] - Spawn screen option. + * @param {boolean} [options.term=false] - Spawn terminal option. + * @param {string} [options.instanceName="Host"] - Name of the instance. + * @param {number} [options.memory=1024] - Memory size for the instance; must be power of two. + * @param {HTMLElement} [options.spawnRoot=undefined] - Htlm element where instance should be spawned. + * @param {boolean} [options.autoStart=true] - Whether to automatically start the instance. + * @param {string} [options.remote="./"] - Remote URL, defaults to origin. + * @param {string} [options.wsUrl=""] - Websocket URL option. + */ + constructor(options) { + const defaultOptions = { + term: true, + screen: false, + instanceName: "Host", + memory: 1024, + spawnRoot: undefined, + autoStart: true, + remote: "./", + wsUrl: "", + }; + const instanceOptions = { ...defaultOptions, ...options }; + this.instances = {}; + this.instanceNames = []; + this.curr_inst = 0; + this.instanceNames.push(instanceOptions.instanceName); + this.instances[instanceOptions.instanceName] = this.initInstance(instanceOptions); + } + /** + * Initialize an instance with given options. + * @param {Object} options - Options for configuring the instance. + * @returns {Promise} - Resolves with the initialized instance. + */ + initInstance(options) { + return new Instance(options); + } + /** + * Continue running a suspended instance. + * @param {string} instName - instName of the instance to continue. + */ + async continueInstance(instName) { + var instance = await this.getInstanceByinstName(instName); + if (!instance.vm.cpu_is_running) + await instance.vm.run(); + } + /** + * Suspend a running instance. + * @param {string} instName - instName of the instance to suspend. + */ + async suspendInstance(instName) { + var instance = await this.getInstanceByinstName(instName); + if (instance.vm.cpu_is_running) + await instance.vm.stop(); + } + /** + * Save the state of a running instance. + * @param {string} instName - instName of the instance to save state. + * @returns {Promise} - Promise resolving once state is saved. + */ + async saveState(instName) { + const instance = this.getInstanceByinstName(instName); + if (instance.vm.cpu_is_running) + return instance.vm.save_state(); + } + /** + * Load the state of a previously saved instance. + * @param {string} instName - instName of the instance to load state. + * @param {any} state - State to load. + * @returns {Promise} - Promise resolving once state is loaded. + */ + async loadState(instName, state) { + const instance = this.getInstanceByinstName(instName); + if (instance.vm.cpu_is_running) + await instance.vm.save_state(state); + } + /** + * Connect two instances for communication through NIC's. + * @param {string} destinationinstName - instName of the destination instance. + * @param {string} sourceinstName - instName of the source instance. + */ + async connectInstances(destinationinstName, sourceinstName) { + const destinationInstance = this.getInstanceByinstName(destinationinstName); + const sourceInstance = this.getInstanceByinstName(sourceinstName); + destinationInstance.add_listener("net0-send", (data) => { + source.bus.send("net0-receive", data); + }); + sourceInstance.add_listener("net0-send", (data) => { + destination.bus.send("net0-receive", data); + }); + } + /** + * Execute a command within an instance. + * @param {Object} inst - Instance object. + * @param {string} cmd - Command to execute. + * @param {Object} env - Environment variables. + * @param {number} [timeout=60] - Timeout for the command execution. + */ + async exec(inst, cmd, env, timeout = 60) { + // TODO: instNamed pipes on the instance would make this super nice so multiple terminals can be had + } + /** + * Destroy a specific instance. + * @param {string} instName - instName of the instance to destroy. + */ + async destroyInstance(instName) { + await this.getInstanceByinstName(instName).destroy(); + } + /** + * Destroy all instances. + */ + async destroyInstances() { + for (const instance in this.instances) + destroyInstance(instance) + } + /** + * Get an instance by its instName. + * @param {string} instName - instName of the instance. + * @returns {Object} - The instance object. + * @throws Will throw an error if the instance instName is not found. + */ + async getInstanceByinstName(instName) { + if (!(instName in this.instances)) + throw Error("getInstance: instName not found in instances object"); + return this.instances[instName]; + } +} + +export default InstanceManager diff --git a/incubator/x86emu/www/main.js b/incubator/x86emu/www/main.js new file mode 100755 index 0000000000..f8257c43cf --- /dev/null +++ b/incubator/x86emu/www/main.js @@ -0,0 +1,44 @@ +#!/usr/bin/env node +"use strict"; + +import('./js/InstanceManager.mjs').then(module => { + const InstanceManager = module.default; + + process.stdin.setRawMode(true); + process.stdin.resume(); + process.stdin.setEncoding("utf8"); + + console.log("Now booting, please stand by ..."); + + const manager = new InstanceManager({ screen: false, term: false, spawnRoot: undefined }); + manager.getInstanceByinstName("Host").then(result => { + const hostvm = result.vm; + + hostvm.add_listener("emulator-started", function() { + process.stdout.write("Welcome to psl!"); + }); + + hostvm.add_listener("serial0-output-byte", function(byte) { + var chr = String.fromCharCode(byte); + if (chr <= "~") { + process.stdout.write(chr); + } + }); + + process.stdin.on("data", function(c) { + // ctrl d + if (c === "\u0004") { + hostvm.stop(); + process.stdin.pause(); + } + else { + hostvm.serial0_send(c); + } + }); + }).catch(error => { + console.log(error); + throw Error("Error in getting host inastance, quitting"); + }); +}).catch(error => { + console.error('Error loading InstanceManager:', error); +}); diff --git a/incubator/x86emu/www/static/.gitkeep b/incubator/x86emu/www/static/.gitkeep new file mode 100644 index 0000000000..e69de29bb2 diff --git a/incubator/x86emu/www/third-party/libv86.js b/incubator/x86emu/www/third-party/libv86.js new file mode 100644 index 0000000000..2382f12537 --- /dev/null +++ b/incubator/x86emu/www/third-party/libv86.js @@ -0,0 +1,626 @@ +;(function(){'use strict';function ba(a,b){function c(x){x=x.toString(16);return"#"+"0".repeat(6-x.length)+x}function d(x,C,S,P){x.style.width="";x.style.height="";P&&(x.style.transform="");var aa=x.getBoundingClientRect();P?x.style.transform=(1===C?"":" scaleX("+C+")")+(1===S?"":" scaleY("+S+")"):(0===C%1&&0===S%1?(e.style.imageRendering="crisp-edges",e.style.imageRendering="pixelated",e.style["-ms-interpolation-mode"]="nearest-neighbor"):(e.style.imageRendering="",e.style["-ms-interpolation-mode"]=""),P=window.devicePixelRatio|| +1,0!==P%1&&(C/=P,S/=P));1!==C&&(x.style.width=aa.width*C+"px");1!==S&&(x.style.height=aa.height*S+"px")}console.assert(a,"1st argument must be a DOM container");var e=a.getElementsByTagName("canvas")[0],g=e.getContext("2d",{alpha:!1}),f=a.getElementsByTagName("div")[0],k=document.createElement("div"),l,m,n=1,p=1,t=1,q,z=!1,w,u,I,U=!1,ea=this;a=new Uint16Array([8962,199,252,233,226,228,224,229,231,234,235,232,239,238,236,196,197,201,230,198,244,246,242,251,249,255,214,220,162,163,165,8359,402,225, +237,243,250,241,209,170,186,191,8976,172,189,188,161,171,187,9617,9618,9619,9474,9508,9569,9570,9558,9557,9571,9553,9559,9565,9564,9563,9488,9492,9524,9516,9500,9472,9532,9566,9567,9562,9556,9577,9574,9568,9552,9580,9575,9576,9572,9573,9561,9560,9554,9555,9579,9578,9496,9484,9608,9604,9612,9616,9600,945,223,915,960,931,963,181,964,934,920,937,948,8734,966,949,8745,8801,177,8805,8804,8992,8993,247,8776,176,8729,183,8730,8319,178,9632,160]);for(var Ab=new Uint16Array([32,9786,9787,9829,9830,9827,9824, +8226,9688,9675,9689,9794,9792,9834,9835,9788,9658,9668,8597,8252,182,167,9644,8616,8593,8595,8594,8592,8735,8596,9650,9660]),Ra=[],db,sa=0;256>sa;sa++)db=126sa?Ab[sa]:sa,Ra[sa]=String.fromCharCode(db);g.imageSmoothingEnabled=!1;k.style.position="absolute";k.style.backgroundColor="#ccc";k.style.width="7px";k.style.display="inline-block";f.style.display="block";e.style.display="none";this.bus=b;b.register("screen-set-mode",function(x){this.set_mode(x)},this);b.register("screen-fill-buffer-end", +function(x){this.update_buffer(x)},this);b.register("screen-put-char",function(x){this.put_char(x[0],x[1],x[2],x[3],x[4])},this);b.register("screen-update-cursor",function(x){this.update_cursor(x[0],x[1])},this);b.register("screen-update-cursor-scanline",function(x){this.update_cursor_scanline(x[0],x[1])},this);b.register("screen-clear",function(){this.clear_screen()},this);b.register("screen-set-size-text",function(x){this.set_size_text(x[0],x[1])},this);b.register("screen-set-size-graphical",function(x){this.set_size_graphical(x[0], +x[1],x[2],x[3])},this);this.init=function(){this.set_size_text(80,25);this.timer()};this.make_screenshot=function(){const x=new Image;if(z)x.src=e.toDataURL("image/png");else{const C=[9,16],S=document.createElement("canvas");S.width=u*C[0];S.height=I*C[1];const P=S.getContext("2d");P.imageSmoothingEnabled=!1;P.font=window.getComputedStyle(f).font;P.textBaseline="top";for(let aa=0;aaC;)f.removeChild(f.firstChild);for(;f.childNodes.length=x&&2*x{g.putImageData(C.image_data,C.screen_x-C.buffer_x,C.screen_y-C.buffer_y,C.buffer_x,C.buffer_y,C.buffer_width,C.buffer_height)})};this.init()};const ca=Object.freeze(["shared","exclusive","unlock"]); +function da(a,b,c){this.fs=a;this.bus=c;this.configspace_tagname=[104,111,115,116,57,112];this.configspace_taglen=this.configspace_tagname.length;this.VERSION="9P2000.L";this.msize=this.BLOCKSIZE=8192;this.replybuffer=new Uint8Array(2*this.msize);this.replybuffersize=0;this.fids=[];this.virtio=new h(b,{name:"virtio-9p",pci_id:48,device_id:4169,subsystem_device_id:9,common:{initial_port:43008,queues:[{size_supported:32,notify_offset:0}],features:[0,32,29,28],on_driver_ok:()=>{}},notification:{initial_port:43264, +single_handler:!1,handlers:[d=>{if(0===d){for(;this.virtqueue.has_request();)d=this.virtqueue.pop_request(),this.ReceiveRequest(d);this.virtqueue.notify_me_after(0)}}]},isr_status:{initial_port:42752},device_specific:{initial_port:42496,struct:[{bytes:2,name:"mount tag length",read:()=>this.configspace_taglen,write:()=>{}}].concat(r.range(254).map(d=>({bytes:1,name:"mount tag name "+d,read:()=>this.configspace_tagname[d]||0,write:()=>{}})))}});this.virtqueue=this.virtio.queues[0]} +da.prototype.get_state=function(){var a=[];a[0]=this.configspace_tagname;a[1]=this.configspace_taglen;a[2]=this.virtio;a[3]=this.VERSION;a[4]=this.BLOCKSIZE;a[5]=this.msize;a[6]=this.replybuffer;a[7]=this.replybuffersize;a[8]=this.fids.map(function(b){return[b.inodeid,b.type,b.uid,b.dbg_name]});a[9]=this.fs;return a}; +da.prototype.set_state=function(a){this.configspace_tagname=a[0];this.configspace_taglen=a[1];this.virtio.set_state(a[2]);this.virtqueue=this.virtio.queues[0];this.VERSION=a[3];this.BLOCKSIZE=a[4];this.msize=a[5];this.replybuffer=a[6];this.replybuffersize=a[7];this.fids=a[8].map(function(b){return{inodeid:b[0],type:b[1],uid:b[2],dbg_name:b[3]}});this.fs.set_state(a[9])};da.prototype.Createfid=function(a,b,c,d){return{inodeid:a,type:b,uid:c,dbg_name:d}}; +da.prototype.update_dbg_name=function(a,b){for(const c of this.fids)c.inodeid===a&&(c.dbg_name=b)};da.prototype.Reset=function(){this.fids=[]};da.prototype.BuildReply=function(a,b,c){v.Marshall(["w","b","h"],[c+7,a+1,b],this.replybuffer,0);c+7>=this.replybuffer.length&&y.Debug("Error in 9p: payloadsize exceeds maximum length");this.replybuffersize=c+7};da.prototype.SendError=function(a,b,c){b=v.Marshall(["w"],[c],this.replybuffer,7);this.BuildReply(6,a,b)}; +da.prototype.SendReply=function(a){a.set_next_blob(this.replybuffer.subarray(0,this.replybuffersize));this.virtqueue.push_reply(a);this.virtqueue.flush_replies()}; +da.prototype.ReceiveRequest=async function(a){var b=new Uint8Array(a.length_readable);a.get_next_blob(b);var c={offset:0},d=v.Unmarshall(["w","b","h"],b,c),e=d[0],g=d[1],f=d[2];switch(g){case 8:e=this.fs.GetTotalSize();b=this.fs.GetSpace();d=[16914839];d[1]=this.BLOCKSIZE;d[2]=Math.floor(b/d[1]);d[3]=d[2]-Math.floor(e/d[1]);d[4]=d[2]-Math.floor(e/d[1]);d[5]=this.fs.CountUsedInodes();d[6]=this.fs.CountFreeInodes();d[7]=0;d[8]=256;e=v.Marshall("wwddddddw".split(""),d,this.replybuffer,7);this.BuildReply(g, +f,e);this.SendReply(a);break;case 112:case 12:d=v.Unmarshall(["w","w"],b,c);var k=d[0];c=d[1];y.Debug("[open] fid="+k+", mode="+c);b=this.fids[k].inodeid;var l=this.fs.GetInode(b);y.Debug("file open "+this.fids[k].dbg_name);e=this.fs.OpenInode(b,c);this.fs.AddEvent(this.fids[k].inodeid,function(){y.Debug("file opened "+this.fids[k].dbg_name+" tag:"+f);var t=[];t[0]=l.qid;t[1]=this.msize-24;v.Marshall(["Q","w"],t,this.replybuffer,7);this.BuildReply(g,f,17);this.SendReply(a)}.bind(this));break;case 70:d= +v.Unmarshall(["w","w","s"],b,c);b=d[0];k=d[1];e=d[2];y.Debug("[link] dfid="+b+", name="+e);e=this.fs.Link(this.fids[b].inodeid,this.fids[k].inodeid,e);if(0>e){this.SendError(f,-1===e?"Operation not permitted":"Unknown error: "+-e,-e);this.SendReply(a);break}this.BuildReply(g,f,0);this.SendReply(a);break;case 16:d=v.Unmarshall(["w","s","s","w"],b,c);k=d[0];e=d[1];b=d[2];d=d[3];y.Debug("[symlink] fid="+k+", name="+e+", symgt="+b+", gid="+d);b=this.fs.CreateSymlink(e,this.fids[k].inodeid,b);l=this.fs.GetInode(b); +l.uid=this.fids[k].uid;l.gid=d;v.Marshall(["Q"],[l.qid],this.replybuffer,7);this.BuildReply(g,f,13);this.SendReply(a);break;case 18:d=v.Unmarshall("wswwww".split(""),b,c);k=d[0];e=d[1];c=d[2];b=d[3];var m=d[4];d=d[5];y.Debug("[mknod] fid="+k+", name="+e+", major="+b+", minor="+m);b=this.fs.CreateNode(e,this.fids[k].inodeid,b,m);l=this.fs.GetInode(b);l.mode=c;l.uid=this.fids[k].uid;l.gid=d;v.Marshall(["Q"],[l.qid],this.replybuffer,7);this.BuildReply(g,f,13);this.SendReply(a);break;case 22:d=v.Unmarshall(["w"], +b,c);k=d[0];l=this.fs.GetInode(this.fids[k].inodeid);y.Debug("[readlink] fid="+k+" name="+this.fids[k].dbg_name+" target="+l.symlink);e=v.Marshall(["s"],[l.symlink],this.replybuffer,7);this.BuildReply(g,f,e);this.SendReply(a);break;case 72:d=v.Unmarshall(["w","s","w","w"],b,c);k=d[0];e=d[1];c=d[2];d=d[3];y.Debug("[mkdir] fid="+k+", name="+e+", mode="+c+", gid="+d);b=this.fs.CreateDirectory(e,this.fids[k].inodeid);l=this.fs.GetInode(b);l.mode=c|ha;l.uid=this.fids[k].uid;l.gid=d;v.Marshall(["Q"],[l.qid], +this.replybuffer,7);this.BuildReply(g,f,13);this.SendReply(a);break;case 14:d=v.Unmarshall(["w","s","w","w","w"],b,c);k=d[0];e=d[1];b=d[2];c=d[3];d=d[4];this.bus.send("9p-create",[e,this.fids[k].inodeid]);y.Debug("[create] fid="+k+", name="+e+", flags="+b+", mode="+c+", gid="+d);b=this.fs.CreateFile(e,this.fids[k].inodeid);this.fids[k].inodeid=b;this.fids[k].type=1;this.fids[k].dbg_name=e;l=this.fs.GetInode(b);l.uid=this.fids[k].uid;l.gid=d;l.mode=c;v.Marshall(["Q","w"],[l.qid,this.msize-24],this.replybuffer, +7);this.BuildReply(g,f,17);this.SendReply(a);break;case 52:d=v.Unmarshall("wbwddws".split(""),b,c);k=d[0];b=d[2];e=0===d[4]?Infinity:d[4];d=this.fs.DescribeLock(d[1],d[3],e,d[5],d[6]);y.Debug("[lock] fid="+k+", type="+ca[d.type]+", start="+d.start+", length="+d.length+", proc_id="+d.proc_id);e=this.fs.Lock(this.fids[k].inodeid,d,b);v.Marshall(["b"],[e],this.replybuffer,7);this.BuildReply(g,f,1);this.SendReply(a);break;case 54:d=v.Unmarshall("wbddws".split(""),b,c);k=d[0];e=0===d[3]?Infinity:d[3]; +d=this.fs.DescribeLock(d[1],d[2],e,d[4],d[5]);y.Debug("[getlock] fid="+k+", type="+ca[d.type]+", start="+d.start+", length="+d.length+", proc_id="+d.proc_id);e=this.fs.GetLock(this.fids[k].inodeid,d);e||(e=d,e.type=2);e=v.Marshall(["b","d","d","w","s"],[e.type,e.start,Infinity===e.length?0:e.length,e.proc_id,e.client_id],this.replybuffer,7);this.BuildReply(g,f,e);this.SendReply(a);break;case 24:d=v.Unmarshall(["w","d"],b,c);k=d[0];l=this.fs.GetInode(this.fids[k].inodeid);y.Debug("[getattr]: fid="+ +k+" name="+this.fids[k].dbg_name+" request mask="+d[1]);if(!l||l.status===ia){y.Debug("getattr: unlinked");this.SendError(f,"No such file or directory",2);this.SendReply(a);break}d[0]|=4096;d[0]=d[1];d[1]=l.qid;d[2]=l.mode;d[3]=l.uid;d[4]=l.gid;d[5]=l.nlinks;d[6]=l.major<<8|l.minor;d[7]=l.size;d[8]=this.BLOCKSIZE;d[9]=Math.floor(l.size/512+1);d[10]=l.atime;d[11]=0;d[12]=l.mtime;d[13]=0;d[14]=l.ctime;d[15]=0;d[16]=0;d[17]=0;d[18]=0;d[19]=0;v.Marshall("dQwwwddddddddddddddd".split(""),d,this.replybuffer, +7);this.BuildReply(g,f,153);this.SendReply(a);break;case 26:d=v.Unmarshall("wwwwwddddd".split(""),b,c);k=d[0];l=this.fs.GetInode(this.fids[k].inodeid);y.Debug("[setattr]: fid="+k+" request mask="+d[1]+" name="+this.fids[k].dbg_name);d[1]&1&&(l.mode=d[2]);d[1]&2&&(l.uid=d[3]);d[1]&4&&(l.gid=d[4]);d[1]&16&&(l.atime=Math.floor((new Date).getTime()/1E3));d[1]&32&&(l.mtime=Math.floor((new Date).getTime()/1E3));d[1]&64&&(l.ctime=Math.floor((new Date).getTime()/1E3));d[1]&128&&(l.atime=d[6]);d[1]&256&&(l.mtime= +d[8]);d[1]&8&&await this.fs.ChangeSize(this.fids[k].inodeid,d[5]);this.BuildReply(g,f,0);this.SendReply(a);break;case 50:d=v.Unmarshall(["w","d"],b,c);k=d[0];this.BuildReply(g,f,0);this.SendReply(a);break;case 40:case 116:d=v.Unmarshall(["w","d","w"],b,c);k=d[0];e=d[1];m=d[2];l=this.fs.GetInode(this.fids[k].inodeid);40==g&&y.Debug("[treaddir]: fid="+k+" offset="+e+" count="+m);116==g&&y.Debug("[read]: fid="+k+" ("+this.fids[k].dbg_name+") offset="+e+" count="+m+" fidtype="+this.fids[k].type);if(!l|| +l.status===ia){y.Debug("read/treaddir: unlinked");this.SendError(f,"No such file or directory",2);this.SendReply(a);break}if(2==this.fids[k].type)for(l.caps.lengthl.size&&(m=0),this.bus.send("9p-read-start",[this.fids[k].dbg_name]),d=await this.fs.Read(d, +e,m),this.bus.send("9p-read-end",[this.fids[k].dbg_name,m]),d&&this.replybuffer.set(d,11);v.Marshall(["w"],[m],this.replybuffer,7);this.BuildReply(g,f,4+m);this.SendReply(a);break;case 118:d=v.Unmarshall(["w","d","w"],b,c);k=d[0];e=d[1];m=d[2];d=this.fids[k].dbg_name;y.Debug("[write]: fid="+k+" ("+d+") offset="+e+" count="+m+" fidtype="+this.fids[k].type);if(2===this.fids[k].type){this.SendError(f,"Setxattr not supported",95);this.SendReply(a);break}else await this.fs.Write(this.fids[k].inodeid,e, +m,b.subarray(c.offset));this.bus.send("9p-write-end",[d,m]);v.Marshall(["w"],[m],this.replybuffer,7);this.BuildReply(g,f,4);this.SendReply(a);break;case 74:d=v.Unmarshall(["w","s","w","s"],b,c);e=d[0];b=d[1];c=d[2];d=d[3];y.Debug("[renameat]: oldname="+b+" newname="+d);e=await this.fs.Rename(this.fids[e].inodeid,b,this.fids[c].inodeid,d);if(0>e){this.SendError(f,-2===e?"No such file or directory":-1===e?"Operation not permitted":-39===e?"Directory not empty":"Unknown error: "+-e,-e);this.SendReply(a); +break}this.BuildReply(g,f,0);this.SendReply(a);break;case 76:d=v.Unmarshall(["w","s","w"],b,c);c=d[0];e=d[1];b=d[2];y.Debug("[unlink]: dirfd="+c+" name="+e+" flags="+b);k=this.fs.Search(this.fids[c].inodeid,e);if(-1==k){this.SendError(f,"No such file or directory",2);this.SendReply(a);break}e=this.fs.Unlink(this.fids[c].inodeid,e);if(0>e){this.SendError(f,-39===e?"Directory not empty":-1===e?"Operation not permitted":"Unknown error: "+-e,-e);this.SendReply(a);break}this.BuildReply(g,f,0);this.SendReply(a); +break;case 100:d=v.Unmarshall(["w","s"],b,c);y.Debug("[version]: msize="+d[0]+" version="+d[1]);this.msize=d[0];e=v.Marshall(["w","s"],[this.msize,this.VERSION],this.replybuffer,7);this.BuildReply(g,f,e);this.SendReply(a);break;case 104:d=v.Unmarshall(["w","w","s","s","w"],b,c);k=d[0];e=d[4];y.Debug("[attach]: fid="+k+" afid="+A(d[1])+" uname="+d[2]+" aname="+d[3]);this.fids[k]=this.Createfid(0,1,e,"");l=this.fs.GetInode(this.fids[k].inodeid);v.Marshall(["Q"],[l.qid],this.replybuffer,7);this.BuildReply(g, +f,13);this.SendReply(a);this.bus.send("9p-attach");break;case 108:d=v.Unmarshall(["h"],b,c);y.Debug("[flush] "+f);this.BuildReply(g,f,0);this.SendReply(a);break;case 110:d=v.Unmarshall(["w","w","h"],b,c);k=d[0];m=d[1];var n=d[2];y.Debug("[walk]: fid="+d[0]+" nwfid="+d[1]+" nwname="+n);if(0==n){this.fids[m]=this.Createfid(this.fids[k].inodeid,1,this.fids[k].uid,this.fids[k].dbg_name);v.Marshall(["h"],[0],this.replybuffer,7);this.BuildReply(g,f,2);this.SendReply(a);break}e=[];for(d=0;db;b++)this.ports[b]=this.create_empty_entry();var c=a.memory_size[0];for(b=0;b<<17>>0,8);return 255},function(d,e){A(d>>>0,8);A(e,2)},function(d){A(d>>>0,8);return-1},function(d,e){A(d>>>0,8);A(e>>>0,8)})} +B.prototype.create_empty_entry=function(){return{read8:this.empty_port_read8,read16:this.empty_port_read16,read32:this.empty_port_read32,write8:this.empty_port_write,write16:this.empty_port_write,write32:this.empty_port_write,device:void 0}};B.prototype.empty_port_read8=function(){return 255};B.prototype.empty_port_read16=function(){return 65535};B.prototype.empty_port_read32=function(){return-1};B.prototype.empty_port_write=function(){}; +B.prototype.register_read=function(a,b,c,d,e){c&&(this.ports[a].read8=c);d&&(this.ports[a].read16=d);e&&(this.ports[a].read32=e);this.ports[a].device=b};B.prototype.register_write=function(a,b,c,d,e){c&&(this.ports[a].write8=c);d&&(this.ports[a].write16=d);e&&(this.ports[a].write32=e);this.ports[a].device=b}; +B.prototype.register_read_consecutive=function(a,b,c,d,e,g){function f(){return c.call(this)|d.call(this)<<8}function k(){return e.call(this)|g.call(this)<<8}function l(){return c.call(this)|d.call(this)<<8|e.call(this)<<16|g.call(this)<<24}e&&g?(this.register_read(a,b,c,f,l),this.register_read(a+1,b,d),this.register_read(a+2,b,e,k),this.register_read(a+3,b,g)):(this.register_read(a,b,c,f),this.register_read(a+1,b,d))}; +B.prototype.register_write_consecutive=function(a,b,c,d,e,g){function f(m){c.call(this,m&255);d.call(this,m>>8&255)}function k(m){e.call(this,m&255);g.call(this,m>>8&255)}function l(m){c.call(this,m&255);d.call(this,m>>8&255);e.call(this,m>>16&255);g.call(this,m>>>24)}e&&g?(this.register_write(a,b,c,f,l),this.register_write(a+1,b,d),this.register_write(a+2,b,e,k),this.register_write(a+3,b,g)):(this.register_write(a,b,c,f),this.register_write(a+1,b,d))}; +B.prototype.mmap_read32_shim=function(a){var b=this.cpu.memory_map_read8[a>>>17];return b(a)|b(a+1)<<8|b(a+2)<<16|b(a+3)<<24};B.prototype.mmap_write32_shim=function(a,b){var c=this.cpu.memory_map_write8[a>>>17];c(a,b&255);c(a+1,b>>8&255);c(a+2,b>>16&255);c(a+3,b>>>24)}; +B.prototype.mmap_register=function(a,b,c,d,e,g){A(a>>>0,8);A(b,8);e||(e=this.mmap_read32_shim.bind(this));g||(g=this.mmap_write32_shim.bind(this));for(a>>>=17;0>>0,8),this.get_port_description(a));return c.write32.call(c.device,b)}; +B.prototype.port_read8=function(a){var b=this.ports[a];b.read8===this.empty_port_read8&&(A(a,4),this.get_port_description(a));b=b.read8.call(b.device);A(a);return b};B.prototype.port_read16=function(a){var b=this.ports[a];b.read16===this.empty_port_read16&&(A(a,4),this.get_port_description(a));b=b.read16.call(b.device);A(a);return b};B.prototype.port_read32=function(a){var b=this.ports[a];b.read32===this.empty_port_read32&&(A(a,4),this.get_port_description(a));return b.read32.call(b.device)}; +var ja={4:"PORT_DMA_ADDR_2",5:"PORT_DMA_CNT_2",10:"PORT_DMA1_MASK_REG",11:"PORT_DMA1_MODE_REG",12:"PORT_DMA1_CLEAR_FF_REG",13:"PORT_DMA1_MASTER_CLEAR",32:"PORT_PIC1_CMD",33:"PORT_PIC1_DATA",64:"PORT_PIT_COUNTER0",65:"PORT_PIT_COUNTER1",66:"PORT_PIT_COUNTER2",67:"PORT_PIT_MODE",96:"PORT_PS2_DATA",97:"PORT_PS2_CTRLB",100:"PORT_PS2_STATUS",112:"PORT_CMOS_INDEX",113:"PORT_CMOS_DATA",128:"PORT_DIAG",129:"PORT_DMA_PAGE_2",146:"PORT_A20",160:"PORT_PIC2_CMD",161:"PORT_PIC2_DATA",178:"PORT_SMI_CMD",179:"PORT_SMI_STATUS", +212:"PORT_DMA2_MASK_REG",214:"PORT_DMA2_MODE_REG",218:"PORT_DMA2_MASTER_CLEAR",240:"PORT_MATH_CLEAR",368:"PORT_ATA2_CMD_BASE",496:"PORT_ATA1_CMD_BASE",632:"PORT_LPT2",744:"PORT_SERIAL4",760:"PORT_SERIAL2",884:"PORT_ATA2_CTRL_BASE",888:"PORT_LPT1",1E3:"PORT_SERIAL3",1008:"PORT_FD_BASE",1010:"PORT_FD_DOR",1012:"PORT_FD_STATUS",1013:"PORT_FD_DATA",1014:"PORT_HD_DATA",1015:"PORT_FD_DIR",1016:"PORT_SERIAL1",3320:"PORT_PCI_CMD",3321:"PORT_PCI_REBOOT",3324:"PORT_PCI_DATA",1026:"PORT_BIOS_DEBUG",1296:"PORT_QEMU_CFG_CTL", +1297:"PORT_QEMU_CFG_DATA",45056:"PORT_ACPI_PM_BASE",45312:"PORT_SMB_BASE",35072:"PORT_BIOS_APM"};B.prototype.get_port_description=function(a){return ja[a]?" ("+ja[a]+")":""};function D(a,b){this.stopping=this.running=!1;this.tick_counter=0;this.worker=null;this.cpu=new E(a,b,()=>{this.idle&&this.next_tick(0)});this.bus=a;a.register("cpu-init",this.init,this);a.register("cpu-run",this.run,this);a.register("cpu-stop",this.stop,this);a.register("cpu-restart",this.restart,this);this.register_yield()}D.prototype.run=function(){this.stopping=!1;this.running||(this.running=!0,this.bus.send("emulator-started"));this.next_tick(0)}; +D.prototype.do_tick=function(){if(this.stopping||!this.running)this.stopping=this.running=!1,this.bus.send("emulator-stopped");else{this.idle=!1;var a=this.cpu.main_loop();this.next_tick(a)}};D.prototype.next_tick=function(a){const b=++this.tick_counter;this.idle=!0;this.yield(a,b)};D.prototype.yield_callback=function(a){a===this.tick_counter&&this.do_tick()};D.prototype.stop=function(){this.running&&(this.stopping=!0)};D.prototype.destroy=function(){this.unregister_yield()}; +D.prototype.restart=function(){this.cpu.reset_cpu();this.cpu.load_bios()};D.prototype.init=function(a){this.cpu.init(a,this.bus);this.bus.send("emulator-ready")}; +if("undefined"!==typeof process)D.prototype.yield=function(a,b){1>a?global.setImmediate(c=>this.yield_callback(c),b):setTimeout(c=>this.yield_callback(c),a,b)},D.prototype.register_yield=function(){},D.prototype.unregister_yield=function(){};else if("undefined"!==typeof Worker){function a(){globalThis.onmessage=function(b){const c=b.data.t;1>c?postMessage(b.data.tick):setTimeout(()=>postMessage(b.data.tick),c)}}D.prototype.register_yield=function(){const b=URL.createObjectURL(new Blob(["("+a.toString()+ +")()"],{type:"text/javascript"}));this.worker=new Worker(b);this.worker.onmessage=c=>this.yield_callback(c.data);URL.revokeObjectURL(b)};D.prototype.yield=function(b,c){this.worker.postMessage({t:b,tick:c})};D.prototype.unregister_yield=function(){this.worker&&this.worker.terminate();this.worker=null}}else D.prototype.yield=function(a){setTimeout(()=>{this.do_tick()},a)},D.prototype.register_yield=function(){},D.prototype.unregister_yield=function(){};D.prototype.save_state=function(){return this.cpu.save_state()}; +D.prototype.restore_state=function(a){return this.cpu.restore_state(a)};if("object"===typeof performance&&performance.now)D.microtick=performance.now.bind(performance);else if("function"===typeof require){const {performance:a}=require("perf_hooks");D.microtick=a.now.bind(a)}else D.microtick="object"===typeof process&&process.hrtime?function(){var a=process.hrtime();return 1E3*a[0]+a[1]/1E6}:Date.now;var F=F||{};F.exportSymbol=function(){};F.exportProperty=function(){};var r=r||{};r.pads=function(a,b){return(a||0===a?a+"":"").padEnd(b," ")};r.pad0=function(a,b){return(a||0===a?a+"":"").padStart(b,"0")};r.zeros=function(a){return Array(a).fill(0)};r.range=function(a){return Array.from(Array(a).keys())}; +r.view=function(a,b,c,d){return new Proxy({},{get:function(e,g){e=new a(b.buffer,c,d);const f=e[g];if("function"===typeof f)return f.bind(e);/^\d+$/.test(g);return f},set:function(e,g,f){/^\d+$/.test(g);(new a(b.buffer,c,d))[g]=f;return!0}})};function A(a,b){a=a?a.toString(16):"";return"0x"+r.pad0(a.toUpperCase(),b||1)} +if("undefined"!==typeof crypto&&crypto.getRandomValues){let a=new Int32Array(1);r.get_rand_int=function(){crypto.getRandomValues(a);return a[0]}}else if("undefined"!==typeof require){const a=require("crypto");r.get_rand_int=function(){return a.randomBytes(4).readInt32LE(0)}} +(function(){if("function"===typeof Math.clz32)r.int_log2_byte=function(d){return 31-Math.clz32(d)},r.int_log2=function(d){return 31-Math.clz32(d)};else{for(var a=new Int8Array(256),b=0,c=-2;256>b;b++)b&b-1||c++,a[b]=c;r.int_log2_byte=function(d){return a[d]};r.int_log2=function(d){d>>>=0;var e=d>>>16;if(e){var g=e>>>8;return g?24+a[g]:16+a[e]}return(g=d>>>8)?8+a[g]:a[d]}}})(); +function ka(a){var b=new Uint8Array(a),c,d;this.length=0;this.push=function(e){this.length!==a&&this.length++;b[d]=e;d=d+1&a-1};this.shift=function(){if(this.length){var e=b[c];c=c+1&a-1;this.length--;return e}return-1};this.peek=function(){return this.length?b[c]:-1};this.clear=function(){this.length=d=c=0};this.clear()}function la(a){this.size=a;this.data=new Float32Array(a);this.length=this.end=this.start=0} +la.prototype.push=function(a){this.length===this.size?this.start=this.start+1&this.size-1:this.length++;this.data[this.end]=a;this.end=this.end+1&this.size-1};la.prototype.shift=function(){if(this.length){var a=this.data[this.start];this.start=this.start+1&this.size-1;this.length--;return a}}; +la.prototype.shift_block=function(a){var b=new Float32Array(a);a>this.length&&(a=this.length);var c=this.start+a,d=this.data.subarray(this.start,c);b.set(d);c>=this.size&&(c-=this.size,b.set(this.data.subarray(0,c),d.length));this.start=c;this.length-=a;return b};la.prototype.peek=function(){if(this.length)return this.data[this.start]};la.prototype.clear=function(){this.length=this.end=this.start=0}; +r.Bitmap=function(a){"number"===typeof a?this.view=new Uint8Array(a+7>>3):a instanceof ArrayBuffer&&(this.view=new Uint8Array(a))};r.Bitmap.prototype.set=function(a,b){const c=a>>3;a=1<<(a&7);this.view[c]=b?this.view[c]|a:this.view[c]&~a};r.Bitmap.prototype.get=function(a){return this.view[a>>3]>>(a&7)&1};r.Bitmap.prototype.get_buffer=function(){return this.view.buffer};r.load_file="undefined"===typeof XMLHttpRequest?ma:na; +function na(a,b,c){function d(){const l=c||0;setTimeout(()=>{na(a,b,l+1)},1E3*([1,1,2,3,5,8,13,21][l]||34))}var e=new XMLHttpRequest;e.open(b.method||"get",a,!0);e.responseType=b.as_json?"json":"arraybuffer";if(b.headers)for(var g=Object.keys(b.headers),f=0;fe.status&&d();else if(e.response){if(b.range){let l=e.getResponseHeader("Content-Encoding");l&&"identity"!==l&&console.error("Server sent Content-Encoding in response to ranged request",{filename:a,enc:l})}b.done&&b.done(e.response,e)}};e.onerror=function(l){console.error("Loading the image "+a+" failed",l);d()};b.progress&&(e.onprogress= +function(l){b.progress(l)});e.send(null)}function ma(a,b){let c=require("fs");b.range?c.open(a,"r",(d,e)=>{if(d)throw d;d=b.range.length;var g=Buffer.allocUnsafe(d);c.read(e,g,0,d,b.range.start,f=>{if(f)throw f;b.done&&b.done(new Uint8Array(g));c.close(e,k=>{if(k)throw k;})})}):c.readFile(a,{encoding:b.as_json?"utf-8":null},function(d,e){d?console.log("Could not read file:",a,d):(d=e,d=b.as_json?JSON.parse(d):(new Uint8Array(d)).buffer,b.done(d))})} +r.read_sized_string_from_mem=function(a,b,c){return String.fromCharCode(...(new Uint8Array(a.buffer,b>>>0,c>>>0)))};(function(){function a(f){this.buffer=f;this.byteLength=f.byteLength;this.onprogress=this.onload=void 0}function b(f,k,l){this.filename=f;this.byteLength=k;this.block_cache=new Map;this.block_cache_is_write=new Set;this.fixed_chunk_size=l;this.cache_reads=!!l;this.onprogress=this.onload=void 0}function c(f,k,l,m,n){const p=f.match(/\.[^\.]+(\.zst)?$/);this.extension=p?p[0]:"";this.basename=f.substring(0,f.length-this.extension.length);this.is_zstd=this.extension.endsWith(".zst");this.basename.endsWith("/")|| +(this.basename+="-");this.block_cache=new Map;this.block_cache_is_write=new Set;this.byteLength=k;this.fixed_chunk_size=l;this.partfile_alt_format=!!m;this.zstd_decompress=n;this.cache_reads=!!l;this.onprogress=this.onload=void 0}function d(f){this.file=f;this.byteLength=f.size;1073741824>20)+" MB ...");this.buffer=new ArrayBuffer(f.size);this.onprogress=this.onload=void 0}function e(f){this.file=f;this.byteLength=f.size;this.block_cache= +new Map;this.block_cache_is_write=new Set;this.onprogress=this.onload=void 0}r.SyncBuffer=a;r.AsyncXHRBuffer=b;r.AsyncXHRPartfileBuffer=c;r.AsyncFileBuffer=e;r.SyncFileBuffer=d;r.buffer_from_object=function(f,k){if(f.buffer instanceof ArrayBuffer)return new r.SyncBuffer(f.buffer);if("undefined"!==typeof File&&f.buffer instanceof File)return k=f.async,void 0===k&&(k=268435456<=f.buffer.size),k?new r.AsyncFileBuffer(f.buffer):new r.SyncFileBuffer(f.buffer);if(f.url)return f.use_parts?new r.AsyncXHRPartfileBuffer(f.url, +f.size,f.fixed_chunk_size,!1,k):new r.AsyncXHRBuffer(f.url,f.size,f.fixed_chunk_size)};a.prototype.load=function(){this.onload&&this.onload({buffer:this.buffer})};a.prototype.get=function(f,k,l){l(new Uint8Array(this.buffer,f,k))};a.prototype.set=function(f,k,l){(new Uint8Array(this.buffer,f,k.byteLength)).set(k);l()};a.prototype.get_buffer=function(f){f(this.buffer)};a.prototype.get_state=function(){const f=[];f[0]=this.byteLength;f[1]=new Uint8Array(this.buffer);return f};a.prototype.set_state= +function(f){this.byteLength=f[0];this.buffer=f[1].slice().buffer};b.prototype.load=function(){void 0!==this.byteLength?this.onload&&this.onload(Object.create(null)):g(this.filename,(f,k)=>{if(f)throw Error("Cannot use: "+this.filename+". "+f);this.byteLength=k;this.onload&&this.onload(Object.create(null))})};b.prototype.get_from_cache=function(f,k){var l=k/256;f/=256;for(var m=0;m{l?k(l):k(null,m.size)})}:function(f,k){r.load_file(f,{done:(l,m)=>{l=m.getResponseHeader("Content-Range")||"";(m=l.match(/\/(\d+)\s*$/))?k(null,+m[1]):k("`Range: bytes=...` header not supported (Got `"+l+"`)")},headers:{Range:"bytes=0-0","X-Accept-Encoding":"identity"}})}})();function G(a,b,c,d,e,g){this.master=new H(this,a,b,d,e,0,g);this.slave=new H(this,a,c,!1,e,1,g);this.current_interface=this.master;this.cpu=a;0===e?(this.ata_port=496,this.irq=14,this.pci_id=240):1===e&&(this.ata_port=368,this.irq=15,this.pci_id=248);this.ata_port_high=this.ata_port|516;this.master_port=46080;this.pci_space=[134,128,16,112,5,0,160,2,0,128,1,1,0,0,0,0,this.ata_port&255|1,this.ata_port>>8,0,0,this.ata_port_high&255|1,this.ata_port_high>>8,0,0,0,0,0,0,0,0,0,0,this.master_port&255|1, +this.master_port>>8,0,0,0,0,0,0,0,0,0,0,67,16,212,130,0,0,0,0,0,0,0,0,0,0,0,0,this.irq,1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];this.pci_bars=[{size:8},{size:4},void 0,void 0,{size:16}];this.name="ide"+e;this.device_control=2;a.io.register_read(this.ata_port|7,this,function(){this.cpu.device_lower_irq(this.irq);return this.read_status()});a.io.register_read(this.ata_port_high| +2,this,this.read_status);a.io.register_write(this.ata_port_high|2,this,this.write_control);a.io.register_read(this.ata_port|0,this,function(){return this.current_interface.read_data(1)},function(){return this.current_interface.read_data(2)},function(){return this.current_interface.read_data(4)});a.io.register_read(this.ata_port|1,this,function(){A(this.current_interface.error&255);return this.current_interface.error&255});a.io.register_read(this.ata_port|2,this,function(){A(this.current_interface.bytecount& +255);return this.current_interface.bytecount&255});a.io.register_read(this.ata_port|3,this,function(){A(this.current_interface.sector&255);return this.current_interface.sector&255});a.io.register_read(this.ata_port|4,this,function(){A(this.current_interface.cylinder_low&255);return this.current_interface.cylinder_low&255});a.io.register_read(this.ata_port|5,this,function(){A(this.current_interface.cylinder_high&255);return this.current_interface.cylinder_high&255});a.io.register_read(this.ata_port| +6,this,function(){return this.current_interface.drive_head&255});a.io.register_write(this.ata_port|0,this,function(f){this.current_interface.write_data_port8(f)},function(f){this.current_interface.write_data_port16(f)},function(f){this.current_interface.write_data_port32(f)});a.io.register_write(this.ata_port|1,this,function(f){A(f);this.master.lba_count=(this.master.lba_count<<8|f)&65535;this.slave.lba_count=(this.slave.lba_count<<8|f)&65535});a.io.register_write(this.ata_port|2,this,function(f){A(f); +this.master.bytecount=(this.master.bytecount<<8|f)&65535;this.slave.bytecount=(this.slave.bytecount<<8|f)&65535});a.io.register_write(this.ata_port|3,this,function(f){A(f);this.master.sector=(this.master.sector<<8|f)&65535;this.slave.sector=(this.slave.sector<<8|f)&65535});a.io.register_write(this.ata_port|4,this,function(f){A(f);this.master.cylinder_low=(this.master.cylinder_low<<8|f)&65535;this.slave.cylinder_low=(this.slave.cylinder_low<<8|f)&65535});a.io.register_write(this.ata_port|5,this,function(f){A(f); +this.master.cylinder_high=(this.master.cylinder_high<<8|f)&65535;this.slave.cylinder_high=(this.slave.cylinder_high<<8|f)&65535});a.io.register_write(this.ata_port|6,this,function(f){var k=f&16;A(f,2);this.current_interface=k?this.slave:this.master;this.master.drive_head=f;this.slave.drive_head=f;this.master.is_lba=this.slave.is_lba=f>>6&1;this.master.head=this.slave.head=f&15});this.dma_command=this.dma_status=this.prdt_addr=0;a.io.register_write(this.ata_port|7,this,function(f){this.cpu.device_lower_irq(this.irq); +this.current_interface.ata_command(f)});a.io.register_read(this.master_port|4,this,void 0,void 0,this.dma_read_addr);a.io.register_write(this.master_port|4,this,void 0,void 0,this.dma_set_addr);a.io.register_read(this.master_port,this,this.dma_read_command8,void 0,this.dma_read_command);a.io.register_write(this.master_port,this,this.dma_write_command8,void 0,this.dma_write_command);a.io.register_read(this.master_port|2,this,this.dma_read_status);a.io.register_write(this.master_port|2,this,this.dma_write_status); +a.io.register_read(this.master_port|8,this,function(){return 0});a.io.register_read(this.master_port|10,this,function(){return 0});a.devices.pci.register_device(this)}G.prototype.read_status=function(){if(this.current_interface.buffer){var a=this.current_interface.status;A(a,2);return a}return 0};G.prototype.write_control=function(a){A(a,2);a&4&&(this.cpu.device_lower_irq(this.irq),this.master.device_reset(),this.slave.device_reset());this.device_control=a}; +G.prototype.dma_read_addr=function(){A(this.prdt_addr,8);return this.prdt_addr};G.prototype.dma_set_addr=function(a){A(a,8);this.prdt_addr=a};G.prototype.dma_read_status=function(){A(this.dma_status);return this.dma_status};G.prototype.dma_write_status=function(a){A(a);this.dma_status&=~(a&6)};G.prototype.dma_read_command=function(){return this.dma_read_command8()|this.dma_read_status()<<16};G.prototype.dma_read_command8=function(){A(this.dma_command);return this.dma_command}; +G.prototype.dma_write_command=function(a){A(a);this.dma_write_command8(a&255);this.dma_write_status(a>>16&255)}; +G.prototype.dma_write_command8=function(a){A(a);let b=this.dma_command;this.dma_command=a&9;if((b&1)!==(a&1))if(0===(a&1))this.dma_status&=-2;else switch(this.dma_status|=1,this.current_interface.current_command){case 37:case 200:this.current_interface.do_ata_read_sectors_dma();break;case 202:case 53:this.current_interface.do_ata_write_sectors_dma();break;case 160:this.current_interface.do_atapi_dma();break;default:A(this.current_interface.current_command)}}; +G.prototype.push_irq=function(){0===(this.device_control&2)&&(this.dma_status|=4,this.cpu.device_raise_irq(this.irq))};G.prototype.get_state=function(){var a=[];a[0]=this.master;a[1]=this.slave;a[2]=this.ata_port;a[3]=this.irq;a[4]=this.pci_id;a[5]=this.ata_port_high;a[6]=this.master_port;a[7]=this.name;a[8]=this.device_control;a[9]=this.prdt_addr;a[10]=this.dma_status;a[11]=this.current_interface===this.master;a[12]=this.dma_command;return a}; +G.prototype.set_state=function(a){this.master.set_state(a[0]);this.slave.set_state(a[1]);this.ata_port=a[2];this.irq=a[3];this.pci_id=a[4];this.ata_port_high=a[5];this.master_port=a[6];this.name=a[7];this.device_control=a[8];this.prdt_addr=a[9];this.dma_status=a[10];this.current_interface=a[11]?this.master:this.slave;this.dma_command=a[12]}; +function H(a,b,c,d,e,g,f){this.device=a;this.bus=f;this.nr=e;this.cpu=b;this.buffer=c;this.sector_size=d?2048:512;this.is_atapi=d;this.cylinder_count=this.sectors_per_track=this.head_count=this.sector_count=0;this.buffer&&(this.sector_count=this.buffer.byteLength/this.sector_size,this.sector_count!==(this.sector_count|0)&&(this.sector_count=Math.ceil(this.sector_count)),d?(this.head_count=1,this.sectors_per_track=0):(this.head_count=16,this.sectors_per_track=63),this.cylinder_count=this.sector_count/ +this.head_count/this.sectors_per_track,this.cylinder_count!==(this.cylinder_count|0)&&(this.cylinder_count=Math.floor(this.cylinder_count)),a=b.devices.rtc,a.cmos_write(57,a.cmos_read(57)|1<<4*this.nr),a.cmos_write(18,a.cmos_read(18)&15|240),a.cmos_write(27,this.cylinder_count&255),a.cmos_write(28,this.cylinder_count>>8&255),a.cmos_write(29,this.head_count&255),a.cmos_write(30,255),a.cmos_write(31,255),a.cmos_write(32,200),a.cmos_write(33,this.cylinder_count&255),a.cmos_write(34,this.cylinder_count>> +8&255),a.cmos_write(35,this.sectors_per_track&255));this.stats={sectors_read:0,sectors_written:0,bytes_read:0,bytes_written:0,loading:!1};this.buffer=c;this.drive_head=this.head=this.cylinder_high=this.cylinder_low=this.lba_count=this.sector=this.bytecount=this.is_lba=0;this.status=80;this.sectors_per_drq=128;this.data_pointer=this.error=0;this.data=new Uint8Array(65536);this.data16=new Uint16Array(this.data.buffer);this.data32=new Int32Array(this.data.buffer);this.data_end=this.data_length=0;this.current_atapi_command= +this.current_command=-1;this.last_io_id=this.write_dest=0;this.in_progress_io_ids=new Set;this.cancelled_io_ids=new Set;Object.seal(this)}H.prototype.device_reset=function(){this.is_atapi?(this.status=0,this.sector=this.error=this.bytecount=1,this.cylinder_low=20,this.cylinder_high=235):(this.status=81,this.sector=this.error=this.bytecount=1,this.cylinder_high=this.cylinder_low=0);this.cancel_io_operations()};H.prototype.push_irq=function(){this.device.push_irq()}; +H.prototype.ata_command=function(a){A(a);if(this.buffer)switch(this.current_command=a,this.error=0,a){case 8:this.data_length=this.data_end=this.data_pointer=0;this.device_reset();this.push_irq();break;case 16:this.status=80;this.cylinder_low=0;this.push_irq();break;case 248:this.status=80;a=this.sector_count-1;this.sector=a&255;this.cylinder_low=a>>8&255;this.cylinder_high=a>>16&255;this.drive_head=this.drive_head&240|a>>24&15;this.push_irq();break;case 39:this.status=80;a=this.sector_count-1;this.sector= +a&255;this.cylinder_low=a>>8&255;this.cylinder_high=a>>16&255;this.sector|=a>>24<<8&65280;this.push_irq();break;case 32:case 36:case 41:case 196:this.ata_read_sectors(a);break;case 48:case 52:case 57:case 197:this.ata_write_sectors(a);break;case 144:this.push_irq();this.error=257;this.status=80;break;case 145:this.status=80;this.push_irq();break;case 160:this.is_atapi&&(this.status=88,this.data_allocate(12),this.data_end=12,this.bytecount=1,this.push_irq());break;case 161:this.is_atapi?(this.create_identify_packet(), +this.status=88,this.cylinder_low=20,this.cylinder_high=235):this.status=65;this.push_irq();break;case 198:A(this.bytecount&255);this.sectors_per_drq=this.bytecount&255;this.status=80;this.push_irq();break;case 37:case 200:this.ata_read_sectors_dma(a);break;case 53:case 202:this.ata_write_sectors_dma(a);break;case 64:this.status=80;this.push_irq();break;case 218:this.status=65;this.error=4;this.push_irq();break;case 224:this.status=80;this.push_irq();break;case 225:this.status=80;this.push_irq();break; +case 231:this.status=80;this.push_irq();break;case 236:if(this.is_atapi){this.status=65;this.error=4;this.push_irq();break}this.create_identify_packet();this.status=88;this.push_irq();break;case 234:this.status=80;this.push_irq();break;case 239:A(this.bytecount&255);this.status=80;this.push_irq();break;case 222:this.status=80;this.push_irq();break;case 245:this.status=80;this.push_irq();break;case 249:this.status=65;this.error=4;break;default:A(a),this.status=65,this.error=4}else this.error=4,this.status= +65,this.push_irq()}; +H.prototype.atapi_handle=function(){A(this.data[0]);this.data_pointer=0;this.current_atapi_command=this.data[0];switch(this.current_atapi_command){case 0:this.data_allocate(0);this.data_end=this.data_length;this.status=80;break;case 3:this.data_allocate(this.data[4]);this.data_end=this.data_length;this.status=88;this.data[0]=240;this.data[2]=5;this.data[7]=8;break;case 18:var a=this.data[4];this.status=88;A(this.data[1],2);this.data.set([5,128,1,49,31,0,0,0,83,79,78,89,32,32,32,32,67,68,45,82,79, +77,32,67,68,85,45,49,48,48,48,32,49,46,49,97]);this.data_end=this.data_length=Math.min(36,a);break;case 26:this.data_allocate(this.data[4]);this.data_end=this.data_length;this.status=88;break;case 30:this.data_allocate(0);this.data_end=this.data_length;this.status=80;break;case 37:a=this.sector_count-1;this.data_set(new Uint8Array([a>>24&255,a>>16&255,a>>8&255,a&255,0,0,this.sector_size>>8&255,this.sector_size&255]));this.data_end=this.data_length;this.status=88;break;case 40:this.lba_count&1?this.atapi_read_dma(this.data): +this.atapi_read(this.data);break;case 66:a=this.data[8];this.data_allocate(Math.min(8,a));this.data_end=this.data_length;this.status=88;break;case 67:a=this.data[8]|this.data[7]<<8;var b=this.data[9]>>6;this.data_allocate(a);this.data_end=this.data_length;A(b,2);A(this.data[6]);0===b?(a=this.sector_count,this.data.set(new Uint8Array([0,18,1,1,0,20,1,0,0,0,0,0,0,22,170,0,a>>24,a>>16&255,a>>8&255,a&255]))):1===b&&this.data.set(new Uint8Array([0,10,1,1,0,0,0,0,0,0,0,0]));this.status=88;break;case 70:a= +this.data[8]|this.data[7]<<8;a=Math.min(a,32);this.data_allocate(a);this.data_end=this.data_length;this.data[0]=a-4>>24&255;this.data[1]=a-4>>16&255;this.data[2]=a-4>>8&255;this.data[3]=a-4&255;this.data[6]=8;this.data[10]=3;this.status=88;break;case 81:this.data_allocate(0);this.data_end=this.data_length;this.status=80;break;case 82:A(this.data[0]);this.status=81;this.data_length=0;this.error=80;break;case 90:a=this.data[8]|this.data[7]<<8;b=this.data[2];A(b);42===b&&this.data_allocate(Math.min(30, +a));this.data_end=this.data_length;this.status=88;break;case 189:this.data_allocate(this.data[9]|this.data[8]<<8);this.data_end=this.data_length;this.data[5]=1;this.status=88;break;case 74:this.status=81;this.data_length=0;this.error=80;A(this.data[0]);break;case 190:A(this.data[0]);this.data_allocate(0);this.data_end=this.data_length;this.status=80;break;default:this.status=81,this.data_length=0,this.error=80,A(this.data[0])}this.bytecount=this.bytecount&-8|2;0===(this.status&128)&&this.push_irq(); +0===(this.status&128)&&0===this.data_length&&(this.bytecount|=1,this.status&=-9)};H.prototype.do_write=function(){this.status=80;var a=this.data.subarray(0,this.data_length);this.ata_advance(this.current_command,this.data_length/512);this.push_irq();this.buffer.set(this.write_dest,a,function(){});this.report_write(this.data_length)}; +H.prototype.atapi_read=function(a){var b=a[2]<<24|a[3]<<16|a[4]<<8|a[5],c=a[7]<<8|a[8];a=a[1];var d=c*this.sector_size,e=b*this.sector_size;J("CD read lba="+A(b)+" lbacount="+A(c)+" bytecount="+A(d)+" flags="+A(a),32768);this.data_length=0;var g=this.cylinder_high<<8&65280|this.cylinder_low&255;J(A(this.cylinder_high,2)+" "+A(this.cylinder_low,2),32768);this.cylinder_low=this.cylinder_high=0;65535===g&&g--;g>d&&(g=d);e>=this.buffer.byteLength?(oa(!1,"CD read: Outside of disk end="+A(e+d)+" size="+ +A(this.buffer.byteLength),32768),this.status=255,this.push_irq()):0===d?(this.status=80,this.data_pointer=0):(d=Math.min(d,this.buffer.byteLength-e),this.status=208,this.report_read_start(),this.read_buffer(e,d,f=>{this.data_set(f);this.status=88;this.bytecount=this.bytecount&-8|2;this.push_irq();this.data_end=g&=-4;this.data_end>this.data_length&&(this.data_end=this.data_length);this.cylinder_low=this.data_end&255;this.cylinder_high=this.data_end>>8&255;this.report_read_end(d)}))}; +H.prototype.atapi_read_dma=function(a){var b=a[2]<<24|a[3]<<16|a[4]<<8|a[5],c=a[7]<<8|a[8];a=a[1];var d=c*this.sector_size,e=b*this.sector_size;J("CD read DMA lba="+A(b)+" lbacount="+A(c)+" bytecount="+A(d)+" flags="+A(a),32768);e>=this.buffer.byteLength?(oa(!1,"CD read: Outside of disk end="+A(e+d)+" size="+A(this.buffer.byteLength),32768),this.status=255,this.push_irq()):(this.status=208,this.report_read_start(),this.read_buffer(e,d,g=>{this.report_read_end(d);this.status=88;this.bytecount=this.bytecount& +-8|2;this.data_set(g);this.do_atapi_dma()}))}; +H.prototype.do_atapi_dma=function(){if(0!==(this.device.dma_status&1)&&0!==(this.status&8)){var a=this.device.prdt_addr,b=0,c=this.data;do{var d=this.cpu.read32s(a),e=this.cpu.read16(a+4),g=this.cpu.read8(a+7)&128;e||(e=65536);A(d);A(e);A(this.data_length);this.cpu.write_blob(c.subarray(b,Math.min(b+e,this.data_length)),d);b+=e;a+=8;if(b>=this.data_length&&!g){A(b);A(this.data_length);A(this.current_command);break}}while(!g);this.status=80;this.device.dma_status&=-2;this.bytecount=this.bytecount& +-8|3;this.push_irq()}};H.prototype.read_data=function(a){if(this.data_pointer>>1]:this.data32[this.data_pointer>>>2];this.data_pointer+=a;0===(this.data_pointer&(0===(this.data_end&4095)?4095:255))&&(A(this.data[this.data_pointer],2),A(this.data_pointer),A(this.data_length));this.data_pointer>=this.data_end&&this.read_end();return b}this.data_pointer+=a;return 0}; +H.prototype.read_end=function(){A(this.current_command);A(this.data_pointer);A(this.data_end);A(this.data_length);if(160===this.current_command)if(this.data_end===this.data_length)this.status=80,this.bytecount=this.bytecount&-8|3,this.push_irq();else{this.status=88;this.bytecount=this.bytecount&-8|2;this.push_irq();var a=this.cylinder_high<<8&65280|this.cylinder_low&255;this.data_end+a>this.data_length?(this.cylinder_low=this.data_length-this.data_end&255,this.cylinder_high=this.data_length-this.data_end>> +8&255,this.data_end=this.data_length):this.data_end+=a;A(this.data_end)}else this.error=0,this.data_pointer>=this.data_length?this.status=80:(a=196===this.current_command||41===this.current_command?Math.min(this.sectors_per_drq,(this.data_length-this.data_end)/512):1,this.ata_advance(this.current_command,a),this.data_end+=512*a,this.status=88,this.push_irq())}; +H.prototype.write_data_port=function(a,b){if(this.data_pointer>=this.data_end)A(a),A(this.data_end),A(this.data_pointer);else{if(0===(this.data_pointer+b&(0===(this.data_end&4095)?4095:255))||20>this.data_end)A(a>>>0),A(this.data_end),A(this.data_pointer);1===b?this.data[this.data_pointer++]=a:2===b?(this.data16[this.data_pointer>>>1]=a,this.data_pointer+=2):(this.data32[this.data_pointer>>>2]=a,this.data_pointer+=4);this.data_pointer===this.data_end&&this.write_end()}}; +H.prototype.write_data_port8=function(a){this.write_data_port(a,1)};H.prototype.write_data_port16=function(a){this.write_data_port(a,2)};H.prototype.write_data_port32=function(a){this.write_data_port(a,4)};H.prototype.write_end=function(){160===this.current_command?this.atapi_handle():(A(this.data_pointer),A(this.data_length),this.data_pointer>=this.data_length?this.do_write():(A(this.current_command),this.status=88,this.data_end+=512,this.push_irq()))}; +H.prototype.ata_advance=function(a,b){this.bytecount-=b;36===a||41===a||52===a||57===a||37===a||53===a?(a=b+this.get_lba48(),this.sector=a&255|a>>16&65280,this.cylinder_low=a>>8&255,this.cylinder_high=a>>16&255):this.is_lba?(a=b+this.get_lba28(),this.sector=a&255,this.cylinder_low=a>>8&255,this.cylinder_high=a>>16&255,this.head=this.head&-16|a&15):(a=b+this.get_chs(),b=a/(this.head_count*this.sectors_per_track)|0,this.cylinder_low=b&255,this.cylinder_high=b>>8&255,this.head=(a/this.sectors_per_track| +0)%this.head_count&15,this.sector=a%this.sectors_per_track+1&255,this.get_chs())}; +H.prototype.ata_read_sectors=function(a){var b=36===a||41===a,c=this.get_count(b);b=this.get_lba(b);var d=32===a||36===a,e=c*this.sector_size,g=b*this.sector_size;J("ATA read cmd="+A(a)+" mode="+(this.is_lba?"lba":"chs")+" lba="+A(b)+" lbacount="+A(c)+" bytecount="+A(e),32768);g+e>this.buffer.byteLength?(this.status=255,this.push_irq()):(this.status=192,this.report_read_start(),this.read_buffer(g,e,f=>{this.data_set(f);this.status=88;this.data_end=d?512:Math.min(e,512*this.sectors_per_drq);this.ata_advance(a, +d?1:Math.min(c,this.sectors_per_track));this.push_irq();this.report_read_end(e)}))};H.prototype.ata_read_sectors_dma=function(a){var b=37===a;a=this.get_count(b);b=this.get_lba(b);var c=a*this.sector_size,d=b*this.sector_size;A(b);A(a);A(c);d+c>this.buffer.byteLength?(this.status=255,this.push_irq()):(this.status=88,this.device.dma_status|=1)}; +H.prototype.do_ata_read_sectors_dma=function(){var a=37===this.current_command,b=this.get_count(a);a=this.get_lba(a);var c=b*this.sector_size;a*=this.sector_size;this.report_read_start();this.read_buffer(a,c,d=>{var e=this.device.prdt_addr,g=0;do{var f=this.cpu.read32s(e),k=this.cpu.read16(e+4),l=this.cpu.read8(e+7)&128;k||(k=65536);A(f);A(k);this.cpu.write_blob(d.subarray(g,g+k),f);g+=k;e+=8}while(!l);this.ata_advance(this.current_command,b);this.status=80;this.device.dma_status&=-2;this.current_command= +-1;this.push_irq();this.report_read_end(c)})};H.prototype.ata_write_sectors=function(a){var b=52===a||57===a,c=this.get_count(b);b=this.get_lba(b);a=48===a||52===a;var d=c*this.sector_size,e=b*this.sector_size;A(b);A(c);A(d);e+d>this.buffer.byteLength?(this.status=255,this.push_irq()):(this.status=88,this.data_allocate_noclear(d),this.data_end=a?512:Math.min(d,512*this.sectors_per_drq),this.write_dest=e)}; +H.prototype.ata_write_sectors_dma=function(a){var b=53===a;a=this.get_count(b);b=this.get_lba(b);var c=a*this.sector_size,d=b*this.sector_size;A(b);A(a);A(c);d+c>this.buffer.byteLength?(this.status=255,this.push_irq()):(this.status=88,this.device.dma_status|=1)}; +H.prototype.do_ata_write_sectors_dma=function(){var a=53===this.current_command,b=this.get_count(a),c=this.get_lba(a);a=b*this.sector_size;c*=this.sector_size;var d=this.device.prdt_addr,e=0;J("prdt addr: "+A(d,8),32768);const g=new Uint8Array(a);do{var f=this.cpu.read32s(d),k=this.cpu.read16(d+4),l=this.cpu.read8(d+7)&128;k||(k=65536);J("dma write transfer dest="+A(f)+" prd_count="+A(k),32768);f=this.cpu.mem8.subarray(f,f+k);g.set(f,e);e+=k;d+=8}while(!l);this.buffer.set(c,g,()=>{this.ata_advance(this.current_command, +b);this.status=80;this.push_irq();this.device.dma_status&=-2;this.current_command=-1});this.report_write(a)};H.prototype.get_chs=function(){return((this.cylinder_low&255|this.cylinder_high<<8&65280)*this.head_count+this.head)*this.sectors_per_track+(this.sector&255)-1};H.prototype.get_lba28=function(){return this.sector&255|this.cylinder_low<<8&65280|this.cylinder_high<<16&16711680|(this.head&15)<<24}; +H.prototype.get_lba48=function(){return(this.sector&255|this.cylinder_low<<8&65280|this.cylinder_high<<16&16711680|this.sector>>8<<24&4278190080)>>>0};H.prototype.get_lba=function(a){return a?this.get_lba48():this.is_lba?this.get_lba28():this.get_chs()};H.prototype.get_count=function(a){a?(a=this.bytecount,0===a&&(a=65536)):(a=this.bytecount&255,0===a&&(a=256));return a}; +H.prototype.create_identify_packet=function(){if(this.drive_head&16)this.data_allocate(0);else{for(var a=0;512>a;a++)this.data[a]=0;a=Math.min(16383,this.cylinder_count);this.data_set([64,this.is_atapi?133:0,a,a>>8,0,0,this.head_count,this.head_count>>8,this.sectors_per_track/512,this.sectors_per_track/512>>8,0,2,this.sectors_per_track,this.sectors_per_track>>8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,3,0,0,2,4,0,0,0,0,0,0,0,0,0,56,118,32,54,68,72,32,32,32,32,32,32,32,32,32,32,32,32,32, +32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,128,0,1,0,0,2,0,0,0,2,0,2,7,0,a,a>>8,this.head_count,this.head_count>>8,this.sectors_per_track,0,this.sector_count&255,this.sector_count>>8&255,this.sector_count>>16&255,this.sector_count>>24&255,0,0,this.sector_count&255,this.sector_count>>8&255,this.sector_count>>16&255,this.sector_count>>24&255,0,0,160===this.current_command?0:7,160===this.current_command?0:4,0,0,30,0,30,0,30,0,30,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,126,0, +0,0,0,0,0,116,0,64,0,64,0,116,0,64,0,0,0,0,0,0,0,0,0,0,1,96,0,0,0,0,0,0,0,0,0,0,0,0,this.sector_count&255,this.sector_count>>8&255,this.sector_count>>16&255,this.sector_count>>24&255]);this.data_end=this.data_length=512}};H.prototype.data_allocate=function(a){this.data_allocate_noclear(a);for(var b=0;b>2;b++)this.data32[b]=0}; +H.prototype.data_allocate_noclear=function(a){this.data.length{this.cancelled_io_ids.delete(d)?this.in_progress_io_ids.has(d):(this.in_progress_io_ids.delete(d),c(e))})};H.prototype.cancel_io_operations=function(){for(const a of this.in_progress_io_ids)this.cancelled_io_ids.add(a);this.in_progress_io_ids.clear()}; +H.prototype.get_state=function(){var a=[];a[0]=this.bytecount;a[1]=this.cylinder_count;a[2]=this.cylinder_high;a[3]=this.cylinder_low;a[4]=this.data_pointer;a[5]=0;a[6]=0;a[7]=0;a[8]=0;a[9]=this.drive_head;a[10]=this.error;a[11]=this.head;a[12]=this.head_count;a[13]=this.is_atapi;a[14]=this.is_lba;a[15]=this.lba_count;a[16]=this.data;a[17]=this.data_length;a[18]=this.sector;a[19]=this.sector_count;a[20]=this.sector_size;a[21]=this.sectors_per_drq;a[22]=this.sectors_per_track;a[23]=this.status;a[24]= +this.write_dest;a[25]=this.current_command;a[26]=this.data_end;a[27]=this.current_atapi_command;a[28]=this.buffer;return a}; +H.prototype.set_state=function(a){this.bytecount=a[0];this.cylinder_count=a[1];this.cylinder_high=a[2];this.cylinder_low=a[3];this.data_pointer=a[4];this.drive_head=a[9];this.error=a[10];this.head=a[11];this.head_count=a[12];this.is_atapi=a[13];this.is_lba=a[14];this.lba_count=a[15];this.data=a[16];this.data_length=a[17];this.sector=a[18];this.sector_count=a[19];this.sector_size=a[20];this.sectors_per_drq=a[21];this.sectors_per_track=a[22];this.status=a[23];this.write_dest=a[24];this.current_command= +a[25];this.data_end=a[26];this.current_atapi_command=a[27];this.data16=new Uint16Array(this.data.buffer);this.data32=new Int32Array(this.data.buffer);this.buffer&&this.buffer.set_state(a[28])};function pa(a){this.pci_addr=new Uint8Array(4);this.pci_value=new Uint8Array(4);this.pci_response=new Uint8Array(4);this.pci_status=new Uint8Array(4);this.pci_addr32=new Int32Array(this.pci_addr.buffer);this.pci_value32=new Int32Array(this.pci_value.buffer);this.pci_response32=new Int32Array(this.pci_response.buffer);this.pci_status32=new Int32Array(this.pci_status.buffer);this.device_spaces=[];this.devices=[];this.cpu=a;for(var b=0;256>b;b++)this.device_spaces[b]=void 0,this.devices[b]=void 0;this.io= +a.io;a.io.register_write(3324,this,function(c){this.pci_write8(this.pci_addr32[0],c)},function(c){this.pci_write16(this.pci_addr32[0],c)},function(c){this.pci_write32(this.pci_addr32[0],c)});a.io.register_write(3325,this,function(c){this.pci_write8(this.pci_addr32[0]+1|0,c)});a.io.register_write(3326,this,function(c){this.pci_write8(this.pci_addr32[0]+2|0,c)},function(c){this.pci_write16(this.pci_addr32[0]+2|0,c)});a.io.register_write(3327,this,function(c){this.pci_write8(this.pci_addr32[0]+3|0,c)}); +a.io.register_read_consecutive(3324,this,function(){return this.pci_response[0]},function(){return this.pci_response[1]},function(){return this.pci_response[2]},function(){return this.pci_response[3]});a.io.register_read_consecutive(3320,this,function(){return this.pci_status[0]},function(){return this.pci_status[1]},function(){return this.pci_status[2]},function(){return this.pci_status[3]});a.io.register_write_consecutive(3320,this,function(c){this.pci_addr[0]=c&252},function(c){2===(this.pci_addr[1]& +6)&&6===(c&6)?a.reboot_internal():this.pci_addr[1]=c},function(c){this.pci_addr[2]=c},function(c){this.pci_addr[3]=c;this.pci_query()});this.register_device({pci_id:0,pci_space:[134,128,55,18,0,0,0,0,2,0,0,6,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,16,0,0,0,0,0,0],pci_bars:[],name:"82441FX PMC"});this.isa_bridge={pci_id:8,pci_space:[134,128,0,112,7,0,0,2,0,0,1,6,0,0,128,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0],pci_bars:[],name:"82371SB PIIX3 ISA"};this.isa_bridge_space=this.register_device(this.isa_bridge);this.isa_bridge_space8=new Uint8Array(this.isa_bridge_space.buffer)}pa.prototype.get_state=function(){for(var a=[],b=0;256>b;b++)a[b]=this.device_spaces[b];a[256]=this.pci_addr;a[257]=this.pci_value;a[258]=this.pci_response;a[259]=this.pci_status;return a}; +pa.prototype.set_state=function(a){for(var b=0;256>b;b++){var c=this.devices[b],d=a[b];if(c&&d){for(var e=0;e>3&31;var d="query enabled="+(this.pci_addr[3]>>7)+(" bdf="+A(a,4));d+=" dev="+A(c,2);d+=" addr="+A(b,2);a=this.device_spaces[a];void 0!==a?(this.pci_status32[0]=-2147483648,this.pci_response32[0]=b>2]:0,d+=" "+A(this.pci_addr32[0]>>>0,8)+" -> "+A(this.pci_response32[0]>>>0,8)):(this.pci_response32[0]=-1,this.pci_status32[0]=0)}; +pa.prototype.pci_write8=function(a,b){var c=a>>8&65535;a&=255;var d=new Uint8Array(this.device_spaces[c].buffer);A(a);A(c>>3,2);A(a,4);A(b,2);d[a]=b};pa.prototype.pci_write16=function(a,b){var c=a>>8&65535;a&=255;var d=new Uint16Array(this.device_spaces[c].buffer);16<=a&&44>a?A(a):(A(a),A(c>>3,2),A(a,4),A(b,4),d[a>>>1]=b)}; +pa.prototype.pci_write32=function(a,b){var c=a>>8&65535;a&=255;var d=this.device_spaces[c],e=this.devices[c];if(d)if(16<=a&&40>a){e=e.pci_bars[a-16>>2];A(b>>>0);A(c>>3,2);if(e){c=a>>2;var g=d[c]&1;-1===(b|3|e.size-1)?(b=~(e.size-1)|g,0===g&&(d[c]=b)):0===g&&(d[c]=e.original_bar);if(1===g){g=d[c]&65534;var f=b&65534;A(g>>>0,8);A(f>>>0,8);this.set_io_bars(e,g,f);d[c]=b|1}}else d[a>>2]=0;A(d[a>>2]>>>0)}else 48===a?(A(c>>3,2),A(b>>>0,8),d[a>>2]=e.pci_rom_size?-1===(b|2047)?-e.pci_rom_size|0:e.pci_rom_address| +0:0):4===a?(A(c>>3,2),A(a,4),A(b>>>0,8)):(A(c>>3,2),A(a,4),A(b>>>0,8),d[a>>>2]=b)};pa.prototype.register_device=function(a){var b=a.pci_id;A(b);var c=new Int32Array(64);c.set(new Int32Array((new Uint8Array(a.pci_space)).buffer));this.device_spaces[b]=c;this.devices[b]=a;b=c.slice(4,10);for(var d=0;d>8&255)-1+((a>>3)-1&255)&3)])};pa.prototype.lower_irq=function(a){this.cpu.device_lower_irq(this.isa_bridge_space8[96+((this.device_spaces[a][15]>>8&255)+(a>>3&255)-2&3)])};function K(a,b){this.io=a.io;this.cpu=a;this.dma=a.devices.dma;this.bytes_expecting=0;this.receiving_command=new Uint8Array(10);this.receiving_index=0;this.next_command=null;this.response_data=new Uint8Array(10);this.last_head=this.last_cylinder=this.drive=this.status_reg2=this.status_reg1=this.status_reg0=this.response_length=this.response_index=0;this.last_sector=1;this.dir=this.dor=0;this.fdb_image=this.fda_image=null;b?this.set_fda(b):(this.eject_fda(),this.cpu.devices.rtc.cmos_write(16,64)); +this.io.register_read(1008,this,this.port3F0_read);this.io.register_read(1010,this,this.port3F2_read);this.io.register_read(1012,this,this.port3F4_read);this.io.register_read(1013,this,this.port3F5_read);this.io.register_read(1015,this,this.port3F7_read);this.io.register_write(1010,this,this.port3F2_write);this.io.register_write(1012,this,this.port3F4_write);this.io.register_write(1013,this,this.port3F5_write)} +K.prototype.eject_fda=function(){this.fda_image=null;this.number_of_cylinders=this.number_of_heads=this.sectors_per_track=0;this.dir=128}; +K.prototype.set_fda=function(a){var b={[163840]:{type:1,tracks:40,sectors:8,heads:1},[184320]:{type:1,tracks:40,sectors:9,heads:1},[204800]:{type:1,tracks:40,sectors:10,heads:1},[327680]:{type:1,tracks:40,sectors:8,heads:2},[368640]:{type:1,tracks:40,sectors:9,heads:2},[409600]:{type:1,tracks:40,sectors:10,heads:2},[737280]:{type:3,tracks:80,sectors:9,heads:2},[1228800]:{type:2,tracks:80,sectors:15,heads:2},[1474560]:{type:4,tracks:80,sectors:18,heads:2},[1763328]:{type:5,tracks:82,sectors:21,heads:2}, +[2949120]:{type:5,tracks:80,sectors:36,heads:2},512:{type:1,tracks:1,sectors:1,heads:1}};let c=a.byteLength,d=b[c];d||(c=1474560>4);A(a);this.dor=a};K.prototype.check_drive_status=function(){this.status_reg1=this.fda_image?0:5;this.response_index=0;this.response_length=1;this.response_data[0]=0}; +K.prototype.seek=function(a){if(0===(a[0]&3)){var b=a[1];a=a[0]>>2&1;b!==this.last_cylinder&&(this.dir=0);this.status_reg1=this.fda_image?0:5;this.status_reg0=32;this.last_cylinder=b;this.last_head=a}this.raise_irq()};K.prototype.calibrate=function(a){this.seek([a[0],0])};K.prototype.check_interrupt_status=function(){this.response_index=0;this.response_length=2;this.response_data[0]=this.status_reg0;this.response_data[1]=this.last_cylinder}; +K.prototype.do_sector=function(a,b){var c=b[2],d=b[1],e=b[3],g=128<this.sectors_per_track&&(d=1,c++,c>=this.number_of_heads&&(c=0,b++)),b!==this.last_cylinder&&(this.dir=0),this.status_reg0=32,this.last_cylinder=b,this.last_head=c,this.last_sector=d,this.response_index=0,this.response_length=7,this.response_data[0]=c<<2|32,this.response_data[1]=0,this.response_data[2]=0,this.response_data[3]=b,this.response_data[4]=c,this.response_data[5]=d,this.response_data[6]=a[4],this.raise_irq())}; +K.prototype.fix_drive_data=function(a){a.slice(0,this.bytes_expecting)};K.prototype.configure=function(a){a.slice(0,this.bytes_expecting)};K.prototype.read_sector_id=function(){this.response_index=0;this.response_length=7;this.response_data[0]=0;this.response_data[1]=0;this.response_data[2]=0;this.response_data[3]=0;this.response_data[4]=0;this.response_data[5]=0;this.response_data[6]=0;this.raise_irq()};K.prototype.raise_irq=function(){this.dor&8&&this.cpu.device_raise_irq(6)};E.prototype.mmap_read8=function(a){return this.memory_map_read8[a>>>17](a)};E.prototype.mmap_write8=function(a,b){this.memory_map_write8[a>>>17](a,b)};E.prototype.mmap_read16=function(a){var b=this.memory_map_read8[a>>>17];return b(a)|b(a+1|0)<<8};E.prototype.mmap_write16=function(a,b){var c=this.memory_map_write8[a>>>17];c(a,b&255);c(a+1|0,b>>8)};E.prototype.mmap_read32=function(a){return this.memory_map_read32[a>>>17](a)}; +E.prototype.mmap_write32=function(a,b){this.memory_map_write32[a>>>17](a,b)};E.prototype.mmap_write64=function(a,b,c){var d=this.memory_map_write32[a>>>17];d(a,b);d(a+4,c)};E.prototype.mmap_write128=function(a,b,c,d,e){var g=this.memory_map_write32[a>>>17];g(a,b);g(a+4,c);g(a+8,d);g(a+12,e)};E.prototype.write_blob=function(a,b){a.length&&(this.in_mapped_range(b),this.in_mapped_range(b+a.length-1),this.jit_dirty_cache(b,b+a.length),this.mem8.set(a,b))}; +E.prototype.read_blob=function(a,b){b&&(this.in_mapped_range(a),this.in_mapped_range(a+b-1));return this.mem8.subarray(a,a+b)};function L(a){this.cpu=a;this.channel_page=new Uint8Array(8);this.channel_pagehi=new Uint8Array(8);this.channel_addr=new Uint16Array(8);this.channel_addr_init=new Uint16Array(8);this.channel_count=new Uint16Array(8);this.channel_count_init=new Uint16Array(8);this.channel_mask=new Uint8Array(8);this.channel_mode=new Uint8Array(8);this.unmask_listeners=[];this.lsb_msb_flipflop=0;a=a.io;a.register_write(0,this,this.port_addr_write.bind(this,0));a.register_write(2,this,this.port_addr_write.bind(this, +1));a.register_write(4,this,this.port_addr_write.bind(this,2));a.register_write(6,this,this.port_addr_write.bind(this,3));a.register_write(1,this,this.port_count_write.bind(this,0));a.register_write(3,this,this.port_count_write.bind(this,1));a.register_write(5,this,this.port_count_write.bind(this,2));a.register_write(7,this,this.port_count_write.bind(this,3));a.register_read(0,this,this.port_addr_read.bind(this,0));a.register_read(2,this,this.port_addr_read.bind(this,1));a.register_read(4,this,this.port_addr_read.bind(this, +2));a.register_read(6,this,this.port_addr_read.bind(this,3));a.register_read(1,this,this.port_count_read.bind(this,0));a.register_read(3,this,this.port_count_read.bind(this,1));a.register_read(5,this,this.port_count_read.bind(this,2));a.register_read(7,this,this.port_count_read.bind(this,3));a.register_write(192,this,this.port_addr_write.bind(this,4));a.register_write(196,this,this.port_addr_write.bind(this,5));a.register_write(200,this,this.port_addr_write.bind(this,6));a.register_write(204,this, +this.port_addr_write.bind(this,7));a.register_write(194,this,this.port_count_write.bind(this,4));a.register_write(198,this,this.port_count_write.bind(this,5));a.register_write(202,this,this.port_count_write.bind(this,6));a.register_write(206,this,this.port_count_write.bind(this,7));a.register_read(192,this,this.port_addr_read.bind(this,4));a.register_read(196,this,this.port_addr_read.bind(this,5));a.register_read(200,this,this.port_addr_read.bind(this,6));a.register_read(204,this,this.port_addr_read.bind(this, +7));a.register_read(194,this,this.port_count_read.bind(this,4));a.register_read(198,this,this.port_count_read.bind(this,5));a.register_read(202,this,this.port_count_read.bind(this,6));a.register_read(206,this,this.port_count_read.bind(this,7));a.register_write(135,this,this.port_page_write.bind(this,0));a.register_write(131,this,this.port_page_write.bind(this,1));a.register_write(129,this,this.port_page_write.bind(this,2));a.register_write(130,this,this.port_page_write.bind(this,3));a.register_write(143, +this,this.port_page_write.bind(this,4));a.register_write(139,this,this.port_page_write.bind(this,5));a.register_write(137,this,this.port_page_write.bind(this,6));a.register_write(138,this,this.port_page_write.bind(this,7));a.register_read(135,this,this.port_page_read.bind(this,0));a.register_read(131,this,this.port_page_read.bind(this,1));a.register_read(129,this,this.port_page_read.bind(this,2));a.register_read(130,this,this.port_page_read.bind(this,3));a.register_read(143,this,this.port_page_read.bind(this, +4));a.register_read(139,this,this.port_page_read.bind(this,5));a.register_read(137,this,this.port_page_read.bind(this,6));a.register_read(138,this,this.port_page_read.bind(this,7));a.register_write(1159,this,this.port_pagehi_write.bind(this,0));a.register_write(1155,this,this.port_pagehi_write.bind(this,1));a.register_write(1153,this,this.port_pagehi_write.bind(this,2));a.register_write(1154,this,this.port_pagehi_write.bind(this,3));a.register_write(1163,this,this.port_pagehi_write.bind(this,5)); +a.register_write(1161,this,this.port_pagehi_write.bind(this,6));a.register_write(1162,this,this.port_pagehi_write.bind(this,7));a.register_read(1159,this,this.port_pagehi_read.bind(this,0));a.register_read(1155,this,this.port_pagehi_read.bind(this,1));a.register_read(1153,this,this.port_pagehi_read.bind(this,2));a.register_read(1154,this,this.port_pagehi_read.bind(this,3));a.register_read(1163,this,this.port_pagehi_read.bind(this,5));a.register_read(1161,this,this.port_pagehi_read.bind(this,6));a.register_read(1162, +this,this.port_pagehi_read.bind(this,7));a.register_write(10,this,this.port_singlemask_write.bind(this,0));a.register_write(212,this,this.port_singlemask_write.bind(this,4));a.register_write(15,this,this.port_multimask_write.bind(this,0));a.register_write(222,this,this.port_multimask_write.bind(this,4));a.register_read(15,this,this.port_multimask_read.bind(this,0));a.register_read(222,this,this.port_multimask_read.bind(this,4));a.register_write(11,this,this.port_mode_write.bind(this,0));a.register_write(214, +this,this.port_mode_write.bind(this,4));a.register_write(12,this,this.portC_write);a.register_write(216,this,this.portC_write)}L.prototype.get_state=function(){return[this.channel_page,this.channel_pagehi,this.channel_addr,this.channel_addr_init,this.channel_count,this.channel_count_init,this.channel_mask,this.channel_mode,this.lsb_msb_flipflop]}; +L.prototype.set_state=function(a){this.channel_page=a[0];this.channel_pagehi=a[1];this.channel_addr=a[2];this.channel_addr_init=a[3];this.channel_count=a[4];this.channel_count_init=a[5];this.channel_mask=a[6];this.channel_mode=a[7];this.lsb_msb_flipflop=a[8]};L.prototype.port_count_write=function(a,b){A(b);this.channel_count[a]=this.flipflop_get(this.channel_count[a],b,!1);this.channel_count_init[a]=this.flipflop_get(this.channel_count_init[a],b,!0)}; +L.prototype.port_count_read=function(a){A(this.channel_count[a]);return this.flipflop_read(this.channel_count[a])};L.prototype.port_addr_write=function(a,b){A(b);this.channel_addr[a]=this.flipflop_get(this.channel_addr[a],b,!1);this.channel_addr_init[a]=this.flipflop_get(this.channel_addr_init[a],b,!0)};L.prototype.port_addr_read=function(a){A(this.channel_addr[a]);return this.flipflop_read(this.channel_addr[a])};L.prototype.port_pagehi_write=function(a,b){A(b);this.channel_pagehi[a]=b}; +L.prototype.port_pagehi_read=function(a){return this.channel_pagehi[a]};L.prototype.port_page_write=function(a,b){A(b);this.channel_page[a]=b};L.prototype.port_page_read=function(a){return this.channel_page[a]};L.prototype.port_singlemask_write=function(a,b){this.update_mask((b&3)+a,b&4?1:0)};L.prototype.port_multimask_write=function(a,b){A(b);for(var c=0;4>c;c++)this.update_mask(a+c,b&1<a.byteLength)e(!0);else{var k=this.cpu;this.channel_addr[d]+=g;a.get(b,g,function(l){k.write_blob(l,f);e(!1)})}}; +L.prototype.do_write=function(a,b,c,d,e){var g=this.channel_count[d]+1&65535,f=5<=d?2:1,k=g*f,l=this.address_get_8bit(d),m=!1,n=!1,p=this.channel_mode[d]&16;J("to "+A(l)+" len "+A(k),16);ck&&(n=!0);b+k>a.byteLength?e(!0):(this.channel_addr[d]+=g,this.channel_count[d]-=g,!m&&p&&(this.channel_addr[d]=this.channel_addr_init[d],this.channel_count[d]=this.channel_count_init[d]),a.set(b,this.cpu.mem8.subarray(l,l+k),()=>{n&&p?this.do_write(a,b+k,c-k,d,e):e(!1)}))}; +L.prototype.address_get_8bit=function(a){var b=this.channel_addr[a];5<=a&&(b<<=1);b=b&65535|this.channel_page[a]<<16;return b|=this.channel_pagehi[a]<<24};L.prototype.count_get_8bit=function(a){var b=this.channel_count[a]+1;5<=a&&(b*=2);return b};L.prototype.flipflop_get=function(a,b,c){c||(this.lsb_msb_flipflop^=1);return this.lsb_msb_flipflop?a&-256|b:a&-65281|b<<8};L.prototype.flipflop_read=function(a){return(this.lsb_msb_flipflop^=1)?a&255:a>>8&255};function qa(a,b){this.cpu=a;this.bus=b;this.counter_start_time=new Float64Array(3);this.counter_start_value=new Uint16Array(3);this.counter_next_low=new Uint8Array(4);this.counter_enabled=new Uint8Array(4);this.counter_mode=new Uint8Array(4);this.counter_read_mode=new Uint8Array(4);this.counter_latch=new Uint8Array(4);this.counter_latch_value=new Uint16Array(3);this.counter_reload=new Uint16Array(3);a.io.register_read(97,this,function(){var c=D.microtick(),d=66.66666666666667*c&1;c=this.did_rollover(2, +c);return d<<4|c<<5});a.io.register_write(97,this,function(c){c&1?this.bus.send("pcspeaker-enable"):this.bus.send("pcspeaker-disable")});a.io.register_read(64,this,function(){return this.counter_read(0)});a.io.register_read(65,this,function(){return this.counter_read(1)});a.io.register_read(66,this,function(){return this.counter_read(2)});a.io.register_write(64,this,function(c){this.counter_write(0,c)});a.io.register_write(65,this,function(c){this.counter_write(1,c)});a.io.register_write(66,this, +function(c){this.counter_write(2,c);this.bus.send("pcspeaker-update",[this.counter_mode[2],this.counter_reload[2]])});a.io.register_write(67,this,this.port43_write)}qa.prototype.get_state=function(){var a=[];a[0]=this.counter_next_low;a[1]=this.counter_enabled;a[2]=this.counter_mode;a[3]=this.counter_read_mode;a[4]=this.counter_latch;a[5]=this.counter_latch_value;a[6]=this.counter_reload;a[7]=this.counter_start_time;a[8]=this.counter_start_value;return a}; +qa.prototype.set_state=function(a){this.counter_next_low=a[0];this.counter_enabled=a[1];this.counter_mode=a[2];this.counter_read_mode=a[3];this.counter_latch=a[4];this.counter_latch_value=a[5];this.counter_reload=a[6];this.counter_start_time=a[7];this.counter_start_value=a[8]}; +qa.prototype.timer=function(a,b){var c=100;b||(this.counter_enabled[0]&&this.did_rollover(0,a)?(this.counter_start_value[0]=this.get_counter_value(0,a),this.counter_start_time[0]=a,this.cpu.device_lower_irq(0),this.cpu.device_raise_irq(0),0===this.counter_mode[0]&&(this.counter_enabled[0]=0)):this.cpu.device_lower_irq(0),this.counter_enabled[0]&&(c=(this.counter_start_value[0]-Math.floor(1193.1816666*(a-this.counter_start_time[0])))/1193.1816666));return c}; +qa.prototype.get_counter_value=function(a,b){if(!this.counter_enabled[a])return 0;b=this.counter_start_value[a]-Math.floor(1193.1816666*(b-this.counter_start_time[a]));a=this.counter_reload[a];b>=a?b%=a:0>b&&(b=b%a+a);return b};qa.prototype.did_rollover=function(a,b){b-=this.counter_start_time[a];return 0>b?!0:this.counter_start_value[a]>8;b=this.counter_next_low[a];3===this.counter_mode[a]&&(this.counter_next_low[a]^=1);a=this.get_counter_value(a,D.microtick());return b?a&255:a>>8}; +qa.prototype.counter_write=function(a,b){this.counter_reload[a]=this.counter_next_low[a]?this.counter_reload[a]&-256|b:this.counter_reload[a]&255|b<<8;3===this.counter_read_mode[a]&&this.counter_next_low[a]||(this.counter_reload[a]||(this.counter_reload[a]=65535),this.counter_start_value[a]=this.counter_reload[a],this.counter_enabled[a]=!0,this.counter_start_time[a]=D.microtick(),A(this.counter_reload[a]));3===this.counter_read_mode[a]&&(this.counter_next_low[a]^=1)}; +qa.prototype.port43_write=function(a){var b=a>>1&7,c=a>>6&3;a=a>>4&3;3!==c&&(0===a?(this.counter_latch[c]=2,b=this.get_counter_value(c,D.microtick()),this.counter_latch_value[c]=b?b-1:0):(6<=b&&(b&=-5),this.counter_next_low[c]=1===a?0:1,0===c&&this.cpu.device_lower_irq(0),0!==b&&3!==b&&2!==b&&A(b),this.counter_mode[c]=b,this.counter_read_mode[c]=a,2===c&&this.bus.send("pcspeaker-update",[this.counter_mode[2],this.counter_reload[2]])))};qa.prototype.dump=function(){};var ra=Uint32Array.from([655360,655360,720896,753664]),ua=Uint32Array.from([131072,65536,32768,32768]); +function M(a,b,c){this.cpu=a;this.bus=b;this.vga_memory_size=c;this.cursor_address=0;this.cursor_scanline_start=14;this.cursor_scanline_end=15;this.max_cols=80;this.max_rows=25;this.virtual_height=this.virtual_width=this.screen_height=this.screen_width=0;this.layers=[];this.start_address_latched=this.start_address=0;this.crtc=new Uint8Array(25);this.line_compare=this.offset_register=this.preset_row_scan=this.underline_location_register=this.vertical_blank_start=this.vertical_display_enable_end=this.horizontal_blank_start= +this.horizontal_display_enable_end=this.crtc_mode=0;this.graphical_mode_is_linear=!0;this.graphical_mode=!1;setTimeout(()=>{b.send("screen-set-mode",this.graphical_mode)},0);this.vga256_palette=new Int32Array(256);this.latch_dword=0;this.svga_version=45253;this.svga_height=this.svga_width=0;this.svga_enabled=!1;this.svga_bpp=32;this.svga_offset_y=this.svga_offset=this.svga_bank_offset=0;this.pci_space=[52,18,17,17,3,1,0,0,0,0,0,3,0,0,0,0,8,14680064,57344,224,0,0,0,0,0,0,191,254,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,244,26,0,17,0,0,190,254,0,0,0,0,0,0,0,0,0,0,0,0];this.pci_id=144;this.pci_bars=[{size:c}];this.pci_rom_size=65536;this.pci_rom_address=4272947200;this.name="vga";this.stats={is_graphical:!1,res_x:0,res_y:0,bpp:0};this.dac_state=this.dac_color_index_read=this.dac_color_index_write=this.index_crtc=0;this.dac_mask=255;this.dac_map=new Uint8Array(16);this.attribute_controller_index=-1;this.palette_source=32;this.color_select=this.horizontal_panning=this.color_plane_enable=this.attribute_mode= +0;this.sequencer_index=-1;this.plane_write_bm=15;this.clocking_mode=this.sequencer_memory_mode=0;this.graphics_index=-1;this.planar_rotate_reg=this.planar_mode=this.plane_read=0;this.planar_bitmap=255;this.max_scan_line=this.color_dont_care=this.color_compare=this.miscellaneous_graphics_register=this.planar_setreset_enable=this.planar_setreset=0;this.port_3DA_value=this.miscellaneous_output_register=255;c=a.io;c.register_write(960,this,this.port3C0_write);c.register_read(960,this,this.port3C0_read, +this.port3C0_read16);c.register_read(961,this,this.port3C1_read);c.register_write(962,this,this.port3C2_write);c.register_write_consecutive(964,this,this.port3C4_write,this.port3C5_write);c.register_read(964,this,this.port3C4_read);c.register_read(965,this,this.port3C5_read);c.register_write_consecutive(974,this,this.port3CE_write,this.port3CF_write);c.register_read(974,this,this.port3CE_read);c.register_read(975,this,this.port3CF_read);c.register_read(966,this,this.port3C6_read);c.register_write(966, +this,this.port3C6_write);c.register_write(967,this,this.port3C7_write);c.register_read(967,this,this.port3C7_read);c.register_write(968,this,this.port3C8_write);c.register_read(968,this,this.port3C8_read);c.register_write(969,this,this.port3C9_write);c.register_read(969,this,this.port3C9_read);c.register_read(972,this,this.port3CC_read);c.register_write_consecutive(980,this,this.port3D4_write,this.port3D5_write);c.register_read(980,this,this.port3D4_read);c.register_read(981,this,this.port3D5_read, +()=>this.port3D5_read());c.register_read(970,this,function(){return 0});c.register_read(986,this,this.port3DA_read);c.register_read(954,this,this.port3DA_read);this.dispi_index=-1;this.dispi_enable_value=0;c.register_write(462,this,void 0,this.port1CE_write);c.register_write(463,this,void 0,this.port1CF_write);c.register_read(463,this,void 0,this.port1CF_read);void 0===this.vga_memory_size||262144>this.vga_memory_size?this.vga_memory_size=262144:268435456>>0;this.svga_memory=r.view(Uint8Array,a.wasm_memory,d,this.vga_memory_size);this.diff_addr_min=this.vga_memory_size;this.diff_addr_max=0;this.diff_plot_min=this.vga_memory_size;this.diff_plot_max=0;this.image_data=null;b.register("screen-fill-buffer",function(){this.screen_fill_buffer()},this);this.vga_memory=new Uint8Array(262144);this.plane0=new Uint8Array(this.vga_memory.buffer, +0,65536);this.plane1=new Uint8Array(this.vga_memory.buffer,65536,65536);this.plane2=new Uint8Array(this.vga_memory.buffer,131072,65536);this.plane3=new Uint8Array(this.vga_memory.buffer,196608,65536);this.pixel_buffer=new Uint8Array(524288);var e=this;c.mmap_register(655360,131072,function(g){return e.vga_memory_read(g)},function(g,f){e.vga_memory_write(g,f)});a.devices.pci.register_device(this)} +M.prototype.get_state=function(){var a=[];a[0]=this.vga_memory_size;a[1]=this.cursor_address;a[2]=this.cursor_scanline_start;a[3]=this.cursor_scanline_end;a[4]=this.max_cols;a[5]=this.max_rows;a[6]=this.vga_memory;a[7]=this.dac_state;a[8]=this.start_address;a[9]=this.graphical_mode;a[10]=this.vga256_palette;a[11]=this.latch_dword;a[12]=this.color_compare;a[13]=this.color_dont_care;a[14]=this.miscellaneous_graphics_register;a[15]=this.svga_width;a[16]=this.svga_height;a[17]=this.crtc_mode;a[18]=this.svga_enabled; +a[19]=this.svga_bpp;a[20]=this.svga_bank_offset;a[21]=this.svga_offset;a[22]=this.index_crtc;a[23]=this.dac_color_index_write;a[24]=this.dac_color_index_read;a[25]=this.dac_map;a[26]=this.sequencer_index;a[27]=this.plane_write_bm;a[28]=this.sequencer_memory_mode;a[29]=this.graphics_index;a[30]=this.plane_read;a[31]=this.planar_mode;a[32]=this.planar_rotate_reg;a[33]=this.planar_bitmap;a[34]=this.max_scan_line;a[35]=this.miscellaneous_output_register;a[36]=this.port_3DA_value;a[37]=this.dispi_index; +a[38]=this.dispi_enable_value;a[39]=this.svga_memory;a[40]=this.graphical_mode_is_linear;a[41]=this.attribute_controller_index;a[42]=this.offset_register;a[43]=this.planar_setreset;a[44]=this.planar_setreset_enable;a[45]=this.start_address_latched;a[46]=this.crtc;a[47]=this.horizontal_display_enable_end;a[48]=this.horizontal_blank_start;a[49]=this.vertical_display_enable_end;a[50]=this.vertical_blank_start;a[51]=this.underline_location_register;a[52]=this.preset_row_scan;a[53]=this.offset_register; +a[54]=this.palette_source;a[55]=this.attribute_mode;a[56]=this.color_plane_enable;a[57]=this.horizontal_panning;a[58]=this.color_select;a[59]=this.clocking_mode;a[60]=this.line_compare;a[61]=this.pixel_buffer;a[62]=this.dac_mask;return a}; +M.prototype.set_state=function(a){this.vga_memory_size=a[0];this.cursor_address=a[1];this.cursor_scanline_start=a[2];this.cursor_scanline_end=a[3];this.max_cols=a[4];this.max_rows=a[5];a[6]&&this.vga_memory.set(a[6]);this.dac_state=a[7];this.start_address=a[8];this.graphical_mode=a[9];this.vga256_palette=a[10];this.latch_dword=a[11];this.color_compare=a[12];this.color_dont_care=a[13];this.miscellaneous_graphics_register=a[14];this.svga_width=a[15];this.svga_height=a[16];this.crtc_mode=a[17];this.svga_enabled= +a[18];this.svga_bpp=a[19];this.svga_bank_offset=a[20];this.svga_offset=a[21];this.index_crtc=a[22];this.dac_color_index_write=a[23];this.dac_color_index_read=a[24];this.dac_map=a[25];this.sequencer_index=a[26];this.plane_write_bm=a[27];this.sequencer_memory_mode=a[28];this.graphics_index=a[29];this.plane_read=a[30];this.planar_mode=a[31];this.planar_rotate_reg=a[32];this.planar_bitmap=a[33];this.max_scan_line=a[34];this.miscellaneous_output_register=a[35];this.port_3DA_value=a[36];this.dispi_index= +a[37];this.dispi_enable_value=a[38];this.svga_memory.set(a[39]);this.graphical_mode_is_linear=a[40];this.attribute_controller_index=a[41];this.offset_register=a[42];this.planar_setreset=a[43];this.planar_setreset_enable=a[44];this.start_address_latched=a[45];this.crtc.set(a[46]);this.horizontal_display_enable_end=a[47];this.horizontal_blank_start=a[48];this.vertical_display_enable_end=a[49];this.vertical_blank_start=a[50];this.underline_location_register=a[51];this.preset_row_scan=a[52];this.offset_register= +a[53];this.palette_source=a[54];this.attribute_mode=a[55];this.color_plane_enable=a[56];this.horizontal_panning=a[57];this.color_select=a[58];this.clocking_mode=a[59];this.line_compare=a[60];a[61]&&this.pixel_buffer.set(a[61]);this.dac_mask=void 0===a[62]?255:a[62];this.bus.send("screen-set-mode",this.graphical_mode);this.graphical_mode?(this.screen_height=this.screen_width=0,this.svga_enabled?(this.set_size_graphical(this.svga_width,this.svga_height,this.svga_bpp,this.svga_width,this.svga_height), +this.update_layers()):(this.update_vga_size(),this.update_layers(),this.complete_replot())):(this.set_size_text(this.max_cols,this.max_rows),this.update_cursor_scanline(),this.update_cursor());this.complete_redraw()}; +M.prototype.vga_memory_read=function(a){if(this.svga_enabled&&this.graphical_mode_is_linear)return this.cpu.read8((a-655360|this.svga_bank_offset)+3758096384|0);var b=this.miscellaneous_graphics_register>>2&3;a-=ra[b];if(0>a||a>=ua[b])return A(a),0;this.latch_dword=this.plane0[a];this.latch_dword|=this.plane1[a]<<8;this.latch_dword|=this.plane2[a]<<16;this.latch_dword|=this.plane3[a]<<24;if(this.planar_mode&8)return b=255,this.color_dont_care&1&&(b&=this.plane0[a]^~(this.color_compare&1?255:0)),this.color_dont_care& +2&&(b&=this.plane1[a]^~(this.color_compare&2?255:0)),this.color_dont_care&4&&(b&=this.plane2[a]^~(this.color_compare&4?255:0)),this.color_dont_care&8&&(b&=this.plane3[a]^~(this.color_compare&8?255:0)),b;b=this.plane_read;this.graphical_mode?this.sequencer_memory_mode&8?(b=a&3,a&=-4):this.planar_mode&16&&(b=a&1,a&=-2):b=0;return this.vga_memory[b<<16|a]}; +M.prototype.vga_memory_write=function(a,b){if(this.svga_enabled&&this.graphical_mode&&this.graphical_mode_is_linear)this.cpu.write8((a-655360|this.svga_bank_offset)+3758096384|0,b);else{var c=this.miscellaneous_graphics_register>>2&3;a-=ra[c];0>a||a>=ua[c]?(A(a),A(b)):this.graphical_mode?this.vga_memory_write_graphical(a,b):this.plane_write_bm&3&&this.vga_memory_write_text_mode(a,b)}}; +M.prototype.vga_memory_write_graphical=function(a,b){var c=this.planar_mode&3,d=this.apply_feed(this.planar_bitmap),e=this.apply_expand(this.planar_setreset),g=this.apply_expand(this.planar_setreset_enable);switch(c){case 0:b=this.apply_rotate(b);var f=this.apply_feed(b);f=this.apply_setreset(f,g);f=this.apply_logical(f,this.latch_dword);f=this.apply_bitmask(f,d);break;case 1:f=this.latch_dword;break;case 2:f=this.apply_expand(b);f=this.apply_logical(f,this.latch_dword);f=this.apply_bitmask(f,d); +break;case 3:b=this.apply_rotate(b),d&=this.apply_feed(b),f=this.apply_bitmask(e,d)}b=15;switch(this.sequencer_memory_mode&12){case 0:b=5<<(a&1);a&=-2;break;case 8:case 12:b=1<<(a&3),a&=-4}b&=this.plane_write_bm;b&1&&(this.plane0[a]=f>>0&255);b&2&&(this.plane1[a]=f>>8&255);b&4&&(this.plane2[a]=f>>16&255);b&8&&(this.plane3[a]=f>>24&255);a=this.vga_addr_to_pixel(a);this.partial_replot(a,a+7)};M.prototype.apply_feed=function(a){return a|a<<8|a<<16|a<<24}; +M.prototype.apply_expand=function(a){return(a&1?255:0)|(a&2?255:0)<<8|(a&4?255:0)<<16|(a&8?255:0)<<24};M.prototype.apply_rotate=function(a){return(a|a<<8)>>>(this.planar_rotate_reg&7)&255};M.prototype.apply_setreset=function(a,b){var c=this.apply_expand(this.planar_setreset);return(a|b&c)&(~b|c)};M.prototype.apply_logical=function(a,b){switch(this.planar_rotate_reg&24){case 8:return a&b;case 16:return a|b;case 24:return a^b}return a};M.prototype.apply_bitmask=function(a,b){return b&a|~b&this.latch_dword}; +M.prototype.text_mode_redraw=function(){var a=this.start_address<<1;const b=this.scan_line_to_screen_row(this.line_compare),c=Math.max(0,2*(2*this.offset_register-this.max_cols));for(var d=0;d>4&15]],this.vga256_palette[this.dac_mask&this.dac_map[f&15]]]);a+=2}a+=c}}; +M.prototype.vga_memory_write_text_mode=function(a,b){var c=Math.max(this.max_cols,2*this.offset_register);let d;if(a>>1>=this.start_address){var e=(a>>1)-this.start_address;d=e/c|0;c=e%c}else e=a>>1,d=(e/c|0)+this.scan_line_to_screen_row(this.line_compare),c=e%c;if(!(c>=this.max_cols||d>=this.max_rows)){if(a&1){var g=b;e=this.vga_memory[a&-2]}else e=b,g=this.vga_memory[a|1];this.bus.send("screen-put-char",[d,c,e,this.vga256_palette[this.dac_mask&this.dac_map[g>>4&15]],this.vga256_palette[this.dac_mask& +this.dac_map[g&15]]]);this.vga_memory[a]=b}};M.prototype.update_cursor=function(){var a=Math.max(this.max_cols,2*this.offset_register);let b;this.cursor_address>=this.start_address?(b=(this.cursor_address-this.start_address)/a|0,a=(this.cursor_address-this.start_address)%a):(b=(this.cursor_address/a|0)+this.scan_line_to_screen_row(this.line_compare),a=this.cursor_address%a);b=Math.min(this.max_rows-1,b);a=Math.min(this.max_cols-1,a);this.bus.send("screen-update-cursor",[b,a])}; +M.prototype.complete_redraw=function(){this.graphical_mode?this.svga_enabled?this.cpu.svga_mark_dirty():(this.diff_addr_min=0,this.diff_addr_max=524288):this.text_mode_redraw()};M.prototype.complete_replot=function(){this.graphical_mode&&!this.svga_enabled&&(this.diff_plot_min=0,this.diff_plot_max=524288,this.complete_redraw())};M.prototype.partial_redraw=function(a,b){athis.diff_addr_max&&(this.diff_addr_max=b)}; +M.prototype.partial_replot=function(a,b){athis.diff_plot_max&&(this.diff_plot_max=b);this.partial_redraw(a,b)};M.prototype.reset_diffs=function(){this.diff_addr_min=this.vga_memory_size;this.diff_addr_max=0;this.diff_plot_min=this.vga_memory_size;this.diff_plot_max=0};M.prototype.destroy=function(){};M.prototype.vga_bytes_per_line=function(){var a=this.offset_register<<2;this.underline_location_register&64?a<<=1:this.crtc_mode&64&&(a>>>=1);return a}; +M.prototype.vga_addr_shift_count=function(){var a=128+(~this.underline_location_register&this.crtc_mode&64);a-=this.underline_location_register&64;a-=this.attribute_mode&64;return a>>>6}; +M.prototype.vga_addr_to_pixel=function(a){var b=this.vga_addr_shift_count();if(~this.crtc_mode&3){var c=a-this.start_address;c&=this.crtc_mode<<13|-24577;c<<=b;var d=c/this.virtual_width|0;c%=this.virtual_width;switch(this.crtc_mode&3){case 2:d=d<<1|a>>13&1;break;case 1:d=d<<1|a>>14&1;break;case 0:d=d<<2|a>>13&3}return d*this.virtual_width+c+(this.start_address<>>=1);a=Math.ceil(a/(1+(this.max_scan_line&31)));this.crtc_mode&1||(a<<=1);this.crtc_mode&2||(a<<=1);return a};M.prototype.set_size_text=function(a,b){this.max_cols=a;this.max_rows=b;this.bus.send("screen-set-size-text",[a,b])}; +M.prototype.set_size_graphical=function(a,b,c,d,e){if(!this.stats.is_graphical||this.stats.bpp!==c||this.screen_width!==a||this.screen_height!==b||this.virtual_width!==d||this.virtual_height!==e){this.screen_width=a;this.screen_height=b;this.virtual_width=d;this.virtual_height=e;this.stats.bpp=c;this.stats.is_graphical=!0;this.stats.res_x=a;this.stats.res_y=b;if("undefined"!==typeof ImageData){const g=d*e,f=this.cpu.svga_allocate_dest_buffer(g)>>>0;this.dest_buffet_offset=f;this.image_data=new ImageData(new Uint8ClampedArray(this.cpu.wasm_memory.buffer, +f,4*g),d,e);this.cpu.svga_mark_dirty()}this.bus.send("screen-set-size-graphical",[a,b,d,e,c])}}; +M.prototype.update_vga_size=function(){if(!this.svga_enabled){var a=Math.min(1+this.horizontal_display_enable_end,this.horizontal_blank_start),b=Math.min(1+this.vertical_display_enable_end,this.vertical_blank_start);if(a&&b)if(this.graphical_mode){a<<=3;var c=this.offset_register<<4;this.attribute_mode&64&&(a>>>=1,c>>>=1);b=this.scan_line_to_screen_row(b);var d=Math.ceil(ua[0]/this.vga_bytes_per_line());this.set_size_graphical(a,b,8,c,d);this.update_vertical_retrace();this.update_layers()}else this.max_scan_line& +128&&(b>>>=1),c=b/(1+(this.max_scan_line&31))|0,a&&c&&this.set_size_text(a,c)}}; +M.prototype.update_layers=function(){this.graphical_mode||this.text_mode_redraw();if(this.svga_enabled)this.layers=[];else if(this.virtual_width&&this.screen_width)if(!this.palette_source||this.clocking_mode&32)this.layers=[],this.bus.send("screen-clear");else{var a=this.start_address_latched,b=this.horizontal_panning;this.attribute_mode&64&&(b>>>=1);var c=this.preset_row_scan>>5&3,d=this.vga_addr_to_pixel(a+c);a=d/this.virtual_width|0;var e=d%this.virtual_width+b;d=this.scan_line_to_screen_row(1+ +this.line_compare);d=Math.min(d,this.screen_height);var g=this.screen_height-d;this.layers=[];e=-e;for(var f=0;ethis.attribute_controller_index)A(this.attribute_controller_index),A(a),this.dac_map[this.attribute_controller_index]=a,this.attribute_mode&64||this.complete_redraw();else switch(this.attribute_controller_index){case 16:A(a);if(this.attribute_mode!==a){var b= +this.attribute_mode;this.attribute_mode=a;var c=0<(a&1);this.svga_enabled||this.graphical_mode===c||(this.graphical_mode=c,this.bus.send("screen-set-mode",this.graphical_mode));(b^a)&64&&this.complete_replot();this.update_vga_size();this.complete_redraw()}break;case 18:A(a);this.color_plane_enable!==a&&(this.color_plane_enable=a,this.complete_redraw());break;case 19:A(a);this.horizontal_panning!==a&&(this.horizontal_panning=a&15,this.update_layers());break;case 20:A(a);this.color_select!==a&&(this.color_select= +a,this.complete_redraw());break;default:A(this.attribute_controller_index),A(a)}this.attribute_controller_index=-1}};M.prototype.port3C0_read=function(){return(this.attribute_controller_index|this.palette_source)&255};M.prototype.port3C0_read16=function(){return this.port3C0_read()|this.port3C1_read()<<8&65280}; +M.prototype.port3C1_read=function(){if(16>this.attribute_controller_index)return A(this.attribute_controller_index),A(this.dac_map[this.attribute_controller_index]),this.dac_map[this.attribute_controller_index]&255;switch(this.attribute_controller_index){case 16:return A(this.attribute_mode),this.attribute_mode;case 18:return A(this.color_plane_enable),this.color_plane_enable;case 19:return A(this.horizontal_panning),this.horizontal_panning;case 20:return A(this.color_select),this.color_select;default:A(this.attribute_controller_index)}return 255}; +M.prototype.port3C2_write=function(a){A(a);this.miscellaneous_output_register=a};M.prototype.port3C4_write=function(a){this.sequencer_index=a};M.prototype.port3C4_read=function(){return this.sequencer_index};M.prototype.port3C5_write=function(a){switch(this.sequencer_index){case 1:A(a);var b=this.clocking_mode;this.clocking_mode=a;(b^a)&32&&this.update_layers();break;case 2:A(a);this.plane_write_bm=a;break;case 4:A(a);this.sequencer_memory_mode=a;break;default:A(this.sequencer_index),A(a)}}; +M.prototype.port3C5_read=function(){A(this.sequencer_index);switch(this.sequencer_index){case 1:return this.clocking_mode;case 2:return this.plane_write_bm;case 4:return this.sequencer_memory_mode;case 6:return 18}return 0};M.prototype.port3C6_write=function(a){this.dac_mask=a};M.prototype.port3C6_read=function(){return this.dac_mask};M.prototype.port3C7_write=function(a){A(a);this.dac_color_index_read=3*a;this.dac_state&=0};M.prototype.port3C7_read=function(){return this.dac_state}; +M.prototype.port3C8_write=function(a){this.dac_color_index_write=3*a;this.dac_state|=3};M.prototype.port3C8_read=function(){return this.dac_color_index_write/3&255}; +M.prototype.port3C9_write=function(a){var b=this.dac_color_index_write/3|0,c=this.dac_color_index_write%3,d=this.vga256_palette[b];if(0===(this.dispi_enable_value&32)){a&=63;const e=a&1;a=a<<2|e<<1|e}0===c?d=d&-16711681|a<<16:1===c?d=d&-65281|a<<8:(d=d&-256|a,A(b),A(d));this.vga256_palette[b]!==d&&(this.vga256_palette[b]=d,this.complete_redraw());this.dac_color_index_write++}; +M.prototype.port3C9_read=function(){var a=this.vga256_palette[this.dac_color_index_read/3|0]>>8*(2-this.dac_color_index_read%3)&255;this.dac_color_index_read++;return this.dispi_enable_value&32?a:a>>2};M.prototype.port3CC_read=function(){return this.miscellaneous_output_register};M.prototype.port3CE_write=function(a){this.graphics_index=a};M.prototype.port3CE_read=function(){return this.graphics_index}; +M.prototype.port3CF_write=function(a){switch(this.graphics_index){case 0:this.planar_setreset=a;A(a);break;case 1:this.planar_setreset_enable=a;A(a);break;case 2:this.color_compare=a;A(a);break;case 3:this.planar_rotate_reg=a;A(a);break;case 4:this.plane_read=a;A(a);break;case 5:var b=this.planar_mode;this.planar_mode=a;A(a);(b^a)&96&&this.complete_replot();break;case 6:A(a);this.miscellaneous_graphics_register!==a&&(this.miscellaneous_graphics_register=a,this.update_vga_size());break;case 7:this.color_dont_care= +a;A(a);break;case 8:this.planar_bitmap=a;A(a);break;default:A(this.graphics_index),A(a)}};M.prototype.port3CF_read=function(){A(this.graphics_index);switch(this.graphics_index){case 0:return this.planar_setreset;case 1:return this.planar_setreset_enable;case 2:return this.color_compare;case 3:return this.planar_rotate_reg;case 4:return this.plane_read;case 5:return this.planar_mode;case 6:return this.miscellaneous_graphics_register;case 7:return this.color_dont_care;case 8:return this.planar_bitmap}return 0}; +M.prototype.port3D4_write=function(a){this.index_crtc=a};M.prototype.port3D4_read=function(){return this.index_crtc}; +M.prototype.port3D5_write=function(a){switch(this.index_crtc){case 1:A(a);this.horizontal_display_enable_end!==a&&(this.horizontal_display_enable_end=a,this.update_vga_size());break;case 2:this.horizontal_blank_start!==a&&(this.horizontal_blank_start=a,this.update_vga_size());break;case 7:A(a);var b=this.vertical_display_enable_end;this.vertical_display_enable_end&=255;this.vertical_display_enable_end=this.vertical_display_enable_end|a<<3&512|a<<7&256;b!=this.vertical_display_enable_end&&this.update_vga_size(); +this.line_compare=this.line_compare&767|a<<4&256;b=this.vertical_blank_start;this.vertical_blank_start=this.vertical_blank_start&767|a<<5&256;b!==this.vertical_blank_start&&this.update_vga_size();this.update_layers();break;case 8:A(a);this.preset_row_scan=a;this.update_layers();break;case 9:A(a);this.max_scan_line=a;this.line_compare=this.line_compare&511|a<<3&512;b=this.vertical_blank_start;this.vertical_blank_start=this.vertical_blank_start&511|a<<4&512;b!==this.vertical_blank_start&&this.update_vga_size(); +this.update_layers();break;case 10:A(a);this.cursor_scanline_start=a;this.update_cursor_scanline();break;case 11:A(a);this.cursor_scanline_end=a;this.update_cursor_scanline();break;case 12:(this.start_address>>8&255)!==a&&(this.start_address=this.start_address&255|a<<8,this.update_layers(),~this.crtc_mode&3&&this.complete_replot());A(a);A(this.start_address,4);break;case 13:(this.start_address&255)!==a&&(this.start_address=this.start_address&65280|a,this.update_layers(),~this.crtc_mode&3&&this.complete_replot()); +A(a);A(this.start_address,4);break;case 14:A(a);this.cursor_address=this.cursor_address&255|a<<8;this.update_cursor();break;case 15:A(a);this.cursor_address=this.cursor_address&65280|a;this.update_cursor();break;case 18:A(a);(this.vertical_display_enable_end&255)!==a&&(this.vertical_display_enable_end=this.vertical_display_enable_end&768|a,this.update_vga_size());break;case 19:A(a);this.offset_register!==a&&(this.offset_register=a,this.update_vga_size(),~this.crtc_mode&3&&this.complete_replot()); +break;case 20:A(a);this.underline_location_register!==a&&(b=this.underline_location_register,this.underline_location_register=a,this.update_vga_size(),(b^a)&64&&this.complete_replot());break;case 21:A(a);(this.vertical_blank_start&255)!==a&&(this.vertical_blank_start=this.vertical_blank_start&768|a,this.update_vga_size());break;case 23:A(a);this.crtc_mode!==a&&(b=this.crtc_mode,this.crtc_mode=a,this.update_vga_size(),(b^a)&67&&this.complete_replot());break;case 24:A(a);this.line_compare=this.line_compare& +768|a;this.update_layers();break;default:this.index_crtc>7&2|this.vertical_blank_start>>5&8|this.line_compare>>4&16|this.vertical_display_enable_end>>3&64;case 8:return this.preset_row_scan;case 9:return this.max_scan_line;case 10:return this.cursor_scanline_start;case 11:return this.cursor_scanline_end;case 12:return this.start_address&255; +case 13:return this.start_address>>8;case 14:return this.cursor_address>>8;case 15:return this.cursor_address&255;case 18:return this.vertical_display_enable_end&255;case 19:return this.offset_register;case 20:return this.underline_location_register;case 21:return this.vertical_blank_start&255;case 23:return this.crtc_mode;case 24:return this.line_compare&255}return this.index_crtc=a?this.svga_version=a:A(a);break;case 1:this.svga_width=a;2560>>16;case 6:return this.screen_width?this.screen_width:1;case 8:return 0;case 9:return this.svga_offset_y;case 10:return this.vga_memory_size/65536|0;default:A(this.dispi_index)}return 255}; +M.prototype.vga_replot=function(){for(var a=this.diff_plot_min&-16,b=Math.min(this.diff_plot_max|15,524287),c=this.vga_addr_shift_count(),d=~this.crtc_mode&3,e=this.planar_mode&96,g=this.attribute_mode&64;a<=b;){var f=a>>>c;if(d){var k=a/this.virtual_width|0,l=a-this.virtual_width*k;switch(d){case 1:f=(k&1)<<13;k>>>=1;break;case 2:f=(k&1)<<14;k>>>=1;break;case 3:f=(k&3)<<13,k>>>=2}f|=(k*this.virtual_width+l>>>c)+this.start_address}k=this.plane0[f];l=this.plane1[f];var m=this.plane2[f],n=this.plane3[f]; +f=new Uint8Array(8);switch(e){case 0:k<<=0;l<<=1;m<<=2;n<<=3;for(var p=7;0<=p;p--)f[7-p]=k>>p&1|l>>p&2|m>>p&4|n>>p&8;break;case 32:f[0]=k>>6&3|m>>4&12;f[1]=k>>4&3|m>>2&12;f[2]=k>>2&3|m>>0&12;f[3]=k>>0&3|m<<2&12;f[4]=l>>6&3|n>>4&12;f[5]=l>>4&3|n>>2&12;f[6]=l>>2&3|n>>0&12;f[7]=l>>0&3|n<<2&12;break;case 64:case 96:f[0]=k>>4&15,f[1]=k>>0&15,f[2]=l>>4&15,f[3]=l>>0&15,f[4]=m>>4&15,f[5]=m>>0&15,f[6]=n>>4&15,f[7]=n>>0&15}if(g)for(k=p=0;4>p;p++,a++,k+=2)this.pixel_buffer[a]=f[k]<<4|f[k+1];else for(p=0;8>p;p++, +a++)this.pixel_buffer[a]=f[p]}}; +M.prototype.vga_redraw=function(){var a=this.diff_addr_min,b=Math.min(this.diff_addr_max,524287);const c=new Int32Array(this.cpu.wasm_memory.buffer,this.dest_buffet_offset,this.virtual_width*this.virtual_height);var d=255,e=0;this.attribute_mode&128&&(d&=207,e|=this.color_select<<4&48);if(this.attribute_mode&64)for(;a<=b;a++){var g=this.pixel_buffer[a]&d|e;g=this.vga256_palette[g];c[a]=g&65280|g<<16|g>>16|4278190080}else for(d&=63,e|=this.color_select<<4&192;a<=b;a++)g=this.dac_map[this.pixel_buffer[a]& +this.color_plane_enable]&d|e,g=this.vga256_palette[g],c[a]=g&65280|g<<16|g>>16|4278190080}; +M.prototype.screen_fill_buffer=function(){if(this.graphical_mode){if(0===this.image_data.data.byteLength){var a=new Uint8ClampedArray(this.cpu.wasm_memory.buffer,this.dest_buffet_offset,4*this.virtual_width*this.virtual_height);this.image_data=new ImageData(a,this.virtual_width,this.virtual_height);this.update_layers()}if(this.svga_enabled){a=0;let d=this.svga_height;if(8===this.svga_bpp){const e=new Int32Array(this.cpu.wasm_memory.buffer,this.dest_buffet_offset,this.screen_width*this.screen_height), +g=new Uint8Array(this.cpu.wasm_memory.buffer,this.svga_memory.byteOffset,this.vga_memory_size);for(var b=0;b>16|4278190080}}else this.cpu.svga_fill_pixel_buffer(this.svga_bpp,this.svga_offset),b=15===this.svga_bpp?2:this.svga_bpp/8,a=((this.cpu.svga_dirty_bitmap_min_offset[0]/b|0)-this.svga_offset)/this.svga_width|0,d=(((this.cpu.svga_dirty_bitmap_max_offset[0]/b|0)-this.svga_offset)/this.svga_width|0)+1;ab)<<5|(0>a)<<4|8|this.mouse_clicks;this.last_mouse_packet=Date.now();this.mouse_buffer.push(c);this.mouse_buffer.push(a);this.mouse_buffer.push(b);4===this.mouse_id?(this.mouse_buffer.push(0|this.wheel_movement&15),this.wheel_movement=0):3===this.mouse_id&&(this.mouse_buffer.push(this.wheel_movement&255),this.wheel_movement=0);this.raise_irq()}; +N.prototype.apply_scaling2=function(a){var b=a>>31;switch(Math.abs(a)){case 0:case 1:case 3:return a;case 2:return b;case 4:return 6*b;case 5:return 9*b;default:return a<<1}}; +N.prototype.port60_read=function(){this.next_byte_is_ready=!1;if(!this.kbd_buffer.length&&!this.mouse_buffer.length)return this.last_port60_byte;this.next_byte_is_aux?(this.cpu.device_lower_irq(12),this.last_port60_byte=this.mouse_buffer.shift()):(this.cpu.device_lower_irq(1),this.last_port60_byte=this.kbd_buffer.shift());A(this.last_port60_byte);(this.kbd_buffer.length||this.mouse_buffer.length)&&this.raise_irq();return this.last_port60_byte}; +N.prototype.port64_read=function(){var a=16;this.next_byte_is_ready&&(a|=1);this.next_byte_is_aux&&(a|=32);A(a);return a}; +N.prototype.port60_write=function(a){A(a);if(this.read_command_register)this.command_register=a,this.read_command_register=!1,A(this.command_register);else if(this.read_output_register)this.read_output_register=!1,this.mouse_buffer.clear(),this.mouse_buffer.push(a),this.mouse_irq();else if(this.next_read_sample){this.next_read_sample=!1;this.mouse_buffer.clear();this.mouse_buffer.push(250);this.sample_rate=a;switch(this.mouse_detect_state){case -1:60===a?(this.mouse_reset_workaround=!0,this.mouse_detect_state= +0):(this.mouse_reset_workaround=!1,this.mouse_detect_state=200===a?1:0);break;case 0:200===a&&(this.mouse_detect_state=1);break;case 1:this.mouse_detect_state=100===a?2:200===a?3:0;break;case 2:80===a&&(this.mouse_id=3);this.mouse_detect_state=-1;break;case 3:80===a&&(this.mouse_id=4),this.mouse_detect_state=-1}A(a);A(this.mouse_id);this.sample_rate||(this.sample_rate=100);this.mouse_irq()}else if(this.next_read_resolution)this.next_read_resolution=!1,this.mouse_buffer.clear(),this.mouse_buffer.push(250), +this.resolution=3>7});a.io.register_write(113,this,this.cmos_port_write);a.io.register_read(113,this,this.cmos_port_read)} +va.prototype.get_state=function(){var a=[];a[0]=this.cmos_index;a[1]=this.cmos_data;a[2]=this.rtc_time;a[3]=this.last_update;a[4]=this.next_interrupt;a[5]=this.next_interrupt_alarm;a[6]=this.periodic_interrupt;a[7]=this.periodic_interrupt_time;a[8]=this.cmos_a;a[9]=this.cmos_b;a[10]=this.cmos_c;a[11]=this.nmi_disabled;return a}; +va.prototype.set_state=function(a){this.cmos_index=a[0];this.cmos_data=a[1];this.rtc_time=a[2];this.last_update=a[3];this.next_interrupt=a[4];this.next_interrupt_alarm=a[5];this.periodic_interrupt=a[6];this.periodic_interrupt_time=a[7];this.cmos_a=a[8];this.cmos_b=a[9];this.cmos_c=a[10];this.nmi_disabled=a[11]}; +va.prototype.timer=function(a){a=Date.now();this.rtc_time+=a-this.last_update;this.last_update=a;this.periodic_interrupt&&this.next_interrupt>4&15)};va.prototype.encode_time=function(a){return this.cmos_b&4?a:this.bcd_pack(a)};va.prototype.decode_time=function(a){return this.cmos_b&4?a:this.bcd_unpack(a)}; +va.prototype.cmos_port_read=function(){var a=this.cmos_index;switch(a){case 0:return this.encode_time((new Date(this.rtc_time)).getUTCSeconds());case 2:return this.encode_time((new Date(this.rtc_time)).getUTCMinutes());case 4:return this.encode_time((new Date(this.rtc_time)).getUTCHours());case 7:return this.encode_time((new Date(this.rtc_time)).getUTCDate());case 8:return this.encode_time((new Date(this.rtc_time)).getUTCMonth()+1);case 9:return this.encode_time((new Date(this.rtc_time)).getUTCFullYear()% +100);case 10:return 999<=D.microtick()%1E3?this.cmos_a|128:this.cmos_a;case 11:return this.cmos_b;case 12:return this.cpu.device_lower_irq(8),a=this.cmos_c,this.cmos_c&=-241,a;case 13:return 0;case 50:return this.encode_time((new Date(this.rtc_time)).getUTCFullYear()/100|0);default:return A(a),this.cmos_data[this.cmos_index]}}; +va.prototype.cmos_port_write=function(a){switch(this.cmos_index){case 10:this.cmos_a=a&127;this.periodic_interrupt_time=1E3/(32768>>(this.cmos_a&15)-1);A(this.cmos_a,2);break;case 11:this.cmos_b=a;this.cmos_b&64&&(this.next_interrupt=Date.now());if(this.cmos_b&32){a=new Date;const b=this.decode_time(this.cmos_data[1]),c=this.decode_time(this.cmos_data[3]),d=this.decode_time(this.cmos_data[5]);this.next_interrupt_alarm=+new Date(Date.UTC(a.getUTCFullYear(),a.getUTCMonth(),a.getUTCDate(),d,c,b))}A(this.cmos_b, +2);break;case 1:case 3:case 5:this.cmos_write(this.cmos_index,a);break;default:A(this.cmos_index),A(a)}this.periodic_interrupt=64===(this.cmos_b&64)&&0<(this.cmos_a&15)};va.prototype.cmos_read=function(a){return this.cmos_data[a]};va.prototype.cmos_write=function(a,b){A(a);A(b);this.cmos_data[a]=b};function wa(a,b,c){this.bus=c;this.cpu=a;this.ints=4;this.line_control=this.baud_rate=0;this.lsr=96;this.ier=this.fifo_control=0;this.iir=1;this.irq=this.scratch_register=this.modem_status=this.modem_control=0;this.input=[];this.current_line="";switch(b){case 1016:this.com=0;this.irq=4;break;case 760:this.com=1;this.irq=3;break;case 1E3:this.com=2;this.irq=4;break;case 744:this.irq=this.com=3;break;default:J("Invalid serial port: "+A(b),16384),this.com=0,this.irq=4}this.bus.register("serial"+this.com+ +"-input",function(d){this.data_received(d)},this);this.bus.register("serial"+this.com+"-modem-status-input",function(d){this.set_modem_status(d)},this);this.bus.register("serial"+this.com+"-carrier-detect-input",function(d){this.set_modem_status(d?this.modem_status|136:this.modem_status&-137)},this);this.bus.register("serial"+this.com+"-ring-indicator-input",function(d){this.set_modem_status(d?this.modem_status|68:this.modem_status&-69)},this);this.bus.register("serial"+this.com+"-data-set-ready-input", +function(d){this.set_modem_status(d?this.modem_status|34:this.modem_status&-35)},this);this.bus.register("serial"+this.com+"-clear-to-send-input",function(d){this.set_modem_status(d?this.modem_status|17:this.modem_status&-18)},this);a=a.io;a.register_write(b,this,function(d){this.write_data(d)},function(d){this.write_data(d&255);this.write_data(d>>8)});a.register_write(b|1,this,function(d){this.line_control&128?(this.baud_rate=this.baud_rate&255|d<<8,A(this.baud_rate)):(0===(this.ier&2)&&d&2&&this.ThrowInterrupt(2), +this.ier=d&15,A(d),this.CheckInterrupt())});a.register_read(b,this,function(){if(this.line_control&128)return this.baud_rate&255;let d=0;0!==this.input.length&&(d=this.input.shift(),A(d));0===this.input.length&&(this.lsr&=-2,this.ClearInterrupt(12),this.ClearInterrupt(4));return d});a.register_read(b|1,this,function(){return this.line_control&128?this.baud_rate>>8:this.ier&15});a.register_read(b|2,this,function(){var d=this.iir&15;A(this.iir);2==this.iir&&this.ClearInterrupt(2);this.fifo_control& +1&&(d|=192);return d});a.register_write(b|2,this,function(d){A(d);this.fifo_control=d});a.register_read(b|3,this,function(){A(this.line_control);return this.line_control});a.register_write(b|3,this,function(d){A(d);this.line_control=d});a.register_read(b|4,this,function(){return this.modem_control});a.register_write(b|4,this,function(d){A(d);this.modem_control=d});a.register_read(b|5,this,function(){A(this.lsr);return this.lsr});a.register_write(b|5,this,function(){});a.register_read(b|6,this,function(){A(this.modem_status); +return this.modem_status&=240});a.register_write(b|6,this,function(d){A(d);this.set_modem_status(d)});a.register_read(b|7,this,function(){return this.scratch_register});a.register_write(b|7,this,function(d){this.scratch_register=d})}wa.prototype.get_state=function(){var a=[];a[0]=this.ints;a[1]=this.baud_rate;a[2]=this.line_control;a[3]=this.lsr;a[4]=this.fifo_control;a[5]=this.ier;a[6]=this.iir;a[7]=this.modem_control;a[8]=this.modem_status;a[9]=this.scratch_register;a[10]=this.irq;return a}; +wa.prototype.set_state=function(a){this.ints=a[0];this.baud_rate=a[1];this.line_control=a[2];this.lsr=a[3];this.fifo_control=a[4];this.ier=a[5];this.iir=a[6];this.modem_control=a[7];this.modem_status=a[8];this.scratch_register=a[9];this.irq=a[10]}; +wa.prototype.CheckInterrupt=function(){this.ints&4096&&this.ier&1?(this.iir=12,this.cpu.device_raise_irq(this.irq)):this.ints&16&&this.ier&1?(this.iir=4,this.cpu.device_raise_irq(this.irq)):this.ints&4&&this.ier&2?(this.iir=2,this.cpu.device_raise_irq(this.irq)):this.ints&1&&this.ier&8?(this.iir=0,this.cpu.device_raise_irq(this.irq)):(this.iir=1,this.cpu.device_lower_irq(this.irq))};wa.prototype.ThrowInterrupt=function(a){this.ints|=1<>4;this.modem_status=a;this.modem_status=this.modem_status|c|b};function xa(a){this.cpu=a;var b=a.io;a.devices.pci.register_device({pci_id:56,pci_space:[134,128,19,113,7,0,128,2,8,0,128,6,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,9,1,0,0],pci_bars:[],name:"acpi"});this.timer_imprecision_offset=this.timer_last_value=0;this.status=1;this.pm1_enable=this.pm1_status=0;this.last_timer=this.get_timer(D.microtick());this.gpe=new Uint8Array(4);b.register_read(45056,this,void 0,function(){return this.pm1_status}); +b.register_write(45056,this,void 0,function(c){A(c,4);this.pm1_status&=~c});b.register_read(45058,this,void 0,function(){return this.pm1_enable});b.register_write(45058,this,void 0,function(c){A(c);this.pm1_enable=c});b.register_read(45060,this,void 0,function(){return this.status});b.register_write(45060,this,void 0,function(c){A(c);this.status=c});b.register_read(45064,this,void 0,void 0,function(){return this.get_timer(D.microtick())&16777215});b.register_read(45024,this,function(){return this.gpe[0]}); +b.register_read(45025,this,function(){return this.gpe[1]});b.register_read(45026,this,function(){return this.gpe[2]});b.register_read(45027,this,function(){return this.gpe[3]});b.register_write(45024,this,function(c){A(c);this.gpe[0]=c});b.register_write(45025,this,function(c){A(c);this.gpe[1]=c});b.register_write(45026,this,function(c){A(c);this.gpe[2]=c});b.register_write(45027,this,function(c){A(c);this.gpe[3]=c})} +xa.prototype.timer=function(a){a=this.get_timer(a);var b=0!==((a^this.last_timer)&8388608);this.pm1_enable&1&&b?(this.pm1_status|=1,this.cpu.device_raise_irq(9)):this.cpu.device_lower_irq(9);this.last_timer=a;return 100}; +xa.prototype.get_timer=function(a){a=Math.round(3579.545*a);a===this.timer_last_value?3579.545>this.timer_imprecision_offset&&this.timer_imprecision_offset++:this.timer_last_value+this.timer_imprecision_offset<=a&&(this.timer_imprecision_offset=0,this.timer_last_value=a);return this.timer_last_value+this.timer_imprecision_offset};xa.prototype.get_state=function(){var a=[];a[0]=this.status;a[1]=this.pm1_status;a[2]=this.pm1_enable;a[3]=this.gpe;return a}; +xa.prototype.set_state=function(a){this.status=a[0];this.pm1_status=a[1];this.pm1_enable=a[2];this.gpe=a[3]};function O(a){this.cpu=a;this.timer_divider=this.apic_id=0;this.timer_divider_shift=1;this.timer_current_count=this.timer_initial_count=0;this.next_tick=D.microtick();this.lvt_error=this.lvt_int1=this.lvt_int0=this.lvt_perf_counter=this.lvt_timer=65536;this.icr1=this.icr0=this.tpr=0;this.irr=new Int32Array(8);this.isr=new Int32Array(8);this.tmr=new Int32Array(8);this.spurious_vector=254;this.destination_format=-1;this.read_error=this.error=this.local_destination=0;a.io.mmap_register(4276092928,1048576, +b=>{A(b>>>0);var c=b&3;return this.read32(b&-4)>>8*c&255},(b,c)=>{A(b);A(c)},b=>this.read32(b),(b,c)=>this.write32(b,c))} +O.prototype.read32=function(a){a=a-4276092928|0;switch(a){case 32:return this.apic_id;case 48:return 327700;case 128:return this.tpr;case 208:return this.local_destination;case 224:return this.destination_format;case 240:return this.spurious_vector;case 256:case 272:case 288:case 304:case 320:case 336:case 352:case 368:return a=a-256>>4,A(this.isr[a]>>>0,8),this.isr[a];case 384:case 400:case 416:case 432:case 448:case 464:case 480:case 496:return a=a-384>>4,A(this.tmr[a]>>>0,8),this.tmr[a];case 512:case 528:case 544:case 560:case 576:case 592:case 608:case 624:return a= +a-512>>4,A(this.irr[a]>>>0,8),this.irr[a];case 640:return A(this.read_error>>>0,8),this.read_error;case 768:return this.icr0;case 784:return this.icr1;case 800:return this.lvt_timer;case 832:return this.lvt_perf_counter;case 848:return this.lvt_int0;case 864:return this.lvt_int1;case 880:return this.lvt_error;case 992:return this.timer_divider;case 896:return this.timer_initial_count;case 912:return A(this.timer_current_count>>>0,8),this.timer_current_count;default:return A(a),0}}; +O.prototype.write32=function(a,b){a=a-4276092928|0;switch(a){case 48:A(b>>>0,8);break;case 128:this.tpr=b&255;this.check_vector();break;case 176:b=this.highest_isr();-1!==b&&(this.register_clear_bit(this.isr,b),this.register_get_bit(this.tmr,b)&&this.cpu.devices.ioapic.remote_eoi(b),this.check_vector());break;case 208:A(b>>>0,8);this.local_destination=b&4278190080;break;case 224:A(b>>>0,8);this.destination_format=b|16777215;break;case 240:A(b>>>0,8);this.spurious_vector=b;break;case 640:A(b>>>0,8); +this.read_error=this.error;this.error=0;break;case 768:a=b&255;var c=b>>8&7,d=b>>11&1,e=b>>15&1,g=b>>18&3,f=this.icr1>>>24;A(b,8);A(a,2);this.icr0=b&-4097;0===g?this.route(a,c,e,f,d):1===g?this.deliver(a,0,e):2===g&&this.deliver(a,c,e);break;case 784:A(b>>>0,8);this.icr1=b;break;case 800:A(b>>>0,8);this.lvt_timer=b;break;case 832:A(b>>>0,8);this.lvt_perf_counter=b;break;case 848:A(b>>>0,8);this.lvt_int0=b;break;case 864:A(b>>>0,8);this.lvt_int1=b;break;case 880:A(b>>>0,8);this.lvt_error=b;break;case 992:A(b>>> +0,8);this.timer_divider=b;b=b&3|(b&8)>>1;this.timer_divider_shift=7===b?0:b+1;break;case 896:A(b>>>0,8);this.timer_initial_count=b>>>0;this.timer_current_count=b>>>0;this.next_tick=D.microtick();this.timer_active=!0;break;case 912:A(b>>>0,8);break;default:A(a),A(b>>>0,8)}}; +O.prototype.timer=function(a){if(0===this.timer_current_count)return 100;const b=1E6/(1<>>0;this.next_tick+=a/b;this.timer_current_count-=a;0>=this.timer_current_count&&(a=this.lvt_timer&393216,131072===a?(this.timer_current_count%=this.timer_initial_count,0>=this.timer_current_count&&(this.timer_current_count+=this.timer_initial_count),0===(this.lvt_timer&65536)&&this.deliver(this.lvt_timer&255,0,!1)):0===a&&(this.timer_current_count=0,0===(this.lvt_timer& +65536)&&this.deliver(this.lvt_timer&255,0,!1)));return Math.max(0,this.timer_current_count/b)};O.prototype.route=function(a,b,c){this.deliver(a,b,c)};O.prototype.deliver=function(a,b,c){5!==b&&4!==b&&(this.register_get_bit(this.irr,a)?A(a,2):(this.register_set_bit(this.irr,a),c?this.register_set_bit(this.tmr,a):this.register_clear_bit(this.tmr,a),this.check_vector()))};O.prototype.highest_irr=function(){return this.register_get_highest_bit(this.irr)};O.prototype.highest_isr=function(){return this.register_get_highest_bit(this.isr)}; +O.prototype.check_vector=function(){var a=this.highest_irr();-1!==a&&(this.highest_isr()>=a||(a&240)<=(this.tpr&240)||this.cpu.handle_irqs())};O.prototype.acknowledge_irq=function(){var a=this.highest_irr();if(-1===a||this.highest_isr()>=a||(a&240)<=(this.tpr&240))return-1;this.register_clear_bit(this.irr,a);this.register_set_bit(this.isr,a);this.check_vector();return a}; +O.prototype.get_state=function(){var a=[];a[0]=this.apic_id;a[1]=this.timer_divider;a[2]=this.timer_divider_shift;a[3]=this.timer_initial_count;a[4]=this.timer_current_count;a[5]=this.next_tick;a[6]=this.lvt_timer;a[7]=this.lvt_perf_counter;a[8]=this.lvt_int0;a[9]=this.lvt_int1;a[10]=this.lvt_error;a[11]=this.tpr;a[12]=this.icr0;a[13]=this.icr1;a[14]=this.irr;a[15]=this.isr;a[16]=this.tmr;a[17]=this.spurious_vector;a[18]=this.destination_format;a[19]=this.local_destination;a[20]=this.error;a[21]= +this.read_error;return a}; +O.prototype.set_state=function(a){this.apic_id=a[0];this.timer_divider=a[1];this.timer_divider_shift=a[2];this.timer_initial_count=a[3];this.timer_current_count=a[4];this.next_tick=a[5];this.lvt_timer=a[6];this.lvt_perf_counter=a[7];this.lvt_int0=a[8];this.lvt_int1=a[9];this.lvt_error=a[10];this.tpr=a[11];this.icr0=a[12];this.icr1=a[13];this.irr=a[14];this.isr=a[15];this.tmr=a[16];this.spurious_vector=a[17];this.destination_format=a[18];this.local_destination=a[19];this.error=a[20];this.read_error= +a[21]};O.prototype.register_get_bit=function(a,b){return a[b>>5]>>(b&31)&1};O.prototype.register_set_bit=function(a,b){a[b>>5]|=1<<(b&31)};O.prototype.register_clear_bit=function(a,b){a[b>>5]&=~(1<<(b&31))};O.prototype.register_get_highest_bit=function(a){for(var b=7;0<=b;b--){var c=a[b];if(c)return r.int_log2(c>>>0)|b<<5}return-1};function ya(a){this.cpu=a;this.ioredtbl_config=new Int32Array(24);this.ioredtbl_destination=new Int32Array(24);for(var b=0;b{c=c-4273995776|0;if(16<=c&&20>c)return c-=16,A(this.ioregsel),this.read(this.ioregsel)>>8*c&255;A(c>>>0);return 0},c=>{A(c>>>0)},c=>{c=c-4273995776|0;if(0===c)return this.ioregsel;if(16===c)return this.read(this.ioregsel); +A(c>>>0);return 0},(c,d)=>{c=c-4273995776|0;0===c?this.ioregsel=d:16===c?this.write(this.ioregsel,d):(A(c>>>0),A(d>>>0,8))})}ya.prototype.remote_eoi=function(a){for(var b=0;24>b;b++){var c=this.ioredtbl_config[b];(c&255)===a&&c&16384&&(A(b),this.ioredtbl_config[b]&=-16385,this.check_irq(b))}}; +ya.prototype.check_irq=function(a){var b=1<>8&7,e=this.ioredtbl_destination[a]>>>24;if(0===(c&32768))this.irr&=~b;else if(this.ioredtbl_config[a]|=16384,c&16384)return;0!==d&&1!==d||this.cpu.devices.apic.route(c&255,d,32768===(c&32768),e,c>>11&1);this.ioredtbl_config[a]&=-4097}}}; +ya.prototype.set_irq=function(a){if(!(24<=a)){var b=1<a){var b=a-16>>1;a=a&1?this.ioredtbl_destination[b]:this.ioredtbl_config[b];A(b);A(a,8);return a}A(a);return 0}; +ya.prototype.write=function(a,b){if(0===a)this.ioapic_id=b>>>24&15;else if(1!==a&&2!==a)if(16<=a&&64>a){var c=a-16>>1;a&1?(this.ioredtbl_destination[c]=b&4278190080,A(b>>>0,8),A(c),A(b>>>24,2)):(this.ioredtbl_config[c]=b&110591|this.ioredtbl_config[c]&-110592,a=b&255,A(b>>>0,8),A(c),A(a,2),this.check_irq(c))}else A(a),A(b>>>0,8)}; +ya.prototype.get_state=function(){var a=[];a[0]=this.ioredtbl_config;a[1]=this.ioredtbl_destination;a[2]=this.ioregsel;a[3]=this.ioapic_id;a[4]=this.irr;a[5]=this.irq_value;return a};ya.prototype.set_state=function(a){this.ioredtbl_config=a[0];this.ioredtbl_destination=a[1];this.ioregsel=a[2];this.ioapic_id=a[3];this.irr=a[4];this.irq_value=a[5]};function za(a){this.message=a}za.prototype=Error();const Aa={Uint8Array,Int8Array,Uint16Array,Int16Array,Uint32Array,Int32Array,Float32Array,Float64Array}; +function Ba(a,b){if("object"!==typeof a||null===a)return a;if(a instanceof Array)return a.map(e=>Ba(e,b));a.constructor===Object&&console.log(a);if(a.BYTES_PER_ELEMENT){var c=new Uint8Array(a.buffer,a.byteOffset,a.length*a.BYTES_PER_ELEMENT);return{__state_type__:a.constructor.name.replace("bound ",""),buffer_id:b.push(c)-1}}a=a.get_state();c=[];for(var d=0;dq)throw new za("Invalid length: "+q);p=new Int32Array(p.buffer,p.byteOffset,4);if(-2039052682!==p[0])throw new za("Invalid header: "+A(p[0]>>>0));if(6!==p[1])throw new za("Version mismatch: dump="+p[1]+" we=6");if(t&&p[2]!==q)throw new za("Length doesn't match header: real="+q+" header="+p[2]);return p[3]}function c(p){p=(new TextDecoder).decode(p);return JSON.parse(p)}a=new Uint8Array(a);if(4247762216===(new Uint32Array(a.buffer, +0,1))[0]){var d=this.zstd_create_ctx(a.length);(new Uint8Array(this.wasm_memory.buffer,this.zstd_get_src_ptr(d),a.length)).set(a);var e=this.zstd_read(d,16),g=new Uint8Array(this.wasm_memory.buffer,e,16),f=b(g,!1);this.zstd_read_free(e,16);e=this.zstd_read(d,f);g=new Uint8Array(this.wasm_memory.buffer,e,f);g=c(g);this.zstd_read_free(e,f);e=g.state;var k=g.buffer_infos;g=[];f=16+f;for(var l of k){k=(f+3&-4)-f;if(1048576d||d+12>=a.length)throw new za("Invalid info block length: "+d);l=a.subarray(16,16+d);e=c(l);l=e.state;e= +e.buffer_infos;let p=16+d;p=p+3&-4;d=e.map(t=>{const q=p+t.offset;return a.buffer.slice(q,q+t.length)});l=Ca(l,d);this.set_state(l)}};function Da(a,b,c){a[0]===b[0]&&a[1]===b[1]&&a[2]===b[2]&&a[3]===b[3]&&a[4]===b[4]&&a[5]===b[5]&&(a[0]=c[0],a[1]=c[1],a[2]=c[2],a[3]=c[3],a[4]=c[4],a[5]=c[5]);a[6]===b[0]&&a[7]===b[1]&&a[8]===b[2]&&a[9]===b[3]&&a[10]===b[4]&&a[11]===b[5]&&(a[6]=c[0],a[7]=c[1],a[8]=c[2],a[9]=c[3],a[10]=c[4],a[11]=c[5]);var d=a[12]<<8|a[13];if(2048===d){if(a=a.subarray(14),4===a[0]>>4&&17===a[9]){a=a.subarray(20);d=a[0]<<8|a[1];var e=a[2]<<8|a[3];A(a[6]<<8|a[7],4);if(67===d||67===e)if(d=a.subarray(8),e=d[236]<<24|d[237]<< +16|d[238]<<8|d[239],1669485411!==e)A(e,8);else for(d[28]===b[0]&&d[29]===b[1]&&d[30]===b[2]&&d[31]===b[3]&&d[32]===b[4]&&d[33]===b[5]&&(d[28]=c[0],d[29]=c[1],d[30]=c[2],d[31]=c[3],d[32]=c[4],d[33]=c[5],a[6]=a[7]=0),e=240;e>8,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,244,26,0,17,0,0,184,254,0,0,0,0,0,0,0,0,0,1,0,0];this.pci_id=40;this.pci_bars=[{size:32}];this.imr=this.isr=0;this.cr=1;this.tpsr=this.tcnt= +this.rcnt=this.dcfg=0;this.memory=new Uint8Array(32768);this.txcr=this.rxcr=0;this.tsr=1;this.mac=new Uint8Array([0,34,21,255*Math.random()|0,255*Math.random()|0,255*Math.random()|0]);this.mar=Uint8Array.of(255,255,255,255,255,255,255,255);this.mac_address_in_state=null;for(b=0;6>b;b++)this.memory[b<<1]=this.memory[b<<1|1]=this.mac[b];this.memory[28]=this.memory[29]=87;this.memory[30]=this.memory[31]=87;J("Mac: "+Ea(this.mac),1048576);this.rsar=0;this.pstart=64;this.pstop=128;this.boundary=this.curpg= +76;b=a.io;b.register_read(this.port|0,this,function(){return this.cr});b.register_write(this.port|0,this,function(e){this.cr=e;A(e,2);A(this.txcr,2);this.cr&1||(e&24&&0===this.rcnt&&this.do_interrupt(64),e&4&&(e=this.tpsr<<8,e=this.memory.subarray(e,e+this.tcnt),this.mac_address_in_state&&(e=new Uint8Array(e),Da(e,this.mac_address_in_state,this.mac)),this.bus.send("net0-send",e),this.bus.send("eth-transmit-end",[e.length]),this.cr&=-5,this.do_interrupt(2),A(e.byteLength)))});b.register_read(this.port| +13,this,function(){return 1===this.get_page()?this.mar[5]:0});b.register_read(this.port|14,this,function(){return 1===this.get_page()?this.mar[6]:0},function(){this.get_page();return 0});b.register_read(this.port|15,this,function(){return 1===this.get_page()?this.mar[7]:0});b.register_read(this.port|31,this,function(){this.get_page();this.do_interrupt(128);return 0});b.register_write(this.port|31,this,function(e){this.get_page();A(e,2)});b.register_read(this.port|1,this,function(){var e=this.get_page(); +return 0===e?this.pstart:1===e?this.mac[0]:2===e?this.pstart:0});b.register_write(this.port|1,this,function(e){var g=this.get_page();0===g?(A(e,2),this.pstart=e):1===g?(A(e),this.mac[0]=e):A(e)});b.register_read(this.port|2,this,function(){var e=this.get_page();return 0===e?this.pstop:1===e?this.mac[1]:2===e?this.pstop:0});b.register_write(this.port|2,this,function(e){var g=this.get_page();0===g?(A(e,2),e>this.memory.length>>8&&(e=this.memory.length>>8,A(e)),this.pstop=e):1===g?(A(e),this.mac[1]= +e):A(e)});b.register_read(this.port|7,this,function(){var e=this.get_page();return 0===e?(A(this.isr,2),this.isr):1===e?(A(this.curpg,2),this.curpg):0});b.register_write(this.port|7,this,function(e){var g=this.get_page();0===g?(A(e,2),this.isr&=~e,this.update_irq()):1===g&&(A(e,2),this.curpg=e)});b.register_write(this.port|13,this,function(e){0===this.get_page()&&(this.txcr=e);A(e,2)});b.register_write(this.port|14,this,function(e){0===this.get_page()?(A(e,2),this.dcfg=e):A(e,2)});b.register_read(this.port| +10,this,function(){var e=this.get_page();return 0===e?80:1===e?this.mar[2]:0});b.register_write(this.port|10,this,function(e){0===this.get_page()?(A(e,2),this.rcnt=this.rcnt&65280|e&255):A(e,2)});b.register_read(this.port|11,this,function(){var e=this.get_page();return 0===e?67:1===e?this.mar[3]:0});b.register_write(this.port|11,this,function(e){0===this.get_page()?(A(e,2),this.rcnt=this.rcnt&255|e<<8&65280):A(e,2)});b.register_read(this.port|8,this,function(){var e=this.get_page();return 0===e?this.rsar& +255:1===e?this.mar[0]:0});b.register_write(this.port|8,this,function(e){0===this.get_page()?(A(e,2),this.rsar=this.rsar&65280|e&255):A(e,2)});b.register_read(this.port|9,this,function(){var e=this.get_page();return 0===e?this.rsar>>8&255:1===e?this.mar[1]:0});b.register_write(this.port|9,this,function(e){0===this.get_page()?(A(e,2),this.rsar=this.rsar&255|e<<8&65280):A(e,2)});b.register_write(this.port|15,this,function(e){0===this.get_page()?(A(e,2),A(this.isr,2),this.imr=e,this.update_irq()):A(e, +2)});b.register_read(this.port|3,this,function(){var e=this.get_page();return 0===e?(A(this.boundary,2),this.boundary):1===e?this.mac[2]:0});b.register_write(this.port|3,this,function(e){var g=this.get_page();0===g?(A(e,2),this.boundary=e):1===g?(A(e),this.mac[2]=e):A(e)});b.register_read(this.port|4,this,function(){var e=this.get_page();return 0===e?this.tsr:1===e?this.mac[3]:0});b.register_write(this.port|4,this,function(e){var g=this.get_page();0===g?(A(e,2),this.tpsr=e):1===g?(A(e),this.mac[3]= +e):A(e)});b.register_read(this.port|5,this,function(){var e=this.get_page();return 0===e?0:1===e?this.mac[4]:0});b.register_write(this.port|5,this,function(e){var g=this.get_page();0===g?(A(e,2),this.tcnt=this.tcnt&-256|e):1===g?(A(e),this.mac[4]=e):A(e)});b.register_read(this.port|6,this,function(){var e=this.get_page();return 0===e?0:1===e?this.mac[5]:0});b.register_write(this.port|6,this,function(e){var g=this.get_page();0===g?(A(e,2),this.tcnt=this.tcnt&255|e<<8):1===g?(A(e),this.mac[5]=e):A(e)}); +b.register_read(this.port|12,this,function(){var e=this.get_page();return 0===e?9:1===e?this.mar[4]:0});b.register_write(this.port|12,this,function(e){0===this.get_page()?(A(e,2),this.rxcr=e):A(e)});b.register_read(this.port|16,this,this.data_port_read8,this.data_port_read16,this.data_port_read32);b.register_write(this.port|16,this,this.data_port_write16,this.data_port_write16,this.data_port_write32);a.devices.pci.register_device(this)} +Fa.prototype.get_state=function(){var a=[];a[0]=this.isr;a[1]=this.imr;a[2]=this.cr;a[3]=this.dcfg;a[4]=this.rcnt;a[5]=this.tcnt;a[6]=this.tpsr;a[7]=this.rsar;a[8]=this.pstart;a[9]=this.curpg;a[10]=this.boundary;a[11]=this.pstop;a[12]=this.rxcr;a[13]=this.txcr;a[14]=this.tsr;a[15]=this.mac;a[16]=this.memory;return a}; +Fa.prototype.set_state=function(a){this.isr=a[0];this.imr=a[1];this.cr=a[2];this.dcfg=a[3];this.rcnt=a[4];this.tcnt=a[5];this.tpsr=a[6];this.rsar=a[7];this.pstart=a[8];this.curpg=a[9];this.boundary=a[10];this.pstop=a[11];this.rxcr=a[12];this.txcr=a[13];this.tsr=a[14];this.preserve_mac_from_state_image?(this.mac=a[15],this.memory=a[16]):this.mac_address_translation&&(this.mac_address_in_state=a[15],this.memory=a[16],Ea(this.mac_address_in_state),Ea(this.mac))}; +Fa.prototype.do_interrupt=function(a){A(a,2);this.isr|=a;this.update_irq()};Fa.prototype.update_irq=function(){this.imr&this.isr?this.pci.raise_irq(this.pci_id):this.pci.lower_irq(this.pci_id)};Fa.prototype.data_port_write=function(a){if(16>=this.rsar||16384<=this.rsar&&32768>this.rsar)this.memory[this.rsar]=a;this.rsar++;this.rcnt--;this.rsar>=this.pstop<<8&&(this.rsar+=this.pstart-this.pstop<<8);0===this.rcnt&&this.do_interrupt(64)}; +Fa.prototype.data_port_write16=function(a){this.data_port_write(a);this.dcfg&1&&this.data_port_write(a>>8)};Fa.prototype.data_port_write32=function(a){this.data_port_write(a);this.data_port_write(a>>8);this.data_port_write(a>>16);this.data_port_write(a>>24)};Fa.prototype.data_port_read=function(){let a=0;32768>this.rsar&&(a=this.memory[this.rsar]);this.rsar++;this.rcnt--;this.rsar>=this.pstop<<8&&(this.rsar+=this.pstart-this.pstop<<8);0===this.rcnt&&this.do_interrupt(64);return a}; +Fa.prototype.data_port_read8=function(){return this.data_port_read16()&255};Fa.prototype.data_port_read16=function(){return this.dcfg&1?this.data_port_read()|this.data_port_read()<<8:this.data_port_read()};Fa.prototype.data_port_read32=function(){return this.data_port_read()|this.data_port_read()<<8|this.data_port_read()<<16|this.data_port_read()<<24}; +Fa.prototype.receive=function(a){if(!(this.cr&1)&&(this.bus.send("eth-receive-end",[a.length]),this.rxcr&16||this.rxcr&4&&255===a[0]&&255===a[1]&&255===a[2]&&255===a[3]&&255===a[4]&&255===a[5]||!(this.rxcr&8&&1===(a[0]&1)||a[0]!==this.mac[0]||a[1]!==this.mac[1]||a[2]!==this.mac[2]||a[3]!==this.mac[3]||a[4]!==this.mac[4]||a[5]!==this.mac[5]))){this.mac_address_in_state&&(a=new Uint8Array(a),Da(a,this.mac,this.mac_address_in_state));var b=this.curpg<<8,c=Math.max(60,a.length)+4,d=b+4,e=this.curpg+1+ +(c>>8),g=b+c,f=1+(c>>8),k=this.boundary>this.curpg?this.boundary-this.curpg:this.pstop-this.curpg+this.boundary-this.pstart;kthis.pstop<<8?(g=(this.pstop<<8)-d,this.memory.set(a.subarray(0,g),d),this.memory.set(a.subarray(g),this.pstart<<8),A(g)):(this.memory.set(a,d),60>a.length&&this.memory.fill(0,d+a.length,d+60)),e>=this.pstop&&(e+=this.pstart-this.pstop),this.memory[b]=1,this.memory[b+1]=e,this.memory[b+ +2]=c,this.memory[b+3]=c>>8,this.curpg=e,A(b),A(c),A(e),this.do_interrupt(1))}};Fa.prototype.get_page=function(){return this.cr>>6&3};var Ga=new Uint8Array(256),Ha=[],Ia=[],Ja=[],Ka=new Uint8Array(256),La=[]; +function Q(a,b){this.cpu=a;this.bus=b;this.write_buffer=new ka(64);this.read_buffer=new ka(64);this.mixer_current_address=this.command_size=this.command=this.read_buffer_lastvalue=0;this.mixer_registers=new Uint8Array(256);this.mixer_reset();this.dummy_speaker_enabled=!1;this.test_register=0;this.dsp_signed=this.dsp_16bit=this.dsp_stereo=this.dsp_highspeed=!1;this.dac_buffers=[new la(65536),new la(65536)];this.dma=a.devices.dma;this.dma_channel=this.dma_irq=this.dma_bytes_block=this.dma_bytes_left= +this.dma_bytes_count=this.dma_sample_count=0;this.dma_channel_8bit=1;this.dma_channel_16bit=5;this.dma_autoinit=!1;this.dma_buffer=new ArrayBuffer(65536);this.dma_buffer_int8=new Int8Array(this.dma_buffer);this.dma_buffer_uint8=new Uint8Array(this.dma_buffer);this.dma_buffer_int16=new Int16Array(this.dma_buffer);this.dma_buffer_uint16=new Uint16Array(this.dma_buffer);this.dma_syncbuffer=new r.SyncBuffer(this.dma_buffer);this.dma_paused=this.dma_waiting_transfer=!1;this.sampling_rate=22050;b.send("dac-tell-sampling-rate", +this.sampling_rate);this.bytes_per_sample=1;this.e2_value=170;this.e2_count=0;this.asp_registers=new Uint8Array(256);this.mpu_read_buffer=new ka(64);this.fm_current_address1=this.fm_current_address0=this.mpu_read_buffer_lastvalue=0;this.fm_waveform_select_enable=!1;this.irq=5;this.irq_triggered=new Uint8Array(16);a.io.register_read_consecutive(544,this,this.port2x0_read,this.port2x1_read,this.port2x2_read,this.port2x3_read);a.io.register_read_consecutive(904,this,this.port2x0_read,this.port2x1_read); +a.io.register_read_consecutive(548,this,this.port2x4_read,this.port2x5_read);a.io.register_read(550,this,this.port2x6_read);a.io.register_read(551,this,this.port2x7_read);a.io.register_read(552,this,this.port2x8_read);a.io.register_read(553,this,this.port2x9_read);a.io.register_read(554,this,this.port2xA_read);a.io.register_read(555,this,this.port2xB_read);a.io.register_read(556,this,this.port2xC_read);a.io.register_read(557,this,this.port2xD_read);a.io.register_read_consecutive(558,this,this.port2xE_read, +this.port2xF_read);a.io.register_write_consecutive(544,this,this.port2x0_write,this.port2x1_write,this.port2x2_write,this.port2x3_write);a.io.register_write_consecutive(904,this,this.port2x0_write,this.port2x1_write);a.io.register_write_consecutive(548,this,this.port2x4_write,this.port2x5_write);a.io.register_write(550,this,this.port2x6_write);a.io.register_write(551,this,this.port2x7_write);a.io.register_write_consecutive(552,this,this.port2x8_write,this.port2x9_write);a.io.register_write(554,this, +this.port2xA_write);a.io.register_write(555,this,this.port2xB_write);a.io.register_write(556,this,this.port2xC_write);a.io.register_write(557,this,this.port2xD_write);a.io.register_write(558,this,this.port2xE_write);a.io.register_write(559,this,this.port2xF_write);a.io.register_read_consecutive(816,this,this.port3x0_read,this.port3x1_read);a.io.register_write_consecutive(816,this,this.port3x0_write,this.port3x1_write);this.dma.on_unmask(this.dma_on_unmask,this);b.register("dac-request-data",function(){this.dac_handle_request()}, +this);b.register("speaker-has-initialized",function(){this.mixer_reset()},this);b.send("speaker-confirm-initialized");this.dsp_reset()} +Q.prototype.dsp_reset=function(){this.write_buffer.clear();this.read_buffer.clear();this.command_size=this.command=0;this.dummy_speaker_enabled=!1;this.test_register=0;this.dsp_signed=this.dsp_16bit=this.dsp_stereo=this.dsp_highspeed=!1;this.dac_buffers[0].clear();this.dac_buffers[1].clear();this.dma_channel=this.dma_irq=this.dma_bytes_block=this.dma_bytes_left=this.dma_bytes_count=this.dma_sample_count=0;this.dma_autoinit=!1;this.dma_buffer_uint8.fill(0);this.dma_paused=this.dma_waiting_transfer= +!1;this.e2_value=170;this.e2_count=0;this.sampling_rate=22050;this.bytes_per_sample=1;this.lower_irq(1);this.irq_triggered.fill(0);this.asp_registers.fill(0);this.asp_registers[5]=1;this.asp_registers[9]=248}; +Q.prototype.get_state=function(){var a=[];a[2]=this.read_buffer_lastvalue;a[3]=this.command;a[4]=this.command_size;a[5]=this.mixer_current_address;a[6]=this.mixer_registers;a[7]=this.dummy_speaker_enabled;a[8]=this.test_register;a[9]=this.dsp_highspeed;a[10]=this.dsp_stereo;a[11]=this.dsp_16bit;a[12]=this.dsp_signed;a[15]=this.dma_sample_count;a[16]=this.dma_bytes_count;a[17]=this.dma_bytes_left;a[18]=this.dma_bytes_block;a[19]=this.dma_irq;a[20]=this.dma_channel;a[21]=this.dma_channel_8bit;a[22]= +this.dma_channel_16bit;a[23]=this.dma_autoinit;a[24]=this.dma_buffer_uint8;a[25]=this.dma_waiting_transfer;a[26]=this.dma_paused;a[27]=this.sampling_rate;a[28]=this.bytes_per_sample;a[29]=this.e2_value;a[30]=this.e2_count;a[31]=this.asp_registers;a[33]=this.mpu_read_buffer_last_value;a[34]=this.irq;a[35]=this.irq_triggered;return a}; +Q.prototype.set_state=function(a){this.read_buffer_lastvalue=a[2];this.command=a[3];this.command_size=a[4];this.mixer_current_address=a[5];this.mixer_registers=a[6];this.mixer_full_update();this.dummy_speaker_enabled=a[7];this.test_register=a[8];this.dsp_highspeed=a[9];this.dsp_stereo=a[10];this.dsp_16bit=a[11];this.dsp_signed=a[12];this.dma_sample_count=a[15];this.dma_bytes_count=a[16];this.dma_bytes_left=a[17];this.dma_bytes_block=a[18];this.dma_irq=a[19];this.dma_channel=a[20];this.dma_channel_8bit= +a[21];this.dma_channel_16bit=a[22];this.dma_autoinit=a[23];this.dma_buffer_uint8=a[24];this.dma_waiting_transfer=a[25];this.dma_paused=a[26];this.sampling_rate=a[27];this.bytes_per_sample=a[28];this.e2_value=a[29];this.e2_count=a[30];this.asp_registers=a[31];this.mpu_read_buffer_last_value=a[33];this.irq=a[34];this.irq_triggered=a[35];this.dma_buffer=this.dma_buffer_uint8.buffer;this.dma_buffer_int8=new Int8Array(this.dma_buffer);this.dma_buffer_int16=new Int16Array(this.dma_buffer);this.dma_buffer_uint16= +new Uint16Array(this.dma_buffer);this.dma_syncbuffer=new r.SyncBuffer(this.dma_buffer);this.dma_paused?this.bus.send("dac-disable"):this.bus.send("dac-enable")};Q.prototype.port2x0_read=function(){return 255};Q.prototype.port2x1_read=function(){return 255};Q.prototype.port2x2_read=function(){return 255};Q.prototype.port2x3_read=function(){return 255};Q.prototype.port2x4_read=function(){return this.mixer_current_address};Q.prototype.port2x5_read=function(){return this.mixer_read(this.mixer_current_address)}; +Q.prototype.port2x6_read=function(){return 255};Q.prototype.port2x7_read=function(){return 255};Q.prototype.port2x8_read=function(){return 255};Q.prototype.port2x9_read=function(){return 255};Q.prototype.port2xA_read=function(){this.read_buffer.length&&(this.read_buffer_lastvalue=this.read_buffer.shift());A(this.read_buffer_lastvalue);String.fromCharCode(this.read_buffer_lastvalue);return this.read_buffer_lastvalue};Q.prototype.port2xB_read=function(){return 255};Q.prototype.port2xC_read=function(){return 127}; +Q.prototype.port2xD_read=function(){return 255};Q.prototype.port2xE_read=function(){this.irq_triggered[1]&&this.lower_irq(1);return(this.read_buffer.length&&!this.dsp_highspeed)<<7|127};Q.prototype.port2xF_read=function(){this.lower_irq(2);return 0};Q.prototype.port2x0_write=function(a){A(a);this.fm_current_address0=0};Q.prototype.port2x1_write=function(a){A(a);var b=La[this.fm_current_address0];b||(b=this.fm_default_write);b.call(this,a,0,this.fm_current_address0)}; +Q.prototype.port2x2_write=function(a){A(a);this.fm_current_address1=0};Q.prototype.port2x3_write=function(a){A(a);var b=La[this.fm_current_address1];b||(b=this.fm_default_write);b.call(this,a,1,this.fm_current_address1)};Q.prototype.port2x4_write=function(a){A(a);this.mixer_current_address=a};Q.prototype.port2x5_write=function(a){A(a);this.mixer_write(this.mixer_current_address,a)}; +Q.prototype.port2x6_write=function(a){A(a);this.dsp_highspeed?this.dsp_highspeed=!1:a&&this.dsp_reset();this.read_buffer.clear();this.read_buffer.push(170)};Q.prototype.port2x7_write=function(){};Q.prototype.port2x8_write=function(){};Q.prototype.port2x9_write=function(){};Q.prototype.port2xA_write=function(){};Q.prototype.port2xB_write=function(){}; +Q.prototype.port2xC_write=function(a){0===this.command?(A(a),this.command=a,this.write_buffer.clear(),this.command_size=Ga[a]):(A(a),this.write_buffer.push(a));this.write_buffer.length>=this.command_size&&this.command_do()};Q.prototype.port2xD_write=function(){};Q.prototype.port2xE_write=function(){};Q.prototype.port2xF_write=function(){}; +Q.prototype.port3x0_read=function(){this.mpu_read_buffer.length&&(this.mpu_read_buffer_lastvalue=this.mpu_read_buffer.shift());A(this.mpu_read_buffer_lastvalue);return this.mpu_read_buffer_lastvalue};Q.prototype.port3x0_write=function(a){A(a)};Q.prototype.port3x1_read=function(){return 0|128*!this.mpu_read_buffer.length};Q.prototype.port3x1_write=function(a){A(a);255==a&&(this.mpu_read_buffer.clear(),this.mpu_read_buffer.push(254))}; +Q.prototype.command_do=function(){var a=Ha[this.command];a||(a=this.dsp_default_handler);a.call(this);this.command_size=this.command=0;this.write_buffer.clear()};Q.prototype.dsp_default_handler=function(){A(this.command)};function R(a,b,c){c||(c=Q.prototype.dsp_default_handler);for(var d=0;dc;c++)b.push(a+c);return b}R([14],2,function(){this.asp_registers[this.write_buffer.shift()]=this.write_buffer.shift()}); +R([15],1,function(){this.read_buffer.clear();this.read_buffer.push(this.asp_registers[this.write_buffer.shift()])});R([16],1,function(){var a=this.write_buffer.shift();a=Na(a/127.5+-1,-1,1);this.dac_buffers[0].push(a);this.dac_buffers[1].push(a);this.bus.send("dac-enable")});R([20,21],2,function(){this.dma_irq=1;this.dma_channel=this.dma_channel_8bit;this.dsp_highspeed=this.dsp_16bit=this.dsp_signed=this.dma_autoinit=!1;this.dma_transfer_size_set();this.dma_transfer_start()});R([22],2);R([23],2); +R([28],0,function(){this.dma_irq=1;this.dma_channel=this.dma_channel_8bit;this.dma_autoinit=!0;this.dsp_highspeed=this.dsp_16bit=this.dsp_signed=!1;this.dma_transfer_start()});R([31],0);R([32],0,function(){this.read_buffer.clear();this.read_buffer.push(127)});R([36],2);R([44],0);R([48],0);R([49],0);R([52],0);R([53],0);R([54],0);R([55],0);R([56],0);R([64],1,function(){this.sampling_rate_change(1E6/(256-this.write_buffer.shift())/this.get_channel_count())}); +R([65,66],2,function(){this.sampling_rate_change(this.write_buffer.shift()<<8|this.write_buffer.shift())});R([72],2,function(){this.dma_transfer_size_set()});R([116],2);R([117],2);R([118],2);R([119],2);R([125],0);R([127],0);R([128],2);R([144],0,function(){this.dma_irq=1;this.dma_channel=this.dma_channel_8bit;this.dma_autoinit=!0;this.dsp_signed=!1;this.dsp_highspeed=!0;this.dsp_16bit=!1;this.dma_transfer_start()});R([145],0);R([152],0);R([153],0);R([160],0);R([168],0); +R(Ma(176),3,function(){if(this.command&8)this.dsp_default_handler();else{var a=this.write_buffer.shift();this.dma_irq=2;this.dma_channel=this.dma_channel_16bit;this.dma_autoinit=!!(this.command&4);this.dsp_signed=!!(a&16);this.dsp_stereo=!!(a&32);this.dsp_16bit=!0;this.dma_transfer_size_set();this.dma_transfer_start()}}); +R(Ma(192),3,function(){if(this.command&8)this.dsp_default_handler();else{var a=this.write_buffer.shift();this.dma_irq=1;this.dma_channel=this.dma_channel_8bit;this.dma_autoinit=!!(this.command&4);this.dsp_signed=!!(a&16);this.dsp_stereo=!!(a&32);this.dsp_16bit=!1;this.dma_transfer_size_set();this.dma_transfer_start()}});R([208],0,function(){this.dma_paused=!0;this.bus.send("dac-disable")});R([209],0,function(){this.dummy_speaker_enabled=!0});R([211],0,function(){this.dummy_speaker_enabled=!1}); +R([212],0,function(){this.dma_paused=!1;this.bus.send("dac-enable")});R([213],0,function(){this.dma_paused=!0;this.bus.send("dac-disable")});R([214],0,function(){this.dma_paused=!1;this.bus.send("dac-enable")});R([216],0,function(){this.read_buffer.clear();this.read_buffer.push(255*this.dummy_speaker_enabled)});R([217,218],0,function(){this.dma_autoinit=!1});R([224],1,function(){this.read_buffer.clear();this.read_buffer.push(~this.write_buffer.shift())}); +R([225],0,function(){this.read_buffer.clear();this.read_buffer.push(4);this.read_buffer.push(5)});R([226],1);R([227],0,function(){this.read_buffer.clear();for(var a=0;44>a;a++)this.read_buffer.push("COPYRIGHT (C) CREATIVE TECHNOLOGY LTD, 1992.".charCodeAt(a));this.read_buffer.push(0)});R([228],1,function(){this.test_register=this.write_buffer.shift()});R([232],0,function(){this.read_buffer.clear();this.read_buffer.push(this.test_register)});R([242,243],0,function(){this.raise_irq()});var Oa=new Uint8Array(256); +Oa[14]=255;Oa[15]=7;Oa[55]=56;R([249],1,function(){var a=this.write_buffer.shift();this.read_buffer.clear();this.read_buffer.push(Oa[a])});Q.prototype.mixer_read=function(a){var b=Ia[a];b?b=b.call(this):(b=this.mixer_registers[a],A(a),A(b));return b};Q.prototype.mixer_write=function(a,b){var c=Ja[a];c?c.call(this,b):(A(a),A(b))};Q.prototype.mixer_default_read=function(){A(this.mixer_current_address);return this.mixer_registers[this.mixer_current_address]}; +Q.prototype.mixer_default_write=function(a){A(this.mixer_current_address);A(a);this.mixer_registers[this.mixer_current_address]=a}; +Q.prototype.mixer_reset=function(){this.mixer_registers[4]=204;this.mixer_registers[34]=204;this.mixer_registers[38]=204;this.mixer_registers[40]=0;this.mixer_registers[46]=0;this.mixer_registers[10]=0;this.mixer_registers[48]=192;this.mixer_registers[49]=192;this.mixer_registers[50]=192;this.mixer_registers[51]=192;this.mixer_registers[52]=192;this.mixer_registers[53]=192;this.mixer_registers[54]=0;this.mixer_registers[55]=0;this.mixer_registers[56]=0;this.mixer_registers[57]=0;this.mixer_registers[59]= +0;this.mixer_registers[60]=31;this.mixer_registers[61]=21;this.mixer_registers[62]=11;this.mixer_registers[63]=0;this.mixer_registers[64]=0;this.mixer_registers[65]=0;this.mixer_registers[66]=0;this.mixer_registers[67]=0;this.mixer_registers[68]=128;this.mixer_registers[69]=128;this.mixer_registers[70]=128;this.mixer_registers[71]=128;this.mixer_full_update()};Q.prototype.mixer_full_update=function(){for(var a=1;a>>4};Ja[a]=function(d){this.mixer_registers[a]=d;var e=d<<4&240|this.mixer_registers[c]&15;this.mixer_write(b,d&240|this.mixer_registers[b]&15);this.mixer_write(c,e)}} +function Ta(a,b,c){Ia[a]=Q.prototype.mixer_default_read;Ja[a]=function(d){this.mixer_registers[a]=d;this.bus.send("mixer-volume",[b,c,(d>>>2)-62])}}Pa(0,function(){this.mixer_reset();return 0});Qa(0);Sa(4,50,51);Sa(34,48,49);Sa(38,52,53);Sa(40,54,55);Sa(46,56,57);Ta(48,0,0);Ta(49,0,1);Ta(50,2,0);Ta(51,2,1);Pa(59);Qa(59,function(a){this.mixer_registers[59]=a;this.bus.send("mixer-volume",[1,2,6*(a>>>6)-18])});Pa(65); +Qa(65,function(a){this.mixer_registers[65]=a;this.bus.send("mixer-gain-left",6*(a>>>6))});Pa(66);Qa(66,function(a){this.mixer_registers[66]=a;this.bus.send("mixer-gain-right",6*(a>>>6))});Pa(68);Qa(68,function(a){this.mixer_registers[68]=a;a>>>=3;this.bus.send("mixer-treble-left",a-(16>a?14:16))});Pa(69);Qa(69,function(a){this.mixer_registers[69]=a;a>>>=3;this.bus.send("mixer-treble-right",a-(16>a?14:16))});Pa(70); +Qa(70,function(a){this.mixer_registers[70]=a;a>>>=3;this.bus.send("mixer-bass-right",a-(16>a?14:16))});Pa(71);Qa(71,function(a){this.mixer_registers[71]=a;a>>>=3;this.bus.send("mixer-bass-right",a-(16>a?14:16))});Pa(128,function(){switch(this.irq){case 2:return 1;case 5:return 2;case 7:return 4;case 10:return 8;default:return 0}});Qa(128,function(a){a&1&&(this.irq=2);a&2&&(this.irq=5);a&4&&(this.irq=7);a&8&&(this.irq=10)}); +Pa(129,function(){var a=0;switch(this.dma_channel_8bit){case 0:a|=1;break;case 1:a|=2;break;case 3:a|=8}switch(this.dma_channel_16bit){case 5:a|=32;break;case 6:a|=64;break;case 7:a|=128}return a});Qa(129,function(a){a&1&&(this.dma_channel_8bit=0);a&2&&(this.dma_channel_8bit=1);a&8&&(this.dma_channel_8bit=3);a&32&&(this.dma_channel_16bit=5);a&64&&(this.dma_channel_16bit=6);a&128&&(this.dma_channel_16bit=7)});Pa(130,function(){for(var a=32,b=0;16>b;b++)a|=b*this.irq_triggered[b];return a}); +Q.prototype.fm_default_write=function(a,b,c){A(c);A(a)};function T(a,b){b||(b=Q.prototype.fm_default_write);for(var c=0;c>2&-4,32),this.dma_bytes_block);this.dma_waiting_transfer=!0;this.dma.channel_mask[this.dma_channel]||this.dma_on_unmask(this.dma_channel)}; +Q.prototype.dma_on_unmask=function(a){a===this.dma_channel&&this.dma_waiting_transfer&&(this.dma_waiting_transfer=!1,this.dma_bytes_left=this.dma_bytes_count,this.dma_paused=!1,this.bus.send("dac-enable"))}; +Q.prototype.dma_transfer_next=function(){var a=Math.min(this.dma_bytes_left,this.dma_bytes_block),b=Math.floor(a/this.bytes_per_sample);this.dma.do_write(this.dma_syncbuffer,0,a,this.dma_channel,c=>{c||(this.dma_to_dac(b),this.dma_bytes_left-=a,this.dma_bytes_left||(this.raise_irq(this.dma_irq),this.dma_autoinit&&(this.dma_bytes_left=this.dma_bytes_count)))})}; +Q.prototype.dma_to_dac=function(a){var b=this.dsp_16bit?32767.5:127.5,c=this.dsp_signed?0:-1,d=this.dsp_stereo?1:2;var e=this.dsp_16bit?this.dsp_signed?this.dma_buffer_int16:this.dma_buffer_uint16:this.dsp_signed?this.dma_buffer_int8:this.dma_buffer_uint8;for(var g=0,f=0;fc)*c+(b<=a&&a<=c)*a};function h(a,b){this.cpu=a;this.pci=a.devices.pci;this.device_id=b.device_id;this.pci_space=[244,26,b.device_id&255,b.device_id>>8,7,5,16,0,1,0,2,0,0,0,0,0,1,168,0,0,0,16,191,254,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,244,26,b.subsystem_device_id&255,b.subsystem_device_id>>8,0,0,0,0,64,0,0,0,0,0,0,0,0,1,0,0];this.pci_space=this.pci_space.concat(r.zeros(256-this.pci_space.length));this.pci_id=b.pci_id;this.pci_bars=[];this.name=b.name;this.driver_feature_select=this.device_feature_select=0;this.device_feature= +new Uint32Array(4);this.driver_feature=new Uint32Array(4);for(var c of b.common.features)this.device_feature[c>>>5]|=1<<(c&31),this.driver_feature[c>>>5]|=1<<(c&31);b.common.features.includes(32);this.features_ok=!0;this.device_status=0;this.config_has_changed=!1;this.config_generation=0;this.queues=[];for(const d of b.common.queues)this.queues.push(new W(a,this,d));this.queue_select=0;this.queue_selected=this.queues[0];this.isr_status=0;c=[];c.push(this.create_common_capability(b.common));c.push(this.create_notification_capability(b.notification)); +c.push(this.create_isr_capability(b.isr_status));b.device_specific&&c.push(this.create_device_specific_capability(b.device_specific));this.init_capabilities(c);a.devices.pci.register_device(this);this.reset()} +h.prototype.create_common_capability=function(a){return{type:1,bar:0,port:a.initial_port,use_mmio:!1,offset:0,extra:new Uint8Array(0),struct:[{bytes:4,name:"device_feature_select",read:()=>this.device_feature_select,write:b=>{this.device_feature_select=b}},{bytes:4,name:"device_feature",read:()=>this.device_feature[this.device_feature_select]||0,write:()=>{}},{bytes:4,name:"driver_feature_select",read:()=>this.driver_feature_select,write:b=>{this.driver_feature_select=b}},{bytes:4,name:"driver_feature", +read:()=>this.driver_feature[this.driver_feature_select]||0,write:b=>{const c=this.device_feature[this.driver_feature_select];this.driver_feature_select65535,write:()=>{}},{bytes:2,name:"num_queues",read:()=>this.queues.length,write:()=>{}},{bytes:1,name:"device_status",read:()=>this.device_status,write:b=>{0===b&&this.reset();b&~this.device_status& +4&&this.device_status&64&&this.notify_config_changes();this.features_ok||(b&=-9);this.device_status=b;if(b&~this.device_status&4)a.on_driver_ok()}},{bytes:1,name:"config_generation",read:()=>this.config_generation,write:()=>{}},{bytes:2,name:"queue_select",read:()=>this.queue_select,write:b=>{this.queue_select=b;this.queue_selected=this.queue_selectthis.queue_selected?this.queue_selected.size:0,write:b=> +{this.queue_selected&&(b&b-1&&(b=1<this.queue_selected.size_supported&&(b=this.queue_selected.size_supported),this.queue_selected.set_size(b))}},{bytes:2,name:"queue_msix_vector",read:()=>65535,write:()=>{}},{bytes:2,name:"queue_enable",read:()=>this.queue_selected?this.queue_selected.enabled|0:0,write:b=>{this.queue_selected&&1===b&&this.queue_selected.is_configured()&&this.queue_selected.enable()}},{bytes:2,name:"queue_notify_off",read:()=>this.queue_selected?this.queue_selected.notify_offset: +0,write:()=>{}},{bytes:4,name:"queue_desc (low dword)",read:()=>this.queue_selected?this.queue_selected.desc_addr:0,write:b=>{this.queue_selected&&(this.queue_selected.desc_addr=b)}},{bytes:4,name:"queue_desc (high dword)",read:()=>0,write:()=>{}},{bytes:4,name:"queue_avail (low dword)",read:()=>this.queue_selected?this.queue_selected.avail_addr:0,write:b=>{this.queue_selected&&(this.queue_selected.avail_addr=b)}},{bytes:4,name:"queue_avail (high dword)",read:()=>0,write:()=>{}},{bytes:4,name:"queue_used (low dword)", +read:()=>this.queue_selected?this.queue_selected.used_addr:0,write:b=>{this.queue_selected&&(this.queue_selected.used_addr=b)}},{bytes:4,name:"queue_used (high dword)",read:()=>0,write:()=>{}}]}}; +h.prototype.create_notification_capability=function(a){const b=[];let c;c=a.single_handler?0:2;for(const [d,e]of a.handlers.entries())b.push({bytes:2,name:"notify"+d,read:()=>65535,write:e||(()=>{})});return{type:2,bar:1,port:a.initial_port,use_mmio:!1,offset:0,extra:new Uint8Array([c&255,c>>8&255,c>>16&255,c>>24]),struct:b}}; +h.prototype.create_isr_capability=function(a){return{type:3,bar:2,port:a.initial_port,use_mmio:!1,offset:0,extra:new Uint8Array(0),struct:[{bytes:1,name:"isr_status",read:()=>{const b=this.isr_status;this.lower_irq();return b},write:()=>{}}]}};h.prototype.create_device_specific_capability=function(a){return{type:4,bar:3,port:a.initial_port,use_mmio:!1,offset:0,extra:new Uint8Array(0),struct:a.struct}}; +h.prototype.init_capabilities=function(a){let b=this.pci_space[52]=64;var c=b;for(const e of a){a=16+e.extra.length;c=b;b=c+a;var d=e.struct.reduce((g,f)=>g+f.bytes,0);d+=e.offset;d=16>d?16:1<>>8&255;this.pci_space[c+ +10]=e.offset>>>16&255;this.pci_space[c+11]=e.offset>>>24;this.pci_space[c+12]=d&255;this.pci_space[c+13]=d>>>8&255;this.pci_space[c+14]=d>>>16&255;this.pci_space[c+15]=d>>>24;for(const [g,f]of e.extra.entries())this.pci_space[c+16+g]=f;c=16+4*e.bar;this.pci_space[c]=e.port&254|!e.use_mmio;this.pci_space[c+1]=e.port>>>8&255;this.pci_space[c+2]=e.port>>>16&255;this.pci_space[c+3]=e.port>>>24&255;c=e.port+e.offset;for(const g of e.struct){let f=g.read;a=g.write;if(!e.use_mmio){d=function(l){return f(l& +-2)>>((l&1)<<3)&255};const k=function(l){return f(l&-4)>>((l&3)<<3)&255};switch(g.bytes){case 4:this.cpu.io.register_read(c,this,k,void 0,f);this.cpu.io.register_write(c,this,void 0,void 0,a);break;case 2:this.cpu.io.register_read(c,this,d,f);this.cpu.io.register_write(c,this,void 0,a);break;case 1:this.cpu.io.register_read(c,this,f),this.cpu.io.register_write(c,this,a)}}c+=g.bytes}}this.pci_space[b]=9;this.pci_space[b+1]=0;this.pci_space[b+2]=20;this.pci_space[b+3]=5;this.pci_space[b+4]=0;this.pci_space[b+ +5]=0;this.pci_space[b+6]=0;this.pci_space[b+7]=0;this.pci_space[b+8]=0;this.pci_space[b+9]=0;this.pci_space[b+10]=0;this.pci_space[b+11]=0;this.pci_space[b+12]=0;this.pci_space[b+13]=0;this.pci_space[b+14]=0;this.pci_space[b+15]=0;this.pci_space[b+16]=0;this.pci_space[b+17]=0;this.pci_space[b+18]=0;this.pci_space[b+19]=0}; +h.prototype.get_state=function(){let a=[];a[0]=this.device_feature_select;a[1]=this.driver_feature_select;a[2]=this.device_feature;a[3]=this.driver_feature;a[4]=this.features_ok;a[5]=this.device_status;a[6]=this.config_has_changed;a[7]=this.config_generation;a[8]=this.isr_status;a[9]=this.queue_select;return a=a.concat(this.queues)}; +h.prototype.set_state=function(a){this.device_feature_select=a[0];this.driver_feature_select=a[1];this.device_feature=a[2];this.driver_feature=a[3];this.features_ok=a[4];this.device_status=a[5];this.config_has_changed=a[6];this.config_generation=a[7];this.isr_status=a[8];this.queue_select=a[9];let b=0;for(let c of a.slice(10))this.queues[b].set_state(c),b++;this.queue_selected=this.queues[this.queue_select]||null}; +h.prototype.reset=function(){this.driver_feature_select=this.device_feature_select=0;this.driver_feature.set(this.device_feature);this.features_ok=!0;this.queue_select=this.device_status=0;this.queue_selected=this.queues[0];for(const a of this.queues)a.reset();this.config_has_changed=!1;this.config_generation=0;this.lower_irq()};h.prototype.notify_config_changes=function(){this.config_has_changed=!0;this.device_status&4&&this.raise_irq(2)}; +h.prototype.update_config_generation=function(){this.config_has_changed&&(this.config_generation++,this.config_generation&=255,this.config_has_changed=!1)};h.prototype.is_feature_negotiated=function(a){return 0<(this.driver_feature[a>>>5]&1<<(a&31))};h.prototype.needs_reset=function(){this.device_status|=64;this.device_status&4&&this.notify_config_changes()};h.prototype.raise_irq=function(a){A(a);this.isr_status|=a;this.pci.raise_irq(this.pci_id)}; +h.prototype.lower_irq=function(){this.isr_status=0;this.pci.lower_irq(this.pci_id)};function W(a,b,c){this.cpu=a;this.virtio=b;this.size_supported=this.size=c.size_supported;this.mask=this.size-1;this.enabled=!1;this.notify_offset=c.notify_offset;this.num_staged_replies=this.used_addr=this.avail_last_idx=this.avail_addr=this.desc_addr=0;this.reset()} +W.prototype.get_state=function(){const a=[];a[0]=this.size;a[1]=this.size_supported;a[2]=this.enabled;a[3]=this.notify_offset;a[4]=this.desc_addr;a[5]=this.avail_addr;a[6]=this.avail_last_idx;a[7]=this.used_addr;a[8]=this.num_staged_replies;return a}; +W.prototype.set_state=function(a){this.size=a[0];this.size_supported=a[1];this.enabled=a[2];this.notify_offset=a[3];this.desc_addr=a[4];this.avail_addr=a[5];this.avail_last_idx=a[6];this.used_addr=a[7];this.num_staged_replies=a[8];this.mask=this.size-1};W.prototype.reset=function(){this.enabled=!1;this.num_staged_replies=this.used_addr=this.avail_last_idx=this.avail_addr=this.desc_addr=0;this.set_size(this.size_supported)}; +W.prototype.is_configured=function(){return this.desc_addr&&this.avail_addr&&this.used_addr};W.prototype.enable=function(){this.is_configured();this.enabled=!0};W.prototype.set_size=function(a){this.size=a;this.mask=a-1};W.prototype.count_requests=function(){return this.avail_get_idx()-this.avail_last_idx&this.mask};W.prototype.has_request=function(){return(this.avail_get_idx()&this.mask)!==this.avail_last_idx}; +W.prototype.pop_request=function(){this.has_request();var a=this.avail_get_entry(this.avail_last_idx);a=new Va(this,a);this.avail_last_idx=this.avail_last_idx+1&this.mask;return a};W.prototype.push_reply=function(a){const b=this.used_get_idx()+this.num_staged_replies&this.mask;this.used_set_entry(b,a.head_idx,a.length_written);this.num_staged_replies++}; +W.prototype.flush_replies=function(){if(0!==this.num_staged_replies){var a=this.used_get_idx()+this.num_staged_replies&65535;this.used_set_idx(a);this.num_staged_replies=0;this.virtio.is_feature_negotiated(29)?(this.avail_get_used_event(),this.virtio.raise_irq(1)):~this.avail_get_flags()&1&&this.virtio.raise_irq(1)}};W.prototype.notify_me_after=function(a){a=this.avail_get_idx()+a&65535;this.used_set_avail_event(a)}; +W.prototype.get_descriptor=function(a,b){return{addr_low:this.cpu.read32s(a+16*b),addr_high:this.cpu.read32s(a+16*b+4),len:this.cpu.read32s(a+16*b+8),flags:this.cpu.read16(a+16*b+12),next:this.cpu.read16(a+16*b+14)}};W.prototype.avail_get_flags=function(){return this.cpu.read16(this.avail_addr)};W.prototype.avail_get_idx=function(){return this.cpu.read16(this.avail_addr+2)};W.prototype.avail_get_entry=function(a){return this.cpu.read16(this.avail_addr+4+2*a)}; +W.prototype.avail_get_used_event=function(){return this.cpu.read16(this.avail_addr+4+2*this.size)};W.prototype.used_get_flags=function(){return this.cpu.read16(this.used_addr)};W.prototype.used_set_flags=function(a){this.cpu.write16(this.used_addr,a)};W.prototype.used_get_idx=function(){return this.cpu.read16(this.used_addr+2)};W.prototype.used_set_idx=function(a){this.cpu.write16(this.used_addr+2,a)}; +W.prototype.used_set_entry=function(a,b,c){this.cpu.write32(this.used_addr+4+8*a,b);this.cpu.write32(this.used_addr+8+8*a,c)};W.prototype.used_set_avail_event=function(a){this.cpu.write16(this.used_addr+4+8*this.size,a)}; +function Va(a,b){this.cpu=a.cpu;this.virtio=a.virtio;this.head_idx=b;this.read_buffers=[];this.length_readable=this.read_buffer_offset=this.read_buffer_idx=0;this.write_buffers=[];this.length_writable=this.length_written=this.write_buffer_offset=this.write_buffer_idx=0;let c=a.desc_addr,d=0,e=a.size,g=!1;const f=this.virtio.is_feature_negotiated(28);do{const k=a.get_descriptor(c,b);A(k.addr_high,8);A(k.addr_low,8);A(k.len,8);A(k.flags,4);A(k.next,4);if(f&&k.flags&4)c=k.addr_low,d=b=0,e=k.len/16;else{if(k.flags& +2)g=!0,this.write_buffers.push(k),this.length_writable+=k.len;else{if(g)break;this.read_buffers.push(k);this.length_readable+=k.len}d++;if(d>e)break;if(k.flags&1)b=k.next;else break}}while(1)} +Va.prototype.get_next_blob=function(a){let b=0,c=a.length;for(;c&&this.read_buffer_idx!==this.read_buffers.length;){var d=this.read_buffers[this.read_buffer_idx];const e=d.addr_low+this.read_buffer_offset;d=d.len-this.read_buffer_offset;d>c?(d=c,this.read_buffer_offset+=c):(this.read_buffer_idx++,this.read_buffer_offset=0);a.set(this.cpu.read_blob(e,d),b);b+=d;c-=d}return b}; +Va.prototype.set_next_blob=function(a){let b=0,c=a.length;for(;c&&this.write_buffer_idx!==this.write_buffers.length;){var d=this.write_buffers[this.write_buffer_idx];const e=d.addr_low+this.write_buffer_offset;d=d.len-this.write_buffer_offset;d>c?(d=c,this.write_buffer_offset+=c):(this.write_buffer_idx++,this.write_buffer_offset=0);this.cpu.write_blob(a.subarray(b,b+d),e);b+=d;c-=d}this.length_written+=b;return b};function Wa(a,b){this.bus=b;this.rows=25;this.cols=80;this.ports=4;b=[{size_supported:16,notify_offset:0},{size_supported:16,notify_offset:1},{size_supported:16,notify_offset:2},{size_supported:16,notify_offset:3}];for(let c=1;c{}},notification:{initial_port:47360, +single_handler:!1,handlers:[c=>{for(c=this.virtio.queues[c];c.count_requests()>c.size-2;)c.pop_request()},c=>{let d=this.virtio.queues[c],e=3>1:0;for(;d.has_request();){const g=d.pop_request(),f=new Uint8Array(g.length_readable);g.get_next_blob(f);this.bus.send("virtio-console"+e+"-output-bytes",f);this.Ack(c,g)}},c=>{if(2==c)for(c=this.virtio.queues[c];c.count_requests()>c.size-2;)c.pop_request()},c=>{if(3==c)for(var d=this.virtio.queues[c];d.has_request();){var e=d.pop_request(),g=new Uint8Array(e.length_readable); +e.get_next_blob(g);var f=v.Unmarshall(["w","h","h"],g,{offset:0});g=f[0];f=f[1];this.Ack(c,e);switch(f){case 0:for(e=0;ethis.cols,write:()=>{}},{bytes:2,name:"rows",read:()=>this.rows, +write:()=>{}},{bytes:4,name:"max_nr_ports",read:()=>this.ports,write:()=>{}},{bytes:4,name:"emerg_wr",read:()=>0,write:()=>{}}]}});for(let c=0;cthis.wm.exports[c],b=c=>{const d=a(c);console.assert(d,"Missing import: "+c);return d};this.reset_cpu=b("reset_cpu");this.getiopl=b("getiopl");this.get_eflags=b("get_eflags");this.handle_irqs=b("handle_irqs");this.main_loop=b("main_loop");this.set_jit_config=b("set_jit_config");this.read8=b("read8");this.read16=b("read16");this.read32s=b("read32s");this.write8=b("write8");this.write16=b("write16");this.write32=b("write32");this.in_mapped_range=b("in_mapped_range"); +this.fpu_load_tag_word=b("fpu_load_tag_word");this.fpu_load_status_word=b("fpu_load_status_word");this.fpu_get_sti_f64=b("fpu_get_sti_f64");this.translate_address_system_read=b("translate_address_system_read_js");this.get_seg_cs=b("get_seg_cs");this.get_real_eip=b("get_real_eip");this.clear_tlb=b("clear_tlb");this.full_clear_tlb=b("full_clear_tlb");this.update_state_flags=b("update_state_flags");this.set_tsc=b("set_tsc");this.store_current_tsc=b("store_current_tsc");this.set_cpuid_level=b("set_cpuid_level"); +this.pic_set_irq=b("pic_set_irq");this.pic_clear_irq=b("pic_clear_irq");this.jit_clear_cache=b("jit_clear_cache_js");this.jit_dirty_cache=b("jit_dirty_cache");this.codegen_finalize_finished=b("codegen_finalize_finished");this.allocate_memory=b("allocate_memory");this.zero_memory=b("zero_memory");this.svga_allocate_memory=b("svga_allocate_memory");this.svga_allocate_dest_buffer=b("svga_allocate_dest_buffer");this.svga_fill_pixel_buffer=b("svga_fill_pixel_buffer");this.svga_mark_dirty=b("svga_mark_dirty"); +this.get_pic_addr_master=b("get_pic_addr_master");this.get_pic_addr_slave=b("get_pic_addr_slave");this.zstd_create_ctx=b("zstd_create_ctx");this.zstd_get_src_ptr=b("zstd_get_src_ptr");this.zstd_free_ctx=b("zstd_free_ctx");this.zstd_read=b("zstd_read");this.zstd_read_free=b("zstd_read_free");this.port20_read=b("port20_read");this.port21_read=b("port21_read");this.portA0_read=b("portA0_read");this.portA1_read=b("portA1_read");this.port20_write=b("port20_write");this.port21_write=b("port21_write");this.portA0_write= +b("portA0_write");this.portA1_write=b("portA1_write");this.port4D0_read=b("port4D0_read");this.port4D1_read=b("port4D1_read");this.port4D0_write=b("port4D0_write");this.port4D1_write=b("port4D1_write")};E.prototype.jit_force_generate=function(a){this.jit_force_generate_unsafe&&this.jit_force_generate_unsafe(a)};E.prototype.jit_clear_func=function(a){this.wm.wasm_table.set(a+1024,null)};E.prototype.jit_clear_all_funcs=function(){const a=this.wm.wasm_table;for(let b=0;900>b;b++)a.set(1024+b,null)}; +E.prototype.get_state=function(){var a=[];a[0]=this.memory_size[0];a[1]=this.segment_is_null;a[2]=this.segment_offsets;a[3]=this.segment_limits;a[4]=this.protected_mode[0];a[5]=this.idtr_offset[0];a[6]=this.idtr_size[0];a[7]=this.gdtr_offset[0];a[8]=this.gdtr_size[0];a[9]=this.page_fault[0];a[10]=this.cr;a[11]=this.cpl[0];a[13]=this.is_32[0];a[16]=this.stack_size_32[0];a[17]=this.in_hlt[0];a[18]=this.last_virt_eip[0];a[19]=this.eip_phys[0];a[22]=this.sysenter_cs[0];a[23]=this.sysenter_eip[0];a[24]= +this.sysenter_esp[0];a[25]=this.prefixes[0];a[26]=this.flags[0];a[27]=this.flags_changed[0];a[28]=this.last_op1[0];a[30]=this.last_op_size[0];a[37]=this.instruction_pointer[0];a[38]=this.previous_ip[0];a[39]=this.reg32;a[40]=this.sreg;a[41]=this.dreg;a[42]=this.reg_pdpte;this.store_current_tsc();a[43]=this.current_tsc;a[45]=this.devices.virtio_9p;a[46]=this.devices.apic;a[47]=this.devices.rtc;a[48]=this.devices.pci;a[49]=this.devices.dma;a[50]=this.devices.acpi;a[52]=this.devices.vga;a[53]=this.devices.ps2; +a[54]=this.devices.uart0;a[55]=this.devices.fdc;a[56]=this.devices.cdrom;a[57]=this.devices.hda;a[58]=this.devices.pit;a[59]=this.devices.net;a[60]=this.get_state_pic();a[61]=this.devices.sb16;a[62]=this.fw_value;a[63]=this.devices.ioapic;a[64]=this.tss_size_32[0];a[66]=this.reg_xmm32s;a[67]=this.fpu_st;a[68]=this.fpu_stack_empty[0];a[69]=this.fpu_stack_ptr[0];a[70]=this.fpu_control_word[0];a[71]=this.fpu_ip[0];a[72]=this.fpu_ip_selector[0];a[73]=this.fpu_dp[0];a[74]=this.fpu_dp_selector[0];a[75]= +this.fpu_opcode[0];const {packed_memory:b,bitmap:c}=this.pack_memory();a[77]=b;a[78]=new Uint8Array(c.get_buffer());a[79]=this.devices.uart1;a[80]=this.devices.uart2;a[81]=this.devices.uart3;a[82]=this.devices.virtio_console;return a}; +E.prototype.get_state_pic=function(){const a=new Uint8Array(this.wasm_memory.buffer,this.get_pic_addr_master(),13),b=new Uint8Array(this.wasm_memory.buffer,this.get_pic_addr_slave(),13),c=[],d=[];c[0]=a[0];c[1]=a[1];c[2]=a[2];c[3]=a[3];c[4]=a[4];c[5]=d;c[6]=a[6];c[7]=a[7];c[8]=a[8];c[9]=a[9];c[10]=a[10];c[11]=a[11];c[12]=a[12];d[0]=b[0];d[1]=b[1];d[2]=b[2];d[3]=b[3];d[4]=b[4];d[5]=null;d[6]=b[6];d[7]=b[7];d[8]=b[8];d[9]=b[9];d[10]=b[10];d[12]=b[12];d[12]=b[12];return c}; +E.prototype.set_state=function(a){this.memory_size[0]=a[0];this.mem8.length!==this.memory_size[0]&&console.warn("Note: Memory size mismatch. we="+this.mem8.length+" state="+this.memory_size[0]);this.segment_is_null.set(a[1]);this.segment_offsets.set(a[2]);this.segment_limits.set(a[3]);this.protected_mode[0]=a[4];this.idtr_offset[0]=a[5];this.idtr_size[0]=a[6];this.gdtr_offset[0]=a[7];this.gdtr_size[0]=a[8];this.page_fault[0]=a[9];this.cr.set(a[10]);this.cpl[0]=a[11];this.is_32[0]=a[13];this.stack_size_32[0]= +a[16];this.in_hlt[0]=a[17];this.last_virt_eip[0]=a[18];this.eip_phys[0]=a[19];this.sysenter_cs[0]=a[22];this.sysenter_eip[0]=a[23];this.sysenter_esp[0]=a[24];this.prefixes[0]=a[25];this.flags[0]=a[26];this.flags_changed[0]=a[27];this.last_op1[0]=a[28];this.last_op_size[0]=a[30];this.instruction_pointer[0]=a[37];this.previous_ip[0]=a[38];this.reg32.set(a[39]);this.sreg.set(a[40]);this.dreg.set(a[41]);a[42]&&this.reg_pdpte.set(a[42]);this.set_tsc(a[43][0],a[43][1]);this.devices.virtio_9p&&this.devices.virtio_9p.set_state(a[45]); +this.devices.apic&&this.devices.apic.set_state(a[46]);this.devices.rtc&&this.devices.rtc.set_state(a[47]);this.devices.pci&&this.devices.pci.set_state(a[48]);this.devices.dma&&this.devices.dma.set_state(a[49]);this.devices.acpi&&this.devices.acpi.set_state(a[50]);this.devices.vga&&this.devices.vga.set_state(a[52]);this.devices.ps2&&this.devices.ps2.set_state(a[53]);this.devices.uart0&&this.devices.uart0.set_state(a[54]);this.devices.fdc&&this.devices.fdc.set_state(a[55]);this.devices.cdrom&&this.devices.cdrom.set_state(a[56]); +this.devices.hda&&this.devices.hda.set_state(a[57]);this.devices.pit&&this.devices.pit.set_state(a[58]);this.devices.net&&this.devices.net.set_state(a[59]);this.set_state_pic(a[60]);this.devices.sb16&&this.devices.sb16.set_state(a[61]);this.devices.uart1&&this.devices.uart1.set_state(a[79]);this.devices.uart2&&this.devices.uart2.set_state(a[80]);this.devices.uart3&&this.devices.uart3.set_state(a[81]);this.devices.virtio_console&&this.devices.virtio_console.set_state(a[82]);this.fw_value=a[62];this.devices.ioapic&& +this.devices.ioapic.set_state(a[63]);this.tss_size_32[0]=a[64];this.reg_xmm32s.set(a[66]);this.fpu_st.set(a[67]);this.fpu_stack_empty[0]=a[68];this.fpu_stack_ptr[0]=a[69];this.fpu_control_word[0]=a[70];this.fpu_ip[0]=a[71];this.fpu_ip_selector[0]=a[72];this.fpu_dp[0]=a[73];this.fpu_dp_selector[0]=a[74];this.fpu_opcode[0]=a[75];const b=new r.Bitmap(a[78].buffer);this.unpack_memory(b,a[77]);this.update_state_flags();this.full_clear_tlb();this.jit_clear_cache()}; +E.prototype.set_state_pic=function(a){const b=new Uint8Array(this.wasm_memory.buffer,this.get_pic_addr_master(),13),c=new Uint8Array(this.wasm_memory.buffer,this.get_pic_addr_slave(),13);b[0]=a[0];b[1]=a[1];b[2]=a[2];b[3]=a[3];b[4]=a[4];const d=a[5];b[6]=a[6];b[7]=a[7];b[8]=a[8];b[9]=a[9];b[10]=a[10];b[11]=a[11];b[12]=a[12];c[0]=d[0];c[1]=d[1];c[2]=d[2];c[3]=d[3];c[4]=d[4];c[6]=d[6];c[7]=d[7];c[8]=d[8];c[9]=d[9];c[10]=d[10];c[12]=d[12];c[12]=d[12]}; +E.prototype.pack_memory=function(){var a=this.mem8.length>>12,b=[];for(var c=0;c>2,d+4096>>2);let e=!0;for(let g=0;g>12;let d=0;for(let g=0;ga?a=1048576:0>(a|0)&&(a=Math.pow(2,31)-131072);a=(a-1|131071)+1|0;console.assert(0===this.memory_size[0],"Expected uninitialised memory");this.memory_size[0]=a;const b=this.allocate_memory(a);this.mem8=r.view(Uint8Array,this.wasm_memory,b,a);this.mem32s=r.view(Uint32Array,this.wasm_memory,b,a>>2)};F.exportProperty(E.prototype,"create_memory",E.prototype.create_memory); +E.prototype.init=function(a,b){this.create_memory("number"===typeof a.memory_size?a.memory_size:67108864);a.disable_jit&&this.set_jit_config(0,1);a.cpuid_level&&this.set_cpuid_level(a.cpuid_level);this.acpi_enabled[0]=+a.acpi;this.reset_cpu();var c=new B(this);this.io=c;this.bios.main=a.bios;this.bios.vga=a.vga_bios;this.load_bios();if(a.bzimage){const e=Za(this.mem8,a.bzimage,a.initrd,a.cmdline||"");e&&this.option_roms.push(e)}c.register_read(179,this,function(){return 0});var d=0;c.register_read(146, +this,function(){return d});c.register_write(146,this,function(e){d=e});c.register_read(1297,this,function(){return this.fw_pointer>8|l<<8&65280}function k(l){return l<<24|l<<8&16711680|l>>8&65280|l>>>24}J("bios config port, index="+A(e));this.fw_pointer=0;if(0===e)this.fw_value=g(1431127377);else if(1===e)this.fw_value= +g(0);else if(3===e)this.fw_value=g(this.memory_size[0]);else if(5===e)this.fw_value=g(1);else if(15===e)this.fw_value=g(1);else if(13===e)this.fw_value=new Uint8Array(16);else if(25===e){e=new Int32Array(4+64*this.option_roms.length);const l=new Uint8Array(e.buffer);e[0]=k(this.option_roms.length);for(let m=0;m>2]=k(p.length);e[t+4>>2]=f(49152+m);for(let q=0;qe?this.fw_value=g(0):49152<=e&&e-49152a.byteLength){var d=new Int32Array(2048);(new Uint8Array(d.buffer)).set(new Uint8Array(a))}else d=new Int32Array(a,0,2048);for(var e=0;8192>e;e+=4){if(464367618===d[e>>2]){var g=d[e+4>>2];if(464367618+g+d[e+8>>2]|0)continue}else continue;J("Multiboot magic found, flags: "+A(g>>>0,8),2);var f=this;this.io.register_read(244,this,function(){return 0},function(){return 0},function(){var n=31860,p=0;if(c){p|=4;f.write32(31760,n);c+="\x00";var t= +(new TextEncoder).encode(c);f.write_blob(t,n);n+=t.length}if(g&2){p|=64;t=0;f.write32(31788,0);f.write32(31792,n);var q=0;var z=!1;for(let u=0;4294967296>u;u+=131072)z&&void 0!==f.memory_map_read8[u>>>17]?(f.write32(n,20),f.write32(n+4,q),f.write32(n+8,0),f.write32(n+12,u-q),f.write32(n+16,0),f.write32(n+20,1),n+=24,t+=24,z=!1):z||void 0!==f.memory_map_read8[u>>>17]||(q=u,z=!0);f.write32(31788,t)}f.write32(31744,p);t=p=0;if(g&65536){z=d[e+12>>2];p=d[e+16>>2];var w=d[e+20>>2];t=d[e+24>>2];q=d[e+28>> +2];A(z,8);A(p,8);A(w,8);A(t,8);A(q,8);z=new Uint8Array(a,e-(z-p),0===w?void 0:w-p);f.write_blob(z,p);p=q|0;t=Math.max(w,t)}else if(1179403647===d[0]){q=new DataView(a);let [u,I]=$a(q,ab);console.assert(52===I);console.assert(1179403647===u.magic,"Bad magic");console.assert(1===u.class,"Unimplemented: 64 bit elf");console.assert(1===u.data,"Unimplemented: big endian");console.assert(1===u.version0,"Bad version0");console.assert(2===u.type,"Unimplemented type");console.assert(1===u.version1,"Bad version1"); +console.assert(52===u.ehsize,"Bad header size");console.assert(32===u.phentsize,"Bad program header size");console.assert(40===u.shentsize,"Bad section header size");[p]=bb(new DataView(q.buffer,q.byteOffset+u.phoff,u.phentsize*u.phnum),cb,u.phnum);bb(new DataView(q.buffer,q.byteOffset+u.shoff,u.shentsize*u.shnum),gb,u.shnum);q=u;z=p;p=q.entry;for(w of z)0!==w.type&&(1===w.type?w.paddr+w.memszp&&(p=p-w.vaddr+w.paddr)):A(w.paddr):2===w.type||3===w.type||4===w.type||6===w.type||7===w.type||1685382480===w.type||1685382481===w.type||1685382482===w.type||1685382483===w.type||A(w.type))}b&&(f.write32(31764,1),f.write32(31768,n),w=t,0!==(w&4095)&&(w=(w&-4096)+4096),t=w+b.byteLength,f.write32(n,w),f.write32(n+4,t),f.write32(n+8,0),f.write32(n+12,0),f.write_blob(new Uint8Array(b),w));f.reg32[3]=31744;f.cr[0]=1;f.protected_mode[0]=1;f.flags[0]= +2;f.is_32[0]=1;f.stack_size_32[0]=1;for(n=0;6>n;n++)f.segment_is_null[n]=0,f.segment_offsets[n]=0,f.segment_limits[n]=4294967295,f.sreg[n]=45058;f.instruction_pointer[0]=f.get_seg_cs()+p|0;f.update_state_flags();f.debug.dump_state();f.debug.dump_regs();return 732803074});this.io.register_write_consecutive(244,this,function(n){console.log("Test exited with code "+A(n,2));throw"HALT";},function(){},function(){},function(){});for(let n=0;15>=n;n++){function p(t){A(n);A(t,2);t?this.device_raise_irq(n): +this.device_lower_irq(n)}this.io.register_write(8192+n,this,p,p,p)}const l=new Uint8Array(512);(new Uint16Array(l.buffer))[0]=43605;l[2]=1;var k=3;l[k++]=102;l[k++]=229;l[k++]=244;let m=l[k]=0;for(let n=0;n>4&240);a.cmos_write(61,c&255);a.cmos_write(21,128);a.cmos_write(22,2);c=0;1048576<=this.memory_size[0]&&(c=this.memory_size[0]-1048576>>10,c=Math.min(c,65535));a.cmos_write(23,c&255);a.cmos_write(24,c>>8&255);a.cmos_write(48,c&255);a.cmos_write(49,c>>8&255);c=0;16777216<=this.memory_size[0]&&(c=this.memory_size[0]-16777216>>16,c=Math.min(c,65535));a.cmos_write(52,c&255);a.cmos_write(53,c>>8&255);a.cmos_write(91,0);a.cmos_write(92, +0);a.cmos_write(93,0);a.cmos_write(20,47);a.cmos_write(95,0);b.fastboot&&a.cmos_write(63,1)}; +E.prototype.load_bios=function(){var a=this.bios.main,b=this.bios.vga;if(a){var c=new Uint8Array(a);this.write_blob(c,1048576-a.byteLength);if(b){var d=new Uint8Array(b);this.write_blob(d,786432);this.io.mmap_register(4272947200,1048576,function(e){e=e-4272947200|0;return e>>0,e>>>0);WebAssembly.instantiate(g,{e:this.jit_imports}).then(f=>{this.wm.wasm_table.set(a+1024,f.instance.exports.f);this.codegen_finalize_finished(a,b,c);this.test_hook_did_finalize_wasm&&this.test_hook_did_finalize_wasm(g)})};E.prototype.log_uncompiled_code=function(){};E.prototype.dump_function_code=function(){}; +E.prototype.run_hardware_timers=function(a,b){const c=this.devices.pit.timer(b,!1),d=this.devices.rtc.timer(b,!1);let e=100,g=100;a&&(e=this.devices.acpi.timer(b),g=this.devices.apic.timer(b));return Math.min(c,d,e,g)};E.prototype.device_raise_irq=function(a){this.pic_set_irq(a);this.devices.ioapic&&this.devices.ioapic.set_irq(a)};E.prototype.device_lower_irq=function(a){this.pic_clear_irq(a);this.devices.ioapic&&this.devices.ioapic.clear_irq(a)}; +"undefined"!==typeof window?window.CPU=E:"undefined"!==typeof module&&"undefined"!==typeof module.exports?module.exports.CPU=E:"function"===typeof importScripts&&(self.CPU=E);E.prototype.debug_init=function(){var a=this,b={};this.debug=b;b.init=function(){};b.get_regs_short=function(){};b.dump_regs=function(){};b.get_state=function(){};b.dump_state=function(){};b.dump_stack=function(){};b.dump_page_structures=function(){if(a.cr[4]&32)for(var g=0;4>g;g++)a.read32s(a.cr[3]+8*g)};b.dump_gdt_ldt=function(){};b.dump_idt=function(){};b.get_memory_dump=function(){};b.memory_hex_dump=function(){};b.used_memory_dump=function(){};b.debug_interrupt=function(){};let c,d;b.dump_code= +function(g,f,k){if(!d){if(void 0===c&&(c="function"===typeof require?require("./capstone-x86.min.js"):window.cs,void 0===c))return;d=[new c.Capstone(c.ARCH_X86,c.MODE_16),new c.Capstone(c.ARCH_X86,c.MODE_32)]}try{d[g].disasm(f,k).forEach(function(l){J(A(l.address>>>0)+": "+r.pads(l.bytes.map(m=>A(m,2).slice(-2)).join(" "),20)+" "+l.mnemonic+" "+l.op_str)})}catch(l){J("Could not disassemble: "+Array.from(f).map(m=>A(m,2)).join(" "))}};let e;b.dump_wasm=function(g){if(void 0===e&&(e="function"===typeof require? +require("./libwabt.js"):new window.WabtModule,void 0===e))return;g=g.slice();try{var f=e.readWasm(g,{readDebugNames:!1});f.generateNames();f.applyNames();f.toText({foldExprs:!0,inlineExport:!0})}catch(m){var k=new Blob([g]),l=document.createElement("a");l.download="failed.wasm";l.href=window.URL.createObjectURL(k);l.dataset.downloadurl=["application/octet-stream",l.download,l.href].join(":");l.click();window.URL.revokeObjectURL(l.src);console.log(m.toString())}finally{f&&f.destroy()}}};let hb=DataView.prototype,ib={size:1,get:hb.getUint8,set:hb.setUint8},jb={size:2,get:hb.getUint16,set:hb.setUint16},X={size:4,get:hb.getUint32,set:hb.setUint32},ab=kb([{magic:X},{class:ib},{data:ib},{version0:ib},{osabi:ib},{abiversion:ib},{pad0:function(a){return{size:a,get:()=>-1}}(7)},{type:jb},{machine:jb},{version1:X},{entry:X},{phoff:X},{shoff:X},{flags:X},{ehsize:jb},{phentsize:jb},{phnum:jb},{shentsize:jb},{shnum:jb},{shstrndx:jb}]);console.assert(52===ab.reduce((a,b)=>a+b.size,0)); +let cb=kb([{type:X},{offset:X},{vaddr:X},{paddr:X},{filesz:X},{memsz:X},{flags:X},{align:X}]);console.assert(32===cb.reduce((a,b)=>a+b.size,0));let gb=kb([{name:X},{type:X},{flags:X},{addr:X},{offset:X},{size:X},{link:X},{info:X},{addralign:X},{entsize:X}]);console.assert(40===gb.reduce((a,b)=>a+b.size,0));function kb(a){return a.map(function(b){var c=Object.keys(b);console.assert(1===c.length);c=c[0];b=b[c];console.assert(0 keyCode not found: ",z,q)}};function mb(a,b){function c(u){if(!w.enabled||!w.emu_enabled)return!1;var I=b||document.body,U;if(!(U=document.pointerLockElement))a:{for(u=u.target;u.parentNode;){if(u===I){U=!0;break a}u=u.parentNode}U=!1}return U}function d(u){c(u)&&(u=u.changedTouches)&&u.length&&(u=u[u.length-1],q=u.clientX,z=u.clientY)}function e(){if(n||t||p)w.bus.send("mouse-click",[!1,!1,!1]),n=t=p=!1}function g(u){if(w.bus&&c(u)&&w.is_running){var I=0,U=0,ea=u.changedTouches;ea?ea.length&&(ea=ea[ea.length-1],I=ea.clientX- +q,U=ea.clientY-z,q=ea.clientX,z=ea.clientY,u.preventDefault()):"number"===typeof u.movementX?(I=u.movementX,U=u.movementY):"number"===typeof u.webkitMovementX?(I=u.webkitMovementX,U=u.webkitMovementY):"number"===typeof u.mozMovementX?(I=u.mozMovementX,U=u.mozMovementY):(I=u.clientX-q,U=u.clientY-z,q=u.clientX,z=u.clientY);w.bus.send("mouse-delta",[.15*I,-(.15*U)]);b&&w.bus.send("mouse-absolute",[u.pageX-b.offsetLeft,u.pageY-b.offsetTop,b.offsetWidth,b.offsetHeight])}}function f(u){c(u)&&l(u,!0)}function k(u){c(u)&& +l(u,!1)}function l(u,I){w.bus&&(1===u.which?n=I:2===u.which?t=I:3===u.which&&(p=I),w.bus.send("mouse-click",[n,t,p]),u.preventDefault())}function m(u){if(c(u)){var I=u.wheelDelta||-u.detail;0>I?I=-1:0{switch(n.data.type){case "queue":m.queue_push(n.data.value);break;case "sampling-rate":m.source_samples_per_destination=n.data.value/sampleRate}};return m}var l=[new Float32Array(256),new Float32Array(256)];Reflect.setPrototypeOf(k.prototype,AudioWorkletProcessor.prototype);Reflect.setPrototypeOf(k,AudioWorkletProcessor);k.prototype.process=k.prototype.process=function(m,n){for(m=0;mm?(m+=this.source_buffer_previous[0].length,this.source_buffer_previous[n][m]):this.source_buffer_current[n][m]};k.prototype.ensure_enough_data=function(m){var n=this.source_buffer_current[0].length;n-this.source_block_start +this.queued_samples&&this.queue_length&&this.dbg_log("Not enough samples - should not happen during midway of playback");this.source_buffer_previous=this.source_buffer_current;this.source_buffer_current=this.queue_shift();var m=this.source_buffer_current[0].length;if(256>m){for(var n=this.queue_start,p=0;256>m&&pthis.queued_samples/this.source_samples_per_destination&&this.port.postMessage({type:"pump"})};k.prototype.queue_push=function(m){this.queue_length{URL.revokeObjectURL(g);this.node_processor=new AudioWorkletNode(this.audio_context,"dac-processor",{numberOfInputs:0,numberOfOutputs:1,outputChannelCount:[2],parameterData:{},processorOptions:{}});this.node_processor.port.postMessage({type:"sampling-rate",value:this.sampling_rate});this.node_processor.port.onmessage=f=>{switch(f.data.type){case "pump":this.pump()}};this.node_processor.connect(this.node_output)}); +this.mixer_connection=c.add_source(this.node_output,2);this.mixer_connection.set_gain_hidden(3);a.register("dac-send-data",function(f){this.queue(f)},this);a.register("dac-enable",function(){this.enabled=!0},this);a.register("dac-disable",function(){this.enabled=!1},this);a.register("dac-tell-sampling-rate",function(f){this.sampling_rate=f;this.node_processor&&this.node_processor.port.postMessage({type:"sampling-rate",value:f})},this)} +ob.prototype.queue=function(a){this.node_processor&&this.node_processor.port.postMessage({type:"queue",value:a},[a[0].buffer,a[1].buffer])};ob.prototype.pump=function(){this.enabled&&this.bus.send("dac-request-data")}; +function pb(a,b,c){this.bus=a;this.audio_context=b;this.enabled=!1;this.sampling_rate=22050;this.buffered_time=0;this.rate_ratio=1;this.node_lowpass=this.audio_context.createBiquadFilter();this.node_lowpass.type="lowpass";this.node_output=this.node_lowpass;this.mixer_connection=c.add_source(this.node_output,2);this.mixer_connection.set_gain_hidden(3);a.register("dac-send-data",function(d){this.queue(d)},this);a.register("dac-enable",function(){this.enabled=!0;this.pump()},this);a.register("dac-disable", +function(){this.enabled=!1},this);a.register("dac-tell-sampling-rate",function(d){this.sampling_rate=d;this.rate_ratio=Math.ceil(8E3/d);this.node_lowpass.frequency.setValueAtTime(d/2,this.audio_context.currentTime)},this)} +pb.prototype.queue=function(a){var b=a[0].length,c=b/this.sampling_rate;if(1this.pump(),1E3*b);a.start(this.buffered_time);this.buffered_time+=c;setTimeout(()=>this.pump(),0)};pb.prototype.pump=function(){this.enabled&&(.2l?void 0===this.update_timer&&(this.update_timer=setTimeout(()=>{this.update_timer=void 0;this.last_update=Date.now();this.render()},16-l)):(void 0!==this.update_timer&&(clearTimeout(this.update_timer),this.update_timer=void 0),this.last_update=k,this.render())};this.render=function(){a.value=this.text;this.text_new_line&&(this.text_new_line= +!1,a.scrollTop=1E9)};this.send_char=function(k){f.bus&&f.bus.send("serial0-input",k)}} +function ub(a,b){this.element=a;if(window.Terminal){var c=this.term=new window.Terminal({logLevel:"off"});c.write("This is the serial console. Whatever you type or paste here will be sent to COM1");var d=c.onData(function(e){for(let g=0;ga||(this.last_connect_attempt=Date.now(),this.socket=new WebSocket(this.url),this.socket.binaryType="arraybuffer",this.socket.onopen=this.handle_open.bind(this),this.socket.onmessage=this.handle_message.bind(this),this.socket.onclose=this.handle_close.bind(this),this.socket.onerror=this.handle_error.bind(this))}}; +vb.prototype.send=function(a){this.socket&&1===this.socket.readyState?this.socket.send(a):(this.send_queue.push(a),this.send_queue.length>2*this.send_queue_limit&&(this.send_queue=this.send_queue.slice(-this.send_queue_limit)),this.connect())};vb.prototype.change_proxy=function(a){this.url=a;this.socket&&(this.socket.onclose=function(){},this.socket.onerror=function(){},this.socket.close(),this.socket=void 0)};function Y(a){this.cpu_is_running=!1;this.cpu_exception_hook=function(){};var b=Xa.create();this.bus=b[0];this.emulator_bus=b[1];var c,d;const e=new WebAssembly.Table({element:"anyfunc",initial:1924});b={cpu_exception_hook:f=>this.cpu_exception_hook(f),run_hardware_timers:function(f,k){return c.run_hardware_timers(f,k)},cpu_event_halt:()=>{this.emulator_bus.send("cpu-event-halt")},abort:function(){},microtick:D.microtick,get_rand_int:function(){return r.get_rand_int()},apic_acknowledge_irq:function(){return c.devices.apic.acknowledge_irq()}, +io_port_read8:function(f){return c.io.port_read8(f)},io_port_read16:function(f){return c.io.port_read16(f)},io_port_read32:function(f){return c.io.port_read32(f)},io_port_write8:function(f,k){c.io.port_write8(f,k)},io_port_write16:function(f,k){c.io.port_write16(f,k)},io_port_write32:function(f,k){c.io.port_write32(f,k)},mmap_read8:function(f){return c.mmap_read8(f)},mmap_read16:function(f){return c.mmap_read16(f)},mmap_read32:function(f){return c.mmap_read32(f)},mmap_write8:function(f,k){c.mmap_write8(f, +k)},mmap_write16:function(f,k){c.mmap_write16(f,k)},mmap_write32:function(f,k){c.mmap_write32(f,k)},mmap_write64:function(f,k,l){c.mmap_write64(f,k,l)},mmap_write128:function(f,k,l,m,n){c.mmap_write128(f,k,l,m,n)},log_from_wasm:function(f,k){r.read_sized_string_from_mem(d,f,k)},console_log_from_wasm:function(f,k){f=r.read_sized_string_from_mem(d,f,k);console.error(f)},dbg_trace_from_wasm:function(){},codegen_finalize:(f,k,l,m,n)=>{c.codegen_finalize(f,k,l,m,n)},jit_clear_func:f=>c.jit_clear_func(f), +jit_clear_all_funcs:()=>c.jit_clear_all_funcs(),__indirect_function_table:e};let g=a.wasm_fn;g||(g=f=>new Promise(k=>{let l="v86.wasm",m="v86-fallback.wasm";if(a.wasm_path){l=a.wasm_path;const n=l.lastIndexOf("/");m=(-1===n?"":l.substr(0,n))+"/"+m}else"undefined"===typeof window&&"string"===typeof __dirname?(l=__dirname+"/"+l,m=__dirname+"/"+m):(l="build/"+l,m="build/"+m);r.load_file(l,{done:async n=>{try{const {instance:p}=await WebAssembly.instantiate(n,f);this.wasm_source=n;k(p.exports)}catch(p){r.load_file(m, +{done:async t=>{const {instance:q}=await WebAssembly.instantiate(t,f);this.wasm_source=t;k(q.exports)}})}},progress:n=>{this.emulator_bus.send("download-progress",{file_index:0,file_count:1,file_name:l,lengthComputable:n.lengthComputable,total:n.total,loaded:n.loaded})}})}));g({env:b}).then(f=>{d=f.memory;f.rust_init();f=this.v86=new D(this.emulator_bus,{exports:f,wasm_table:e});c=f.cpu;this.continue_init(f,a)});this.zstd_worker=null;this.zstd_worker_request_id=0} +Y.prototype.continue_init=async function(a,b){function c(t,q){switch(t){case "hda":e.hda=this.disk_images.hda=q;break;case "hdb":e.hdb=this.disk_images.hdb=q;break;case "cdrom":e.cdrom=this.disk_images.cdrom=q;break;case "fda":e.fda=this.disk_images.fda=q;break;case "fdb":e.fdb=this.disk_images.fdb=q;break;case "multiboot":e.multiboot=this.disk_images.multiboot=q.buffer;break;case "bzimage":e.bzimage=this.disk_images.bzimage=q.buffer;break;case "initrd":e.initrd=this.disk_images.initrd=q.buffer;break; +case "bios":e.bios=q.buffer;break;case "vga_bios":e.vga_bios=q.buffer;break;case "initial_state":e.initial_state=q.buffer;break;case "fs9p_json":e.fs9p_json=q}}async function d(){if(e.fs9p&&e.fs9p_json&&(e.initial_state||e.fs9p.load_from_json(e.fs9p_json),b.bzimage_initrd_from_filesystem)){const {bzimage_path:t,initrd_path:q}=this.get_bzimage_initrd_from_filesystem(e.fs9p),[z,w]=await Promise.all([e.fs9p.read_file(q),e.fs9p.read_file(t)]);c.call(this,"initrd",new r.SyncBuffer(z.buffer));c.call(this, +"bzimage",new r.SyncBuffer(w.buffer))}this.serial_adapter&&this.serial_adapter.show&&this.serial_adapter.show();this.bus.send("cpu-init",e);e.initial_state&&(a.restore_state(e.initial_state),e.initial_state=void 0);b.autostart&&this.bus.send("cpu-run");this.emulator_bus.send("emulator-loaded")}this.bus.register("emulator-stopped",function(){this.cpu_is_running=!1},this);this.bus.register("emulator-started",function(){this.cpu_is_running=!0},this);var e={};this.disk_images={fda:void 0,fdb:void 0,hda:void 0, +hdb:void 0,cdrom:void 0};var g=b.boot_order?b.boot_order:b.fda?801:b.hda?786:291;e.acpi=b.acpi;e.disable_jit=b.disable_jit;e.load_devices=!0;e.log_level=b.log_level;e.memory_size=b.memory_size||67108864;e.vga_memory_size=b.vga_memory_size||8388608;e.boot_order=g;e.fastboot=b.fastboot||!1;e.fda=void 0;e.fdb=void 0;e.uart1=b.uart1;e.uart2=b.uart2;e.uart3=b.uart3;e.cmdline=b.cmdline;e.preserve_mac_from_state_image=b.preserve_mac_from_state_image;e.mac_address_translation=b.mac_address_translation;e.cpuid_level= +b.cpuid_level;e.virtio_console=b.virtio_console;b.network_adapter?this.network_adapter=b.network_adapter(this.bus):b.network_relay_url&&(this.network_adapter=new vb(b.network_relay_url,this.bus));e.enable_ne2k=!0;b.disable_keyboard||(this.keyboard_adapter=new lb(this.bus));b.disable_mouse||(this.mouse_adapter=new mb(this.bus,b.screen_container));b.screen_container?this.screen_adapter=new ba(b.screen_container,this.bus):b.screen_dummy&&(this.screen_adapter=new wb(this.bus));b.serial_container&&(this.serial_adapter= +new tb(b.serial_container,this.bus));b.serial_container_xtermjs&&(this.serial_adapter=new ub(b.serial_container_xtermjs,this.bus));b.disable_speaker||(this.speaker_adapter=new nb(this.bus));var f=[];g=(t,q)=>{if(q)if(q.get&&q.set&&q.load)f.push({name:t,loadable:q});else{if("bios"===t||"vga_bios"===t||"initial_state"===t||"multiboot"===t||"bzimage"===t||"initrd"===t)q.async=!1;q.url&&!q.async?f.push({name:t,url:q.url,size:q.size}):f.push({name:t,loadable:r.buffer_from_object(q,this.zstd_decompress_worker.bind(this))})}}; +b.state&&console.warn("Warning: Unknown option 'state'. Did you mean 'initial_state'?");g("bios",b.bios);g("vga_bios",b.vga_bios);g("cdrom",b.cdrom);g("hda",b.hda);g("hdb",b.hdb);g("fda",b.fda);g("fdb",b.fdb);g("initial_state",b.initial_state);g("multiboot",b.multiboot);g("bzimage",b.bzimage);g("initrd",b.initrd);if(b.filesystem){g=b.filesystem.basefs;var k=b.filesystem.baseurl;let t=new xb;k&&(t=new yb(t,k));e.fs9p=this.fs9p=new Z(t);if(g){if("object"===typeof g){var l=g.size;g=g.url}f.push({name:"fs9p_json", +url:g,size:l,as_json:!0})}}var m=this,n=f.length,p=function(t){if(t===n)setTimeout(d.bind(this),0);else{var q=f[t];q.loadable?(q.loadable.onload=function(){c.call(this,q.name,q.loadable);p(t+1)}.bind(this),q.loadable.load()):r.load_file(q.url,{done:function(z){q.url.endsWith(".zst")&&"initial_state"!==q.name&&(z=this.zstd_decompress(q.size,new Uint8Array(z)));c.call(this,q.name,q.as_json?z:new r.SyncBuffer(z));p(t+1)}.bind(this),progress:function(z){200===z.target.status?m.emulator_bus.send("download-progress", +{file_index:t,file_count:n,file_name:q.url,lengthComputable:z.lengthComputable,total:z.total||q.size,loaded:z.loaded}):m.emulator_bus.send("download-error",{file_index:t,file_count:n,file_name:q.url,request:z.target})},as_json:q.as_json})}}.bind(this);p(0)}; +Y.prototype.zstd_decompress=function(a,b){const c=this.v86.cpu;this.zstd_context=c.zstd_create_ctx(b.length);(new Uint8Array(c.wasm_memory.buffer)).set(b,c.zstd_get_src_ptr(this.zstd_context));b=c.zstd_read(this.zstd_context,a);const d=c.wasm_memory.buffer.slice(b,b+a);c.zstd_read_free(b,a);c.zstd_free_ctx(this.zstd_context);this.zstd_context=null;return d}; +Y.prototype.zstd_decompress_worker=async function(a,b){if(!this.zstd_worker){const c=URL.createObjectURL(new Blob(["("+function(){let d;globalThis.onmessage=function(e){if(d){var {src:g,decompressed_size:f,id:k}=e.data;e=d.exports;var l=e.zstd_create_ctx(g.length);(new Uint8Array(e.memory.buffer)).set(g,e.zstd_get_src_ptr(l));var m=e.zstd_read(l,f),n=e.memory.buffer.slice(m,m+f);e.zstd_read_free(m,f);e.zstd_free_ctx(l);postMessage({result:n,id:k},[n])}else l=Object.fromEntries("cpu_exception_hook run_hardware_timers cpu_event_halt microtick get_rand_int apic_acknowledge_irq io_port_read8 io_port_read16 io_port_read32 io_port_write8 io_port_write16 io_port_write32 mmap_read8 mmap_read16 mmap_read32 mmap_write8 mmap_write16 mmap_write32 mmap_write64 mmap_write128 codegen_finalize jit_clear_func jit_clear_all_funcs".split(" ").map(p=> +[p,()=>console.error("zstd worker unexpectedly called "+p)])),l.__indirect_function_table=new WebAssembly.Table({element:"anyfunc",initial:1024}),l.abort=()=>{throw Error("zstd worker aborted");},l.log_from_wasm=l.console_log_from_wasm=(p,t)=>{console.log(String.fromCharCode(...(new Uint8Array(d.exports.memory.buffer,p,t))))},l.dbg_trace_from_wasm=()=>console.trace(),d=new WebAssembly.Instance(new WebAssembly.Module(e.data),{env:l})}}.toString()+")()"],{type:"text/javascript"}));this.zstd_worker= +new Worker(c);URL.revokeObjectURL(c);this.zstd_worker.postMessage(this.wasm_source,[this.wasm_source])}return new Promise(c=>{const d=this.zstd_worker_request_id++,e=async g=>{g.data.id===d&&(this.zstd_worker.removeEventListener("message",e),c(g.data.result))};this.zstd_worker.addEventListener("message",e);this.zstd_worker.postMessage({src:b,decompressed_size:a,id:d},[b.buffer])})}; +Y.prototype.get_bzimage_initrd_from_filesystem=function(a){const b=(a.read_dir("/")||[]).map(e=>"/"+e);a=(a.read_dir("/boot/")||[]).map(e=>"/boot/"+e);let c,d;for(let e of[].concat(b,a)){const g=/old/i.test(e)||/fallback/i.test(e),f=/vmlinuz/i.test(e)||/bzimage/i.test(e),k=/initrd/i.test(e)||/initramfs/i.test(e);!f||d&&g||(d=e);!k||c&&g||(c=e)}c&&d||(console.log("Failed to find bzimage or initrd in filesystem. Files:"),console.log(b.join(" ")),console.log(a.join(" ")));return{initrd_path:c,bzimage_path:d}}; +Y.prototype.run=async function(){this.bus.send("cpu-run")};F.exportProperty(Y.prototype,"run",Y.prototype.run);Y.prototype.stop=async function(){this.cpu_is_running&&await new Promise(a=>{const b=()=>{this.remove_listener("emulator-stopped",b);a()};this.add_listener("emulator-stopped",b);this.bus.send("cpu-stop")})};F.exportProperty(Y.prototype,"stop",Y.prototype.stop); +Y.prototype.destroy=async function(){await this.stop();this.v86.destroy();this.keyboard_adapter&&this.keyboard_adapter.destroy();this.network_adapter&&this.network_adapter.destroy();this.mouse_adapter&&this.mouse_adapter.destroy();this.screen_adapter&&this.screen_adapter.destroy();this.serial_adapter&&this.serial_adapter.destroy();this.speaker_adapter&&this.speaker_adapter.destroy()};F.exportProperty(Y.prototype,"destroy",Y.prototype.destroy);Y.prototype.restart=function(){this.bus.send("cpu-restart")}; +F.exportProperty(Y.prototype,"restart",Y.prototype.restart);Y.prototype.add_listener=function(a,b){this.bus.register(a,b,this)};F.exportProperty(Y.prototype,"add_listener",Y.prototype.add_listener);Y.prototype.remove_listener=function(a,b){this.bus.unregister(a,b)};F.exportProperty(Y.prototype,"remove_listener",Y.prototype.remove_listener);Y.prototype.restore_state=async function(a){this.v86.restore_state(a)};F.exportProperty(Y.prototype,"restore_state",Y.prototype.restore_state); +Y.prototype.save_state=async function(){return this.v86.save_state()};F.exportProperty(Y.prototype,"save_state",Y.prototype.save_state);Y.prototype.get_instruction_counter=function(){return this.v86?this.v86.cpu.instruction_counter[0]>>>0:0};F.exportProperty(Y.prototype,"get_instruction_counter",Y.prototype.get_instruction_counter);Y.prototype.is_running=function(){return this.cpu_is_running};F.exportProperty(Y.prototype,"is_running",Y.prototype.is_running); +Y.prototype.set_fda=async function(a){if(a.url&&!a.async)r.load_file(a.url,{done:b=>{this.v86.cpu.devices.fdc.set_fda(new r.SyncBuffer(b))}});else{const b=r.buffer_from_object(a,this.zstd_decompress_worker.bind(this));b.onload=()=>{this.v86.cpu.devices.fdc.set_fda(b)};await b.load()}};F.exportProperty(Y.prototype,"set_fda",Y.prototype.set_fda);Y.prototype.eject_fda=function(){this.v86.cpu.devices.fdc.eject_fda()};F.exportProperty(Y.prototype,"eject_fda",Y.prototype.eject_fda); +Y.prototype.keyboard_send_scancodes=function(a){for(var b=0;b{const k=this.fs9p.Mount(a,g);d&&(-2===k?d(new zb):-17===k?d(new Db):0>k?d(Error("Failed to mount. Error number: "+-k)):d(null))};b?g.load_from_json(c,()=>f()):f()};F.exportProperty(Y.prototype,"mount_fs",Y.prototype.mount_fs); +Y.prototype.create_file=async function(a,b){var c=this.fs9p;if(c){var d=a.split("/");d=d[d.length-1];a=c.SearchPath(a).parentid;if(""!==d&&-1!==a)await c.CreateBinaryFile(d,a,b);else return Promise.reject(new zb)}};F.exportProperty(Y.prototype,"create_file",Y.prototype.create_file);Y.prototype.read_file=async function(a){var b=this.fs9p;if(b)return(a=await b.read_file(a))?a:Promise.reject(new zb)};F.exportProperty(Y.prototype,"read_file",Y.prototype.read_file); +Y.prototype.automatically=function(a){const b=c=>{const d=c[0];if(d){var e=c.slice(1);if(d.sleep)setTimeout(()=>b(e),1E3*d.sleep);else if(d.vga_text){const g=this.screen_adapter.get_text_screen();for(let f of g)if(f.includes(d.vga_text)){b(e);return}setTimeout(()=>b(c),1E3)}else d.keyboard_send?(d.keyboard_send instanceof Array?this.keyboard_send_scancodes(d.keyboard_send):this.keyboard_send_text(d.keyboard_send),b(e)):d.call&&(d.call(),b(e))}};b(a)}; +Y.prototype.read_memory=function(a,b){return this.v86.cpu.read_blob(a,b)};Y.prototype.write_memory=function(a,b){this.v86.cpu.write_blob(a,b)};Y.prototype.set_serial_container_xtermjs=function(a){this.serial_adapter&&this.serial_adapter.destroy&&this.serial_adapter.destroy();this.serial_adapter=new ub(a,this.bus);this.serial_adapter.show()};function Db(a){this.message=a||"File already exists"}Db.prototype=Error.prototype;function zb(a){this.message=a||"File not found"}zb.prototype=Error.prototype; +"undefined"!==typeof window?(window.V86Starter=Y,window.V86=Y):"undefined"!==typeof module&&"undefined"!==typeof module.exports?(module.exports.V86Starter=Y,module.exports.V86=Y):"function"===typeof importScripts&&(self.V86Starter=Y,self.V86=Y);var Eb={Connector:function(a){this.listeners={};this.pair=a;a.addEventListener("message",function(b){b=b.data;for(var c=this.listeners[b[0]],d=0;d>20)+"m\n";b=b+"Config:\nJIT_DISABLED="+(a.wm.exports.get_jit_config(0)+"\n");b+="MAX_PAGES="+a.wm.exports.get_jit_config(1)+"\n";b+="JIT_USE_LOOP_SAFETY="+!!a.wm.exports.get_jit_config(2)+"\n";return b+="MAX_EXTRA_BASIC_BLOCKS="+a.wm.exports.get_jit_config(3)+"\n"},print_instruction_counts:function(a){return[Fb.print_instruction_counts_offset(a, +!1,!1,!1,!1),Fb.print_instruction_counts_offset(a,!0,!1,!1,!1),Fb.print_instruction_counts_offset(a,!1,!0,!1,!1),Fb.print_instruction_counts_offset(a,!1,!1,!0,!1),Fb.print_instruction_counts_offset(a,!1,!1,!1,!0)].join("\n\n")},print_instruction_counts_offset:function(a,b,c,d,e){let g="";var f=[],k=b?"compiled":c?"jit exit":d?"unguarded register":e?"wasm size":"executed";for(let n=0;256>n;n++)for(let p=0;8>p;p++)for(let t of[!1,!0]){var l=a.wm.exports.get_opstats_buffer(b,c,d,e,n,!1,t,p);f.push({opcode:n, +count:l,is_mem:t,fixed_g:p});l=a.wm.exports.get_opstats_buffer(b,c,d,e,n,!0,t,p);f.push({opcode:3840|n,count:l,is_mem:t,fixed_g:p})}a=0;b=new Set([38,46,54,62,100,101,102,103,240,242,243]);for(let {count:n,opcode:p}of f)b.has(p)||(a+=n);if(0===a)return"";c=new Uint32Array(256);b=new Uint32Array(256);for(let {opcode:n,count:p}of f)3840==(n&65280)?b[n&255]+=p:c[n&255]+=p;g=g+"------------------\nTotal: "+(a+"\n");const m=1E7Math.round(n/m)));d=String(d).length; +g+=`Instruction counts ${k} (in ${m}):\n`;for(e=0;256>e;e++)g+=e.toString(16).padStart(2,"0")+":"+r.pads(Math.round(c[e]/m),d),g=15==e%16?g+"\n":g+" ";g=g+"\n"+`Instruction counts ${k} (0f, in ${m}):\n`;for(k=0;256>k;k++)g+=(k&255).toString(16).padStart(2,"0")+":"+r.pads(Math.round(b[k]/m),d),g=15==k%16?g+"\n":g+" ";g+="\n";f=f.filter(({count:n})=>n).sort(({count:n},{count:p})=>p-n);for(let {opcode:n,is_mem:p,fixed_g:t,count:q}of f.slice(0,200))f=n.toString(16)+"_"+t+(p?"_m":"_r"),g+=f+":"+(q/a*100).toFixed(2)+ +" ";return g+"\n"}};"undefined"!==typeof module&&"undefined"!==typeof module.exports&&(module.exports.print_stats=Fb);function xb(){this.filedata=new Map}xb.prototype.read=async function(a,b,c){return(a=this.filedata.get(a))?a.subarray(b,b+c):null};xb.prototype.cache=async function(a,b){this.filedata.set(a,b)};xb.prototype.uncache=function(a){this.filedata.delete(a)};function yb(a,b){this.storage=a;this.baseurl=b}yb.prototype.load_from_server=function(a){return new Promise(b=>{r.load_file(this.baseurl+a,{done:async c=>{c=new Uint8Array(c);await this.cache(a,c);b(c)}})})}; +yb.prototype.read=async function(a,b,c){const d=await this.storage.read(a,b,c);return d?d:(await this.load_from_server(a)).subarray(b,b+c)};yb.prototype.cache=async function(a,b){return await this.storage.cache(a,b)};yb.prototype.uncache=function(a){this.storage.uncache(a)}; +"undefined"!==typeof window?(window.MemoryFileStorage=xb,window.ServerFileStorageWrapper=yb):"undefined"!==typeof module&&"undefined"!==typeof module.exports?(module.exports.MemoryFileStorage=xb,module.exports.ServerFileStorageWrapper=yb):"function"===typeof importScripts&&(self.MemoryFileStorage=xb,self.ServerFileStorageWrapper=yb);var ha=16384,ia=4;function Z(a,b){this.inodes=[];this.events=[];this.storage=a;this.qidcounter=b||{last_qidnumber:0};this.inodedata={};this.total_size=274877906944;this.used_size=0;this.mounts=[];this.CreateDirectory("",-1)}Z.prototype.get_state=function(){let a=[];a[0]=this.inodes;a[1]=this.qidcounter.last_qidnumber;a[2]=[];for(const [b,c]of Object.entries(this.inodedata))0===(this.inodes[b].mode&ha)&&a[2].push([b,c]);a[3]=this.total_size;a[4]=this.used_size;return a=a.concat(this.mounts)}; +Z.prototype.set_state=function(a){this.inodes=a[0].map(b=>{const c=new Gb(0);c.set_state(b);return c});this.qidcounter.last_qidnumber=a[1];this.inodedata={};for(let [b,c]of a[2])c.buffer.byteLength!==c.byteLength&&(c=c.slice()),this.inodedata[b]=c;this.total_size=a[3];this.used_size=a[4];this.mounts=a.slice(5)};Z.prototype.AddEvent=function(a,b){var c=this.inodes[a];0==c.status||2==c.status?b():this.is_forwarder(c)?this.follow_fs(c).AddEvent(c.foreign_id,b):this.events.push({id:a,OnEvent:b})}; +Z.prototype.HandleEvent=function(a){var b=this.inodes[a];this.is_forwarder(b)&&this.follow_fs(b).HandleEvent(b.foreign_id);b=[];for(var c=0;c>8;this.qid.version=a[11];this.qid.path=a[12];this.nlinks=a[13]}; +Z.prototype.divert=function(a,b){const c=this.Search(a,b),d=this.inodes[c],e=new Gb(-1);this.IsDirectory(c);Object.assign(e,d);const g=this.inodes.length;this.inodes.push(e);e.fid=g;this.is_forwarder(d)&&this.mounts[d.mount_id].backtrack.set(d.foreign_id,g);this.should_be_linked(d)&&(this.unlink_from_dir(a,b),this.link_under_dir(a,g,b));if(this.IsDirectory(c)&&!this.is_forwarder(d))for(const [f,k]of e.direntries)"."!==f&&".."!==f&&this.IsDirectory(k)&&this.inodes[k].direntries.set("..",g);this.inodedata[g]= +this.inodedata[c];delete this.inodedata[c];d.direntries=new Map;d.nlinks=0;return g};Z.prototype.copy_inode=function(a,b){Object.assign(b,a,{fid:b.fid,direntries:b.direntries,nlinks:b.nlinks})};Z.prototype.CreateInode=function(){const a=Math.round(Date.now()/1E3),b=new Gb(++this.qidcounter.last_qidnumber);b.atime=b.ctime=b.mtime=a;return b}; +Z.prototype.CreateDirectory=function(a,b){var c=this.inodes[b];if(0<=b&&this.is_forwarder(c))return b=c.foreign_id,a=this.follow_fs(c).CreateDirectory(a,b),this.create_forwarder(c.mount_id,a);c=this.CreateInode();c.mode=511|ha;0<=b&&(c.uid=this.inodes[b].uid,c.gid=this.inodes[b].gid,c.mode=this.inodes[b].mode&511|ha);c.qid.type=ha>>8;this.PushInode(c,b,a);this.NotifyListeners(this.inodes.length-1,"newdir");return this.inodes.length-1}; +Z.prototype.CreateFile=function(a,b){var c=this.inodes[b];if(this.is_forwarder(c))return b=c.foreign_id,a=this.follow_fs(c).CreateFile(a,b),this.create_forwarder(c.mount_id,a);c=this.CreateInode();c.uid=this.inodes[b].uid;c.gid=this.inodes[b].gid;c.qid.type=128;c.mode=this.inodes[b].mode&438|32768;this.PushInode(c,b,a);this.NotifyListeners(this.inodes.length-1,"newfile");return this.inodes.length-1}; +Z.prototype.CreateNode=function(a,b,c,d){var e=this.inodes[b];if(this.is_forwarder(e))return b=e.foreign_id,a=this.follow_fs(e).CreateNode(a,b,c,d),this.create_forwarder(e.mount_id,a);e=this.CreateInode();e.major=c;e.minor=d;e.uid=this.inodes[b].uid;e.gid=this.inodes[b].gid;e.qid.type=192;e.mode=this.inodes[b].mode&438;this.PushInode(e,b,a);return this.inodes.length-1}; +Z.prototype.CreateSymlink=function(a,b,c){var d=this.inodes[b];if(this.is_forwarder(d))return b=d.foreign_id,a=this.follow_fs(d).CreateSymlink(a,b,c),this.create_forwarder(d.mount_id,a);d=this.CreateInode();d.uid=this.inodes[b].uid;d.gid=this.inodes[b].gid;d.qid.type=160;d.symlink=c;d.mode=40960;this.PushInode(d,b,a);return this.inodes.length-1}; +Z.prototype.CreateTextFile=async function(a,b,c){var d=this.inodes[b];if(this.is_forwarder(d))return b=d.foreign_id,c=await this.follow_fs(d).CreateTextFile(a,b,c),this.create_forwarder(d.mount_id,c);d=this.CreateFile(a,b);b=this.inodes[d];a=new Uint8Array(c.length);b.size=c.length;for(b=0;bf)return f}var k=this.inodes[e],l=this.inodes[a];f=this.inodes[c];if(this.is_forwarder(l)||this.is_forwarder(f))if(this.is_forwarder(l)&&l.mount_id===f.mount_id){if(a=await this.follow_fs(l).Rename(l.foreign_id,b,f.foreign_id,d),0>a)return a}else{if(this.is_a_root(e)||!this.IsDirectory(e)&&1f)return f;await this.DeleteData(l);a=this.Unlink(a,b);if(0>a)return a}else this.unlink_from_dir(a,b),this.link_under_dir(c,e,d),k.qid.version++;this.NotifyListeners(e,"rename",{oldpath:g});return 0}; +Z.prototype.Write=async function(a,b,c,d){this.NotifyListeners(a,"write");var e=this.inodes[a];if(this.is_forwarder(e))a=e.foreign_id,await this.follow_fs(e).Write(a,b,c,d);else{var g=await this.get_buffer(a);!g||g.lengthb.nlinks&&y.Debug("Error in filesystem: negative nlinks="+b.nlinks+" at id ="+a);if(this.IsDirectory(a)){b=this.GetInode(a);this.IsDirectory(a)&&0>this.GetParent(a)&&y.Debug("Error in filesystem: negative parent id "+a);for(const [c,d]of b.direntries){0===c.length&&y.Debug("Error in filesystem: inode with no name and id "+d);for(const e of c)32>e&&y.Debug("Error in filesystem: Unallowed char in filename")}}}}; +Z.prototype.FillDirectory=function(a){var b=this.inodes[a];if(this.is_forwarder(b))this.follow_fs(b).FillDirectory(b.foreign_id);else{var c=0;for(const d of b.direntries.keys())c+=24+Ib.UTF8Length(d);a=this.inodedata[a]=new Uint8Array(c);b.size=c;c=0;for(const [d,e]of b.direntries)b=this.GetInode(e),c+=v.Marshall(["Q","d","b","s"],[b.qid,c+13+8+1+2+Ib.UTF8Length(d),b.mode>>12,d],a,c)}}; +Z.prototype.RoundToDirentry=function(a,b){a=this.inodedata[a];if(b>=a.length)return a.length;let c=0;for(;;){const d=v.Unmarshall(["Q","d"],a,{offset:c})[1];if(d>b)break;c=d}return c};Z.prototype.IsDirectory=function(a){a=this.inodes[a];return this.is_forwarder(a)?this.follow_fs(a).IsDirectory(a.foreign_id):(a.mode&61440)===ha}; +Z.prototype.IsEmpty=function(a){a=this.inodes[a];if(this.is_forwarder(a))return this.follow_fs(a).IsDirectory(a.foreign_id);for(const b of a.direntries.keys())if("."!==b&&".."!==b)return!1;return!0};Z.prototype.GetChildren=function(a){this.IsDirectory(a);a=this.inodes[a];if(this.is_forwarder(a))return this.follow_fs(a).GetChildren(a.foreign_id);const b=[];for(const c of a.direntries.keys())"."!==c&&".."!==c&&b.push(c);return b}; +Z.prototype.GetParent=function(a){this.IsDirectory(a);a=this.inodes[a];if(this.should_be_linked(a))return a.direntries.get("..");const b=this.follow_fs(a).GetParent(a.foreign_id);return this.get_forwarder(a.mount_id,b)}; +Z.prototype.PrepareCAPs=function(a){a=this.GetInode(a);if(a.caps)return a.caps.length;a.caps=new Uint8Array(20);a.caps[0]=0;a.caps[1]=0;a.caps[2]=0;a.caps[3]=2;a.caps[4]=255;a.caps[5]=255;a.caps[6]=255;a.caps[7]=255;a.caps[8]=255;a.caps[9]=255;a.caps[10]=255;a.caps[11]=255;a.caps[12]=63;a.caps[13]=0;a.caps[14]=0;a.caps[15]=0;a.caps[16]=63;a.caps[17]=0;a.caps[18]=0;a.caps[19]=0;return a.caps.length};function Jb(a){this.fs=a;this.backtrack=new Map} +Jb.prototype.get_state=function(){const a=[];a[0]=this.fs;a[1]=[...this.backtrack];return a};Jb.prototype.set_state=function(a){this.fs=a[0];this.backtrack=new Map(a[1])};Z.prototype.set_forwarder=function(a,b,c){const d=this.inodes[a];this.is_forwarder(d)&&this.mounts[d.mount_id].backtrack.delete(d.foreign_id);d.status=5;d.mount_id=b;d.foreign_id=c;this.mounts[b].backtrack.set(c,a)}; +Z.prototype.create_forwarder=function(a,b){const c=this.CreateInode(),d=this.inodes.length;this.inodes.push(c);c.fid=d;this.set_forwarder(d,a,b);return d};Z.prototype.is_forwarder=function(a){return 5===a.status};Z.prototype.is_a_root=function(a){return 0===this.GetInode(a).fid};Z.prototype.get_forwarder=function(a,b){const c=this.mounts[a].backtrack.get(b);return void 0===c?this.create_forwarder(a,b):c};Z.prototype.delete_forwarder=function(a){this.is_forwarder(a);a.status=-1;this.mounts[a.mount_id].backtrack.delete(a.foreign_id)}; +Z.prototype.follow_fs=function(a){const b=this.mounts[a.mount_id];this.is_forwarder(a);return b.fs};Z.prototype.Mount=function(a,b){a=this.SearchPath(a);if(-1===a.parentid)return-2;if(-1!==a.id)return-17;if(a.forward_path){var c=this.inodes[a.parentid];b=this.follow_fs(c).Mount(a.forward_path,b);return 0>b?b:this.get_forwarder(c.mount_id,b)}c=this.mounts.length;this.mounts.push(new Jb(b));b=this.create_forwarder(c,0);this.link_under_dir(a.parentid,b,a.name);return b}; +function Hb(){this.type=2;this.start=0;this.length=Infinity;this.proc_id=-1;this.client_id=""}Hb.prototype.get_state=function(){const a=[];a[0]=this.type;a[1]=this.start;a[2]=Infinity===this.length?0:this.length;a[3]=this.proc_id;a[4]=this.client_id;return a};Hb.prototype.set_state=function(a){this.type=a[0];this.start=a[1];this.length=0===a[2]?Infinity:a[2];this.proc_id=a[3];this.client_id=a[4]};Hb.prototype.clone=function(){const a=new Hb;a.set_state(this.get_state());return a}; +Hb.prototype.conflicts_with=function(a){return this.proc_id===a.proc_id&&this.client_id===a.client_id||2===this.type||2===a.type||1!==this.type&&1!==a.type||this.start+this.length<=a.start||a.start+a.length<=this.start?!1:!0};Hb.prototype.is_alike=function(a){return a.proc_id===this.proc_id&&a.client_id===this.client_id&&a.type===this.type};Hb.prototype.may_merge_after=function(a){return this.is_alike(a)&&a.start+a.length===this.start}; +Z.prototype.DescribeLock=function(a,b,c,d,e){const g=new Hb;g.type=a;g.start=b;g.length=c;g.proc_id=d;g.client_id=e;return g};Z.prototype.GetLock=function(a,b){a=this.inodes[a];if(this.is_forwarder(a)){var c=a.foreign_id;return this.follow_fs(a).GetLock(c,b)}for(c of a.locks)if(b.conflicts_with(c))return c.clone();return null}; +Z.prototype.Lock=function(a,b,c){const d=this.inodes[a];if(this.is_forwarder(d))return a=d.foreign_id,this.follow_fs(d).Lock(a,b,c);b=b.clone();if(2!==b.type&&this.GetLock(a,b))return 1;for(c=0;c=g&&0=g&&(d.locks.splice(c,1),c--)}if(2!==b.type){c=b;a=!1;for(e=0;e"."!==b&&".."!==b)};Z.prototype.read_file=function(a){a=this.SearchPath(a);if(-1===a.id)return Promise.resolve(null);const b=this.GetInode(a.id);return this.Read(a.id,0,b.size)};var y={Debug:function(a){[].slice.apply(arguments).join(" ")},Abort:function(){}};var v={Marshall:function(a,b,c,d){for(var e,g=0,f=0;f>8&255;c[d++]=e>>16&255;c[d++]=e>>24&255;g+=4;break;case "d":c[d++]=e&255;c[d++]=e>>8&255;c[d++]=e>>16&255;c[d++]=e>>24&255;c[d++]=0;c[d++]=0;c[d++]=0;c[d++]=0;g+=8;break;case "h":c[d++]=e&255;c[d++]=e>>8;g+=2;break;case "b":c[d++]=e;g+=1;break;case "s":var k=d,l=0;c[d++]=0;c[d++]=0;g+=2;for(var m of e)Kb(m.charCodeAt(0)).forEach(function(n){c[d++]=n;g+=1;l++});c[k+0]=l&255;c[k+1]= +l>>8&255;break;case "Q":v.Marshall(["b","w","d"],[e.type,e.version,e.path],c,d);d+=13;g+=13;break;default:y.Debug("Marshall: Unknown type="+a[f])}return g},Unmarshall:function(a,b,c){let d=c.offset;for(var e=[],g=0;g>>0;e.push(f);break;case "d":f=b[d++];f+=b[d++]<<8;f+=b[d++]<<16;f+=b[d++]<<24>>>0;d+=4;e.push(f);break;case "h":f=b[d++];e.push(f+(b[d++]<<8));break;case "b":e.push(b[d++]);break;case "s":f=b[d++]; +f+=b[d++]<<8;for(var k="",l=new Lb,m=0;m + * bios: { + * buffer: document.all.hd_image.files[0] + * } + * // start with empty hard disk + * hda: { + * buffer: new ArrayBuffer(16 * 1024 * 1024) + * } + * ``` + * + * @param {{ + disable_mouse: (boolean|undefined), + disable_keyboard: (boolean|undefined), + wasm_fn: (Function|undefined), + }} options + * @constructor + */ +function V86(options) +{ + //var worker = new Worker("src/browser/worker.js"); + //var adapter_bus = this.bus = WorkerBus.init(worker); + + this.cpu_is_running = false; + this.cpu_exception_hook = function(n) {}; + + const bus = Bus.create(); + const adapter_bus = this.bus = bus[0]; + this.emulator_bus = bus[1]; + + var cpu; + var wasm_memory; + + const wasm_table = new WebAssembly.Table({ element: "anyfunc", initial: WASM_TABLE_SIZE + WASM_TABLE_OFFSET }); + + const wasm_shared_funcs = { + "cpu_exception_hook": n => this.cpu_exception_hook(n), + "run_hardware_timers": function(a, t) { return cpu.run_hardware_timers(a, t); }, + "cpu_event_halt": () => { this.emulator_bus.send("cpu-event-halt"); }, + "abort": function() { dbg_assert(false); }, + "microtick": v86.microtick, + "get_rand_int": function() { return v86util.get_rand_int(); }, + "apic_acknowledge_irq": function() { return cpu.devices.apic.acknowledge_irq(); }, + + "io_port_read8": function(addr) { return cpu.io.port_read8(addr); }, + "io_port_read16": function(addr) { return cpu.io.port_read16(addr); }, + "io_port_read32": function(addr) { return cpu.io.port_read32(addr); }, + "io_port_write8": function(addr, value) { cpu.io.port_write8(addr, value); }, + "io_port_write16": function(addr, value) { cpu.io.port_write16(addr, value); }, + "io_port_write32": function(addr, value) { cpu.io.port_write32(addr, value); }, + + "mmap_read8": function(addr) { return cpu.mmap_read8(addr); }, + "mmap_read16": function(addr) { return cpu.mmap_read16(addr); }, + "mmap_read32": function(addr) { return cpu.mmap_read32(addr); }, + "mmap_write8": function(addr, value) { cpu.mmap_write8(addr, value); }, + "mmap_write16": function(addr, value) { cpu.mmap_write16(addr, value); }, + "mmap_write32": function(addr, value) { cpu.mmap_write32(addr, value); }, + "mmap_write64": function(addr, value0, value1) { cpu.mmap_write64(addr, value0, value1); }, + "mmap_write128": function(addr, value0, value1, value2, value3) { + cpu.mmap_write128(addr, value0, value1, value2, value3); + }, + + "log_from_wasm": function(offset, len) { + const str = v86util.read_sized_string_from_mem(wasm_memory, offset, len); + dbg_log(str, LOG_CPU); + }, + "console_log_from_wasm": function(offset, len) { + const str = v86util.read_sized_string_from_mem(wasm_memory, offset, len); + console.error(str); + }, + "dbg_trace_from_wasm": function() { + dbg_trace(LOG_CPU); + }, + + "codegen_finalize": (wasm_table_index, start, state_flags, ptr, len) => { + cpu.codegen_finalize(wasm_table_index, start, state_flags, ptr, len); + }, + "jit_clear_func": (wasm_table_index) => cpu.jit_clear_func(wasm_table_index), + "jit_clear_all_funcs": () => cpu.jit_clear_all_funcs(), + + "__indirect_function_table": wasm_table, + }; + + let wasm_fn = options.wasm_fn; + + if(!wasm_fn) + { + wasm_fn = env => + { + return new Promise(resolve => { + let v86_bin = DEBUG ? "v86-debug.wasm" : "v86.wasm"; + let v86_bin_fallback = "v86-fallback.wasm"; + + if(options.wasm_path) + { + v86_bin = options.wasm_path; + const slash = v86_bin.lastIndexOf("/"); + const dir = slash === -1 ? "" : v86_bin.substr(0, slash); + v86_bin_fallback = dir + "/" + v86_bin_fallback; + } + else if(typeof window === "undefined" && typeof __dirname === "string") + { + v86_bin = __dirname + "/" + v86_bin; + v86_bin_fallback = __dirname + "/" + v86_bin_fallback; + } + else + { + v86_bin = "build/" + v86_bin; + v86_bin_fallback = "build/" + v86_bin_fallback; + } + + v86util.load_file(v86_bin, { + done: async bytes => + { + try + { + const { instance } = await WebAssembly.instantiate(bytes, env); + this.wasm_source = bytes; + resolve(instance.exports); + } + catch(err) + { + v86util.load_file(v86_bin_fallback, { + done: async bytes => { + const { instance } = await WebAssembly.instantiate(bytes, env); + this.wasm_source = bytes; + resolve(instance.exports); + }, + }); + } + }, + progress: e => + { + this.emulator_bus.send("download-progress", { + file_index: 0, + file_count: 1, + file_name: v86_bin, + + lengthComputable: e.lengthComputable, + total: e.total, + loaded: e.loaded, + }); + } + }); + }); + }; + } + + wasm_fn({ "env": wasm_shared_funcs }) + .then((exports) => { + wasm_memory = exports.memory; + exports["rust_init"](); + + const emulator = this.v86 = new v86(this.emulator_bus, { exports, wasm_table }); + cpu = emulator.cpu; + + this.continue_init(emulator, options); + }); + + this.zstd_worker = null; + this.zstd_worker_request_id = 0; +} + +V86.prototype.continue_init = async function(emulator, options) +{ + this.bus.register("emulator-stopped", function() + { + this.cpu_is_running = false; + }, this); + + this.bus.register("emulator-started", function() + { + this.cpu_is_running = true; + }, this); + + var settings = {}; + + this.disk_images = { + fda: undefined, + fdb: undefined, + hda: undefined, + hdb: undefined, + cdrom: undefined, + }; + + const boot_order = + options.boot_order ? options.boot_order : + options.fda ? BOOT_ORDER_FD_FIRST : + options.hda ? BOOT_ORDER_HD_FIRST : BOOT_ORDER_CD_FIRST; + + settings.acpi = options.acpi; + settings.disable_jit = options.disable_jit; + settings.load_devices = true; + settings.log_level = options.log_level; + settings.memory_size = options.memory_size || 64 * 1024 * 1024; + settings.vga_memory_size = options.vga_memory_size || 8 * 1024 * 1024; + settings.boot_order = boot_order; + settings.fastboot = options.fastboot || false; + settings.fda = undefined; + settings.fdb = undefined; + settings.uart1 = options.uart1; + settings.uart2 = options.uart2; + settings.uart3 = options.uart3; + settings.cmdline = options.cmdline; + settings.preserve_mac_from_state_image = options.preserve_mac_from_state_image; + settings.mac_address_translation = options.mac_address_translation; + settings.cpuid_level = options.cpuid_level; + settings.virtio_console = options.virtio_console; + + if(options.network_adapter) + { + this.network_adapter = options.network_adapter(this.bus); + } + else if(options.network_relay_url) + { + this.network_adapter = new NetworkAdapter(options.network_relay_url, this.bus); + } + + // Enable unconditionally, so that state images don't miss hardware + // TODO: Should be properly fixed in restore_state + settings.enable_ne2k = true; + + if(!options.disable_keyboard) + { + this.keyboard_adapter = new KeyboardAdapter(this.bus); + } + if(!options.disable_mouse) + { + this.mouse_adapter = new MouseAdapter(this.bus, options.screen_container); + } + + if(options.screen_container) + { + this.screen_adapter = new ScreenAdapter(options.screen_container, this.bus); + } + else if(options.screen_dummy) + { + this.screen_adapter = new DummyScreenAdapter(this.bus); + } + + if(options.serial_container) + { + this.serial_adapter = new SerialAdapter(options.serial_container, this.bus); + //this.recording_adapter = new SerialRecordingAdapter(this.bus); + } + + if(options.serial_container_xtermjs) + { + this.serial_adapter = new SerialAdapterXtermJS(options.serial_container_xtermjs, this.bus); + } + + if(!options.disable_speaker) + { + this.speaker_adapter = new SpeakerAdapter(this.bus); + } + + // ugly, but required for closure compiler compilation + function put_on_settings(name, buffer) + { + switch(name) + { + case "hda": + settings.hda = this.disk_images.hda = buffer; + break; + case "hdb": + settings.hdb = this.disk_images.hdb = buffer; + break; + case "cdrom": + settings.cdrom = this.disk_images.cdrom = buffer; + break; + case "fda": + settings.fda = this.disk_images.fda = buffer; + break; + case "fdb": + settings.fdb = this.disk_images.fdb = buffer; + break; + + case "multiboot": + settings.multiboot = this.disk_images.multiboot = buffer.buffer; + break; + case "bzimage": + settings.bzimage = this.disk_images.bzimage = buffer.buffer; + break; + case "initrd": + settings.initrd = this.disk_images.initrd = buffer.buffer; + break; + + case "bios": + settings.bios = buffer.buffer; + break; + case "vga_bios": + settings.vga_bios = buffer.buffer; + break; + case "initial_state": + settings.initial_state = buffer.buffer; + break; + case "fs9p_json": + settings.fs9p_json = buffer; + break; + default: + dbg_assert(false, name); + } + } + + var files_to_load = []; + + const add_file = (name, file) => + { + if(!file) + { + return; + } + + if(file.get && file.set && file.load) + { + files_to_load.push({ + name: name, + loadable: file, + }); + return; + } + + if(name === "bios" || name === "vga_bios" || + name === "initial_state" || name === "multiboot" || + name === "bzimage" || name === "initrd") + { + // Ignore async for these because they must be available before boot. + // This should make result.buffer available after the object is loaded + file.async = false; + } + + if(file.url && !file.async) + { + files_to_load.push({ + name: name, + url: file.url, + size: file.size, + }); + } + else + { + files_to_load.push({ + name, + loadable: v86util.buffer_from_object(file, this.zstd_decompress_worker.bind(this)), + }); + } + }; + + if(options.state) + { + console.warn("Warning: Unknown option 'state'. Did you mean 'initial_state'?"); + } + + add_file("bios", options.bios); + add_file("vga_bios", options.vga_bios); + add_file("cdrom", options.cdrom); + add_file("hda", options.hda); + add_file("hdb", options.hdb); + add_file("fda", options.fda); + add_file("fdb", options.fdb); + add_file("initial_state", options.initial_state); + add_file("multiboot", options.multiboot); + add_file("bzimage", options.bzimage); + add_file("initrd", options.initrd); + + if(options.filesystem) + { + var fs_url = options.filesystem.basefs; + var base_url = options.filesystem.baseurl; + + let file_storage = new MemoryFileStorage(); + + if(base_url) + { + file_storage = new ServerFileStorageWrapper(file_storage, base_url); + } + settings.fs9p = this.fs9p = new FS(file_storage); + + if(fs_url) + { + dbg_assert(base_url, "Filesystem: baseurl must be specified"); + + var size; + + if(typeof fs_url === "object") + { + size = fs_url.size; + fs_url = fs_url.url; + } + dbg_assert(typeof fs_url === "string"); + + files_to_load.push({ + name: "fs9p_json", + url: fs_url, + size: size, + as_json: true, + }); + } + } + + var starter = this; + var total = files_to_load.length; + + var cont = function(index) + { + if(index === total) + { + setTimeout(done.bind(this), 0); + return; + } + + var f = files_to_load[index]; + + if(f.loadable) + { + f.loadable.onload = function(e) + { + put_on_settings.call(this, f.name, f.loadable); + cont(index + 1); + }.bind(this); + f.loadable.load(); + } + else + { + v86util.load_file(f.url, { + done: function(result) + { + if(f.url.endsWith(".zst") && f.name !== "initial_state") + { + dbg_assert(f.size, "A size must be provided for compressed images"); + result = this.zstd_decompress(f.size, new Uint8Array(result)); + } + + put_on_settings.call(this, f.name, f.as_json ? result : new v86util.SyncBuffer(result)); + cont(index + 1); + }.bind(this), + progress: function progress(e) + { + if(e.target.status === 200) + { + starter.emulator_bus.send("download-progress", { + file_index: index, + file_count: total, + file_name: f.url, + + lengthComputable: e.lengthComputable, + total: e.total || f.size, + loaded: e.loaded, + }); + } + else + { + starter.emulator_bus.send("download-error", { + file_index: index, + file_count: total, + file_name: f.url, + request: e.target, + }); + } + }, + as_json: f.as_json, + }); + } + }.bind(this); + cont(0); + + async function done() + { + //if(settings.initial_state) + //{ + // // avoid large allocation now, memory will be restored later anyway + // settings.memory_size = 0; + //} + + if(settings.fs9p && settings.fs9p_json) + { + if(!settings.initial_state) + { + settings.fs9p.load_from_json(settings.fs9p_json); + } + else + { + dbg_log("Filesystem basefs ignored: Overridden by state image"); + } + + if(options.bzimage_initrd_from_filesystem) + { + const { bzimage_path, initrd_path } = this.get_bzimage_initrd_from_filesystem(settings.fs9p); + + dbg_log("Found bzimage: " + bzimage_path + " and initrd: " + initrd_path); + + const [initrd, bzimage] = await Promise.all([ + settings.fs9p.read_file(initrd_path), + settings.fs9p.read_file(bzimage_path), + ]); + put_on_settings.call(this, "initrd", new v86util.SyncBuffer(initrd.buffer)); + put_on_settings.call(this, "bzimage", new v86util.SyncBuffer(bzimage.buffer)); + finish.call(this); + } + else + { + finish.call(this); + } + } + else + { + dbg_assert( + !options.bzimage_initrd_from_filesystem, + "bzimage_initrd_from_filesystem: Requires a filesystem"); + finish.call(this); + } + + function finish() + { + this.serial_adapter && this.serial_adapter.show && this.serial_adapter.show(); + + this.bus.send("cpu-init", settings); + + if(settings.initial_state) + { + emulator.restore_state(settings.initial_state); + + // The GC can't free settings, since it is referenced from + // several closures. This isn't needed anymore, so we delete it + // here + settings.initial_state = undefined; + } + + if(options.autostart) + { + this.bus.send("cpu-run"); + } + + this.emulator_bus.send("emulator-loaded"); + } + } +}; + +/** + * @param {number} decompressed_size + * @param {Uint8Array} src + * @return {ArrayBuffer} + */ +V86.prototype.zstd_decompress = function(decompressed_size, src) +{ + const cpu = this.v86.cpu; + + dbg_assert(!this.zstd_context); + this.zstd_context = cpu.zstd_create_ctx(src.length); + + new Uint8Array(cpu.wasm_memory.buffer).set(src, cpu.zstd_get_src_ptr(this.zstd_context)); + + const ptr = cpu.zstd_read(this.zstd_context, decompressed_size); + const result = cpu.wasm_memory.buffer.slice(ptr, ptr + decompressed_size); + cpu.zstd_read_free(ptr, decompressed_size); + + cpu.zstd_free_ctx(this.zstd_context); + this.zstd_context = null; + + return result; +}; + +/** + * @param {number} decompressed_size + * @param {Uint8Array} src + * @return {Promise} + */ +V86.prototype.zstd_decompress_worker = async function(decompressed_size, src) +{ + if(!this.zstd_worker) + { + function the_worker() + { + let wasm; + + globalThis.onmessage = function(e) + { + if(!wasm) + { + const env = Object.fromEntries([ + "cpu_exception_hook", "run_hardware_timers", + "cpu_event_halt", "microtick", "get_rand_int", + "apic_acknowledge_irq", + "io_port_read8", "io_port_read16", "io_port_read32", + "io_port_write8", "io_port_write16", "io_port_write32", + "mmap_read8", "mmap_read16", "mmap_read32", + "mmap_write8", "mmap_write16", "mmap_write32", "mmap_write64", "mmap_write128", + "codegen_finalize", + "jit_clear_func", "jit_clear_all_funcs", + ].map(f => [f, () => console.error("zstd worker unexpectedly called " + f)])); + + env["__indirect_function_table"] = new WebAssembly.Table({ element: "anyfunc", initial: 1024 }); + env["abort"] = () => { throw new Error("zstd worker aborted"); }; + env["log_from_wasm"] = env["console_log_from_wasm"] = (off, len) => { + console.log(String.fromCharCode(...new Uint8Array(wasm.exports.memory.buffer, off, len))); + }; + env["dbg_trace_from_wasm"] = () => console.trace(); + + wasm = new WebAssembly.Instance(new WebAssembly.Module(e.data), { "env": env }); + return; + } + + const { src, decompressed_size, id } = e.data; + const exports = wasm.exports; + + const zstd_context = exports["zstd_create_ctx"](src.length); + new Uint8Array(exports.memory.buffer).set(src, exports["zstd_get_src_ptr"](zstd_context)); + + const ptr = exports["zstd_read"](zstd_context, decompressed_size); + const result = exports.memory.buffer.slice(ptr, ptr + decompressed_size); + exports["zstd_read_free"](ptr, decompressed_size); + + exports["zstd_free_ctx"](zstd_context); + + postMessage({ result, id }, [result]); + }; + } + + const url = URL.createObjectURL(new Blob(["(" + the_worker.toString() + ")()"], { type: "text/javascript" })); + this.zstd_worker = new Worker(url); + URL.revokeObjectURL(url); + this.zstd_worker.postMessage(this.wasm_source, [this.wasm_source]); + } + + return new Promise(resolve => { + const id = this.zstd_worker_request_id++; + const done = async e => + { + if(e.data.id === id) + { + this.zstd_worker.removeEventListener("message", done); + dbg_assert(decompressed_size === e.data.result.byteLength); + resolve(e.data.result); + } + }; + this.zstd_worker.addEventListener("message", done); + this.zstd_worker.postMessage({ src, decompressed_size, id }, [src.buffer]); + }); +}; + +V86.prototype.get_bzimage_initrd_from_filesystem = function(filesystem) +{ + const root = (filesystem.read_dir("/") || []).map(x => "/" + x); + const boot = (filesystem.read_dir("/boot/") || []).map(x => "/boot/" + x); + + let initrd_path; + let bzimage_path; + + for(let f of [].concat(root, boot)) + { + const old = /old/i.test(f) || /fallback/i.test(f); + const is_bzimage = /vmlinuz/i.test(f) || /bzimage/i.test(f); + const is_initrd = /initrd/i.test(f) || /initramfs/i.test(f); + + if(is_bzimage && (!bzimage_path || !old)) + { + bzimage_path = f; + } + + if(is_initrd && (!initrd_path || !old)) + { + initrd_path = f; + } + } + + if(!initrd_path || !bzimage_path) + { + console.log("Failed to find bzimage or initrd in filesystem. Files:"); + console.log(root.join(" ")); + console.log(boot.join(" ")); + } + + return { initrd_path, bzimage_path }; +}; + +/** + * Start emulation. Do nothing if emulator is running already. Can be + * asynchronous. + * @export + */ +V86.prototype.run = async function() +{ + this.bus.send("cpu-run"); +}; + +/** + * Stop emulation. Do nothing if emulator is not running. Can be asynchronous. + * @export + */ +V86.prototype.stop = async function() +{ + if(!this.cpu_is_running) + { + return; + } + + await new Promise(resolve => { + const listener = () => { + this.remove_listener("emulator-stopped", listener); + resolve(); + }; + this.add_listener("emulator-stopped", listener); + this.bus.send("cpu-stop"); + }); +}; + +/** + * @ignore + * @export + */ +V86.prototype.destroy = async function() +{ + await this.stop(); + + this.v86.destroy(); + this.keyboard_adapter && this.keyboard_adapter.destroy(); + this.network_adapter && this.network_adapter.destroy(); + this.mouse_adapter && this.mouse_adapter.destroy(); + this.screen_adapter && this.screen_adapter.destroy(); + this.serial_adapter && this.serial_adapter.destroy() + this.speaker_adapter && this.speaker_adapter.destroy(); +}; + +/** + * Restart (force a reboot). + * @export + */ +V86.prototype.restart = function() +{ + this.bus.send("cpu-restart"); +}; + +/** + * Add an event listener (the emulator is an event emitter). A list of events + * can be found at [events.md](events.md). + * + * The callback function gets a single argument which depends on the event. + * + * @param {string} event Name of the event. + * @param {function(*)} listener The callback function. + * @export + */ +V86.prototype.add_listener = function(event, listener) +{ + this.bus.register(event, listener, this); +}; + +/** + * Remove an event listener. + * + * @param {string} event + * @param {function(*)} listener + * @export + */ +V86.prototype.remove_listener = function(event, listener) +{ + this.bus.unregister(event, listener); +}; + +/** + * Restore the emulator state from the given state, which must be an + * ArrayBuffer returned by + * [`save_state`](#save_statefunctionobject-arraybuffer-callback). + * + * Note that the state can only be restored correctly if this constructor has + * been created with the same options as the original instance (e.g., same disk + * images, memory size, etc.). + * + * Different versions of the emulator might use a different format for the + * state buffer. + * + * @param {ArrayBuffer} state + * @export + */ +V86.prototype.restore_state = async function(state) +{ + dbg_assert(arguments.length === 1); + this.v86.restore_state(state); +}; + +/** + * Asynchronously save the current state of the emulator. + * + * @return {Promise} + * @export + */ +V86.prototype.save_state = async function() +{ + dbg_assert(arguments.length === 0); + return this.v86.save_state(); +}; + +/** + * @return {number} + * @ignore + * @export + */ +V86.prototype.get_instruction_counter = function() +{ + if(this.v86) + { + return this.v86.cpu.instruction_counter[0] >>> 0; + } + else + { + // TODO: Should be handled using events + return 0; + } +}; + +/** + * @return {boolean} + * @export + */ +V86.prototype.is_running = function() +{ + return this.cpu_is_running; +}; + +/** + * Set the image inserted in the floppy drive. Can be changed at runtime, as + * when physically changing the floppy disk. + * @export + */ +V86.prototype.set_fda = async function(file) +{ + if(file.url && !file.async) + { + v86util.load_file(file.url, { + done: result => + { + this.v86.cpu.devices.fdc.set_fda(new v86util.SyncBuffer(result)); + }, + }); + } + else + { + const image = v86util.buffer_from_object(file, this.zstd_decompress_worker.bind(this)); + image.onload = () => + { + this.v86.cpu.devices.fdc.set_fda(image); + }; + await image.load(); + } +}; + +/** + * Eject the floppy drive. + * @export + */ +V86.prototype.eject_fda = function() +{ + this.v86.cpu.devices.fdc.eject_fda(); +}; + +/** + * Send a sequence of scan codes to the emulated PS2 controller. A list of + * codes can be found at http://stanislavs.org/helppc/make_codes.html. + * Do nothing if there is no keyboard controller. + * + * @param {Array.} codes + * @export + */ +V86.prototype.keyboard_send_scancodes = function(codes) +{ + for(var i = 0; i < codes.length; i++) + { + this.bus.send("keyboard-code", codes[i]); + } +}; + +/** + * Send translated keys + * @ignore + * @export + */ +V86.prototype.keyboard_send_keys = function(codes) +{ + for(var i = 0; i < codes.length; i++) + { + this.keyboard_adapter.simulate_press(codes[i]); + } +}; + +/** + * Send text + * @ignore + * @export + */ +V86.prototype.keyboard_send_text = function(string) +{ + for(var i = 0; i < string.length; i++) + { + this.keyboard_adapter.simulate_char(string[i]); + } +}; + +/** + * Download a screenshot. + * + * @ignore + * @export + */ +V86.prototype.screen_make_screenshot = function() +{ + if(this.screen_adapter) + { + return this.screen_adapter.make_screenshot(); + } + return null; +}; + +/** + * Set the scaling level of the emulated screen. + * + * @param {number} sx + * @param {number} sy + * + * @ignore + * @export + */ +V86.prototype.screen_set_scale = function(sx, sy) +{ + if(this.screen_adapter) + { + this.screen_adapter.set_scale(sx, sy); + } +}; + +/** + * Go fullscreen. + * + * @ignore + * @export + */ +V86.prototype.screen_go_fullscreen = function() +{ + if(!this.screen_adapter) + { + return; + } + + var elem = document.getElementById("screen_container"); + + if(!elem) + { + return; + } + + // bracket notation because otherwise they get renamed by closure compiler + var fn = elem["requestFullScreen"] || + elem["webkitRequestFullscreen"] || + elem["mozRequestFullScreen"] || + elem["msRequestFullScreen"]; + + if(fn) + { + fn.call(elem); + + // This is necessary, because otherwise chromium keyboard doesn't work anymore. + // Might (but doesn't seem to) break something else + var focus_element = document.getElementsByClassName("phone_keyboard")[0]; + focus_element && focus_element.focus(); + } + + try { + navigator.keyboard.lock(); + } catch(e) {} + + this.lock_mouse(); +}; + +/** + * Lock the mouse cursor: It becomes invisble and is not moved out of the + * browser window. + * + * @ignore + * @export + */ +V86.prototype.lock_mouse = function() +{ + var elem = document.body; + + var fn = elem["requestPointerLock"] || + elem["mozRequestPointerLock"] || + elem["webkitRequestPointerLock"]; + + if(fn) + { + fn.call(elem); + } +}; + +/** + * Enable or disable sending mouse events to the emulated PS2 controller. + * + * @param {boolean} enabled + */ +V86.prototype.mouse_set_status = function(enabled) +{ + if(this.mouse_adapter) + { + this.mouse_adapter.emu_enabled = enabled; + } +}; + +/** + * Enable or disable sending keyboard events to the emulated PS2 controller. + * + * @param {boolean} enabled + * @export + */ +V86.prototype.keyboard_set_status = function(enabled) +{ + if(this.keyboard_adapter) + { + this.keyboard_adapter.emu_enabled = enabled; + } +}; + + +/** + * Send a string to the first emulated serial terminal. + * + * @param {string} data + * @export + */ +V86.prototype.serial0_send = function(data) +{ + for(var i = 0; i < data.length; i++) + { + this.bus.send("serial0-input", data.charCodeAt(i)); + } +}; + +/** + * Send bytes to a serial port (to be received by the emulated PC). + * + * @param {Uint8Array} data + * @export + */ +V86.prototype.serial_send_bytes = function(serial, data) +{ + for(var i = 0; i < data.length; i++) + { + this.bus.send("serial" + serial + "-input", data[i]); + } +}; + +/** + * Set the modem status of a serial port. + */ +V86.prototype.serial_set_modem_status = function(serial, status) +{ + this.bus.send("serial" + serial + "-modem-status-input", status); +}; + +/** + * Set the carrier detect status of a serial port. + */ +V86.prototype.serial_set_carrier_detect = function(serial, status) +{ + this.bus.send("serial" + serial + "-carrier-detect-input", status); +}; + +/** + * Set the ring indicator status of a serial port. + */ +V86.prototype.serial_set_ring_indicator = function(serial, status) +{ + this.bus.send("serial" + serial + "-ring-indicator-input", status); +}; + +/** + * Set the data set ready status of a serial port. + */ +V86.prototype.serial_set_data_set_ready = function(serial, status) +{ + this.bus.send("serial" + serial + "-data-set-ready-input", status); +}; + +/** + * Set the clear to send status of a serial port. + */ +V86.prototype.serial_set_clear_to_send = function(serial, status) +{ + this.bus.send("serial" + serial + "-clear-to-send-input", status); +}; + +/** + * Mount another filesystem to the current filesystem. + * @param {string} path Path for the mount point + * @param {string|undefined} baseurl + * @param {string|undefined} basefs As a JSON string + * @param {function(Object)=} callback + * @export + */ +V86.prototype.mount_fs = async function(path, baseurl, basefs, callback) +{ + let file_storage = new MemoryFileStorage(); + + if(baseurl) + { + file_storage = new ServerFileStorageWrapper(file_storage, baseurl); + } + const newfs = new FS(file_storage, this.fs9p.qidcounter); + const mount = () => + { + const idx = this.fs9p.Mount(path, newfs); + if(!callback) + { + return; + } + if(idx === -ENOENT) + { + callback(new FileNotFoundError()); + } + else if(idx === -EEXIST) + { + callback(new FileExistsError()); + } + else if(idx < 0) + { + dbg_assert(false, "Unexpected error code: " + (-idx)); + callback(new Error("Failed to mount. Error number: " + (-idx))); + } + else + { + callback(null); + } + }; + if(baseurl) + { + dbg_assert(typeof basefs === "object", "Filesystem: basefs must be a JSON object"); + newfs.load_from_json(basefs, () => mount()); + } + else + { + mount(); + } +}; + +/** + * Write to a file in the 9p filesystem. Nothing happens if no filesystem has + * been initialized. + * + * @param {string} file + * @param {Uint8Array} data + * @export + */ +V86.prototype.create_file = async function(file, data) +{ + dbg_assert(arguments.length === 2); + var fs = this.fs9p; + + if(!fs) + { + return; + } + + var parts = file.split("/"); + var filename = parts[parts.length - 1]; + + var path_infos = fs.SearchPath(file); + var parent_id = path_infos.parentid; + var not_found = filename === "" || parent_id === -1; + + if(!not_found) + { + await fs.CreateBinaryFile(filename, parent_id, data); + } + else + { + return Promise.reject(new FileNotFoundError()); + } +}; + +/** + * Read a file in the 9p filesystem. Nothing happens if no filesystem has been + * initialized. + * + * @param {string} file + * @export + */ +V86.prototype.read_file = async function(file) +{ + dbg_assert(arguments.length === 1); + var fs = this.fs9p; + + if(!fs) + { + return; + } + + const result = await fs.read_file(file); + + if(result) + { + return result; + } + else + { + return Promise.reject(new FileNotFoundError()); + } +}; + +V86.prototype.automatically = function(steps) +{ + const run = (steps) => + { + const step = steps[0]; + + if(!step) + { + return; + } + + const remaining_steps = steps.slice(1); + + if(step.sleep) + { + setTimeout(() => run(remaining_steps), step.sleep * 1000); + return; + } + + if(step.vga_text) + { + const screen = this.screen_adapter.get_text_screen(); + + for(let line of screen) + { + if(line.includes(step.vga_text)) + { + run(remaining_steps); + return; + } + } + + setTimeout(() => run(steps), 1000); + return; + } + + if(step.keyboard_send) + { + if(step.keyboard_send instanceof Array) + { + this.keyboard_send_scancodes(step.keyboard_send); + } + else + { + dbg_assert(typeof step.keyboard_send === "string"); + this.keyboard_send_text(step.keyboard_send); + } + + run(remaining_steps); + return; + } + + if(step.call) + { + step.call(); + run(remaining_steps); + return; + } + + dbg_assert(false, step); + }; + + run(steps); + +}; + +/** + * Reads data from memory at specified offset. + * + * @param {number} offset + * @param {number} length + * @returns + */ +V86.prototype.read_memory = function(offset, length) +{ + return this.v86.cpu.read_blob(offset, length); +}; + +/** + * Writes data to memory at specified offset. + * + * @param {Array.|Uint8Array} blob + * @param {number} offset + */ +V86.prototype.write_memory = function(blob, offset) +{ + this.v86.cpu.write_blob(blob, offset); +}; + +V86.prototype.set_serial_container_xtermjs = function(element) +{ + this.serial_adapter && this.serial_adapter.destroy && this.serial_adapter.destroy(); + this.serial_adapter = new SerialAdapterXtermJS(element, this.bus); + this.serial_adapter.show(); +}; + +/** + * @ignore + * @constructor + * + * @param {string=} message + */ +function FileExistsError(message) +{ + this.message = message || "File already exists"; +} +FileExistsError.prototype = Error.prototype; + +/** + * @ignore + * @constructor + * + * @param {string=} message + */ +function FileNotFoundError(message) +{ + this.message = message || "File not found"; +} +FileNotFoundError.prototype = Error.prototype; + +// Closure Compiler's way of exporting +if(typeof window !== "undefined") +{ + window["V86Starter"] = V86; + window["V86"] = V86; +} +else if(typeof module !== "undefined" && typeof module.exports !== "undefined") +{ + module.exports["V86Starter"] = V86; + module.exports["V86"] = V86; +} +else if(typeof importScripts === "function") +{ + // web worker + self["V86Starter"] = V86; + self["V86"] = V86; +} diff --git a/incubator/x86emu/www/third-party/xterm.css b/incubator/x86emu/www/third-party/xterm.css new file mode 100644 index 0000000000..e97b643905 --- /dev/null +++ b/incubator/x86emu/www/third-party/xterm.css @@ -0,0 +1,218 @@ +/** + * Copyright (c) 2014 The xterm.js authors. All rights reserved. + * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License) + * https://github.com/chjj/term.js + * @license MIT + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + * + * Originally forked from (with the author's permission): + * Fabrice Bellard's javascript vt100 for jslinux: + * http://bellard.org/jslinux/ + * Copyright (c) 2011 Fabrice Bellard + * The original design remains. The terminal itself + * has been extended to include xterm CSI codes, among + * other features. + */ + +/** + * Default styles for xterm.js + */ + +.xterm { + cursor: text; + position: relative; + user-select: none; + -ms-user-select: none; + -webkit-user-select: none; +} + +.xterm.focus, +.xterm:focus { + outline: none; +} + +.xterm .xterm-helpers { + position: absolute; + top: 0; + /** + * The z-index of the helpers must be higher than the canvases in order for + * IMEs to appear on top. + */ + z-index: 5; +} + +.xterm .xterm-helper-textarea { + padding: 0; + border: 0; + margin: 0; + /* Move textarea out of the screen to the far left, so that the cursor is not visible */ + position: absolute; + opacity: 0; + left: -9999em; + top: 0; + width: 0; + height: 0; + z-index: -5; + /** Prevent wrapping so the IME appears against the textarea at the correct position */ + white-space: nowrap; + overflow: hidden; + resize: none; +} + +.xterm .composition-view { + /* TODO: Composition position got messed up somewhere */ + background: #000; + color: #FFF; + display: none; + position: absolute; + white-space: nowrap; + z-index: 1; +} + +.xterm .composition-view.active { + display: block; +} + +.xterm .xterm-viewport { + /* On OS X this is required in order for the scroll bar to appear fully opaque */ + background-color: #000; + overflow-y: scroll; + cursor: default; + position: absolute; + right: 0; + left: 0; + top: 0; + bottom: 0; +} + +.xterm .xterm-screen { + position: relative; +} + +.xterm .xterm-screen canvas { + position: absolute; + left: 0; + top: 0; +} + +.xterm .xterm-scroll-area { + visibility: hidden; +} + +.xterm-char-measure-element { + display: inline-block; + visibility: hidden; + position: absolute; + top: 0; + left: -9999em; + line-height: normal; +} + +.xterm.enable-mouse-events { + /* When mouse events are enabled (eg. tmux), revert to the standard pointer cursor */ + cursor: default; +} + +.xterm.xterm-cursor-pointer, +.xterm .xterm-cursor-pointer { + cursor: pointer; +} + +.xterm.column-select.focus { + /* Column selection mode */ + cursor: crosshair; +} + +.xterm .xterm-accessibility:not(.debug), +.xterm .xterm-message { + position: absolute; + left: 0; + top: 0; + bottom: 0; + right: 0; + z-index: 10; + color: transparent; + pointer-events: none; +} + +.xterm .xterm-accessibility-tree:not(.debug) *::selection { + color: transparent; +} + +.xterm .xterm-accessibility-tree { + user-select: text; + white-space: pre; +} + +.xterm .live-region { + position: absolute; + left: -9999px; + width: 1px; + height: 1px; + overflow: hidden; +} + +.xterm-dim { + /* Dim should not apply to background, so the opacity of the foreground color is applied + * explicitly in the generated class and reset to 1 here */ + opacity: 1 !important; +} + +.xterm-underline-1 { text-decoration: underline; } +.xterm-underline-2 { text-decoration: double underline; } +.xterm-underline-3 { text-decoration: wavy underline; } +.xterm-underline-4 { text-decoration: dotted underline; } +.xterm-underline-5 { text-decoration: dashed underline; } + +.xterm-overline { + text-decoration: overline; +} + +.xterm-overline.xterm-underline-1 { text-decoration: overline underline; } +.xterm-overline.xterm-underline-2 { text-decoration: overline double underline; } +.xterm-overline.xterm-underline-3 { text-decoration: overline wavy underline; } +.xterm-overline.xterm-underline-4 { text-decoration: overline dotted underline; } +.xterm-overline.xterm-underline-5 { text-decoration: overline dashed underline; } + +.xterm-strikethrough { + text-decoration: line-through; +} + +.xterm-screen .xterm-decoration-container .xterm-decoration { + z-index: 6; + position: absolute; +} + +.xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer { + z-index: 7; +} + +.xterm-decoration-overview-ruler { + z-index: 8; + position: absolute; + top: 0; + right: 0; + pointer-events: none; +} + +.xterm-decoration-top { + z-index: 2; + position: relative; +} diff --git a/incubator/x86emu/www/third-party/xterm.js b/incubator/x86emu/www/third-party/xterm.js new file mode 100644 index 0000000000..4b20013f6d --- /dev/null +++ b/incubator/x86emu/www/third-party/xterm.js @@ -0,0 +1,2 @@ +!function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var i=t();for(var s in i)("object"==typeof exports?exports:e)[s]=i[s]}}(globalThis,(()=>(()=>{"use strict";var e={4567:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.AccessibilityManager=void 0;const n=i(9042),o=i(9924),a=i(844),h=i(4725),c=i(2585),l=i(3656);let d=t.AccessibilityManager=class extends a.Disposable{constructor(e,t,i,s){super(),this._terminal=e,this._coreBrowserService=i,this._renderService=s,this._rowColumns=new WeakMap,this._liveRegionLineCount=0,this._charsToConsume=[],this._charsToAnnounce="",this._accessibilityContainer=this._coreBrowserService.mainDocument.createElement("div"),this._accessibilityContainer.classList.add("xterm-accessibility"),this._rowContainer=this._coreBrowserService.mainDocument.createElement("div"),this._rowContainer.setAttribute("role","list"),this._rowContainer.classList.add("xterm-accessibility-tree"),this._rowElements=[];for(let e=0;ethis._handleBoundaryFocus(e,0),this._bottomBoundaryFocusListener=e=>this._handleBoundaryFocus(e,1),this._rowElements[0].addEventListener("focus",this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._refreshRowsDimensions(),this._accessibilityContainer.appendChild(this._rowContainer),this._liveRegion=this._coreBrowserService.mainDocument.createElement("div"),this._liveRegion.classList.add("live-region"),this._liveRegion.setAttribute("aria-live","assertive"),this._accessibilityContainer.appendChild(this._liveRegion),this._liveRegionDebouncer=this.register(new o.TimeBasedDebouncer(this._renderRows.bind(this))),!this._terminal.element)throw new Error("Cannot enable accessibility before Terminal.open");this._terminal.element.insertAdjacentElement("afterbegin",this._accessibilityContainer),this.register(this._terminal.onResize((e=>this._handleResize(e.rows)))),this.register(this._terminal.onRender((e=>this._refreshRows(e.start,e.end)))),this.register(this._terminal.onScroll((()=>this._refreshRows()))),this.register(this._terminal.onA11yChar((e=>this._handleChar(e)))),this.register(this._terminal.onLineFeed((()=>this._handleChar("\n")))),this.register(this._terminal.onA11yTab((e=>this._handleTab(e)))),this.register(this._terminal.onKey((e=>this._handleKey(e.key)))),this.register(this._terminal.onBlur((()=>this._clearLiveRegion()))),this.register(this._renderService.onDimensionsChange((()=>this._refreshRowsDimensions()))),this.register((0,l.addDisposableDomListener)(document,"selectionchange",(()=>this._handleSelectionChange()))),this.register(this._coreBrowserService.onDprChange((()=>this._refreshRowsDimensions()))),this._refreshRows(),this.register((0,a.toDisposable)((()=>{this._accessibilityContainer.remove(),this._rowElements.length=0})))}_handleTab(e){for(let t=0;t0?this._charsToConsume.shift()!==e&&(this._charsToAnnounce+=e):this._charsToAnnounce+=e,"\n"===e&&(this._liveRegionLineCount++,21===this._liveRegionLineCount&&(this._liveRegion.textContent+=n.tooMuchOutput)))}_clearLiveRegion(){this._liveRegion.textContent="",this._liveRegionLineCount=0}_handleKey(e){this._clearLiveRegion(),/\p{Control}/u.test(e)||this._charsToConsume.push(e)}_refreshRows(e,t){this._liveRegionDebouncer.refresh(e,t,this._terminal.rows)}_renderRows(e,t){const i=this._terminal.buffer,s=i.lines.length.toString();for(let r=e;r<=t;r++){const e=i.lines.get(i.ydisp+r),t=[],n=e?.translateToString(!0,void 0,void 0,t)||"",o=(i.ydisp+r+1).toString(),a=this._rowElements[r];a&&(0===n.length?(a.innerText=" ",this._rowColumns.set(a,[0,1])):(a.textContent=n,this._rowColumns.set(a,t)),a.setAttribute("aria-posinset",o),a.setAttribute("aria-setsize",s))}this._announceCharacters()}_announceCharacters(){0!==this._charsToAnnounce.length&&(this._liveRegion.textContent+=this._charsToAnnounce,this._charsToAnnounce="")}_handleBoundaryFocus(e,t){const i=e.target,s=this._rowElements[0===t?1:this._rowElements.length-2];if(i.getAttribute("aria-posinset")===(0===t?"1":`${this._terminal.buffer.lines.length}`))return;if(e.relatedTarget!==s)return;let r,n;if(0===t?(r=i,n=this._rowElements.pop(),this._rowContainer.removeChild(n)):(r=this._rowElements.shift(),n=i,this._rowContainer.removeChild(r)),r.removeEventListener("focus",this._topBoundaryFocusListener),n.removeEventListener("focus",this._bottomBoundaryFocusListener),0===t){const e=this._createAccessibilityTreeNode();this._rowElements.unshift(e),this._rowContainer.insertAdjacentElement("afterbegin",e)}else{const e=this._createAccessibilityTreeNode();this._rowElements.push(e),this._rowContainer.appendChild(e)}this._rowElements[0].addEventListener("focus",this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._terminal.scrollLines(0===t?-1:1),this._rowElements[0===t?1:this._rowElements.length-2].focus(),e.preventDefault(),e.stopImmediatePropagation()}_handleSelectionChange(){if(0===this._rowElements.length)return;const e=document.getSelection();if(!e)return;if(e.isCollapsed)return void(this._rowContainer.contains(e.anchorNode)&&this._terminal.clearSelection());if(!e.anchorNode||!e.focusNode)return void console.error("anchorNode and/or focusNode are null");let t={node:e.anchorNode,offset:e.anchorOffset},i={node:e.focusNode,offset:e.focusOffset};if((t.node.compareDocumentPosition(i.node)&Node.DOCUMENT_POSITION_PRECEDING||t.node===i.node&&t.offset>i.offset)&&([t,i]=[i,t]),t.node.compareDocumentPosition(this._rowElements[0])&(Node.DOCUMENT_POSITION_CONTAINED_BY|Node.DOCUMENT_POSITION_FOLLOWING)&&(t={node:this._rowElements[0].childNodes[0],offset:0}),!this._rowContainer.contains(t.node))return;const s=this._rowElements.slice(-1)[0];if(i.node.compareDocumentPosition(s)&(Node.DOCUMENT_POSITION_CONTAINED_BY|Node.DOCUMENT_POSITION_PRECEDING)&&(i={node:s,offset:s.textContent?.length??0}),!this._rowContainer.contains(i.node))return;const r=({node:e,offset:t})=>{const i=e instanceof Text?e.parentNode:e;let s=parseInt(i?.getAttribute("aria-posinset"),10)-1;if(isNaN(s))return console.warn("row is invalid. Race condition?"),null;const r=this._rowColumns.get(i);if(!r)return console.warn("columns is null. Race condition?"),null;let n=t=this._terminal.cols&&(++s,n=0),{row:s,column:n}},n=r(t),o=r(i);if(n&&o){if(n.row>o.row||n.row===o.row&&n.column>=o.column)throw new Error("invalid range");this._terminal.select(n.column,n.row,(o.row-n.row)*this._terminal.cols-n.column+o.column)}}_handleResize(e){this._rowElements[this._rowElements.length-1].removeEventListener("focus",this._bottomBoundaryFocusListener);for(let e=this._rowContainer.children.length;ee;)this._rowContainer.removeChild(this._rowElements.pop());this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._refreshRowsDimensions()}_createAccessibilityTreeNode(){const e=this._coreBrowserService.mainDocument.createElement("div");return e.setAttribute("role","listitem"),e.tabIndex=-1,this._refreshRowDimensions(e),e}_refreshRowsDimensions(){if(this._renderService.dimensions.css.cell.height){this._accessibilityContainer.style.width=`${this._renderService.dimensions.css.canvas.width}px`,this._rowElements.length!==this._terminal.rows&&this._handleResize(this._terminal.rows);for(let e=0;e{function i(e){return e.replace(/\r?\n/g,"\r")}function s(e,t){return t?"[200~"+e+"[201~":e}function r(e,t,r,n){e=s(e=i(e),r.decPrivateModes.bracketedPasteMode&&!0!==n.rawOptions.ignoreBracketedPasteMode),r.triggerDataEvent(e,!0),t.value=""}function n(e,t,i){const s=i.getBoundingClientRect(),r=e.clientX-s.left-10,n=e.clientY-s.top-10;t.style.width="20px",t.style.height="20px",t.style.left=`${r}px`,t.style.top=`${n}px`,t.style.zIndex="1000",t.focus()}Object.defineProperty(t,"__esModule",{value:!0}),t.rightClickHandler=t.moveTextAreaUnderMouseCursor=t.paste=t.handlePasteEvent=t.copyHandler=t.bracketTextForPaste=t.prepareTextForTerminal=void 0,t.prepareTextForTerminal=i,t.bracketTextForPaste=s,t.copyHandler=function(e,t){e.clipboardData&&e.clipboardData.setData("text/plain",t.selectionText),e.preventDefault()},t.handlePasteEvent=function(e,t,i,s){e.stopPropagation(),e.clipboardData&&r(e.clipboardData.getData("text/plain"),t,i,s)},t.paste=r,t.moveTextAreaUnderMouseCursor=n,t.rightClickHandler=function(e,t,i,s,r){n(e,t,i),r&&s.rightClickSelect(e),t.value=s.selectionText,t.select()}},7239:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ColorContrastCache=void 0;const s=i(1505);t.ColorContrastCache=class{constructor(){this._color=new s.TwoKeyMap,this._css=new s.TwoKeyMap}setCss(e,t,i){this._css.set(e,t,i)}getCss(e,t){return this._css.get(e,t)}setColor(e,t,i){this._color.set(e,t,i)}getColor(e,t){return this._color.get(e,t)}clear(){this._color.clear(),this._css.clear()}}},3656:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.addDisposableDomListener=void 0,t.addDisposableDomListener=function(e,t,i,s){e.addEventListener(t,i,s);let r=!1;return{dispose:()=>{r||(r=!0,e.removeEventListener(t,i,s))}}}},3551:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.Linkifier=void 0;const n=i(3656),o=i(8460),a=i(844),h=i(2585),c=i(4725);let l=t.Linkifier=class extends a.Disposable{get currentLink(){return this._currentLink}constructor(e,t,i,s,r){super(),this._element=e,this._mouseService=t,this._renderService=i,this._bufferService=s,this._linkProviderService=r,this._linkCacheDisposables=[],this._isMouseOut=!0,this._wasResized=!1,this._activeLine=-1,this._onShowLinkUnderline=this.register(new o.EventEmitter),this.onShowLinkUnderline=this._onShowLinkUnderline.event,this._onHideLinkUnderline=this.register(new o.EventEmitter),this.onHideLinkUnderline=this._onHideLinkUnderline.event,this.register((0,a.getDisposeArrayDisposable)(this._linkCacheDisposables)),this.register((0,a.toDisposable)((()=>{this._lastMouseEvent=void 0,this._activeProviderReplies?.clear()}))),this.register(this._bufferService.onResize((()=>{this._clearCurrentLink(),this._wasResized=!0}))),this.register((0,n.addDisposableDomListener)(this._element,"mouseleave",(()=>{this._isMouseOut=!0,this._clearCurrentLink()}))),this.register((0,n.addDisposableDomListener)(this._element,"mousemove",this._handleMouseMove.bind(this))),this.register((0,n.addDisposableDomListener)(this._element,"mousedown",this._handleMouseDown.bind(this))),this.register((0,n.addDisposableDomListener)(this._element,"mouseup",this._handleMouseUp.bind(this)))}_handleMouseMove(e){this._lastMouseEvent=e;const t=this._positionFromMouseEvent(e,this._element,this._mouseService);if(!t)return;this._isMouseOut=!1;const i=e.composedPath();for(let e=0;e{e?.forEach((e=>{e.link.dispose&&e.link.dispose()}))})),this._activeProviderReplies=new Map,this._activeLine=e.y);let i=!1;for(const[s,r]of this._linkProviderService.linkProviders.entries())if(t){const t=this._activeProviderReplies?.get(s);t&&(i=this._checkLinkProviderResult(s,e,i))}else r.provideLinks(e.y,(t=>{if(this._isMouseOut)return;const r=t?.map((e=>({link:e})));this._activeProviderReplies?.set(s,r),i=this._checkLinkProviderResult(s,e,i),this._activeProviderReplies?.size===this._linkProviderService.linkProviders.length&&this._removeIntersectingLinks(e.y,this._activeProviderReplies)}))}_removeIntersectingLinks(e,t){const i=new Set;for(let s=0;se?this._bufferService.cols:s.link.range.end.x;for(let e=n;e<=o;e++){if(i.has(e)){r.splice(t--,1);break}i.add(e)}}}}_checkLinkProviderResult(e,t,i){if(!this._activeProviderReplies)return i;const s=this._activeProviderReplies.get(e);let r=!1;for(let t=0;tthis._linkAtPosition(e.link,t)));e&&(i=!0,this._handleNewLink(e))}if(this._activeProviderReplies.size===this._linkProviderService.linkProviders.length&&!i)for(let e=0;ethis._linkAtPosition(e.link,t)));if(s){i=!0,this._handleNewLink(s);break}}return i}_handleMouseDown(){this._mouseDownLink=this._currentLink}_handleMouseUp(e){if(!this._currentLink)return;const t=this._positionFromMouseEvent(e,this._element,this._mouseService);t&&this._mouseDownLink===this._currentLink&&this._linkAtPosition(this._currentLink.link,t)&&this._currentLink.link.activate(e,this._currentLink.link.text)}_clearCurrentLink(e,t){this._currentLink&&this._lastMouseEvent&&(!e||!t||this._currentLink.link.range.start.y>=e&&this._currentLink.link.range.end.y<=t)&&(this._linkLeave(this._element,this._currentLink.link,this._lastMouseEvent),this._currentLink=void 0,(0,a.disposeArray)(this._linkCacheDisposables))}_handleNewLink(e){if(!this._lastMouseEvent)return;const t=this._positionFromMouseEvent(this._lastMouseEvent,this._element,this._mouseService);t&&this._linkAtPosition(e.link,t)&&(this._currentLink=e,this._currentLink.state={decorations:{underline:void 0===e.link.decorations||e.link.decorations.underline,pointerCursor:void 0===e.link.decorations||e.link.decorations.pointerCursor},isHovered:!0},this._linkHover(this._element,e.link,this._lastMouseEvent),e.link.decorations={},Object.defineProperties(e.link.decorations,{pointerCursor:{get:()=>this._currentLink?.state?.decorations.pointerCursor,set:e=>{this._currentLink?.state&&this._currentLink.state.decorations.pointerCursor!==e&&(this._currentLink.state.decorations.pointerCursor=e,this._currentLink.state.isHovered&&this._element.classList.toggle("xterm-cursor-pointer",e))}},underline:{get:()=>this._currentLink?.state?.decorations.underline,set:t=>{this._currentLink?.state&&this._currentLink?.state?.decorations.underline!==t&&(this._currentLink.state.decorations.underline=t,this._currentLink.state.isHovered&&this._fireUnderlineEvent(e.link,t))}}}),this._linkCacheDisposables.push(this._renderService.onRenderedViewportChange((e=>{if(!this._currentLink)return;const t=0===e.start?0:e.start+1+this._bufferService.buffer.ydisp,i=this._bufferService.buffer.ydisp+1+e.end;if(this._currentLink.link.range.start.y>=t&&this._currentLink.link.range.end.y<=i&&(this._clearCurrentLink(t,i),this._lastMouseEvent)){const e=this._positionFromMouseEvent(this._lastMouseEvent,this._element,this._mouseService);e&&this._askForLink(e,!1)}}))))}_linkHover(e,t,i){this._currentLink?.state&&(this._currentLink.state.isHovered=!0,this._currentLink.state.decorations.underline&&this._fireUnderlineEvent(t,!0),this._currentLink.state.decorations.pointerCursor&&e.classList.add("xterm-cursor-pointer")),t.hover&&t.hover(i,t.text)}_fireUnderlineEvent(e,t){const i=e.range,s=this._bufferService.buffer.ydisp,r=this._createLinkUnderlineEvent(i.start.x-1,i.start.y-s-1,i.end.x,i.end.y-s-1,void 0);(t?this._onShowLinkUnderline:this._onHideLinkUnderline).fire(r)}_linkLeave(e,t,i){this._currentLink?.state&&(this._currentLink.state.isHovered=!1,this._currentLink.state.decorations.underline&&this._fireUnderlineEvent(t,!1),this._currentLink.state.decorations.pointerCursor&&e.classList.remove("xterm-cursor-pointer")),t.leave&&t.leave(i,t.text)}_linkAtPosition(e,t){const i=e.range.start.y*this._bufferService.cols+e.range.start.x,s=e.range.end.y*this._bufferService.cols+e.range.end.x,r=t.y*this._bufferService.cols+t.x;return i<=r&&r<=s}_positionFromMouseEvent(e,t,i){const s=i.getCoords(e,t,this._bufferService.cols,this._bufferService.rows);if(s)return{x:s[0],y:s[1]+this._bufferService.buffer.ydisp}}_createLinkUnderlineEvent(e,t,i,s,r){return{x1:e,y1:t,x2:i,y2:s,cols:this._bufferService.cols,fg:r}}};t.Linkifier=l=s([r(1,c.IMouseService),r(2,c.IRenderService),r(3,h.IBufferService),r(4,c.ILinkProviderService)],l)},9042:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.tooMuchOutput=t.promptLabel=void 0,t.promptLabel="Terminal input",t.tooMuchOutput="Too much output to announce, navigate to rows manually to read"},3730:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.OscLinkProvider=void 0;const n=i(511),o=i(2585);let a=t.OscLinkProvider=class{constructor(e,t,i){this._bufferService=e,this._optionsService=t,this._oscLinkService=i}provideLinks(e,t){const i=this._bufferService.buffer.lines.get(e-1);if(!i)return void t(void 0);const s=[],r=this._optionsService.rawOptions.linkHandler,o=new n.CellData,a=i.getTrimmedLength();let c=-1,l=-1,d=!1;for(let t=0;tr?r.activate(e,t,n):h(0,t),hover:(e,t)=>r?.hover?.(e,t,n),leave:(e,t)=>r?.leave?.(e,t,n)})}d=!1,o.hasExtendedAttrs()&&o.extended.urlId?(l=t,c=o.extended.urlId):(l=-1,c=-1)}}t(s)}};function h(e,t){if(confirm(`Do you want to navigate to ${t}?\n\nWARNING: This link could potentially be dangerous`)){const e=window.open();if(e){try{e.opener=null}catch{}e.location.href=t}else console.warn("Opening link blocked as opener could not be cleared")}}t.OscLinkProvider=a=s([r(0,o.IBufferService),r(1,o.IOptionsService),r(2,o.IOscLinkService)],a)},6193:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.RenderDebouncer=void 0,t.RenderDebouncer=class{constructor(e,t){this._renderCallback=e,this._coreBrowserService=t,this._refreshCallbacks=[]}dispose(){this._animationFrame&&(this._coreBrowserService.window.cancelAnimationFrame(this._animationFrame),this._animationFrame=void 0)}addRefreshCallback(e){return this._refreshCallbacks.push(e),this._animationFrame||(this._animationFrame=this._coreBrowserService.window.requestAnimationFrame((()=>this._innerRefresh()))),this._animationFrame}refresh(e,t,i){this._rowCount=i,e=void 0!==e?e:0,t=void 0!==t?t:this._rowCount-1,this._rowStart=void 0!==this._rowStart?Math.min(this._rowStart,e):e,this._rowEnd=void 0!==this._rowEnd?Math.max(this._rowEnd,t):t,this._animationFrame||(this._animationFrame=this._coreBrowserService.window.requestAnimationFrame((()=>this._innerRefresh())))}_innerRefresh(){if(this._animationFrame=void 0,void 0===this._rowStart||void 0===this._rowEnd||void 0===this._rowCount)return void this._runRefreshCallbacks();const e=Math.max(this._rowStart,0),t=Math.min(this._rowEnd,this._rowCount-1);this._rowStart=void 0,this._rowEnd=void 0,this._renderCallback(e,t),this._runRefreshCallbacks()}_runRefreshCallbacks(){for(const e of this._refreshCallbacks)e(0);this._refreshCallbacks=[]}}},3236:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Terminal=void 0;const s=i(3614),r=i(3656),n=i(3551),o=i(9042),a=i(3730),h=i(1680),c=i(3107),l=i(5744),d=i(2950),_=i(1296),u=i(428),f=i(4269),v=i(5114),p=i(8934),g=i(3230),m=i(9312),S=i(4725),C=i(6731),b=i(8055),w=i(8969),y=i(8460),E=i(844),k=i(6114),L=i(8437),D=i(2584),R=i(7399),x=i(5941),A=i(9074),B=i(2585),T=i(5435),M=i(4567),O=i(779);class P extends w.CoreTerminal{get onFocus(){return this._onFocus.event}get onBlur(){return this._onBlur.event}get onA11yChar(){return this._onA11yCharEmitter.event}get onA11yTab(){return this._onA11yTabEmitter.event}get onWillOpen(){return this._onWillOpen.event}constructor(e={}){super(e),this.browser=k,this._keyDownHandled=!1,this._keyDownSeen=!1,this._keyPressHandled=!1,this._unprocessedDeadKey=!1,this._accessibilityManager=this.register(new E.MutableDisposable),this._onCursorMove=this.register(new y.EventEmitter),this.onCursorMove=this._onCursorMove.event,this._onKey=this.register(new y.EventEmitter),this.onKey=this._onKey.event,this._onRender=this.register(new y.EventEmitter),this.onRender=this._onRender.event,this._onSelectionChange=this.register(new y.EventEmitter),this.onSelectionChange=this._onSelectionChange.event,this._onTitleChange=this.register(new y.EventEmitter),this.onTitleChange=this._onTitleChange.event,this._onBell=this.register(new y.EventEmitter),this.onBell=this._onBell.event,this._onFocus=this.register(new y.EventEmitter),this._onBlur=this.register(new y.EventEmitter),this._onA11yCharEmitter=this.register(new y.EventEmitter),this._onA11yTabEmitter=this.register(new y.EventEmitter),this._onWillOpen=this.register(new y.EventEmitter),this._setup(),this._decorationService=this._instantiationService.createInstance(A.DecorationService),this._instantiationService.setService(B.IDecorationService,this._decorationService),this._linkProviderService=this._instantiationService.createInstance(O.LinkProviderService),this._instantiationService.setService(S.ILinkProviderService,this._linkProviderService),this._linkProviderService.registerLinkProvider(this._instantiationService.createInstance(a.OscLinkProvider)),this.register(this._inputHandler.onRequestBell((()=>this._onBell.fire()))),this.register(this._inputHandler.onRequestRefreshRows(((e,t)=>this.refresh(e,t)))),this.register(this._inputHandler.onRequestSendFocus((()=>this._reportFocus()))),this.register(this._inputHandler.onRequestReset((()=>this.reset()))),this.register(this._inputHandler.onRequestWindowsOptionsReport((e=>this._reportWindowsOptions(e)))),this.register(this._inputHandler.onColor((e=>this._handleColorEvent(e)))),this.register((0,y.forwardEvent)(this._inputHandler.onCursorMove,this._onCursorMove)),this.register((0,y.forwardEvent)(this._inputHandler.onTitleChange,this._onTitleChange)),this.register((0,y.forwardEvent)(this._inputHandler.onA11yChar,this._onA11yCharEmitter)),this.register((0,y.forwardEvent)(this._inputHandler.onA11yTab,this._onA11yTabEmitter)),this.register(this._bufferService.onResize((e=>this._afterResize(e.cols,e.rows)))),this.register((0,E.toDisposable)((()=>{this._customKeyEventHandler=void 0,this.element?.parentNode?.removeChild(this.element)})))}_handleColorEvent(e){if(this._themeService)for(const t of e){let e,i="";switch(t.index){case 256:e="foreground",i="10";break;case 257:e="background",i="11";break;case 258:e="cursor",i="12";break;default:e="ansi",i="4;"+t.index}switch(t.type){case 0:const s=b.color.toColorRGB("ansi"===e?this._themeService.colors.ansi[t.index]:this._themeService.colors[e]);this.coreService.triggerDataEvent(`${D.C0.ESC}]${i};${(0,x.toRgbString)(s)}${D.C1_ESCAPED.ST}`);break;case 1:if("ansi"===e)this._themeService.modifyColors((e=>e.ansi[t.index]=b.channels.toColor(...t.color)));else{const i=e;this._themeService.modifyColors((e=>e[i]=b.channels.toColor(...t.color)))}break;case 2:this._themeService.restoreColor(t.index)}}}_setup(){super._setup(),this._customKeyEventHandler=void 0}get buffer(){return this.buffers.active}focus(){this.textarea&&this.textarea.focus({preventScroll:!0})}_handleScreenReaderModeOptionChange(e){e?!this._accessibilityManager.value&&this._renderService&&(this._accessibilityManager.value=this._instantiationService.createInstance(M.AccessibilityManager,this)):this._accessibilityManager.clear()}_handleTextAreaFocus(e){this.coreService.decPrivateModes.sendFocus&&this.coreService.triggerDataEvent(D.C0.ESC+"[I"),this.element.classList.add("focus"),this._showCursor(),this._onFocus.fire()}blur(){return this.textarea?.blur()}_handleTextAreaBlur(){this.textarea.value="",this.refresh(this.buffer.y,this.buffer.y),this.coreService.decPrivateModes.sendFocus&&this.coreService.triggerDataEvent(D.C0.ESC+"[O"),this.element.classList.remove("focus"),this._onBlur.fire()}_syncTextArea(){if(!this.textarea||!this.buffer.isCursorInViewport||this._compositionHelper.isComposing||!this._renderService)return;const e=this.buffer.ybase+this.buffer.y,t=this.buffer.lines.get(e);if(!t)return;const i=Math.min(this.buffer.x,this.cols-1),s=this._renderService.dimensions.css.cell.height,r=t.getWidth(i),n=this._renderService.dimensions.css.cell.width*r,o=this.buffer.y*this._renderService.dimensions.css.cell.height,a=i*this._renderService.dimensions.css.cell.width;this.textarea.style.left=a+"px",this.textarea.style.top=o+"px",this.textarea.style.width=n+"px",this.textarea.style.height=s+"px",this.textarea.style.lineHeight=s+"px",this.textarea.style.zIndex="-5"}_initGlobal(){this._bindKeys(),this.register((0,r.addDisposableDomListener)(this.element,"copy",(e=>{this.hasSelection()&&(0,s.copyHandler)(e,this._selectionService)})));const e=e=>(0,s.handlePasteEvent)(e,this.textarea,this.coreService,this.optionsService);this.register((0,r.addDisposableDomListener)(this.textarea,"paste",e)),this.register((0,r.addDisposableDomListener)(this.element,"paste",e)),k.isFirefox?this.register((0,r.addDisposableDomListener)(this.element,"mousedown",(e=>{2===e.button&&(0,s.rightClickHandler)(e,this.textarea,this.screenElement,this._selectionService,this.options.rightClickSelectsWord)}))):this.register((0,r.addDisposableDomListener)(this.element,"contextmenu",(e=>{(0,s.rightClickHandler)(e,this.textarea,this.screenElement,this._selectionService,this.options.rightClickSelectsWord)}))),k.isLinux&&this.register((0,r.addDisposableDomListener)(this.element,"auxclick",(e=>{1===e.button&&(0,s.moveTextAreaUnderMouseCursor)(e,this.textarea,this.screenElement)})))}_bindKeys(){this.register((0,r.addDisposableDomListener)(this.textarea,"keyup",(e=>this._keyUp(e)),!0)),this.register((0,r.addDisposableDomListener)(this.textarea,"keydown",(e=>this._keyDown(e)),!0)),this.register((0,r.addDisposableDomListener)(this.textarea,"keypress",(e=>this._keyPress(e)),!0)),this.register((0,r.addDisposableDomListener)(this.textarea,"compositionstart",(()=>this._compositionHelper.compositionstart()))),this.register((0,r.addDisposableDomListener)(this.textarea,"compositionupdate",(e=>this._compositionHelper.compositionupdate(e)))),this.register((0,r.addDisposableDomListener)(this.textarea,"compositionend",(()=>this._compositionHelper.compositionend()))),this.register((0,r.addDisposableDomListener)(this.textarea,"input",(e=>this._inputEvent(e)),!0)),this.register(this.onRender((()=>this._compositionHelper.updateCompositionElements())))}open(e){if(!e)throw new Error("Terminal requires a parent element.");if(e.isConnected||this._logService.debug("Terminal.open was called on an element that was not attached to the DOM"),this.element?.ownerDocument.defaultView&&this._coreBrowserService)return void(this.element.ownerDocument.defaultView!==this._coreBrowserService.window&&(this._coreBrowserService.window=this.element.ownerDocument.defaultView));this._document=e.ownerDocument,this.options.documentOverride&&this.options.documentOverride instanceof Document&&(this._document=this.optionsService.rawOptions.documentOverride),this.element=this._document.createElement("div"),this.element.dir="ltr",this.element.classList.add("terminal"),this.element.classList.add("xterm"),e.appendChild(this.element);const t=this._document.createDocumentFragment();this._viewportElement=this._document.createElement("div"),this._viewportElement.classList.add("xterm-viewport"),t.appendChild(this._viewportElement),this._viewportScrollArea=this._document.createElement("div"),this._viewportScrollArea.classList.add("xterm-scroll-area"),this._viewportElement.appendChild(this._viewportScrollArea),this.screenElement=this._document.createElement("div"),this.screenElement.classList.add("xterm-screen"),this.register((0,r.addDisposableDomListener)(this.screenElement,"mousemove",(e=>this.updateCursorStyle(e)))),this._helperContainer=this._document.createElement("div"),this._helperContainer.classList.add("xterm-helpers"),this.screenElement.appendChild(this._helperContainer),t.appendChild(this.screenElement),this.textarea=this._document.createElement("textarea"),this.textarea.classList.add("xterm-helper-textarea"),this.textarea.setAttribute("aria-label",o.promptLabel),k.isChromeOS||this.textarea.setAttribute("aria-multiline","false"),this.textarea.setAttribute("autocorrect","off"),this.textarea.setAttribute("autocapitalize","off"),this.textarea.setAttribute("spellcheck","false"),this.textarea.tabIndex=0,this._coreBrowserService=this.register(this._instantiationService.createInstance(v.CoreBrowserService,this.textarea,e.ownerDocument.defaultView??window,this._document??"undefined"!=typeof window?window.document:null)),this._instantiationService.setService(S.ICoreBrowserService,this._coreBrowserService),this.register((0,r.addDisposableDomListener)(this.textarea,"focus",(e=>this._handleTextAreaFocus(e)))),this.register((0,r.addDisposableDomListener)(this.textarea,"blur",(()=>this._handleTextAreaBlur()))),this._helperContainer.appendChild(this.textarea),this._charSizeService=this._instantiationService.createInstance(u.CharSizeService,this._document,this._helperContainer),this._instantiationService.setService(S.ICharSizeService,this._charSizeService),this._themeService=this._instantiationService.createInstance(C.ThemeService),this._instantiationService.setService(S.IThemeService,this._themeService),this._characterJoinerService=this._instantiationService.createInstance(f.CharacterJoinerService),this._instantiationService.setService(S.ICharacterJoinerService,this._characterJoinerService),this._renderService=this.register(this._instantiationService.createInstance(g.RenderService,this.rows,this.screenElement)),this._instantiationService.setService(S.IRenderService,this._renderService),this.register(this._renderService.onRenderedViewportChange((e=>this._onRender.fire(e)))),this.onResize((e=>this._renderService.resize(e.cols,e.rows))),this._compositionView=this._document.createElement("div"),this._compositionView.classList.add("composition-view"),this._compositionHelper=this._instantiationService.createInstance(d.CompositionHelper,this.textarea,this._compositionView),this._helperContainer.appendChild(this._compositionView),this._mouseService=this._instantiationService.createInstance(p.MouseService),this._instantiationService.setService(S.IMouseService,this._mouseService),this.linkifier=this.register(this._instantiationService.createInstance(n.Linkifier,this.screenElement)),this.element.appendChild(t);try{this._onWillOpen.fire(this.element)}catch{}this._renderService.hasRenderer()||this._renderService.setRenderer(this._createRenderer()),this.viewport=this._instantiationService.createInstance(h.Viewport,this._viewportElement,this._viewportScrollArea),this.viewport.onRequestScrollLines((e=>this.scrollLines(e.amount,e.suppressScrollEvent,1))),this.register(this._inputHandler.onRequestSyncScrollBar((()=>this.viewport.syncScrollArea()))),this.register(this.viewport),this.register(this.onCursorMove((()=>{this._renderService.handleCursorMove(),this._syncTextArea()}))),this.register(this.onResize((()=>this._renderService.handleResize(this.cols,this.rows)))),this.register(this.onBlur((()=>this._renderService.handleBlur()))),this.register(this.onFocus((()=>this._renderService.handleFocus()))),this.register(this._renderService.onDimensionsChange((()=>this.viewport.syncScrollArea()))),this._selectionService=this.register(this._instantiationService.createInstance(m.SelectionService,this.element,this.screenElement,this.linkifier)),this._instantiationService.setService(S.ISelectionService,this._selectionService),this.register(this._selectionService.onRequestScrollLines((e=>this.scrollLines(e.amount,e.suppressScrollEvent)))),this.register(this._selectionService.onSelectionChange((()=>this._onSelectionChange.fire()))),this.register(this._selectionService.onRequestRedraw((e=>this._renderService.handleSelectionChanged(e.start,e.end,e.columnSelectMode)))),this.register(this._selectionService.onLinuxMouseSelection((e=>{this.textarea.value=e,this.textarea.focus(),this.textarea.select()}))),this.register(this._onScroll.event((e=>{this.viewport.syncScrollArea(),this._selectionService.refresh()}))),this.register((0,r.addDisposableDomListener)(this._viewportElement,"scroll",(()=>this._selectionService.refresh()))),this.register(this._instantiationService.createInstance(c.BufferDecorationRenderer,this.screenElement)),this.register((0,r.addDisposableDomListener)(this.element,"mousedown",(e=>this._selectionService.handleMouseDown(e)))),this.coreMouseService.areMouseEventsActive?(this._selectionService.disable(),this.element.classList.add("enable-mouse-events")):this._selectionService.enable(),this.options.screenReaderMode&&(this._accessibilityManager.value=this._instantiationService.createInstance(M.AccessibilityManager,this)),this.register(this.optionsService.onSpecificOptionChange("screenReaderMode",(e=>this._handleScreenReaderModeOptionChange(e)))),this.options.overviewRulerWidth&&(this._overviewRulerRenderer=this.register(this._instantiationService.createInstance(l.OverviewRulerRenderer,this._viewportElement,this.screenElement))),this.optionsService.onSpecificOptionChange("overviewRulerWidth",(e=>{!this._overviewRulerRenderer&&e&&this._viewportElement&&this.screenElement&&(this._overviewRulerRenderer=this.register(this._instantiationService.createInstance(l.OverviewRulerRenderer,this._viewportElement,this.screenElement)))})),this._charSizeService.measure(),this.refresh(0,this.rows-1),this._initGlobal(),this.bindMouse()}_createRenderer(){return this._instantiationService.createInstance(_.DomRenderer,this,this._document,this.element,this.screenElement,this._viewportElement,this._helperContainer,this.linkifier)}bindMouse(){const e=this,t=this.element;function i(t){const i=e._mouseService.getMouseReportCoords(t,e.screenElement);if(!i)return!1;let s,r;switch(t.overrideType||t.type){case"mousemove":r=32,void 0===t.buttons?(s=3,void 0!==t.button&&(s=t.button<3?t.button:3)):s=1&t.buttons?0:4&t.buttons?1:2&t.buttons?2:3;break;case"mouseup":r=0,s=t.button<3?t.button:3;break;case"mousedown":r=1,s=t.button<3?t.button:3;break;case"wheel":if(e._customWheelEventHandler&&!1===e._customWheelEventHandler(t))return!1;if(0===e.viewport.getLinesScrolled(t))return!1;r=t.deltaY<0?0:1,s=4;break;default:return!1}return!(void 0===r||void 0===s||s>4)&&e.coreMouseService.triggerMouseEvent({col:i.col,row:i.row,x:i.x,y:i.y,button:s,action:r,ctrl:t.ctrlKey,alt:t.altKey,shift:t.shiftKey})}const s={mouseup:null,wheel:null,mousedrag:null,mousemove:null},n={mouseup:e=>(i(e),e.buttons||(this._document.removeEventListener("mouseup",s.mouseup),s.mousedrag&&this._document.removeEventListener("mousemove",s.mousedrag)),this.cancel(e)),wheel:e=>(i(e),this.cancel(e,!0)),mousedrag:e=>{e.buttons&&i(e)},mousemove:e=>{e.buttons||i(e)}};this.register(this.coreMouseService.onProtocolChange((e=>{e?("debug"===this.optionsService.rawOptions.logLevel&&this._logService.debug("Binding to mouse events:",this.coreMouseService.explainEvents(e)),this.element.classList.add("enable-mouse-events"),this._selectionService.disable()):(this._logService.debug("Unbinding from mouse events."),this.element.classList.remove("enable-mouse-events"),this._selectionService.enable()),8&e?s.mousemove||(t.addEventListener("mousemove",n.mousemove),s.mousemove=n.mousemove):(t.removeEventListener("mousemove",s.mousemove),s.mousemove=null),16&e?s.wheel||(t.addEventListener("wheel",n.wheel,{passive:!1}),s.wheel=n.wheel):(t.removeEventListener("wheel",s.wheel),s.wheel=null),2&e?s.mouseup||(s.mouseup=n.mouseup):(this._document.removeEventListener("mouseup",s.mouseup),s.mouseup=null),4&e?s.mousedrag||(s.mousedrag=n.mousedrag):(this._document.removeEventListener("mousemove",s.mousedrag),s.mousedrag=null)}))),this.coreMouseService.activeProtocol=this.coreMouseService.activeProtocol,this.register((0,r.addDisposableDomListener)(t,"mousedown",(e=>{if(e.preventDefault(),this.focus(),this.coreMouseService.areMouseEventsActive&&!this._selectionService.shouldForceSelection(e))return i(e),s.mouseup&&this._document.addEventListener("mouseup",s.mouseup),s.mousedrag&&this._document.addEventListener("mousemove",s.mousedrag),this.cancel(e)}))),this.register((0,r.addDisposableDomListener)(t,"wheel",(e=>{if(!s.wheel){if(this._customWheelEventHandler&&!1===this._customWheelEventHandler(e))return!1;if(!this.buffer.hasScrollback){const t=this.viewport.getLinesScrolled(e);if(0===t)return;const i=D.C0.ESC+(this.coreService.decPrivateModes.applicationCursorKeys?"O":"[")+(e.deltaY<0?"A":"B");let s="";for(let e=0;e{if(!this.coreMouseService.areMouseEventsActive)return this.viewport.handleTouchStart(e),this.cancel(e)}),{passive:!0})),this.register((0,r.addDisposableDomListener)(t,"touchmove",(e=>{if(!this.coreMouseService.areMouseEventsActive)return this.viewport.handleTouchMove(e)?void 0:this.cancel(e)}),{passive:!1}))}refresh(e,t){this._renderService?.refreshRows(e,t)}updateCursorStyle(e){this._selectionService?.shouldColumnSelect(e)?this.element.classList.add("column-select"):this.element.classList.remove("column-select")}_showCursor(){this.coreService.isCursorInitialized||(this.coreService.isCursorInitialized=!0,this.refresh(this.buffer.y,this.buffer.y))}scrollLines(e,t,i=0){1===i?(super.scrollLines(e,t,i),this.refresh(0,this.rows-1)):this.viewport?.scrollLines(e)}paste(e){(0,s.paste)(e,this.textarea,this.coreService,this.optionsService)}attachCustomKeyEventHandler(e){this._customKeyEventHandler=e}attachCustomWheelEventHandler(e){this._customWheelEventHandler=e}registerLinkProvider(e){return this._linkProviderService.registerLinkProvider(e)}registerCharacterJoiner(e){if(!this._characterJoinerService)throw new Error("Terminal must be opened first");const t=this._characterJoinerService.register(e);return this.refresh(0,this.rows-1),t}deregisterCharacterJoiner(e){if(!this._characterJoinerService)throw new Error("Terminal must be opened first");this._characterJoinerService.deregister(e)&&this.refresh(0,this.rows-1)}get markers(){return this.buffer.markers}registerMarker(e){return this.buffer.addMarker(this.buffer.ybase+this.buffer.y+e)}registerDecoration(e){return this._decorationService.registerDecoration(e)}hasSelection(){return!!this._selectionService&&this._selectionService.hasSelection}select(e,t,i){this._selectionService.setSelection(e,t,i)}getSelection(){return this._selectionService?this._selectionService.selectionText:""}getSelectionPosition(){if(this._selectionService&&this._selectionService.hasSelection)return{start:{x:this._selectionService.selectionStart[0],y:this._selectionService.selectionStart[1]},end:{x:this._selectionService.selectionEnd[0],y:this._selectionService.selectionEnd[1]}}}clearSelection(){this._selectionService?.clearSelection()}selectAll(){this._selectionService?.selectAll()}selectLines(e,t){this._selectionService?.selectLines(e,t)}_keyDown(e){if(this._keyDownHandled=!1,this._keyDownSeen=!0,this._customKeyEventHandler&&!1===this._customKeyEventHandler(e))return!1;const t=this.browser.isMac&&this.options.macOptionIsMeta&&e.altKey;if(!t&&!this._compositionHelper.keydown(e))return this.options.scrollOnUserInput&&this.buffer.ybase!==this.buffer.ydisp&&this.scrollToBottom(),!1;t||"Dead"!==e.key&&"AltGraph"!==e.key||(this._unprocessedDeadKey=!0);const i=(0,R.evaluateKeyboardEvent)(e,this.coreService.decPrivateModes.applicationCursorKeys,this.browser.isMac,this.options.macOptionIsMeta);if(this.updateCursorStyle(e),3===i.type||2===i.type){const t=this.rows-1;return this.scrollLines(2===i.type?-t:t),this.cancel(e,!0)}return 1===i.type&&this.selectAll(),!!this._isThirdLevelShift(this.browser,e)||(i.cancel&&this.cancel(e,!0),!i.key||!!(e.key&&!e.ctrlKey&&!e.altKey&&!e.metaKey&&1===e.key.length&&e.key.charCodeAt(0)>=65&&e.key.charCodeAt(0)<=90)||(this._unprocessedDeadKey?(this._unprocessedDeadKey=!1,!0):(i.key!==D.C0.ETX&&i.key!==D.C0.CR||(this.textarea.value=""),this._onKey.fire({key:i.key,domEvent:e}),this._showCursor(),this.coreService.triggerDataEvent(i.key,!0),!this.optionsService.rawOptions.screenReaderMode||e.altKey||e.ctrlKey?this.cancel(e,!0):void(this._keyDownHandled=!0))))}_isThirdLevelShift(e,t){const i=e.isMac&&!this.options.macOptionIsMeta&&t.altKey&&!t.ctrlKey&&!t.metaKey||e.isWindows&&t.altKey&&t.ctrlKey&&!t.metaKey||e.isWindows&&t.getModifierState("AltGraph");return"keypress"===t.type?i:i&&(!t.keyCode||t.keyCode>47)}_keyUp(e){this._keyDownSeen=!1,this._customKeyEventHandler&&!1===this._customKeyEventHandler(e)||(function(e){return 16===e.keyCode||17===e.keyCode||18===e.keyCode}(e)||this.focus(),this.updateCursorStyle(e),this._keyPressHandled=!1)}_keyPress(e){let t;if(this._keyPressHandled=!1,this._keyDownHandled)return!1;if(this._customKeyEventHandler&&!1===this._customKeyEventHandler(e))return!1;if(this.cancel(e),e.charCode)t=e.charCode;else if(null===e.which||void 0===e.which)t=e.keyCode;else{if(0===e.which||0===e.charCode)return!1;t=e.which}return!(!t||(e.altKey||e.ctrlKey||e.metaKey)&&!this._isThirdLevelShift(this.browser,e)||(t=String.fromCharCode(t),this._onKey.fire({key:t,domEvent:e}),this._showCursor(),this.coreService.triggerDataEvent(t,!0),this._keyPressHandled=!0,this._unprocessedDeadKey=!1,0))}_inputEvent(e){if(e.data&&"insertText"===e.inputType&&(!e.composed||!this._keyDownSeen)&&!this.optionsService.rawOptions.screenReaderMode){if(this._keyPressHandled)return!1;this._unprocessedDeadKey=!1;const t=e.data;return this.coreService.triggerDataEvent(t,!0),this.cancel(e),!0}return!1}resize(e,t){e!==this.cols||t!==this.rows?super.resize(e,t):this._charSizeService&&!this._charSizeService.hasValidSize&&this._charSizeService.measure()}_afterResize(e,t){this._charSizeService?.measure(),this.viewport?.syncScrollArea(!0)}clear(){if(0!==this.buffer.ybase||0!==this.buffer.y){this.buffer.clearAllMarkers(),this.buffer.lines.set(0,this.buffer.lines.get(this.buffer.ybase+this.buffer.y)),this.buffer.lines.length=1,this.buffer.ydisp=0,this.buffer.ybase=0,this.buffer.y=0;for(let e=1;e{Object.defineProperty(t,"__esModule",{value:!0}),t.TimeBasedDebouncer=void 0,t.TimeBasedDebouncer=class{constructor(e,t=1e3){this._renderCallback=e,this._debounceThresholdMS=t,this._lastRefreshMs=0,this._additionalRefreshRequested=!1}dispose(){this._refreshTimeoutID&&clearTimeout(this._refreshTimeoutID)}refresh(e,t,i){this._rowCount=i,e=void 0!==e?e:0,t=void 0!==t?t:this._rowCount-1,this._rowStart=void 0!==this._rowStart?Math.min(this._rowStart,e):e,this._rowEnd=void 0!==this._rowEnd?Math.max(this._rowEnd,t):t;const s=Date.now();if(s-this._lastRefreshMs>=this._debounceThresholdMS)this._lastRefreshMs=s,this._innerRefresh();else if(!this._additionalRefreshRequested){const e=s-this._lastRefreshMs,t=this._debounceThresholdMS-e;this._additionalRefreshRequested=!0,this._refreshTimeoutID=window.setTimeout((()=>{this._lastRefreshMs=Date.now(),this._innerRefresh(),this._additionalRefreshRequested=!1,this._refreshTimeoutID=void 0}),t)}}_innerRefresh(){if(void 0===this._rowStart||void 0===this._rowEnd||void 0===this._rowCount)return;const e=Math.max(this._rowStart,0),t=Math.min(this._rowEnd,this._rowCount-1);this._rowStart=void 0,this._rowEnd=void 0,this._renderCallback(e,t)}}},1680:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.Viewport=void 0;const n=i(3656),o=i(4725),a=i(8460),h=i(844),c=i(2585);let l=t.Viewport=class extends h.Disposable{constructor(e,t,i,s,r,o,h,c){super(),this._viewportElement=e,this._scrollArea=t,this._bufferService=i,this._optionsService=s,this._charSizeService=r,this._renderService=o,this._coreBrowserService=h,this.scrollBarWidth=0,this._currentRowHeight=0,this._currentDeviceCellHeight=0,this._lastRecordedBufferLength=0,this._lastRecordedViewportHeight=0,this._lastRecordedBufferHeight=0,this._lastTouchY=0,this._lastScrollTop=0,this._wheelPartialScroll=0,this._refreshAnimationFrame=null,this._ignoreNextScrollEvent=!1,this._smoothScrollState={startTime:0,origin:-1,target:-1},this._onRequestScrollLines=this.register(new a.EventEmitter),this.onRequestScrollLines=this._onRequestScrollLines.event,this.scrollBarWidth=this._viewportElement.offsetWidth-this._scrollArea.offsetWidth||15,this.register((0,n.addDisposableDomListener)(this._viewportElement,"scroll",this._handleScroll.bind(this))),this._activeBuffer=this._bufferService.buffer,this.register(this._bufferService.buffers.onBufferActivate((e=>this._activeBuffer=e.activeBuffer))),this._renderDimensions=this._renderService.dimensions,this.register(this._renderService.onDimensionsChange((e=>this._renderDimensions=e))),this._handleThemeChange(c.colors),this.register(c.onChangeColors((e=>this._handleThemeChange(e)))),this.register(this._optionsService.onSpecificOptionChange("scrollback",(()=>this.syncScrollArea()))),setTimeout((()=>this.syncScrollArea()))}_handleThemeChange(e){this._viewportElement.style.backgroundColor=e.background.css}reset(){this._currentRowHeight=0,this._currentDeviceCellHeight=0,this._lastRecordedBufferLength=0,this._lastRecordedViewportHeight=0,this._lastRecordedBufferHeight=0,this._lastTouchY=0,this._lastScrollTop=0,this._coreBrowserService.window.requestAnimationFrame((()=>this.syncScrollArea()))}_refresh(e){if(e)return this._innerRefresh(),void(null!==this._refreshAnimationFrame&&this._coreBrowserService.window.cancelAnimationFrame(this._refreshAnimationFrame));null===this._refreshAnimationFrame&&(this._refreshAnimationFrame=this._coreBrowserService.window.requestAnimationFrame((()=>this._innerRefresh())))}_innerRefresh(){if(this._charSizeService.height>0){this._currentRowHeight=this._renderDimensions.device.cell.height/this._coreBrowserService.dpr,this._currentDeviceCellHeight=this._renderDimensions.device.cell.height,this._lastRecordedViewportHeight=this._viewportElement.offsetHeight;const e=Math.round(this._currentRowHeight*this._lastRecordedBufferLength)+(this._lastRecordedViewportHeight-this._renderDimensions.css.canvas.height);this._lastRecordedBufferHeight!==e&&(this._lastRecordedBufferHeight=e,this._scrollArea.style.height=this._lastRecordedBufferHeight+"px")}const e=this._bufferService.buffer.ydisp*this._currentRowHeight;this._viewportElement.scrollTop!==e&&(this._ignoreNextScrollEvent=!0,this._viewportElement.scrollTop=e),this._refreshAnimationFrame=null}syncScrollArea(e=!1){if(this._lastRecordedBufferLength!==this._bufferService.buffer.lines.length)return this._lastRecordedBufferLength=this._bufferService.buffer.lines.length,void this._refresh(e);this._lastRecordedViewportHeight===this._renderService.dimensions.css.canvas.height&&this._lastScrollTop===this._activeBuffer.ydisp*this._currentRowHeight&&this._renderDimensions.device.cell.height===this._currentDeviceCellHeight||this._refresh(e)}_handleScroll(e){if(this._lastScrollTop=this._viewportElement.scrollTop,!this._viewportElement.offsetParent)return;if(this._ignoreNextScrollEvent)return this._ignoreNextScrollEvent=!1,void this._onRequestScrollLines.fire({amount:0,suppressScrollEvent:!0});const t=Math.round(this._lastScrollTop/this._currentRowHeight)-this._bufferService.buffer.ydisp;this._onRequestScrollLines.fire({amount:t,suppressScrollEvent:!0})}_smoothScroll(){if(this._isDisposed||-1===this._smoothScrollState.origin||-1===this._smoothScrollState.target)return;const e=this._smoothScrollPercent();this._viewportElement.scrollTop=this._smoothScrollState.origin+Math.round(e*(this._smoothScrollState.target-this._smoothScrollState.origin)),e<1?this._coreBrowserService.window.requestAnimationFrame((()=>this._smoothScroll())):this._clearSmoothScrollState()}_smoothScrollPercent(){return this._optionsService.rawOptions.smoothScrollDuration&&this._smoothScrollState.startTime?Math.max(Math.min((Date.now()-this._smoothScrollState.startTime)/this._optionsService.rawOptions.smoothScrollDuration,1),0):1}_clearSmoothScrollState(){this._smoothScrollState.startTime=0,this._smoothScrollState.origin=-1,this._smoothScrollState.target=-1}_bubbleScroll(e,t){const i=this._viewportElement.scrollTop+this._lastRecordedViewportHeight;return!(t<0&&0!==this._viewportElement.scrollTop||t>0&&i0&&(i=e),s=""}}return{bufferElements:r,cursorElement:i}}getLinesScrolled(e){if(0===e.deltaY||e.shiftKey)return 0;let t=this._applyScrollModifier(e.deltaY,e);return e.deltaMode===WheelEvent.DOM_DELTA_PIXEL?(t/=this._currentRowHeight+0,this._wheelPartialScroll+=t,t=Math.floor(Math.abs(this._wheelPartialScroll))*(this._wheelPartialScroll>0?1:-1),this._wheelPartialScroll%=1):e.deltaMode===WheelEvent.DOM_DELTA_PAGE&&(t*=this._bufferService.rows),t}_applyScrollModifier(e,t){const i=this._optionsService.rawOptions.fastScrollModifier;return"alt"===i&&t.altKey||"ctrl"===i&&t.ctrlKey||"shift"===i&&t.shiftKey?e*this._optionsService.rawOptions.fastScrollSensitivity*this._optionsService.rawOptions.scrollSensitivity:e*this._optionsService.rawOptions.scrollSensitivity}handleTouchStart(e){this._lastTouchY=e.touches[0].pageY}handleTouchMove(e){const t=this._lastTouchY-e.touches[0].pageY;return this._lastTouchY=e.touches[0].pageY,0!==t&&(this._viewportElement.scrollTop+=t,this._bubbleScroll(e,t))}};t.Viewport=l=s([r(2,c.IBufferService),r(3,c.IOptionsService),r(4,o.ICharSizeService),r(5,o.IRenderService),r(6,o.ICoreBrowserService),r(7,o.IThemeService)],l)},3107:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.BufferDecorationRenderer=void 0;const n=i(4725),o=i(844),a=i(2585);let h=t.BufferDecorationRenderer=class extends o.Disposable{constructor(e,t,i,s,r){super(),this._screenElement=e,this._bufferService=t,this._coreBrowserService=i,this._decorationService=s,this._renderService=r,this._decorationElements=new Map,this._altBufferIsActive=!1,this._dimensionsChanged=!1,this._container=document.createElement("div"),this._container.classList.add("xterm-decoration-container"),this._screenElement.appendChild(this._container),this.register(this._renderService.onRenderedViewportChange((()=>this._doRefreshDecorations()))),this.register(this._renderService.onDimensionsChange((()=>{this._dimensionsChanged=!0,this._queueRefresh()}))),this.register(this._coreBrowserService.onDprChange((()=>this._queueRefresh()))),this.register(this._bufferService.buffers.onBufferActivate((()=>{this._altBufferIsActive=this._bufferService.buffer===this._bufferService.buffers.alt}))),this.register(this._decorationService.onDecorationRegistered((()=>this._queueRefresh()))),this.register(this._decorationService.onDecorationRemoved((e=>this._removeDecoration(e)))),this.register((0,o.toDisposable)((()=>{this._container.remove(),this._decorationElements.clear()})))}_queueRefresh(){void 0===this._animationFrame&&(this._animationFrame=this._renderService.addRefreshCallback((()=>{this._doRefreshDecorations(),this._animationFrame=void 0})))}_doRefreshDecorations(){for(const e of this._decorationService.decorations)this._renderDecoration(e);this._dimensionsChanged=!1}_renderDecoration(e){this._refreshStyle(e),this._dimensionsChanged&&this._refreshXPosition(e)}_createElement(e){const t=this._coreBrowserService.mainDocument.createElement("div");t.classList.add("xterm-decoration"),t.classList.toggle("xterm-decoration-top-layer","top"===e?.options?.layer),t.style.width=`${Math.round((e.options.width||1)*this._renderService.dimensions.css.cell.width)}px`,t.style.height=(e.options.height||1)*this._renderService.dimensions.css.cell.height+"px",t.style.top=(e.marker.line-this._bufferService.buffers.active.ydisp)*this._renderService.dimensions.css.cell.height+"px",t.style.lineHeight=`${this._renderService.dimensions.css.cell.height}px`;const i=e.options.x??0;return i&&i>this._bufferService.cols&&(t.style.display="none"),this._refreshXPosition(e,t),t}_refreshStyle(e){const t=e.marker.line-this._bufferService.buffers.active.ydisp;if(t<0||t>=this._bufferService.rows)e.element&&(e.element.style.display="none",e.onRenderEmitter.fire(e.element));else{let i=this._decorationElements.get(e);i||(i=this._createElement(e),e.element=i,this._decorationElements.set(e,i),this._container.appendChild(i),e.onDispose((()=>{this._decorationElements.delete(e),i.remove()}))),i.style.top=t*this._renderService.dimensions.css.cell.height+"px",i.style.display=this._altBufferIsActive?"none":"block",e.onRenderEmitter.fire(i)}}_refreshXPosition(e,t=e.element){if(!t)return;const i=e.options.x??0;"right"===(e.options.anchor||"left")?t.style.right=i?i*this._renderService.dimensions.css.cell.width+"px":"":t.style.left=i?i*this._renderService.dimensions.css.cell.width+"px":""}_removeDecoration(e){this._decorationElements.get(e)?.remove(),this._decorationElements.delete(e),e.dispose()}};t.BufferDecorationRenderer=h=s([r(1,a.IBufferService),r(2,n.ICoreBrowserService),r(3,a.IDecorationService),r(4,n.IRenderService)],h)},5871:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ColorZoneStore=void 0,t.ColorZoneStore=class{constructor(){this._zones=[],this._zonePool=[],this._zonePoolIndex=0,this._linePadding={full:0,left:0,center:0,right:0}}get zones(){return this._zonePool.length=Math.min(this._zonePool.length,this._zones.length),this._zones}clear(){this._zones.length=0,this._zonePoolIndex=0}addDecoration(e){if(e.options.overviewRulerOptions){for(const t of this._zones)if(t.color===e.options.overviewRulerOptions.color&&t.position===e.options.overviewRulerOptions.position){if(this._lineIntersectsZone(t,e.marker.line))return;if(this._lineAdjacentToZone(t,e.marker.line,e.options.overviewRulerOptions.position))return void this._addLineToZone(t,e.marker.line)}if(this._zonePoolIndex=e.startBufferLine&&t<=e.endBufferLine}_lineAdjacentToZone(e,t,i){return t>=e.startBufferLine-this._linePadding[i||"full"]&&t<=e.endBufferLine+this._linePadding[i||"full"]}_addLineToZone(e,t){e.startBufferLine=Math.min(e.startBufferLine,t),e.endBufferLine=Math.max(e.endBufferLine,t)}}},5744:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.OverviewRulerRenderer=void 0;const n=i(5871),o=i(4725),a=i(844),h=i(2585),c={full:0,left:0,center:0,right:0},l={full:0,left:0,center:0,right:0},d={full:0,left:0,center:0,right:0};let _=t.OverviewRulerRenderer=class extends a.Disposable{get _width(){return this._optionsService.options.overviewRulerWidth||0}constructor(e,t,i,s,r,o,h){super(),this._viewportElement=e,this._screenElement=t,this._bufferService=i,this._decorationService=s,this._renderService=r,this._optionsService=o,this._coreBrowserService=h,this._colorZoneStore=new n.ColorZoneStore,this._shouldUpdateDimensions=!0,this._shouldUpdateAnchor=!0,this._lastKnownBufferLength=0,this._canvas=this._coreBrowserService.mainDocument.createElement("canvas"),this._canvas.classList.add("xterm-decoration-overview-ruler"),this._refreshCanvasDimensions(),this._viewportElement.parentElement?.insertBefore(this._canvas,this._viewportElement);const c=this._canvas.getContext("2d");if(!c)throw new Error("Ctx cannot be null");this._ctx=c,this._registerDecorationListeners(),this._registerBufferChangeListeners(),this._registerDimensionChangeListeners(),this.register((0,a.toDisposable)((()=>{this._canvas?.remove()})))}_registerDecorationListeners(){this.register(this._decorationService.onDecorationRegistered((()=>this._queueRefresh(void 0,!0)))),this.register(this._decorationService.onDecorationRemoved((()=>this._queueRefresh(void 0,!0))))}_registerBufferChangeListeners(){this.register(this._renderService.onRenderedViewportChange((()=>this._queueRefresh()))),this.register(this._bufferService.buffers.onBufferActivate((()=>{this._canvas.style.display=this._bufferService.buffer===this._bufferService.buffers.alt?"none":"block"}))),this.register(this._bufferService.onScroll((()=>{this._lastKnownBufferLength!==this._bufferService.buffers.normal.lines.length&&(this._refreshDrawHeightConstants(),this._refreshColorZonePadding())})))}_registerDimensionChangeListeners(){this.register(this._renderService.onRender((()=>{this._containerHeight&&this._containerHeight===this._screenElement.clientHeight||(this._queueRefresh(!0),this._containerHeight=this._screenElement.clientHeight)}))),this.register(this._optionsService.onSpecificOptionChange("overviewRulerWidth",(()=>this._queueRefresh(!0)))),this.register(this._coreBrowserService.onDprChange((()=>this._queueRefresh(!0)))),this._queueRefresh(!0)}_refreshDrawConstants(){const e=Math.floor(this._canvas.width/3),t=Math.ceil(this._canvas.width/3);l.full=this._canvas.width,l.left=e,l.center=t,l.right=e,this._refreshDrawHeightConstants(),d.full=0,d.left=0,d.center=l.left,d.right=l.left+l.center}_refreshDrawHeightConstants(){c.full=Math.round(2*this._coreBrowserService.dpr);const e=this._canvas.height/this._bufferService.buffer.lines.length,t=Math.round(Math.max(Math.min(e,12),6)*this._coreBrowserService.dpr);c.left=t,c.center=t,c.right=t}_refreshColorZonePadding(){this._colorZoneStore.setPadding({full:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*c.full),left:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*c.left),center:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*c.center),right:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*c.right)}),this._lastKnownBufferLength=this._bufferService.buffers.normal.lines.length}_refreshCanvasDimensions(){this._canvas.style.width=`${this._width}px`,this._canvas.width=Math.round(this._width*this._coreBrowserService.dpr),this._canvas.style.height=`${this._screenElement.clientHeight}px`,this._canvas.height=Math.round(this._screenElement.clientHeight*this._coreBrowserService.dpr),this._refreshDrawConstants(),this._refreshColorZonePadding()}_refreshDecorations(){this._shouldUpdateDimensions&&this._refreshCanvasDimensions(),this._ctx.clearRect(0,0,this._canvas.width,this._canvas.height),this._colorZoneStore.clear();for(const e of this._decorationService.decorations)this._colorZoneStore.addDecoration(e);this._ctx.lineWidth=1;const e=this._colorZoneStore.zones;for(const t of e)"full"!==t.position&&this._renderColorZone(t);for(const t of e)"full"===t.position&&this._renderColorZone(t);this._shouldUpdateDimensions=!1,this._shouldUpdateAnchor=!1}_renderColorZone(e){this._ctx.fillStyle=e.color,this._ctx.fillRect(d[e.position||"full"],Math.round((this._canvas.height-1)*(e.startBufferLine/this._bufferService.buffers.active.lines.length)-c[e.position||"full"]/2),l[e.position||"full"],Math.round((this._canvas.height-1)*((e.endBufferLine-e.startBufferLine)/this._bufferService.buffers.active.lines.length)+c[e.position||"full"]))}_queueRefresh(e,t){this._shouldUpdateDimensions=e||this._shouldUpdateDimensions,this._shouldUpdateAnchor=t||this._shouldUpdateAnchor,void 0===this._animationFrame&&(this._animationFrame=this._coreBrowserService.window.requestAnimationFrame((()=>{this._refreshDecorations(),this._animationFrame=void 0})))}};t.OverviewRulerRenderer=_=s([r(2,h.IBufferService),r(3,h.IDecorationService),r(4,o.IRenderService),r(5,h.IOptionsService),r(6,o.ICoreBrowserService)],_)},2950:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CompositionHelper=void 0;const n=i(4725),o=i(2585),a=i(2584);let h=t.CompositionHelper=class{get isComposing(){return this._isComposing}constructor(e,t,i,s,r,n){this._textarea=e,this._compositionView=t,this._bufferService=i,this._optionsService=s,this._coreService=r,this._renderService=n,this._isComposing=!1,this._isSendingComposition=!1,this._compositionPosition={start:0,end:0},this._dataAlreadySent=""}compositionstart(){this._isComposing=!0,this._compositionPosition.start=this._textarea.value.length,this._compositionView.textContent="",this._dataAlreadySent="",this._compositionView.classList.add("active")}compositionupdate(e){this._compositionView.textContent=e.data,this.updateCompositionElements(),setTimeout((()=>{this._compositionPosition.end=this._textarea.value.length}),0)}compositionend(){this._finalizeComposition(!0)}keydown(e){if(this._isComposing||this._isSendingComposition){if(229===e.keyCode)return!1;if(16===e.keyCode||17===e.keyCode||18===e.keyCode)return!1;this._finalizeComposition(!1)}return 229!==e.keyCode||(this._handleAnyTextareaChanges(),!1)}_finalizeComposition(e){if(this._compositionView.classList.remove("active"),this._isComposing=!1,e){const e={start:this._compositionPosition.start,end:this._compositionPosition.end};this._isSendingComposition=!0,setTimeout((()=>{if(this._isSendingComposition){let t;this._isSendingComposition=!1,e.start+=this._dataAlreadySent.length,t=this._isComposing?this._textarea.value.substring(e.start,e.end):this._textarea.value.substring(e.start),t.length>0&&this._coreService.triggerDataEvent(t,!0)}}),0)}else{this._isSendingComposition=!1;const e=this._textarea.value.substring(this._compositionPosition.start,this._compositionPosition.end);this._coreService.triggerDataEvent(e,!0)}}_handleAnyTextareaChanges(){const e=this._textarea.value;setTimeout((()=>{if(!this._isComposing){const t=this._textarea.value,i=t.replace(e,"");this._dataAlreadySent=i,t.length>e.length?this._coreService.triggerDataEvent(i,!0):t.lengththis.updateCompositionElements(!0)),0)}}};t.CompositionHelper=h=s([r(2,o.IBufferService),r(3,o.IOptionsService),r(4,o.ICoreService),r(5,n.IRenderService)],h)},9806:(e,t)=>{function i(e,t,i){const s=i.getBoundingClientRect(),r=e.getComputedStyle(i),n=parseInt(r.getPropertyValue("padding-left")),o=parseInt(r.getPropertyValue("padding-top"));return[t.clientX-s.left-n,t.clientY-s.top-o]}Object.defineProperty(t,"__esModule",{value:!0}),t.getCoords=t.getCoordsRelativeToElement=void 0,t.getCoordsRelativeToElement=i,t.getCoords=function(e,t,s,r,n,o,a,h,c){if(!o)return;const l=i(e,t,s);return l?(l[0]=Math.ceil((l[0]+(c?a/2:0))/a),l[1]=Math.ceil(l[1]/h),l[0]=Math.min(Math.max(l[0],1),r+(c?1:0)),l[1]=Math.min(Math.max(l[1],1),n),l):void 0}},9504:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.moveToCellSequence=void 0;const s=i(2584);function r(e,t,i,s){const r=e-n(e,i),a=t-n(t,i),l=Math.abs(r-a)-function(e,t,i){let s=0;const r=e-n(e,i),a=t-n(t,i);for(let n=0;n=0&&et?"A":"B"}function a(e,t,i,s,r,n){let o=e,a=t,h="";for(;o!==i||a!==s;)o+=r?1:-1,r&&o>n.cols-1?(h+=n.buffer.translateBufferLineToString(a,!1,e,o),o=0,e=0,a++):!r&&o<0&&(h+=n.buffer.translateBufferLineToString(a,!1,0,e+1),o=n.cols-1,e=o,a--);return h+n.buffer.translateBufferLineToString(a,!1,e,o)}function h(e,t){const i=t?"O":"[";return s.C0.ESC+i+e}function c(e,t){e=Math.floor(e);let i="";for(let s=0;s0?s-n(s,o):t;const _=s,u=function(e,t,i,s,o,a){let h;return h=r(i,s,o,a).length>0?s-n(s,o):t,e=i&&he?"D":"C",c(Math.abs(o-e),h(d,s));d=l>t?"D":"C";const _=Math.abs(l-t);return c(function(e,t){return t.cols-e}(l>t?e:o,i)+(_-1)*i.cols+1+((l>t?o:e)-1),h(d,s))}},1296:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.DomRenderer=void 0;const n=i(3787),o=i(2550),a=i(2223),h=i(6171),c=i(6052),l=i(4725),d=i(8055),_=i(8460),u=i(844),f=i(2585),v="xterm-dom-renderer-owner-",p="xterm-rows",g="xterm-fg-",m="xterm-bg-",S="xterm-focus",C="xterm-selection";let b=1,w=t.DomRenderer=class extends u.Disposable{constructor(e,t,i,s,r,a,l,d,f,g,m,S,w){super(),this._terminal=e,this._document=t,this._element=i,this._screenElement=s,this._viewportElement=r,this._helperContainer=a,this._linkifier2=l,this._charSizeService=f,this._optionsService=g,this._bufferService=m,this._coreBrowserService=S,this._themeService=w,this._terminalClass=b++,this._rowElements=[],this._selectionRenderModel=(0,c.createSelectionRenderModel)(),this.onRequestRedraw=this.register(new _.EventEmitter).event,this._rowContainer=this._document.createElement("div"),this._rowContainer.classList.add(p),this._rowContainer.style.lineHeight="normal",this._rowContainer.setAttribute("aria-hidden","true"),this._refreshRowElements(this._bufferService.cols,this._bufferService.rows),this._selectionContainer=this._document.createElement("div"),this._selectionContainer.classList.add(C),this._selectionContainer.setAttribute("aria-hidden","true"),this.dimensions=(0,h.createRenderDimensions)(),this._updateDimensions(),this.register(this._optionsService.onOptionChange((()=>this._handleOptionsChanged()))),this.register(this._themeService.onChangeColors((e=>this._injectCss(e)))),this._injectCss(this._themeService.colors),this._rowFactory=d.createInstance(n.DomRendererRowFactory,document),this._element.classList.add(v+this._terminalClass),this._screenElement.appendChild(this._rowContainer),this._screenElement.appendChild(this._selectionContainer),this.register(this._linkifier2.onShowLinkUnderline((e=>this._handleLinkHover(e)))),this.register(this._linkifier2.onHideLinkUnderline((e=>this._handleLinkLeave(e)))),this.register((0,u.toDisposable)((()=>{this._element.classList.remove(v+this._terminalClass),this._rowContainer.remove(),this._selectionContainer.remove(),this._widthCache.dispose(),this._themeStyleElement.remove(),this._dimensionsStyleElement.remove()}))),this._widthCache=new o.WidthCache(this._document,this._helperContainer),this._widthCache.setFont(this._optionsService.rawOptions.fontFamily,this._optionsService.rawOptions.fontSize,this._optionsService.rawOptions.fontWeight,this._optionsService.rawOptions.fontWeightBold),this._setDefaultSpacing()}_updateDimensions(){const e=this._coreBrowserService.dpr;this.dimensions.device.char.width=this._charSizeService.width*e,this.dimensions.device.char.height=Math.ceil(this._charSizeService.height*e),this.dimensions.device.cell.width=this.dimensions.device.char.width+Math.round(this._optionsService.rawOptions.letterSpacing),this.dimensions.device.cell.height=Math.floor(this.dimensions.device.char.height*this._optionsService.rawOptions.lineHeight),this.dimensions.device.char.left=0,this.dimensions.device.char.top=0,this.dimensions.device.canvas.width=this.dimensions.device.cell.width*this._bufferService.cols,this.dimensions.device.canvas.height=this.dimensions.device.cell.height*this._bufferService.rows,this.dimensions.css.canvas.width=Math.round(this.dimensions.device.canvas.width/e),this.dimensions.css.canvas.height=Math.round(this.dimensions.device.canvas.height/e),this.dimensions.css.cell.width=this.dimensions.css.canvas.width/this._bufferService.cols,this.dimensions.css.cell.height=this.dimensions.css.canvas.height/this._bufferService.rows;for(const e of this._rowElements)e.style.width=`${this.dimensions.css.canvas.width}px`,e.style.height=`${this.dimensions.css.cell.height}px`,e.style.lineHeight=`${this.dimensions.css.cell.height}px`,e.style.overflow="hidden";this._dimensionsStyleElement||(this._dimensionsStyleElement=this._document.createElement("style"),this._screenElement.appendChild(this._dimensionsStyleElement));const t=`${this._terminalSelector} .${p} span { display: inline-block; height: 100%; vertical-align: top;}`;this._dimensionsStyleElement.textContent=t,this._selectionContainer.style.height=this._viewportElement.style.height,this._screenElement.style.width=`${this.dimensions.css.canvas.width}px`,this._screenElement.style.height=`${this.dimensions.css.canvas.height}px`}_injectCss(e){this._themeStyleElement||(this._themeStyleElement=this._document.createElement("style"),this._screenElement.appendChild(this._themeStyleElement));let t=`${this._terminalSelector} .${p} { color: ${e.foreground.css}; font-family: ${this._optionsService.rawOptions.fontFamily}; font-size: ${this._optionsService.rawOptions.fontSize}px; font-kerning: none; white-space: pre}`;t+=`${this._terminalSelector} .${p} .xterm-dim { color: ${d.color.multiplyOpacity(e.foreground,.5).css};}`,t+=`${this._terminalSelector} span:not(.xterm-bold) { font-weight: ${this._optionsService.rawOptions.fontWeight};}${this._terminalSelector} span.xterm-bold { font-weight: ${this._optionsService.rawOptions.fontWeightBold};}${this._terminalSelector} span.xterm-italic { font-style: italic;}`,t+="@keyframes blink_box_shadow_"+this._terminalClass+" { 50% { border-bottom-style: hidden; }}",t+="@keyframes blink_block_"+this._terminalClass+" { 0% {"+` background-color: ${e.cursor.css};`+` color: ${e.cursorAccent.css}; } 50% { background-color: inherit;`+` color: ${e.cursor.css}; }}`,t+=`${this._terminalSelector} .${p}.${S} .xterm-cursor.xterm-cursor-blink:not(.xterm-cursor-block) { animation: blink_box_shadow_`+this._terminalClass+" 1s step-end infinite;}"+`${this._terminalSelector} .${p}.${S} .xterm-cursor.xterm-cursor-blink.xterm-cursor-block { animation: blink_block_`+this._terminalClass+" 1s step-end infinite;}"+`${this._terminalSelector} .${p} .xterm-cursor.xterm-cursor-block {`+` background-color: ${e.cursor.css} !important;`+` color: ${e.cursorAccent.css} !important;}`+`${this._terminalSelector} .${p} .xterm-cursor.xterm-cursor-outline {`+` outline: 1px solid ${e.cursor.css}; outline-offset: -1px;}`+`${this._terminalSelector} .${p} .xterm-cursor.xterm-cursor-bar {`+` box-shadow: ${this._optionsService.rawOptions.cursorWidth}px 0 0 ${e.cursor.css} inset;}`+`${this._terminalSelector} .${p} .xterm-cursor.xterm-cursor-underline {`+` border-bottom: 1px ${e.cursor.css}; border-bottom-style: solid; height: calc(100% - 1px);}`,t+=`${this._terminalSelector} .${C} { position: absolute; top: 0; left: 0; z-index: 1; pointer-events: none;}${this._terminalSelector}.focus .${C} div { position: absolute; background-color: ${e.selectionBackgroundOpaque.css};}${this._terminalSelector} .${C} div { position: absolute; background-color: ${e.selectionInactiveBackgroundOpaque.css};}`;for(const[i,s]of e.ansi.entries())t+=`${this._terminalSelector} .${g}${i} { color: ${s.css}; }${this._terminalSelector} .${g}${i}.xterm-dim { color: ${d.color.multiplyOpacity(s,.5).css}; }${this._terminalSelector} .${m}${i} { background-color: ${s.css}; }`;t+=`${this._terminalSelector} .${g}${a.INVERTED_DEFAULT_COLOR} { color: ${d.color.opaque(e.background).css}; }${this._terminalSelector} .${g}${a.INVERTED_DEFAULT_COLOR}.xterm-dim { color: ${d.color.multiplyOpacity(d.color.opaque(e.background),.5).css}; }${this._terminalSelector} .${m}${a.INVERTED_DEFAULT_COLOR} { background-color: ${e.foreground.css}; }`,this._themeStyleElement.textContent=t}_setDefaultSpacing(){const e=this.dimensions.css.cell.width-this._widthCache.get("W",!1,!1);this._rowContainer.style.letterSpacing=`${e}px`,this._rowFactory.defaultSpacing=e}handleDevicePixelRatioChange(){this._updateDimensions(),this._widthCache.clear(),this._setDefaultSpacing()}_refreshRowElements(e,t){for(let e=this._rowElements.length;e<=t;e++){const e=this._document.createElement("div");this._rowContainer.appendChild(e),this._rowElements.push(e)}for(;this._rowElements.length>t;)this._rowContainer.removeChild(this._rowElements.pop())}handleResize(e,t){this._refreshRowElements(e,t),this._updateDimensions(),this.handleSelectionChanged(this._selectionRenderModel.selectionStart,this._selectionRenderModel.selectionEnd,this._selectionRenderModel.columnSelectMode)}handleCharSizeChanged(){this._updateDimensions(),this._widthCache.clear(),this._setDefaultSpacing()}handleBlur(){this._rowContainer.classList.remove(S),this.renderRows(0,this._bufferService.rows-1)}handleFocus(){this._rowContainer.classList.add(S),this.renderRows(this._bufferService.buffer.y,this._bufferService.buffer.y)}handleSelectionChanged(e,t,i){if(this._selectionContainer.replaceChildren(),this._rowFactory.handleSelectionChanged(e,t,i),this.renderRows(0,this._bufferService.rows-1),!e||!t)return;this._selectionRenderModel.update(this._terminal,e,t,i);const s=this._selectionRenderModel.viewportStartRow,r=this._selectionRenderModel.viewportEndRow,n=this._selectionRenderModel.viewportCappedStartRow,o=this._selectionRenderModel.viewportCappedEndRow;if(n>=this._bufferService.rows||o<0)return;const a=this._document.createDocumentFragment();if(i){const i=e[0]>t[0];a.appendChild(this._createSelectionElement(n,i?t[0]:e[0],i?e[0]:t[0],o-n+1))}else{const i=s===n?e[0]:0,h=n===r?t[0]:this._bufferService.cols;a.appendChild(this._createSelectionElement(n,i,h));const c=o-n-1;if(a.appendChild(this._createSelectionElement(n+1,0,this._bufferService.cols,c)),n!==o){const e=r===o?t[0]:this._bufferService.cols;a.appendChild(this._createSelectionElement(o,0,e))}}this._selectionContainer.appendChild(a)}_createSelectionElement(e,t,i,s=1){const r=this._document.createElement("div"),n=t*this.dimensions.css.cell.width;let o=this.dimensions.css.cell.width*(i-t);return n+o>this.dimensions.css.canvas.width&&(o=this.dimensions.css.canvas.width-n),r.style.height=s*this.dimensions.css.cell.height+"px",r.style.top=e*this.dimensions.css.cell.height+"px",r.style.left=`${n}px`,r.style.width=`${o}px`,r}handleCursorMove(){}_handleOptionsChanged(){this._updateDimensions(),this._injectCss(this._themeService.colors),this._widthCache.setFont(this._optionsService.rawOptions.fontFamily,this._optionsService.rawOptions.fontSize,this._optionsService.rawOptions.fontWeight,this._optionsService.rawOptions.fontWeightBold),this._setDefaultSpacing()}clear(){for(const e of this._rowElements)e.replaceChildren()}renderRows(e,t){const i=this._bufferService.buffer,s=i.ybase+i.y,r=Math.min(i.x,this._bufferService.cols-1),n=this._optionsService.rawOptions.cursorBlink,o=this._optionsService.rawOptions.cursorStyle,a=this._optionsService.rawOptions.cursorInactiveStyle;for(let h=e;h<=t;h++){const e=h+i.ydisp,t=this._rowElements[h],c=i.lines.get(e);if(!t||!c)break;t.replaceChildren(...this._rowFactory.createRow(c,e,e===s,o,a,r,n,this.dimensions.css.cell.width,this._widthCache,-1,-1))}}get _terminalSelector(){return`.${v}${this._terminalClass}`}_handleLinkHover(e){this._setCellUnderline(e.x1,e.x2,e.y1,e.y2,e.cols,!0)}_handleLinkLeave(e){this._setCellUnderline(e.x1,e.x2,e.y1,e.y2,e.cols,!1)}_setCellUnderline(e,t,i,s,r,n){i<0&&(e=0),s<0&&(t=0);const o=this._bufferService.rows-1;i=Math.max(Math.min(i,o),0),s=Math.max(Math.min(s,o),0),r=Math.min(r,this._bufferService.cols);const a=this._bufferService.buffer,h=a.ybase+a.y,c=Math.min(a.x,r-1),l=this._optionsService.rawOptions.cursorBlink,d=this._optionsService.rawOptions.cursorStyle,_=this._optionsService.rawOptions.cursorInactiveStyle;for(let o=i;o<=s;++o){const u=o+a.ydisp,f=this._rowElements[o],v=a.lines.get(u);if(!f||!v)break;f.replaceChildren(...this._rowFactory.createRow(v,u,u===h,d,_,c,l,this.dimensions.css.cell.width,this._widthCache,n?o===i?e:0:-1,n?(o===s?t:r)-1:-1))}}};t.DomRenderer=w=s([r(7,f.IInstantiationService),r(8,l.ICharSizeService),r(9,f.IOptionsService),r(10,f.IBufferService),r(11,l.ICoreBrowserService),r(12,l.IThemeService)],w)},3787:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.DomRendererRowFactory=void 0;const n=i(2223),o=i(643),a=i(511),h=i(2585),c=i(8055),l=i(4725),d=i(4269),_=i(6171),u=i(3734);let f=t.DomRendererRowFactory=class{constructor(e,t,i,s,r,n,o){this._document=e,this._characterJoinerService=t,this._optionsService=i,this._coreBrowserService=s,this._coreService=r,this._decorationService=n,this._themeService=o,this._workCell=new a.CellData,this._columnSelectMode=!1,this.defaultSpacing=0}handleSelectionChanged(e,t,i){this._selectionStart=e,this._selectionEnd=t,this._columnSelectMode=i}createRow(e,t,i,s,r,a,h,l,_,f,p){const g=[],m=this._characterJoinerService.getJoinedCharacters(t),S=this._themeService.colors;let C,b=e.getNoBgTrimmedLength();i&&b0&&M===m[0][0]){O=!0;const t=m.shift();I=new d.JoinedCellData(this._workCell,e.translateToString(!0,t[0],t[1]),t[1]-t[0]),P=t[1]-1,b=I.getWidth()}const H=this._isCellInSelection(M,t),F=i&&M===a,W=T&&M>=f&&M<=p;let U=!1;this._decorationService.forEachDecorationAtCell(M,t,void 0,(e=>{U=!0}));let N=I.getChars()||o.WHITESPACE_CELL_CHAR;if(" "===N&&(I.isUnderline()||I.isOverline())&&(N=" "),A=b*l-_.get(N,I.isBold(),I.isItalic()),C){if(w&&(H&&x||!H&&!x&&I.bg===E)&&(H&&x&&S.selectionForeground||I.fg===k)&&I.extended.ext===L&&W===D&&A===R&&!F&&!O&&!U){I.isInvisible()?y+=o.WHITESPACE_CELL_CHAR:y+=N,w++;continue}w&&(C.textContent=y),C=this._document.createElement("span"),w=0,y=""}else C=this._document.createElement("span");if(E=I.bg,k=I.fg,L=I.extended.ext,D=W,R=A,x=H,O&&a>=M&&a<=P&&(a=M),!this._coreService.isCursorHidden&&F&&this._coreService.isCursorInitialized)if(B.push("xterm-cursor"),this._coreBrowserService.isFocused)h&&B.push("xterm-cursor-blink"),B.push("bar"===s?"xterm-cursor-bar":"underline"===s?"xterm-cursor-underline":"xterm-cursor-block");else if(r)switch(r){case"outline":B.push("xterm-cursor-outline");break;case"block":B.push("xterm-cursor-block");break;case"bar":B.push("xterm-cursor-bar");break;case"underline":B.push("xterm-cursor-underline")}if(I.isBold()&&B.push("xterm-bold"),I.isItalic()&&B.push("xterm-italic"),I.isDim()&&B.push("xterm-dim"),y=I.isInvisible()?o.WHITESPACE_CELL_CHAR:I.getChars()||o.WHITESPACE_CELL_CHAR,I.isUnderline()&&(B.push(`xterm-underline-${I.extended.underlineStyle}`)," "===y&&(y=" "),!I.isUnderlineColorDefault()))if(I.isUnderlineColorRGB())C.style.textDecorationColor=`rgb(${u.AttributeData.toColorRGB(I.getUnderlineColor()).join(",")})`;else{let e=I.getUnderlineColor();this._optionsService.rawOptions.drawBoldTextInBrightColors&&I.isBold()&&e<8&&(e+=8),C.style.textDecorationColor=S.ansi[e].css}I.isOverline()&&(B.push("xterm-overline")," "===y&&(y=" ")),I.isStrikethrough()&&B.push("xterm-strikethrough"),W&&(C.style.textDecoration="underline");let $=I.getFgColor(),j=I.getFgColorMode(),z=I.getBgColor(),K=I.getBgColorMode();const q=!!I.isInverse();if(q){const e=$;$=z,z=e;const t=j;j=K,K=t}let V,G,X,J=!1;switch(this._decorationService.forEachDecorationAtCell(M,t,void 0,(e=>{"top"!==e.options.layer&&J||(e.backgroundColorRGB&&(K=50331648,z=e.backgroundColorRGB.rgba>>8&16777215,V=e.backgroundColorRGB),e.foregroundColorRGB&&(j=50331648,$=e.foregroundColorRGB.rgba>>8&16777215,G=e.foregroundColorRGB),J="top"===e.options.layer)})),!J&&H&&(V=this._coreBrowserService.isFocused?S.selectionBackgroundOpaque:S.selectionInactiveBackgroundOpaque,z=V.rgba>>8&16777215,K=50331648,J=!0,S.selectionForeground&&(j=50331648,$=S.selectionForeground.rgba>>8&16777215,G=S.selectionForeground)),J&&B.push("xterm-decoration-top"),K){case 16777216:case 33554432:X=S.ansi[z],B.push(`xterm-bg-${z}`);break;case 50331648:X=c.channels.toColor(z>>16,z>>8&255,255&z),this._addStyle(C,`background-color:#${v((z>>>0).toString(16),"0",6)}`);break;default:q?(X=S.foreground,B.push(`xterm-bg-${n.INVERTED_DEFAULT_COLOR}`)):X=S.background}switch(V||I.isDim()&&(V=c.color.multiplyOpacity(X,.5)),j){case 16777216:case 33554432:I.isBold()&&$<8&&this._optionsService.rawOptions.drawBoldTextInBrightColors&&($+=8),this._applyMinimumContrast(C,X,S.ansi[$],I,V,void 0)||B.push(`xterm-fg-${$}`);break;case 50331648:const e=c.channels.toColor($>>16&255,$>>8&255,255&$);this._applyMinimumContrast(C,X,e,I,V,G)||this._addStyle(C,`color:#${v($.toString(16),"0",6)}`);break;default:this._applyMinimumContrast(C,X,S.foreground,I,V,G)||q&&B.push(`xterm-fg-${n.INVERTED_DEFAULT_COLOR}`)}B.length&&(C.className=B.join(" "),B.length=0),F||O||U?C.textContent=y:w++,A!==this.defaultSpacing&&(C.style.letterSpacing=`${A}px`),g.push(C),M=P}return C&&w&&(C.textContent=y),g}_applyMinimumContrast(e,t,i,s,r,n){if(1===this._optionsService.rawOptions.minimumContrastRatio||(0,_.treatGlyphAsBackgroundColor)(s.getCode()))return!1;const o=this._getContrastCache(s);let a;if(r||n||(a=o.getColor(t.rgba,i.rgba)),void 0===a){const e=this._optionsService.rawOptions.minimumContrastRatio/(s.isDim()?2:1);a=c.color.ensureContrastRatio(r||t,n||i,e),o.setColor((r||t).rgba,(n||i).rgba,a??null)}return!!a&&(this._addStyle(e,`color:${a.css}`),!0)}_getContrastCache(e){return e.isDim()?this._themeService.colors.halfContrastCache:this._themeService.colors.contrastCache}_addStyle(e,t){e.setAttribute("style",`${e.getAttribute("style")||""}${t};`)}_isCellInSelection(e,t){const i=this._selectionStart,s=this._selectionEnd;return!(!i||!s)&&(this._columnSelectMode?i[0]<=s[0]?e>=i[0]&&t>=i[1]&&e=i[1]&&e>=s[0]&&t<=s[1]:t>i[1]&&t=i[0]&&e=i[0])}};function v(e,t,i){for(;e.length{Object.defineProperty(t,"__esModule",{value:!0}),t.WidthCache=void 0,t.WidthCache=class{constructor(e,t){this._flat=new Float32Array(256),this._font="",this._fontSize=0,this._weight="normal",this._weightBold="bold",this._measureElements=[],this._container=e.createElement("div"),this._container.classList.add("xterm-width-cache-measure-container"),this._container.setAttribute("aria-hidden","true"),this._container.style.whiteSpace="pre",this._container.style.fontKerning="none";const i=e.createElement("span");i.classList.add("xterm-char-measure-element");const s=e.createElement("span");s.classList.add("xterm-char-measure-element"),s.style.fontWeight="bold";const r=e.createElement("span");r.classList.add("xterm-char-measure-element"),r.style.fontStyle="italic";const n=e.createElement("span");n.classList.add("xterm-char-measure-element"),n.style.fontWeight="bold",n.style.fontStyle="italic",this._measureElements=[i,s,r,n],this._container.appendChild(i),this._container.appendChild(s),this._container.appendChild(r),this._container.appendChild(n),t.appendChild(this._container),this.clear()}dispose(){this._container.remove(),this._measureElements.length=0,this._holey=void 0}clear(){this._flat.fill(-9999),this._holey=new Map}setFont(e,t,i,s){e===this._font&&t===this._fontSize&&i===this._weight&&s===this._weightBold||(this._font=e,this._fontSize=t,this._weight=i,this._weightBold=s,this._container.style.fontFamily=this._font,this._container.style.fontSize=`${this._fontSize}px`,this._measureElements[0].style.fontWeight=`${i}`,this._measureElements[1].style.fontWeight=`${s}`,this._measureElements[2].style.fontWeight=`${i}`,this._measureElements[3].style.fontWeight=`${s}`,this.clear())}get(e,t,i){let s=0;if(!t&&!i&&1===e.length&&(s=e.charCodeAt(0))<256){if(-9999!==this._flat[s])return this._flat[s];const t=this._measure(e,0);return t>0&&(this._flat[s]=t),t}let r=e;t&&(r+="B"),i&&(r+="I");let n=this._holey.get(r);if(void 0===n){let s=0;t&&(s|=1),i&&(s|=2),n=this._measure(e,s),n>0&&this._holey.set(r,n)}return n}_measure(e,t){const i=this._measureElements[t];return i.textContent=e.repeat(32),i.offsetWidth/32}}},2223:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.TEXT_BASELINE=t.DIM_OPACITY=t.INVERTED_DEFAULT_COLOR=void 0;const s=i(6114);t.INVERTED_DEFAULT_COLOR=257,t.DIM_OPACITY=.5,t.TEXT_BASELINE=s.isFirefox||s.isLegacyEdge?"bottom":"ideographic"},6171:(e,t)=>{function i(e){return 57508<=e&&e<=57558}Object.defineProperty(t,"__esModule",{value:!0}),t.computeNextVariantOffset=t.createRenderDimensions=t.treatGlyphAsBackgroundColor=t.isRestrictedPowerlineGlyph=t.isPowerlineGlyph=t.throwIfFalsy=void 0,t.throwIfFalsy=function(e){if(!e)throw new Error("value must not be falsy");return e},t.isPowerlineGlyph=i,t.isRestrictedPowerlineGlyph=function(e){return 57520<=e&&e<=57527},t.treatGlyphAsBackgroundColor=function(e){return i(e)||function(e){return 9472<=e&&e<=9631}(e)},t.createRenderDimensions=function(){return{css:{canvas:{width:0,height:0},cell:{width:0,height:0}},device:{canvas:{width:0,height:0},cell:{width:0,height:0},char:{width:0,height:0,left:0,top:0}}}},t.computeNextVariantOffset=function(e,t,i=0){return(e-(2*Math.round(t)-i))%(2*Math.round(t))}},6052:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.createSelectionRenderModel=void 0;class i{constructor(){this.clear()}clear(){this.hasSelection=!1,this.columnSelectMode=!1,this.viewportStartRow=0,this.viewportEndRow=0,this.viewportCappedStartRow=0,this.viewportCappedEndRow=0,this.startCol=0,this.endCol=0,this.selectionStart=void 0,this.selectionEnd=void 0}update(e,t,i,s=!1){if(this.selectionStart=t,this.selectionEnd=i,!t||!i||t[0]===i[0]&&t[1]===i[1])return void this.clear();const r=e.buffers.active.ydisp,n=t[1]-r,o=i[1]-r,a=Math.max(n,0),h=Math.min(o,e.rows-1);a>=e.rows||h<0?this.clear():(this.hasSelection=!0,this.columnSelectMode=s,this.viewportStartRow=n,this.viewportEndRow=o,this.viewportCappedStartRow=a,this.viewportCappedEndRow=h,this.startCol=t[0],this.endCol=i[0])}isCellSelected(e,t,i){return!!this.hasSelection&&(i-=e.buffer.active.viewportY,this.columnSelectMode?this.startCol<=this.endCol?t>=this.startCol&&i>=this.viewportCappedStartRow&&t=this.viewportCappedStartRow&&t>=this.endCol&&i<=this.viewportCappedEndRow:i>this.viewportStartRow&&i=this.startCol&&t=this.startCol)}}t.createSelectionRenderModel=function(){return new i}},456:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.SelectionModel=void 0,t.SelectionModel=class{constructor(e){this._bufferService=e,this.isSelectAllActive=!1,this.selectionStartLength=0}clearSelection(){this.selectionStart=void 0,this.selectionEnd=void 0,this.isSelectAllActive=!1,this.selectionStartLength=0}get finalSelectionStart(){return this.isSelectAllActive?[0,0]:this.selectionEnd&&this.selectionStart&&this.areSelectionValuesReversed()?this.selectionEnd:this.selectionStart}get finalSelectionEnd(){if(this.isSelectAllActive)return[this._bufferService.cols,this._bufferService.buffer.ybase+this._bufferService.rows-1];if(this.selectionStart){if(!this.selectionEnd||this.areSelectionValuesReversed()){const e=this.selectionStart[0]+this.selectionStartLength;return e>this._bufferService.cols?e%this._bufferService.cols==0?[this._bufferService.cols,this.selectionStart[1]+Math.floor(e/this._bufferService.cols)-1]:[e%this._bufferService.cols,this.selectionStart[1]+Math.floor(e/this._bufferService.cols)]:[e,this.selectionStart[1]]}if(this.selectionStartLength&&this.selectionEnd[1]===this.selectionStart[1]){const e=this.selectionStart[0]+this.selectionStartLength;return e>this._bufferService.cols?[e%this._bufferService.cols,this.selectionStart[1]+Math.floor(e/this._bufferService.cols)]:[Math.max(e,this.selectionEnd[0]),this.selectionEnd[1]]}return this.selectionEnd}}areSelectionValuesReversed(){const e=this.selectionStart,t=this.selectionEnd;return!(!e||!t)&&(e[1]>t[1]||e[1]===t[1]&&e[0]>t[0])}handleTrim(e){return this.selectionStart&&(this.selectionStart[1]-=e),this.selectionEnd&&(this.selectionEnd[1]-=e),this.selectionEnd&&this.selectionEnd[1]<0?(this.clearSelection(),!0):(this.selectionStart&&this.selectionStart[1]<0&&(this.selectionStart[1]=0),!1)}}},428:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CharSizeService=void 0;const n=i(2585),o=i(8460),a=i(844);let h=t.CharSizeService=class extends a.Disposable{get hasValidSize(){return this.width>0&&this.height>0}constructor(e,t,i){super(),this._optionsService=i,this.width=0,this.height=0,this._onCharSizeChange=this.register(new o.EventEmitter),this.onCharSizeChange=this._onCharSizeChange.event;try{this._measureStrategy=this.register(new d(this._optionsService))}catch{this._measureStrategy=this.register(new l(e,t,this._optionsService))}this.register(this._optionsService.onMultipleOptionChange(["fontFamily","fontSize"],(()=>this.measure())))}measure(){const e=this._measureStrategy.measure();e.width===this.width&&e.height===this.height||(this.width=e.width,this.height=e.height,this._onCharSizeChange.fire())}};t.CharSizeService=h=s([r(2,n.IOptionsService)],h);class c extends a.Disposable{constructor(){super(...arguments),this._result={width:0,height:0}}_validateAndSet(e,t){void 0!==e&&e>0&&void 0!==t&&t>0&&(this._result.width=e,this._result.height=t)}}class l extends c{constructor(e,t,i){super(),this._document=e,this._parentElement=t,this._optionsService=i,this._measureElement=this._document.createElement("span"),this._measureElement.classList.add("xterm-char-measure-element"),this._measureElement.textContent="W".repeat(32),this._measureElement.setAttribute("aria-hidden","true"),this._measureElement.style.whiteSpace="pre",this._measureElement.style.fontKerning="none",this._parentElement.appendChild(this._measureElement)}measure(){return this._measureElement.style.fontFamily=this._optionsService.rawOptions.fontFamily,this._measureElement.style.fontSize=`${this._optionsService.rawOptions.fontSize}px`,this._validateAndSet(Number(this._measureElement.offsetWidth)/32,Number(this._measureElement.offsetHeight)),this._result}}class d extends c{constructor(e){super(),this._optionsService=e,this._canvas=new OffscreenCanvas(100,100),this._ctx=this._canvas.getContext("2d");const t=this._ctx.measureText("W");if(!("width"in t&&"fontBoundingBoxAscent"in t&&"fontBoundingBoxDescent"in t))throw new Error("Required font metrics not supported")}measure(){this._ctx.font=`${this._optionsService.rawOptions.fontSize}px ${this._optionsService.rawOptions.fontFamily}`;const e=this._ctx.measureText("W");return this._validateAndSet(e.width,e.fontBoundingBoxAscent+e.fontBoundingBoxDescent),this._result}}},4269:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CharacterJoinerService=t.JoinedCellData=void 0;const n=i(3734),o=i(643),a=i(511),h=i(2585);class c extends n.AttributeData{constructor(e,t,i){super(),this.content=0,this.combinedData="",this.fg=e.fg,this.bg=e.bg,this.combinedData=t,this._width=i}isCombined(){return 2097152}getWidth(){return this._width}getChars(){return this.combinedData}getCode(){return 2097151}setFromCharData(e){throw new Error("not implemented")}getAsCharData(){return[this.fg,this.getChars(),this.getWidth(),this.getCode()]}}t.JoinedCellData=c;let l=t.CharacterJoinerService=class e{constructor(e){this._bufferService=e,this._characterJoiners=[],this._nextCharacterJoinerId=0,this._workCell=new a.CellData}register(e){const t={id:this._nextCharacterJoinerId++,handler:e};return this._characterJoiners.push(t),t.id}deregister(e){for(let t=0;t1){const e=this._getJoinedRanges(s,a,n,t,r);for(let t=0;t1){const e=this._getJoinedRanges(s,a,n,t,r);for(let t=0;t{Object.defineProperty(t,"__esModule",{value:!0}),t.CoreBrowserService=void 0;const s=i(844),r=i(8460),n=i(3656);class o extends s.Disposable{constructor(e,t,i){super(),this._textarea=e,this._window=t,this.mainDocument=i,this._isFocused=!1,this._cachedIsFocused=void 0,this._screenDprMonitor=new a(this._window),this._onDprChange=this.register(new r.EventEmitter),this.onDprChange=this._onDprChange.event,this._onWindowChange=this.register(new r.EventEmitter),this.onWindowChange=this._onWindowChange.event,this.register(this.onWindowChange((e=>this._screenDprMonitor.setWindow(e)))),this.register((0,r.forwardEvent)(this._screenDprMonitor.onDprChange,this._onDprChange)),this._textarea.addEventListener("focus",(()=>this._isFocused=!0)),this._textarea.addEventListener("blur",(()=>this._isFocused=!1))}get window(){return this._window}set window(e){this._window!==e&&(this._window=e,this._onWindowChange.fire(this._window))}get dpr(){return this.window.devicePixelRatio}get isFocused(){return void 0===this._cachedIsFocused&&(this._cachedIsFocused=this._isFocused&&this._textarea.ownerDocument.hasFocus(),queueMicrotask((()=>this._cachedIsFocused=void 0))),this._cachedIsFocused}}t.CoreBrowserService=o;class a extends s.Disposable{constructor(e){super(),this._parentWindow=e,this._windowResizeListener=this.register(new s.MutableDisposable),this._onDprChange=this.register(new r.EventEmitter),this.onDprChange=this._onDprChange.event,this._outerListener=()=>this._setDprAndFireIfDiffers(),this._currentDevicePixelRatio=this._parentWindow.devicePixelRatio,this._updateDpr(),this._setWindowResizeListener(),this.register((0,s.toDisposable)((()=>this.clearListener())))}setWindow(e){this._parentWindow=e,this._setWindowResizeListener(),this._setDprAndFireIfDiffers()}_setWindowResizeListener(){this._windowResizeListener.value=(0,n.addDisposableDomListener)(this._parentWindow,"resize",(()=>this._setDprAndFireIfDiffers()))}_setDprAndFireIfDiffers(){this._parentWindow.devicePixelRatio!==this._currentDevicePixelRatio&&this._onDprChange.fire(this._parentWindow.devicePixelRatio),this._updateDpr()}_updateDpr(){this._outerListener&&(this._resolutionMediaMatchList?.removeListener(this._outerListener),this._currentDevicePixelRatio=this._parentWindow.devicePixelRatio,this._resolutionMediaMatchList=this._parentWindow.matchMedia(`screen and (resolution: ${this._parentWindow.devicePixelRatio}dppx)`),this._resolutionMediaMatchList.addListener(this._outerListener))}clearListener(){this._resolutionMediaMatchList&&this._outerListener&&(this._resolutionMediaMatchList.removeListener(this._outerListener),this._resolutionMediaMatchList=void 0,this._outerListener=void 0)}}},779:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.LinkProviderService=void 0;const s=i(844);class r extends s.Disposable{constructor(){super(),this.linkProviders=[],this.register((0,s.toDisposable)((()=>this.linkProviders.length=0)))}registerLinkProvider(e){return this.linkProviders.push(e),{dispose:()=>{const t=this.linkProviders.indexOf(e);-1!==t&&this.linkProviders.splice(t,1)}}}}t.LinkProviderService=r},8934:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.MouseService=void 0;const n=i(4725),o=i(9806);let a=t.MouseService=class{constructor(e,t){this._renderService=e,this._charSizeService=t}getCoords(e,t,i,s,r){return(0,o.getCoords)(window,e,t,i,s,this._charSizeService.hasValidSize,this._renderService.dimensions.css.cell.width,this._renderService.dimensions.css.cell.height,r)}getMouseReportCoords(e,t){const i=(0,o.getCoordsRelativeToElement)(window,e,t);if(this._charSizeService.hasValidSize)return i[0]=Math.min(Math.max(i[0],0),this._renderService.dimensions.css.canvas.width-1),i[1]=Math.min(Math.max(i[1],0),this._renderService.dimensions.css.canvas.height-1),{col:Math.floor(i[0]/this._renderService.dimensions.css.cell.width),row:Math.floor(i[1]/this._renderService.dimensions.css.cell.height),x:Math.floor(i[0]),y:Math.floor(i[1])}}};t.MouseService=a=s([r(0,n.IRenderService),r(1,n.ICharSizeService)],a)},3230:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.RenderService=void 0;const n=i(6193),o=i(4725),a=i(8460),h=i(844),c=i(7226),l=i(2585);let d=t.RenderService=class extends h.Disposable{get dimensions(){return this._renderer.value.dimensions}constructor(e,t,i,s,r,o,l,d){super(),this._rowCount=e,this._charSizeService=s,this._renderer=this.register(new h.MutableDisposable),this._pausedResizeTask=new c.DebouncedIdleTask,this._observerDisposable=this.register(new h.MutableDisposable),this._isPaused=!1,this._needsFullRefresh=!1,this._isNextRenderRedrawOnly=!0,this._needsSelectionRefresh=!1,this._canvasWidth=0,this._canvasHeight=0,this._selectionState={start:void 0,end:void 0,columnSelectMode:!1},this._onDimensionsChange=this.register(new a.EventEmitter),this.onDimensionsChange=this._onDimensionsChange.event,this._onRenderedViewportChange=this.register(new a.EventEmitter),this.onRenderedViewportChange=this._onRenderedViewportChange.event,this._onRender=this.register(new a.EventEmitter),this.onRender=this._onRender.event,this._onRefreshRequest=this.register(new a.EventEmitter),this.onRefreshRequest=this._onRefreshRequest.event,this._renderDebouncer=new n.RenderDebouncer(((e,t)=>this._renderRows(e,t)),l),this.register(this._renderDebouncer),this.register(l.onDprChange((()=>this.handleDevicePixelRatioChange()))),this.register(o.onResize((()=>this._fullRefresh()))),this.register(o.buffers.onBufferActivate((()=>this._renderer.value?.clear()))),this.register(i.onOptionChange((()=>this._handleOptionsChanged()))),this.register(this._charSizeService.onCharSizeChange((()=>this.handleCharSizeChanged()))),this.register(r.onDecorationRegistered((()=>this._fullRefresh()))),this.register(r.onDecorationRemoved((()=>this._fullRefresh()))),this.register(i.onMultipleOptionChange(["customGlyphs","drawBoldTextInBrightColors","letterSpacing","lineHeight","fontFamily","fontSize","fontWeight","fontWeightBold","minimumContrastRatio"],(()=>{this.clear(),this.handleResize(o.cols,o.rows),this._fullRefresh()}))),this.register(i.onMultipleOptionChange(["cursorBlink","cursorStyle"],(()=>this.refreshRows(o.buffer.y,o.buffer.y,!0)))),this.register(d.onChangeColors((()=>this._fullRefresh()))),this._registerIntersectionObserver(l.window,t),this.register(l.onWindowChange((e=>this._registerIntersectionObserver(e,t))))}_registerIntersectionObserver(e,t){if("IntersectionObserver"in e){const i=new e.IntersectionObserver((e=>this._handleIntersectionChange(e[e.length-1])),{threshold:0});i.observe(t),this._observerDisposable.value=(0,h.toDisposable)((()=>i.disconnect()))}}_handleIntersectionChange(e){this._isPaused=void 0===e.isIntersecting?0===e.intersectionRatio:!e.isIntersecting,this._isPaused||this._charSizeService.hasValidSize||this._charSizeService.measure(),!this._isPaused&&this._needsFullRefresh&&(this._pausedResizeTask.flush(),this.refreshRows(0,this._rowCount-1),this._needsFullRefresh=!1)}refreshRows(e,t,i=!1){this._isPaused?this._needsFullRefresh=!0:(i||(this._isNextRenderRedrawOnly=!1),this._renderDebouncer.refresh(e,t,this._rowCount))}_renderRows(e,t){this._renderer.value&&(e=Math.min(e,this._rowCount-1),t=Math.min(t,this._rowCount-1),this._renderer.value.renderRows(e,t),this._needsSelectionRefresh&&(this._renderer.value.handleSelectionChanged(this._selectionState.start,this._selectionState.end,this._selectionState.columnSelectMode),this._needsSelectionRefresh=!1),this._isNextRenderRedrawOnly||this._onRenderedViewportChange.fire({start:e,end:t}),this._onRender.fire({start:e,end:t}),this._isNextRenderRedrawOnly=!0)}resize(e,t){this._rowCount=t,this._fireOnCanvasResize()}_handleOptionsChanged(){this._renderer.value&&(this.refreshRows(0,this._rowCount-1),this._fireOnCanvasResize())}_fireOnCanvasResize(){this._renderer.value&&(this._renderer.value.dimensions.css.canvas.width===this._canvasWidth&&this._renderer.value.dimensions.css.canvas.height===this._canvasHeight||this._onDimensionsChange.fire(this._renderer.value.dimensions))}hasRenderer(){return!!this._renderer.value}setRenderer(e){this._renderer.value=e,this._renderer.value&&(this._renderer.value.onRequestRedraw((e=>this.refreshRows(e.start,e.end,!0))),this._needsSelectionRefresh=!0,this._fullRefresh())}addRefreshCallback(e){return this._renderDebouncer.addRefreshCallback(e)}_fullRefresh(){this._isPaused?this._needsFullRefresh=!0:this.refreshRows(0,this._rowCount-1)}clearTextureAtlas(){this._renderer.value&&(this._renderer.value.clearTextureAtlas?.(),this._fullRefresh())}handleDevicePixelRatioChange(){this._charSizeService.measure(),this._renderer.value&&(this._renderer.value.handleDevicePixelRatioChange(),this.refreshRows(0,this._rowCount-1))}handleResize(e,t){this._renderer.value&&(this._isPaused?this._pausedResizeTask.set((()=>this._renderer.value?.handleResize(e,t))):this._renderer.value.handleResize(e,t),this._fullRefresh())}handleCharSizeChanged(){this._renderer.value?.handleCharSizeChanged()}handleBlur(){this._renderer.value?.handleBlur()}handleFocus(){this._renderer.value?.handleFocus()}handleSelectionChanged(e,t,i){this._selectionState.start=e,this._selectionState.end=t,this._selectionState.columnSelectMode=i,this._renderer.value?.handleSelectionChanged(e,t,i)}handleCursorMove(){this._renderer.value?.handleCursorMove()}clear(){this._renderer.value?.clear()}};t.RenderService=d=s([r(2,l.IOptionsService),r(3,o.ICharSizeService),r(4,l.IDecorationService),r(5,l.IBufferService),r(6,o.ICoreBrowserService),r(7,o.IThemeService)],d)},9312:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.SelectionService=void 0;const n=i(9806),o=i(9504),a=i(456),h=i(4725),c=i(8460),l=i(844),d=i(6114),_=i(4841),u=i(511),f=i(2585),v=String.fromCharCode(160),p=new RegExp(v,"g");let g=t.SelectionService=class extends l.Disposable{constructor(e,t,i,s,r,n,o,h,d){super(),this._element=e,this._screenElement=t,this._linkifier=i,this._bufferService=s,this._coreService=r,this._mouseService=n,this._optionsService=o,this._renderService=h,this._coreBrowserService=d,this._dragScrollAmount=0,this._enabled=!0,this._workCell=new u.CellData,this._mouseDownTimeStamp=0,this._oldHasSelection=!1,this._oldSelectionStart=void 0,this._oldSelectionEnd=void 0,this._onLinuxMouseSelection=this.register(new c.EventEmitter),this.onLinuxMouseSelection=this._onLinuxMouseSelection.event,this._onRedrawRequest=this.register(new c.EventEmitter),this.onRequestRedraw=this._onRedrawRequest.event,this._onSelectionChange=this.register(new c.EventEmitter),this.onSelectionChange=this._onSelectionChange.event,this._onRequestScrollLines=this.register(new c.EventEmitter),this.onRequestScrollLines=this._onRequestScrollLines.event,this._mouseMoveListener=e=>this._handleMouseMove(e),this._mouseUpListener=e=>this._handleMouseUp(e),this._coreService.onUserInput((()=>{this.hasSelection&&this.clearSelection()})),this._trimListener=this._bufferService.buffer.lines.onTrim((e=>this._handleTrim(e))),this.register(this._bufferService.buffers.onBufferActivate((e=>this._handleBufferActivate(e)))),this.enable(),this._model=new a.SelectionModel(this._bufferService),this._activeSelectionMode=0,this.register((0,l.toDisposable)((()=>{this._removeMouseDownListeners()})))}reset(){this.clearSelection()}disable(){this.clearSelection(),this._enabled=!1}enable(){this._enabled=!0}get selectionStart(){return this._model.finalSelectionStart}get selectionEnd(){return this._model.finalSelectionEnd}get hasSelection(){const e=this._model.finalSelectionStart,t=this._model.finalSelectionEnd;return!(!e||!t||e[0]===t[0]&&e[1]===t[1])}get selectionText(){const e=this._model.finalSelectionStart,t=this._model.finalSelectionEnd;if(!e||!t)return"";const i=this._bufferService.buffer,s=[];if(3===this._activeSelectionMode){if(e[0]===t[0])return"";const r=e[0]e.replace(p," "))).join(d.isWindows?"\r\n":"\n")}clearSelection(){this._model.clearSelection(),this._removeMouseDownListeners(),this.refresh(),this._onSelectionChange.fire()}refresh(e){this._refreshAnimationFrame||(this._refreshAnimationFrame=this._coreBrowserService.window.requestAnimationFrame((()=>this._refresh()))),d.isLinux&&e&&this.selectionText.length&&this._onLinuxMouseSelection.fire(this.selectionText)}_refresh(){this._refreshAnimationFrame=void 0,this._onRedrawRequest.fire({start:this._model.finalSelectionStart,end:this._model.finalSelectionEnd,columnSelectMode:3===this._activeSelectionMode})}_isClickInSelection(e){const t=this._getMouseBufferCoords(e),i=this._model.finalSelectionStart,s=this._model.finalSelectionEnd;return!!(i&&s&&t)&&this._areCoordsInSelection(t,i,s)}isCellInSelection(e,t){const i=this._model.finalSelectionStart,s=this._model.finalSelectionEnd;return!(!i||!s)&&this._areCoordsInSelection([e,t],i,s)}_areCoordsInSelection(e,t,i){return e[1]>t[1]&&e[1]=t[0]&&e[0]=t[0]}_selectWordAtCursor(e,t){const i=this._linkifier.currentLink?.link?.range;if(i)return this._model.selectionStart=[i.start.x-1,i.start.y-1],this._model.selectionStartLength=(0,_.getRangeLength)(i,this._bufferService.cols),this._model.selectionEnd=void 0,!0;const s=this._getMouseBufferCoords(e);return!!s&&(this._selectWordAt(s,t),this._model.selectionEnd=void 0,!0)}selectAll(){this._model.isSelectAllActive=!0,this.refresh(),this._onSelectionChange.fire()}selectLines(e,t){this._model.clearSelection(),e=Math.max(e,0),t=Math.min(t,this._bufferService.buffer.lines.length-1),this._model.selectionStart=[0,e],this._model.selectionEnd=[this._bufferService.cols,t],this.refresh(),this._onSelectionChange.fire()}_handleTrim(e){this._model.handleTrim(e)&&this.refresh()}_getMouseBufferCoords(e){const t=this._mouseService.getCoords(e,this._screenElement,this._bufferService.cols,this._bufferService.rows,!0);if(t)return t[0]--,t[1]--,t[1]+=this._bufferService.buffer.ydisp,t}_getMouseEventScrollAmount(e){let t=(0,n.getCoordsRelativeToElement)(this._coreBrowserService.window,e,this._screenElement)[1];const i=this._renderService.dimensions.css.canvas.height;return t>=0&&t<=i?0:(t>i&&(t-=i),t=Math.min(Math.max(t,-50),50),t/=50,t/Math.abs(t)+Math.round(14*t))}shouldForceSelection(e){return d.isMac?e.altKey&&this._optionsService.rawOptions.macOptionClickForcesSelection:e.shiftKey}handleMouseDown(e){if(this._mouseDownTimeStamp=e.timeStamp,(2!==e.button||!this.hasSelection)&&0===e.button){if(!this._enabled){if(!this.shouldForceSelection(e))return;e.stopPropagation()}e.preventDefault(),this._dragScrollAmount=0,this._enabled&&e.shiftKey?this._handleIncrementalClick(e):1===e.detail?this._handleSingleClick(e):2===e.detail?this._handleDoubleClick(e):3===e.detail&&this._handleTripleClick(e),this._addMouseDownListeners(),this.refresh(!0)}}_addMouseDownListeners(){this._screenElement.ownerDocument&&(this._screenElement.ownerDocument.addEventListener("mousemove",this._mouseMoveListener),this._screenElement.ownerDocument.addEventListener("mouseup",this._mouseUpListener)),this._dragScrollIntervalTimer=this._coreBrowserService.window.setInterval((()=>this._dragScroll()),50)}_removeMouseDownListeners(){this._screenElement.ownerDocument&&(this._screenElement.ownerDocument.removeEventListener("mousemove",this._mouseMoveListener),this._screenElement.ownerDocument.removeEventListener("mouseup",this._mouseUpListener)),this._coreBrowserService.window.clearInterval(this._dragScrollIntervalTimer),this._dragScrollIntervalTimer=void 0}_handleIncrementalClick(e){this._model.selectionStart&&(this._model.selectionEnd=this._getMouseBufferCoords(e))}_handleSingleClick(e){if(this._model.selectionStartLength=0,this._model.isSelectAllActive=!1,this._activeSelectionMode=this.shouldColumnSelect(e)?3:0,this._model.selectionStart=this._getMouseBufferCoords(e),!this._model.selectionStart)return;this._model.selectionEnd=void 0;const t=this._bufferService.buffer.lines.get(this._model.selectionStart[1]);t&&t.length!==this._model.selectionStart[0]&&0===t.hasWidth(this._model.selectionStart[0])&&this._model.selectionStart[0]++}_handleDoubleClick(e){this._selectWordAtCursor(e,!0)&&(this._activeSelectionMode=1)}_handleTripleClick(e){const t=this._getMouseBufferCoords(e);t&&(this._activeSelectionMode=2,this._selectLineAt(t[1]))}shouldColumnSelect(e){return e.altKey&&!(d.isMac&&this._optionsService.rawOptions.macOptionClickForcesSelection)}_handleMouseMove(e){if(e.stopImmediatePropagation(),!this._model.selectionStart)return;const t=this._model.selectionEnd?[this._model.selectionEnd[0],this._model.selectionEnd[1]]:null;if(this._model.selectionEnd=this._getMouseBufferCoords(e),!this._model.selectionEnd)return void this.refresh(!0);2===this._activeSelectionMode?this._model.selectionEnd[1]0?this._model.selectionEnd[0]=this._bufferService.cols:this._dragScrollAmount<0&&(this._model.selectionEnd[0]=0));const i=this._bufferService.buffer;if(this._model.selectionEnd[1]0?(3!==this._activeSelectionMode&&(this._model.selectionEnd[0]=this._bufferService.cols),this._model.selectionEnd[1]=Math.min(e.ydisp+this._bufferService.rows,e.lines.length-1)):(3!==this._activeSelectionMode&&(this._model.selectionEnd[0]=0),this._model.selectionEnd[1]=e.ydisp),this.refresh()}}_handleMouseUp(e){const t=e.timeStamp-this._mouseDownTimeStamp;if(this._removeMouseDownListeners(),this.selectionText.length<=1&&t<500&&e.altKey&&this._optionsService.rawOptions.altClickMovesCursor){if(this._bufferService.buffer.ybase===this._bufferService.buffer.ydisp){const t=this._mouseService.getCoords(e,this._element,this._bufferService.cols,this._bufferService.rows,!1);if(t&&void 0!==t[0]&&void 0!==t[1]){const e=(0,o.moveToCellSequence)(t[0]-1,t[1]-1,this._bufferService,this._coreService.decPrivateModes.applicationCursorKeys);this._coreService.triggerDataEvent(e,!0)}}}else this._fireEventIfSelectionChanged()}_fireEventIfSelectionChanged(){const e=this._model.finalSelectionStart,t=this._model.finalSelectionEnd,i=!(!e||!t||e[0]===t[0]&&e[1]===t[1]);i?e&&t&&(this._oldSelectionStart&&this._oldSelectionEnd&&e[0]===this._oldSelectionStart[0]&&e[1]===this._oldSelectionStart[1]&&t[0]===this._oldSelectionEnd[0]&&t[1]===this._oldSelectionEnd[1]||this._fireOnSelectionChange(e,t,i)):this._oldHasSelection&&this._fireOnSelectionChange(e,t,i)}_fireOnSelectionChange(e,t,i){this._oldSelectionStart=e,this._oldSelectionEnd=t,this._oldHasSelection=i,this._onSelectionChange.fire()}_handleBufferActivate(e){this.clearSelection(),this._trimListener.dispose(),this._trimListener=e.activeBuffer.lines.onTrim((e=>this._handleTrim(e)))}_convertViewportColToCharacterIndex(e,t){let i=t;for(let s=0;t>=s;s++){const r=e.loadCell(s,this._workCell).getChars().length;0===this._workCell.getWidth()?i--:r>1&&t!==s&&(i+=r-1)}return i}setSelection(e,t,i){this._model.clearSelection(),this._removeMouseDownListeners(),this._model.selectionStart=[e,t],this._model.selectionStartLength=i,this.refresh(),this._fireEventIfSelectionChanged()}rightClickSelect(e){this._isClickInSelection(e)||(this._selectWordAtCursor(e,!1)&&this.refresh(!0),this._fireEventIfSelectionChanged())}_getWordAt(e,t,i=!0,s=!0){if(e[0]>=this._bufferService.cols)return;const r=this._bufferService.buffer,n=r.lines.get(e[1]);if(!n)return;const o=r.translateBufferLineToString(e[1],!1);let a=this._convertViewportColToCharacterIndex(n,e[0]),h=a;const c=e[0]-a;let l=0,d=0,_=0,u=0;if(" "===o.charAt(a)){for(;a>0&&" "===o.charAt(a-1);)a--;for(;h1&&(u+=s-1,h+=s-1);t>0&&a>0&&!this._isCharWordSeparator(n.loadCell(t-1,this._workCell));){n.loadCell(t-1,this._workCell);const e=this._workCell.getChars().length;0===this._workCell.getWidth()?(l++,t--):e>1&&(_+=e-1,a-=e-1),a--,t--}for(;i1&&(u+=e-1,h+=e-1),h++,i++}}h++;let f=a+c-l+_,v=Math.min(this._bufferService.cols,h-a+l+d-_-u);if(t||""!==o.slice(a,h).trim()){if(i&&0===f&&32!==n.getCodePoint(0)){const t=r.lines.get(e[1]-1);if(t&&n.isWrapped&&32!==t.getCodePoint(this._bufferService.cols-1)){const t=this._getWordAt([this._bufferService.cols-1,e[1]-1],!1,!0,!1);if(t){const e=this._bufferService.cols-t.start;f-=e,v+=e}}}if(s&&f+v===this._bufferService.cols&&32!==n.getCodePoint(this._bufferService.cols-1)){const t=r.lines.get(e[1]+1);if(t?.isWrapped&&32!==t.getCodePoint(0)){const t=this._getWordAt([0,e[1]+1],!1,!1,!0);t&&(v+=t.length)}}return{start:f,length:v}}}_selectWordAt(e,t){const i=this._getWordAt(e,t);if(i){for(;i.start<0;)i.start+=this._bufferService.cols,e[1]--;this._model.selectionStart=[i.start,e[1]],this._model.selectionStartLength=i.length}}_selectToWordAt(e){const t=this._getWordAt(e,!0);if(t){let i=e[1];for(;t.start<0;)t.start+=this._bufferService.cols,i--;if(!this._model.areSelectionValuesReversed())for(;t.start+t.length>this._bufferService.cols;)t.length-=this._bufferService.cols,i++;this._model.selectionEnd=[this._model.areSelectionValuesReversed()?t.start:t.start+t.length,i]}}_isCharWordSeparator(e){return 0!==e.getWidth()&&this._optionsService.rawOptions.wordSeparator.indexOf(e.getChars())>=0}_selectLineAt(e){const t=this._bufferService.buffer.getWrappedRangeForLine(e),i={start:{x:0,y:t.first},end:{x:this._bufferService.cols-1,y:t.last}};this._model.selectionStart=[0,t.first],this._model.selectionEnd=void 0,this._model.selectionStartLength=(0,_.getRangeLength)(i,this._bufferService.cols)}};t.SelectionService=g=s([r(3,f.IBufferService),r(4,f.ICoreService),r(5,h.IMouseService),r(6,f.IOptionsService),r(7,h.IRenderService),r(8,h.ICoreBrowserService)],g)},4725:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ILinkProviderService=t.IThemeService=t.ICharacterJoinerService=t.ISelectionService=t.IRenderService=t.IMouseService=t.ICoreBrowserService=t.ICharSizeService=void 0;const s=i(8343);t.ICharSizeService=(0,s.createDecorator)("CharSizeService"),t.ICoreBrowserService=(0,s.createDecorator)("CoreBrowserService"),t.IMouseService=(0,s.createDecorator)("MouseService"),t.IRenderService=(0,s.createDecorator)("RenderService"),t.ISelectionService=(0,s.createDecorator)("SelectionService"),t.ICharacterJoinerService=(0,s.createDecorator)("CharacterJoinerService"),t.IThemeService=(0,s.createDecorator)("ThemeService"),t.ILinkProviderService=(0,s.createDecorator)("LinkProviderService")},6731:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.ThemeService=t.DEFAULT_ANSI_COLORS=void 0;const n=i(7239),o=i(8055),a=i(8460),h=i(844),c=i(2585),l=o.css.toColor("#ffffff"),d=o.css.toColor("#000000"),_=o.css.toColor("#ffffff"),u=o.css.toColor("#000000"),f={css:"rgba(255, 255, 255, 0.3)",rgba:4294967117};t.DEFAULT_ANSI_COLORS=Object.freeze((()=>{const e=[o.css.toColor("#2e3436"),o.css.toColor("#cc0000"),o.css.toColor("#4e9a06"),o.css.toColor("#c4a000"),o.css.toColor("#3465a4"),o.css.toColor("#75507b"),o.css.toColor("#06989a"),o.css.toColor("#d3d7cf"),o.css.toColor("#555753"),o.css.toColor("#ef2929"),o.css.toColor("#8ae234"),o.css.toColor("#fce94f"),o.css.toColor("#729fcf"),o.css.toColor("#ad7fa8"),o.css.toColor("#34e2e2"),o.css.toColor("#eeeeec")],t=[0,95,135,175,215,255];for(let i=0;i<216;i++){const s=t[i/36%6|0],r=t[i/6%6|0],n=t[i%6];e.push({css:o.channels.toCss(s,r,n),rgba:o.channels.toRgba(s,r,n)})}for(let t=0;t<24;t++){const i=8+10*t;e.push({css:o.channels.toCss(i,i,i),rgba:o.channels.toRgba(i,i,i)})}return e})());let v=t.ThemeService=class extends h.Disposable{get colors(){return this._colors}constructor(e){super(),this._optionsService=e,this._contrastCache=new n.ColorContrastCache,this._halfContrastCache=new n.ColorContrastCache,this._onChangeColors=this.register(new a.EventEmitter),this.onChangeColors=this._onChangeColors.event,this._colors={foreground:l,background:d,cursor:_,cursorAccent:u,selectionForeground:void 0,selectionBackgroundTransparent:f,selectionBackgroundOpaque:o.color.blend(d,f),selectionInactiveBackgroundTransparent:f,selectionInactiveBackgroundOpaque:o.color.blend(d,f),ansi:t.DEFAULT_ANSI_COLORS.slice(),contrastCache:this._contrastCache,halfContrastCache:this._halfContrastCache},this._updateRestoreColors(),this._setTheme(this._optionsService.rawOptions.theme),this.register(this._optionsService.onSpecificOptionChange("minimumContrastRatio",(()=>this._contrastCache.clear()))),this.register(this._optionsService.onSpecificOptionChange("theme",(()=>this._setTheme(this._optionsService.rawOptions.theme))))}_setTheme(e={}){const i=this._colors;if(i.foreground=p(e.foreground,l),i.background=p(e.background,d),i.cursor=p(e.cursor,_),i.cursorAccent=p(e.cursorAccent,u),i.selectionBackgroundTransparent=p(e.selectionBackground,f),i.selectionBackgroundOpaque=o.color.blend(i.background,i.selectionBackgroundTransparent),i.selectionInactiveBackgroundTransparent=p(e.selectionInactiveBackground,i.selectionBackgroundTransparent),i.selectionInactiveBackgroundOpaque=o.color.blend(i.background,i.selectionInactiveBackgroundTransparent),i.selectionForeground=e.selectionForeground?p(e.selectionForeground,o.NULL_COLOR):void 0,i.selectionForeground===o.NULL_COLOR&&(i.selectionForeground=void 0),o.color.isOpaque(i.selectionBackgroundTransparent)){const e=.3;i.selectionBackgroundTransparent=o.color.opacity(i.selectionBackgroundTransparent,e)}if(o.color.isOpaque(i.selectionInactiveBackgroundTransparent)){const e=.3;i.selectionInactiveBackgroundTransparent=o.color.opacity(i.selectionInactiveBackgroundTransparent,e)}if(i.ansi=t.DEFAULT_ANSI_COLORS.slice(),i.ansi[0]=p(e.black,t.DEFAULT_ANSI_COLORS[0]),i.ansi[1]=p(e.red,t.DEFAULT_ANSI_COLORS[1]),i.ansi[2]=p(e.green,t.DEFAULT_ANSI_COLORS[2]),i.ansi[3]=p(e.yellow,t.DEFAULT_ANSI_COLORS[3]),i.ansi[4]=p(e.blue,t.DEFAULT_ANSI_COLORS[4]),i.ansi[5]=p(e.magenta,t.DEFAULT_ANSI_COLORS[5]),i.ansi[6]=p(e.cyan,t.DEFAULT_ANSI_COLORS[6]),i.ansi[7]=p(e.white,t.DEFAULT_ANSI_COLORS[7]),i.ansi[8]=p(e.brightBlack,t.DEFAULT_ANSI_COLORS[8]),i.ansi[9]=p(e.brightRed,t.DEFAULT_ANSI_COLORS[9]),i.ansi[10]=p(e.brightGreen,t.DEFAULT_ANSI_COLORS[10]),i.ansi[11]=p(e.brightYellow,t.DEFAULT_ANSI_COLORS[11]),i.ansi[12]=p(e.brightBlue,t.DEFAULT_ANSI_COLORS[12]),i.ansi[13]=p(e.brightMagenta,t.DEFAULT_ANSI_COLORS[13]),i.ansi[14]=p(e.brightCyan,t.DEFAULT_ANSI_COLORS[14]),i.ansi[15]=p(e.brightWhite,t.DEFAULT_ANSI_COLORS[15]),e.extendedAnsi){const s=Math.min(i.ansi.length-16,e.extendedAnsi.length);for(let r=0;r{Object.defineProperty(t,"__esModule",{value:!0}),t.CircularList=void 0;const s=i(8460),r=i(844);class n extends r.Disposable{constructor(e){super(),this._maxLength=e,this.onDeleteEmitter=this.register(new s.EventEmitter),this.onDelete=this.onDeleteEmitter.event,this.onInsertEmitter=this.register(new s.EventEmitter),this.onInsert=this.onInsertEmitter.event,this.onTrimEmitter=this.register(new s.EventEmitter),this.onTrim=this.onTrimEmitter.event,this._array=new Array(this._maxLength),this._startIndex=0,this._length=0}get maxLength(){return this._maxLength}set maxLength(e){if(this._maxLength===e)return;const t=new Array(e);for(let i=0;ithis._length)for(let t=this._length;t=e;t--)this._array[this._getCyclicIndex(t+i.length)]=this._array[this._getCyclicIndex(t)];for(let t=0;tthis._maxLength){const e=this._length+i.length-this._maxLength;this._startIndex+=e,this._length=this._maxLength,this.onTrimEmitter.fire(e)}else this._length+=i.length}trimStart(e){e>this._length&&(e=this._length),this._startIndex+=e,this._length-=e,this.onTrimEmitter.fire(e)}shiftElements(e,t,i){if(!(t<=0)){if(e<0||e>=this._length)throw new Error("start argument out of range");if(e+i<0)throw new Error("Cannot shift elements in list beyond index 0");if(i>0){for(let s=t-1;s>=0;s--)this.set(e+s+i,this.get(e+s));const s=e+t+i-this._length;if(s>0)for(this._length+=s;this._length>this._maxLength;)this._length--,this._startIndex++,this.onTrimEmitter.fire(1)}else for(let s=0;s{Object.defineProperty(t,"__esModule",{value:!0}),t.clone=void 0,t.clone=function e(t,i=5){if("object"!=typeof t)return t;const s=Array.isArray(t)?[]:{};for(const r in t)s[r]=i<=1?t[r]:t[r]&&e(t[r],i-1);return s}},8055:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.contrastRatio=t.toPaddedHex=t.rgba=t.rgb=t.css=t.color=t.channels=t.NULL_COLOR=void 0;const s=i(6114);let r=0,n=0,o=0,a=0;var h,c,l,d,_;function u(e){const t=e.toString(16);return t.length<2?"0"+t:t}function f(e,t){return e>>0},e.toColor=function(t,i,s,r){return{css:e.toCss(t,i,s,r),rgba:e.toRgba(t,i,s,r)}}}(h||(t.channels=h={})),function(e){function t(e,t){return a=Math.round(255*t),[r,n,o]=_.toChannels(e.rgba),{css:h.toCss(r,n,o,a),rgba:h.toRgba(r,n,o,a)}}e.blend=function(e,t){if(a=(255&t.rgba)/255,1===a)return{css:t.css,rgba:t.rgba};const i=t.rgba>>24&255,s=t.rgba>>16&255,c=t.rgba>>8&255,l=e.rgba>>24&255,d=e.rgba>>16&255,_=e.rgba>>8&255;return r=l+Math.round((i-l)*a),n=d+Math.round((s-d)*a),o=_+Math.round((c-_)*a),{css:h.toCss(r,n,o),rgba:h.toRgba(r,n,o)}},e.isOpaque=function(e){return 255==(255&e.rgba)},e.ensureContrastRatio=function(e,t,i){const s=_.ensureContrastRatio(e.rgba,t.rgba,i);if(s)return h.toColor(s>>24&255,s>>16&255,s>>8&255)},e.opaque=function(e){const t=(255|e.rgba)>>>0;return[r,n,o]=_.toChannels(t),{css:h.toCss(r,n,o),rgba:t}},e.opacity=t,e.multiplyOpacity=function(e,i){return a=255&e.rgba,t(e,a*i/255)},e.toColorRGB=function(e){return[e.rgba>>24&255,e.rgba>>16&255,e.rgba>>8&255]}}(c||(t.color=c={})),function(e){let t,i;if(!s.isNode){const e=document.createElement("canvas");e.width=1,e.height=1;const s=e.getContext("2d",{willReadFrequently:!0});s&&(t=s,t.globalCompositeOperation="copy",i=t.createLinearGradient(0,0,1,1))}e.toColor=function(e){if(e.match(/#[\da-f]{3,8}/i))switch(e.length){case 4:return r=parseInt(e.slice(1,2).repeat(2),16),n=parseInt(e.slice(2,3).repeat(2),16),o=parseInt(e.slice(3,4).repeat(2),16),h.toColor(r,n,o);case 5:return r=parseInt(e.slice(1,2).repeat(2),16),n=parseInt(e.slice(2,3).repeat(2),16),o=parseInt(e.slice(3,4).repeat(2),16),a=parseInt(e.slice(4,5).repeat(2),16),h.toColor(r,n,o,a);case 7:return{css:e,rgba:(parseInt(e.slice(1),16)<<8|255)>>>0};case 9:return{css:e,rgba:parseInt(e.slice(1),16)>>>0}}const s=e.match(/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(,\s*(0|1|\d?\.(\d+))\s*)?\)/);if(s)return r=parseInt(s[1]),n=parseInt(s[2]),o=parseInt(s[3]),a=Math.round(255*(void 0===s[5]?1:parseFloat(s[5]))),h.toColor(r,n,o,a);if(!t||!i)throw new Error("css.toColor: Unsupported css format");if(t.fillStyle=i,t.fillStyle=e,"string"!=typeof t.fillStyle)throw new Error("css.toColor: Unsupported css format");if(t.fillRect(0,0,1,1),[r,n,o,a]=t.getImageData(0,0,1,1).data,255!==a)throw new Error("css.toColor: Unsupported css format");return{rgba:h.toRgba(r,n,o,a),css:e}}}(l||(t.css=l={})),function(e){function t(e,t,i){const s=e/255,r=t/255,n=i/255;return.2126*(s<=.03928?s/12.92:Math.pow((s+.055)/1.055,2.4))+.7152*(r<=.03928?r/12.92:Math.pow((r+.055)/1.055,2.4))+.0722*(n<=.03928?n/12.92:Math.pow((n+.055)/1.055,2.4))}e.relativeLuminance=function(e){return t(e>>16&255,e>>8&255,255&e)},e.relativeLuminance2=t}(d||(t.rgb=d={})),function(e){function t(e,t,i){const s=e>>24&255,r=e>>16&255,n=e>>8&255;let o=t>>24&255,a=t>>16&255,h=t>>8&255,c=f(d.relativeLuminance2(o,a,h),d.relativeLuminance2(s,r,n));for(;c0||a>0||h>0);)o-=Math.max(0,Math.ceil(.1*o)),a-=Math.max(0,Math.ceil(.1*a)),h-=Math.max(0,Math.ceil(.1*h)),c=f(d.relativeLuminance2(o,a,h),d.relativeLuminance2(s,r,n));return(o<<24|a<<16|h<<8|255)>>>0}function i(e,t,i){const s=e>>24&255,r=e>>16&255,n=e>>8&255;let o=t>>24&255,a=t>>16&255,h=t>>8&255,c=f(d.relativeLuminance2(o,a,h),d.relativeLuminance2(s,r,n));for(;c>>0}e.blend=function(e,t){if(a=(255&t)/255,1===a)return t;const i=t>>24&255,s=t>>16&255,c=t>>8&255,l=e>>24&255,d=e>>16&255,_=e>>8&255;return r=l+Math.round((i-l)*a),n=d+Math.round((s-d)*a),o=_+Math.round((c-_)*a),h.toRgba(r,n,o)},e.ensureContrastRatio=function(e,s,r){const n=d.relativeLuminance(e>>8),o=d.relativeLuminance(s>>8);if(f(n,o)>8));if(af(n,d.relativeLuminance(t>>8))?o:t}return o}const a=i(e,s,r),h=f(n,d.relativeLuminance(a>>8));if(hf(n,d.relativeLuminance(i>>8))?a:i}return a}},e.reduceLuminance=t,e.increaseLuminance=i,e.toChannels=function(e){return[e>>24&255,e>>16&255,e>>8&255,255&e]}}(_||(t.rgba=_={})),t.toPaddedHex=u,t.contrastRatio=f},8969:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.CoreTerminal=void 0;const s=i(844),r=i(2585),n=i(4348),o=i(7866),a=i(744),h=i(7302),c=i(6975),l=i(8460),d=i(1753),_=i(1480),u=i(7994),f=i(9282),v=i(5435),p=i(5981),g=i(2660);let m=!1;class S extends s.Disposable{get onScroll(){return this._onScrollApi||(this._onScrollApi=this.register(new l.EventEmitter),this._onScroll.event((e=>{this._onScrollApi?.fire(e.position)}))),this._onScrollApi.event}get cols(){return this._bufferService.cols}get rows(){return this._bufferService.rows}get buffers(){return this._bufferService.buffers}get options(){return this.optionsService.options}set options(e){for(const t in e)this.optionsService.options[t]=e[t]}constructor(e){super(),this._windowsWrappingHeuristics=this.register(new s.MutableDisposable),this._onBinary=this.register(new l.EventEmitter),this.onBinary=this._onBinary.event,this._onData=this.register(new l.EventEmitter),this.onData=this._onData.event,this._onLineFeed=this.register(new l.EventEmitter),this.onLineFeed=this._onLineFeed.event,this._onResize=this.register(new l.EventEmitter),this.onResize=this._onResize.event,this._onWriteParsed=this.register(new l.EventEmitter),this.onWriteParsed=this._onWriteParsed.event,this._onScroll=this.register(new l.EventEmitter),this._instantiationService=new n.InstantiationService,this.optionsService=this.register(new h.OptionsService(e)),this._instantiationService.setService(r.IOptionsService,this.optionsService),this._bufferService=this.register(this._instantiationService.createInstance(a.BufferService)),this._instantiationService.setService(r.IBufferService,this._bufferService),this._logService=this.register(this._instantiationService.createInstance(o.LogService)),this._instantiationService.setService(r.ILogService,this._logService),this.coreService=this.register(this._instantiationService.createInstance(c.CoreService)),this._instantiationService.setService(r.ICoreService,this.coreService),this.coreMouseService=this.register(this._instantiationService.createInstance(d.CoreMouseService)),this._instantiationService.setService(r.ICoreMouseService,this.coreMouseService),this.unicodeService=this.register(this._instantiationService.createInstance(_.UnicodeService)),this._instantiationService.setService(r.IUnicodeService,this.unicodeService),this._charsetService=this._instantiationService.createInstance(u.CharsetService),this._instantiationService.setService(r.ICharsetService,this._charsetService),this._oscLinkService=this._instantiationService.createInstance(g.OscLinkService),this._instantiationService.setService(r.IOscLinkService,this._oscLinkService),this._inputHandler=this.register(new v.InputHandler(this._bufferService,this._charsetService,this.coreService,this._logService,this.optionsService,this._oscLinkService,this.coreMouseService,this.unicodeService)),this.register((0,l.forwardEvent)(this._inputHandler.onLineFeed,this._onLineFeed)),this.register(this._inputHandler),this.register((0,l.forwardEvent)(this._bufferService.onResize,this._onResize)),this.register((0,l.forwardEvent)(this.coreService.onData,this._onData)),this.register((0,l.forwardEvent)(this.coreService.onBinary,this._onBinary)),this.register(this.coreService.onRequestScrollToBottom((()=>this.scrollToBottom()))),this.register(this.coreService.onUserInput((()=>this._writeBuffer.handleUserInput()))),this.register(this.optionsService.onMultipleOptionChange(["windowsMode","windowsPty"],(()=>this._handleWindowsPtyOptionChange()))),this.register(this._bufferService.onScroll((e=>{this._onScroll.fire({position:this._bufferService.buffer.ydisp,source:0}),this._inputHandler.markRangeDirty(this._bufferService.buffer.scrollTop,this._bufferService.buffer.scrollBottom)}))),this.register(this._inputHandler.onScroll((e=>{this._onScroll.fire({position:this._bufferService.buffer.ydisp,source:0}),this._inputHandler.markRangeDirty(this._bufferService.buffer.scrollTop,this._bufferService.buffer.scrollBottom)}))),this._writeBuffer=this.register(new p.WriteBuffer(((e,t)=>this._inputHandler.parse(e,t)))),this.register((0,l.forwardEvent)(this._writeBuffer.onWriteParsed,this._onWriteParsed))}write(e,t){this._writeBuffer.write(e,t)}writeSync(e,t){this._logService.logLevel<=r.LogLevelEnum.WARN&&!m&&(this._logService.warn("writeSync is unreliable and will be removed soon."),m=!0),this._writeBuffer.writeSync(e,t)}input(e,t=!0){this.coreService.triggerDataEvent(e,t)}resize(e,t){isNaN(e)||isNaN(t)||(e=Math.max(e,a.MINIMUM_COLS),t=Math.max(t,a.MINIMUM_ROWS),this._bufferService.resize(e,t))}scroll(e,t=!1){this._bufferService.scroll(e,t)}scrollLines(e,t,i){this._bufferService.scrollLines(e,t,i)}scrollPages(e){this.scrollLines(e*(this.rows-1))}scrollToTop(){this.scrollLines(-this._bufferService.buffer.ydisp)}scrollToBottom(){this.scrollLines(this._bufferService.buffer.ybase-this._bufferService.buffer.ydisp)}scrollToLine(e){const t=e-this._bufferService.buffer.ydisp;0!==t&&this.scrollLines(t)}registerEscHandler(e,t){return this._inputHandler.registerEscHandler(e,t)}registerDcsHandler(e,t){return this._inputHandler.registerDcsHandler(e,t)}registerCsiHandler(e,t){return this._inputHandler.registerCsiHandler(e,t)}registerOscHandler(e,t){return this._inputHandler.registerOscHandler(e,t)}_setup(){this._handleWindowsPtyOptionChange()}reset(){this._inputHandler.reset(),this._bufferService.reset(),this._charsetService.reset(),this.coreService.reset(),this.coreMouseService.reset()}_handleWindowsPtyOptionChange(){let e=!1;const t=this.optionsService.rawOptions.windowsPty;t&&void 0!==t.buildNumber&&void 0!==t.buildNumber?e=!!("conpty"===t.backend&&t.buildNumber<21376):this.optionsService.rawOptions.windowsMode&&(e=!0),e?this._enableWindowsWrappingHeuristics():this._windowsWrappingHeuristics.clear()}_enableWindowsWrappingHeuristics(){if(!this._windowsWrappingHeuristics.value){const e=[];e.push(this.onLineFeed(f.updateWindowsModeWrappedState.bind(null,this._bufferService))),e.push(this.registerCsiHandler({final:"H"},(()=>((0,f.updateWindowsModeWrappedState)(this._bufferService),!1)))),this._windowsWrappingHeuristics.value=(0,s.toDisposable)((()=>{for(const t of e)t.dispose()}))}}}t.CoreTerminal=S},8460:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.runAndSubscribe=t.forwardEvent=t.EventEmitter=void 0,t.EventEmitter=class{constructor(){this._listeners=[],this._disposed=!1}get event(){return this._event||(this._event=e=>(this._listeners.push(e),{dispose:()=>{if(!this._disposed)for(let t=0;tt.fire(e)))},t.runAndSubscribe=function(e,t){return t(void 0),e((e=>t(e)))}},5435:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.InputHandler=t.WindowsOptionsReportType=void 0;const n=i(2584),o=i(7116),a=i(2015),h=i(844),c=i(482),l=i(8437),d=i(8460),_=i(643),u=i(511),f=i(3734),v=i(2585),p=i(1480),g=i(6242),m=i(6351),S=i(5941),C={"(":0,")":1,"*":2,"+":3,"-":1,".":2},b=131072;function w(e,t){if(e>24)return t.setWinLines||!1;switch(e){case 1:return!!t.restoreWin;case 2:return!!t.minimizeWin;case 3:return!!t.setWinPosition;case 4:return!!t.setWinSizePixels;case 5:return!!t.raiseWin;case 6:return!!t.lowerWin;case 7:return!!t.refreshWin;case 8:return!!t.setWinSizeChars;case 9:return!!t.maximizeWin;case 10:return!!t.fullscreenWin;case 11:return!!t.getWinState;case 13:return!!t.getWinPosition;case 14:return!!t.getWinSizePixels;case 15:return!!t.getScreenSizePixels;case 16:return!!t.getCellSizePixels;case 18:return!!t.getWinSizeChars;case 19:return!!t.getScreenSizeChars;case 20:return!!t.getIconTitle;case 21:return!!t.getWinTitle;case 22:return!!t.pushTitle;case 23:return!!t.popTitle;case 24:return!!t.setWinLines}return!1}var y;!function(e){e[e.GET_WIN_SIZE_PIXELS=0]="GET_WIN_SIZE_PIXELS",e[e.GET_CELL_SIZE_PIXELS=1]="GET_CELL_SIZE_PIXELS"}(y||(t.WindowsOptionsReportType=y={}));let E=0;class k extends h.Disposable{getAttrData(){return this._curAttrData}constructor(e,t,i,s,r,h,_,f,v=new a.EscapeSequenceParser){super(),this._bufferService=e,this._charsetService=t,this._coreService=i,this._logService=s,this._optionsService=r,this._oscLinkService=h,this._coreMouseService=_,this._unicodeService=f,this._parser=v,this._parseBuffer=new Uint32Array(4096),this._stringDecoder=new c.StringToUtf32,this._utf8Decoder=new c.Utf8ToUtf32,this._workCell=new u.CellData,this._windowTitle="",this._iconName="",this._windowTitleStack=[],this._iconNameStack=[],this._curAttrData=l.DEFAULT_ATTR_DATA.clone(),this._eraseAttrDataInternal=l.DEFAULT_ATTR_DATA.clone(),this._onRequestBell=this.register(new d.EventEmitter),this.onRequestBell=this._onRequestBell.event,this._onRequestRefreshRows=this.register(new d.EventEmitter),this.onRequestRefreshRows=this._onRequestRefreshRows.event,this._onRequestReset=this.register(new d.EventEmitter),this.onRequestReset=this._onRequestReset.event,this._onRequestSendFocus=this.register(new d.EventEmitter),this.onRequestSendFocus=this._onRequestSendFocus.event,this._onRequestSyncScrollBar=this.register(new d.EventEmitter),this.onRequestSyncScrollBar=this._onRequestSyncScrollBar.event,this._onRequestWindowsOptionsReport=this.register(new d.EventEmitter),this.onRequestWindowsOptionsReport=this._onRequestWindowsOptionsReport.event,this._onA11yChar=this.register(new d.EventEmitter),this.onA11yChar=this._onA11yChar.event,this._onA11yTab=this.register(new d.EventEmitter),this.onA11yTab=this._onA11yTab.event,this._onCursorMove=this.register(new d.EventEmitter),this.onCursorMove=this._onCursorMove.event,this._onLineFeed=this.register(new d.EventEmitter),this.onLineFeed=this._onLineFeed.event,this._onScroll=this.register(new d.EventEmitter),this.onScroll=this._onScroll.event,this._onTitleChange=this.register(new d.EventEmitter),this.onTitleChange=this._onTitleChange.event,this._onColor=this.register(new d.EventEmitter),this.onColor=this._onColor.event,this._parseStack={paused:!1,cursorStartX:0,cursorStartY:0,decodedLength:0,position:0},this._specialColors=[256,257,258],this.register(this._parser),this._dirtyRowTracker=new L(this._bufferService),this._activeBuffer=this._bufferService.buffer,this.register(this._bufferService.buffers.onBufferActivate((e=>this._activeBuffer=e.activeBuffer))),this._parser.setCsiHandlerFallback(((e,t)=>{this._logService.debug("Unknown CSI code: ",{identifier:this._parser.identToString(e),params:t.toArray()})})),this._parser.setEscHandlerFallback((e=>{this._logService.debug("Unknown ESC code: ",{identifier:this._parser.identToString(e)})})),this._parser.setExecuteHandlerFallback((e=>{this._logService.debug("Unknown EXECUTE code: ",{code:e})})),this._parser.setOscHandlerFallback(((e,t,i)=>{this._logService.debug("Unknown OSC code: ",{identifier:e,action:t,data:i})})),this._parser.setDcsHandlerFallback(((e,t,i)=>{"HOOK"===t&&(i=i.toArray()),this._logService.debug("Unknown DCS code: ",{identifier:this._parser.identToString(e),action:t,payload:i})})),this._parser.setPrintHandler(((e,t,i)=>this.print(e,t,i))),this._parser.registerCsiHandler({final:"@"},(e=>this.insertChars(e))),this._parser.registerCsiHandler({intermediates:" ",final:"@"},(e=>this.scrollLeft(e))),this._parser.registerCsiHandler({final:"A"},(e=>this.cursorUp(e))),this._parser.registerCsiHandler({intermediates:" ",final:"A"},(e=>this.scrollRight(e))),this._parser.registerCsiHandler({final:"B"},(e=>this.cursorDown(e))),this._parser.registerCsiHandler({final:"C"},(e=>this.cursorForward(e))),this._parser.registerCsiHandler({final:"D"},(e=>this.cursorBackward(e))),this._parser.registerCsiHandler({final:"E"},(e=>this.cursorNextLine(e))),this._parser.registerCsiHandler({final:"F"},(e=>this.cursorPrecedingLine(e))),this._parser.registerCsiHandler({final:"G"},(e=>this.cursorCharAbsolute(e))),this._parser.registerCsiHandler({final:"H"},(e=>this.cursorPosition(e))),this._parser.registerCsiHandler({final:"I"},(e=>this.cursorForwardTab(e))),this._parser.registerCsiHandler({final:"J"},(e=>this.eraseInDisplay(e,!1))),this._parser.registerCsiHandler({prefix:"?",final:"J"},(e=>this.eraseInDisplay(e,!0))),this._parser.registerCsiHandler({final:"K"},(e=>this.eraseInLine(e,!1))),this._parser.registerCsiHandler({prefix:"?",final:"K"},(e=>this.eraseInLine(e,!0))),this._parser.registerCsiHandler({final:"L"},(e=>this.insertLines(e))),this._parser.registerCsiHandler({final:"M"},(e=>this.deleteLines(e))),this._parser.registerCsiHandler({final:"P"},(e=>this.deleteChars(e))),this._parser.registerCsiHandler({final:"S"},(e=>this.scrollUp(e))),this._parser.registerCsiHandler({final:"T"},(e=>this.scrollDown(e))),this._parser.registerCsiHandler({final:"X"},(e=>this.eraseChars(e))),this._parser.registerCsiHandler({final:"Z"},(e=>this.cursorBackwardTab(e))),this._parser.registerCsiHandler({final:"`"},(e=>this.charPosAbsolute(e))),this._parser.registerCsiHandler({final:"a"},(e=>this.hPositionRelative(e))),this._parser.registerCsiHandler({final:"b"},(e=>this.repeatPrecedingCharacter(e))),this._parser.registerCsiHandler({final:"c"},(e=>this.sendDeviceAttributesPrimary(e))),this._parser.registerCsiHandler({prefix:">",final:"c"},(e=>this.sendDeviceAttributesSecondary(e))),this._parser.registerCsiHandler({final:"d"},(e=>this.linePosAbsolute(e))),this._parser.registerCsiHandler({final:"e"},(e=>this.vPositionRelative(e))),this._parser.registerCsiHandler({final:"f"},(e=>this.hVPosition(e))),this._parser.registerCsiHandler({final:"g"},(e=>this.tabClear(e))),this._parser.registerCsiHandler({final:"h"},(e=>this.setMode(e))),this._parser.registerCsiHandler({prefix:"?",final:"h"},(e=>this.setModePrivate(e))),this._parser.registerCsiHandler({final:"l"},(e=>this.resetMode(e))),this._parser.registerCsiHandler({prefix:"?",final:"l"},(e=>this.resetModePrivate(e))),this._parser.registerCsiHandler({final:"m"},(e=>this.charAttributes(e))),this._parser.registerCsiHandler({final:"n"},(e=>this.deviceStatus(e))),this._parser.registerCsiHandler({prefix:"?",final:"n"},(e=>this.deviceStatusPrivate(e))),this._parser.registerCsiHandler({intermediates:"!",final:"p"},(e=>this.softReset(e))),this._parser.registerCsiHandler({intermediates:" ",final:"q"},(e=>this.setCursorStyle(e))),this._parser.registerCsiHandler({final:"r"},(e=>this.setScrollRegion(e))),this._parser.registerCsiHandler({final:"s"},(e=>this.saveCursor(e))),this._parser.registerCsiHandler({final:"t"},(e=>this.windowOptions(e))),this._parser.registerCsiHandler({final:"u"},(e=>this.restoreCursor(e))),this._parser.registerCsiHandler({intermediates:"'",final:"}"},(e=>this.insertColumns(e))),this._parser.registerCsiHandler({intermediates:"'",final:"~"},(e=>this.deleteColumns(e))),this._parser.registerCsiHandler({intermediates:'"',final:"q"},(e=>this.selectProtected(e))),this._parser.registerCsiHandler({intermediates:"$",final:"p"},(e=>this.requestMode(e,!0))),this._parser.registerCsiHandler({prefix:"?",intermediates:"$",final:"p"},(e=>this.requestMode(e,!1))),this._parser.setExecuteHandler(n.C0.BEL,(()=>this.bell())),this._parser.setExecuteHandler(n.C0.LF,(()=>this.lineFeed())),this._parser.setExecuteHandler(n.C0.VT,(()=>this.lineFeed())),this._parser.setExecuteHandler(n.C0.FF,(()=>this.lineFeed())),this._parser.setExecuteHandler(n.C0.CR,(()=>this.carriageReturn())),this._parser.setExecuteHandler(n.C0.BS,(()=>this.backspace())),this._parser.setExecuteHandler(n.C0.HT,(()=>this.tab())),this._parser.setExecuteHandler(n.C0.SO,(()=>this.shiftOut())),this._parser.setExecuteHandler(n.C0.SI,(()=>this.shiftIn())),this._parser.setExecuteHandler(n.C1.IND,(()=>this.index())),this._parser.setExecuteHandler(n.C1.NEL,(()=>this.nextLine())),this._parser.setExecuteHandler(n.C1.HTS,(()=>this.tabSet())),this._parser.registerOscHandler(0,new g.OscHandler((e=>(this.setTitle(e),this.setIconName(e),!0)))),this._parser.registerOscHandler(1,new g.OscHandler((e=>this.setIconName(e)))),this._parser.registerOscHandler(2,new g.OscHandler((e=>this.setTitle(e)))),this._parser.registerOscHandler(4,new g.OscHandler((e=>this.setOrReportIndexedColor(e)))),this._parser.registerOscHandler(8,new g.OscHandler((e=>this.setHyperlink(e)))),this._parser.registerOscHandler(10,new g.OscHandler((e=>this.setOrReportFgColor(e)))),this._parser.registerOscHandler(11,new g.OscHandler((e=>this.setOrReportBgColor(e)))),this._parser.registerOscHandler(12,new g.OscHandler((e=>this.setOrReportCursorColor(e)))),this._parser.registerOscHandler(104,new g.OscHandler((e=>this.restoreIndexedColor(e)))),this._parser.registerOscHandler(110,new g.OscHandler((e=>this.restoreFgColor(e)))),this._parser.registerOscHandler(111,new g.OscHandler((e=>this.restoreBgColor(e)))),this._parser.registerOscHandler(112,new g.OscHandler((e=>this.restoreCursorColor(e)))),this._parser.registerEscHandler({final:"7"},(()=>this.saveCursor())),this._parser.registerEscHandler({final:"8"},(()=>this.restoreCursor())),this._parser.registerEscHandler({final:"D"},(()=>this.index())),this._parser.registerEscHandler({final:"E"},(()=>this.nextLine())),this._parser.registerEscHandler({final:"H"},(()=>this.tabSet())),this._parser.registerEscHandler({final:"M"},(()=>this.reverseIndex())),this._parser.registerEscHandler({final:"="},(()=>this.keypadApplicationMode())),this._parser.registerEscHandler({final:">"},(()=>this.keypadNumericMode())),this._parser.registerEscHandler({final:"c"},(()=>this.fullReset())),this._parser.registerEscHandler({final:"n"},(()=>this.setgLevel(2))),this._parser.registerEscHandler({final:"o"},(()=>this.setgLevel(3))),this._parser.registerEscHandler({final:"|"},(()=>this.setgLevel(3))),this._parser.registerEscHandler({final:"}"},(()=>this.setgLevel(2))),this._parser.registerEscHandler({final:"~"},(()=>this.setgLevel(1))),this._parser.registerEscHandler({intermediates:"%",final:"@"},(()=>this.selectDefaultCharset())),this._parser.registerEscHandler({intermediates:"%",final:"G"},(()=>this.selectDefaultCharset()));for(const e in o.CHARSETS)this._parser.registerEscHandler({intermediates:"(",final:e},(()=>this.selectCharset("("+e))),this._parser.registerEscHandler({intermediates:")",final:e},(()=>this.selectCharset(")"+e))),this._parser.registerEscHandler({intermediates:"*",final:e},(()=>this.selectCharset("*"+e))),this._parser.registerEscHandler({intermediates:"+",final:e},(()=>this.selectCharset("+"+e))),this._parser.registerEscHandler({intermediates:"-",final:e},(()=>this.selectCharset("-"+e))),this._parser.registerEscHandler({intermediates:".",final:e},(()=>this.selectCharset("."+e))),this._parser.registerEscHandler({intermediates:"/",final:e},(()=>this.selectCharset("/"+e)));this._parser.registerEscHandler({intermediates:"#",final:"8"},(()=>this.screenAlignmentPattern())),this._parser.setErrorHandler((e=>(this._logService.error("Parsing error: ",e),e))),this._parser.registerDcsHandler({intermediates:"$",final:"q"},new m.DcsHandler(((e,t)=>this.requestStatusString(e,t))))}_preserveStack(e,t,i,s){this._parseStack.paused=!0,this._parseStack.cursorStartX=e,this._parseStack.cursorStartY=t,this._parseStack.decodedLength=i,this._parseStack.position=s}_logSlowResolvingAsync(e){this._logService.logLevel<=v.LogLevelEnum.WARN&&Promise.race([e,new Promise(((e,t)=>setTimeout((()=>t("#SLOW_TIMEOUT")),5e3)))]).catch((e=>{if("#SLOW_TIMEOUT"!==e)throw e;console.warn("async parser handler taking longer than 5000 ms")}))}_getCurrentLinkId(){return this._curAttrData.extended.urlId}parse(e,t){let i,s=this._activeBuffer.x,r=this._activeBuffer.y,n=0;const o=this._parseStack.paused;if(o){if(i=this._parser.parse(this._parseBuffer,this._parseStack.decodedLength,t))return this._logSlowResolvingAsync(i),i;s=this._parseStack.cursorStartX,r=this._parseStack.cursorStartY,this._parseStack.paused=!1,e.length>b&&(n=this._parseStack.position+b)}if(this._logService.logLevel<=v.LogLevelEnum.DEBUG&&this._logService.debug("parsing data"+("string"==typeof e?` "${e}"`:` "${Array.prototype.map.call(e,(e=>String.fromCharCode(e))).join("")}"`),"string"==typeof e?e.split("").map((e=>e.charCodeAt(0))):e),this._parseBuffer.lengthb)for(let t=n;t0&&2===f.getWidth(this._activeBuffer.x-1)&&f.setCellFromCodepoint(this._activeBuffer.x-1,0,1,u);let v=this._parser.precedingJoinState;for(let g=t;ga)if(h){const e=f;let t=this._activeBuffer.x-m;for(this._activeBuffer.x=m,this._activeBuffer.y++,this._activeBuffer.y===this._activeBuffer.scrollBottom+1?(this._activeBuffer.y--,this._bufferService.scroll(this._eraseAttrData(),!0)):(this._activeBuffer.y>=this._bufferService.rows&&(this._activeBuffer.y=this._bufferService.rows-1),this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y).isWrapped=!0),f=this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y),m>0&&f instanceof l.BufferLine&&f.copyCellsFrom(e,t,0,m,!1);t=0;)f.setCellFromCodepoint(this._activeBuffer.x++,0,0,u)}else if(d&&(f.insertCells(this._activeBuffer.x,r-m,this._activeBuffer.getNullCell(u)),2===f.getWidth(a-1)&&f.setCellFromCodepoint(a-1,_.NULL_CELL_CODE,_.NULL_CELL_WIDTH,u)),f.setCellFromCodepoint(this._activeBuffer.x++,s,r,u),r>0)for(;--r;)f.setCellFromCodepoint(this._activeBuffer.x++,0,0,u)}this._parser.precedingJoinState=v,this._activeBuffer.x0&&0===f.getWidth(this._activeBuffer.x)&&!f.hasContent(this._activeBuffer.x)&&f.setCellFromCodepoint(this._activeBuffer.x,0,1,u),this._dirtyRowTracker.markDirty(this._activeBuffer.y)}registerCsiHandler(e,t){return"t"!==e.final||e.prefix||e.intermediates?this._parser.registerCsiHandler(e,t):this._parser.registerCsiHandler(e,(e=>!w(e.params[0],this._optionsService.rawOptions.windowOptions)||t(e)))}registerDcsHandler(e,t){return this._parser.registerDcsHandler(e,new m.DcsHandler(t))}registerEscHandler(e,t){return this._parser.registerEscHandler(e,t)}registerOscHandler(e,t){return this._parser.registerOscHandler(e,new g.OscHandler(t))}bell(){return this._onRequestBell.fire(),!0}lineFeed(){return this._dirtyRowTracker.markDirty(this._activeBuffer.y),this._optionsService.rawOptions.convertEol&&(this._activeBuffer.x=0),this._activeBuffer.y++,this._activeBuffer.y===this._activeBuffer.scrollBottom+1?(this._activeBuffer.y--,this._bufferService.scroll(this._eraseAttrData())):this._activeBuffer.y>=this._bufferService.rows?this._activeBuffer.y=this._bufferService.rows-1:this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y).isWrapped=!1,this._activeBuffer.x>=this._bufferService.cols&&this._activeBuffer.x--,this._dirtyRowTracker.markDirty(this._activeBuffer.y),this._onLineFeed.fire(),!0}carriageReturn(){return this._activeBuffer.x=0,!0}backspace(){if(!this._coreService.decPrivateModes.reverseWraparound)return this._restrictCursor(),this._activeBuffer.x>0&&this._activeBuffer.x--,!0;if(this._restrictCursor(this._bufferService.cols),this._activeBuffer.x>0)this._activeBuffer.x--;else if(0===this._activeBuffer.x&&this._activeBuffer.y>this._activeBuffer.scrollTop&&this._activeBuffer.y<=this._activeBuffer.scrollBottom&&this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y)?.isWrapped){this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y).isWrapped=!1,this._activeBuffer.y--,this._activeBuffer.x=this._bufferService.cols-1;const e=this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y);e.hasWidth(this._activeBuffer.x)&&!e.hasContent(this._activeBuffer.x)&&this._activeBuffer.x--}return this._restrictCursor(),!0}tab(){if(this._activeBuffer.x>=this._bufferService.cols)return!0;const e=this._activeBuffer.x;return this._activeBuffer.x=this._activeBuffer.nextStop(),this._optionsService.rawOptions.screenReaderMode&&this._onA11yTab.fire(this._activeBuffer.x-e),!0}shiftOut(){return this._charsetService.setgLevel(1),!0}shiftIn(){return this._charsetService.setgLevel(0),!0}_restrictCursor(e=this._bufferService.cols-1){this._activeBuffer.x=Math.min(e,Math.max(0,this._activeBuffer.x)),this._activeBuffer.y=this._coreService.decPrivateModes.origin?Math.min(this._activeBuffer.scrollBottom,Math.max(this._activeBuffer.scrollTop,this._activeBuffer.y)):Math.min(this._bufferService.rows-1,Math.max(0,this._activeBuffer.y)),this._dirtyRowTracker.markDirty(this._activeBuffer.y)}_setCursor(e,t){this._dirtyRowTracker.markDirty(this._activeBuffer.y),this._coreService.decPrivateModes.origin?(this._activeBuffer.x=e,this._activeBuffer.y=this._activeBuffer.scrollTop+t):(this._activeBuffer.x=e,this._activeBuffer.y=t),this._restrictCursor(),this._dirtyRowTracker.markDirty(this._activeBuffer.y)}_moveCursor(e,t){this._restrictCursor(),this._setCursor(this._activeBuffer.x+e,this._activeBuffer.y+t)}cursorUp(e){const t=this._activeBuffer.y-this._activeBuffer.scrollTop;return t>=0?this._moveCursor(0,-Math.min(t,e.params[0]||1)):this._moveCursor(0,-(e.params[0]||1)),!0}cursorDown(e){const t=this._activeBuffer.scrollBottom-this._activeBuffer.y;return t>=0?this._moveCursor(0,Math.min(t,e.params[0]||1)):this._moveCursor(0,e.params[0]||1),!0}cursorForward(e){return this._moveCursor(e.params[0]||1,0),!0}cursorBackward(e){return this._moveCursor(-(e.params[0]||1),0),!0}cursorNextLine(e){return this.cursorDown(e),this._activeBuffer.x=0,!0}cursorPrecedingLine(e){return this.cursorUp(e),this._activeBuffer.x=0,!0}cursorCharAbsolute(e){return this._setCursor((e.params[0]||1)-1,this._activeBuffer.y),!0}cursorPosition(e){return this._setCursor(e.length>=2?(e.params[1]||1)-1:0,(e.params[0]||1)-1),!0}charPosAbsolute(e){return this._setCursor((e.params[0]||1)-1,this._activeBuffer.y),!0}hPositionRelative(e){return this._moveCursor(e.params[0]||1,0),!0}linePosAbsolute(e){return this._setCursor(this._activeBuffer.x,(e.params[0]||1)-1),!0}vPositionRelative(e){return this._moveCursor(0,e.params[0]||1),!0}hVPosition(e){return this.cursorPosition(e),!0}tabClear(e){const t=e.params[0];return 0===t?delete this._activeBuffer.tabs[this._activeBuffer.x]:3===t&&(this._activeBuffer.tabs={}),!0}cursorForwardTab(e){if(this._activeBuffer.x>=this._bufferService.cols)return!0;let t=e.params[0]||1;for(;t--;)this._activeBuffer.x=this._activeBuffer.nextStop();return!0}cursorBackwardTab(e){if(this._activeBuffer.x>=this._bufferService.cols)return!0;let t=e.params[0]||1;for(;t--;)this._activeBuffer.x=this._activeBuffer.prevStop();return!0}selectProtected(e){const t=e.params[0];return 1===t&&(this._curAttrData.bg|=536870912),2!==t&&0!==t||(this._curAttrData.bg&=-536870913),!0}_eraseInBufferLine(e,t,i,s=!1,r=!1){const n=this._activeBuffer.lines.get(this._activeBuffer.ybase+e);n.replaceCells(t,i,this._activeBuffer.getNullCell(this._eraseAttrData()),r),s&&(n.isWrapped=!1)}_resetBufferLine(e,t=!1){const i=this._activeBuffer.lines.get(this._activeBuffer.ybase+e);i&&(i.fill(this._activeBuffer.getNullCell(this._eraseAttrData()),t),this._bufferService.buffer.clearMarkers(this._activeBuffer.ybase+e),i.isWrapped=!1)}eraseInDisplay(e,t=!1){let i;switch(this._restrictCursor(this._bufferService.cols),e.params[0]){case 0:for(i=this._activeBuffer.y,this._dirtyRowTracker.markDirty(i),this._eraseInBufferLine(i++,this._activeBuffer.x,this._bufferService.cols,0===this._activeBuffer.x,t);i=this._bufferService.cols&&(this._activeBuffer.lines.get(i+1).isWrapped=!1);i--;)this._resetBufferLine(i,t);this._dirtyRowTracker.markDirty(0);break;case 2:for(i=this._bufferService.rows,this._dirtyRowTracker.markDirty(i-1);i--;)this._resetBufferLine(i,t);this._dirtyRowTracker.markDirty(0);break;case 3:const e=this._activeBuffer.lines.length-this._bufferService.rows;e>0&&(this._activeBuffer.lines.trimStart(e),this._activeBuffer.ybase=Math.max(this._activeBuffer.ybase-e,0),this._activeBuffer.ydisp=Math.max(this._activeBuffer.ydisp-e,0),this._onScroll.fire(0))}return!0}eraseInLine(e,t=!1){switch(this._restrictCursor(this._bufferService.cols),e.params[0]){case 0:this._eraseInBufferLine(this._activeBuffer.y,this._activeBuffer.x,this._bufferService.cols,0===this._activeBuffer.x,t);break;case 1:this._eraseInBufferLine(this._activeBuffer.y,0,this._activeBuffer.x+1,!1,t);break;case 2:this._eraseInBufferLine(this._activeBuffer.y,0,this._bufferService.cols,!0,t)}return this._dirtyRowTracker.markDirty(this._activeBuffer.y),!0}insertLines(e){this._restrictCursor();let t=e.params[0]||1;if(this._activeBuffer.y>this._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.y65535?2:1}let h=a;for(let e=1;e0||(this._is("xterm")||this._is("rxvt-unicode")||this._is("screen")?this._coreService.triggerDataEvent(n.C0.ESC+"[?1;2c"):this._is("linux")&&this._coreService.triggerDataEvent(n.C0.ESC+"[?6c")),!0}sendDeviceAttributesSecondary(e){return e.params[0]>0||(this._is("xterm")?this._coreService.triggerDataEvent(n.C0.ESC+"[>0;276;0c"):this._is("rxvt-unicode")?this._coreService.triggerDataEvent(n.C0.ESC+"[>85;95;0c"):this._is("linux")?this._coreService.triggerDataEvent(e.params[0]+"c"):this._is("screen")&&this._coreService.triggerDataEvent(n.C0.ESC+"[>83;40003;0c")),!0}_is(e){return 0===(this._optionsService.rawOptions.termName+"").indexOf(e)}setMode(e){for(let t=0;te?1:2,u=e.params[0];return f=u,v=t?2===u?4:4===u?_(o.modes.insertMode):12===u?3:20===u?_(d.convertEol):0:1===u?_(i.applicationCursorKeys):3===u?d.windowOptions.setWinLines?80===h?2:132===h?1:0:0:6===u?_(i.origin):7===u?_(i.wraparound):8===u?3:9===u?_("X10"===s):12===u?_(d.cursorBlink):25===u?_(!o.isCursorHidden):45===u?_(i.reverseWraparound):66===u?_(i.applicationKeypad):67===u?4:1e3===u?_("VT200"===s):1002===u?_("DRAG"===s):1003===u?_("ANY"===s):1004===u?_(i.sendFocus):1005===u?4:1006===u?_("SGR"===r):1015===u?4:1016===u?_("SGR_PIXELS"===r):1048===u?1:47===u||1047===u||1049===u?_(c===l):2004===u?_(i.bracketedPasteMode):0,o.triggerDataEvent(`${n.C0.ESC}[${t?"":"?"}${f};${v}$y`),!0;var f,v}_updateAttrColor(e,t,i,s,r){return 2===t?(e|=50331648,e&=-16777216,e|=f.AttributeData.fromColorRGB([i,s,r])):5===t&&(e&=-50331904,e|=33554432|255&i),e}_extractColor(e,t,i){const s=[0,0,-1,0,0,0];let r=0,n=0;do{if(s[n+r]=e.params[t+n],e.hasSubParams(t+n)){const i=e.getSubParams(t+n);let o=0;do{5===s[1]&&(r=1),s[n+o+1+r]=i[o]}while(++o=2||2===s[1]&&n+r>=5)break;s[1]&&(r=1)}while(++n+t5)&&(e=1),t.extended.underlineStyle=e,t.fg|=268435456,0===e&&(t.fg&=-268435457),t.updateExtended()}_processSGR0(e){e.fg=l.DEFAULT_ATTR_DATA.fg,e.bg=l.DEFAULT_ATTR_DATA.bg,e.extended=e.extended.clone(),e.extended.underlineStyle=0,e.extended.underlineColor&=-67108864,e.updateExtended()}charAttributes(e){if(1===e.length&&0===e.params[0])return this._processSGR0(this._curAttrData),!0;const t=e.length;let i;const s=this._curAttrData;for(let r=0;r=30&&i<=37?(s.fg&=-50331904,s.fg|=16777216|i-30):i>=40&&i<=47?(s.bg&=-50331904,s.bg|=16777216|i-40):i>=90&&i<=97?(s.fg&=-50331904,s.fg|=16777224|i-90):i>=100&&i<=107?(s.bg&=-50331904,s.bg|=16777224|i-100):0===i?this._processSGR0(s):1===i?s.fg|=134217728:3===i?s.bg|=67108864:4===i?(s.fg|=268435456,this._processUnderline(e.hasSubParams(r)?e.getSubParams(r)[0]:1,s)):5===i?s.fg|=536870912:7===i?s.fg|=67108864:8===i?s.fg|=1073741824:9===i?s.fg|=2147483648:2===i?s.bg|=134217728:21===i?this._processUnderline(2,s):22===i?(s.fg&=-134217729,s.bg&=-134217729):23===i?s.bg&=-67108865:24===i?(s.fg&=-268435457,this._processUnderline(0,s)):25===i?s.fg&=-536870913:27===i?s.fg&=-67108865:28===i?s.fg&=-1073741825:29===i?s.fg&=2147483647:39===i?(s.fg&=-67108864,s.fg|=16777215&l.DEFAULT_ATTR_DATA.fg):49===i?(s.bg&=-67108864,s.bg|=16777215&l.DEFAULT_ATTR_DATA.bg):38===i||48===i||58===i?r+=this._extractColor(e,r,s):53===i?s.bg|=1073741824:55===i?s.bg&=-1073741825:59===i?(s.extended=s.extended.clone(),s.extended.underlineColor=-1,s.updateExtended()):100===i?(s.fg&=-67108864,s.fg|=16777215&l.DEFAULT_ATTR_DATA.fg,s.bg&=-67108864,s.bg|=16777215&l.DEFAULT_ATTR_DATA.bg):this._logService.debug("Unknown SGR attribute: %d.",i);return!0}deviceStatus(e){switch(e.params[0]){case 5:this._coreService.triggerDataEvent(`${n.C0.ESC}[0n`);break;case 6:const e=this._activeBuffer.y+1,t=this._activeBuffer.x+1;this._coreService.triggerDataEvent(`${n.C0.ESC}[${e};${t}R`)}return!0}deviceStatusPrivate(e){if(6===e.params[0]){const e=this._activeBuffer.y+1,t=this._activeBuffer.x+1;this._coreService.triggerDataEvent(`${n.C0.ESC}[?${e};${t}R`)}return!0}softReset(e){return this._coreService.isCursorHidden=!1,this._onRequestSyncScrollBar.fire(),this._activeBuffer.scrollTop=0,this._activeBuffer.scrollBottom=this._bufferService.rows-1,this._curAttrData=l.DEFAULT_ATTR_DATA.clone(),this._coreService.reset(),this._charsetService.reset(),this._activeBuffer.savedX=0,this._activeBuffer.savedY=this._activeBuffer.ybase,this._activeBuffer.savedCurAttrData.fg=this._curAttrData.fg,this._activeBuffer.savedCurAttrData.bg=this._curAttrData.bg,this._activeBuffer.savedCharset=this._charsetService.charset,this._coreService.decPrivateModes.origin=!1,!0}setCursorStyle(e){const t=e.params[0]||1;switch(t){case 1:case 2:this._optionsService.options.cursorStyle="block";break;case 3:case 4:this._optionsService.options.cursorStyle="underline";break;case 5:case 6:this._optionsService.options.cursorStyle="bar"}const i=t%2==1;return this._optionsService.options.cursorBlink=i,!0}setScrollRegion(e){const t=e.params[0]||1;let i;return(e.length<2||(i=e.params[1])>this._bufferService.rows||0===i)&&(i=this._bufferService.rows),i>t&&(this._activeBuffer.scrollTop=t-1,this._activeBuffer.scrollBottom=i-1,this._setCursor(0,0)),!0}windowOptions(e){if(!w(e.params[0],this._optionsService.rawOptions.windowOptions))return!0;const t=e.length>1?e.params[1]:0;switch(e.params[0]){case 14:2!==t&&this._onRequestWindowsOptionsReport.fire(y.GET_WIN_SIZE_PIXELS);break;case 16:this._onRequestWindowsOptionsReport.fire(y.GET_CELL_SIZE_PIXELS);break;case 18:this._bufferService&&this._coreService.triggerDataEvent(`${n.C0.ESC}[8;${this._bufferService.rows};${this._bufferService.cols}t`);break;case 22:0!==t&&2!==t||(this._windowTitleStack.push(this._windowTitle),this._windowTitleStack.length>10&&this._windowTitleStack.shift()),0!==t&&1!==t||(this._iconNameStack.push(this._iconName),this._iconNameStack.length>10&&this._iconNameStack.shift());break;case 23:0!==t&&2!==t||this._windowTitleStack.length&&this.setTitle(this._windowTitleStack.pop()),0!==t&&1!==t||this._iconNameStack.length&&this.setIconName(this._iconNameStack.pop())}return!0}saveCursor(e){return this._activeBuffer.savedX=this._activeBuffer.x,this._activeBuffer.savedY=this._activeBuffer.ybase+this._activeBuffer.y,this._activeBuffer.savedCurAttrData.fg=this._curAttrData.fg,this._activeBuffer.savedCurAttrData.bg=this._curAttrData.bg,this._activeBuffer.savedCharset=this._charsetService.charset,!0}restoreCursor(e){return this._activeBuffer.x=this._activeBuffer.savedX||0,this._activeBuffer.y=Math.max(this._activeBuffer.savedY-this._activeBuffer.ybase,0),this._curAttrData.fg=this._activeBuffer.savedCurAttrData.fg,this._curAttrData.bg=this._activeBuffer.savedCurAttrData.bg,this._charsetService.charset=this._savedCharset,this._activeBuffer.savedCharset&&(this._charsetService.charset=this._activeBuffer.savedCharset),this._restrictCursor(),!0}setTitle(e){return this._windowTitle=e,this._onTitleChange.fire(e),!0}setIconName(e){return this._iconName=e,!0}setOrReportIndexedColor(e){const t=[],i=e.split(";");for(;i.length>1;){const e=i.shift(),s=i.shift();if(/^\d+$/.exec(e)){const i=parseInt(e);if(D(i))if("?"===s)t.push({type:0,index:i});else{const e=(0,S.parseColor)(s);e&&t.push({type:1,index:i,color:e})}}}return t.length&&this._onColor.fire(t),!0}setHyperlink(e){const t=e.split(";");return!(t.length<2)&&(t[1]?this._createHyperlink(t[0],t[1]):!t[0]&&this._finishHyperlink())}_createHyperlink(e,t){this._getCurrentLinkId()&&this._finishHyperlink();const i=e.split(":");let s;const r=i.findIndex((e=>e.startsWith("id=")));return-1!==r&&(s=i[r].slice(3)||void 0),this._curAttrData.extended=this._curAttrData.extended.clone(),this._curAttrData.extended.urlId=this._oscLinkService.registerLink({id:s,uri:t}),this._curAttrData.updateExtended(),!0}_finishHyperlink(){return this._curAttrData.extended=this._curAttrData.extended.clone(),this._curAttrData.extended.urlId=0,this._curAttrData.updateExtended(),!0}_setOrReportSpecialColor(e,t){const i=e.split(";");for(let e=0;e=this._specialColors.length);++e,++t)if("?"===i[e])this._onColor.fire([{type:0,index:this._specialColors[t]}]);else{const s=(0,S.parseColor)(i[e]);s&&this._onColor.fire([{type:1,index:this._specialColors[t],color:s}])}return!0}setOrReportFgColor(e){return this._setOrReportSpecialColor(e,0)}setOrReportBgColor(e){return this._setOrReportSpecialColor(e,1)}setOrReportCursorColor(e){return this._setOrReportSpecialColor(e,2)}restoreIndexedColor(e){if(!e)return this._onColor.fire([{type:2}]),!0;const t=[],i=e.split(";");for(let e=0;e=this._bufferService.rows&&(this._activeBuffer.y=this._bufferService.rows-1),this._restrictCursor(),!0}tabSet(){return this._activeBuffer.tabs[this._activeBuffer.x]=!0,!0}reverseIndex(){if(this._restrictCursor(),this._activeBuffer.y===this._activeBuffer.scrollTop){const e=this._activeBuffer.scrollBottom-this._activeBuffer.scrollTop;this._activeBuffer.lines.shiftElements(this._activeBuffer.ybase+this._activeBuffer.y,e,1),this._activeBuffer.lines.set(this._activeBuffer.ybase+this._activeBuffer.y,this._activeBuffer.getBlankLine(this._eraseAttrData())),this._dirtyRowTracker.markRangeDirty(this._activeBuffer.scrollTop,this._activeBuffer.scrollBottom)}else this._activeBuffer.y--,this._restrictCursor();return!0}fullReset(){return this._parser.reset(),this._onRequestReset.fire(),!0}reset(){this._curAttrData=l.DEFAULT_ATTR_DATA.clone(),this._eraseAttrDataInternal=l.DEFAULT_ATTR_DATA.clone()}_eraseAttrData(){return this._eraseAttrDataInternal.bg&=-67108864,this._eraseAttrDataInternal.bg|=67108863&this._curAttrData.bg,this._eraseAttrDataInternal}setgLevel(e){return this._charsetService.setgLevel(e),!0}screenAlignmentPattern(){const e=new u.CellData;e.content=1<<22|"E".charCodeAt(0),e.fg=this._curAttrData.fg,e.bg=this._curAttrData.bg,this._setCursor(0,0);for(let t=0;t(this._coreService.triggerDataEvent(`${n.C0.ESC}${e}${n.C0.ESC}\\`),!0))('"q'===e?`P1$r${this._curAttrData.isProtected()?1:0}"q`:'"p'===e?'P1$r61;1"p':"r"===e?`P1$r${i.scrollTop+1};${i.scrollBottom+1}r`:"m"===e?"P1$r0m":" q"===e?`P1$r${{block:2,underline:4,bar:6}[s.cursorStyle]-(s.cursorBlink?1:0)} q`:"P0$r")}markRangeDirty(e,t){this._dirtyRowTracker.markRangeDirty(e,t)}}t.InputHandler=k;let L=class{constructor(e){this._bufferService=e,this.clearRange()}clearRange(){this.start=this._bufferService.buffer.y,this.end=this._bufferService.buffer.y}markDirty(e){ethis.end&&(this.end=e)}markRangeDirty(e,t){e>t&&(E=e,e=t,t=E),ethis.end&&(this.end=t)}markAllDirty(){this.markRangeDirty(0,this._bufferService.rows-1)}};function D(e){return 0<=e&&e<256}L=s([r(0,v.IBufferService)],L)},844:(e,t)=>{function i(e){for(const t of e)t.dispose();e.length=0}Object.defineProperty(t,"__esModule",{value:!0}),t.getDisposeArrayDisposable=t.disposeArray=t.toDisposable=t.MutableDisposable=t.Disposable=void 0,t.Disposable=class{constructor(){this._disposables=[],this._isDisposed=!1}dispose(){this._isDisposed=!0;for(const e of this._disposables)e.dispose();this._disposables.length=0}register(e){return this._disposables.push(e),e}unregister(e){const t=this._disposables.indexOf(e);-1!==t&&this._disposables.splice(t,1)}},t.MutableDisposable=class{constructor(){this._isDisposed=!1}get value(){return this._isDisposed?void 0:this._value}set value(e){this._isDisposed||e===this._value||(this._value?.dispose(),this._value=e)}clear(){this.value=void 0}dispose(){this._isDisposed=!0,this._value?.dispose(),this._value=void 0}},t.toDisposable=function(e){return{dispose:e}},t.disposeArray=i,t.getDisposeArrayDisposable=function(e){return{dispose:()=>i(e)}}},1505:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.FourKeyMap=t.TwoKeyMap=void 0;class i{constructor(){this._data={}}set(e,t,i){this._data[e]||(this._data[e]={}),this._data[e][t]=i}get(e,t){return this._data[e]?this._data[e][t]:void 0}clear(){this._data={}}}t.TwoKeyMap=i,t.FourKeyMap=class{constructor(){this._data=new i}set(e,t,s,r,n){this._data.get(e,t)||this._data.set(e,t,new i),this._data.get(e,t).set(s,r,n)}get(e,t,i,s){return this._data.get(e,t)?.get(i,s)}clear(){this._data.clear()}}},6114:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.isChromeOS=t.isLinux=t.isWindows=t.isIphone=t.isIpad=t.isMac=t.getSafariVersion=t.isSafari=t.isLegacyEdge=t.isFirefox=t.isNode=void 0,t.isNode="undefined"!=typeof process;const i=t.isNode?"node":navigator.userAgent,s=t.isNode?"node":navigator.platform;t.isFirefox=i.includes("Firefox"),t.isLegacyEdge=i.includes("Edge"),t.isSafari=/^((?!chrome|android).)*safari/i.test(i),t.getSafariVersion=function(){if(!t.isSafari)return 0;const e=i.match(/Version\/(\d+)/);return null===e||e.length<2?0:parseInt(e[1])},t.isMac=["Macintosh","MacIntel","MacPPC","Mac68K"].includes(s),t.isIpad="iPad"===s,t.isIphone="iPhone"===s,t.isWindows=["Windows","Win16","Win32","WinCE"].includes(s),t.isLinux=s.indexOf("Linux")>=0,t.isChromeOS=/\bCrOS\b/.test(i)},6106:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.SortedList=void 0;let i=0;t.SortedList=class{constructor(e){this._getKey=e,this._array=[]}clear(){this._array.length=0}insert(e){0!==this._array.length?(i=this._search(this._getKey(e)),this._array.splice(i,0,e)):this._array.push(e)}delete(e){if(0===this._array.length)return!1;const t=this._getKey(e);if(void 0===t)return!1;if(i=this._search(t),-1===i)return!1;if(this._getKey(this._array[i])!==t)return!1;do{if(this._array[i]===e)return this._array.splice(i,1),!0}while(++i=this._array.length)&&this._getKey(this._array[i])===e))do{yield this._array[i]}while(++i=this._array.length)&&this._getKey(this._array[i])===e))do{t(this._array[i])}while(++i=t;){let s=t+i>>1;const r=this._getKey(this._array[s]);if(r>e)i=s-1;else{if(!(r0&&this._getKey(this._array[s-1])===e;)s--;return s}t=s+1}}return t}}},7226:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DebouncedIdleTask=t.IdleTaskQueue=t.PriorityTaskQueue=void 0;const s=i(6114);class r{constructor(){this._tasks=[],this._i=0}enqueue(e){this._tasks.push(e),this._start()}flush(){for(;this._ir)return s-t<-20&&console.warn(`task queue exceeded allotted deadline by ${Math.abs(Math.round(s-t))}ms`),void this._start();s=r}this.clear()}}class n extends r{_requestCallback(e){return setTimeout((()=>e(this._createDeadline(16))))}_cancelCallback(e){clearTimeout(e)}_createDeadline(e){const t=Date.now()+e;return{timeRemaining:()=>Math.max(0,t-Date.now())}}}t.PriorityTaskQueue=n,t.IdleTaskQueue=!s.isNode&&"requestIdleCallback"in window?class extends r{_requestCallback(e){return requestIdleCallback(e)}_cancelCallback(e){cancelIdleCallback(e)}}:n,t.DebouncedIdleTask=class{constructor(){this._queue=new t.IdleTaskQueue}set(e){this._queue.clear(),this._queue.enqueue(e)}flush(){this._queue.flush()}}},9282:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.updateWindowsModeWrappedState=void 0;const s=i(643);t.updateWindowsModeWrappedState=function(e){const t=e.buffer.lines.get(e.buffer.ybase+e.buffer.y-1),i=t?.get(e.cols-1),r=e.buffer.lines.get(e.buffer.ybase+e.buffer.y);r&&i&&(r.isWrapped=i[s.CHAR_DATA_CODE_INDEX]!==s.NULL_CELL_CODE&&i[s.CHAR_DATA_CODE_INDEX]!==s.WHITESPACE_CELL_CODE)}},3734:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ExtendedAttrs=t.AttributeData=void 0;class i{constructor(){this.fg=0,this.bg=0,this.extended=new s}static toColorRGB(e){return[e>>>16&255,e>>>8&255,255&e]}static fromColorRGB(e){return(255&e[0])<<16|(255&e[1])<<8|255&e[2]}clone(){const e=new i;return e.fg=this.fg,e.bg=this.bg,e.extended=this.extended.clone(),e}isInverse(){return 67108864&this.fg}isBold(){return 134217728&this.fg}isUnderline(){return this.hasExtendedAttrs()&&0!==this.extended.underlineStyle?1:268435456&this.fg}isBlink(){return 536870912&this.fg}isInvisible(){return 1073741824&this.fg}isItalic(){return 67108864&this.bg}isDim(){return 134217728&this.bg}isStrikethrough(){return 2147483648&this.fg}isProtected(){return 536870912&this.bg}isOverline(){return 1073741824&this.bg}getFgColorMode(){return 50331648&this.fg}getBgColorMode(){return 50331648&this.bg}isFgRGB(){return 50331648==(50331648&this.fg)}isBgRGB(){return 50331648==(50331648&this.bg)}isFgPalette(){return 16777216==(50331648&this.fg)||33554432==(50331648&this.fg)}isBgPalette(){return 16777216==(50331648&this.bg)||33554432==(50331648&this.bg)}isFgDefault(){return 0==(50331648&this.fg)}isBgDefault(){return 0==(50331648&this.bg)}isAttributeDefault(){return 0===this.fg&&0===this.bg}getFgColor(){switch(50331648&this.fg){case 16777216:case 33554432:return 255&this.fg;case 50331648:return 16777215&this.fg;default:return-1}}getBgColor(){switch(50331648&this.bg){case 16777216:case 33554432:return 255&this.bg;case 50331648:return 16777215&this.bg;default:return-1}}hasExtendedAttrs(){return 268435456&this.bg}updateExtended(){this.extended.isEmpty()?this.bg&=-268435457:this.bg|=268435456}getUnderlineColor(){if(268435456&this.bg&&~this.extended.underlineColor)switch(50331648&this.extended.underlineColor){case 16777216:case 33554432:return 255&this.extended.underlineColor;case 50331648:return 16777215&this.extended.underlineColor;default:return this.getFgColor()}return this.getFgColor()}getUnderlineColorMode(){return 268435456&this.bg&&~this.extended.underlineColor?50331648&this.extended.underlineColor:this.getFgColorMode()}isUnderlineColorRGB(){return 268435456&this.bg&&~this.extended.underlineColor?50331648==(50331648&this.extended.underlineColor):this.isFgRGB()}isUnderlineColorPalette(){return 268435456&this.bg&&~this.extended.underlineColor?16777216==(50331648&this.extended.underlineColor)||33554432==(50331648&this.extended.underlineColor):this.isFgPalette()}isUnderlineColorDefault(){return 268435456&this.bg&&~this.extended.underlineColor?0==(50331648&this.extended.underlineColor):this.isFgDefault()}getUnderlineStyle(){return 268435456&this.fg?268435456&this.bg?this.extended.underlineStyle:1:0}getUnderlineVariantOffset(){return this.extended.underlineVariantOffset}}t.AttributeData=i;class s{get ext(){return this._urlId?-469762049&this._ext|this.underlineStyle<<26:this._ext}set ext(e){this._ext=e}get underlineStyle(){return this._urlId?5:(469762048&this._ext)>>26}set underlineStyle(e){this._ext&=-469762049,this._ext|=e<<26&469762048}get underlineColor(){return 67108863&this._ext}set underlineColor(e){this._ext&=-67108864,this._ext|=67108863&e}get urlId(){return this._urlId}set urlId(e){this._urlId=e}get underlineVariantOffset(){const e=(3758096384&this._ext)>>29;return e<0?4294967288^e:e}set underlineVariantOffset(e){this._ext&=536870911,this._ext|=e<<29&3758096384}constructor(e=0,t=0){this._ext=0,this._urlId=0,this._ext=e,this._urlId=t}clone(){return new s(this._ext,this._urlId)}isEmpty(){return 0===this.underlineStyle&&0===this._urlId}}t.ExtendedAttrs=s},9092:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Buffer=t.MAX_BUFFER_SIZE=void 0;const s=i(6349),r=i(7226),n=i(3734),o=i(8437),a=i(4634),h=i(511),c=i(643),l=i(4863),d=i(7116);t.MAX_BUFFER_SIZE=4294967295,t.Buffer=class{constructor(e,t,i){this._hasScrollback=e,this._optionsService=t,this._bufferService=i,this.ydisp=0,this.ybase=0,this.y=0,this.x=0,this.tabs={},this.savedY=0,this.savedX=0,this.savedCurAttrData=o.DEFAULT_ATTR_DATA.clone(),this.savedCharset=d.DEFAULT_CHARSET,this.markers=[],this._nullCell=h.CellData.fromCharData([0,c.NULL_CELL_CHAR,c.NULL_CELL_WIDTH,c.NULL_CELL_CODE]),this._whitespaceCell=h.CellData.fromCharData([0,c.WHITESPACE_CELL_CHAR,c.WHITESPACE_CELL_WIDTH,c.WHITESPACE_CELL_CODE]),this._isClearing=!1,this._memoryCleanupQueue=new r.IdleTaskQueue,this._memoryCleanupPosition=0,this._cols=this._bufferService.cols,this._rows=this._bufferService.rows,this.lines=new s.CircularList(this._getCorrectBufferLength(this._rows)),this.scrollTop=0,this.scrollBottom=this._rows-1,this.setupTabStops()}getNullCell(e){return e?(this._nullCell.fg=e.fg,this._nullCell.bg=e.bg,this._nullCell.extended=e.extended):(this._nullCell.fg=0,this._nullCell.bg=0,this._nullCell.extended=new n.ExtendedAttrs),this._nullCell}getWhitespaceCell(e){return e?(this._whitespaceCell.fg=e.fg,this._whitespaceCell.bg=e.bg,this._whitespaceCell.extended=e.extended):(this._whitespaceCell.fg=0,this._whitespaceCell.bg=0,this._whitespaceCell.extended=new n.ExtendedAttrs),this._whitespaceCell}getBlankLine(e,t){return new o.BufferLine(this._bufferService.cols,this.getNullCell(e),t)}get hasScrollback(){return this._hasScrollback&&this.lines.maxLength>this._rows}get isCursorInViewport(){const e=this.ybase+this.y-this.ydisp;return e>=0&&et.MAX_BUFFER_SIZE?t.MAX_BUFFER_SIZE:i}fillViewportRows(e){if(0===this.lines.length){void 0===e&&(e=o.DEFAULT_ATTR_DATA);let t=this._rows;for(;t--;)this.lines.push(this.getBlankLine(e))}}clear(){this.ydisp=0,this.ybase=0,this.y=0,this.x=0,this.lines=new s.CircularList(this._getCorrectBufferLength(this._rows)),this.scrollTop=0,this.scrollBottom=this._rows-1,this.setupTabStops()}resize(e,t){const i=this.getNullCell(o.DEFAULT_ATTR_DATA);let s=0;const r=this._getCorrectBufferLength(t);if(r>this.lines.maxLength&&(this.lines.maxLength=r),this.lines.length>0){if(this._cols0&&this.lines.length<=this.ybase+this.y+n+1?(this.ybase--,n++,this.ydisp>0&&this.ydisp--):this.lines.push(new o.BufferLine(e,i)));else for(let e=this._rows;e>t;e--)this.lines.length>t+this.ybase&&(this.lines.length>this.ybase+this.y+1?this.lines.pop():(this.ybase++,this.ydisp++));if(r0&&(this.lines.trimStart(e),this.ybase=Math.max(this.ybase-e,0),this.ydisp=Math.max(this.ydisp-e,0),this.savedY=Math.max(this.savedY-e,0)),this.lines.maxLength=r}this.x=Math.min(this.x,e-1),this.y=Math.min(this.y,t-1),n&&(this.y+=n),this.savedX=Math.min(this.savedX,e-1),this.scrollTop=0}if(this.scrollBottom=t-1,this._isReflowEnabled&&(this._reflow(e,t),this._cols>e))for(let t=0;t.1*this.lines.length&&(this._memoryCleanupPosition=0,this._memoryCleanupQueue.enqueue((()=>this._batchedMemoryCleanup())))}_batchedMemoryCleanup(){let e=!0;this._memoryCleanupPosition>=this.lines.length&&(this._memoryCleanupPosition=0,e=!1);let t=0;for(;this._memoryCleanupPosition100)return!0;return e}get _isReflowEnabled(){const e=this._optionsService.rawOptions.windowsPty;return e&&e.buildNumber?this._hasScrollback&&"conpty"===e.backend&&e.buildNumber>=21376:this._hasScrollback&&!this._optionsService.rawOptions.windowsMode}_reflow(e,t){this._cols!==e&&(e>this._cols?this._reflowLarger(e,t):this._reflowSmaller(e,t))}_reflowLarger(e,t){const i=(0,a.reflowLargerGetLinesToRemove)(this.lines,this._cols,e,this.ybase+this.y,this.getNullCell(o.DEFAULT_ATTR_DATA));if(i.length>0){const s=(0,a.reflowLargerCreateNewLayout)(this.lines,i);(0,a.reflowLargerApplyNewLayout)(this.lines,s.layout),this._reflowLargerAdjustViewport(e,t,s.countRemoved)}}_reflowLargerAdjustViewport(e,t,i){const s=this.getNullCell(o.DEFAULT_ATTR_DATA);let r=i;for(;r-- >0;)0===this.ybase?(this.y>0&&this.y--,this.lines.length=0;n--){let h=this.lines.get(n);if(!h||!h.isWrapped&&h.getTrimmedLength()<=e)continue;const c=[h];for(;h.isWrapped&&n>0;)h=this.lines.get(--n),c.unshift(h);const l=this.ybase+this.y;if(l>=n&&l0&&(s.push({start:n+c.length+r,newLines:v}),r+=v.length),c.push(...v);let p=_.length-1,g=_[p];0===g&&(p--,g=_[p]);let m=c.length-u-1,S=d;for(;m>=0;){const e=Math.min(S,g);if(void 0===c[p])break;if(c[p].copyCellsFrom(c[m],S-e,g-e,e,!0),g-=e,0===g&&(p--,g=_[p]),S-=e,0===S){m--;const e=Math.max(m,0);S=(0,a.getWrappedLineTrimmedLength)(c,e,this._cols)}}for(let t=0;t0;)0===this.ybase?this.y0){const e=[],t=[];for(let e=0;e=0;c--)if(a&&a.start>n+h){for(let e=a.newLines.length-1;e>=0;e--)this.lines.set(c--,a.newLines[e]);c++,e.push({index:n+1,amount:a.newLines.length}),h+=a.newLines.length,a=s[++o]}else this.lines.set(c,t[n--]);let c=0;for(let t=e.length-1;t>=0;t--)e[t].index+=c,this.lines.onInsertEmitter.fire(e[t]),c+=e[t].amount;const l=Math.max(0,i+r-this.lines.maxLength);l>0&&this.lines.onTrimEmitter.fire(l)}}translateBufferLineToString(e,t,i=0,s){const r=this.lines.get(e);return r?r.translateToString(t,i,s):""}getWrappedRangeForLine(e){let t=e,i=e;for(;t>0&&this.lines.get(t).isWrapped;)t--;for(;i+10;);return e>=this._cols?this._cols-1:e<0?0:e}nextStop(e){for(null==e&&(e=this.x);!this.tabs[++e]&&e=this._cols?this._cols-1:e<0?0:e}clearMarkers(e){this._isClearing=!0;for(let t=0;t{t.line-=e,t.line<0&&t.dispose()}))),t.register(this.lines.onInsert((e=>{t.line>=e.index&&(t.line+=e.amount)}))),t.register(this.lines.onDelete((e=>{t.line>=e.index&&t.linee.index&&(t.line-=e.amount)}))),t.register(t.onDispose((()=>this._removeMarker(t)))),t}_removeMarker(e){this._isClearing||this.markers.splice(this.markers.indexOf(e),1)}}},8437:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferLine=t.DEFAULT_ATTR_DATA=void 0;const s=i(3734),r=i(511),n=i(643),o=i(482);t.DEFAULT_ATTR_DATA=Object.freeze(new s.AttributeData);let a=0;class h{constructor(e,t,i=!1){this.isWrapped=i,this._combined={},this._extendedAttrs={},this._data=new Uint32Array(3*e);const s=t||r.CellData.fromCharData([0,n.NULL_CELL_CHAR,n.NULL_CELL_WIDTH,n.NULL_CELL_CODE]);for(let t=0;t>22,2097152&t?this._combined[e].charCodeAt(this._combined[e].length-1):i]}set(e,t){this._data[3*e+1]=t[n.CHAR_DATA_ATTR_INDEX],t[n.CHAR_DATA_CHAR_INDEX].length>1?(this._combined[e]=t[1],this._data[3*e+0]=2097152|e|t[n.CHAR_DATA_WIDTH_INDEX]<<22):this._data[3*e+0]=t[n.CHAR_DATA_CHAR_INDEX].charCodeAt(0)|t[n.CHAR_DATA_WIDTH_INDEX]<<22}getWidth(e){return this._data[3*e+0]>>22}hasWidth(e){return 12582912&this._data[3*e+0]}getFg(e){return this._data[3*e+1]}getBg(e){return this._data[3*e+2]}hasContent(e){return 4194303&this._data[3*e+0]}getCodePoint(e){const t=this._data[3*e+0];return 2097152&t?this._combined[e].charCodeAt(this._combined[e].length-1):2097151&t}isCombined(e){return 2097152&this._data[3*e+0]}getString(e){const t=this._data[3*e+0];return 2097152&t?this._combined[e]:2097151&t?(0,o.stringFromCodePoint)(2097151&t):""}isProtected(e){return 536870912&this._data[3*e+2]}loadCell(e,t){return a=3*e,t.content=this._data[a+0],t.fg=this._data[a+1],t.bg=this._data[a+2],2097152&t.content&&(t.combinedData=this._combined[e]),268435456&t.bg&&(t.extended=this._extendedAttrs[e]),t}setCell(e,t){2097152&t.content&&(this._combined[e]=t.combinedData),268435456&t.bg&&(this._extendedAttrs[e]=t.extended),this._data[3*e+0]=t.content,this._data[3*e+1]=t.fg,this._data[3*e+2]=t.bg}setCellFromCodepoint(e,t,i,s){268435456&s.bg&&(this._extendedAttrs[e]=s.extended),this._data[3*e+0]=t|i<<22,this._data[3*e+1]=s.fg,this._data[3*e+2]=s.bg}addCodepointToCell(e,t,i){let s=this._data[3*e+0];2097152&s?this._combined[e]+=(0,o.stringFromCodePoint)(t):2097151&s?(this._combined[e]=(0,o.stringFromCodePoint)(2097151&s)+(0,o.stringFromCodePoint)(t),s&=-2097152,s|=2097152):s=t|1<<22,i&&(s&=-12582913,s|=i<<22),this._data[3*e+0]=s}insertCells(e,t,i){if((e%=this.length)&&2===this.getWidth(e-1)&&this.setCellFromCodepoint(e-1,0,1,i),t=0;--i)this.setCell(e+t+i,this.loadCell(e+i,s));for(let s=0;sthis.length){if(this._data.buffer.byteLength>=4*i)this._data=new Uint32Array(this._data.buffer,0,i);else{const e=new Uint32Array(i);e.set(this._data),this._data=e}for(let i=this.length;i=e&&delete this._combined[s]}const s=Object.keys(this._extendedAttrs);for(let t=0;t=e&&delete this._extendedAttrs[i]}}return this.length=e,4*i*2=0;--e)if(4194303&this._data[3*e+0])return e+(this._data[3*e+0]>>22);return 0}getNoBgTrimmedLength(){for(let e=this.length-1;e>=0;--e)if(4194303&this._data[3*e+0]||50331648&this._data[3*e+2])return e+(this._data[3*e+0]>>22);return 0}copyCellsFrom(e,t,i,s,r){const n=e._data;if(r)for(let r=s-1;r>=0;r--){for(let e=0;e<3;e++)this._data[3*(i+r)+e]=n[3*(t+r)+e];268435456&n[3*(t+r)+2]&&(this._extendedAttrs[i+r]=e._extendedAttrs[t+r])}else for(let r=0;r=t&&(this._combined[r-t+i]=e._combined[r])}}translateToString(e,t,i,s){t=t??0,i=i??this.length,e&&(i=Math.min(i,this.getTrimmedLength())),s&&(s.length=0);let r="";for(;t>22||1}return s&&s.push(t),r}}t.BufferLine=h},4841:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.getRangeLength=void 0,t.getRangeLength=function(e,t){if(e.start.y>e.end.y)throw new Error(`Buffer range end (${e.end.x}, ${e.end.y}) cannot be before start (${e.start.x}, ${e.start.y})`);return t*(e.end.y-e.start.y)+(e.end.x-e.start.x+1)}},4634:(e,t)=>{function i(e,t,i){if(t===e.length-1)return e[t].getTrimmedLength();const s=!e[t].hasContent(i-1)&&1===e[t].getWidth(i-1),r=2===e[t+1].getWidth(0);return s&&r?i-1:i}Object.defineProperty(t,"__esModule",{value:!0}),t.getWrappedLineTrimmedLength=t.reflowSmallerGetNewLineLengths=t.reflowLargerApplyNewLayout=t.reflowLargerCreateNewLayout=t.reflowLargerGetLinesToRemove=void 0,t.reflowLargerGetLinesToRemove=function(e,t,s,r,n){const o=[];for(let a=0;a=a&&r0&&(e>d||0===l[e].getTrimmedLength());e--)v++;v>0&&(o.push(a+l.length-v),o.push(v)),a+=l.length-1}return o},t.reflowLargerCreateNewLayout=function(e,t){const i=[];let s=0,r=t[s],n=0;for(let o=0;oi(e,r,t))).reduce(((e,t)=>e+t));let o=0,a=0,h=0;for(;hc&&(o-=c,a++);const l=2===e[a].getWidth(o-1);l&&o--;const d=l?s-1:s;r.push(d),h+=d}return r},t.getWrappedLineTrimmedLength=i},5295:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferSet=void 0;const s=i(8460),r=i(844),n=i(9092);class o extends r.Disposable{constructor(e,t){super(),this._optionsService=e,this._bufferService=t,this._onBufferActivate=this.register(new s.EventEmitter),this.onBufferActivate=this._onBufferActivate.event,this.reset(),this.register(this._optionsService.onSpecificOptionChange("scrollback",(()=>this.resize(this._bufferService.cols,this._bufferService.rows)))),this.register(this._optionsService.onSpecificOptionChange("tabStopWidth",(()=>this.setupTabStops())))}reset(){this._normal=new n.Buffer(!0,this._optionsService,this._bufferService),this._normal.fillViewportRows(),this._alt=new n.Buffer(!1,this._optionsService,this._bufferService),this._activeBuffer=this._normal,this._onBufferActivate.fire({activeBuffer:this._normal,inactiveBuffer:this._alt}),this.setupTabStops()}get alt(){return this._alt}get active(){return this._activeBuffer}get normal(){return this._normal}activateNormalBuffer(){this._activeBuffer!==this._normal&&(this._normal.x=this._alt.x,this._normal.y=this._alt.y,this._alt.clearAllMarkers(),this._alt.clear(),this._activeBuffer=this._normal,this._onBufferActivate.fire({activeBuffer:this._normal,inactiveBuffer:this._alt}))}activateAltBuffer(e){this._activeBuffer!==this._alt&&(this._alt.fillViewportRows(e),this._alt.x=this._normal.x,this._alt.y=this._normal.y,this._activeBuffer=this._alt,this._onBufferActivate.fire({activeBuffer:this._alt,inactiveBuffer:this._normal}))}resize(e,t){this._normal.resize(e,t),this._alt.resize(e,t),this.setupTabStops(e)}setupTabStops(e){this._normal.setupTabStops(e),this._alt.setupTabStops(e)}}t.BufferSet=o},511:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.CellData=void 0;const s=i(482),r=i(643),n=i(3734);class o extends n.AttributeData{constructor(){super(...arguments),this.content=0,this.fg=0,this.bg=0,this.extended=new n.ExtendedAttrs,this.combinedData=""}static fromCharData(e){const t=new o;return t.setFromCharData(e),t}isCombined(){return 2097152&this.content}getWidth(){return this.content>>22}getChars(){return 2097152&this.content?this.combinedData:2097151&this.content?(0,s.stringFromCodePoint)(2097151&this.content):""}getCode(){return this.isCombined()?this.combinedData.charCodeAt(this.combinedData.length-1):2097151&this.content}setFromCharData(e){this.fg=e[r.CHAR_DATA_ATTR_INDEX],this.bg=0;let t=!1;if(e[r.CHAR_DATA_CHAR_INDEX].length>2)t=!0;else if(2===e[r.CHAR_DATA_CHAR_INDEX].length){const i=e[r.CHAR_DATA_CHAR_INDEX].charCodeAt(0);if(55296<=i&&i<=56319){const s=e[r.CHAR_DATA_CHAR_INDEX].charCodeAt(1);56320<=s&&s<=57343?this.content=1024*(i-55296)+s-56320+65536|e[r.CHAR_DATA_WIDTH_INDEX]<<22:t=!0}else t=!0}else this.content=e[r.CHAR_DATA_CHAR_INDEX].charCodeAt(0)|e[r.CHAR_DATA_WIDTH_INDEX]<<22;t&&(this.combinedData=e[r.CHAR_DATA_CHAR_INDEX],this.content=2097152|e[r.CHAR_DATA_WIDTH_INDEX]<<22)}getAsCharData(){return[this.fg,this.getChars(),this.getWidth(),this.getCode()]}}t.CellData=o},643:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.WHITESPACE_CELL_CODE=t.WHITESPACE_CELL_WIDTH=t.WHITESPACE_CELL_CHAR=t.NULL_CELL_CODE=t.NULL_CELL_WIDTH=t.NULL_CELL_CHAR=t.CHAR_DATA_CODE_INDEX=t.CHAR_DATA_WIDTH_INDEX=t.CHAR_DATA_CHAR_INDEX=t.CHAR_DATA_ATTR_INDEX=t.DEFAULT_EXT=t.DEFAULT_ATTR=t.DEFAULT_COLOR=void 0,t.DEFAULT_COLOR=0,t.DEFAULT_ATTR=256|t.DEFAULT_COLOR<<9,t.DEFAULT_EXT=0,t.CHAR_DATA_ATTR_INDEX=0,t.CHAR_DATA_CHAR_INDEX=1,t.CHAR_DATA_WIDTH_INDEX=2,t.CHAR_DATA_CODE_INDEX=3,t.NULL_CELL_CHAR="",t.NULL_CELL_WIDTH=1,t.NULL_CELL_CODE=0,t.WHITESPACE_CELL_CHAR=" ",t.WHITESPACE_CELL_WIDTH=1,t.WHITESPACE_CELL_CODE=32},4863:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Marker=void 0;const s=i(8460),r=i(844);class n{get id(){return this._id}constructor(e){this.line=e,this.isDisposed=!1,this._disposables=[],this._id=n._nextId++,this._onDispose=this.register(new s.EventEmitter),this.onDispose=this._onDispose.event}dispose(){this.isDisposed||(this.isDisposed=!0,this.line=-1,this._onDispose.fire(),(0,r.disposeArray)(this._disposables),this._disposables.length=0)}register(e){return this._disposables.push(e),e}}t.Marker=n,n._nextId=1},7116:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DEFAULT_CHARSET=t.CHARSETS=void 0,t.CHARSETS={},t.DEFAULT_CHARSET=t.CHARSETS.B,t.CHARSETS[0]={"`":"◆",a:"▒",b:"␉",c:"␌",d:"␍",e:"␊",f:"°",g:"±",h:"␤",i:"␋",j:"┘",k:"┐",l:"┌",m:"└",n:"┼",o:"⎺",p:"⎻",q:"─",r:"⎼",s:"⎽",t:"├",u:"┤",v:"┴",w:"┬",x:"│",y:"≤",z:"≥","{":"π","|":"≠","}":"£","~":"·"},t.CHARSETS.A={"#":"£"},t.CHARSETS.B=void 0,t.CHARSETS[4]={"#":"£","@":"¾","[":"ij","\\":"½","]":"|","{":"¨","|":"f","}":"¼","~":"´"},t.CHARSETS.C=t.CHARSETS[5]={"[":"Ä","\\":"Ö","]":"Å","^":"Ü","`":"é","{":"ä","|":"ö","}":"å","~":"ü"},t.CHARSETS.R={"#":"£","@":"à","[":"°","\\":"ç","]":"§","{":"é","|":"ù","}":"è","~":"¨"},t.CHARSETS.Q={"@":"à","[":"â","\\":"ç","]":"ê","^":"î","`":"ô","{":"é","|":"ù","}":"è","~":"û"},t.CHARSETS.K={"@":"§","[":"Ä","\\":"Ö","]":"Ü","{":"ä","|":"ö","}":"ü","~":"ß"},t.CHARSETS.Y={"#":"£","@":"§","[":"°","\\":"ç","]":"é","`":"ù","{":"à","|":"ò","}":"è","~":"ì"},t.CHARSETS.E=t.CHARSETS[6]={"@":"Ä","[":"Æ","\\":"Ø","]":"Å","^":"Ü","`":"ä","{":"æ","|":"ø","}":"å","~":"ü"},t.CHARSETS.Z={"#":"£","@":"§","[":"¡","\\":"Ñ","]":"¿","{":"°","|":"ñ","}":"ç"},t.CHARSETS.H=t.CHARSETS[7]={"@":"É","[":"Ä","\\":"Ö","]":"Å","^":"Ü","`":"é","{":"ä","|":"ö","}":"å","~":"ü"},t.CHARSETS["="]={"#":"ù","@":"à","[":"é","\\":"ç","]":"ê","^":"î",_:"è","`":"ô","{":"ä","|":"ö","}":"ü","~":"û"}},2584:(e,t)=>{var i,s,r;Object.defineProperty(t,"__esModule",{value:!0}),t.C1_ESCAPED=t.C1=t.C0=void 0,function(e){e.NUL="\0",e.SOH="",e.STX="",e.ETX="",e.EOT="",e.ENQ="",e.ACK="",e.BEL="",e.BS="\b",e.HT="\t",e.LF="\n",e.VT="\v",e.FF="\f",e.CR="\r",e.SO="",e.SI="",e.DLE="",e.DC1="",e.DC2="",e.DC3="",e.DC4="",e.NAK="",e.SYN="",e.ETB="",e.CAN="",e.EM="",e.SUB="",e.ESC="",e.FS="",e.GS="",e.RS="",e.US="",e.SP=" ",e.DEL=""}(i||(t.C0=i={})),function(e){e.PAD="€",e.HOP="",e.BPH="‚",e.NBH="ƒ",e.IND="„",e.NEL="…",e.SSA="†",e.ESA="‡",e.HTS="ˆ",e.HTJ="‰",e.VTS="Š",e.PLD="‹",e.PLU="Œ",e.RI="",e.SS2="Ž",e.SS3="",e.DCS="",e.PU1="‘",e.PU2="’",e.STS="“",e.CCH="”",e.MW="•",e.SPA="–",e.EPA="—",e.SOS="˜",e.SGCI="™",e.SCI="š",e.CSI="›",e.ST="œ",e.OSC="",e.PM="ž",e.APC="Ÿ"}(s||(t.C1=s={})),function(e){e.ST=`${i.ESC}\\`}(r||(t.C1_ESCAPED=r={}))},7399:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.evaluateKeyboardEvent=void 0;const s=i(2584),r={48:["0",")"],49:["1","!"],50:["2","@"],51:["3","#"],52:["4","$"],53:["5","%"],54:["6","^"],55:["7","&"],56:["8","*"],57:["9","("],186:[";",":"],187:["=","+"],188:[",","<"],189:["-","_"],190:[".",">"],191:["/","?"],192:["`","~"],219:["[","{"],220:["\\","|"],221:["]","}"],222:["'",'"']};t.evaluateKeyboardEvent=function(e,t,i,n){const o={type:0,cancel:!1,key:void 0},a=(e.shiftKey?1:0)|(e.altKey?2:0)|(e.ctrlKey?4:0)|(e.metaKey?8:0);switch(e.keyCode){case 0:"UIKeyInputUpArrow"===e.key?o.key=t?s.C0.ESC+"OA":s.C0.ESC+"[A":"UIKeyInputLeftArrow"===e.key?o.key=t?s.C0.ESC+"OD":s.C0.ESC+"[D":"UIKeyInputRightArrow"===e.key?o.key=t?s.C0.ESC+"OC":s.C0.ESC+"[C":"UIKeyInputDownArrow"===e.key&&(o.key=t?s.C0.ESC+"OB":s.C0.ESC+"[B");break;case 8:o.key=e.ctrlKey?"\b":s.C0.DEL,e.altKey&&(o.key=s.C0.ESC+o.key);break;case 9:if(e.shiftKey){o.key=s.C0.ESC+"[Z";break}o.key=s.C0.HT,o.cancel=!0;break;case 13:o.key=e.altKey?s.C0.ESC+s.C0.CR:s.C0.CR,o.cancel=!0;break;case 27:o.key=s.C0.ESC,e.altKey&&(o.key=s.C0.ESC+s.C0.ESC),o.cancel=!0;break;case 37:if(e.metaKey)break;a?(o.key=s.C0.ESC+"[1;"+(a+1)+"D",o.key===s.C0.ESC+"[1;3D"&&(o.key=s.C0.ESC+(i?"b":"[1;5D"))):o.key=t?s.C0.ESC+"OD":s.C0.ESC+"[D";break;case 39:if(e.metaKey)break;a?(o.key=s.C0.ESC+"[1;"+(a+1)+"C",o.key===s.C0.ESC+"[1;3C"&&(o.key=s.C0.ESC+(i?"f":"[1;5C"))):o.key=t?s.C0.ESC+"OC":s.C0.ESC+"[C";break;case 38:if(e.metaKey)break;a?(o.key=s.C0.ESC+"[1;"+(a+1)+"A",i||o.key!==s.C0.ESC+"[1;3A"||(o.key=s.C0.ESC+"[1;5A")):o.key=t?s.C0.ESC+"OA":s.C0.ESC+"[A";break;case 40:if(e.metaKey)break;a?(o.key=s.C0.ESC+"[1;"+(a+1)+"B",i||o.key!==s.C0.ESC+"[1;3B"||(o.key=s.C0.ESC+"[1;5B")):o.key=t?s.C0.ESC+"OB":s.C0.ESC+"[B";break;case 45:e.shiftKey||e.ctrlKey||(o.key=s.C0.ESC+"[2~");break;case 46:o.key=a?s.C0.ESC+"[3;"+(a+1)+"~":s.C0.ESC+"[3~";break;case 36:o.key=a?s.C0.ESC+"[1;"+(a+1)+"H":t?s.C0.ESC+"OH":s.C0.ESC+"[H";break;case 35:o.key=a?s.C0.ESC+"[1;"+(a+1)+"F":t?s.C0.ESC+"OF":s.C0.ESC+"[F";break;case 33:e.shiftKey?o.type=2:e.ctrlKey?o.key=s.C0.ESC+"[5;"+(a+1)+"~":o.key=s.C0.ESC+"[5~";break;case 34:e.shiftKey?o.type=3:e.ctrlKey?o.key=s.C0.ESC+"[6;"+(a+1)+"~":o.key=s.C0.ESC+"[6~";break;case 112:o.key=a?s.C0.ESC+"[1;"+(a+1)+"P":s.C0.ESC+"OP";break;case 113:o.key=a?s.C0.ESC+"[1;"+(a+1)+"Q":s.C0.ESC+"OQ";break;case 114:o.key=a?s.C0.ESC+"[1;"+(a+1)+"R":s.C0.ESC+"OR";break;case 115:o.key=a?s.C0.ESC+"[1;"+(a+1)+"S":s.C0.ESC+"OS";break;case 116:o.key=a?s.C0.ESC+"[15;"+(a+1)+"~":s.C0.ESC+"[15~";break;case 117:o.key=a?s.C0.ESC+"[17;"+(a+1)+"~":s.C0.ESC+"[17~";break;case 118:o.key=a?s.C0.ESC+"[18;"+(a+1)+"~":s.C0.ESC+"[18~";break;case 119:o.key=a?s.C0.ESC+"[19;"+(a+1)+"~":s.C0.ESC+"[19~";break;case 120:o.key=a?s.C0.ESC+"[20;"+(a+1)+"~":s.C0.ESC+"[20~";break;case 121:o.key=a?s.C0.ESC+"[21;"+(a+1)+"~":s.C0.ESC+"[21~";break;case 122:o.key=a?s.C0.ESC+"[23;"+(a+1)+"~":s.C0.ESC+"[23~";break;case 123:o.key=a?s.C0.ESC+"[24;"+(a+1)+"~":s.C0.ESC+"[24~";break;default:if(!e.ctrlKey||e.shiftKey||e.altKey||e.metaKey)if(i&&!n||!e.altKey||e.metaKey)!i||e.altKey||e.ctrlKey||e.shiftKey||!e.metaKey?e.key&&!e.ctrlKey&&!e.altKey&&!e.metaKey&&e.keyCode>=48&&1===e.key.length?o.key=e.key:e.key&&e.ctrlKey&&("_"===e.key&&(o.key=s.C0.US),"@"===e.key&&(o.key=s.C0.NUL)):65===e.keyCode&&(o.type=1);else{const t=r[e.keyCode],i=t?.[e.shiftKey?1:0];if(i)o.key=s.C0.ESC+i;else if(e.keyCode>=65&&e.keyCode<=90){const t=e.ctrlKey?e.keyCode-64:e.keyCode+32;let i=String.fromCharCode(t);e.shiftKey&&(i=i.toUpperCase()),o.key=s.C0.ESC+i}else if(32===e.keyCode)o.key=s.C0.ESC+(e.ctrlKey?s.C0.NUL:" ");else if("Dead"===e.key&&e.code.startsWith("Key")){let t=e.code.slice(3,4);e.shiftKey||(t=t.toLowerCase()),o.key=s.C0.ESC+t,o.cancel=!0}}else e.keyCode>=65&&e.keyCode<=90?o.key=String.fromCharCode(e.keyCode-64):32===e.keyCode?o.key=s.C0.NUL:e.keyCode>=51&&e.keyCode<=55?o.key=String.fromCharCode(e.keyCode-51+27):56===e.keyCode?o.key=s.C0.DEL:219===e.keyCode?o.key=s.C0.ESC:220===e.keyCode?o.key=s.C0.FS:221===e.keyCode&&(o.key=s.C0.GS)}return o}},482:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Utf8ToUtf32=t.StringToUtf32=t.utf32ToString=t.stringFromCodePoint=void 0,t.stringFromCodePoint=function(e){return e>65535?(e-=65536,String.fromCharCode(55296+(e>>10))+String.fromCharCode(e%1024+56320)):String.fromCharCode(e)},t.utf32ToString=function(e,t=0,i=e.length){let s="";for(let r=t;r65535?(t-=65536,s+=String.fromCharCode(55296+(t>>10))+String.fromCharCode(t%1024+56320)):s+=String.fromCharCode(t)}return s},t.StringToUtf32=class{constructor(){this._interim=0}clear(){this._interim=0}decode(e,t){const i=e.length;if(!i)return 0;let s=0,r=0;if(this._interim){const i=e.charCodeAt(r++);56320<=i&&i<=57343?t[s++]=1024*(this._interim-55296)+i-56320+65536:(t[s++]=this._interim,t[s++]=i),this._interim=0}for(let n=r;n=i)return this._interim=r,s;const o=e.charCodeAt(n);56320<=o&&o<=57343?t[s++]=1024*(r-55296)+o-56320+65536:(t[s++]=r,t[s++]=o)}else 65279!==r&&(t[s++]=r)}return s}},t.Utf8ToUtf32=class{constructor(){this.interim=new Uint8Array(3)}clear(){this.interim.fill(0)}decode(e,t){const i=e.length;if(!i)return 0;let s,r,n,o,a=0,h=0,c=0;if(this.interim[0]){let s=!1,r=this.interim[0];r&=192==(224&r)?31:224==(240&r)?15:7;let n,o=0;for(;(n=63&this.interim[++o])&&o<4;)r<<=6,r|=n;const h=192==(224&this.interim[0])?2:224==(240&this.interim[0])?3:4,l=h-o;for(;c=i)return 0;if(n=e[c++],128!=(192&n)){c--,s=!0;break}this.interim[o++]=n,r<<=6,r|=63&n}s||(2===h?r<128?c--:t[a++]=r:3===h?r<2048||r>=55296&&r<=57343||65279===r||(t[a++]=r):r<65536||r>1114111||(t[a++]=r)),this.interim.fill(0)}const l=i-4;let d=c;for(;d=i)return this.interim[0]=s,a;if(r=e[d++],128!=(192&r)){d--;continue}if(h=(31&s)<<6|63&r,h<128){d--;continue}t[a++]=h}else if(224==(240&s)){if(d>=i)return this.interim[0]=s,a;if(r=e[d++],128!=(192&r)){d--;continue}if(d>=i)return this.interim[0]=s,this.interim[1]=r,a;if(n=e[d++],128!=(192&n)){d--;continue}if(h=(15&s)<<12|(63&r)<<6|63&n,h<2048||h>=55296&&h<=57343||65279===h)continue;t[a++]=h}else if(240==(248&s)){if(d>=i)return this.interim[0]=s,a;if(r=e[d++],128!=(192&r)){d--;continue}if(d>=i)return this.interim[0]=s,this.interim[1]=r,a;if(n=e[d++],128!=(192&n)){d--;continue}if(d>=i)return this.interim[0]=s,this.interim[1]=r,this.interim[2]=n,a;if(o=e[d++],128!=(192&o)){d--;continue}if(h=(7&s)<<18|(63&r)<<12|(63&n)<<6|63&o,h<65536||h>1114111)continue;t[a++]=h}}return a}}},225:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.UnicodeV6=void 0;const s=i(1480),r=[[768,879],[1155,1158],[1160,1161],[1425,1469],[1471,1471],[1473,1474],[1476,1477],[1479,1479],[1536,1539],[1552,1557],[1611,1630],[1648,1648],[1750,1764],[1767,1768],[1770,1773],[1807,1807],[1809,1809],[1840,1866],[1958,1968],[2027,2035],[2305,2306],[2364,2364],[2369,2376],[2381,2381],[2385,2388],[2402,2403],[2433,2433],[2492,2492],[2497,2500],[2509,2509],[2530,2531],[2561,2562],[2620,2620],[2625,2626],[2631,2632],[2635,2637],[2672,2673],[2689,2690],[2748,2748],[2753,2757],[2759,2760],[2765,2765],[2786,2787],[2817,2817],[2876,2876],[2879,2879],[2881,2883],[2893,2893],[2902,2902],[2946,2946],[3008,3008],[3021,3021],[3134,3136],[3142,3144],[3146,3149],[3157,3158],[3260,3260],[3263,3263],[3270,3270],[3276,3277],[3298,3299],[3393,3395],[3405,3405],[3530,3530],[3538,3540],[3542,3542],[3633,3633],[3636,3642],[3655,3662],[3761,3761],[3764,3769],[3771,3772],[3784,3789],[3864,3865],[3893,3893],[3895,3895],[3897,3897],[3953,3966],[3968,3972],[3974,3975],[3984,3991],[3993,4028],[4038,4038],[4141,4144],[4146,4146],[4150,4151],[4153,4153],[4184,4185],[4448,4607],[4959,4959],[5906,5908],[5938,5940],[5970,5971],[6002,6003],[6068,6069],[6071,6077],[6086,6086],[6089,6099],[6109,6109],[6155,6157],[6313,6313],[6432,6434],[6439,6440],[6450,6450],[6457,6459],[6679,6680],[6912,6915],[6964,6964],[6966,6970],[6972,6972],[6978,6978],[7019,7027],[7616,7626],[7678,7679],[8203,8207],[8234,8238],[8288,8291],[8298,8303],[8400,8431],[12330,12335],[12441,12442],[43014,43014],[43019,43019],[43045,43046],[64286,64286],[65024,65039],[65056,65059],[65279,65279],[65529,65531]],n=[[68097,68099],[68101,68102],[68108,68111],[68152,68154],[68159,68159],[119143,119145],[119155,119170],[119173,119179],[119210,119213],[119362,119364],[917505,917505],[917536,917631],[917760,917999]];let o;t.UnicodeV6=class{constructor(){if(this.version="6",!o){o=new Uint8Array(65536),o.fill(1),o[0]=0,o.fill(0,1,32),o.fill(0,127,160),o.fill(2,4352,4448),o[9001]=2,o[9002]=2,o.fill(2,11904,42192),o[12351]=1,o.fill(2,44032,55204),o.fill(2,63744,64256),o.fill(2,65040,65050),o.fill(2,65072,65136),o.fill(2,65280,65377),o.fill(2,65504,65511);for(let e=0;et[r][1])return!1;for(;r>=s;)if(i=s+r>>1,e>t[i][1])s=i+1;else{if(!(e=131072&&e<=196605||e>=196608&&e<=262141?2:1}charProperties(e,t){let i=this.wcwidth(e),r=0===i&&0!==t;if(r){const e=s.UnicodeService.extractWidth(t);0===e?r=!1:e>i&&(i=e)}return s.UnicodeService.createPropertyValue(0,i,r)}}},5981:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.WriteBuffer=void 0;const s=i(8460),r=i(844);class n extends r.Disposable{constructor(e){super(),this._action=e,this._writeBuffer=[],this._callbacks=[],this._pendingData=0,this._bufferOffset=0,this._isSyncWriting=!1,this._syncCalls=0,this._didUserInput=!1,this._onWriteParsed=this.register(new s.EventEmitter),this.onWriteParsed=this._onWriteParsed.event}handleUserInput(){this._didUserInput=!0}writeSync(e,t){if(void 0!==t&&this._syncCalls>t)return void(this._syncCalls=0);if(this._pendingData+=e.length,this._writeBuffer.push(e),this._callbacks.push(void 0),this._syncCalls++,this._isSyncWriting)return;let i;for(this._isSyncWriting=!0;i=this._writeBuffer.shift();){this._action(i);const e=this._callbacks.shift();e&&e()}this._pendingData=0,this._bufferOffset=2147483647,this._isSyncWriting=!1,this._syncCalls=0}write(e,t){if(this._pendingData>5e7)throw new Error("write data discarded, use flow control to avoid losing data");if(!this._writeBuffer.length){if(this._bufferOffset=0,this._didUserInput)return this._didUserInput=!1,this._pendingData+=e.length,this._writeBuffer.push(e),this._callbacks.push(t),void this._innerWrite();setTimeout((()=>this._innerWrite()))}this._pendingData+=e.length,this._writeBuffer.push(e),this._callbacks.push(t)}_innerWrite(e=0,t=!0){const i=e||Date.now();for(;this._writeBuffer.length>this._bufferOffset;){const e=this._writeBuffer[this._bufferOffset],s=this._action(e,t);if(s){const e=e=>Date.now()-i>=12?setTimeout((()=>this._innerWrite(0,e))):this._innerWrite(i,e);return void s.catch((e=>(queueMicrotask((()=>{throw e})),Promise.resolve(!1)))).then(e)}const r=this._callbacks[this._bufferOffset];if(r&&r(),this._bufferOffset++,this._pendingData-=e.length,Date.now()-i>=12)break}this._writeBuffer.length>this._bufferOffset?(this._bufferOffset>50&&(this._writeBuffer=this._writeBuffer.slice(this._bufferOffset),this._callbacks=this._callbacks.slice(this._bufferOffset),this._bufferOffset=0),setTimeout((()=>this._innerWrite()))):(this._writeBuffer.length=0,this._callbacks.length=0,this._pendingData=0,this._bufferOffset=0),this._onWriteParsed.fire()}}t.WriteBuffer=n},5941:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.toRgbString=t.parseColor=void 0;const i=/^([\da-f])\/([\da-f])\/([\da-f])$|^([\da-f]{2})\/([\da-f]{2})\/([\da-f]{2})$|^([\da-f]{3})\/([\da-f]{3})\/([\da-f]{3})$|^([\da-f]{4})\/([\da-f]{4})\/([\da-f]{4})$/,s=/^[\da-f]+$/;function r(e,t){const i=e.toString(16),s=i.length<2?"0"+i:i;switch(t){case 4:return i[0];case 8:return s;case 12:return(s+s).slice(0,3);default:return s+s}}t.parseColor=function(e){if(!e)return;let t=e.toLowerCase();if(0===t.indexOf("rgb:")){t=t.slice(4);const e=i.exec(t);if(e){const t=e[1]?15:e[4]?255:e[7]?4095:65535;return[Math.round(parseInt(e[1]||e[4]||e[7]||e[10],16)/t*255),Math.round(parseInt(e[2]||e[5]||e[8]||e[11],16)/t*255),Math.round(parseInt(e[3]||e[6]||e[9]||e[12],16)/t*255)]}}else if(0===t.indexOf("#")&&(t=t.slice(1),s.exec(t)&&[3,6,9,12].includes(t.length))){const e=t.length/3,i=[0,0,0];for(let s=0;s<3;++s){const r=parseInt(t.slice(e*s,e*s+e),16);i[s]=1===e?r<<4:2===e?r:3===e?r>>4:r>>8}return i}},t.toRgbString=function(e,t=16){const[i,s,n]=e;return`rgb:${r(i,t)}/${r(s,t)}/${r(n,t)}`}},5770:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.PAYLOAD_LIMIT=void 0,t.PAYLOAD_LIMIT=1e7},6351:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DcsHandler=t.DcsParser=void 0;const s=i(482),r=i(8742),n=i(5770),o=[];t.DcsParser=class{constructor(){this._handlers=Object.create(null),this._active=o,this._ident=0,this._handlerFb=()=>{},this._stack={paused:!1,loopPosition:0,fallThrough:!1}}dispose(){this._handlers=Object.create(null),this._handlerFb=()=>{},this._active=o}registerHandler(e,t){void 0===this._handlers[e]&&(this._handlers[e]=[]);const i=this._handlers[e];return i.push(t),{dispose:()=>{const e=i.indexOf(t);-1!==e&&i.splice(e,1)}}}clearHandler(e){this._handlers[e]&&delete this._handlers[e]}setHandlerFallback(e){this._handlerFb=e}reset(){if(this._active.length)for(let e=this._stack.paused?this._stack.loopPosition-1:this._active.length-1;e>=0;--e)this._active[e].unhook(!1);this._stack.paused=!1,this._active=o,this._ident=0}hook(e,t){if(this.reset(),this._ident=e,this._active=this._handlers[e]||o,this._active.length)for(let e=this._active.length-1;e>=0;e--)this._active[e].hook(t);else this._handlerFb(this._ident,"HOOK",t)}put(e,t,i){if(this._active.length)for(let s=this._active.length-1;s>=0;s--)this._active[s].put(e,t,i);else this._handlerFb(this._ident,"PUT",(0,s.utf32ToString)(e,t,i))}unhook(e,t=!0){if(this._active.length){let i=!1,s=this._active.length-1,r=!1;if(this._stack.paused&&(s=this._stack.loopPosition-1,i=t,r=this._stack.fallThrough,this._stack.paused=!1),!r&&!1===i){for(;s>=0&&(i=this._active[s].unhook(e),!0!==i);s--)if(i instanceof Promise)return this._stack.paused=!0,this._stack.loopPosition=s,this._stack.fallThrough=!1,i;s--}for(;s>=0;s--)if(i=this._active[s].unhook(!1),i instanceof Promise)return this._stack.paused=!0,this._stack.loopPosition=s,this._stack.fallThrough=!0,i}else this._handlerFb(this._ident,"UNHOOK",e);this._active=o,this._ident=0}};const a=new r.Params;a.addParam(0),t.DcsHandler=class{constructor(e){this._handler=e,this._data="",this._params=a,this._hitLimit=!1}hook(e){this._params=e.length>1||e.params[0]?e.clone():a,this._data="",this._hitLimit=!1}put(e,t,i){this._hitLimit||(this._data+=(0,s.utf32ToString)(e,t,i),this._data.length>n.PAYLOAD_LIMIT&&(this._data="",this._hitLimit=!0))}unhook(e){let t=!1;if(this._hitLimit)t=!1;else if(e&&(t=this._handler(this._data,this._params),t instanceof Promise))return t.then((e=>(this._params=a,this._data="",this._hitLimit=!1,e)));return this._params=a,this._data="",this._hitLimit=!1,t}}},2015:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.EscapeSequenceParser=t.VT500_TRANSITION_TABLE=t.TransitionTable=void 0;const s=i(844),r=i(8742),n=i(6242),o=i(6351);class a{constructor(e){this.table=new Uint8Array(e)}setDefault(e,t){this.table.fill(e<<4|t)}add(e,t,i,s){this.table[t<<8|e]=i<<4|s}addMany(e,t,i,s){for(let r=0;rt)),i=(e,i)=>t.slice(e,i),s=i(32,127),r=i(0,24);r.push(25),r.push.apply(r,i(28,32));const n=i(0,14);let o;for(o in e.setDefault(1,0),e.addMany(s,0,2,0),n)e.addMany([24,26,153,154],o,3,0),e.addMany(i(128,144),o,3,0),e.addMany(i(144,152),o,3,0),e.add(156,o,0,0),e.add(27,o,11,1),e.add(157,o,4,8),e.addMany([152,158,159],o,0,7),e.add(155,o,11,3),e.add(144,o,11,9);return e.addMany(r,0,3,0),e.addMany(r,1,3,1),e.add(127,1,0,1),e.addMany(r,8,0,8),e.addMany(r,3,3,3),e.add(127,3,0,3),e.addMany(r,4,3,4),e.add(127,4,0,4),e.addMany(r,6,3,6),e.addMany(r,5,3,5),e.add(127,5,0,5),e.addMany(r,2,3,2),e.add(127,2,0,2),e.add(93,1,4,8),e.addMany(s,8,5,8),e.add(127,8,5,8),e.addMany([156,27,24,26,7],8,6,0),e.addMany(i(28,32),8,0,8),e.addMany([88,94,95],1,0,7),e.addMany(s,7,0,7),e.addMany(r,7,0,7),e.add(156,7,0,0),e.add(127,7,0,7),e.add(91,1,11,3),e.addMany(i(64,127),3,7,0),e.addMany(i(48,60),3,8,4),e.addMany([60,61,62,63],3,9,4),e.addMany(i(48,60),4,8,4),e.addMany(i(64,127),4,7,0),e.addMany([60,61,62,63],4,0,6),e.addMany(i(32,64),6,0,6),e.add(127,6,0,6),e.addMany(i(64,127),6,0,0),e.addMany(i(32,48),3,9,5),e.addMany(i(32,48),5,9,5),e.addMany(i(48,64),5,0,6),e.addMany(i(64,127),5,7,0),e.addMany(i(32,48),4,9,5),e.addMany(i(32,48),1,9,2),e.addMany(i(32,48),2,9,2),e.addMany(i(48,127),2,10,0),e.addMany(i(48,80),1,10,0),e.addMany(i(81,88),1,10,0),e.addMany([89,90,92],1,10,0),e.addMany(i(96,127),1,10,0),e.add(80,1,11,9),e.addMany(r,9,0,9),e.add(127,9,0,9),e.addMany(i(28,32),9,0,9),e.addMany(i(32,48),9,9,12),e.addMany(i(48,60),9,8,10),e.addMany([60,61,62,63],9,9,10),e.addMany(r,11,0,11),e.addMany(i(32,128),11,0,11),e.addMany(i(28,32),11,0,11),e.addMany(r,10,0,10),e.add(127,10,0,10),e.addMany(i(28,32),10,0,10),e.addMany(i(48,60),10,8,10),e.addMany([60,61,62,63],10,0,11),e.addMany(i(32,48),10,9,12),e.addMany(r,12,0,12),e.add(127,12,0,12),e.addMany(i(28,32),12,0,12),e.addMany(i(32,48),12,9,12),e.addMany(i(48,64),12,0,11),e.addMany(i(64,127),12,12,13),e.addMany(i(64,127),10,12,13),e.addMany(i(64,127),9,12,13),e.addMany(r,13,13,13),e.addMany(s,13,13,13),e.add(127,13,0,13),e.addMany([27,156,24,26],13,14,0),e.add(h,0,2,0),e.add(h,8,5,8),e.add(h,6,0,6),e.add(h,11,0,11),e.add(h,13,13,13),e}();class c extends s.Disposable{constructor(e=t.VT500_TRANSITION_TABLE){super(),this._transitions=e,this._parseStack={state:0,handlers:[],handlerPos:0,transition:0,chunkPos:0},this.initialState=0,this.currentState=this.initialState,this._params=new r.Params,this._params.addParam(0),this._collect=0,this.precedingJoinState=0,this._printHandlerFb=(e,t,i)=>{},this._executeHandlerFb=e=>{},this._csiHandlerFb=(e,t)=>{},this._escHandlerFb=e=>{},this._errorHandlerFb=e=>e,this._printHandler=this._printHandlerFb,this._executeHandlers=Object.create(null),this._csiHandlers=Object.create(null),this._escHandlers=Object.create(null),this.register((0,s.toDisposable)((()=>{this._csiHandlers=Object.create(null),this._executeHandlers=Object.create(null),this._escHandlers=Object.create(null)}))),this._oscParser=this.register(new n.OscParser),this._dcsParser=this.register(new o.DcsParser),this._errorHandler=this._errorHandlerFb,this.registerEscHandler({final:"\\"},(()=>!0))}_identifier(e,t=[64,126]){let i=0;if(e.prefix){if(e.prefix.length>1)throw new Error("only one byte as prefix supported");if(i=e.prefix.charCodeAt(0),i&&60>i||i>63)throw new Error("prefix must be in range 0x3c .. 0x3f")}if(e.intermediates){if(e.intermediates.length>2)throw new Error("only two bytes as intermediates are supported");for(let t=0;ts||s>47)throw new Error("intermediate must be in range 0x20 .. 0x2f");i<<=8,i|=s}}if(1!==e.final.length)throw new Error("final must be a single byte");const s=e.final.charCodeAt(0);if(t[0]>s||s>t[1])throw new Error(`final must be in range ${t[0]} .. ${t[1]}`);return i<<=8,i|=s,i}identToString(e){const t=[];for(;e;)t.push(String.fromCharCode(255&e)),e>>=8;return t.reverse().join("")}setPrintHandler(e){this._printHandler=e}clearPrintHandler(){this._printHandler=this._printHandlerFb}registerEscHandler(e,t){const i=this._identifier(e,[48,126]);void 0===this._escHandlers[i]&&(this._escHandlers[i]=[]);const s=this._escHandlers[i];return s.push(t),{dispose:()=>{const e=s.indexOf(t);-1!==e&&s.splice(e,1)}}}clearEscHandler(e){this._escHandlers[this._identifier(e,[48,126])]&&delete this._escHandlers[this._identifier(e,[48,126])]}setEscHandlerFallback(e){this._escHandlerFb=e}setExecuteHandler(e,t){this._executeHandlers[e.charCodeAt(0)]=t}clearExecuteHandler(e){this._executeHandlers[e.charCodeAt(0)]&&delete this._executeHandlers[e.charCodeAt(0)]}setExecuteHandlerFallback(e){this._executeHandlerFb=e}registerCsiHandler(e,t){const i=this._identifier(e);void 0===this._csiHandlers[i]&&(this._csiHandlers[i]=[]);const s=this._csiHandlers[i];return s.push(t),{dispose:()=>{const e=s.indexOf(t);-1!==e&&s.splice(e,1)}}}clearCsiHandler(e){this._csiHandlers[this._identifier(e)]&&delete this._csiHandlers[this._identifier(e)]}setCsiHandlerFallback(e){this._csiHandlerFb=e}registerDcsHandler(e,t){return this._dcsParser.registerHandler(this._identifier(e),t)}clearDcsHandler(e){this._dcsParser.clearHandler(this._identifier(e))}setDcsHandlerFallback(e){this._dcsParser.setHandlerFallback(e)}registerOscHandler(e,t){return this._oscParser.registerHandler(e,t)}clearOscHandler(e){this._oscParser.clearHandler(e)}setOscHandlerFallback(e){this._oscParser.setHandlerFallback(e)}setErrorHandler(e){this._errorHandler=e}clearErrorHandler(){this._errorHandler=this._errorHandlerFb}reset(){this.currentState=this.initialState,this._oscParser.reset(),this._dcsParser.reset(),this._params.reset(),this._params.addParam(0),this._collect=0,this.precedingJoinState=0,0!==this._parseStack.state&&(this._parseStack.state=2,this._parseStack.handlers=[])}_preserveStack(e,t,i,s,r){this._parseStack.state=e,this._parseStack.handlers=t,this._parseStack.handlerPos=i,this._parseStack.transition=s,this._parseStack.chunkPos=r}parse(e,t,i){let s,r=0,n=0,o=0;if(this._parseStack.state)if(2===this._parseStack.state)this._parseStack.state=0,o=this._parseStack.chunkPos+1;else{if(void 0===i||1===this._parseStack.state)throw this._parseStack.state=1,new Error("improper continuation due to previous async handler, giving up parsing");const t=this._parseStack.handlers;let n=this._parseStack.handlerPos-1;switch(this._parseStack.state){case 3:if(!1===i&&n>-1)for(;n>=0&&(s=t[n](this._params),!0!==s);n--)if(s instanceof Promise)return this._parseStack.handlerPos=n,s;this._parseStack.handlers=[];break;case 4:if(!1===i&&n>-1)for(;n>=0&&(s=t[n](),!0!==s);n--)if(s instanceof Promise)return this._parseStack.handlerPos=n,s;this._parseStack.handlers=[];break;case 6:if(r=e[this._parseStack.chunkPos],s=this._dcsParser.unhook(24!==r&&26!==r,i),s)return s;27===r&&(this._parseStack.transition|=1),this._params.reset(),this._params.addParam(0),this._collect=0;break;case 5:if(r=e[this._parseStack.chunkPos],s=this._oscParser.end(24!==r&&26!==r,i),s)return s;27===r&&(this._parseStack.transition|=1),this._params.reset(),this._params.addParam(0),this._collect=0}this._parseStack.state=0,o=this._parseStack.chunkPos+1,this.precedingJoinState=0,this.currentState=15&this._parseStack.transition}for(let i=o;i>4){case 2:for(let s=i+1;;++s){if(s>=t||(r=e[s])<32||r>126&&r=t||(r=e[s])<32||r>126&&r=t||(r=e[s])<32||r>126&&r=t||(r=e[s])<32||r>126&&r=0&&(s=o[a](this._params),!0!==s);a--)if(s instanceof Promise)return this._preserveStack(3,o,a,n,i),s;a<0&&this._csiHandlerFb(this._collect<<8|r,this._params),this.precedingJoinState=0;break;case 8:do{switch(r){case 59:this._params.addParam(0);break;case 58:this._params.addSubParam(-1);break;default:this._params.addDigit(r-48)}}while(++i47&&r<60);i--;break;case 9:this._collect<<=8,this._collect|=r;break;case 10:const c=this._escHandlers[this._collect<<8|r];let l=c?c.length-1:-1;for(;l>=0&&(s=c[l](),!0!==s);l--)if(s instanceof Promise)return this._preserveStack(4,c,l,n,i),s;l<0&&this._escHandlerFb(this._collect<<8|r),this.precedingJoinState=0;break;case 11:this._params.reset(),this._params.addParam(0),this._collect=0;break;case 12:this._dcsParser.hook(this._collect<<8|r,this._params);break;case 13:for(let s=i+1;;++s)if(s>=t||24===(r=e[s])||26===r||27===r||r>127&&r=t||(r=e[s])<32||r>127&&r{Object.defineProperty(t,"__esModule",{value:!0}),t.OscHandler=t.OscParser=void 0;const s=i(5770),r=i(482),n=[];t.OscParser=class{constructor(){this._state=0,this._active=n,this._id=-1,this._handlers=Object.create(null),this._handlerFb=()=>{},this._stack={paused:!1,loopPosition:0,fallThrough:!1}}registerHandler(e,t){void 0===this._handlers[e]&&(this._handlers[e]=[]);const i=this._handlers[e];return i.push(t),{dispose:()=>{const e=i.indexOf(t);-1!==e&&i.splice(e,1)}}}clearHandler(e){this._handlers[e]&&delete this._handlers[e]}setHandlerFallback(e){this._handlerFb=e}dispose(){this._handlers=Object.create(null),this._handlerFb=()=>{},this._active=n}reset(){if(2===this._state)for(let e=this._stack.paused?this._stack.loopPosition-1:this._active.length-1;e>=0;--e)this._active[e].end(!1);this._stack.paused=!1,this._active=n,this._id=-1,this._state=0}_start(){if(this._active=this._handlers[this._id]||n,this._active.length)for(let e=this._active.length-1;e>=0;e--)this._active[e].start();else this._handlerFb(this._id,"START")}_put(e,t,i){if(this._active.length)for(let s=this._active.length-1;s>=0;s--)this._active[s].put(e,t,i);else this._handlerFb(this._id,"PUT",(0,r.utf32ToString)(e,t,i))}start(){this.reset(),this._state=1}put(e,t,i){if(3!==this._state){if(1===this._state)for(;t0&&this._put(e,t,i)}}end(e,t=!0){if(0!==this._state){if(3!==this._state)if(1===this._state&&this._start(),this._active.length){let i=!1,s=this._active.length-1,r=!1;if(this._stack.paused&&(s=this._stack.loopPosition-1,i=t,r=this._stack.fallThrough,this._stack.paused=!1),!r&&!1===i){for(;s>=0&&(i=this._active[s].end(e),!0!==i);s--)if(i instanceof Promise)return this._stack.paused=!0,this._stack.loopPosition=s,this._stack.fallThrough=!1,i;s--}for(;s>=0;s--)if(i=this._active[s].end(!1),i instanceof Promise)return this._stack.paused=!0,this._stack.loopPosition=s,this._stack.fallThrough=!0,i}else this._handlerFb(this._id,"END",e);this._active=n,this._id=-1,this._state=0}}},t.OscHandler=class{constructor(e){this._handler=e,this._data="",this._hitLimit=!1}start(){this._data="",this._hitLimit=!1}put(e,t,i){this._hitLimit||(this._data+=(0,r.utf32ToString)(e,t,i),this._data.length>s.PAYLOAD_LIMIT&&(this._data="",this._hitLimit=!0))}end(e){let t=!1;if(this._hitLimit)t=!1;else if(e&&(t=this._handler(this._data),t instanceof Promise))return t.then((e=>(this._data="",this._hitLimit=!1,e)));return this._data="",this._hitLimit=!1,t}}},8742:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Params=void 0;const i=2147483647;class s{static fromArray(e){const t=new s;if(!e.length)return t;for(let i=Array.isArray(e[0])?1:0;i256)throw new Error("maxSubParamsLength must not be greater than 256");this.params=new Int32Array(e),this.length=0,this._subParams=new Int32Array(t),this._subParamsLength=0,this._subParamsIdx=new Uint16Array(e),this._rejectDigits=!1,this._rejectSubDigits=!1,this._digitIsSub=!1}clone(){const e=new s(this.maxLength,this.maxSubParamsLength);return e.params.set(this.params),e.length=this.length,e._subParams.set(this._subParams),e._subParamsLength=this._subParamsLength,e._subParamsIdx.set(this._subParamsIdx),e._rejectDigits=this._rejectDigits,e._rejectSubDigits=this._rejectSubDigits,e._digitIsSub=this._digitIsSub,e}toArray(){const e=[];for(let t=0;t>8,s=255&this._subParamsIdx[t];s-i>0&&e.push(Array.prototype.slice.call(this._subParams,i,s))}return e}reset(){this.length=0,this._subParamsLength=0,this._rejectDigits=!1,this._rejectSubDigits=!1,this._digitIsSub=!1}addParam(e){if(this._digitIsSub=!1,this.length>=this.maxLength)this._rejectDigits=!0;else{if(e<-1)throw new Error("values lesser than -1 are not allowed");this._subParamsIdx[this.length]=this._subParamsLength<<8|this._subParamsLength,this.params[this.length++]=e>i?i:e}}addSubParam(e){if(this._digitIsSub=!0,this.length)if(this._rejectDigits||this._subParamsLength>=this.maxSubParamsLength)this._rejectSubDigits=!0;else{if(e<-1)throw new Error("values lesser than -1 are not allowed");this._subParams[this._subParamsLength++]=e>i?i:e,this._subParamsIdx[this.length-1]++}}hasSubParams(e){return(255&this._subParamsIdx[e])-(this._subParamsIdx[e]>>8)>0}getSubParams(e){const t=this._subParamsIdx[e]>>8,i=255&this._subParamsIdx[e];return i-t>0?this._subParams.subarray(t,i):null}getSubParamsAll(){const e={};for(let t=0;t>8,s=255&this._subParamsIdx[t];s-i>0&&(e[t]=this._subParams.slice(i,s))}return e}addDigit(e){let t;if(this._rejectDigits||!(t=this._digitIsSub?this._subParamsLength:this.length)||this._digitIsSub&&this._rejectSubDigits)return;const s=this._digitIsSub?this._subParams:this.params,r=s[t-1];s[t-1]=~r?Math.min(10*r+e,i):e}}t.Params=s},5741:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.AddonManager=void 0,t.AddonManager=class{constructor(){this._addons=[]}dispose(){for(let e=this._addons.length-1;e>=0;e--)this._addons[e].instance.dispose()}loadAddon(e,t){const i={instance:t,dispose:t.dispose,isDisposed:!1};this._addons.push(i),t.dispose=()=>this._wrappedAddonDispose(i),t.activate(e)}_wrappedAddonDispose(e){if(e.isDisposed)return;let t=-1;for(let i=0;i{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferApiView=void 0;const s=i(3785),r=i(511);t.BufferApiView=class{constructor(e,t){this._buffer=e,this.type=t}init(e){return this._buffer=e,this}get cursorY(){return this._buffer.y}get cursorX(){return this._buffer.x}get viewportY(){return this._buffer.ydisp}get baseY(){return this._buffer.ybase}get length(){return this._buffer.lines.length}getLine(e){const t=this._buffer.lines.get(e);if(t)return new s.BufferLineApiView(t)}getNullCell(){return new r.CellData}}},3785:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferLineApiView=void 0;const s=i(511);t.BufferLineApiView=class{constructor(e){this._line=e}get isWrapped(){return this._line.isWrapped}get length(){return this._line.length}getCell(e,t){if(!(e<0||e>=this._line.length))return t?(this._line.loadCell(e,t),t):this._line.loadCell(e,new s.CellData)}translateToString(e,t,i){return this._line.translateToString(e,t,i)}}},8285:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferNamespaceApi=void 0;const s=i(8771),r=i(8460),n=i(844);class o extends n.Disposable{constructor(e){super(),this._core=e,this._onBufferChange=this.register(new r.EventEmitter),this.onBufferChange=this._onBufferChange.event,this._normal=new s.BufferApiView(this._core.buffers.normal,"normal"),this._alternate=new s.BufferApiView(this._core.buffers.alt,"alternate"),this._core.buffers.onBufferActivate((()=>this._onBufferChange.fire(this.active)))}get active(){if(this._core.buffers.active===this._core.buffers.normal)return this.normal;if(this._core.buffers.active===this._core.buffers.alt)return this.alternate;throw new Error("Active buffer is neither normal nor alternate")}get normal(){return this._normal.init(this._core.buffers.normal)}get alternate(){return this._alternate.init(this._core.buffers.alt)}}t.BufferNamespaceApi=o},7975:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ParserApi=void 0,t.ParserApi=class{constructor(e){this._core=e}registerCsiHandler(e,t){return this._core.registerCsiHandler(e,(e=>t(e.toArray())))}addCsiHandler(e,t){return this.registerCsiHandler(e,t)}registerDcsHandler(e,t){return this._core.registerDcsHandler(e,((e,i)=>t(e,i.toArray())))}addDcsHandler(e,t){return this.registerDcsHandler(e,t)}registerEscHandler(e,t){return this._core.registerEscHandler(e,t)}addEscHandler(e,t){return this.registerEscHandler(e,t)}registerOscHandler(e,t){return this._core.registerOscHandler(e,t)}addOscHandler(e,t){return this.registerOscHandler(e,t)}}},7090:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.UnicodeApi=void 0,t.UnicodeApi=class{constructor(e){this._core=e}register(e){this._core.unicodeService.register(e)}get versions(){return this._core.unicodeService.versions}get activeVersion(){return this._core.unicodeService.activeVersion}set activeVersion(e){this._core.unicodeService.activeVersion=e}}},744:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.BufferService=t.MINIMUM_ROWS=t.MINIMUM_COLS=void 0;const n=i(8460),o=i(844),a=i(5295),h=i(2585);t.MINIMUM_COLS=2,t.MINIMUM_ROWS=1;let c=t.BufferService=class extends o.Disposable{get buffer(){return this.buffers.active}constructor(e){super(),this.isUserScrolling=!1,this._onResize=this.register(new n.EventEmitter),this.onResize=this._onResize.event,this._onScroll=this.register(new n.EventEmitter),this.onScroll=this._onScroll.event,this.cols=Math.max(e.rawOptions.cols||0,t.MINIMUM_COLS),this.rows=Math.max(e.rawOptions.rows||0,t.MINIMUM_ROWS),this.buffers=this.register(new a.BufferSet(e,this))}resize(e,t){this.cols=e,this.rows=t,this.buffers.resize(e,t),this._onResize.fire({cols:e,rows:t})}reset(){this.buffers.reset(),this.isUserScrolling=!1}scroll(e,t=!1){const i=this.buffer;let s;s=this._cachedBlankLine,s&&s.length===this.cols&&s.getFg(0)===e.fg&&s.getBg(0)===e.bg||(s=i.getBlankLine(e,t),this._cachedBlankLine=s),s.isWrapped=t;const r=i.ybase+i.scrollTop,n=i.ybase+i.scrollBottom;if(0===i.scrollTop){const e=i.lines.isFull;n===i.lines.length-1?e?i.lines.recycle().copyFrom(s):i.lines.push(s.clone()):i.lines.splice(n+1,0,s.clone()),e?this.isUserScrolling&&(i.ydisp=Math.max(i.ydisp-1,0)):(i.ybase++,this.isUserScrolling||i.ydisp++)}else{const e=n-r+1;i.lines.shiftElements(r+1,e-1,-1),i.lines.set(n,s.clone())}this.isUserScrolling||(i.ydisp=i.ybase),this._onScroll.fire(i.ydisp)}scrollLines(e,t,i){const s=this.buffer;if(e<0){if(0===s.ydisp)return;this.isUserScrolling=!0}else e+s.ydisp>=s.ybase&&(this.isUserScrolling=!1);const r=s.ydisp;s.ydisp=Math.max(Math.min(s.ydisp+e,s.ybase),0),r!==s.ydisp&&(t||this._onScroll.fire(s.ydisp))}};t.BufferService=c=s([r(0,h.IOptionsService)],c)},7994:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.CharsetService=void 0,t.CharsetService=class{constructor(){this.glevel=0,this._charsets=[]}reset(){this.charset=void 0,this._charsets=[],this.glevel=0}setgLevel(e){this.glevel=e,this.charset=this._charsets[e]}setgCharset(e,t){this._charsets[e]=t,this.glevel===e&&(this.charset=t)}}},1753:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CoreMouseService=void 0;const n=i(2585),o=i(8460),a=i(844),h={NONE:{events:0,restrict:()=>!1},X10:{events:1,restrict:e=>4!==e.button&&1===e.action&&(e.ctrl=!1,e.alt=!1,e.shift=!1,!0)},VT200:{events:19,restrict:e=>32!==e.action},DRAG:{events:23,restrict:e=>32!==e.action||3!==e.button},ANY:{events:31,restrict:e=>!0}};function c(e,t){let i=(e.ctrl?16:0)|(e.shift?4:0)|(e.alt?8:0);return 4===e.button?(i|=64,i|=e.action):(i|=3&e.button,4&e.button&&(i|=64),8&e.button&&(i|=128),32===e.action?i|=32:0!==e.action||t||(i|=3)),i}const l=String.fromCharCode,d={DEFAULT:e=>{const t=[c(e,!1)+32,e.col+32,e.row+32];return t[0]>255||t[1]>255||t[2]>255?"":`${l(t[0])}${l(t[1])}${l(t[2])}`},SGR:e=>{const t=0===e.action&&4!==e.button?"m":"M";return`[<${c(e,!0)};${e.col};${e.row}${t}`},SGR_PIXELS:e=>{const t=0===e.action&&4!==e.button?"m":"M";return`[<${c(e,!0)};${e.x};${e.y}${t}`}};let _=t.CoreMouseService=class extends a.Disposable{constructor(e,t){super(),this._bufferService=e,this._coreService=t,this._protocols={},this._encodings={},this._activeProtocol="",this._activeEncoding="",this._lastEvent=null,this._onProtocolChange=this.register(new o.EventEmitter),this.onProtocolChange=this._onProtocolChange.event;for(const e of Object.keys(h))this.addProtocol(e,h[e]);for(const e of Object.keys(d))this.addEncoding(e,d[e]);this.reset()}addProtocol(e,t){this._protocols[e]=t}addEncoding(e,t){this._encodings[e]=t}get activeProtocol(){return this._activeProtocol}get areMouseEventsActive(){return 0!==this._protocols[this._activeProtocol].events}set activeProtocol(e){if(!this._protocols[e])throw new Error(`unknown protocol "${e}"`);this._activeProtocol=e,this._onProtocolChange.fire(this._protocols[e].events)}get activeEncoding(){return this._activeEncoding}set activeEncoding(e){if(!this._encodings[e])throw new Error(`unknown encoding "${e}"`);this._activeEncoding=e}reset(){this.activeProtocol="NONE",this.activeEncoding="DEFAULT",this._lastEvent=null}triggerMouseEvent(e){if(e.col<0||e.col>=this._bufferService.cols||e.row<0||e.row>=this._bufferService.rows)return!1;if(4===e.button&&32===e.action)return!1;if(3===e.button&&32!==e.action)return!1;if(4!==e.button&&(2===e.action||3===e.action))return!1;if(e.col++,e.row++,32===e.action&&this._lastEvent&&this._equalEvents(this._lastEvent,e,"SGR_PIXELS"===this._activeEncoding))return!1;if(!this._protocols[this._activeProtocol].restrict(e))return!1;const t=this._encodings[this._activeEncoding](e);return t&&("DEFAULT"===this._activeEncoding?this._coreService.triggerBinaryEvent(t):this._coreService.triggerDataEvent(t,!0)),this._lastEvent=e,!0}explainEvents(e){return{down:!!(1&e),up:!!(2&e),drag:!!(4&e),move:!!(8&e),wheel:!!(16&e)}}_equalEvents(e,t,i){if(i){if(e.x!==t.x)return!1;if(e.y!==t.y)return!1}else{if(e.col!==t.col)return!1;if(e.row!==t.row)return!1}return e.button===t.button&&e.action===t.action&&e.ctrl===t.ctrl&&e.alt===t.alt&&e.shift===t.shift}};t.CoreMouseService=_=s([r(0,n.IBufferService),r(1,n.ICoreService)],_)},6975:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CoreService=void 0;const n=i(1439),o=i(8460),a=i(844),h=i(2585),c=Object.freeze({insertMode:!1}),l=Object.freeze({applicationCursorKeys:!1,applicationKeypad:!1,bracketedPasteMode:!1,origin:!1,reverseWraparound:!1,sendFocus:!1,wraparound:!0});let d=t.CoreService=class extends a.Disposable{constructor(e,t,i){super(),this._bufferService=e,this._logService=t,this._optionsService=i,this.isCursorInitialized=!1,this.isCursorHidden=!1,this._onData=this.register(new o.EventEmitter),this.onData=this._onData.event,this._onUserInput=this.register(new o.EventEmitter),this.onUserInput=this._onUserInput.event,this._onBinary=this.register(new o.EventEmitter),this.onBinary=this._onBinary.event,this._onRequestScrollToBottom=this.register(new o.EventEmitter),this.onRequestScrollToBottom=this._onRequestScrollToBottom.event,this.modes=(0,n.clone)(c),this.decPrivateModes=(0,n.clone)(l)}reset(){this.modes=(0,n.clone)(c),this.decPrivateModes=(0,n.clone)(l)}triggerDataEvent(e,t=!1){if(this._optionsService.rawOptions.disableStdin)return;const i=this._bufferService.buffer;t&&this._optionsService.rawOptions.scrollOnUserInput&&i.ybase!==i.ydisp&&this._onRequestScrollToBottom.fire(),t&&this._onUserInput.fire(),this._logService.debug(`sending data "${e}"`,(()=>e.split("").map((e=>e.charCodeAt(0))))),this._onData.fire(e)}triggerBinaryEvent(e){this._optionsService.rawOptions.disableStdin||(this._logService.debug(`sending binary "${e}"`,(()=>e.split("").map((e=>e.charCodeAt(0))))),this._onBinary.fire(e))}};t.CoreService=d=s([r(0,h.IBufferService),r(1,h.ILogService),r(2,h.IOptionsService)],d)},9074:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DecorationService=void 0;const s=i(8055),r=i(8460),n=i(844),o=i(6106);let a=0,h=0;class c extends n.Disposable{get decorations(){return this._decorations.values()}constructor(){super(),this._decorations=new o.SortedList((e=>e?.marker.line)),this._onDecorationRegistered=this.register(new r.EventEmitter),this.onDecorationRegistered=this._onDecorationRegistered.event,this._onDecorationRemoved=this.register(new r.EventEmitter),this.onDecorationRemoved=this._onDecorationRemoved.event,this.register((0,n.toDisposable)((()=>this.reset())))}registerDecoration(e){if(e.marker.isDisposed)return;const t=new l(e);if(t){const e=t.marker.onDispose((()=>t.dispose()));t.onDispose((()=>{t&&(this._decorations.delete(t)&&this._onDecorationRemoved.fire(t),e.dispose())})),this._decorations.insert(t),this._onDecorationRegistered.fire(t)}return t}reset(){for(const e of this._decorations.values())e.dispose();this._decorations.clear()}*getDecorationsAtCell(e,t,i){let s=0,r=0;for(const n of this._decorations.getKeyIterator(t))s=n.options.x??0,r=s+(n.options.width??1),e>=s&&e{a=t.options.x??0,h=a+(t.options.width??1),e>=a&&e{Object.defineProperty(t,"__esModule",{value:!0}),t.InstantiationService=t.ServiceCollection=void 0;const s=i(2585),r=i(8343);class n{constructor(...e){this._entries=new Map;for(const[t,i]of e)this.set(t,i)}set(e,t){const i=this._entries.get(e);return this._entries.set(e,t),i}forEach(e){for(const[t,i]of this._entries.entries())e(t,i)}has(e){return this._entries.has(e)}get(e){return this._entries.get(e)}}t.ServiceCollection=n,t.InstantiationService=class{constructor(){this._services=new n,this._services.set(s.IInstantiationService,this)}setService(e,t){this._services.set(e,t)}getService(e){return this._services.get(e)}createInstance(e,...t){const i=(0,r.getServiceDependencies)(e).sort(((e,t)=>e.index-t.index)),s=[];for(const t of i){const i=this._services.get(t.id);if(!i)throw new Error(`[createInstance] ${e.name} depends on UNKNOWN service ${t.id}.`);s.push(i)}const n=i.length>0?i[0].index:t.length;if(t.length!==n)throw new Error(`[createInstance] First service dependency of ${e.name} at position ${n+1} conflicts with ${t.length} static arguments`);return new e(...[...t,...s])}}},7866:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.traceCall=t.setTraceLogger=t.LogService=void 0;const n=i(844),o=i(2585),a={trace:o.LogLevelEnum.TRACE,debug:o.LogLevelEnum.DEBUG,info:o.LogLevelEnum.INFO,warn:o.LogLevelEnum.WARN,error:o.LogLevelEnum.ERROR,off:o.LogLevelEnum.OFF};let h,c=t.LogService=class extends n.Disposable{get logLevel(){return this._logLevel}constructor(e){super(),this._optionsService=e,this._logLevel=o.LogLevelEnum.OFF,this._updateLogLevel(),this.register(this._optionsService.onSpecificOptionChange("logLevel",(()=>this._updateLogLevel()))),h=this}_updateLogLevel(){this._logLevel=a[this._optionsService.rawOptions.logLevel]}_evalLazyOptionalParams(e){for(let t=0;tJSON.stringify(e))).join(", ")})`);const t=s.apply(this,e);return h.trace(`GlyphRenderer#${s.name} return`,t),t}}},7302:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.OptionsService=t.DEFAULT_OPTIONS=void 0;const s=i(8460),r=i(844),n=i(6114);t.DEFAULT_OPTIONS={cols:80,rows:24,cursorBlink:!1,cursorStyle:"block",cursorWidth:1,cursorInactiveStyle:"outline",customGlyphs:!0,drawBoldTextInBrightColors:!0,documentOverride:null,fastScrollModifier:"alt",fastScrollSensitivity:5,fontFamily:"courier-new, courier, monospace",fontSize:15,fontWeight:"normal",fontWeightBold:"bold",ignoreBracketedPasteMode:!1,lineHeight:1,letterSpacing:0,linkHandler:null,logLevel:"info",logger:null,scrollback:1e3,scrollOnUserInput:!0,scrollSensitivity:1,screenReaderMode:!1,smoothScrollDuration:0,macOptionIsMeta:!1,macOptionClickForcesSelection:!1,minimumContrastRatio:1,disableStdin:!1,allowProposedApi:!1,allowTransparency:!1,tabStopWidth:8,theme:{},rightClickSelectsWord:n.isMac,windowOptions:{},windowsMode:!1,windowsPty:{},wordSeparator:" ()[]{}',\"`",altClickMovesCursor:!0,convertEol:!1,termName:"xterm",cancelEvents:!1,overviewRulerWidth:0};const o=["normal","bold","100","200","300","400","500","600","700","800","900"];class a extends r.Disposable{constructor(e){super(),this._onOptionChange=this.register(new s.EventEmitter),this.onOptionChange=this._onOptionChange.event;const i={...t.DEFAULT_OPTIONS};for(const t in e)if(t in i)try{const s=e[t];i[t]=this._sanitizeAndValidateOption(t,s)}catch(e){console.error(e)}this.rawOptions=i,this.options={...i},this._setupOptions(),this.register((0,r.toDisposable)((()=>{this.rawOptions.linkHandler=null,this.rawOptions.documentOverride=null})))}onSpecificOptionChange(e,t){return this.onOptionChange((i=>{i===e&&t(this.rawOptions[e])}))}onMultipleOptionChange(e,t){return this.onOptionChange((i=>{-1!==e.indexOf(i)&&t()}))}_setupOptions(){const e=e=>{if(!(e in t.DEFAULT_OPTIONS))throw new Error(`No option with key "${e}"`);return this.rawOptions[e]},i=(e,i)=>{if(!(e in t.DEFAULT_OPTIONS))throw new Error(`No option with key "${e}"`);i=this._sanitizeAndValidateOption(e,i),this.rawOptions[e]!==i&&(this.rawOptions[e]=i,this._onOptionChange.fire(e))};for(const t in this.rawOptions){const s={get:e.bind(this,t),set:i.bind(this,t)};Object.defineProperty(this.options,t,s)}}_sanitizeAndValidateOption(e,i){switch(e){case"cursorStyle":if(i||(i=t.DEFAULT_OPTIONS[e]),!function(e){return"block"===e||"underline"===e||"bar"===e}(i))throw new Error(`"${i}" is not a valid value for ${e}`);break;case"wordSeparator":i||(i=t.DEFAULT_OPTIONS[e]);break;case"fontWeight":case"fontWeightBold":if("number"==typeof i&&1<=i&&i<=1e3)break;i=o.includes(i)?i:t.DEFAULT_OPTIONS[e];break;case"cursorWidth":i=Math.floor(i);case"lineHeight":case"tabStopWidth":if(i<1)throw new Error(`${e} cannot be less than 1, value: ${i}`);break;case"minimumContrastRatio":i=Math.max(1,Math.min(21,Math.round(10*i)/10));break;case"scrollback":if((i=Math.min(i,4294967295))<0)throw new Error(`${e} cannot be less than 0, value: ${i}`);break;case"fastScrollSensitivity":case"scrollSensitivity":if(i<=0)throw new Error(`${e} cannot be less than or equal to 0, value: ${i}`);break;case"rows":case"cols":if(!i&&0!==i)throw new Error(`${e} must be numeric, value: ${i}`);break;case"windowsPty":i=i??{}}return i}}t.OptionsService=a},2660:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.OscLinkService=void 0;const n=i(2585);let o=t.OscLinkService=class{constructor(e){this._bufferService=e,this._nextId=1,this._entriesWithId=new Map,this._dataByLinkId=new Map}registerLink(e){const t=this._bufferService.buffer;if(void 0===e.id){const i=t.addMarker(t.ybase+t.y),s={data:e,id:this._nextId++,lines:[i]};return i.onDispose((()=>this._removeMarkerFromLink(s,i))),this._dataByLinkId.set(s.id,s),s.id}const i=e,s=this._getEntryIdKey(i),r=this._entriesWithId.get(s);if(r)return this.addLineToLink(r.id,t.ybase+t.y),r.id;const n=t.addMarker(t.ybase+t.y),o={id:this._nextId++,key:this._getEntryIdKey(i),data:i,lines:[n]};return n.onDispose((()=>this._removeMarkerFromLink(o,n))),this._entriesWithId.set(o.key,o),this._dataByLinkId.set(o.id,o),o.id}addLineToLink(e,t){const i=this._dataByLinkId.get(e);if(i&&i.lines.every((e=>e.line!==t))){const e=this._bufferService.buffer.addMarker(t);i.lines.push(e),e.onDispose((()=>this._removeMarkerFromLink(i,e)))}}getLinkData(e){return this._dataByLinkId.get(e)?.data}_getEntryIdKey(e){return`${e.id};;${e.uri}`}_removeMarkerFromLink(e,t){const i=e.lines.indexOf(t);-1!==i&&(e.lines.splice(i,1),0===e.lines.length&&(void 0!==e.data.id&&this._entriesWithId.delete(e.key),this._dataByLinkId.delete(e.id)))}};t.OscLinkService=o=s([r(0,n.IBufferService)],o)},8343:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.createDecorator=t.getServiceDependencies=t.serviceRegistry=void 0;const i="di$target",s="di$dependencies";t.serviceRegistry=new Map,t.getServiceDependencies=function(e){return e[s]||[]},t.createDecorator=function(e){if(t.serviceRegistry.has(e))return t.serviceRegistry.get(e);const r=function(e,t,n){if(3!==arguments.length)throw new Error("@IServiceName-decorator can only be used to decorate a parameter");!function(e,t,r){t[i]===t?t[s].push({id:e,index:r}):(t[s]=[{id:e,index:r}],t[i]=t)}(r,e,n)};return r.toString=()=>e,t.serviceRegistry.set(e,r),r}},2585:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.IDecorationService=t.IUnicodeService=t.IOscLinkService=t.IOptionsService=t.ILogService=t.LogLevelEnum=t.IInstantiationService=t.ICharsetService=t.ICoreService=t.ICoreMouseService=t.IBufferService=void 0;const s=i(8343);var r;t.IBufferService=(0,s.createDecorator)("BufferService"),t.ICoreMouseService=(0,s.createDecorator)("CoreMouseService"),t.ICoreService=(0,s.createDecorator)("CoreService"),t.ICharsetService=(0,s.createDecorator)("CharsetService"),t.IInstantiationService=(0,s.createDecorator)("InstantiationService"),function(e){e[e.TRACE=0]="TRACE",e[e.DEBUG=1]="DEBUG",e[e.INFO=2]="INFO",e[e.WARN=3]="WARN",e[e.ERROR=4]="ERROR",e[e.OFF=5]="OFF"}(r||(t.LogLevelEnum=r={})),t.ILogService=(0,s.createDecorator)("LogService"),t.IOptionsService=(0,s.createDecorator)("OptionsService"),t.IOscLinkService=(0,s.createDecorator)("OscLinkService"),t.IUnicodeService=(0,s.createDecorator)("UnicodeService"),t.IDecorationService=(0,s.createDecorator)("DecorationService")},1480:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.UnicodeService=void 0;const s=i(8460),r=i(225);class n{static extractShouldJoin(e){return 0!=(1&e)}static extractWidth(e){return e>>1&3}static extractCharKind(e){return e>>3}static createPropertyValue(e,t,i=!1){return(16777215&e)<<3|(3&t)<<1|(i?1:0)}constructor(){this._providers=Object.create(null),this._active="",this._onChange=new s.EventEmitter,this.onChange=this._onChange.event;const e=new r.UnicodeV6;this.register(e),this._active=e.version,this._activeProvider=e}dispose(){this._onChange.dispose()}get versions(){return Object.keys(this._providers)}get activeVersion(){return this._active}set activeVersion(e){if(!this._providers[e])throw new Error(`unknown Unicode version "${e}"`);this._active=e,this._activeProvider=this._providers[e],this._onChange.fire(e)}register(e){this._providers[e.version]=e}wcwidth(e){return this._activeProvider.wcwidth(e)}getStringCellWidth(e){let t=0,i=0;const s=e.length;for(let r=0;r=s)return t+this.wcwidth(o);const i=e.charCodeAt(r);56320<=i&&i<=57343?o=1024*(o-55296)+i-56320+65536:t+=this.wcwidth(i)}const a=this.charProperties(o,i);let h=n.extractWidth(a);n.extractShouldJoin(a)&&(h-=n.extractWidth(i)),t+=h,i=a}return t}charProperties(e,t){return this._activeProvider.charProperties(e,t)}}t.UnicodeService=n}},t={};function i(s){var r=t[s];if(void 0!==r)return r.exports;var n=t[s]={exports:{}};return e[s].call(n.exports,n,n.exports,i),n.exports}var s={};return(()=>{var e=s;Object.defineProperty(e,"__esModule",{value:!0}),e.Terminal=void 0;const t=i(9042),r=i(3236),n=i(844),o=i(5741),a=i(8285),h=i(7975),c=i(7090),l=["cols","rows"];class d extends n.Disposable{constructor(e){super(),this._core=this.register(new r.Terminal(e)),this._addonManager=this.register(new o.AddonManager),this._publicOptions={...this._core.options};const t=e=>this._core.options[e],i=(e,t)=>{this._checkReadonlyOptions(e),this._core.options[e]=t};for(const e in this._core.options){const s={get:t.bind(this,e),set:i.bind(this,e)};Object.defineProperty(this._publicOptions,e,s)}}_checkReadonlyOptions(e){if(l.includes(e))throw new Error(`Option "${e}" can only be set in the constructor`)}_checkProposedApi(){if(!this._core.optionsService.rawOptions.allowProposedApi)throw new Error("You must set the allowProposedApi option to true to use proposed API")}get onBell(){return this._core.onBell}get onBinary(){return this._core.onBinary}get onCursorMove(){return this._core.onCursorMove}get onData(){return this._core.onData}get onKey(){return this._core.onKey}get onLineFeed(){return this._core.onLineFeed}get onRender(){return this._core.onRender}get onResize(){return this._core.onResize}get onScroll(){return this._core.onScroll}get onSelectionChange(){return this._core.onSelectionChange}get onTitleChange(){return this._core.onTitleChange}get onWriteParsed(){return this._core.onWriteParsed}get element(){return this._core.element}get parser(){return this._parser||(this._parser=new h.ParserApi(this._core)),this._parser}get unicode(){return this._checkProposedApi(),new c.UnicodeApi(this._core)}get textarea(){return this._core.textarea}get rows(){return this._core.rows}get cols(){return this._core.cols}get buffer(){return this._buffer||(this._buffer=this.register(new a.BufferNamespaceApi(this._core))),this._buffer}get markers(){return this._checkProposedApi(),this._core.markers}get modes(){const e=this._core.coreService.decPrivateModes;let t="none";switch(this._core.coreMouseService.activeProtocol){case"X10":t="x10";break;case"VT200":t="vt200";break;case"DRAG":t="drag";break;case"ANY":t="any"}return{applicationCursorKeysMode:e.applicationCursorKeys,applicationKeypadMode:e.applicationKeypad,bracketedPasteMode:e.bracketedPasteMode,insertMode:this._core.coreService.modes.insertMode,mouseTrackingMode:t,originMode:e.origin,reverseWraparoundMode:e.reverseWraparound,sendFocusMode:e.sendFocus,wraparoundMode:e.wraparound}}get options(){return this._publicOptions}set options(e){for(const t in e)this._publicOptions[t]=e[t]}blur(){this._core.blur()}focus(){this._core.focus()}input(e,t=!0){this._core.input(e,t)}resize(e,t){this._verifyIntegers(e,t),this._core.resize(e,t)}open(e){this._core.open(e)}attachCustomKeyEventHandler(e){this._core.attachCustomKeyEventHandler(e)}attachCustomWheelEventHandler(e){this._core.attachCustomWheelEventHandler(e)}registerLinkProvider(e){return this._core.registerLinkProvider(e)}registerCharacterJoiner(e){return this._checkProposedApi(),this._core.registerCharacterJoiner(e)}deregisterCharacterJoiner(e){this._checkProposedApi(),this._core.deregisterCharacterJoiner(e)}registerMarker(e=0){return this._verifyIntegers(e),this._core.registerMarker(e)}registerDecoration(e){return this._checkProposedApi(),this._verifyPositiveIntegers(e.x??0,e.width??0,e.height??0),this._core.registerDecoration(e)}hasSelection(){return this._core.hasSelection()}select(e,t,i){this._verifyIntegers(e,t,i),this._core.select(e,t,i)}getSelection(){return this._core.getSelection()}getSelectionPosition(){return this._core.getSelectionPosition()}clearSelection(){this._core.clearSelection()}selectAll(){this._core.selectAll()}selectLines(e,t){this._verifyIntegers(e,t),this._core.selectLines(e,t)}dispose(){super.dispose()}scrollLines(e){this._verifyIntegers(e),this._core.scrollLines(e)}scrollPages(e){this._verifyIntegers(e),this._core.scrollPages(e)}scrollToTop(){this._core.scrollToTop()}scrollToBottom(){this._core.scrollToBottom()}scrollToLine(e){this._verifyIntegers(e),this._core.scrollToLine(e)}clear(){this._core.clear()}write(e,t){this._core.write(e,t)}writeln(e,t){this._core.write(e),this._core.write("\r\n",t)}paste(e){this._core.paste(e)}refresh(e,t){this._verifyIntegers(e,t),this._core.refresh(e,t)}reset(){this._core.reset()}clearTextureAtlas(){this._core.clearTextureAtlas()}loadAddon(e){this._addonManager.loadAddon(this,e)}static get strings(){return t}_verifyIntegers(...e){for(const t of e)if(t===1/0||isNaN(t)||t%1!=0)throw new Error("This API only accepts integers")}_verifyPositiveIntegers(...e){for(const t of e)if(t&&(t===1/0||isNaN(t)||t%1!=0||t<0))throw new Error("This API only accepts positive integers")}}e.Terminal=d})(),s})())); +//# sourceMappingURL=xterm.js.map \ No newline at end of file From d13efbbe23e16dfca691cca43a4f93c3523941ad Mon Sep 17 00:00:00 2001 From: lsileoni Date: Thu, 11 Apr 2024 12:22:45 +0300 Subject: [PATCH 0002/2119] Changed vm dir to make_container in starter script --- incubator/x86emu/v86starter.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/incubator/x86emu/v86starter.sh b/incubator/x86emu/v86starter.sh index 84b4cda6ef..85f9cbbbee 100755 --- a/incubator/x86emu/v86starter.sh +++ b/incubator/x86emu/v86starter.sh @@ -3,7 +3,7 @@ ROOT_DIR="$(pwd)" mkdir -p "$ROOT_DIR/vm" -cd "$ROOT_DIR/vm" || exit +cd "$ROOT_DIR/make_container" || exit docker build . -t v86builder docker run --name v86build v86builder mkdir -p "$ROOT_DIR/vm/v86" From 4815eb10a9d005d2440f9c6e751a22ce51b74b82 Mon Sep 17 00:00:00 2001 From: lsileoni Date: Thu, 11 Apr 2024 12:41:17 +0300 Subject: [PATCH 0003/2119] Don't bind to all interfaces by default in web server --- incubator/x86emu/v86starter.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/incubator/x86emu/v86starter.sh b/incubator/x86emu/v86starter.sh index 85f9cbbbee..506455df00 100755 --- a/incubator/x86emu/v86starter.sh +++ b/incubator/x86emu/v86starter.sh @@ -36,5 +36,5 @@ cp -r "$ROOT_DIR/vm/v86/static/debian-9p-rootfs-flat/" "$ROOT_DIR/www/images/9p- # Start a HTTP server cd "$ROOT_DIR/www/" || exit -echo "Opening a server on port 8080" -python3 -m http.server 8080 +echo "Opening a server on localhost with port 8080" +python3 -m http.server -b 127.0.0.1 8080 From 2405ee90e9077a3a06456af8b38ece2eb9dee0a4 Mon Sep 17 00:00:00 2001 From: lsileoni Date: Thu, 11 Apr 2024 15:48:31 +0300 Subject: [PATCH 0004/2119] Ignore generated .bin files --- incubator/x86emu/.gitignore | 1 + 1 file changed, 1 insertion(+) create mode 100644 incubator/x86emu/.gitignore diff --git a/incubator/x86emu/.gitignore b/incubator/x86emu/.gitignore new file mode 100644 index 0000000000..a8a0dcec44 --- /dev/null +++ b/incubator/x86emu/.gitignore @@ -0,0 +1 @@ +*.bin From 21ef0598f9c5cee935ffa912e920992a15293d9a Mon Sep 17 00:00:00 2001 From: lsileoni Date: Thu, 11 Apr 2024 15:49:46 +0300 Subject: [PATCH 0005/2119] Also ignore wasm blobs --- incubator/x86emu/.gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/incubator/x86emu/.gitignore b/incubator/x86emu/.gitignore index a8a0dcec44..f3f1b28b11 100644 --- a/incubator/x86emu/.gitignore +++ b/incubator/x86emu/.gitignore @@ -1 +1,2 @@ *.bin +*.wasm From d6a327ea8664bc276d84cdcaa9a7a3f68aae1de8 Mon Sep 17 00:00:00 2001 From: lsileoni Date: Thu, 11 Apr 2024 15:51:50 +0300 Subject: [PATCH 0006/2119] Changed vm build target directory to /tmp because of package.json issue --- incubator/x86emu/v86starter.sh | 20 +++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/incubator/x86emu/v86starter.sh b/incubator/x86emu/v86starter.sh index 506455df00..e5cee4dfaa 100755 --- a/incubator/x86emu/v86starter.sh +++ b/incubator/x86emu/v86starter.sh @@ -2,19 +2,21 @@ ROOT_DIR="$(pwd)" -mkdir -p "$ROOT_DIR/vm" +# This has to be something, that isn't wrapped by a repo with a package.json +VM_DIR="/tmp/vm" + +mkdir -p "$VM_DIR" cd "$ROOT_DIR/make_container" || exit docker build . -t v86builder docker run --name v86build v86builder -mkdir -p "$ROOT_DIR/vm/v86" -docker cp v86build:/app/v86 "$ROOT_DIR/vm/" +docker cp v86build:/app/v86 "$VM_DIR" docker rm v86build # Overwrite v86'd debian Dockerfile with our own -cat "$ROOT_DIR/imagegen/Dockerfile" > "$ROOT_DIR/vm/v86/tools/docker/debian/Dockerfile" +cat "$ROOT_DIR/imagegen/Dockerfile" > "$VM_DIR/v86/tools/docker/debian/Dockerfile" # Navigate to the Dockerfile directory -cd "$ROOT_DIR/vm/v86/tools/docker/debian" || exit +cd "$VM_DIR/v86/tools/docker/debian" || exit # Build the container which will be used to serve v86 chmod +x build-container.sh @@ -29,10 +31,10 @@ mkdir -p "$ROOT_DIR/www/third-party" mkdir -p "$ROOT_DIR/www/static" # Copy necessary files to deployment directory -cp "$ROOT_DIR/vm/v86/build/libv86.js" "$ROOT_DIR/www/third-party/libv86.js" -cp "$ROOT_DIR/vm/v86/build/v86.wasm" "$ROOT_DIR/www/third-party/v86.wasm" -cp "$ROOT_DIR/vm/v86/static/debian-state-base.bin" "$ROOT_DIR/www/images/image.bin" -cp -r "$ROOT_DIR/vm/v86/static/debian-9p-rootfs-flat/" "$ROOT_DIR/www/images/9p-rootfs/" +cp "$VM_DIR/v86/build/libv86.js" "$ROOT_DIR/www/third-party/libv86.js" +cp "$VM_DIR/v86/build/v86.wasm" "$ROOT_DIR/www/third-party/v86.wasm" +cp "$VM_DIR/v86/images/debian-state-base.bin" "$ROOT_DIR/www/static/image.bin" +cp -r "$VM_DIR/v86/images/debian-9p-rootfs-flat/" "$ROOT_DIR/www/static/9p-rootfs/" # Start a HTTP server cd "$ROOT_DIR/www/" || exit From 902a242f6b2f4d51718212a71c8def0bf6c393e9 Mon Sep 17 00:00:00 2001 From: lsileoni Date: Thu, 11 Apr 2024 19:15:58 +0300 Subject: [PATCH 0007/2119] Rebuilding logic and zstd compression for v86starter --- incubator/x86emu/v86starter.sh | 82 +++++++++++++++++++++------------- 1 file changed, 52 insertions(+), 30 deletions(-) diff --git a/incubator/x86emu/v86starter.sh b/incubator/x86emu/v86starter.sh index e5cee4dfaa..dbbff8fe9e 100755 --- a/incubator/x86emu/v86starter.sh +++ b/incubator/x86emu/v86starter.sh @@ -5,36 +5,58 @@ ROOT_DIR="$(pwd)" # This has to be something, that isn't wrapped by a repo with a package.json VM_DIR="/tmp/vm" -mkdir -p "$VM_DIR" -cd "$ROOT_DIR/make_container" || exit -docker build . -t v86builder -docker run --name v86build v86builder -docker cp v86build:/app/v86 "$VM_DIR" -docker rm v86build - -# Overwrite v86'd debian Dockerfile with our own -cat "$ROOT_DIR/imagegen/Dockerfile" > "$VM_DIR/v86/tools/docker/debian/Dockerfile" - -# Navigate to the Dockerfile directory -cd "$VM_DIR/v86/tools/docker/debian" || exit - -# Build the container which will be used to serve v86 -chmod +x build-container.sh -./build-container.sh - -# Build the state of the VM -chmod +x build-state.js -./build-state.js - -# Make project directories -mkdir -p "$ROOT_DIR/www/third-party" -mkdir -p "$ROOT_DIR/www/static" - -# Copy necessary files to deployment directory -cp "$VM_DIR/v86/build/libv86.js" "$ROOT_DIR/www/third-party/libv86.js" -cp "$VM_DIR/v86/build/v86.wasm" "$ROOT_DIR/www/third-party/v86.wasm" -cp "$VM_DIR/v86/images/debian-state-base.bin" "$ROOT_DIR/www/static/image.bin" -cp -r "$VM_DIR/v86/images/debian-9p-rootfs-flat/" "$ROOT_DIR/www/static/9p-rootfs/" +# Goes from 1 to 22 +ZSTD_LEVEL=22 + +build() +{ + mkdir -p "$VM_DIR" + rm -rf "$VM_DIR/v86" + cd "$ROOT_DIR/make_container" || exit + docker build . -t v86builder + docker run --name v86build v86builder + docker cp v86build:/app/v86 "$VM_DIR" + docker rm v86build + + # Overwrite v86'd debian Dockerfile with our own + cat "$ROOT_DIR/imagegen/Dockerfile" > "$VM_DIR/v86/tools/docker/debian/Dockerfile" + + # Navigate to the Dockerfile directory + cd "$VM_DIR/v86/tools/docker/debian" || exit + + # Build the container which will be used to serve v86 + chmod +x build-container.sh + ./build-container.sh + + # Build the state of the VM + chmod +x build-state.js + ./build-state.js + + # Compress the generated state image + zstd --ultra -$ZSTD_LEVEL < "$VM_DIR/v86/images/debian-state-base.bin" > "$VM_DIR/v86/images/image.bin" + + # Make project directories + mkdir -p "$ROOT_DIR/www/third-party" + mkdir -p "$ROOT_DIR/www/static" + + # Copy necessary files to deployment directory + cp "$VM_DIR/v86/build/libv86.js" "$ROOT_DIR/www/third-party/libv86.js" + cp "$VM_DIR/v86/build/v86.wasm" "$ROOT_DIR/www/third-party/v86.wasm" + cp "$VM_DIR/v86/images/debian-state-base.bin" "$ROOT_DIR/www/static/image.bin" + cp -r "$VM_DIR/v86/images/debian-9p-rootfs-flat/" "$ROOT_DIR/www/static/9p-rootfs/" +} + +if [ ! -d "$VM_DIR/v86" ] +then + build +else + echo "V86 appears to be built" + read -p "Do you want to rebuild V86? (yes/no): " rebuild_choice + if [ "$rebuild_choice" = "yes" ]; then + echo "Rebuilding v86..." + build + fi +fi # Start a HTTP server cd "$ROOT_DIR/www/" || exit From a6b7ec5c66be75ecd3068c6c88fabefafbf6e472 Mon Sep 17 00:00:00 2001 From: lsileoni Date: Thu, 11 Apr 2024 20:52:47 +0300 Subject: [PATCH 0008/2119] Clean up index.html usage example --- incubator/x86emu/www/index.html | 80 +-------------------------------- 1 file changed, 2 insertions(+), 78 deletions(-) diff --git a/incubator/x86emu/www/index.html b/incubator/x86emu/www/index.html index 68cab0f7c4..48418f4434 100644 --- a/incubator/x86emu/www/index.html +++ b/incubator/x86emu/www/index.html @@ -10,87 +10,11 @@ import InstanceManager from "./js/InstanceManager.mjs" document.addEventListener("DOMContentLoaded", () => { - window.manager = new InstanceManager({spawnRoot: document.body, screen: true}); + window.manager = new InstanceManager({spawnRoot: document.body, term: true}); + window.manager.createInstance({spawnRoot: document.body, term: true}) }); - - // var term = new Terminal({ - // allowTransparency: true, - // }); - // term.open(document.getElementById('terminal')); - // term.write("Now booting emu, please stand by ..."); - // var emulator = new V86({ - // // network_relay_url: "ws://localhost:8080/", - // wasm_path: "./lib/v86.wasm", - // preserve_mac_from_state_image: true, - // memory_size: 1024 * 1024 * 1024, - // vga_memory_size: 8 * 1024 * 1024, - // initial_state: {url: "./images/image.bin"}, - // filesystem: {baseurl: "./images/9p-rootfs/"}, - // autostart: true, - // }); - - // emulator.add_listener("emulator-started", function () { - // // emulator.serial0_send("\nsh networking.sh > /dev/null 2>&1 &\n\n"); - // // emulator.serial0_send("clear\n"); - // term.write("Welcome to psl!"); - // emulator.serial0_send("\n"); - // }); - - // emulator.add_listener("serial0-output-byte", function (byte) { - // var chr = String.fromCharCode(byte); - // if (chr <= "~") { - // term.write(chr); - // } - // }); - - // term.onData(data => { - // emulator.serial0_send(data); - // }); - // var termt = new Terminal({ - // allowTransparency: true, - // }); - // termt.open(document.getElementById('second_terminal')); - // termt.write("Now booting, please stand by ..."); - // var emulatort = new V86({ - // // network_relay_url: "ws://localhost:8080/", - // wasm_path: "./lib/v86.wasm", - // preserve_mac_from_state_image: true, - // memory_size: 512 * 1024 * 1024, - // vga_memory_size: 8 * 1024 * 1024, - // initial_state: {url: "./images/image.bin"}, - // filesystem: {baseurl: "./images/9p-rootfs/"}, - // autostart: true, - // }); - - // emulatort.add_listener("emulator-started", function () { - // // emulatort.serial0_send("\nsh networking.sh > /dev/null 2>&1 &\n\n"); - // // emulatort.serial0_send("clear\n"); - // termt.write("Welcome to psl!"); - // emulatort.serial0_send("\n"); - // }); - - // emulatort.add_listener("serial0-output-byte", function (byte) { - // var chr = String.fromCharCode(byte); - // if (chr <= "~") { - // termt.write(chr); - // } - // }); - - // termt.onData(data => { - // emulatort.serial0_send(data); - // }); - // emulator.add_listener("net0-send", function (data) { - // emulatort.bus.send("net0-receive", data); - // }); - // emulatort.add_listener("net0-send", function (data) { - // emulator.bus.send("net0-receive", data); - // }); - -
-
- From 2b28388fa73136a0ee76756c1ef9d400fd1c3e53 Mon Sep 17 00:00:00 2001 From: lsileoni Date: Thu, 11 Apr 2024 20:53:48 +0300 Subject: [PATCH 0009/2119] Changes to module imports for parity between the browser and node, fixed browser and node examples --- incubator/x86emu/www/js/Instance.mjs | 41 ++++++++++++++++++--- incubator/x86emu/www/js/InstanceManager.mjs | 13 ++++--- incubator/x86emu/www/js/V86Wrapper.mjs | 16 ++++++++ incubator/x86emu/www/main.js | 10 ++--- 4 files changed, 65 insertions(+), 15 deletions(-) create mode 100644 incubator/x86emu/www/js/V86Wrapper.mjs diff --git a/incubator/x86emu/www/js/Instance.mjs b/incubator/x86emu/www/js/Instance.mjs index cbb75e4682..e64dd40455 100644 --- a/incubator/x86emu/www/js/Instance.mjs +++ b/incubator/x86emu/www/js/Instance.mjs @@ -1,4 +1,4 @@ -import * as libv86 from '../third-party/libv86.js'; +import { V86 } from "./V86Wrapper.mjs"; /** * Class representing an Instance of an emulator machine. */ @@ -17,7 +17,7 @@ class Instance { */ constructor(options) { const defaultOptions = { - term: true, + term: false, screen: false, memory: 1024, spawnRoot: undefined, @@ -29,7 +29,7 @@ class Instance { const instanceOptions = { ...defaultOptions, ...options }; if (!instanceOptions.remote.endsWith('/')) - throw new Error("Remote URL must end with a slash"); + throw new Error("Instance ctor: Remote URL must end with a slash"); if (typeof self !== 'undefined' && self.crypto) { this.instanceID = self.crypto.randomUUID(); } else { @@ -48,8 +48,10 @@ class Instance { if (!(instanceOptions.wsUrl === "")) v86Options.network_relay_url = instanceOptions.wsUrl; if (!((Math.log(v86Options.memory_size) / Math.log(2)) % 1 === 0)) - throw new Error("Amount of memory provided isn't a power of two"); + throw new Error("Instance ctor: Amount of memory provided isn't a power of two"); if (instanceOptions.screen === true) { + if (instanceOptions.spawnRoot === undefined) + throw new Error("Instance ctor: spawnRoot is undefined, cannot continue") instanceOptions.spawnRoot.appendChild((() => { const div = document.createElement("div"); div.setAttribute("id", instanceOptions.instanceName + '-screen'); @@ -66,7 +68,36 @@ class Instance { })()); v86Options.screen_container = document.getElementById(instanceOptions.instanceName + '-screen'); } - this.vm = new libv86.V86(v86Options); + this.vm = new V86(v86Options); + if (instanceOptions.term === true) { + if (instanceOptions.spawnRoot === undefined) + throw new Error("Instance ctor: spawnRoot is undefined, cannot continue") + var term = new Terminal({ + allowTransparency: true, + }); + instanceOptions.spawnRoot.appendChild((() => { + const div = document.createElement("div"); + div.setAttribute("id", instanceOptions.instanceName + '-terminal'); + return div; + })()); + term.open(document.getElementById(instanceOptions.instanceName + '-terminal')); + term.write("Now booting emu, please stand by ..."); + this.vm.add_listener("emulator-started", () => { + // emulator.serial0_send("\nsh networking.sh > /dev/null 2>&1 &\n\n"); + // emulator.serial0_send("clear\n"); + term.write("Welcome to psl!"); + this.vm.serial0_send("\n"); + }); + this.vm.add_listener("serial0-output-byte", (byte) => { + var chr = String.fromCharCode(byte); + if (chr <= "~") { + term.write(chr); + } + }); + term.onData(data => { + this.vm.serial0_send(data); + }); + } } } diff --git a/incubator/x86emu/www/js/InstanceManager.mjs b/incubator/x86emu/www/js/InstanceManager.mjs index 577d068395..6e8ebce644 100644 --- a/incubator/x86emu/www/js/InstanceManager.mjs +++ b/incubator/x86emu/www/js/InstanceManager.mjs @@ -18,7 +18,7 @@ class InstanceManager { */ constructor(options) { const defaultOptions = { - term: true, + term: false, screen: false, instanceName: "Host", memory: 1024, @@ -32,15 +32,18 @@ class InstanceManager { this.instanceNames = []; this.curr_inst = 0; this.instanceNames.push(instanceOptions.instanceName); - this.instances[instanceOptions.instanceName] = this.initInstance(instanceOptions); + this.instances[instanceOptions.instanceName] = new Instance(instanceOptions); } /** - * Initialize an instance with given options. + * Create an instance with given options and adds it to the pool of instances. * @param {Object} options - Options for configuring the instance. * @returns {Promise} - Resolves with the initialized instance. */ - initInstance(options) { - return new Instance(options); + async createInstance(options) { + const instance = new Instance(options); + this.instanceNames.push(instance.instanceName); + this.instances[instance.instanceName] = instance; + return instance; } /** * Continue running a suspended instance. diff --git a/incubator/x86emu/www/js/V86Wrapper.mjs b/incubator/x86emu/www/js/V86Wrapper.mjs new file mode 100644 index 0000000000..5417bc6867 --- /dev/null +++ b/incubator/x86emu/www/js/V86Wrapper.mjs @@ -0,0 +1,16 @@ +let V86; + +if (typeof window !== 'undefined') { + V86 = window.V86; +} else { + try { + const { createRequire } = await import('module'); + const require = createRequire(import.meta.url); + const NodeV86 = require("../third-party/libv86.js"); + V86 = NodeV86.V86; + } catch (error) { + console.error('Failed to load V86 in Node.js environment:', error); + } +} + +export { V86 }; diff --git a/incubator/x86emu/www/main.js b/incubator/x86emu/www/main.js index f8257c43cf..ea5129f5b5 100755 --- a/incubator/x86emu/www/main.js +++ b/incubator/x86emu/www/main.js @@ -14,19 +14,19 @@ import('./js/InstanceManager.mjs').then(module => { manager.getInstanceByinstName("Host").then(result => { const hostvm = result.vm; - hostvm.add_listener("emulator-started", function() { + hostvm.add_listener("emulator-started", () => { process.stdout.write("Welcome to psl!"); + hostvm.serial0_send("\n"); }); - hostvm.add_listener("serial0-output-byte", function(byte) { + hostvm.add_listener("serial0-output-byte", (byte) => { var chr = String.fromCharCode(byte); if (chr <= "~") { process.stdout.write(chr); } }); - process.stdin.on("data", function(c) { - // ctrl d + process.stdin.on("data", (c) => { if (c === "\u0004") { hostvm.stop(); process.stdin.pause(); @@ -36,7 +36,7 @@ import('./js/InstanceManager.mjs').then(module => { } }); }).catch(error => { - console.log(error); + console.error(error); throw Error("Error in getting host inastance, quitting"); }); }).catch(error => { From fa841582a9906bb30ad1b18d8a056e86e2c106fd Mon Sep 17 00:00:00 2001 From: lsileoni Date: Thu, 11 Apr 2024 20:54:21 +0300 Subject: [PATCH 0010/2119] Added temporary package.json, so node doens't refer to the repo root package.json --- incubator/x86emu/www/package.json | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 incubator/x86emu/www/package.json diff --git a/incubator/x86emu/www/package.json b/incubator/x86emu/www/package.json new file mode 100644 index 0000000000..1f9153e46d --- /dev/null +++ b/incubator/x86emu/www/package.json @@ -0,0 +1,11 @@ +{ + "name": "x86incubator", + "version": "1.0.0", + "description": "x86emu experimental repo for puter", + "main": "main.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Puter Technologies Inc.", + "license": "AGPL-3.0-only" +} From 2ebda29f02a5d91eeb5ba6cb6901a3e9a9f5c284 Mon Sep 17 00:00:00 2001 From: lsileoni Date: Thu, 11 Apr 2024 21:38:36 +0300 Subject: [PATCH 0011/2119] Don't bind manager to window for now --- incubator/x86emu/www/index.html | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/incubator/x86emu/www/index.html b/incubator/x86emu/www/index.html index 48418f4434..ccc5e2153e 100644 --- a/incubator/x86emu/www/index.html +++ b/incubator/x86emu/www/index.html @@ -10,8 +10,8 @@ import InstanceManager from "./js/InstanceManager.mjs" document.addEventListener("DOMContentLoaded", () => { - window.manager = new InstanceManager({spawnRoot: document.body, term: true}); - window.manager.createInstance({spawnRoot: document.body, term: true}) + const manager = new InstanceManager({spawnRoot: document.body, term: true}); + manager.createInstance({spawnRoot: document.body, term: true}); }); From f1dedf5a74a7a1ecf020f53c91ef6d74a3f833f1 Mon Sep 17 00:00:00 2001 From: lsileoni Date: Thu, 11 Apr 2024 21:39:07 +0300 Subject: [PATCH 0012/2119] Proper order for moving the compressed file into the static directory --- incubator/x86emu/v86starter.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/incubator/x86emu/v86starter.sh b/incubator/x86emu/v86starter.sh index dbbff8fe9e..c8410d3677 100755 --- a/incubator/x86emu/v86starter.sh +++ b/incubator/x86emu/v86starter.sh @@ -39,10 +39,10 @@ build() mkdir -p "$ROOT_DIR/www/third-party" mkdir -p "$ROOT_DIR/www/static" - # Copy necessary files to deployment directory + # Copy/move necessary files to deployment directory + mv "$VM_DIR/v86/images/image.bin" "$ROOT_DIR/www/static/image.bin" cp "$VM_DIR/v86/build/libv86.js" "$ROOT_DIR/www/third-party/libv86.js" cp "$VM_DIR/v86/build/v86.wasm" "$ROOT_DIR/www/third-party/v86.wasm" - cp "$VM_DIR/v86/images/debian-state-base.bin" "$ROOT_DIR/www/static/image.bin" cp -r "$VM_DIR/v86/images/debian-9p-rootfs-flat/" "$ROOT_DIR/www/static/9p-rootfs/" } From d800b12569053e90a4d23684ffa70516cb129a8a Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 9 May 2024 16:18:57 -0400 Subject: [PATCH 0013/2119] refactor(backend): Trigger webserver events in webserver We were triggering webserver events in Kernel. This change improves adherence to separation-of-concerns and ensures event cascading is working as expected. This also better formalizes the boot sequence. --- packages/backend/src/Kernel.js | 17 +++-------------- .../src/services/RefreshAssociationsService.js | 2 +- .../backend/src/services/WebServerService.js | 14 ++++++++++++++ 3 files changed, 18 insertions(+), 15 deletions(-) diff --git a/packages/backend/src/Kernel.js b/packages/backend/src/Kernel.js index 51746f5666..b92ebb9b90 100644 --- a/packages/backend/src/Kernel.js +++ b/packages/backend/src/Kernel.js @@ -152,17 +152,7 @@ class Kernel extends AdvancedBase { const { services } = this; await services.ready; - { - const app = services.get('web-server').app; - app.use(async (req, res, next) => { - req.services = services; - next(); - }); - await services.emit('boot.services-initialized'); - await services.emit('install.middlewares.context-aware', { app }); - await services.emit('install.routes', { app }); - await services.emit('install.routes-gui', { app }); - } + await services.emit('boot.consolidation'); // === END: Initialize Service Registry === @@ -178,9 +168,8 @@ class Kernel extends AdvancedBase { }); })(); - - await services.emit('start.webserver'); - await services.emit('ready.webserver'); + await services.emit('boot.activation'); + await services.emit('boot.ready'); } } diff --git a/packages/backend/src/services/RefreshAssociationsService.js b/packages/backend/src/services/RefreshAssociationsService.js index 94c47ccb1e..5485dcea6f 100644 --- a/packages/backend/src/services/RefreshAssociationsService.js +++ b/packages/backend/src/services/RefreshAssociationsService.js @@ -20,7 +20,7 @@ const { Context } = require("../util/context"); const BaseService = require("./BaseService"); class RefreshAssociationsService extends BaseService { - async ['__on_boot.services-initialized'] () { + async ['__on_boot.consolidation'] () { const { refresh_associations_cache } = require('../helpers'); await Context.allow_fallback(async () => { diff --git a/packages/backend/src/services/WebServerService.js b/packages/backend/src/services/WebServerService.js index 597c3fa732..73d95bb9c4 100644 --- a/packages/backend/src/services/WebServerService.js +++ b/packages/backend/src/services/WebServerService.js @@ -42,6 +42,20 @@ class WebServerService extends BaseService { morgan: require('morgan'), }; + async ['__on_boot.consolidation'] () { + const app = this.app; + const services = this.services; + await services.emit('install.middlewares.context-aware', { app }); + await services.emit('install.routes', { app }); + await services.emit('install.routes-gui', { app }); + } + + async ['__on_boot.activation'] () { + const services = this.services; + await services.emit('start.webserver'); + await services.emit('ready.webserver'); + } + async ['__on_start.webserver'] () { await es_import_promise; From 15dec2111884b553d7f59dd982f2c95a1a04ba52 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 9 May 2024 17:06:40 -0400 Subject: [PATCH 0014/2119] doc(backend): Document the boot sequence Now that the boot sequence is better formalized it may be documented. --- .../backend/doc/contributors/boot-sequence.md | 87 +++++++++++++++++++ 1 file changed, 87 insertions(+) create mode 100644 packages/backend/doc/contributors/boot-sequence.md diff --git a/packages/backend/doc/contributors/boot-sequence.md b/packages/backend/doc/contributors/boot-sequence.md new file mode 100644 index 0000000000..bdc111e1e4 --- /dev/null +++ b/packages/backend/doc/contributors/boot-sequence.md @@ -0,0 +1,87 @@ +# Puter Backend Boot Sequence + +This document describes the boot sequence of Puter's backend. + +**Constriction** + - Data structures are created + +**Initialization** + - Registries are populated + - Services prepare for next phase + +**Consolidation** + - Service event bus receives first event (`boot.consolidation`) + - Services perform coordinated setup behaviors + - Services prepare for next phase + +**Activation** + - Blocking listeners of `boot.consolidation` have resolved + - HTTP servers start listening + +**Ready** + - Services are informed that Puter is providing service + +## Boot Phases + +### Construction + +Services implement a method called `construct` which initializes members +of an instance. Services do not override the class constructor of +**BaseService**. This makes it possible to use the `new` operator without +invoking a service's constructor behavior during debugging. + +The first phase of the boot sequence, "construction", is simply a loop to +call `construct` on all registered services. + +The `_construct` override should not: +- call other services +- emit events + +### Initialization + +At initialization, the `init()` method is called on all services. +The `_init` override can be used to: +- register information with other services, when services don't + need to register this information in a specific sequence. + An example of this is registering commands with CommandService. +- perform setup that is required before the consolidation phase starts. + +### Consolidation + +Consolidation is a phase where services should emit events that +are related to bringing up the system. For example, WebServerService +('web-server') emits an event telling services to install middlewares, +and later emits an event telling services to install routes. + +Consolidation starts when Kernel emits `boot.consolidation` to the +services event bus, which happens after `init()` resolves for all +services. + +### Activation + +Activation is a phase where services begin listening on external +interfaces. For example, this is when the web server starts listening. + +Activation starts when Kernel emits `boot.activation`. + +### Ready + +Ready is a phase where services are informed that everything is up. + +Ready starts when Kernel emits `boot.ready`. + +## Events and Asynchronous Execution + +The services event bus is implemented so you can `await` a call to `.emit()`. +Event listeners can choose to have blocking behavior by returning a promise. + +During emission of a particular event, listeners of this event will not +block each other, but all listeners must resolve before the call to +`.emit()` is resolved. (i.e. `emit` uses `Promise.all`) + +## Legacy Services + +Some services were implemented before the `BaseService` class - which +implements the `init` method - was created. These services are called +"legacy services" and they are instantiated _after_ initialization but +_before_ consolidation. From a89c9d59cf09e14e043ed63dafac5d1a0da20367 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 10 May 2024 18:28:57 -0400 Subject: [PATCH 0015/2119] Add UserProtectedEndpointsService --- packages/backend/src/CoreModule.js | 3 + packages/backend/src/api/APIError.js | 22 +++++ .../routers/user-protected/change-password.js | 7 ++ .../web/UserProtectedEndpointsService.js | 92 +++++++++++++++++++ packages/backend/src/util/expressutil.js | 21 +++++ 5 files changed, 145 insertions(+) create mode 100644 packages/backend/src/routers/user-protected/change-password.js create mode 100644 packages/backend/src/services/web/UserProtectedEndpointsService.js create mode 100644 packages/backend/src/util/expressutil.js diff --git a/packages/backend/src/CoreModule.js b/packages/backend/src/CoreModule.js index 4d1f84e51c..b8f2311269 100644 --- a/packages/backend/src/CoreModule.js +++ b/packages/backend/src/CoreModule.js @@ -204,6 +204,9 @@ const install = async ({ services, app }) => { const { OTPService } = require('./services/auth/OTPService'); services.registerService('otp', OTPService); + + const { UserProtectedEndpointsService } = require("./services/web/UserProtectedEndpointsService"); + services.registerService('__user-protected-endpoints', UserProtectedEndpointsService); } const install_legacy = async ({ services }) => { diff --git a/packages/backend/src/api/APIError.js b/packages/backend/src/api/APIError.js index b7591d9795..0ec6ba9691 100644 --- a/packages/backend/src/api/APIError.js +++ b/packages/backend/src/api/APIError.js @@ -340,6 +340,28 @@ module.exports = class APIError { message: '2FA is already enabled.', }, + // protected endpoints + 'too_many_requests': { + status: 429, + message: 'Too many requests.', + }, + 'user_tokens_only': { + status: 403, + message: 'This endpoint must be requested with a user session', + }, + 'temporary_accounts_not_allowed': { + status: 403, + message: 'Temporary accounts cannot perform this action', + }, + 'password_required': { + status: 400, + message: 'Password is required.', + }, + 'password_mismatch': { + status: 403, + message: 'Password does not match.', + }, + // Object Mapping 'field_not_allowed_for_create': { status: 400, diff --git a/packages/backend/src/routers/user-protected/change-password.js b/packages/backend/src/routers/user-protected/change-password.js new file mode 100644 index 0000000000..9f6980d09b --- /dev/null +++ b/packages/backend/src/routers/user-protected/change-password.js @@ -0,0 +1,7 @@ +module.exports = { + route: '/change-password', + methods: ['POST'], + handler: async (req, res, next) => { + res.send('this is a test response'); + } +}; diff --git a/packages/backend/src/services/web/UserProtectedEndpointsService.js b/packages/backend/src/services/web/UserProtectedEndpointsService.js new file mode 100644 index 0000000000..ae9acd0592 --- /dev/null +++ b/packages/backend/src/services/web/UserProtectedEndpointsService.js @@ -0,0 +1,92 @@ +const { get_user } = require("../../helpers"); +const auth2 = require("../../middleware/auth2"); +const { Context } = require("../../util/context"); +const BaseService = require("../BaseService"); +const { UserActorType } = require("../auth/Actor"); +const { Endpoint } = require("../../util/expressutil"); +const APIError = require("../../api/APIError.js"); + +/** + * This service registers endpoints that are protected by password authentication, + * excluding login. These endpoints are typically for actions that affect + * security settings on the user's account. + */ +class UserProtectedEndpointsService extends BaseService { + static MODULES = { + express: require('express'), + }; + + ['__on_install.routes'] () { + const router = (() => { + const require = this.require; + const express = require('express'); + return express.Router(); + })() + + const { app } = this.services.get('web-server'); + app.use('/user-protected', router); + + // Apply edge (unauthenticated) rate-limiting + router.use((req, res, next) => { + const svc_edgeRateLimit = req.services.get('edge-rate-limit'); + if ( ! svc_edgeRateLimit.check(req.baseUrl + req.path) ) { + return APIError.create('too_many_requests').write(res); + } + next(); + }) + + // Require authenticated session + router.use(auth2); + + // Only allow user sessions, not API tokens for apps + router.use((req, res, next) => { + const actor = Context.get('actor'); + if ( ! (actor.type instanceof UserActorType) ) { + return APIError.create('user_tokens_only').write(res); + } + next(); + }); + + // Prioritize consistency for user object + router.use(async (req, res, next) => { + const user = await get_user({ id: req.user.id, force: true }); + req.user = user; + next(); + }); + + // Do not allow temporary users + router.use(async (req, res, next) => { + if ( req.user.password === null ) { + return APIError.create('temporary_account').write(res); + } + next(); + }); + + // Require password in request + router.use(async (req, res, next) => { + if ( ! req.body.password ) { + return (APIError.create('password_required')).write(res); + } + + const bcrypt = (() => { + const require = this.require; + return require('bcrypt'); + })(); + + const user = await get_user({ id: req.user.id, force: true }); + const isMatch = await bcrypt.compare(req.body.password, user.password); + if ( ! isMatch ) { + return APIError.create('password_mismatch').write(res); + } + next(); + }); + + Endpoint( + require('../../routers/user-protected/change-password.js') + ).attach(router); + } +} + +module.exports = { + UserProtectedEndpointsService +}; diff --git a/packages/backend/src/util/expressutil.js b/packages/backend/src/util/expressutil.js new file mode 100644 index 0000000000..a786370239 --- /dev/null +++ b/packages/backend/src/util/expressutil.js @@ -0,0 +1,21 @@ +const eggspress = require("../api/eggspress"); + +const Endpoint = function Endpoint (spec) { + return { + attach (route) { + const eggspress_options = { + allowedMethods: spec.methods ?? ['GET'], + }; + const eggspress_router = eggspress( + spec.route, + eggspress_options, + spec.handler, + ); + route.use(eggspress_router); + } + }; +} + +module.exports = { + Endpoint, +}; From 9076fddc0d3f15aedb91a72e859745f8baac4eef Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sat, 11 May 2024 02:04:57 -0400 Subject: [PATCH 0016/2119] Add new password change endpoint --- .../routers/user-protected/change-password.js | 80 ++++++++++++++++++- src/UI/UIWindowChangePassword.js | 4 +- 2 files changed, 81 insertions(+), 3 deletions(-) diff --git a/packages/backend/src/routers/user-protected/change-password.js b/packages/backend/src/routers/user-protected/change-password.js index 9f6980d09b..3c1f2a1d9e 100644 --- a/packages/backend/src/routers/user-protected/change-password.js +++ b/packages/backend/src/routers/user-protected/change-password.js @@ -1,7 +1,85 @@ +// TODO: DRY: This is the same function used by UIWindowChangePassword! + +const { invalidate_cached_user } = require("../../helpers"); +const { DB_WRITE } = require("../../services/database/consts"); + +// duplicate definition is in src/helpers.js (puter GUI) +const check_password_strength = (password) => { + // Define criteria for password strength + const criteria = { + minLength: 8, + hasUpperCase: /[A-Z]/.test(password), + hasLowerCase: /[a-z]/.test(password), + hasNumber: /\d/.test(password), + hasSpecialChar: /[!@#$%^&*()_+\-=[\]{};':"\\|,.<>/?]/.test(password) + }; + + let overallPass = true; + + // Initialize report object + let criteria_report = { + minLength: { + message: `Password must be at least ${criteria.minLength} characters long`, + pass: password.length >= criteria.minLength, + }, + hasUpperCase: { + message: 'Password must contain at least one uppercase letter', + pass: criteria.hasUpperCase, + }, + hasLowerCase: { + message: 'Password must contain at least one lowercase letter', + pass: criteria.hasLowerCase, + }, + hasNumber: { + message: 'Password must contain at least one number', + pass: criteria.hasNumber, + }, + hasSpecialChar: { + message: 'Password must contain at least one special character', + pass: criteria.hasSpecialChar, + }, + }; + + // Check overall pass status and add messages + for (let criterion in criteria) { + if (!criteria_report[criterion].pass) { + overallPass = false; + break; + } + } + + return { + overallPass: overallPass, + report: criteria_report, + }; +} + module.exports = { route: '/change-password', methods: ['POST'], handler: async (req, res, next) => { - res.send('this is a test response'); + // Validate new password + const { new_pass } = req.body; + const { overallPass: strong } = check_password_strength(new_pass); + if ( ! strong ) { + req.status(400).send('Password does not meet requirements.'); + } + + // Update user + // TODO: DI for endpoint definitions like this one + const bcrypt = require('bcrypt'); + const db = req.services.get('database').get(DB_WRITE, 'auth'); + await db.write( + 'UPDATE user SET password=?, `pass_recovery_token` = NULL, `change_email_confirm_token` = NULL WHERE `id` = ?', + [await bcrypt.hash(req.body.new_pass, 8), req.user.id] + ); + invalidate_cached_user(req.user); + + // Notify user about password change + // TODO: audit log for user in security tab + const svc_email = req.services.get('email'); + svc_email.send_email({ email: req.user.email }, 'password_change_notification'); + + return res.send('Password successfully updated.') } }; diff --git a/src/UI/UIWindowChangePassword.js b/src/UI/UIWindowChangePassword.js index 9301ed1620..7bce110074 100644 --- a/src/UI/UIWindowChangePassword.js +++ b/src/UI/UIWindowChangePassword.js @@ -114,7 +114,7 @@ async function UIWindowChangePassword(options){ $(el_window).find('.form-error-msg').hide(); $.ajax({ - url: window.api_origin + "/passwd", + url: window.api_origin + "/user-protected/change-password", type: 'POST', async: true, headers: { @@ -122,7 +122,7 @@ async function UIWindowChangePassword(options){ }, contentType: "application/json", data: JSON.stringify({ - old_pass: current_password, + password: current_password, new_pass: new_password, }), success: function (data){ From 1493cacb6962293fecbf3ca51b2f08112c91e725 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sat, 11 May 2024 02:28:18 -0400 Subject: [PATCH 0017/2119] Add rate-limiting to new password change endpoint --- .../src/services/abuse-prevention/EdgeRateLimitService.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/packages/backend/src/services/abuse-prevention/EdgeRateLimitService.js b/packages/backend/src/services/abuse-prevention/EdgeRateLimitService.js index e3214a6301..c5852c3aa9 100644 --- a/packages/backend/src/services/abuse-prevention/EdgeRateLimitService.js +++ b/packages/backend/src/services/abuse-prevention/EdgeRateLimitService.js @@ -1,5 +1,6 @@ const { Context } = require("../../util/context"); const { asyncSafeSetInterval } = require("../../util/promise"); +const { quot } = require("../../util/strutil"); const { MINUTE, HOUR } = require('../../util/time.js'); const BaseService = require("../BaseService"); @@ -55,6 +56,10 @@ class EdgeRateLimitService extends BaseService { limit: 10, window: HOUR, }, + ['/user-protected/change-password']: { + limit: 10, + window: HOUR, + }, ['login-otp']: { limit: 15, window: 30 * MINUTE, @@ -77,6 +82,9 @@ class EdgeRateLimitService extends BaseService { } check (scope) { + if ( ! this.scopes.hasOwnProperty(scope) ) { + throw new Error(`unrecognized rate-limit scope: ${quot(scope)}`) + } const { window, limit } = this.scopes[scope]; const requester = Context.get('requester'); From 23215bd6f7e6a79fd90351387e396e75bf86f64a Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sun, 12 May 2024 22:08:44 -0400 Subject: [PATCH 0018/2119] Move change_email/start to password-protected endpoint --- packages/backend/src/routers/change_email.js | 67 ------------------ .../routers/user-protected/change-email.js | 68 +++++++++++++++++++ .../abuse-prevention/EdgeRateLimitService.js | 10 +++ .../web/UserProtectedEndpointsService.js | 6 +- src/UI/Settings/UIWindowChangeEmail.js | 18 ++++- src/i18n/translations/en.js | 1 + 6 files changed, 101 insertions(+), 69 deletions(-) create mode 100644 packages/backend/src/routers/user-protected/change-email.js diff --git a/packages/backend/src/routers/change_email.js b/packages/backend/src/routers/change_email.js index aa8456ab91..5a6f81edd0 100644 --- a/packages/backend/src/routers/change_email.js +++ b/packages/backend/src/routers/change_email.js @@ -28,72 +28,6 @@ const config = require('../config.js'); const jwt = require('jsonwebtoken'); const { invalidate_cached_user_by_id } = require('../helpers.js'); -const CHANGE_EMAIL_START = eggspress('/change_email/start', { - subdomain: 'api', - auth: true, - verified: true, - allowedMethods: ['POST'], -}, async (req, res, next) => { - const user = req.user; - const new_email = req.body.new_email; - - // TODO: DRY: signup.js - // validation - if( ! new_email ) { - throw APIError.create('field_missing', null, { key: 'new_email' }); - } - if ( typeof new_email !== 'string' ) { - throw APIError.create('field_invalid', null, { - key: 'new_email', expected: 'a valid email address' }); - } - if ( ! validator.isEmail(new_email) ) { - throw APIError.create('field_invalid', null, { - key: 'new_email', expected: 'a valid email address' }); - } - - const svc_edgeRateLimit = req.services.get('edge-rate-limit'); - if ( ! svc_edgeRateLimit.check('change-email-start') ) { - return res.status(429).send('Too many requests.'); - } - - // check if email is already in use - const db = req.services.get('database').get(DB_WRITE, 'auth'); - const rows = await db.read( - 'SELECT COUNT(*) AS `count` FROM `user` WHERE `email` = ?', - [new_email] - ); - if ( rows[0].count > 0 ) { - throw APIError.create('email_already_in_use', null, { email: new_email }); - } - - // generate confirmation token - const token = crypto.randomBytes(4).toString('hex'); - const jwt_token = jwt.sign({ - user_id: user.id, - token, - }, config.jwt_secret, { expiresIn: '24h' }); - - // send confirmation email - const svc_email = req.services.get('email'); - await svc_email.send_email({ email: new_email }, 'email_change_request', { - confirm_url: `${config.origin}/change_email/confirm?token=${jwt_token}`, - username: user.username, - }); - const old_email = user.email; - // TODO: NotificationService - await svc_email.send_email({ email: old_email }, 'email_change_notification', { - new_email: new_email, - }); - - // update user - await db.write( - 'UPDATE `user` SET `unconfirmed_change_email` = ?, `change_email_confirm_token` = ? WHERE `id` = ?', - [new_email, token, user.id] - ); - - res.send({ success: true }); -}); - const CHANGE_EMAIL_CONFIRM = eggspress('/change_email/confirm', { allowedMethods: ['GET'], }, async (req, res, next) => { @@ -137,6 +71,5 @@ const CHANGE_EMAIL_CONFIRM = eggspress('/change_email/confirm', { }); module.exports = app => { - app.use(CHANGE_EMAIL_START); app.use(CHANGE_EMAIL_CONFIRM); } diff --git a/packages/backend/src/routers/user-protected/change-email.js b/packages/backend/src/routers/user-protected/change-email.js new file mode 100644 index 0000000000..c4195712c7 --- /dev/null +++ b/packages/backend/src/routers/user-protected/change-email.js @@ -0,0 +1,68 @@ +const APIError = require("../../api/APIError"); +const { DB_WRITE } = require("../../services/database/consts"); +const jwt = require('jsonwebtoken'); +const validator = require('validator'); +const crypto = require('crypto'); +const config = require("../../config"); + +module.exports = { + route: '/change-email', + methods: ['POST'], + handler: async (req, res, next) => { + const user = req.user; + const new_email = req.body.new_email; + + console.log('DID REACH HERE'); + + // TODO: DRY: signup.js + // validation + if( ! new_email ) { + throw APIError.create('field_missing', null, { key: 'new_email' }); + } + if ( typeof new_email !== 'string' ) { + throw APIError.create('field_invalid', null, { + key: 'new_email', expected: 'a valid email address' }); + } + if ( ! validator.isEmail(new_email) ) { + throw APIError.create('field_invalid', null, { + key: 'new_email', expected: 'a valid email address' }); + } + + // check if email is already in use + const db = req.services.get('database').get(DB_WRITE, 'auth'); + const rows = await db.read( + 'SELECT COUNT(*) AS `count` FROM `user` WHERE `email` = ?', + [new_email] + ); + if ( rows[0].count > 0 ) { + throw APIError.create('email_already_in_use', null, { email: new_email }); + } + + // generate confirmation token + const token = crypto.randomBytes(4).toString('hex'); + const jwt_token = jwt.sign({ + user_id: user.id, + token, + }, config.jwt_secret, { expiresIn: '24h' }); + + // send confirmation email + const svc_email = req.services.get('email'); + await svc_email.send_email({ email: new_email }, 'email_change_request', { + confirm_url: `${config.origin}/change_email/confirm?token=${jwt_token}`, + username: user.username, + }); + const old_email = user.email; + // TODO: NotificationService + await svc_email.send_email({ email: old_email }, 'email_change_notification', { + new_email: new_email, + }); + + // update user + await db.write( + 'UPDATE `user` SET `unconfirmed_change_email` = ?, `change_email_confirm_token` = ? WHERE `id` = ?', + [new_email, token, user.id] + ); + + res.send({ success: true }); + } +}; diff --git a/packages/backend/src/services/abuse-prevention/EdgeRateLimitService.js b/packages/backend/src/services/abuse-prevention/EdgeRateLimitService.js index c5852c3aa9..7efe8f7780 100644 --- a/packages/backend/src/services/abuse-prevention/EdgeRateLimitService.js +++ b/packages/backend/src/services/abuse-prevention/EdgeRateLimitService.js @@ -5,6 +5,12 @@ const { quot } = require("../../util/strutil"); const { MINUTE, HOUR } = require('../../util/time.js'); const BaseService = require("../BaseService"); +/* INCREMENTAL CHANGES + The first scopes are of the form 'name-of-endpoint', but later it was + decided that they're of the form `/path/to/endpoint`. New scopes should + follow the latter form. +*/ + class EdgeRateLimitService extends BaseService { _construct () { this.scopes = { @@ -60,6 +66,10 @@ class EdgeRateLimitService extends BaseService { limit: 10, window: HOUR, }, + ['/user-protected/change-email']: { + limit: 10, + window: HOUR, + }, ['login-otp']: { limit: 15, window: 30 * MINUTE, diff --git a/packages/backend/src/services/web/UserProtectedEndpointsService.js b/packages/backend/src/services/web/UserProtectedEndpointsService.js index ae9acd0592..d9413b775f 100644 --- a/packages/backend/src/services/web/UserProtectedEndpointsService.js +++ b/packages/backend/src/services/web/UserProtectedEndpointsService.js @@ -82,7 +82,11 @@ class UserProtectedEndpointsService extends BaseService { }); Endpoint( - require('../../routers/user-protected/change-password.js') + require('../../routers/user-protected/change-password.js'), + ).attach(router); + + Endpoint( + require('../../routers/user-protected/change-email.js'), ).attach(router); } } diff --git a/src/UI/Settings/UIWindowChangeEmail.js b/src/UI/Settings/UIWindowChangeEmail.js index 1b28c0aeee..787bcc893b 100644 --- a/src/UI/Settings/UIWindowChangeEmail.js +++ b/src/UI/Settings/UIWindowChangeEmail.js @@ -17,11 +17,18 @@ * along with this program. If not, see . */ +import Placeholder from '../../util/Placeholder.js'; +import PasswordEntry from '../Components/PasswordEntry.js'; import UIWindow from '../UIWindow.js' +// TODO: DRY: We could specify a validator and endpoint instead of writing +// a DOM tree and event handlers for each of these. (low priority) async function UIWindowChangeEmail(options){ options = options ?? {}; + const password_entry = new PasswordEntry({}); + const place_password_entry = Placeholder(); + const internal_id = window.uuidv4(); let h = ''; h += `
`; @@ -34,6 +41,11 @@ async function UIWindowChangeEmail(options){ h += ``; h += ``; h += `
`; + // password confirmation + h += `
`; + h += ``; + h += `${place_password_entry.html}`; + h += `
`; // Change Email h += ``; @@ -73,11 +85,14 @@ async function UIWindowChangeEmail(options){ ...options.window_options }) + password_entry.attach(place_password_entry); + $(el_window).find('.change-email-btn').on('click', function(e){ // hide previous error/success msg $(el_window).find('.form-success-msg, .form-success-msg').hide(); const new_email = $(el_window).find('.new-email').val(); + const password = $(el_window).find('.password').val(); if(!new_email){ $(el_window).find('.form-error-msg').html(i18n('all_fields_required')); @@ -93,7 +108,7 @@ async function UIWindowChangeEmail(options){ $(el_window).find('.new-email').attr('disabled', true); $.ajax({ - url: window.api_origin + "/change_email/start", + url: window.api_origin + "/user-protected/change-email", type: 'POST', async: true, headers: { @@ -102,6 +117,7 @@ async function UIWindowChangeEmail(options){ contentType: "application/json", data: JSON.stringify({ new_email: new_email, + password: password_entry.get('value'), }), success: function (data){ $(el_window).find('.form-success-msg').html(i18n('email_change_confirmation_sent')); diff --git a/src/i18n/translations/en.js b/src/i18n/translations/en.js index dfb507a719..3ec4eb6729 100644 --- a/src/i18n/translations/en.js +++ b/src/i18n/translations/en.js @@ -23,6 +23,7 @@ const en = { dictionary: { about: "About", account: "Account", + account_password: "Verify Account Password", access_granted_to: "Access Granted To", add_existing_account: "Add Existing Account", all_fields_required: 'All fields are required.', From c2f1694107e52ebb3171bece58b942fe4331600d Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 13 May 2024 01:04:46 -0400 Subject: [PATCH 0019/2119] Require password entry to disable 2FA --- .../backend/src/routers/auth/configure-2fa.js | 16 --- .../src/routers/user-protected/disable-2fa.js | 22 +++ .../abuse-prevention/EdgeRateLimitService.js | 4 + .../web/UserProtectedEndpointsService.js | 4 + src/UI/Components/PasswordEntry.js | 136 ++++++++++++++++++ src/UI/Settings/UITabSecurity.js | 111 ++++++++++---- src/i18n/translations/en.js | 1 + 7 files changed, 252 insertions(+), 42 deletions(-) create mode 100644 packages/backend/src/routers/user-protected/disable-2fa.js create mode 100644 src/UI/Components/PasswordEntry.js diff --git a/packages/backend/src/routers/auth/configure-2fa.js b/packages/backend/src/routers/auth/configure-2fa.js index bb50379c7c..eda6bb7560 100644 --- a/packages/backend/src/routers/auth/configure-2fa.js +++ b/packages/backend/src/routers/auth/configure-2fa.js @@ -107,22 +107,6 @@ module.exports = eggspress('/auth/configure-2fa/:action', { return {}; }; - actions.disable = async () => { - await db.write( - `UPDATE user SET otp_enabled = 0, otp_recovery_codes = '' WHERE uuid = ?`, - [user.uuid] - ); - // update cached user - req.user.otp_enabled = 0; - - const svc_email = req.services.get('email'); - await svc_email.send_email({ email: user.email }, 'disabled_2fa', { - username: user.username, - }); - - return { success: true }; - }; - if ( ! actions[action] ) { throw APIError.create('invalid_action', null, { action }); } diff --git a/packages/backend/src/routers/user-protected/disable-2fa.js b/packages/backend/src/routers/user-protected/disable-2fa.js new file mode 100644 index 0000000000..5ada045137 --- /dev/null +++ b/packages/backend/src/routers/user-protected/disable-2fa.js @@ -0,0 +1,22 @@ +const { DB_WRITE } = require("../../services/database/consts"); + +module.exports = { + route: '/disable-2fa', + methods: ['POST'], + handler: async (req, res, next) => { + const db = req.services.get('database').get(DB_WRITE, '2fa.disable'); + await db.write( + `UPDATE user SET otp_enabled = 0, otp_recovery_codes = NULL, otp_secret = NULL WHERE uuid = ?`, + [req.user.uuid] + ); + // update cached user + req.user.otp_enabled = 0; + + const svc_email = req.services.get('email'); + await svc_email.send_email({ email: req.user.email }, 'disabled_2fa', { + username: req.user.username, + }); + + res.send({ success: true }); + } +}; diff --git a/packages/backend/src/services/abuse-prevention/EdgeRateLimitService.js b/packages/backend/src/services/abuse-prevention/EdgeRateLimitService.js index 7efe8f7780..01b8abe6f1 100644 --- a/packages/backend/src/services/abuse-prevention/EdgeRateLimitService.js +++ b/packages/backend/src/services/abuse-prevention/EdgeRateLimitService.js @@ -70,6 +70,10 @@ class EdgeRateLimitService extends BaseService { limit: 10, window: HOUR, }, + ['/user-protected/disable-2fa']: { + limit: 10, + window: HOUR, + }, ['login-otp']: { limit: 15, window: 30 * MINUTE, diff --git a/packages/backend/src/services/web/UserProtectedEndpointsService.js b/packages/backend/src/services/web/UserProtectedEndpointsService.js index d9413b775f..73c401227c 100644 --- a/packages/backend/src/services/web/UserProtectedEndpointsService.js +++ b/packages/backend/src/services/web/UserProtectedEndpointsService.js @@ -88,6 +88,10 @@ class UserProtectedEndpointsService extends BaseService { Endpoint( require('../../routers/user-protected/change-email.js'), ).attach(router); + + Endpoint( + require('../../routers/user-protected/disable-2fa.js'), + ).attach(router); } } diff --git a/src/UI/Components/PasswordEntry.js b/src/UI/Components/PasswordEntry.js new file mode 100644 index 0000000000..cbacdffea4 --- /dev/null +++ b/src/UI/Components/PasswordEntry.js @@ -0,0 +1,136 @@ +import { Component, defineComponent } from "../../util/Component.js"; + +export default class PasswordEntry extends Component { + static PROPERTIES = { + spec: {}, + value: {}, + error: {}, + on_submit: {}, + show_password: {}, + } + + static CSS = /*css*/` + fieldset { + display: flex; + flex-direction: column; + } + input { + flex-grow: 1; + } + + /* TODO: I'd rather not duplicate this */ + .error { + display: none; + color: red; + border: 1px solid red; + border-radius: 4px; + padding: 9px; + margin-bottom: 15px; + text-align: center; + font-size: 13px; + } + .error-message { + display: none; + color: rgb(215 2 2); + font-size: 14px; + margin-top: 10px; + margin-bottom: 10px; + padding: 10px; + border-radius: 4px; + border: 1px solid rgb(215 2 2); + text-align: center; + } + .password-and-toggle { + display: flex; + align-items: center; + gap: 10px; + } + .password-and-toggle input { + flex-grow: 1; + } + + + /* TODO: DRY: This is from style.css */ + input[type=text], input[type=password], input[type=email], select { + width: 100%; + padding: 8px; + border: 1px solid #ccc; + border-radius: 4px; + box-sizing: border-box; + outline: none; + -webkit-font-smoothing: antialiased; + color: #393f46; + font-size: 14px; + } + + /* to prevent auto-zoom on input focus in mobile */ + .device-phone input[type=text], .device-phone input[type=password], .device-phone input[type=email], .device-phone select { + font-size: 17px; + } + + input[type=text]:focus, input[type=password]:focus, input[type=email]:focus, select:focus { + border: 2px solid #01a0fd; + padding: 7px; + } + `; + + create_template ({ template }) { + $(template).html(/*html*/` +
+
+
+ + +
+
+ `); + } + + on_focus () { + $(this.dom_).find('input').focus(); + } + + on_ready ({ listen }) { + listen('error', (error) => { + if ( ! error ) return $(this.dom_).find('.error').hide(); + $(this.dom_).find('.error').text(error).show(); + }); + + listen('value', (value) => { + // clear input + if ( value === undefined ) { + $(this.dom_).find('input').val(''); + } + }); + + const input = $(this.dom_).find('input'); + input.on('input', () => { + this.set('value', input.val()); + }); + + const on_submit = this.get('on_submit'); + if ( on_submit ) { + $(this.dom_).find('input').on('keyup', (e) => { + if ( e.key === 'Enter' ) { + on_submit(); + } + }); + } + + $(this.dom_).find("#toggle-show-password").on("click", () => { + this.set('show_password', !this.get('show_password')); + const show_password = this.get('show_password'); + // hide/show password and update icon + $(this.dom_).find("input").attr("type", show_password ? "text" : "password"); + $(this.dom_).find("#toggle-show-password").attr("src", show_password ? window.icons["eye-closed.svg"] : window.icons["eye-open.svg"]) + }); + } +} + +defineComponent('c-password-entry', PasswordEntry); diff --git a/src/UI/Settings/UITabSecurity.js b/src/UI/Settings/UITabSecurity.js index 7514b9ce7e..5d6564ad62 100644 --- a/src/UI/Settings/UITabSecurity.js +++ b/src/UI/Settings/UITabSecurity.js @@ -1,4 +1,10 @@ +import TeePromise from "../../util/TeePromise.js"; +import Button from "../Components/Button.js"; +import Flexer from "../Components/Flexer.js"; +import JustHTML from "../Components/JustHTML.js"; +import PasswordEntry from "../Components/PasswordEntry.js"; import UIAlert from "../UIAlert.js"; +import UIComponentWindow from "../UIComponentWindow.js"; import UIWindow2FASetup from "../UIWindow2FASetup.js"; import UIWindowQR from "../UIWindowQR.js"; @@ -64,35 +70,88 @@ export default { }); $el_window.find('.disable-2fa').on('click', async function (e) { - const confirmation = i18n('disable_2fa_confirm'); - const alert_resp = await UIAlert({ - message: confirmation, - window_options: { - parent_uuid: $el_window.attr('data-element_uuid'), - disable_parent_window: true, - parent_center: true, - }, - buttons:[ - { - label: i18n('yes'), - value: true, - type: 'primary', - }, - { - label: i18n('cancel'), - value: false, + let win, password_entry; + const password_confirm_promise = new TeePromise(); + const try_password = async () => { + const value = password_entry.get('value'); + const resp = await fetch(`${window.api_origin}/user-protected/disable-2fa`, { + method: 'POST', + headers: { + Authorization: `Bearer ${puter.authToken}`, + 'Content-Type': 'application/json', }, + body: JSON.stringify({ + password: value, + }), + }); + if ( resp.status !== 200 ) { + /* eslint no-empty: ["error", { "allowEmptyCatch": true }] */ + let message; try { + message = (await resp.json()).message; + } catch (e) {} + message = message || i18n('error_unknown_cause'); + password_entry.set('error', message); + return; + } + password_confirm_promise.resolve(true); + $(win).close(); + } + const password_confirm = new Flexer({ + children: [ + new JustHTML({ + html: /*html*/` +

${ + i18n('disable_2fa_confirm') + }

+

${ + i18n('disable_2fa_instructions') + }

+ ` + }), + new Flexer({ + gap: '5pt', + children: [ + new PasswordEntry({ + _ref: me => password_entry = me, + on_submit: async () => { + try_password(); + } + }), + new Button({ + label: i18n('disable_2fa'), + on_click: async () => { + try_password(); + } + }), + new Button({ + label: i18n('cancel'), + style: 'secondary', + on_click: async () => { + password_confirm_promise.resolve(false); + $(win).close(); + } + }) + ] + }), ] - }) - if ( ! alert_resp ) return; - const resp = await fetch(`${window.api_origin}/auth/configure-2fa/disable`, { - method: 'POST', - headers: { - Authorization: `Bearer ${puter.authToken}`, - 'Content-Type': 'application/json', + }); + win = await UIComponentWindow({ + component: password_confirm, + width: 500, + backdrop: true, + is_resizable: false, + body_css: { + width: 'initial', + height: '100%', + 'background-color': 'rgb(245 247 249)', + 'backdrop-filter': 'blur(3px)', + padding: '20px', }, - body: JSON.stringify({}), }); + password_entry.focus(); + + const ok = await password_confirm_promise; + if ( ! ok ) return; $el_window.find('.enable-2fa').show(); $el_window.find('.disable-2fa').hide(); @@ -101,4 +160,4 @@ export default { $el_window.find('.settings-card-security').addClass('settings-card-warning'); }); } -} \ No newline at end of file +} diff --git a/src/i18n/translations/en.js b/src/i18n/translations/en.js index 3ec4eb6729..18ee54324c 100644 --- a/src/i18n/translations/en.js +++ b/src/i18n/translations/en.js @@ -97,6 +97,7 @@ const en = { dir_published_as_website: `%strong% has been published to:`, disable_2fa: 'Disable 2FA', disable_2fa_confirm: "Are you sure you want to disable 2FA?", + disable_2fa_instructions: "Enter your password to disable 2FA.", disassociate_dir: "Disassociate Directory", download: 'Download', download_file: 'Download File', From afb9d866b5091058711db931cde904947e661c15 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 13 May 2024 18:17:39 -0400 Subject: [PATCH 0020/2119] fix: Fix phoenix app prefix and TokenService test --- packages/backend/src/services/auth/TokenService.js | 14 +++++++------- .../database/SqliteDatabaseAccessService.js | 7 ++++++- .../database/sqlite_setup/0009_app-prefix-fix.sql | 1 + 3 files changed, 14 insertions(+), 8 deletions(-) create mode 100644 packages/backend/src/services/database/sqlite_setup/0009_app-prefix-fix.sql diff --git a/packages/backend/src/services/auth/TokenService.js b/packages/backend/src/services/auth/TokenService.js index 1715a8bc93..041e06cab1 100644 --- a/packages/backend/src/services/auth/TokenService.js +++ b/packages/backend/src/services/auth/TokenService.js @@ -186,7 +186,7 @@ class TokenService extends BaseService { _test ({ assert }) { const U1 = '843f1d83-3c30-48c7-8964-62aff1a912d0'; const U2 = '42e9c36b-8a53-4c3e-8e18-fe549b10a44d'; - const U3 = 'c22ef816-edb6-47c5-8c41-31c6520fa9e6'; + const U3 = 'app-c22ef816-edb6-47c5-8c41-31c6520fa9e6'; // Test compression { const context = this.compression.auth; @@ -198,20 +198,20 @@ class TokenService extends BaseService { }; const compressed = this._compress_payload(context, payload); - assert(() => compressed.u === uuid_compression.encode(U1)); + assert(() => compressed.u === uuid_compression().encode(U1)); assert(() => compressed.t === 's'); - assert(() => compressed.uu === uuid_compression.encode(U2)); - assert(() => compressed.au === uuid_compression.encode(U3)); + assert(() => compressed.uu === uuid_compression().encode(U2)); + assert(() => compressed.au === uuid_compression('app-').encode(U3)); } // Test decompression { const context = this.compression.auth; const payload = { - u: uuid_compression.encode(U1), + u: uuid_compression().encode(U1), t: 's', - uu: uuid_compression.encode(U2), - au: uuid_compression.encode(U3), + uu: uuid_compression().encode(U2), + au: uuid_compression('app-').encode(U3), }; const decompressed = this._decompress_payload(context, payload); diff --git a/packages/backend/src/services/database/SqliteDatabaseAccessService.js b/packages/backend/src/services/database/SqliteDatabaseAccessService.js index d38ddf6647..fcf98d31d5 100644 --- a/packages/backend/src/services/database/SqliteDatabaseAccessService.js +++ b/packages/backend/src/services/database/SqliteDatabaseAccessService.js @@ -42,7 +42,7 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { this.db = new Database(this.config.path); // Database upgrade logic - const TARGET_VERSION = 6; + const TARGET_VERSION = 7; if ( do_setup ) { this.log.noticeme(`SETUP: creating database at ${this.config.path}`); @@ -55,6 +55,7 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { '0006_update-apps.sql', '0007_sessions.sql', '0008_otp.sql', + '0009_app-prefix-fix', ].map(p => path_.join(__dirname, 'sqlite_setup', p)); const fs = require('fs'); for ( const filename of sql_files ) { @@ -95,6 +96,10 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { upgrade_files.push('0008_otp.sql'); } + if ( user_version <= 6 ) { + upgrade_files.push('0009_app-prefix-fix.sql'); + } + if ( upgrade_files.length > 0 ) { this.log.noticeme(`Database out of date: ${this.config.path}`); this.log.noticeme(`UPGRADING DATABASE: ${user_version} -> ${TARGET_VERSION}`); diff --git a/packages/backend/src/services/database/sqlite_setup/0009_app-prefix-fix.sql b/packages/backend/src/services/database/sqlite_setup/0009_app-prefix-fix.sql new file mode 100644 index 0000000000..eb1a181216 --- /dev/null +++ b/packages/backend/src/services/database/sqlite_setup/0009_app-prefix-fix.sql @@ -0,0 +1 @@ +UPDATE `apps` SET `uid` = 'app-129e4bfb-4c8a-47e0-bec2-0279c21ace06' WHERE `name` = 'phoenix'; From da7f73baa693dc13b5fe5ec57f91b7f24329c7f8 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 13 May 2024 19:08:51 -0400 Subject: [PATCH 0021/2119] Add AntiCSRFService --- packages/backend/src/CoreModule.js | 3 + .../src/services/auth/AntiCSRFService.js | 118 ++++++++++++++++++ 2 files changed, 121 insertions(+) create mode 100644 packages/backend/src/services/auth/AntiCSRFService.js diff --git a/packages/backend/src/CoreModule.js b/packages/backend/src/CoreModule.js index b8f2311269..be2b392a80 100644 --- a/packages/backend/src/CoreModule.js +++ b/packages/backend/src/CoreModule.js @@ -207,6 +207,9 @@ const install = async ({ services, app }) => { const { UserProtectedEndpointsService } = require("./services/web/UserProtectedEndpointsService"); services.registerService('__user-protected-endpoints', UserProtectedEndpointsService); + + const { AntiCSRFService } = require('./services/auth/AntiCSRFService'); + services.registerService('anti-csrf', AntiCSRFService); } const install_legacy = async ({ services }) => { diff --git a/packages/backend/src/services/auth/AntiCSRFService.js b/packages/backend/src/services/auth/AntiCSRFService.js new file mode 100644 index 0000000000..412f335363 --- /dev/null +++ b/packages/backend/src/services/auth/AntiCSRFService.js @@ -0,0 +1,118 @@ +const eggspress = require("../../api/eggspress"); +const config = require("../../config"); +const { subdomain } = require("../../helpers"); +const BaseService = require("../BaseService"); + +class CircularQueue { + constructor (size) { + this.size = size; + this.queue = []; + this.index = 0; + this.map = new Map(); + } + + push (item) { + if ( this.queue[this.index] ) { + this.map.delete(this.queue[this.index]); + } + this.queue[this.index] = item; + this.map.set(item, this.index); + this.index = (this.index + 1) % this.size; + } + + get (index) { + return this.queue[(this.index + index) % this.size]; + } + + has (item) { + return this.map.has(item); + } + + maybe_consume (item) { + if ( this.has(item) ) { + const index = this.map.get(item); + this.map.delete(item); + this.queue[index] = null; + return true; + } + return false; + } +} + +class AntiCSRFService extends BaseService { + _construct () { + this.map_session_to_tokens = {}; + } + + ['__on_install.routes'] () { + const { app } = this.services.get('web-server'); + + app.use(eggspress('/get-anticsrf-token', { + auth2: true, + allowedMethods: ['GET'], + }, async (req, res) => { + // We disallow `api.` because it has a more relaxed CORS policy + const subdomain_check = config.experimental_no_subdomain || + (subdomain(req) !== 'api'); + if ( ! subdomain_check ) { + return res.status(404).send('Hey, stop that!'); + } + + // TODO: session uuid instead of user + const token = this.create_token(req.user.uuid); + res.send({ token }); + })); + } + + create_token (session) { + let tokens = this.map_session_to_tokens[session]; + if ( ! tokens ) { + tokens = new CircularQueue(10); + this.map_session_to_tokens[session] = tokens; + } + const token = this.generate_token_(); + tokens.push(token); + return token; + } + + consume_token (session, token) { + const tokens = this.map_session_to_tokens[session]; + if ( ! tokens ) return false; + return tokens.maybe_consume(token); + } + + generate_token_ () { + return require('crypto').randomBytes(32).toString('hex'); + } + + _test ({ assert }) { + // Do this several times, like a user would + for ( let i=0 ; i < 30 ; i++ ) { + // Generate 30 tokens + const tokens = []; + for ( let j=0 ; j < 30 ; j++ ) { + tokens.push(this.create_token('session')); + } + // Only the last 10 should be valid + const results_for_stale_tokens = []; + for ( let j=0 ; j < 20 ; j++ ) { + const result = this.consume_token('session', tokens[j]); + results_for_stale_tokens.push(result); + } + assert(() => results_for_stale_tokens.every(v => v === false)); + // The last 10 should be valid + const results_for_valid_tokens = []; + for ( let j=20 ; j < 30 ; j++ ) { + const result = this.consume_token('session', tokens[j]); + results_for_valid_tokens.push(result); + } + assert(() => results_for_valid_tokens.every(v => v === true)); + // A completely arbitrary token should not be valid + assert(() => this.consume_token('session', 'arbitrary') === false); + } + } +} + +module.exports = { + AntiCSRFService, +}; From 800aef1942f7fc948fa2064bae29ae62b8eacdb8 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 13 May 2024 20:40:27 -0400 Subject: [PATCH 0022/2119] Implement anti-CSRF for logout --- packages/backend/src/routers/logout.js | 5 +++++ src/initgui.js | 3 +++ 2 files changed, 8 insertions(+) diff --git a/packages/backend/src/routers/logout.js b/packages/backend/src/routers/logout.js index 771c9ad7ca..caadfbe90d 100644 --- a/packages/backend/src/routers/logout.js +++ b/packages/backend/src/routers/logout.js @@ -29,6 +29,11 @@ router.post('/logout', auth, express.json(), async (req, res, next)=>{ // check subdomain if(require('../helpers').subdomain(req) !== 'api' && require('../helpers').subdomain(req) !== '') next(); + // check anti-csrf token + const svc_antiCSRF = req.services.get('anti-csrf'); + if ( ! svc_antiCSRF.consume_token(req.user.uuid, req.body.anti_csrf) ) { + return res.status(400).json({ message: 'incorrect anti-CSRF token' }); + } // delete cookie res.clearCookie(config.cookie_name); // delete session diff --git a/src/initgui.js b/src/initgui.js index c45a427f55..1cfcd517e2 100644 --- a/src/initgui.js +++ b/src/initgui.js @@ -1981,6 +1981,8 @@ window.initgui = async function(){ // logout try{ + const resp = await fetch(`${window.gui_origin}/get-anticsrf-token`); + const { token } = await resp.json(); await $.ajax({ url: window.gui_origin + "/logout", type: 'POST', @@ -1989,6 +1991,7 @@ window.initgui = async function(){ headers: { "Authorization": "Bearer " + window.auth_token }, + data: JSON.stringify({ anti_csrf: token }), statusCode: { 401: function () { }, From fafbc292ca9a69dfabbeba86c485d37251dedc6c Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Mon, 13 May 2024 17:47:03 +0100 Subject: [PATCH 0023/2119] Remove xterm dependency from Phoenix This is used by Terminal, not Phoenix. --- packages/phoenix/package-lock.json | 17 +---------------- packages/phoenix/package.json | 4 +--- 2 files changed, 2 insertions(+), 19 deletions(-) diff --git a/packages/phoenix/package-lock.json b/packages/phoenix/package-lock.json index c9a9c9021c..29250347cf 100644 --- a/packages/phoenix/package-lock.json +++ b/packages/phoenix/package-lock.json @@ -22,9 +22,7 @@ "fs-mode-to-string": "^0.0.2", "json-query": "^2.2.2", "path-browserify": "^1.0.1", - "sinon": "^17.0.1", - "xterm": "^5.1.0", - "xterm-addon-fit": "^0.7.0" + "sinon": "^17.0.1" }, "devDependencies": { "@rollup/plugin-commonjs": "^24.1.0", @@ -1796,19 +1794,6 @@ "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "dev": true }, - "node_modules/xterm": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/xterm/-/xterm-5.1.0.tgz", - "integrity": "sha512-LovENH4WDzpwynj+OTkLyZgJPeDom9Gra4DMlGAgz6pZhIDCQ+YuO7yfwanY+gVbn/mmZIStNOnVRU/ikQuAEQ==" - }, - "node_modules/xterm-addon-fit": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/xterm-addon-fit/-/xterm-addon-fit-0.7.0.tgz", - "integrity": "sha512-tQgHGoHqRTgeROPnvmtEJywLKoC/V9eNs4bLLz7iyJr1aW/QFzRwfd3MGiJ6odJd9xEfxcW36/xRU47JkD5NKQ==", - "peerDependencies": { - "xterm": "^5.0.0" - } - }, "node_modules/y18n": { "version": "5.0.8", "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", diff --git a/packages/phoenix/package.json b/packages/phoenix/package.json index 1be9acc962..22191b1473 100644 --- a/packages/phoenix/package.json +++ b/packages/phoenix/package.json @@ -26,9 +26,7 @@ "fs-mode-to-string": "^0.0.2", "json-query": "^2.2.2", "path-browserify": "^1.0.1", - "sinon": "^17.0.1", - "xterm": "^5.1.0", - "xterm-addon-fit": "^0.7.0" + "sinon": "^17.0.1" }, "optionalDependencies": { "node-pty": "^1.0.0" From 2656b47640cbb993b15ff2e99219bd7abab3e3a2 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Tue, 14 May 2024 13:46:43 +0100 Subject: [PATCH 0024/2119] chore: Update xterm From version 5.4.0 onwards, xterm scopes its package names as `@xterm/foo` instead of just `xterm-foo`. We currently have a copy of xterm.css which we use instead of directly including the one from the `@xterm/xterm` package, so I've updated the contents of that too. --- package-lock.json | 43 +++++++++++------------------- packages/terminal/assets/xterm.css | 17 +++++++++--- packages/terminal/package.json | 4 +-- packages/terminal/src/main.js | 4 +-- 4 files changed, 33 insertions(+), 35 deletions(-) diff --git a/package-lock.json b/package-lock.json index 5f13df7289..6f6c696e09 100644 --- a/package-lock.json +++ b/package-lock.json @@ -4071,6 +4071,19 @@ } } }, + "node_modules/@xterm/addon-fit": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@xterm/addon-fit/-/addon-fit-0.10.0.tgz", + "integrity": "sha512-UFYkDm4HUahf2lnEyHvio51TNGiLK66mqP2JoATy7hRZeXaGMRDr00JiSF7m63vR5WKATF605yEggJKsw0JpMQ==", + "peerDependencies": { + "@xterm/xterm": "^5.0.0" + } + }, + "node_modules/@xterm/xterm": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/@xterm/xterm/-/xterm-5.5.0.tgz", + "integrity": "sha512-hqJHYaQb5OptNunnyAnkHyM8aCjZ1MEIDTQu1iIbbTD/xops91NB5yq1ZK/dC2JDbVWtF23zUtl9JE2NqwT87A==" + }, "node_modules/@xtuc/ieee754": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", @@ -11561,9 +11574,7 @@ "fs-mode-to-string": "^0.0.2", "json-query": "^2.2.2", "path-browserify": "^1.0.1", - "sinon": "^17.0.1", - "xterm": "^5.1.0", - "xterm-addon-fit": "^0.7.0" + "sinon": "^17.0.1" }, "devDependencies": { "@rollup/plugin-commonjs": "^24.1.0", @@ -12131,17 +12142,6 @@ "defaults": "^1.0.3" } }, - "packages/phoenix/node_modules/xterm": { - "version": "5.1.0", - "license": "MIT" - }, - "packages/phoenix/node_modules/xterm-addon-fit": { - "version": "0.7.0", - "license": "MIT", - "peerDependencies": { - "xterm": "^5.0.0" - } - }, "packages/phoenix/packages/contextlink": { "version": "0.0.0", "extraneous": true, @@ -12180,8 +12180,8 @@ "version": "0.0.0", "license": "AGPL-3.0-only", "dependencies": { - "xterm": "^5.3.0", - "xterm-addon-fit": "^0.7.0" + "@xterm/addon-fit": "^0.10.0", + "@xterm/xterm": "^5.5.0" }, "devDependencies": { "@rollup/plugin-commonjs": "^24.1.0", @@ -12723,17 +12723,6 @@ "engines": { "node": ">=12" } - }, - "packages/terminal/node_modules/xterm": { - "version": "5.3.0", - "license": "MIT" - }, - "packages/terminal/node_modules/xterm-addon-fit": { - "version": "0.7.0", - "license": "MIT", - "peerDependencies": { - "xterm": "^5.0.0" - } } } } diff --git a/packages/terminal/assets/xterm.css b/packages/terminal/assets/xterm.css index 74acc26708..49a21fea9d 100644 --- a/packages/terminal/assets/xterm.css +++ b/packages/terminal/assets/xterm.css @@ -140,7 +140,7 @@ cursor: crosshair; } -.xterm .xterm-accessibility, +.xterm .xterm-accessibility:not(.debug), .xterm .xterm-message { position: absolute; left: 0; @@ -152,6 +152,15 @@ pointer-events: none; } +.xterm .xterm-accessibility-tree:not(.debug) *::selection { + color: transparent; +} + +.xterm .xterm-accessibility-tree { + user-select: text; + white-space: pre; +} + .xterm .live-region { position: absolute; left: -9999px; @@ -187,12 +196,12 @@ } .xterm-screen .xterm-decoration-container .xterm-decoration { - z-index: 6; - position: absolute; + z-index: 6; + position: absolute; } .xterm-screen .xterm-decoration-container .xterm-decoration.xterm-decoration-top-layer { - z-index: 7; + z-index: 7; } .xterm-decoration-overview-ruler { diff --git a/packages/terminal/package.json b/packages/terminal/package.json index 9edbc06f66..30ae9f627e 100644 --- a/packages/terminal/package.json +++ b/packages/terminal/package.json @@ -19,7 +19,7 @@ "rollup-plugin-copy": "^3.4.0" }, "dependencies": { - "xterm": "^5.3.0", - "xterm-addon-fit": "^0.7.0" + "@xterm/xterm": "^5.5.0", + "@xterm/addon-fit": "^0.10.0" } } diff --git a/packages/terminal/src/main.js b/packages/terminal/src/main.js index 0935fad883..7c482939fd 100644 --- a/packages/terminal/src/main.js +++ b/packages/terminal/src/main.js @@ -16,8 +16,8 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { Terminal } from 'xterm'; -import { FitAddon } from 'xterm-addon-fit'; +import { Terminal } from '@xterm/xterm'; +import { FitAddon } from '@xterm/addon-fit'; import { PTY } from './pty/PTY'; import { XDocumentANSIShell } from './pty/XDocumentANSIShell'; From 4ef3e53de34f0097950a7e707ca2483863beafb5 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Tue, 14 May 2024 16:00:59 +0100 Subject: [PATCH 0025/2119] fix(Terminal): Accept input from Chrome on Android Xterm.js produces two kinds of events: onKey and onData. On a desktop, these are effectively the same, but on mobile, IME inputs produce data but not key presses. By listening to onData instead of onKey, we get that input. With some experimentation, I also found that we don't need the code to handle enter, home, end, or Ctrl-Shift-V. All of these function as expected without that code, so we can remove it and simplify this further. :^) --- packages/terminal/src/main.js | 41 +++-------------------------------- 1 file changed, 3 insertions(+), 38 deletions(-) diff --git a/packages/terminal/src/main.js b/packages/terminal/src/main.js index 7c482939fd..d27f557fc8 100644 --- a/packages/terminal/src/main.js +++ b/packages/terminal/src/main.js @@ -28,9 +28,7 @@ class XTermIO { } bind () { - this.term.onKey(this.handleKey.bind(this)); - - this.term.attachCustomKeyEventHandler(this.handleKeyBeforeProcess.bind(this)); + this.term.onData(this.handleData.bind(this)); (async () => { for ( ;; ) { @@ -40,41 +38,8 @@ class XTermIO { })(); } - async handleKeyBeforeProcess (evt) { - if ( evt.key === 'V' && evt.ctrlKey && evt.shiftKey && evt.type === 'keydown' ) { - const clipboard = navigator.clipboard; - const text = await clipboard.readText(); - this.pty.out.write(text); - } - } - - handleKey ({ key, domEvent }) { - const pty = this.pty; - - const handlers = { - Enter: () => { - pty.out.write('\n'); - }, - // Backspace: () => { - // pty.out.write('\x08'); - // }, - // Delete: () => { - // pty.out.write('\x1B[3~'); - // }, - Home: () => { - pty.out.write('\x1B[H'); - }, - End: () => { - pty.out.write('\x1B[F'); - } - } - - if ( handlers.hasOwnProperty(domEvent.key) ) { - const writeKey = handlers[domEvent.key](); - if ( ! writeKey ) return; - } - - pty.out.write(key); + handleData ( data ) { + this.pty.out.write(data); } } From 923d5878c30b7ed6194ec163af2697ec21cd0ab3 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 14 May 2024 17:33:14 -0400 Subject: [PATCH 0026/2119] Prevent enable of 2FA without configure --- packages/backend/src/api/APIError.js | 4 ++++ packages/backend/src/routers/auth/configure-2fa.js | 6 ++++++ 2 files changed, 10 insertions(+) diff --git a/packages/backend/src/api/APIError.js b/packages/backend/src/api/APIError.js index 0ec6ba9691..709365596c 100644 --- a/packages/backend/src/api/APIError.js +++ b/packages/backend/src/api/APIError.js @@ -339,6 +339,10 @@ module.exports = class APIError { status: 409, message: '2FA is already enabled.', }, + '2fa_not_configured': { + status: 409, + message: '2FA is not configured.', + }, // protected endpoints 'too_many_requests': { diff --git a/packages/backend/src/routers/auth/configure-2fa.js b/packages/backend/src/routers/auth/configure-2fa.js index eda6bb7560..995e0e7a3a 100644 --- a/packages/backend/src/routers/auth/configure-2fa.js +++ b/packages/backend/src/routers/auth/configure-2fa.js @@ -88,10 +88,16 @@ module.exports = eggspress('/auth/configure-2fa/:action', { const user = await get_user({ id: req.user.id, force: true }); + // Verify that 2FA isn't already enabled if ( user.otp_enabled ) { throw APIError.create('2fa_already_enabled'); } + // Verify that TOTP secret was set (configuration step not skipped) + if ( ! user.otp_secret ) { + throw APIError.create('2fa_not_configured'); + } + await db.write( `UPDATE user SET otp_enabled = 1 WHERE uuid = ?`, [user.uuid] From 0b093dd57eb42b9bad5a634f3690f29d90c6e802 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 14 May 2024 19:40:57 -0400 Subject: [PATCH 0027/2119] Revoke other sessions when password is changed --- .../backend/src/routers/user-protected/change-password.js | 8 ++++++++ packages/backend/src/services/auth/AuthService.js | 7 +++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/routers/user-protected/change-password.js b/packages/backend/src/routers/user-protected/change-password.js index 3c1f2a1d9e..de8bb2dee6 100644 --- a/packages/backend/src/routers/user-protected/change-password.js +++ b/packages/backend/src/routers/user-protected/change-password.js @@ -80,6 +80,14 @@ module.exports = { const svc_email = req.services.get('email'); svc_email.send_email({ email: req.user.email }, 'password_change_notification'); + // Kick out all other sessions + const svc_auth = req.services.get('auth'); + const sessions = await svc_auth.list_sessions(req.actor); + for ( const session of sessions ) { + if ( session.current ) continue; + await svc_auth.revoke_session(req.actor, session.uuid); + } + return res.send('Password successfully updated.') } }; diff --git a/packages/backend/src/services/auth/AuthService.js b/packages/backend/src/services/auth/AuthService.js index b6d2823173..07fdde7468 100644 --- a/packages/backend/src/services/auth/AuthService.js +++ b/packages/backend/src/services/auth/AuthService.js @@ -365,11 +365,14 @@ class AuthService extends BaseService { mysql: () => session.meta, otherwise: () => JSON.parse(session.meta ?? "{}") })(); + sessions.push(session); + }; + + for ( const session of sessions ) { if ( session.uuid === actor.type.session ) { session.current = true; } - sessions.push(session); - }; + } return sessions; } From a8160a8cdcdd6aff98728a6f1643d93386e6bb5a Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Wed, 15 May 2024 10:18:28 +0100 Subject: [PATCH 0028/2119] fix: Add missing file extension to 0009_app-prefix-fix.sql in DB init --- .../src/services/database/SqliteDatabaseAccessService.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/packages/backend/src/services/database/SqliteDatabaseAccessService.js b/packages/backend/src/services/database/SqliteDatabaseAccessService.js index fcf98d31d5..c39e4eff62 100644 --- a/packages/backend/src/services/database/SqliteDatabaseAccessService.js +++ b/packages/backend/src/services/database/SqliteDatabaseAccessService.js @@ -55,7 +55,7 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { '0006_update-apps.sql', '0007_sessions.sql', '0008_otp.sql', - '0009_app-prefix-fix', + '0009_app-prefix-fix.sql', ].map(p => path_.join(__dirname, 'sqlite_setup', p)); const fs = require('fs'); for ( const filename of sql_files ) { From 062e23b5c9673db1f8b0ff0469289d52dd1e3f99 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Wed, 15 May 2024 17:46:50 +0100 Subject: [PATCH 0029/2119] fix: Correct APIError imports APIError is the only thing exported from its file, so we must not wrap it in {}. --- packages/backend/src/api/filesystem/FlagParam.js | 2 +- packages/backend/src/api/filesystem/StringParam.js | 2 +- packages/backend/src/filesystem/hl_operations/hl_data_read.js | 2 +- packages/backend/src/filesystem/hl_operations/hl_stat.js | 2 +- packages/backend/src/filesystem/ll_operations/ll_rmnode.js | 2 +- packages/backend/src/routers/auth/list-permissions.js | 2 +- packages/backend/src/routers/auth/list-sessions.js | 2 +- packages/backend/src/routers/auth/revoke-user-app.js | 2 +- 8 files changed, 8 insertions(+), 8 deletions(-) diff --git a/packages/backend/src/api/filesystem/FlagParam.js b/packages/backend/src/api/filesystem/FlagParam.js index 3ba1b2b1c6..d4b12ecda2 100644 --- a/packages/backend/src/api/filesystem/FlagParam.js +++ b/packages/backend/src/api/filesystem/FlagParam.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { APIError } = require('../../api/APIError'); +const APIError = require('../../api/APIError'); module.exports = class FlagParam { constructor (srckey, options) { diff --git a/packages/backend/src/api/filesystem/StringParam.js b/packages/backend/src/api/filesystem/StringParam.js index 17e46231ed..4762b9b166 100644 --- a/packages/backend/src/api/filesystem/StringParam.js +++ b/packages/backend/src/api/filesystem/StringParam.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { APIError } = require('../../api/APIError'); +const APIError = require('../../api/APIError'); module.exports = class StringParam { constructor (srckey, options) { diff --git a/packages/backend/src/filesystem/hl_operations/hl_data_read.js b/packages/backend/src/filesystem/hl_operations/hl_data_read.js index e19e9530ac..f7ec619c05 100644 --- a/packages/backend/src/filesystem/hl_operations/hl_data_read.js +++ b/packages/backend/src/filesystem/hl_operations/hl_data_read.js @@ -20,7 +20,7 @@ const { stream_to_buffer } = require("../../util/streamutil"); const { HLFilesystemOperation } = require("./definitions"); const { chkperm } = require('../../helpers'); const { LLRead } = require('../ll_operations/ll_read'); -const { APIError } = require('../../api/APIError'); +const APIError = require('../../api/APIError'); /** * HLDataRead reads a stream of objects from a file containing structured data. diff --git a/packages/backend/src/filesystem/hl_operations/hl_stat.js b/packages/backend/src/filesystem/hl_operations/hl_stat.js index a8ea07a3da..43d9239a5b 100644 --- a/packages/backend/src/filesystem/hl_operations/hl_stat.js +++ b/packages/backend/src/filesystem/hl_operations/hl_stat.js @@ -19,7 +19,7 @@ const { chkperm } = require("../../helpers"); const { Context } = require("../../util/context"); const { HLFilesystemOperation } = require("./definitions"); -const { APIError } = require('../../api/APIError'); +const APIError = require('../../api/APIError'); class HLStat extends HLFilesystemOperation { static MODULES = { diff --git a/packages/backend/src/filesystem/ll_operations/ll_rmnode.js b/packages/backend/src/filesystem/ll_operations/ll_rmnode.js index 0fa6c11fca..c0cbc4fc06 100644 --- a/packages/backend/src/filesystem/ll_operations/ll_rmnode.js +++ b/packages/backend/src/filesystem/ll_operations/ll_rmnode.js @@ -19,7 +19,7 @@ const { Context } = require("../../util/context"); const { ParallelTasks } = require("../../util/otelutil"); const { LLFilesystemOperation } = require("./definitions"); -const { APIError } = require("../../api/APIError"); +const APIError = require("../../api/APIError"); class LLRmNode extends LLFilesystemOperation { async _run () { diff --git a/packages/backend/src/routers/auth/list-permissions.js b/packages/backend/src/routers/auth/list-permissions.js index 096ba23c04..9eb9cc7920 100644 --- a/packages/backend/src/routers/auth/list-permissions.js +++ b/packages/backend/src/routers/auth/list-permissions.js @@ -21,7 +21,7 @@ const { get_app, get_user } = require("../../helpers"); const { UserActorType } = require("../../services/auth/Actor"); const { DB_READ } = require("../../services/database/consts"); const { Context } = require("../../util/context"); -const { APIError } = require('../../api/APIError'); +const APIError = require('../../api/APIError'); module.exports = eggspress('/auth/list-permissions', { subdomain: 'api', diff --git a/packages/backend/src/routers/auth/list-sessions.js b/packages/backend/src/routers/auth/list-sessions.js index 9d4992c08c..bdf94ca7c0 100644 --- a/packages/backend/src/routers/auth/list-sessions.js +++ b/packages/backend/src/routers/auth/list-sessions.js @@ -1,7 +1,7 @@ const eggspress = require("../../api/eggspress"); const { UserActorType } = require("../../services/auth/Actor"); const { Context } = require("../../util/context"); -const { APIError } = require('../../api/APIError'); +const APIError = require('../../api/APIError'); module.exports = eggspress('/auth/list-sessions', { subdomain: 'api', diff --git a/packages/backend/src/routers/auth/revoke-user-app.js b/packages/backend/src/routers/auth/revoke-user-app.js index 7087b9766d..853f0b2b42 100644 --- a/packages/backend/src/routers/auth/revoke-user-app.js +++ b/packages/backend/src/routers/auth/revoke-user-app.js @@ -19,7 +19,7 @@ const eggspress = require("../../api/eggspress"); const { UserActorType } = require("../../services/auth/Actor"); const { Context } = require("../../util/context"); -const { APIError } = require('../../api/APIError'); +const APIError = require('../../api/APIError'); module.exports = eggspress('/auth/revoke-user-app', { subdomain: 'api', From 2e0d7361cb7ce7a68053382d18cb9036882c18df Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 15 May 2024 15:32:18 -0400 Subject: [PATCH 0030/2119] Add method to patch services --- packages/backend/src/services/Container.js | 5 ++++ packages/backend/src/services/ServicePatch.js | 27 +++++++++++++++++++ 2 files changed, 32 insertions(+) create mode 100644 packages/backend/src/services/ServicePatch.js diff --git a/packages/backend/src/services/Container.js b/packages/backend/src/services/Container.js index 43a40d855e..6df9b693e2 100644 --- a/packages/backend/src/services/Container.js +++ b/packages/backend/src/services/Container.js @@ -32,6 +32,11 @@ class Container { ? cls.getInstance({ services: this, config, my_config, name, args }) : new cls({ services: this, config, my_config, name, args }) ; } + patchService (name, patch, args) { + const original_service = this.instances_[name]; + const patch_instance = new patch(); + patch_instance.patch({ original_service, args }); + } set (name, instance) { this.instances_[name] = instance; } get (name, opts) { if ( this.instances_[name] ) { diff --git a/packages/backend/src/services/ServicePatch.js b/packages/backend/src/services/ServicePatch.js new file mode 100644 index 0000000000..ea70384516 --- /dev/null +++ b/packages/backend/src/services/ServicePatch.js @@ -0,0 +1,27 @@ +const { AdvancedBase } = require("@heyputer/puter-js-common"); + +class ServicePatch extends AdvancedBase { + patch ({ original_service }) { + const patch_methods = this._get_merged_static_object('PATCH_METHODS'); + for ( const k in patch_methods ) { + if ( typeof patch_methods[k] !== 'function' ) { + throw new Error(`Patch method ${k} to ${original_service.service_name} ` + + `from ${this.constructor.name} ` + + `is not a function.`) + } + + const patch_method = patch_methods[k]; + + const patch_arguments = { + that: original_service, + original: original_service[k].bind(original_service), + }; + + original_service[k] = (...a) => { + return patch_method.call(this, patch_arguments, ...a); + } + } + } +} + +module.exports = ServicePatch; From 21444daefb994555ebaf1ff4206f4e072535f73b Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 15 May 2024 15:36:59 -0400 Subject: [PATCH 0031/2119] Add jsdoc comments to registerService and patchService --- packages/backend/src/services/Container.js | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/packages/backend/src/services/Container.js b/packages/backend/src/services/Container.js index 6df9b693e2..ee85eb9b93 100644 --- a/packages/backend/src/services/Container.js +++ b/packages/backend/src/services/Container.js @@ -26,12 +26,27 @@ class Container { this.instances_ = {}; this.ready = new TeePromise(); } + /** + * registerService registers a service with the servuces container. + * + * @param {String} name - the name of the service + * @param {BaseService.constructor} cls - an implementation of BaseService + * @param {Array} args - arguments to pass to the service constructor + */ registerService (name, cls, args) { const my_config = config.services?.[name] || {}; this.instances_[name] = cls.getInstance ? cls.getInstance({ services: this, config, my_config, name, args }) : new cls({ services: this, config, my_config, name, args }) ; } + /** + * patchService allows overriding methods on a service that is already + * constructed and initialized. + * + * @param {String} name - the name of the service to patch + * @param {ServicePatch.constructor} patch - the patch + * @param {Array} args - arguments to pass to the patch + */ patchService (name, patch, args) { const original_service = this.instances_[name]; const patch_instance = new patch(); From c70e378973ad93ae888be3c4bd4c1ddf195d203f Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 15 May 2024 15:42:00 -0400 Subject: [PATCH 0032/2119] Add error id for expired auth tokens --- packages/backend/src/api/APIError.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/packages/backend/src/api/APIError.js b/packages/backend/src/api/APIError.js index 709365596c..fee79b9a86 100644 --- a/packages/backend/src/api/APIError.js +++ b/packages/backend/src/api/APIError.js @@ -319,6 +319,10 @@ module.exports = class APIError { status: 401, message: 'This authentication token is not supported here.', }, + 'token_expired': { + status: 401, + message: 'Authentication token has expired.', + }, 'account_suspended': { status: 403, message: 'Account suspended.', From 691c8f1436ac94395aeed09fa4cb4cfdc624d494 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 15 May 2024 18:22:54 -0400 Subject: [PATCH 0033/2119] Add locking to save_account --- packages/backend/src/CoreModule.js | 3 + packages/backend/src/routers/save_account.js | 227 +++++++++--------- packages/backend/src/services/LockService.js | 105 ++++++++ .../backend/src/services/fs/FSLockService.js | 1 + 4 files changed, 227 insertions(+), 109 deletions(-) create mode 100644 packages/backend/src/services/LockService.js diff --git a/packages/backend/src/CoreModule.js b/packages/backend/src/CoreModule.js index be2b392a80..eece920944 100644 --- a/packages/backend/src/CoreModule.js +++ b/packages/backend/src/CoreModule.js @@ -210,6 +210,9 @@ const install = async ({ services, app }) => { const { AntiCSRFService } = require('./services/auth/AntiCSRFService'); services.registerService('anti-csrf', AntiCSRFService); + + const { LockService } = require('./services/LockService'); + services.registerService('lock', LockService); } const install_legacy = async ({ services }) => { diff --git a/packages/backend/src/routers/save_account.js b/packages/backend/src/routers/save_account.js index df076bd9b1..bb33b5fda2 100644 --- a/packages/backend/src/routers/save_account.js +++ b/packages/backend/src/routers/save_account.js @@ -75,123 +75,132 @@ router.post('/save_account', auth, express.json(), async (req, res, next)=>{ return res.status(429).send('Too many requests.'); } - // duplicate username check, do this only if user has supplied a new username - if(req.body.username !== req.user.username && await username_exists(req.body.username)) - return res.status(400).send('This username already exists in our database. Please use another one.'); - // duplicate email check (pseudo-users don't count) - let rows2 = await db.read(`SELECT EXISTS(SELECT 1 FROM user WHERE email=? AND password IS NOT NULL) AS email_exists`, [req.body.email]); - if(rows2[0].email_exists) - return res.status(400).send('This email already exists in our database. Please use another one.'); - // get pseudo user, if exists - let pseudo_user = await db.read(`SELECT * FROM user WHERE email = ? AND password IS NULL`, [req.body.email]); - pseudo_user = pseudo_user[0]; - - // send_confirmation_code - req.body.send_confirmation_code = req.body.send_confirmation_code ?? true; - - // todo email confirmation is required by default unless: - // Pseudo user converting and matching uuid is provided - let email_confirmation_required = 0; - - // ----------------------------------- - // Get referral user - // ----------------------------------- - let referred_by_user = undefined; - if ( req.body.referral_code ) { - referred_by_user = await get_user({ referral_code: req.body.referral_code }); - if ( ! referred_by_user ) { - return res.status(400).send('Referral code not found'); + const svc_lock = req.services.get('lock'); + return svc_lock.lock([ + `save-account:username:${req.body.username}`, + `save-account:email:${req.body.email}` + ], async () => { + await new Promise((rslv) => { + setTimeout(rslv, 5000); + }); + // duplicate username check, do this only if user has supplied a new username + if(req.body.username !== req.user.username && await username_exists(req.body.username)) + return res.status(400).send('This username already exists in our database. Please use another one.'); + // duplicate email check (pseudo-users don't count) + let rows2 = await db.read(`SELECT EXISTS(SELECT 1 FROM user WHERE email=? AND password IS NOT NULL) AS email_exists`, [req.body.email]); + if(rows2[0].email_exists) + return res.status(400).send('This email already exists in our database. Please use another one.'); + // get pseudo user, if exists + let pseudo_user = await db.read(`SELECT * FROM user WHERE email = ? AND password IS NULL`, [req.body.email]); + pseudo_user = pseudo_user[0]; + + // send_confirmation_code + req.body.send_confirmation_code = req.body.send_confirmation_code ?? true; + + // todo email confirmation is required by default unless: + // Pseudo user converting and matching uuid is provided + let email_confirmation_required = 0; + + // ----------------------------------- + // Get referral user + // ----------------------------------- + let referred_by_user = undefined; + if ( req.body.referral_code ) { + referred_by_user = await get_user({ referral_code: req.body.referral_code }); + if ( ! referred_by_user ) { + return res.status(400).send('Referral code not found'); + } } - } - - // ----------------------------------- - // New User - // ----------------------------------- - const user_uuid = req.user.uuid; - let email_confirm_code = Math.floor(100000 + Math.random() * 900000); - const email_confirm_token = uuidv4(); - - if(pseudo_user === undefined){ - await db.write( - `UPDATE user - SET - username = ?, email = ?, password = ?, email_confirm_code = ?, email_confirm_token = ?${ - referred_by_user ? ', referred_by = ?' : '' } - WHERE - id = ?`, - [ - // username - req.body.username, - // email - req.body.email, - // password - await bcrypt.hash(req.body.password, 8), - // email_confirm_code - email_confirm_code, - //email_confirm_token - email_confirm_token, - // referred_by - ...(referred_by_user ? [referred_by_user.id] : []), - // id - req.user.id - ] - ); - invalidate_cached_user(req.user); - - // Update root directory name - await db.write( - `UPDATE fsentries SET name = ? WHERE user_id = ? and parent_uid IS NULL`, - [ - // name - req.body.username, - // id - req.user.id, - ] - ); - const filesystem = req.services.get('filesystem'); - await filesystem.update_child_paths(`/${req.user.username}`, `/${req.body.username}`, req.user.id); - - if(req.body.send_confirmation_code) - send_email_verification_code(email_confirm_code, req.body.email); - else - send_email_verification_token(email_confirm_token, req.body.email, user_uuid); - } - // create token for login - const svc_auth = req.services.get('auth'); - const { token } = await svc_auth.create_session_token(req.user, { req }); + // ----------------------------------- + // New User + // ----------------------------------- + const user_uuid = req.user.uuid; + let email_confirm_code = Math.floor(100000 + Math.random() * 900000); + const email_confirm_token = uuidv4(); + + if(pseudo_user === undefined){ + await db.write( + `UPDATE user + SET + username = ?, email = ?, password = ?, email_confirm_code = ?, email_confirm_token = ?${ + referred_by_user ? ', referred_by = ?' : '' } + WHERE + id = ?`, + [ + // username + req.body.username, + // email + req.body.email, + // password + await bcrypt.hash(req.body.password, 8), + // email_confirm_code + email_confirm_code, + //email_confirm_token + email_confirm_token, + // referred_by + ...(referred_by_user ? [referred_by_user.id] : []), + // id + req.user.id + ] + ); + invalidate_cached_user(req.user); + + // Update root directory name + await db.write( + `UPDATE fsentries SET name = ? WHERE user_id = ? and parent_uid IS NULL`, + [ + // name + req.body.username, + // id + req.user.id, + ] + ); + const filesystem = req.services.get('filesystem'); + await filesystem.update_child_paths(`/${req.user.username}`, `/${req.body.username}`, req.user.id); + + if(req.body.send_confirmation_code) + send_email_verification_code(email_confirm_code, req.body.email); + else + send_email_verification_token(email_confirm_token, req.body.email, user_uuid); + } - // user id - // todo if pseudo user, assign directly no need to do another DB lookup - const user_id = req.user.id; - const user_res = await db.read('SELECT * FROM `user` WHERE `id` = ? LIMIT 1', [user_id]); - const user = user_res[0]; + // create token for login + const svc_auth = req.services.get('auth'); + const { token } = await svc_auth.create_session_token(req.user, { req }); - // todo send LINK-based verification email + // user id + // todo if pseudo user, assign directly no need to do another DB lookup + const user_id = req.user.id; + const user_res = await db.read('SELECT * FROM `user` WHERE `id` = ? LIMIT 1', [user_id]); + const user = user_res[0]; - //set cookie - res.cookie(config.cookie_name, token); + // todo send LINK-based verification email - { - const svc_event = req.services.get('event'); - svc_event.emit('user.save_account', { user }); - } + //set cookie + res.cookie(config.cookie_name, token); - // return results - return res.send({ - token: token, - user:{ - username: user.username, - uuid: user.uuid, - email: user.email, - is_temp: false, - requires_email_confirmation: user.requires_email_confirmation, - email_confirmed: user.email_confirmed, - email_confirmation_required: email_confirmation_required, - taskbar_items: await get_taskbar_items(user), - referral_code: user.referral_code, + { + const svc_event = req.services.get('event'); + svc_event.emit('user.save_account', { user }); } - }) + + // return results + return res.send({ + token: token, + user:{ + username: user.username, + uuid: user.uuid, + email: user.email, + is_temp: false, + requires_email_confirmation: user.requires_email_confirmation, + email_confirmed: user.email_confirmed, + email_confirmation_required: email_confirmation_required, + taskbar_items: await get_taskbar_items(user), + referral_code: user.referral_code, + } + }) + }); }) module.exports = router \ No newline at end of file diff --git a/packages/backend/src/services/LockService.js b/packages/backend/src/services/LockService.js new file mode 100644 index 0000000000..25161ba091 --- /dev/null +++ b/packages/backend/src/services/LockService.js @@ -0,0 +1,105 @@ +const { RWLock } = require("../util/lockutil"); +const BaseService = require("./BaseService"); + +/** + * LockService implements robust critical sections when the behavior + * might return early or throw an error. + * + * This serivces uses RWLock but always locks in write mode. + */ +class LockService extends BaseService { + async _construct () { + this.locks = {}; + } + async _init () { + const svc_commands = this.services.get('commands'); + svc_commands.registerCommands('lock', [ + { + id: 'locks', + description: 'lists locks', + handler: async (args, log) => { + for ( const name in this.locks ) { + let line = name + ': '; + if ( this.locks[name].effective_mode === RWLock.TYPE_READ ) { + line += `READING (${this.locks[name].readers_})`; + log.log(line); + } + else + if ( this.locks[name].effective_mode === RWLock.TYPE_WRITE ) { + line += 'WRITING'; + log.log(line); + } + else { + line += 'UNKNOWN'; + log.log(line); + + // log the lock's internal state + const lines = JSON.stringify( + this.locks[name], + null, 2 + ).split('\n'); + for ( const line of lines ) { + log.log(' -> ' + line); + } + } + } + } + } + ]); + } + + async lock (name, opt_options, callback) { + if ( typeof opt_options === 'function' ) { + callback = opt_options; + opt_options = {}; + } + + // If name is an array, lock all of them + if ( Array.isArray(name) ) { + const names = name; + // TODO: verbose log option by service + // console.log('LOCKING NAMES', names) + const section = names.reduce((current_callback, name) => { + return async () => { + return await this.lock(name, opt_options, current_callback); + }; + }, callback); + + return await section(); + } + + if ( ! this.locks[name] ) { + const rwlock = new RWLock(); + this.locks[name] = rwlock; + } + + const handle = await this.locks[name].wlock(); + // TODO: verbose log option by service + // console.log(`\x1B[36;1mLOCK (${name})\x1B[0m`); + + + let timeout, timed_out; + if ( opt_options.timeout ) { + timeout = setTimeout(() => { + handle.unlock(); + // TODO: verbose log option by service + // throw new Error(`lock ${name} timed out`); + }, opt_options.timeout); + } + + try { + return await callback(); + } finally { + if ( timeout ) { + clearTimeout(timeout); + } + if ( ! timed_out ) { + // TODO: verbose log option by service + // console.log(`\x1B[36;1mUNLOCK (${name})\x1B[0m`); + handle.unlock(); + } + } + } +} + +module.exports = { LockService }; \ No newline at end of file diff --git a/packages/backend/src/services/fs/FSLockService.js b/packages/backend/src/services/fs/FSLockService.js index 83bf49885b..a9fc3d0bf8 100644 --- a/packages/backend/src/services/fs/FSLockService.js +++ b/packages/backend/src/services/fs/FSLockService.js @@ -23,6 +23,7 @@ const BaseService = require("../BaseService"); const MODE_READ = Symbol('read'); const MODE_WRITE = Symbol('write'); +// TODO: DRY: could use LockService now class FSLockService extends BaseService { async _construct () { this.locks = {}; From bee0e19eaf2eb04fcbfd5f08c1b8861b88ccf46a Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 15 May 2024 20:59:20 -0400 Subject: [PATCH 0034/2119] Fix 8688ggu00 --- src/IPC.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/IPC.js b/src/IPC.js index a566ed5101..9f87909d11 100644 --- a/src/IPC.js +++ b/src/IPC.js @@ -1015,6 +1015,9 @@ window.addEventListener('message', async (event) => { let target_path; let create_missing_ancestors = false; + console.warn(`The method ${event.data.msg} is deprecated - see docs.puter.com for more information.`); + event.data.filename = event.data.filename.replace(/(\.\.\/|\.\.\\)/g, ''); + if(event.data.msg === 'saveToPictures') target_path = path.join(window.pictures_path, event.data.filename); else if(event.data.msg === 'saveToDesktop') From b6ea37c5177081580cc46a031718f57ad0a09a10 Mon Sep 17 00:00:00 2001 From: Zac0511 Date: Thu, 16 May 2024 18:06:21 +0200 Subject: [PATCH 0035/2119] Update fr.js Since there was a lot of text and menus added, and they were not translated, so i just translated them. --- src/i18n/translations/fr.js | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/src/i18n/translations/fr.js b/src/i18n/translations/fr.js index 5f6bbe0e27..63f9207275 100644 --- a/src/i18n/translations/fr.js +++ b/src/i18n/translations/fr.js @@ -160,6 +160,36 @@ const fr = { yes_release_it: "Oui, le libérer", you_have_been_referred_to_puter_by_a_friend: "Vous avez été recommandé à Puter par un ami !", zip: "Compresser", + zipping_file: "Compression de %strong%", + + // === 2FA Setup === + setup2fa_1_step_heading: 'Ouvrez votre application Authenticator', + setup2fa_1_instructions: ` + Vous pouvez utiliser n'importe quelle application d'authentification prenant en charge le protocole TOTP (Time-based One-Time Password). + Il y a beaucoup de choix, mais si vous n'êtes pas sûr + Authy + est un bon choix pour Android et iOS + `, + setup2fa_2_step_heading: 'Scannez le QR code', + setup2fa_3_step_heading: 'Entrez le code à 6 chiffres', + setup2fa_4_step_heading: 'Copiez vos codes de récupération', + setup2fa_4_instructions: ` + Ces codes de récupération sont le seul moyen d'accéder à votre compte si vous perdez votre téléphone ou si vous ne pouvez pas utiliser votre application d'authentification. + Assurez-vous de les conserver dans un endroit sûr. + `, + setup2fa_5_step_heading: 'Confirmer la configuration A2F', + setup2fa_5_confirmation_1: 'J'ai enregistré mes codes de récupération dans un emplacement sécurisé', + setup2fa_5_confirmation_2: 'Je suis prêt à activer l'A2F', + setup2fa_5_button: 'Activer l'A2F', + + // === 2FA Login === + login2fa_otp_title: 'Entrez le code A2F', + login2fa_otp_instructions: 'Saisissez le code à 6 chiffres de votre application Authenticator', + login2fa_recovery_title: 'Entrez un code de récupération', + login2fa_recovery_instructions: 'Entrez l'un de vos codes de récupération pour accéder à votre compte.', + login2fa_use_recovery_code: 'Utiliser un code de récupération', + login2fa_recovery_back: 'Retour', + login2fa_recovery_placeholder: 'XXXXXXXX', } } From e1ae9241af9d61a27e496d32076c5ffda8e31f0c Mon Sep 17 00:00:00 2001 From: Zac0511 Date: Thu, 16 May 2024 18:27:12 +0200 Subject: [PATCH 0036/2119] Update fr.js --- src/i18n/translations/fr.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/i18n/translations/fr.js b/src/i18n/translations/fr.js index 63f9207275..d12d2614ad 100644 --- a/src/i18n/translations/fr.js +++ b/src/i18n/translations/fr.js @@ -178,15 +178,15 @@ const fr = { Assurez-vous de les conserver dans un endroit sûr. `, setup2fa_5_step_heading: 'Confirmer la configuration A2F', - setup2fa_5_confirmation_1: 'J'ai enregistré mes codes de récupération dans un emplacement sécurisé', - setup2fa_5_confirmation_2: 'Je suis prêt à activer l'A2F', - setup2fa_5_button: 'Activer l'A2F', + setup2fa_5_confirmation_1: 'J\'ai enregistré mes codes de récupération dans un emplacement sécurisé', + setup2fa_5_confirmation_2: 'Je suis prêt à activer l\'A2F', + setup2fa_5_button: 'Activer l\'A2F', // === 2FA Login === login2fa_otp_title: 'Entrez le code A2F', login2fa_otp_instructions: 'Saisissez le code à 6 chiffres de votre application Authenticator', login2fa_recovery_title: 'Entrez un code de récupération', - login2fa_recovery_instructions: 'Entrez l'un de vos codes de récupération pour accéder à votre compte.', + login2fa_recovery_instructions: 'Entrez l\'un de vos codes de récupération pour accéder à votre compte.', login2fa_use_recovery_code: 'Utiliser un code de récupération', login2fa_recovery_back: 'Retour', login2fa_recovery_placeholder: 'XXXXXXXX', From b68873c5f4862a7931b65a230ec5d3f52ccd49db Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 16 May 2024 12:48:57 -0400 Subject: [PATCH 0037/2119] Fix 8688grpf1 --- src/UI/Components/Slider.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/UI/Components/Slider.js b/src/UI/Components/Slider.js index 26308048f7..18281d80df 100644 --- a/src/UI/Components/Slider.js +++ b/src/UI/Components/Slider.js @@ -81,9 +81,15 @@ export default class Slider extends Component { $(template).html(/*html*/`
- +
`); + + // Set attributes here to prevent XSS injection + $(template).find('.slider-input').attr('min', min); + $(template).find('.slider-input').attr('max', max); + $(template).find('.slider-input').attr('value', value); + $(template).find('.slider-input').attr('step', step); } on_ready ({ listen }) { From 43d0936533e04032451301637518dc5a0c7b39b6 Mon Sep 17 00:00:00 2001 From: Christian Neff Date: Thu, 16 May 2024 19:51:42 +0200 Subject: [PATCH 0038/2119] Update de.js Translated: - 2FA strings - Task Manager strings - 2 other scattered strings --- src/i18n/translations/de.js | 37 ++++++++++++++++++++++++++++++++++++- 1 file changed, 36 insertions(+), 1 deletion(-) diff --git a/src/i18n/translations/de.js b/src/i18n/translations/de.js index 7f6b085881..8e4421f90e 100644 --- a/src/i18n/translations/de.js +++ b/src/i18n/translations/de.js @@ -136,6 +136,7 @@ const de = { send: "Senden", send_password_recovery_email: "Senden Sie eine E-Mail zur Passwortwiederherstellung", session_saved: "Vielen Dank, dass Sie ein Konto erstellt haben. Diese Sitzung wurde gespeichert.", + settings: "Einstellungen", set_new_password: "Neues Passwort erstellen", share_to: "Teilen mit", show_all_windows: "Alle Fenster zeigen", @@ -148,6 +149,10 @@ const de = { start: 'Start', storage_puter_used: 'Verwendet von Puter', taking_longer_than_usual: 'Es dauert etwas länger als gewöhnlich. Bitte warten…', + task_manager: "Task-Manager", + taskmgr_header_name: "Name", + taskmgr_header_status: "Status", + taskmgr_header_type: "Typ", text_document: 'Textdokument', tos_fineprint: `Indem Sie auf „Kostenloses Konto erstellen“ klicken, stimmen Sie den {{link=terms}}Nutzungsbedingungen{{/link}} und der {{link=privacy}}Datenschutzerklärung{{/link}} von Puter zu.`, trash: 'Papierkorb', @@ -162,7 +167,37 @@ const de = { yes_release_it: 'Ja, veröffentlichen', you_have_been_referred_to_puter_by_a_friend: "Sie wurden von einem Freund an Puter verwiesen!", zip: "Zippen", + zipping_file: "Zippe %strong%", + + // === 2FA Setup === + setup2fa_1_step_heading: 'Öffnen Sie Ihre Authentifizierungs-App', + setup2fa_1_instructions: ` + Sie können jede Authentifizierungs-App verwenden, die das TOTP-Protokoll (Time-based One-Time Password) unterstützt. + Es gibt viele zur Auswahl, aber wenn Sie sich nicht sicher sind ist + Authy + eine gute Wahl für Android und iOS. + `, + setup2fa_2_step_heading: 'Scannen Sie den QR-Code', + setup2fa_3_step_heading: 'Geben Sie den 6-stelligen Code ein', + setup2fa_4_step_heading: 'Kopieren Sie Ihre Wiederherstellungscodes', + setup2fa_4_instructions: ` + Diese Wiederherstellungscodes sind die einzige Möglichkeit, auf Ihr Konto zuzugreifen, wenn Sie Ihr Telefon verlieren oder Ihre Authentifizierungs-App nicht verwenden können. + Bewahren Sie sie unbedingt an einem sicheren Ort auf. + `, + setup2fa_5_step_heading: '2FA-Einrichtung bestätigen', + setup2fa_5_confirmation_1: 'Ich habe meine Wiederherstellungscodes an einem sicheren Ort gespeichert', + setup2fa_5_confirmation_2: 'Ich bin bereit, 2FA zu aktivieren', + setup2fa_5_button: '2FA aktivieren', + + // === 2FA Login === + login2fa_otp_title: '2FA-Code eingeben', + login2fa_otp_instructions: 'Geben Sie den 6-stelligen Code aus Ihrer Authentifizierungs-App ein.', + login2fa_recovery_title: 'Wiederherstellungscode eingeben', + login2fa_recovery_instructions: 'Geben Sie einen Ihrer Wiederherstellungscodes ein, um auf Ihr Konto zuzugreifen.', + login2fa_use_recovery_code: 'Einen Wiederherstellungscode verwenden', + login2fa_recovery_back: 'Zurück', + login2fa_recovery_placeholder: 'XXXXXXXX', } }; -export default de; \ No newline at end of file +export default de; From f042b095f13d283e7bddd0a513d6a38541443b57 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 16 May 2024 17:25:36 -0400 Subject: [PATCH 0039/2119] Fix 8688gxkuj --- packages/backend/src/routers/down.js | 8 +++++++- src/helpers.js | 26 ++++++++++++++++++++------ 2 files changed, 27 insertions(+), 7 deletions(-) diff --git a/packages/backend/src/routers/down.js b/packages/backend/src/routers/down.js index 266c2701cc..c1ee3b446c 100644 --- a/packages/backend/src/routers/down.js +++ b/packages/backend/src/routers/down.js @@ -11,7 +11,7 @@ const { HLRead } = require('../filesystem/hl_operations/hl_read.js'); // -----------------------------------------------------------------------// // GET /down // -----------------------------------------------------------------------// -router.get('/down', auth, fs, express.json(), async (req, res, next)=>{ +router.post('/down', auth, fs, express.json(), async (req, res, next)=>{ // check subdomain if(require('../helpers').subdomain(req) !== 'api') next(); @@ -20,6 +20,12 @@ router.get('/down', auth, fs, express.json(), async (req, res, next)=>{ if((config.strict_email_verification_required || req.user.requires_email_confirmation) && !req.user.email_confirmed) return res.status(400).send({code: 'account_is_not_verified', message: 'Account is not verified'}); + // check anti-csrf token + const svc_antiCSRF = req.services.get('anti-csrf'); + if ( ! svc_antiCSRF.consume_token(req.user.uuid, req.body.anti_csrf) ) { + return res.status(400).json({ message: 'incorrect anti-CSRF token' }); + } + // validation if(!req.query.path) return res.status(400).send('path is required') diff --git a/src/helpers.js b/src/helpers.js index 41cd5dec1b..5e15a53a2b 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -1542,12 +1542,26 @@ window.trigger_download = (paths)=>{ }); } - urls.forEach(function (e) { - fetch(e.download) - .then(res => res.blob()) - .then(blob => { - saveAs(blob, e.filename); - }); + urls.forEach(async function (e) { + const anti_csrf = await (async () => { + const resp = await fetch(`${window.gui_origin}/get-anticsrf-token`); + const { token } = await resp.json(); + return token; + })(); + fetch(e.download, { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + puter.authToken, + }, + body: JSON.stringify({ + anti_csrf, + }), + }) + .then(res => res.blob()) + .then(blob => { + saveAs(blob, e.filename); + }); }); } From 49b257ecffbb1e12090b86a67528a5ad09da69db Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 9 May 2024 19:25:02 -0400 Subject: [PATCH 0040/2119] fix(security): Move token for socket.io to request body Currently this commit breaks websocket events and needs to be updated. --- packages/backend/src/helpers.js | 4 ++-- packages/backend/src/services/WebServerService.js | 4 ++-- packages/puter-js/src/modules/FileSystem/index.js | 2 +- src/UI/UIDesktop.js | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/backend/src/helpers.js b/packages/backend/src/helpers.js index 06cabf757d..d102309e0a 100644 --- a/packages/backend/src/helpers.js +++ b/packages/backend/src/helpers.js @@ -1146,8 +1146,8 @@ async function jwt_auth(req){ else if(req.query && req.query.auth_token) token = req.query.auth_token; // Socket - else if(req.handshake && req.handshake.query && req.handshake.query.auth_token) - token = req.handshake.query.auth_token; + else if(req.handshake && req.handshake.auth && req.handshake.auth.auth_token) + token = req.handshake.auth.auth_token; if(!token || token === 'null') throw('No auth token found'); diff --git a/packages/backend/src/services/WebServerService.js b/packages/backend/src/services/WebServerService.js index 73d95bb9c4..cecbd3eaef 100644 --- a/packages/backend/src/services/WebServerService.js +++ b/packages/backend/src/services/WebServerService.js @@ -158,7 +158,7 @@ class WebServerService extends BaseService { // Socket.io middleware for authentication socketio.use(async (socket, next) => { - if (socket.handshake.query.auth_token) { + if (socket.handshake.auth.auth_token) { try { let auth_res = await jwt_auth(socket); // successful auth @@ -168,7 +168,7 @@ class WebServerService extends BaseService { socket.join(socket.user.id); next(); } catch (e) { - console.log('socket auth err'); + console.log('socket auth err', e); } } }); diff --git a/packages/puter-js/src/modules/FileSystem/index.js b/packages/puter-js/src/modules/FileSystem/index.js index a554010267..0e6b2679d2 100644 --- a/packages/puter-js/src/modules/FileSystem/index.js +++ b/packages/puter-js/src/modules/FileSystem/index.js @@ -65,7 +65,7 @@ class FileSystem{ } this.socket = io(this.APIOrigin, { - query: { + auth: { auth_token: this.authToken, } }); diff --git a/src/UI/UIDesktop.js b/src/UI/UIDesktop.js index c6715b2921..e663815331 100644 --- a/src/UI/UIDesktop.js +++ b/src/UI/UIDesktop.js @@ -43,7 +43,7 @@ async function UIDesktop(options){ // connect socket. window.socket = io(window.gui_origin + '/', { - query: { + auth: { auth_token: window.auth_token } }); From 5031cea0408698cf4844ac980001fd3d72a48d71 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 16 May 2024 18:55:59 -0400 Subject: [PATCH 0041/2119] Update _default.js for deployment purposes --- packages/backend/src/config.js | 2 ++ packages/backend/src/routers/_default.js | 12 ++++++------ 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/packages/backend/src/config.js b/packages/backend/src/config.js index 55b13fadc5..bb0a0cf9ff 100644 --- a/packages/backend/src/config.js +++ b/packages/backend/src/config.js @@ -62,6 +62,8 @@ config.thumb_width = 80; config.thumb_height = 80; config.app_max_icon_size = 5*1024*1024; +config.defaultjs_asset_path = '../../'; + // config.origin = config.protocol + '://' + config.domain; // config.api_base_url = config.protocol + '://api.' + config.domain; // config.social_card = `${config.origin}/assets/img/screenshot.png`; diff --git a/packages/backend/src/routers/_default.js b/packages/backend/src/routers/_default.js index ff95a02aa2..23806b9efd 100644 --- a/packages/backend/src/routers/_default.js +++ b/packages/backend/src/routers/_default.js @@ -46,7 +46,7 @@ router.all('*', async function(req, res, next) { // cloud.js must be accessible globally regardless of subdomain // -------------------------------------- else if (path === '/cloud.js') { - return res.sendFile(_path.join(__dirname, '../../puter.js/alpha.js'), function (err) { + return res.sendFile(_path.join(__dirname, config.defaultjs_asset_path, 'puter.js/alpha.js'), function (err) { if (err && err.statusCode) { return res.status(err.statusCode).send('Error /cloud.js') } @@ -56,14 +56,14 @@ router.all('*', async function(req, res, next) { // /puter.js/v1 must be accessible globally regardless of subdomain // -------------------------------------- else if (path === '/puter.js/v1' || path === '/puter.js/v1/') { - return res.sendFile(_path.join(__dirname, '../../puter.js/v1.js'), function (err) { + return res.sendFile(_path.join(__dirname, config.defaultjs_asset_path, 'puter.js/v1.js'), function (err) { if (err && err.statusCode) { return res.status(err.statusCode).send('Error /puter.js') } }); } else if (path === '/puter.js/v2' || path === '/puter.js/v2/') { - return res.sendFile(_path.join(__dirname, '../../puter.js/v2.js'), function (err) { + return res.sendFile(_path.join(__dirname, config.defaultjs_asset_path, 'puter.js/v2.js'), function (err) { if (err && err.statusCode) { return res.status(err.statusCode).send('Error /puter.js') } @@ -74,14 +74,14 @@ router.all('*', async function(req, res, next) { // -------------------------------------- else if( subdomain === 'js'){ if (path === '/v1' || path === '/v1/') { - return res.sendFile(_path.join(__dirname, '../../puter.js/v1.js'), function (err) { + return res.sendFile(_path.join(__dirname, config.defaultjs_asset_path, 'puter.js/v1.js'), function (err) { if (err && err.statusCode) { return res.status(err.statusCode).send('Error /puter.js') } }); } if (path === '/v2' || path === '/v2/') { - return res.sendFile(_path.join(__dirname, '../../puter.js/v2.js'), function (err) { + return res.sendFile(_path.join(__dirname, config.defaultjs_asset_path, 'puter.js/v2.js'), function (err) { if (err && err.statusCode) { return res.status(err.statusCode).send('Error /puter.js') } @@ -364,7 +364,7 @@ router.all('*', async function(req, res, next) { subdomain === 'draw' || subdomain === 'camera' || subdomain === 'recorder' || subdomain === 'dev-center' || subdomain === 'terminal'){ - let root = _path.join(__dirname, '../../apps/', subdomain); + let root = _path.join(__dirname, config.defaultjs_asset_path, 'apps', subdomain); if ( subdomain === 'docs' ) root += '/dist'; root = _path.normalize(root); From e3f57ee20ef677cbc031d59cfa7ea6c161c34eb3 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 16 May 2024 18:24:50 -0400 Subject: [PATCH 0042/2119] Add path builder --- packages/backend/src/routers/_default.js | 11 ++++- packages/backend/src/util/pathutil.js | 60 ++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 2 deletions(-) create mode 100644 packages/backend/src/util/pathutil.js diff --git a/packages/backend/src/routers/_default.js b/packages/backend/src/routers/_default.js index 23806b9efd..ebbe2bdfba 100644 --- a/packages/backend/src/routers/_default.js +++ b/packages/backend/src/routers/_default.js @@ -26,6 +26,7 @@ const auth = require('../middleware/auth.js'); const { generate_puter_page_html } = require('../temp/puter_page_loader'); const { Context } = require('../util/context'); const { DB_READ } = require('../services/database/consts'); +const { PathBuilder } = require('../util/pathutil.js'); let auth_user; @@ -246,6 +247,7 @@ router.all('*', async function(req, res, next) { // /assets/ // ------------------------ else if (path.startsWith('/assets/')) { + path = PathBuilder.resolve(path); return res.sendFile(path, { root: __dirname + '../../public' }, function (err) { if (err && err.statusCode) { return res.status(err.statusCode).send('Error /public/') @@ -338,7 +340,7 @@ router.all('*', async function(req, res, next) { // /dist/... else if(path.startsWith('/dist/') || path.startsWith('/src/')){ - path = _path.resolve(path); + path = PathBuilder.resolve(path); return res.sendFile(path, {root: config.assets.gui}, function(err){ if(err && err.statusCode){ return res.status(err.statusCode).send('Error /gui/dist/') @@ -348,6 +350,7 @@ router.all('*', async function(req, res, next) { // All other paths else{ + path = PathBuilder.resolve(path); return res.sendFile(path, {root: _path.join(config.assets.gui, 'src')}, function(err){ if(err && err.statusCode){ return res.status(err.statusCode).send('Error /gui/') @@ -364,7 +367,11 @@ router.all('*', async function(req, res, next) { subdomain === 'draw' || subdomain === 'camera' || subdomain === 'recorder' || subdomain === 'dev-center' || subdomain === 'terminal'){ - let root = _path.join(__dirname, config.defaultjs_asset_path, 'apps', subdomain); + let root = PathBuilder + .add(__dirname) + .add(config.defaultjs_asset_path, { allow_traversal: true }) + .add('apps').add(subdomain) + .build(); if ( subdomain === 'docs' ) root += '/dist'; root = _path.normalize(root); diff --git a/packages/backend/src/util/pathutil.js b/packages/backend/src/util/pathutil.js new file mode 100644 index 0000000000..9069dc6615 --- /dev/null +++ b/packages/backend/src/util/pathutil.js @@ -0,0 +1,60 @@ +const { AdvancedBase } = require("@heyputer/puter-js-common"); + +/** + * PathBuilder implements the builder pattern for building paths. + * This makes it clear which path fragments are allowed to traverse + * to parent directories. + */ +class PathBuilder extends AdvancedBase { + static MODULES = { + path: require('path'), + } + + constructor() { + super(); + this.path_ = ''; + } + + static create () { + return new PathBuilder(); + } + + static add (fragment, options) { + return PathBuilder.create().add(fragment, options); + } + + static resolve (fragment) { + const p = PathBuilder.create(); + const require = p.require; + const node_path = require('path'); + fragment = node_path.resolve(fragment); + return p.add(fragment).build(); + } + + add (fragment, options) { + options = options || {}; + if ( ! options.allow_traversal ) { + fragment = fragment.replace(/(\.\.\/|\.\.\\)/g, ''); + if ( fragment === '..' ) { + fragment = ''; + } + } + + const require = this.require; + const node_path = require('path'); + + this.path_ = this.path_ + ? node_path.join(this.path_, fragment) + : fragment; + + return this; + } + + build () { + return this.path_; + } +} + +module.exports = { + PathBuilder, +}; From c55b1e4680bd009752f599da77b384f79ce9ccd9 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 16 May 2024 19:08:51 -0400 Subject: [PATCH 0043/2119] Remove verification requirement on contact us form --- packages/backend/src/routers/contactUs.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/packages/backend/src/routers/contactUs.js b/packages/backend/src/routers/contactUs.js index 80c92bda1b..6b8ae829b3 100644 --- a/packages/backend/src/routers/contactUs.js +++ b/packages/backend/src/routers/contactUs.js @@ -32,10 +32,6 @@ router.post('/contactUs', auth, express.json(), async (req, res, next)=>{ if(require('../helpers').subdomain(req) !== 'api') next(); - // check if user is verified - if(req.user.email_confirmed) - return res.status(400).send({code: 'account_is_not_verified', message: 'Account is not verified'}); - // message is required if(!req.body.message) return res.status(400).send({message: 'message is required'}) From 545fc103b8471f368412783418156333dac7cf07 Mon Sep 17 00:00:00 2001 From: Zac0511 Date: Fri, 17 May 2024 09:10:55 +0200 Subject: [PATCH 0044/2119] Update fr.js Complete rework of the file for the latest updates --- src/i18n/translations/fr.js | 361 ++++++++++++++++++++++-------------- 1 file changed, 217 insertions(+), 144 deletions(-) diff --git a/src/i18n/translations/fr.js b/src/i18n/translations/fr.js index d12d2614ad..671f808650 100644 --- a/src/i18n/translations/fr.js +++ b/src/i18n/translations/fr.js @@ -3,194 +3,267 @@ * * This file is part of Puter. * - * Puter 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. + * Puter est un logiciel libre : vous pouvez le redistribuer et/ou le modifier + * selon les termes de la GNU Affero General Public License publiée + * par la Free Software Foundation, soit la version 3 de la licence, soit + * (à votre choix) toute version ultérieure. * - * 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. + * Ce programme est distribué dans l'espoir qu'il sera utile, + * mais SANS AUCUNE GARANTIE ; sans même la garantie implicite de + * QUALITÉ MARCHANDE ou d'ADÉQUATION À UN OBJECTIF PARTICULIER. Voir la + * GNU Affero General Public License pour plus de détails. * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * Vous devriez avoir reçu une copie de la GNU Affero General Public License + * avec ce programme. Sinon, voir . */ const fr = { name: "Français", english_name: "French", code: "fr", dictionary: { + about: "À propos", + account: "Compte", + account_password: "Vérifiez le mot de passe du compte", access_granted_to: "Accès accordé à", add_existing_account: "Ajouter un compte existant", - all_fields_required: "Tous les champs sont obligatoires.", + all_fields_required: 'Tous les champs sont obligatoires.', apply: "Appliquer", - ascending: "Ascendant", + ascending: 'Ascendant', + auto_arrange: 'Disposition automatique', background: "Arrière-plan", browse: "Parcourir", - cancel: "Annuler", - center: "Centre", - change_desktop_background: "Changer l'arrière-plan du bureau…", + cancel: 'Annuler', + center: 'Centrer', + change_desktop_background: 'Changer le fond d'écran…', + change_email: "Changer l'adresse e-mail", + change_language: "Changer de langue", change_password: "Changer le mot de passe", + change_ui_colors: "Changer les couleurs de l'interface", change_username: "Changer le nom d'utilisateur", + close: 'Fermer', close_all_windows: "Fermer toutes les fenêtres", - color: "Couleur", - confirm_account_for_free_referral_storage_c2a: "Créez un compte et confirmez votre adresse e-mail pour recevoir 1 Go de stockage gratuit. Votre ami recevra également 1 Go de stockage gratuit.", + close_all_windows_confirm: "Êtes-vous sûr de vouloir fermer toutes les fenêtres?", + close_all_windows_and_log_out: 'Fermer les fenêtres et se déconnecter', + change_always_open_with: "Voulez-vous toujours ouvrir ce type de fichier avec", + color: 'Couleur', + hue: 'Teinte', + confirm_2fa_setup: 'J'ai ajouté le code à mon application d'authentification', + confirm_2fa_recovery: 'J'ai enregistré mes codes de récupération dans un endroit sûr', + confirm_account_for_free_referral_storage_c2a: 'Créez un compte et confirmez votre adresse e-mail pour recevoir 1 Go de stockage gratuit. Votre ami recevra également 1 Go de stockage gratuit.', + confirm_code_generic_incorrect: "Code incorrect.", + confirm_code_generic_too_many_requests: "Trop de demandes. Veuillez attendre quelques minutes.", + confirm_code_generic_submit: "Soumettre le code", + confirm_code_generic_try_again: "Réessayer", + confirm_code_generic_title: "Entrez le code de confirmation", + confirm_code_2fa_instruction: "Entrez le code à 6 chiffres de votre application d'authentification.", + confirm_code_2fa_submit_btn: "Soumettre", + confirm_code_2fa_title: "Entrez le code 2FA", + confirm_delete_multiple_items: 'Êtes-vous sûr de vouloir supprimer définitivement ces éléments?', + confirm_delete_single_item: 'Voulez-vous supprimer définitivement cet élément?', + confirm_open_apps_log_out: 'Vous avez des applications ouvertes. Êtes-vous sûr de vouloir vous déconnecter?', confirm_new_password: "Confirmer le nouveau mot de passe", - contact_us: "Contactez-nous", - contain: "Contenir", + confirm_delete_user: "Êtes-vous sûr de vouloir supprimer votre compte? Tous vos fichiers et données seront définitivement supprimés. Cette action est irréversible.", + confirm_delete_user_title: "Supprimer le compte?", + confirm_session_revoke: "Êtes-vous sûr de vouloir révoquer cette session?", + contact_us: "Nous contacter", + contact_us_verification_required: "Vous devez avoir une adresse e-mail vérifiée pour utiliser cette fonctionnalité.", + contain: 'Contenir', continue: "Continuer", - copy: "Copier", + copy: 'Copier', copy_link: "Copier le lien", copying: "Copie en cours", - cover: "Couverture", + copying_file: "Copie de %%", + cover: 'Couvrir', create_account: "Créer un compte", create_free_account: "Créer un compte gratuit", create_shortcut: "Créer un raccourci", + credits: "Crédits", current_password: "Mot de passe actuel", - cut: "Couper", - date_modified: "Date de modification", - delete: "Supprimer", + cut: 'Couper', + clock: "Horloge", + clock_visible_hide: 'Cacher - Toujours caché', + clock_visible_show: 'Afficher - Toujours visible', + clock_visible_auto: 'Auto - Par défaut, visible uniquement en mode plein écran.', + date_modified: 'Date modifiée', + default: 'Par défaut', + delete: 'Supprimer', + delete_account: "Supprimer le compte", delete_permanently: "Supprimer définitivement", - deploy_as_app: "Déployer en tant qu'application", - descending: "Descendant", + deleting_file: "Suppression de %%", + deploy_as_app: 'Déployer en tant qu'application', + descending: 'Descendant', desktop_background_fit: "Ajuster", - dir_published_as_website: `%strong% a été publié sur :`, + developers: "Développeurs", + dir_published_as_website: `%strong% a été publié à :`, + disable_2fa: 'Désactiver la 2FA', + disable_2fa_confirm: "Êtes-vous sûr de vouloir désactiver la 2FA?", + disable_2fa_instructions: "Entrez votre mot de passe pour désactiver la 2FA.", disassociate_dir: "Dissocier le répertoire", - download: "Télécharger", + download: 'Télécharger', + download_file: 'Télécharger le fichier', downloading: "Téléchargement en cours", email: "E-mail", + email_change_confirmation_sent: "Un e-mail de confirmation a été envoyé à votre nouvelle adresse e-mail. Veuillez vérifier votre boîte de réception et suivre les instructions pour terminer le processus.", + email_invalid: 'L\'adresse e-mail est invalide.', email_or_username: "E-mail ou nom d'utilisateur", - empty_trash: "Vider la corbeille", - empty_trash_confirmation: "Êtes-vous sûr de vouloir supprimer définitivement les éléments de la corbeille ?", - emptying_trash: "Vidage de la corbeille en cours…", + email_required: 'L\'adresse e-mail est obligatoire.', + empty_trash: 'Vider la corbeille', + empty_trash_confirmation: `Êtes-vous sûr de vouloir supprimer définitivement les éléments de la corbeille?`, + emptying_trash: 'Vidage de la corbeille en cours…', + enable_2fa: 'Activer la 2FA', + end_hard: "Terminer en force", + end_process_force_confirm: "Êtes-vous sûr de vouloir forcer l'arrêt de ce processus?", + end_soft: "Terminer doucement", + enlarged_qr_code: "Code QR agrandi", + enter_password_to_confirm_delete_user: "Entrez votre mot de passe pour confirmer la suppression du compte", + error_unknown_cause: "Une erreur inconnue s'est produite.", + error_uploading_files: "Échec du téléchargement des fichiers", feedback: "Retour d'information", feedback_c2a: "Veuillez utiliser le formulaire ci-dessous pour nous envoyer vos commentaires, suggestions et rapports de bogues.", - feedback_sent_confirmation: "Merci de nous avoir contactés. Si vous avez un e-mail associé à votre compte, vous recevrez une réponse de notre part dès que possible.", - forgot_pass_c2a: "Mot de passe oublié ?", + feedback_sent_confirmation: "Merci de nous avoir contactés. Si vous avez un e-mail associé à votre compte, vous recevrez une réponse dès que possible.", + fit: "Ajuster", + force_quit: 'Forcer la fermeture', + forgot_pass_c2a: "Mot de passe oublié?", from: "De", general: "Général", - get_a_copy_of_on_puter: `Obtenez une copie de '%%' sur Puter.com !`, - get_copy_link: "Obtenir un lien de copie", + get_a_copy_of_on_puter: `Obtenez une copie de '%%' sur Puter.com!`, + get_copy_link: 'Obtenir le lien de copie', hide_all_windows: "Masquer toutes les fenêtres", - html_document: "Document HTML", - image: "Image", + html_document: 'Document HTML', + image: 'Image', + incorrect_password: "Mot de passe incorrect", invite_link: "Lien d'invitation", - items_in_trash_cannot_be_renamed: "Cet élément ne peut pas être renommé car il se trouve dans la corbeille. Pour renommer cet élément, déplacez-le d'abord hors de la corbeille.", - jpeg_image: "Image JPEG", - keep_in_taskbar: "Garder dans la barre des tâches", + item: 'élément', + items_in_trash_cannot_be_renamed: `Cet élément ne peut pas être renommé car il est dans la corbeille. Pour renommer cet élément, sortez-le d'abord de la corbeille.`, + jpeg_image: 'Image JPEG', + keep_in_taskbar: 'Garder dans la barre des tâches', + language: "Langue", + license: "Licence", + lightness: 'Luminosité', + link_copied: "Lien copié", + loading: 'Chargement', log_in: "Se connecter", - log_out: "Se déconnecter", - move: "Déplacer", - moving_file: "Déplacement en cours %%", + log_into_another_account_anyway: 'Se connecter à un autre compte quand même', + log_out: 'Se déconnecter', + looks_good: "Ça a l'air bien!", + manage_sessions: "Gérer les sessions", + move: 'Déplacer', + moving_file: "Déplacement de %%", my_websites: "Mes sites web", - name: "Nom", - name_cannot_be_empty: "Le nom ne peut pas être vide.", - name_cannot_contain_double_period: "Le nom ne peut pas contenir deux points ('..').", - name_cannot_contain_period: "Le nom ne peut pas contenir de point ('.').", - name_cannot_contain_slash: "Le nom ne peut pas contenir de slash ('/').", - name_must_be_string: "Le nom ne peut être qu'une chaîne de caractères.", - name_too_long: "Le nom ne peut pas dépasser %% caractères.", - new: "Nouveau", - new_folder: "Nouveau dossier", + name: 'Nom', + name_cannot_be_empty: 'Le nom ne peut pas être vide.', + name_cannot_contain_double_period: "Le nom ne peut pas être '..'.", + name_cannot_contain_period: "Le nom ne peut pas être '.'.", + name_cannot_contain_slash: "Le nom ne peut pas contenir '/'.", + name_must_be_string: "Le nom doit être une chaîne de caractères.", + name_too_long: `Le nom ne peut pas dépasser %% caractères.`, + new_file: 'Nouveau fichier', + new_folder: 'Nouveau dossier', new_password: "Nouveau mot de passe", - new_username: "Nouveau nom d'utilisateur", - no_dir_associated_with_site: "Aucun répertoire associé à cette adresse.", - no_websites_published: "Vous n'avez publié aucun site web pour le moment.", - ok: "OK", - open: "Ouvrir", - open_in_new_tab: "Ouvrir dans un nouvel onglet", - open_in_new_window: "Ouvrir dans une nouvelle fenêtre", - open_with: "Ouvrir avec", + new_password_must_be_different: "Le nouveau mot de passe doit être différent de l'ancien.", + new_site: "Nouveau site", + new_website: "Nouveau site web", + next: "Suivant", + no_access: "Pas d'accès", + no_app_to_open_file: 'Aucune application installée pour ouvrir ce fichier.', + no_email_on_account: "Aucune adresse e-mail associée à ce compte.", + no_files_or_folders_here_yet: 'Pas encore de fichiers ou de dossiers ici', + no_notifications: "Pas de notifications", + no_open_apps: "Pas d'applications ouvertes", + notifications: "Notifications", + notifications_for: "Notifications pour", + not_logged_in: "Non connecté", + old_password: "Ancien mot de passe", + open: 'Ouvrir', + open_containing_folder: 'Ouvrir le dossier contenant', + open_in_browser: 'Ouvrir dans le navigateur', + options: "Options", + paste: 'Coller', password: "Mot de passe", - password_changed: "Mot de passe modifié.", - passwords_do_not_match: "Les champs 'Nouveau mot de passe' et 'Confirmer le nouveau mot de passe' ne correspondent pas.", - paste: "Coller", - paste_into_folder: "Coller dans le dossier", - pick_name_for_website: "Choisissez un nom pour votre site web :", - picture: "Image", - powered_by_puter_js: "Propulsé par {{link=docs}}Puter.js{{/link}}", - preparing: "Préparation en cours...", - preparing_for_upload: "Préparation du téléchargement en cours...", + password_change_success: "Mot de passe changé avec succès.", + password_must_be_at_least_characters: "Le mot de passe doit contenir au moins %% caractères.", + password_required: 'Le mot de passe est obligatoire.', + passwords_must_match: 'Les mots de passe doivent correspondre.', + paste_link: "Coller le lien", + permission_denied: "Permission refusée", + permission_denied_read_only_storage: "Le stockage est en lecture seule.", + photo: 'Photo', + please_provide_an_account_password: 'Veuillez fournir un mot de passe pour le compte.', + preferences: 'Préférences', + press_esc_to_exit_full_screen: "Appuyez sur Échap pour quitter le mode plein écran.", + profile: 'Profil', properties: "Propriétés", publish: "Publier", - publish_as_website: "Publier en tant que site web", - recent: "Récent", - recover_password: "Récupérer le mot de passe", - refer_friends_c2a: "Obtenez 1 Go pour chaque ami qui crée et confirme un compte sur Puter. Votre ami recevra également 1 Go !", - refer_friends_social_media_c2a: "Obtenez 1 Go de stockage gratuit sur Puter.com !", - refresh: "Actualiser", - release_address_confirmation: "Êtes-vous sûr de vouloir libérer cette adresse ?", - remove_from_taskbar: "Supprimer de la barre des tâches", - rename: "Renommer", - repeat: "Répéter", - resend_confirmation_code: "Renvoyer le code de confirmation", - restore: "Restaurer", - save_account_to_get_copy_link: "Veuillez créer un compte pour continuer.", - save_account_to_publish: "Veuillez créer un compte pour continuer.", - save_session_c2a: "Créez un compte pour enregistrer votre session en cours et éviter de perdre votre travail.", - scan_qr_c2a: "Scannez le code ci-dessous pour vous connecter à cette session depuis d'autres appareils", - select: "Sélectionner", - select_color: "Sélectionner la couleur…", - send: "Envoyer", - send_password_recovery_email: "Envoyer un e-mail de récupération de mot de passe", - session_saved: "Merci d'avoir créé un compte. Cette session a été enregistrée.", - set_new_password: "Définir un nouveau mot de passe", - share_to: "Partager sur", - show_all_windows: "Afficher toutes les fenêtres", - show_hidden: "Afficher les éléments masqués", - sign_in_with_puter: "Se connecter avec Puter", + publish_now: 'Publier maintenant', + publishing_file: "Publication de %%", + qrcode: 'Code QR', + qrcode_invalid: 'Le code QR n'est pas valide.', + recover: "Récupérer", + recover_account: "Récupérer le compte", + recover_files: 'Récupérer les fichiers', + recovery_email_sent: "Un e-mail de récupération a été envoyé à votre adresse e-mail.", + refresh: 'Rafraîchir', + remove: "Retirer", + rename: 'Renommer', + renaming_file: "Renommage de %%", + required: 'Obligatoire', + reset: 'Réinitialiser', + reset_password: 'Réinitialiser le mot de passe', + restore: 'Restaurer', + rotate: 'Pivoter', + save: "Sauvegarder", + save_as: 'Enregistrer sous', + saving: 'Sauvegarde en cours', + screen_saver: 'Économiseur d\'écran', + search: 'Rechercher', + security: 'Sécurité', + select: 'Sélectionner', + select_all: 'Tout sélectionner', + send: 'Envoyer', + send_feedback: 'Envoyer des commentaires', + settings: 'Paramètres', + share: 'Partager', + shortcut: 'Raccourci', + sign_in: "Se connecter", + sign_in_with: 'Se connecter avec', sign_up: "S'inscrire", - signing_in: "Connexion en cours...", - size: "Taille", - sort_by: "Trier par", - start: "Démarrer", - taking_longer_than_usual: "Cela prend un peu plus de temps que d'habitude. Veuillez patienter...", - text_document: "Document texte", - tos_fineprint: "En cliquant sur 'Créer un compte gratuit', vous acceptez les {{link=terms}}Conditions d'utilisation{{/link}} et la {{link=privacy}}Politique de confidentialité{{/link}} de Puter.", - trash: "Corbeille", - type: "Type", - undo: "Annuler", - unzip: "Décompresser", - upload: "Téléverser", - upload_here: "Téléverser ici", + size: 'Taille', + something_went_wrong: 'Quelque chose s\'est mal passé.', + status: 'Statut', + storage_quota_exceeded: "Quota de stockage dépassé", + support: 'Support', + take_screenshot: 'Prendre une capture d\'écran', + taskbar: 'Barre des tâches', + tasks: 'Tâches', + terms_of_service: "Conditions d'utilisation", + time: 'Heure', + time_format: 'Format de l\'heure', + today: "Aujourd'hui", + tools: 'Outils', + trash: 'Corbeille', + try_again: 'Réessayer', + type: 'Type', + type_a_message: 'Tapez un message…', + unknown: "Inconnu", + unlock: "Déverrouiller", + untitled: "Sans titre", + upload: 'Télécharger', + uploading: "Téléchargement en cours", username: "Nom d'utilisateur", - username_changed: "Nom d'utilisateur mis à jour avec succès.", - versions: "Versions", - yes_release_it: "Oui, le libérer", - you_have_been_referred_to_puter_by_a_friend: "Vous avez été recommandé à Puter par un ami !", - zip: "Compresser", - zipping_file: "Compression de %strong%", - - // === 2FA Setup === - setup2fa_1_step_heading: 'Ouvrez votre application Authenticator', - setup2fa_1_instructions: ` - Vous pouvez utiliser n'importe quelle application d'authentification prenant en charge le protocole TOTP (Time-based One-Time Password). - Il y a beaucoup de choix, mais si vous n'êtes pas sûr - Authy - est un bon choix pour Android et iOS - `, - setup2fa_2_step_heading: 'Scannez le QR code', - setup2fa_3_step_heading: 'Entrez le code à 6 chiffres', - setup2fa_4_step_heading: 'Copiez vos codes de récupération', - setup2fa_4_instructions: ` - Ces codes de récupération sont le seul moyen d'accéder à votre compte si vous perdez votre téléphone ou si vous ne pouvez pas utiliser votre application d'authentification. - Assurez-vous de les conserver dans un endroit sûr. - `, - setup2fa_5_step_heading: 'Confirmer la configuration A2F', - setup2fa_5_confirmation_1: 'J\'ai enregistré mes codes de récupération dans un emplacement sécurisé', - setup2fa_5_confirmation_2: 'Je suis prêt à activer l\'A2F', - setup2fa_5_button: 'Activer l\'A2F', - - // === 2FA Login === - login2fa_otp_title: 'Entrez le code A2F', - login2fa_otp_instructions: 'Saisissez le code à 6 chiffres de votre application Authenticator', - login2fa_recovery_title: 'Entrez un code de récupération', - login2fa_recovery_instructions: 'Entrez l\'un de vos codes de récupération pour accéder à votre compte.', - login2fa_use_recovery_code: 'Utiliser un code de récupération', - login2fa_recovery_back: 'Retour', - login2fa_recovery_placeholder: 'XXXXXXXX', + username_cannot_be_empty: "Le nom d'utilisateur ne peut pas être vide.", + username_or_password_invalid: "Nom d'utilisateur ou mot de passe invalide.", + username_required: "Le nom d'utilisateur est obligatoire.", + video: 'Vidéo', + visibility: 'Visibilité', + web_app: 'Application web', + website: 'Site web', + website_name: "Nom du site", + website_url: "URL du site", + windows: 'Fenêtres', + wrong_password: "Mauvais mot de passe", + yes: "Oui", + yesterday: "Hier" } -} +}; export default fr; From 9c39b0453db00398c85f773a35c94d476b6442a7 Mon Sep 17 00:00:00 2001 From: Zac0511 Date: Fri, 17 May 2024 09:16:12 +0200 Subject: [PATCH 0045/2119] Update fr.js Little update for some bugs --- src/i18n/translations/fr.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/i18n/translations/fr.js b/src/i18n/translations/fr.js index 671f808650..3bc82d1add 100644 --- a/src/i18n/translations/fr.js +++ b/src/i18n/translations/fr.js @@ -47,7 +47,7 @@ const fr = { change_always_open_with: "Voulez-vous toujours ouvrir ce type de fichier avec", color: 'Couleur', hue: 'Teinte', - confirm_2fa_setup: 'J'ai ajouté le code à mon application d'authentification', + confirm_2fa_setup: 'J'ai ajouté le code à mon application d\'authentification', confirm_2fa_recovery: 'J'ai enregistré mes codes de récupération dans un endroit sûr', confirm_account_for_free_referral_storage_c2a: 'Créez un compte et confirmez votre adresse e-mail pour recevoir 1 Go de stockage gratuit. Votre ami recevra également 1 Go de stockage gratuit.', confirm_code_generic_incorrect: "Code incorrect.", @@ -90,7 +90,7 @@ const fr = { delete_account: "Supprimer le compte", delete_permanently: "Supprimer définitivement", deleting_file: "Suppression de %%", - deploy_as_app: 'Déployer en tant qu'application', + deploy_as_app: 'Déployer en tant qu\'application', descending: 'Descendant', desktop_background_fit: "Ajuster", developers: "Développeurs", From 5f47e7f0fa02938a248521936542432aeab73591 Mon Sep 17 00:00:00 2001 From: Zac0511 Date: Fri, 17 May 2024 09:55:25 +0200 Subject: [PATCH 0046/2119] Update fr.js Bug repairing... again --- src/i18n/translations/fr.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/i18n/translations/fr.js b/src/i18n/translations/fr.js index 3bc82d1add..4d94a6adb6 100644 --- a/src/i18n/translations/fr.js +++ b/src/i18n/translations/fr.js @@ -48,7 +48,7 @@ const fr = { color: 'Couleur', hue: 'Teinte', confirm_2fa_setup: 'J'ai ajouté le code à mon application d\'authentification', - confirm_2fa_recovery: 'J'ai enregistré mes codes de récupération dans un endroit sûr', + confirm_2fa_recovery: 'J\'ai enregistré mes codes de récupération dans un endroit sûr', confirm_account_for_free_referral_storage_c2a: 'Créez un compte et confirmez votre adresse e-mail pour recevoir 1 Go de stockage gratuit. Votre ami recevra également 1 Go de stockage gratuit.', confirm_code_generic_incorrect: "Code incorrect.", confirm_code_generic_too_many_requests: "Trop de demandes. Veuillez attendre quelques minutes.", @@ -123,7 +123,7 @@ const fr = { feedback_sent_confirmation: "Merci de nous avoir contactés. Si vous avez un e-mail associé à votre compte, vous recevrez une réponse dès que possible.", fit: "Ajuster", force_quit: 'Forcer la fermeture', - forgot_pass_c2a: "Mot de passe oublié?", + forgot_pass_c2a: "Mot de passe oublié ?", from: "De", general: "Général", get_a_copy_of_on_puter: `Obtenez une copie de '%%' sur Puter.com!`, @@ -197,7 +197,7 @@ const fr = { publish_now: 'Publier maintenant', publishing_file: "Publication de %%", qrcode: 'Code QR', - qrcode_invalid: 'Le code QR n'est pas valide.', + qrcode_invalid: 'Le code QR n\'est pas valide.', recover: "Récupérer", recover_account: "Récupérer le compte", recover_files: 'Récupérer les fichiers', From 8f19f4dc5b2e931a28e635d8af7f4b1c3b6ce9b7 Mon Sep 17 00:00:00 2001 From: Zac0511 Date: Fri, 17 May 2024 13:58:33 +0200 Subject: [PATCH 0047/2119] Update fr.js Complete rework of the file, completly remade from en.js --- src/i18n/translations/fr.js | 379 ++++++++++++++++++++---------------- 1 file changed, 216 insertions(+), 163 deletions(-) diff --git a/src/i18n/translations/fr.js b/src/i18n/translations/fr.js index 4d94a6adb6..f7537acb71 100644 --- a/src/i18n/translations/fr.js +++ b/src/i18n/translations/fr.js @@ -3,88 +3,88 @@ * * This file is part of Puter. * - * Puter est un logiciel libre : vous pouvez le redistribuer et/ou le modifier - * selon les termes de la GNU Affero General Public License publiée - * par la Free Software Foundation, soit la version 3 de la licence, soit - * (à votre choix) toute version ultérieure. + * Puter 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. * - * Ce programme est distribué dans l'espoir qu'il sera utile, - * mais SANS AUCUNE GARANTIE ; sans même la garantie implicite de - * QUALITÉ MARCHANDE ou d'ADÉQUATION À UN OBJECTIF PARTICULIER. Voir la - * GNU Affero General Public License pour plus de détails. + * 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. * - * Vous devriez avoir reçu une copie de la GNU Affero General Public License - * avec ce programme. Sinon, voir . + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ const fr = { name: "Français", english_name: "French", code: "fr", dictionary: { - about: "À propos", + about: "A propos", account: "Compte", - account_password: "Vérifiez le mot de passe du compte", + account_password: "Vérifier le mot de passe du compte", access_granted_to: "Accès accordé à", add_existing_account: "Ajouter un compte existant", - all_fields_required: 'Tous les champs sont obligatoires.', + all_fields_required: 'Tous les champs sont requis.', apply: "Appliquer", ascending: 'Ascendant', - auto_arrange: 'Disposition automatique', + auto_arrange: 'Organisation automatique', background: "Arrière-plan", browse: "Parcourir", cancel: 'Annuler', center: 'Centrer', - change_desktop_background: 'Changer le fond d'écran…', - change_email: "Changer l'adresse e-mail", + change_desktop_background: 'Changer l’arrière-plan du bureau…', + change_email: "Changer l'e-mail", change_language: "Changer de langue", change_password: "Changer le mot de passe", - change_ui_colors: "Changer les couleurs de l'interface", - change_username: "Changer le nom d'utilisateur", + change_ui_colors: "Changer les couleurs d'interface", + change_username: "Change le nom d'utilisateur", close: 'Fermer', close_all_windows: "Fermer toutes les fenêtres", - close_all_windows_confirm: "Êtes-vous sûr de vouloir fermer toutes les fenêtres?", + close_all_windows_confirm: "Êtes-vous sûr de vouloir fermer toutes les fenêtres ?", close_all_windows_and_log_out: 'Fermer les fenêtres et se déconnecter', change_always_open_with: "Voulez-vous toujours ouvrir ce type de fichier avec", color: 'Couleur', hue: 'Teinte', - confirm_2fa_setup: 'J'ai ajouté le code à mon application d\'authentification', - confirm_2fa_recovery: 'J\'ai enregistré mes codes de récupération dans un endroit sûr', - confirm_account_for_free_referral_storage_c2a: 'Créez un compte et confirmez votre adresse e-mail pour recevoir 1 Go de stockage gratuit. Votre ami recevra également 1 Go de stockage gratuit.', + confirm_2fa_setup: 'J\'ai ajouté le code à mon application d\'authentification', + confirm_2fa_recovery: 'J\'ai enregistré mes codes de récupération dans un emplacement sécurisé', + confirm_account_for_free_referral_storage_c2a: 'Créez un compte et confirmez votre adresse e-mail pour recevoir 1 Go de stockage gratuit. Votre ami bénéficiera également de 1 Go de stockage gratuit.', confirm_code_generic_incorrect: "Code incorrect.", - confirm_code_generic_too_many_requests: "Trop de demandes. Veuillez attendre quelques minutes.", - confirm_code_generic_submit: "Soumettre le code", + confirm_code_generic_too_many_requests: "Trop de demandes. Veuillez patienter quelques minutes.", + confirm_code_generic_submit: "Envoyer le code", confirm_code_generic_try_again: "Réessayer", confirm_code_generic_title: "Entrez le code de confirmation", - confirm_code_2fa_instruction: "Entrez le code à 6 chiffres de votre application d'authentification.", - confirm_code_2fa_submit_btn: "Soumettre", - confirm_code_2fa_title: "Entrez le code 2FA", - confirm_delete_multiple_items: 'Êtes-vous sûr de vouloir supprimer définitivement ces éléments?', - confirm_delete_single_item: 'Voulez-vous supprimer définitivement cet élément?', - confirm_open_apps_log_out: 'Vous avez des applications ouvertes. Êtes-vous sûr de vouloir vous déconnecter?', + confirm_code_2fa_instruction: "Saisissez le code à 6 chiffres de votre application d'authentification.", + confirm_code_2fa_submit_btn: "Valider", + confirm_code_2fa_title: "Entrez le code A2F", + confirm_delete_multiple_items: 'Êtes-vous sûr de vouloir supprimer définitivement ces éléments ?', + confirm_delete_single_item: 'Voulez-vous supprimer définitivement cet élément ?', + confirm_open_apps_log_out: 'Vous avez des applications ouvertes. Êtes-vous sûr de vouloir vous déconnecter ?', confirm_new_password: "Confirmer le nouveau mot de passe", - confirm_delete_user: "Êtes-vous sûr de vouloir supprimer votre compte? Tous vos fichiers et données seront définitivement supprimés. Cette action est irréversible.", - confirm_delete_user_title: "Supprimer le compte?", - confirm_session_revoke: "Êtes-vous sûr de vouloir révoquer cette session?", + confirm_delete_user: "Êtes-vous sûr de vouloir supprimer votre compte ? Tous vos fichiers et données seront définitivement supprimés. Cette action est irréversible.", + confirm_delete_user_title: "Supprimer le compte ?", + confirm_session_revoke: "Êtes-vous sûr de vouloir révoquer cette session ?", contact_us: "Nous contacter", - contact_us_verification_required: "Vous devez avoir une adresse e-mail vérifiée pour utiliser cette fonctionnalité.", + contact_us_verification_required: "Vous devez disposer d'une adresse e-mail vérifiée pour pouvoir utiliser ceci.", contain: 'Contenir', continue: "Continuer", copy: 'Copier', copy_link: "Copier le lien", - copying: "Copie en cours", - copying_file: "Copie de %%", - cover: 'Couvrir', + copying: "Copie...", + copying_file: "Copie de %%...", + cover: 'Couverture', create_account: "Créer un compte", - create_free_account: "Créer un compte gratuit", + create_free_account: "Créer un compte gratuitement", create_shortcut: "Créer un raccourci", credits: "Crédits", current_password: "Mot de passe actuel", cut: 'Couper', clock: "Horloge", - clock_visible_hide: 'Cacher - Toujours caché', + clock_visible_hide: 'Cacher - Toujours cachée', clock_visible_show: 'Afficher - Toujours visible', clock_visible_auto: 'Auto - Par défaut, visible uniquement en mode plein écran.', - date_modified: 'Date modifiée', + date_modified: 'Date de modification', default: 'Par défaut', delete: 'Supprimer', delete_account: "Supprimer le compte", @@ -94,39 +94,39 @@ const fr = { descending: 'Descendant', desktop_background_fit: "Ajuster", developers: "Développeurs", - dir_published_as_website: `%strong% a été publié à :`, - disable_2fa: 'Désactiver la 2FA', - disable_2fa_confirm: "Êtes-vous sûr de vouloir désactiver la 2FA?", - disable_2fa_instructions: "Entrez votre mot de passe pour désactiver la 2FA.", + dir_published_as_website: `%strong% a été publié sur :`, + disable_2fa: 'Désactiver l\'A2F', + disable_2fa_confirm: "Êtes-vous sûr de vouloir désactiver l\'A2F ?", + disable_2fa_instructions: "Entrez votre mot de passe pour désactiver l\'A2F.", disassociate_dir: "Dissocier le répertoire", download: 'Télécharger', download_file: 'Télécharger le fichier', downloading: "Téléchargement en cours", email: "E-mail", email_change_confirmation_sent: "Un e-mail de confirmation a été envoyé à votre nouvelle adresse e-mail. Veuillez vérifier votre boîte de réception et suivre les instructions pour terminer le processus.", - email_invalid: 'L\'adresse e-mail est invalide.', + email_invalid: 'L\'e-mail n\'est pas valide.', email_or_username: "E-mail ou nom d'utilisateur", - email_required: 'L\'adresse e-mail est obligatoire.', + email_required: 'Un e-mail est requis.', empty_trash: 'Vider la corbeille', - empty_trash_confirmation: `Êtes-vous sûr de vouloir supprimer définitivement les éléments de la corbeille?`, - emptying_trash: 'Vidage de la corbeille en cours…', - enable_2fa: 'Activer la 2FA', - end_hard: "Terminer en force", - end_process_force_confirm: "Êtes-vous sûr de vouloir forcer l'arrêt de ce processus?", - end_soft: "Terminer doucement", + empty_trash_confirmation: `Êtes-vous sûr de vouloir supprimer définitivement les éléments de la corbeille ?`, + emptying_trash: 'Vidage de la corbeille...', + enable_2fa: 'Activer l\'A2F', + end_hard: "Forcer l'ârret", + end_process_force_confirm: "Êtes-vous sûr de vouloir forcer l'arrêt de ce processus ?", + end_soft: "Quitter", enlarged_qr_code: "Code QR agrandi", - enter_password_to_confirm_delete_user: "Entrez votre mot de passe pour confirmer la suppression du compte", - error_unknown_cause: "Une erreur inconnue s'est produite.", - error_uploading_files: "Échec du téléchargement des fichiers", - feedback: "Retour d'information", - feedback_c2a: "Veuillez utiliser le formulaire ci-dessous pour nous envoyer vos commentaires, suggestions et rapports de bogues.", - feedback_sent_confirmation: "Merci de nous avoir contactés. Si vous avez un e-mail associé à votre compte, vous recevrez une réponse dès que possible.", + enter_password_to_confirm_delete_user: "Entrez votre mot passe pour confirmer la supression du compte", + error_unknown_cause: "Une erreur inconnue s'est produite", + error_uploading_files: "Échec de l'importation des fichiers", + feedback: "Commentaires", + feedback_c2a: "Veuillez utiliser le formulaire ci-dessous pour nous envoyer vos retours, commentaires et rapports de bugs.", + feedback_sent_confirmation: "Merci de nous contacter. Si vous avez un e-mail associé à votre compte, vous recevrez une réponse de notre part dans les plus brefs délais.", fit: "Ajuster", - force_quit: 'Forcer la fermeture', + force_quit: 'Forcer l\'arrêt', forgot_pass_c2a: "Mot de passe oublié ?", - from: "De", + from: "Depuis", general: "Général", - get_a_copy_of_on_puter: `Obtenez une copie de '%%' sur Puter.com!`, + get_a_copy_of_on_puter: `Obtenez une copie de '%%' sur Puter.com !`, get_copy_link: 'Obtenir le lien de copie', hide_all_windows: "Masquer toutes les fenêtres", html_document: 'Document HTML', @@ -134,7 +134,7 @@ const fr = { incorrect_password: "Mot de passe incorrect", invite_link: "Lien d'invitation", item: 'élément', - items_in_trash_cannot_be_renamed: `Cet élément ne peut pas être renommé car il est dans la corbeille. Pour renommer cet élément, sortez-le d'abord de la corbeille.`, + items_in_trash_cannot_be_renamed: `Cet élément ne peut pas être renommé car il se trouve dans la corbeille. Pour renommer cet élément, faites-le d'abord glisser hors de la corbeille.`, jpeg_image: 'Image JPEG', keep_in_taskbar: 'Garder dans la barre des tâches', language: "Langue", @@ -145,124 +145,177 @@ const fr = { log_in: "Se connecter", log_into_another_account_anyway: 'Se connecter à un autre compte quand même', log_out: 'Se déconnecter', - looks_good: "Ça a l'air bien!", + looks_good: "Ça a l'air bien !", manage_sessions: "Gérer les sessions", move: 'Déplacer', moving_file: "Déplacement de %%", - my_websites: "Mes sites web", + my_websites: "Mes sites internet", name: 'Nom', name_cannot_be_empty: 'Le nom ne peut pas être vide.', - name_cannot_contain_double_period: "Le nom ne peut pas être '..'.", - name_cannot_contain_period: "Le nom ne peut pas être '.'.", - name_cannot_contain_slash: "Le nom ne peut pas contenir '/'.", - name_must_be_string: "Le nom doit être une chaîne de caractères.", - name_too_long: `Le nom ne peut pas dépasser %% caractères.`, - new_file: 'Nouveau fichier', + name_cannot_contain_double_period: "Le nom ne peut pas être le caractère '..'.", + name_cannot_contain_period: "Le nom ne peut pas être le caractère '.'.", + name_cannot_contain_slash: "Le nom ne peut pas contenir le caractère '/'.", + name_must_be_string: "Le nom ne peut être qu'une chaîne.", + name_too_long: `Le nom ne peut pas contenir plus de %% caractères.`, + new: 'Nouveau', + new_email: 'Nouvel e-mail', new_folder: 'Nouveau dossier', new_password: "Nouveau mot de passe", - new_password_must_be_different: "Le nouveau mot de passe doit être différent de l'ancien.", - new_site: "Nouveau site", - new_website: "Nouveau site web", - next: "Suivant", - no_access: "Pas d'accès", - no_app_to_open_file: 'Aucune application installée pour ouvrir ce fichier.', - no_email_on_account: "Aucune adresse e-mail associée à ce compte.", - no_files_or_folders_here_yet: 'Pas encore de fichiers ou de dossiers ici', - no_notifications: "Pas de notifications", - no_open_apps: "Pas d'applications ouvertes", - notifications: "Notifications", - notifications_for: "Notifications pour", - not_logged_in: "Non connecté", - old_password: "Ancien mot de passe", - open: 'Ouvrir', - open_containing_folder: 'Ouvrir le dossier contenant', - open_in_browser: 'Ouvrir dans le navigateur', - options: "Options", - paste: 'Coller', + new_username: "Nouveau nom d'utilisateur", + no: 'Non', + no_dir_associated_with_site: 'Aucun répertoire associé à cette adresse.', + no_websites_published: "Vous n'avez pas encore publié de sites internet.", + ok: 'OK', + open: "Ouvrir", + open_in_new_tab: "Ouvrir dans un nouvel onglet", + open_in_new_window: "Ouvrir dans une nouvelle fenêtre", + open_with: "Ouvrir avec", + oss_code_and_content: "Logiciels et contenu open source", password: "Mot de passe", - password_change_success: "Mot de passe changé avec succès.", - password_must_be_at_least_characters: "Le mot de passe doit contenir au moins %% caractères.", - password_required: 'Le mot de passe est obligatoire.', - passwords_must_match: 'Les mots de passe doivent correspondre.', - paste_link: "Coller le lien", - permission_denied: "Permission refusée", - permission_denied_read_only_storage: "Le stockage est en lecture seule.", - photo: 'Photo', - please_provide_an_account_password: 'Veuillez fournir un mot de passe pour le compte.', - preferences: 'Préférences', - press_esc_to_exit_full_screen: "Appuyez sur Échap pour quitter le mode plein écran.", - profile: 'Profil', + password_changed: "Mot de passe modifié.", + password_recovery_rate_limit: "Vous avez atteint notre limite de débit ; veuillez patienter quelques minutes. Pour éviter cela à l'avenir, évitez de recharger la page trop de fois.", + password_recovery_token_invalid: "Ce jeton de récupération de mot de passe n'est plus valide.", + password_recovery_unknown_error: "Une erreur inconnue s'est produite. Veuillez réessayer plus tard.", + password_required: 'Mot de passe requis.', + password_strength_error: "Le mot de passe doit comporter au moins 8 caractères et contenir au moins une lettre majuscule, une lettre minuscule, un chiffre et un caractère spécial.", + passwords_do_not_match: '`Nouveau mot de passe` et `Confirmer le nouveau mot de passe` ne correspondent pas.', + paste: 'Coller', + paste_into_folder: "Coller dans le dossier", + personalization: "Personnalisation", + pick_name_for_website: "Choisissez un nom pour votre site internet :", + picture: "Image", + plural_suffix: 's', + powered_by_puter_js: `Propulsé par {{link=docs}}Puter.js{{/link}}`, + preparing: "Préparation...", + preparing_for_upload: "Préparation de l'importation...", + print: 'Imprimer', + privacy: "Confidentialité", + proceed_to_login: 'Procéder à la connexion', + proceed_with_account_deletion: "Procéder à la suppression du compte", + process_status_initializing: "Initialisation", + process_status_running: "En cours", + process_type_app: 'Application', + process_type_init: 'Init', + process_type_ui: 'IU', properties: "Propriétés", publish: "Publier", - publish_now: 'Publier maintenant', - publishing_file: "Publication de %%", - qrcode: 'Code QR', - qrcode_invalid: 'Le code QR n\'est pas valide.', - recover: "Récupérer", - recover_account: "Récupérer le compte", - recover_files: 'Récupérer les fichiers', - recovery_email_sent: "Un e-mail de récupération a été envoyé à votre adresse e-mail.", - refresh: 'Rafraîchir', - remove: "Retirer", + publish_as_website: 'Publier en tant que site internet', + puter_description: `Puter est un cloud personnel axé sur la confidentialité pour conserver tous vos fichiers, applications et jeux en un seul + endroit sécurisé, accessible de partout et à tout moment.`, + reading_file: "Lecture de %strong%", + recent: "Récent", + recommended: "Recommandé", + recover_password: "Récupérer le mot de passe", + refer_friends_c2a: "Obtenez 1 Go pour chaque ami qui crée et confirme un compte sur Puter. Votre ami recevra également 1 Go !", + refer_friends_social_media_c2a: `Obtenez 1 Go de stockage gratuit sur Puter.com !`, + refresh: 'Actualiser', + release_address_confirmation: `Etes-vous sûr de vouloir libérer cette adresse ?`, + remove_from_taskbar: 'Retirer de la barre des tâches', rename: 'Renommer', - renaming_file: "Renommage de %%", - required: 'Obligatoire', - reset: 'Réinitialiser', - reset_password: 'Réinitialiser le mot de passe', - restore: 'Restaurer', - rotate: 'Pivoter', - save: "Sauvegarder", - save_as: 'Enregistrer sous', - saving: 'Sauvegarde en cours', - screen_saver: 'Économiseur d\'écran', - search: 'Rechercher', - security: 'Sécurité', - select: 'Sélectionner', - select_all: 'Tout sélectionner', - send: 'Envoyer', - send_feedback: 'Envoyer des commentaires', - settings: 'Paramètres', - share: 'Partager', - shortcut: 'Raccourci', - sign_in: "Se connecter", - sign_in_with: 'Se connecter avec', + repeat: 'Répéter', + replace: 'Remplacer', + replace_all: 'Tout remplacer', + resend_confirmation_code: "Renvoyer le code de confirmation", + reset_colors: "Réinitialiser les couleurs", + restart_puter_confirm: "Êtes-vous sûr de vouloir redémarrer Puter ?", + restore: "Restaurer", + saturation: 'Saturation', + save_account: 'Enregistrer le compte', + save_account_to_get_copy_link: "Veuillez créer un compte pour continuer.", + save_account_to_publish: 'Veuillez créer un compte pour continuer.', + save_session: 'Sauvegarder la session', + save_session_c2a: 'Créez un compte pour enregistrer votre session actuelle et éviter de perdre votre travail.', + scan_qr_c2a: 'Scannez le code ci-dessous\npour vous connecter à cette session depuis d\'autres appareils', + scan_qr_2fa: 'Scan the QR code with your authenticator app', + scan_qr_generic: 'Scannez ce code QR à l\'aide de votre téléphone ou d\'un autre appareil', + seconds: 'secondes', + security: "Sécurité", + select: "Sélectionner", + selected: 'sélectionné', + select_color: 'Sélectionnez la couleur…', + sessions: "Sessions", + send: "Envoyer", + send_password_recovery_email: "Envoyer un e-mail de récupération de mot de passe", + session_saved: "Merci d'avoir créé un compte. Cette session a été sauvegardée.", + settings: "Paramètres", + set_new_password: "Definir un nouveau mot de passe", + share_to: "Partager à", + show_all_windows: "Afficher toutes les fenêtres", + show_hidden: 'Afficher les fichiers cachés', + sign_in_with_puter: "Se connecter avec Puter", sign_up: "S'inscrire", + signing_in: "Connexion…", size: 'Taille', - something_went_wrong: 'Quelque chose s\'est mal passé.', - status: 'Statut', - storage_quota_exceeded: "Quota de stockage dépassé", - support: 'Support', - take_screenshot: 'Prendre une capture d\'écran', - taskbar: 'Barre des tâches', - tasks: 'Tâches', - terms_of_service: "Conditions d'utilisation", - time: 'Heure', - time_format: 'Format de l\'heure', - today: "Aujourd'hui", - tools: 'Outils', + skip: 'Passer', + something_went_wrong: "Quelque chose s'est mal passé.", + sort_by: 'Trier par', + start: 'Démarrer', + status: "Statut", + storage_usage: "Utilisation du stockage", + storage_puter_used: 'utilisé par Puter', + taking_longer_than_usual: "Cela prend un peu plus de temps que d'habitude. Veuillez patienter...", + task_manager: "Gestionnaire des tâches", + taskmgr_header_name: "Nom", + taskmgr_header_status: "Statut", + taskmgr_header_type: "Type", + terms: "Termes", + text_document: 'Document texte', + tos_fineprint: `En cliquant sur "Créer un compte gratuit", vous acceptez les {{link=terms}}Conditions d'utilisation{{/link}} et la {{link=privacy}}Politique de confidentialité{{/link}} de Puter.`, + transparency: "Transparence", trash: 'Corbeille', - try_again: 'Réessayer', + two_factor: 'Authentification à deux facteurs', + two_factor_disabled: 'A2F désactivée', + two_factor_enabled: 'A2F activée', type: 'Type', - type_a_message: 'Tapez un message…', - unknown: "Inconnu", - unlock: "Déverrouiller", - untitled: "Sans titre", - upload: 'Télécharger', - uploading: "Téléchargement en cours", + type_confirm_to_delete_account: "Tapez 'confirm' pour supprimer votre compte.", + ui_colors: "Couleurs d'interface", + ui_manage_sessions: "Gestionnaire de sessions", + ui_revoke: "Révoquer", + undo: 'Annuler', + unlimited: 'Illimité', + unzip: "Décompresser", + upload: 'Importer', + upload_here: 'Importer ici', + usage: 'Usage', username: "Nom d'utilisateur", - username_cannot_be_empty: "Le nom d'utilisateur ne peut pas être vide.", - username_or_password_invalid: "Nom d'utilisateur ou mot de passe invalide.", - username_required: "Le nom d'utilisateur est obligatoire.", - video: 'Vidéo', + username_changed: 'Nom d\'utilisateur mis à jour avec succès.', + username_required: 'Le nom d\'utilisateur est requis.', + versions: "Versions", visibility: 'Visibilité', - web_app: 'Application web', - website: 'Site web', - website_name: "Nom du site", - website_url: "URL du site", - windows: 'Fenêtres', - wrong_password: "Mauvais mot de passe", - yes: "Oui", - yesterday: "Hier" + yes: 'Oui', + yes_release_it: 'Oui, libérez-la', + you_have_been_referred_to_puter_by_a_friend: "Vous avez été recommandé à Puter par un ami !", + zip: "Compresser", + zipping_file: "Compression de %strong%", + + // === 2FA Setup === + setup2fa_1_step_heading: 'Ouvrez votre application d'authentification', + setup2fa_1_instructions: ` + Vous pouvez utiliser n'importe quelle application d'authentification prenant en charge le protocole TOTP (Time-based One-Time Password). + Il y a beaucoup de choix, mais si vous n'êtes pas sûr + Authy + est un choix solide pour Android et iOS. + `, + setup2fa_2_step_heading: 'Scannez le code QR', + setup2fa_3_step_heading: 'Entrez le code à 6 chiffres', + setup2fa_4_step_heading: 'Copiez vos codes de récupération', + setup2fa_4_instructions: ` + Ces codes de récupération sont le seul moyen d'accéder à votre compte si vous perdez votre téléphone ou si vous ne pouvez pas utiliser votre application d'authentification. + Assurez-vous de les conserver dans un endroit sûr. + `, + setup2fa_5_step_heading: 'Confirmer la configuration de l\'A2F', + setup2fa_5_confirmation_1: 'J\'ai enregistré mes codes de récupération dans un emplacement sécurisé', + setup2fa_5_confirmation_2: 'Je suis prêt à activer l\'A2F', + setup2fa_5_button: 'Activer l\'A2F', + + // === 2FA Login === + login2fa_otp_title: 'Entrez le code A2F', + login2fa_otp_instructions: 'Saisissez le code à 6 chiffres de votre application d\'authentification.', + login2fa_recovery_title: 'Entrez un code de récupération', + login2fa_recovery_instructions: 'Entrez l\'un de vos codes de récupération pour accéder à votre compte.', + login2fa_use_recovery_code: 'Utiliser un code de récupération', + login2fa_recovery_back: 'Retour', + login2fa_recovery_placeholder: 'XXXXXXXX', } }; From e0af914c902d6f607afe4c825d9ba208113bc418 Mon Sep 17 00:00:00 2001 From: Zac0511 Date: Fri, 17 May 2024 14:00:43 +0200 Subject: [PATCH 0048/2119] Update fr.js --- src/i18n/translations/fr.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/i18n/translations/fr.js b/src/i18n/translations/fr.js index f7537acb71..7ea28bc087 100644 --- a/src/i18n/translations/fr.js +++ b/src/i18n/translations/fr.js @@ -289,7 +289,7 @@ const fr = { zipping_file: "Compression de %strong%", // === 2FA Setup === - setup2fa_1_step_heading: 'Ouvrez votre application d'authentification', + setup2fa_1_step_heading: 'Ouvrez votre application d\'authentification', setup2fa_1_instructions: ` Vous pouvez utiliser n'importe quelle application d'authentification prenant en charge le protocole TOTP (Time-based One-Time Password). Il y a beaucoup de choix, mais si vous n'êtes pas sûr @@ -300,7 +300,7 @@ const fr = { setup2fa_3_step_heading: 'Entrez le code à 6 chiffres', setup2fa_4_step_heading: 'Copiez vos codes de récupération', setup2fa_4_instructions: ` - Ces codes de récupération sont le seul moyen d'accéder à votre compte si vous perdez votre téléphone ou si vous ne pouvez pas utiliser votre application d'authentification. + Ces codes de récupération sont le seul moyen d'accéder à votre compte si vous perdez votre téléphone ou si vous ne pouvez pas utiliser votre application d\'authentification. Assurez-vous de les conserver dans un endroit sûr. `, setup2fa_5_step_heading: 'Confirmer la configuration de l\'A2F', From f9b53530580bc00c18cf90fa07f5302ce5c0c7e0 Mon Sep 17 00:00:00 2001 From: Zac0511 Date: Fri, 17 May 2024 14:15:49 +0200 Subject: [PATCH 0049/2119] Update fr.js --- src/i18n/translations/fr.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/i18n/translations/fr.js b/src/i18n/translations/fr.js index 7ea28bc087..1710592c43 100644 --- a/src/i18n/translations/fr.js +++ b/src/i18n/translations/fr.js @@ -304,15 +304,15 @@ const fr = { Assurez-vous de les conserver dans un endroit sûr. `, setup2fa_5_step_heading: 'Confirmer la configuration de l\'A2F', - setup2fa_5_confirmation_1: 'J\'ai enregistré mes codes de récupération dans un emplacement sécurisé', - setup2fa_5_confirmation_2: 'Je suis prêt à activer l\'A2F', - setup2fa_5_button: 'Activer l\'A2F', + setup2fa_5_confirmation_1: "J'ai enregistré mes codes de récupération dans un emplacement sécurisé", + setup2fa_5_confirmation_2: "Je suis prêt à activer l'A2F", + setup2fa_5_button: "Activer l'A2F", // === 2FA Login === login2fa_otp_title: 'Entrez le code A2F', - login2fa_otp_instructions: 'Saisissez le code à 6 chiffres de votre application d\'authentification.', + login2fa_otp_instructions: "Saisissez le code à 6 chiffres de votre application d'authentification.", login2fa_recovery_title: 'Entrez un code de récupération', - login2fa_recovery_instructions: 'Entrez l\'un de vos codes de récupération pour accéder à votre compte.', + login2fa_recovery_instructions: "Entrez l'un de vos codes de récupération pour accéder à votre compte.", login2fa_use_recovery_code: 'Utiliser un code de récupération', login2fa_recovery_back: 'Retour', login2fa_recovery_placeholder: 'XXXXXXXX', From eaf1e96fa227074196d97b1f28db05edb9e8f509 Mon Sep 17 00:00:00 2001 From: Zac0511 Date: Fri, 17 May 2024 14:19:19 +0200 Subject: [PATCH 0050/2119] Update fr.js --- src/i18n/translations/fr.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/i18n/translations/fr.js b/src/i18n/translations/fr.js index 1710592c43..3471e97e2e 100644 --- a/src/i18n/translations/fr.js +++ b/src/i18n/translations/fr.js @@ -47,8 +47,8 @@ const fr = { change_always_open_with: "Voulez-vous toujours ouvrir ce type de fichier avec", color: 'Couleur', hue: 'Teinte', - confirm_2fa_setup: 'J\'ai ajouté le code à mon application d\'authentification', - confirm_2fa_recovery: 'J\'ai enregistré mes codes de récupération dans un emplacement sécurisé', + confirm_2fa_setup: "J'ai ajouté le code à mon application d'authentification", + confirm_2fa_recovery: "J'ai enregistré mes codes de récupération dans un emplacement sécurisé", confirm_account_for_free_referral_storage_c2a: 'Créez un compte et confirmez votre adresse e-mail pour recevoir 1 Go de stockage gratuit. Votre ami bénéficiera également de 1 Go de stockage gratuit.', confirm_code_generic_incorrect: "Code incorrect.", confirm_code_generic_too_many_requests: "Trop de demandes. Veuillez patienter quelques minutes.", @@ -90,14 +90,14 @@ const fr = { delete_account: "Supprimer le compte", delete_permanently: "Supprimer définitivement", deleting_file: "Suppression de %%", - deploy_as_app: 'Déployer en tant qu\'application', + deploy_as_app: "Déployer en tant qu'application", descending: 'Descendant', desktop_background_fit: "Ajuster", developers: "Développeurs", dir_published_as_website: `%strong% a été publié sur :`, - disable_2fa: 'Désactiver l\'A2F', - disable_2fa_confirm: "Êtes-vous sûr de vouloir désactiver l\'A2F ?", - disable_2fa_instructions: "Entrez votre mot de passe pour désactiver l\'A2F.", + disable_2fa: "Désactiver l'A2F", + disable_2fa_confirm: "Êtes-vous sûr de vouloir désactiver l'A2F ?", + disable_2fa_instructions: "Entrez votre mot de passe pour désactiver l'A2F.", disassociate_dir: "Dissocier le répertoire", download: 'Télécharger', download_file: 'Télécharger le fichier', From 99ca8755f30f954b9940f9b723de1248ff65a821 Mon Sep 17 00:00:00 2001 From: Zac0511 Date: Fri, 17 May 2024 14:22:22 +0200 Subject: [PATCH 0051/2119] Update fr.js --- src/i18n/translations/fr.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/i18n/translations/fr.js b/src/i18n/translations/fr.js index 3471e97e2e..1bdb6a7fd4 100644 --- a/src/i18n/translations/fr.js +++ b/src/i18n/translations/fr.js @@ -300,7 +300,7 @@ const fr = { setup2fa_3_step_heading: 'Entrez le code à 6 chiffres', setup2fa_4_step_heading: 'Copiez vos codes de récupération', setup2fa_4_instructions: ` - Ces codes de récupération sont le seul moyen d'accéder à votre compte si vous perdez votre téléphone ou si vous ne pouvez pas utiliser votre application d\'authentification. + Ces codes de récupération sont le seul moyen d'accéder à votre compte si vous perdez votre téléphone ou si vous ne pouvez pas utiliser votre application d'authentification. Assurez-vous de les conserver dans un endroit sûr. `, setup2fa_5_step_heading: 'Confirmer la configuration de l\'A2F', From 340b9202c05ec40e8528fd6a21f7e59933601904 Mon Sep 17 00:00:00 2001 From: Zac0511 Date: Fri, 17 May 2024 14:36:54 +0200 Subject: [PATCH 0052/2119] Update fr.js --- src/i18n/translations/fr.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/i18n/translations/fr.js b/src/i18n/translations/fr.js index 1bdb6a7fd4..998dcb142a 100644 --- a/src/i18n/translations/fr.js +++ b/src/i18n/translations/fr.js @@ -94,7 +94,7 @@ const fr = { descending: 'Descendant', desktop_background_fit: "Ajuster", developers: "Développeurs", - dir_published_as_website: `%strong% a été publié sur :`, + dir_published_as_website: `%strong% a été publié sur :`, disable_2fa: "Désactiver l'A2F", disable_2fa_confirm: "Êtes-vous sûr de vouloir désactiver l'A2F ?", disable_2fa_instructions: "Entrez votre mot de passe pour désactiver l'A2F.", @@ -108,7 +108,7 @@ const fr = { email_or_username: "E-mail ou nom d'utilisateur", email_required: 'Un e-mail est requis.', empty_trash: 'Vider la corbeille', - empty_trash_confirmation: `Êtes-vous sûr de vouloir supprimer définitivement les éléments de la corbeille ?`, + empty_trash_confirmation: `Êtes-vous sûr de vouloir supprimer définitivement les éléments de la corbeille ?`, emptying_trash: 'Vidage de la corbeille...', enable_2fa: 'Activer l\'A2F', end_hard: "Forcer l'ârret", @@ -126,7 +126,7 @@ const fr = { forgot_pass_c2a: "Mot de passe oublié ?", from: "Depuis", general: "Général", - get_a_copy_of_on_puter: `Obtenez une copie de '%%' sur Puter.com !`, + get_a_copy_of_on_puter: `Obtenez une copie de '%%' sur Puter.com !`, get_copy_link: 'Obtenir le lien de copie', hide_all_windows: "Masquer toutes les fenêtres", html_document: 'Document HTML', @@ -156,7 +156,7 @@ const fr = { name_cannot_contain_period: "Le nom ne peut pas être le caractère '.'.", name_cannot_contain_slash: "Le nom ne peut pas contenir le caractère '/'.", name_must_be_string: "Le nom ne peut être qu'une chaîne.", - name_too_long: `Le nom ne peut pas contenir plus de %% caractères.`, + name_too_long: `Le nom ne peut pas contenir plus de %% caractères.`, new: 'Nouveau', new_email: 'Nouvel e-mail', new_folder: 'Nouveau dossier', @@ -207,9 +207,9 @@ const fr = { recommended: "Recommandé", recover_password: "Récupérer le mot de passe", refer_friends_c2a: "Obtenez 1 Go pour chaque ami qui crée et confirme un compte sur Puter. Votre ami recevra également 1 Go !", - refer_friends_social_media_c2a: `Obtenez 1 Go de stockage gratuit sur Puter.com !`, + refer_friends_social_media_c2a: `Obtenez 1 Go de stockage gratuit sur Puter.com !`, refresh: 'Actualiser', - release_address_confirmation: `Etes-vous sûr de vouloir libérer cette adresse ?`, + release_address_confirmation: `Etes-vous sûr de vouloir libérer cette adresse ?`, remove_from_taskbar: 'Retirer de la barre des tâches', rename: 'Renommer', repeat: 'Répéter', From a9c89cef19986da6ae5660ec4acb363a0aaf015f Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Fri, 17 May 2024 14:32:15 +0100 Subject: [PATCH 0053/2119] refactor: Reduce boilerplate for returning errors from puter.fs.upload() --- .../modules/FileSystem/operations/upload.js | 37 +++++++------------ 1 file changed, 13 insertions(+), 24 deletions(-) diff --git a/packages/puter-js/src/modules/FileSystem/operations/upload.js b/packages/puter-js/src/modules/FileSystem/operations/upload.js index 90bbff0138..b32da230e6 100644 --- a/packages/puter-js/src/modules/FileSystem/operations/upload.js +++ b/packages/puter-js/src/modules/FileSystem/operations/upload.js @@ -15,16 +15,19 @@ const upload = async function(items, dirPath, options = {}){ } } + const error = (e) => { + // if error callback is provided, call it + if(options.error && typeof options.error === 'function') + options.error(e); + return reject(e); + }; + // xhr object to be used for the upload let xhr = new XMLHttpRequest(); // Can not write to root - if(dirPath === '/'){ - // if error callback is provided, call it - if(options.error && typeof options.error === 'function') - options.error('Can not upload to root directory.'); - return reject('Can not upload to root directory.'); - } + if(dirPath === '/') + return error('Can not upload to root directory.'); // If dirPath is not provided or it's not starting with a slash, it means it's a relative path // in that case, we need to prepend the app's root directory to it @@ -145,10 +148,7 @@ const upload = async function(items, dirPath, options = {}){ // Continue only if there are actually any files/directories to upload if(dirs.length === 0 && files.length === 0){ - if(options.error && typeof options.error === 'function'){ - options.error({code: 'EMPTY_UPLOAD', message: 'No files or directories to upload.'}); - } - return reject({code: 'EMPTY_UPLOAD', message: 'No files or directories to upload.'}); + return error({code: 'EMPTY_UPLOAD', message: 'No files or directories to upload.'}); } // Check storage capacity. @@ -163,10 +163,7 @@ const upload = async function(items, dirPath, options = {}){ try{ storage = await this.space(); if(storage.capacity - storage.used < total_size){ - if(options.error && typeof options.error === 'function'){ - options.error({code: 'NOT_ENOUGH_SPACE', message: 'Not enough storage space available.'}); - } - return reject({code: 'NOT_ENOUGH_SPACE', message: 'Not enough storage space available.'}); + return error({code: 'NOT_ENOUGH_SPACE', message: 'Not enough storage space available.'}); } }catch(e){ // Ignored @@ -368,18 +365,10 @@ const upload = async function(items, dirPath, options = {}){ break; } } - // if error callback is provided, call it - if(options.error && typeof options.error === 'function'){ - options.error(failed_operation); - } - return reject(failed_operation); + return error(failed_operation); } - // if error callback is provided, call it - if(options.error && typeof options.error === 'function'){ - options.error(resp); - } - return reject(resp); + return error(resp); } // Success else{ From 03fe3b6a0db14ce32a0640dc48a95de94a1e6038 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Fri, 17 May 2024 14:38:46 +0100 Subject: [PATCH 0054/2119] Reject invalid types for puter.fs.upload() items or .write() data Previously, this would crash in upload() when trying to iterate the `entries` array, which is undefined when the `items` parameter is an unsupported type. --- .../puter-js/src/modules/FileSystem/operations/upload.js | 6 +++++- .../puter-js/src/modules/FileSystem/operations/write.js | 5 +++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/packages/puter-js/src/modules/FileSystem/operations/upload.js b/packages/puter-js/src/modules/FileSystem/operations/upload.js index b32da230e6..ab8778ea9b 100644 --- a/packages/puter-js/src/modules/FileSystem/operations/upload.js +++ b/packages/puter-js/src/modules/FileSystem/operations/upload.js @@ -122,7 +122,11 @@ const upload = async function(items, dirPath, options = {}){ entries[i].filepath = entries[i].name; entries[i].fullPath = entries[i].name; } - } + } + // Anything else is invalid + else { + return error({ code: 'field_invalid', message: 'upload() items parameter is an invalid type' }); + } // Will hold directories and files to be uploaded let dirs = []; diff --git a/packages/puter-js/src/modules/FileSystem/operations/write.js b/packages/puter-js/src/modules/FileSystem/operations/write.js index 6ed2fd1a5c..c1319ad4b6 100644 --- a/packages/puter-js/src/modules/FileSystem/operations/write.js +++ b/packages/puter-js/src/modules/FileSystem/operations/write.js @@ -46,6 +46,11 @@ const write = async function (targetPath, data, options = {}) { if(!data) data = new File([data ?? ''], filename); + // data should be a File now. If it's not, it's an unsupported type + if (!(data instanceof File)) { + throw new Error({ code: 'field_invalid', message: 'write() data parameter is an invalid type' }); + } + // perform upload return this.upload(data, parent, options); } From 6900233c5aaa2d1a49f495e9f9a060796757a91e Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Fri, 17 May 2024 15:30:48 +0100 Subject: [PATCH 0055/2119] fix: Remove null or duplicate app entries from suggest_app_for_fsentry() --- packages/backend/src/helpers.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/helpers.js b/packages/backend/src/helpers.js index d102309e0a..e2b80964bf 100644 --- a/packages/backend/src/helpers.js +++ b/packages/backend/src/helpers.js @@ -1770,7 +1770,15 @@ async function suggest_app_for_fsentry(fsentry, options){ monitor.end(); // return list - return suggested_apps; + return suggested_apps.filter((suggested_app, pos, self) => { + // Remove any null values caused by calling `get_app()` for apps that don't exist. + // This happens on self-host because we don't include `code`, among others. + if (!suggested_app) + return false; + + // Remove any duplicate entries + return self.indexOf(suggested_app) === pos; + }); } function build_item_object(item){ From e4543c5f35f9dd895508b197ee76834c537ff8ce Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 17 May 2024 12:32:16 -0400 Subject: [PATCH 0056/2119] Fix 8688ggu00 (2) --- packages/backend/src/util/pathutil.js | 9 +++++---- src/IPC.js | 3 ++- 2 files changed, 7 insertions(+), 5 deletions(-) diff --git a/packages/backend/src/util/pathutil.js b/packages/backend/src/util/pathutil.js index 9069dc6615..928db0bd7f 100644 --- a/packages/backend/src/util/pathutil.js +++ b/packages/backend/src/util/pathutil.js @@ -32,17 +32,18 @@ class PathBuilder extends AdvancedBase { } add (fragment, options) { + const require = this.require; + const node_path = require('path'); + options = options || {}; if ( ! options.allow_traversal ) { - fragment = fragment.replace(/(\.\.\/|\.\.\\)/g, ''); + fragment = node_path.normalize(fragment); + fragment = fragment.replace(/(\.+\/|\.+\\)/g, ''); if ( fragment === '..' ) { fragment = ''; } } - const require = this.require; - const node_path = require('path'); - this.path_ = this.path_ ? node_path.join(this.path_, fragment) : fragment; diff --git a/src/IPC.js b/src/IPC.js index 9f87909d11..a04cba01a2 100644 --- a/src/IPC.js +++ b/src/IPC.js @@ -1016,7 +1016,8 @@ window.addEventListener('message', async (event) => { let create_missing_ancestors = false; console.warn(`The method ${event.data.msg} is deprecated - see docs.puter.com for more information.`); - event.data.filename = event.data.filename.replace(/(\.\.\/|\.\.\\)/g, ''); + event.data.filename = path.normalize(event.data.filename) + .replace(/(\.+\/|\.+\\)/g, ''); if(event.data.msg === 'saveToPictures') target_path = path.join(window.pictures_path, event.data.filename); From f964f06f3fc1a826e9263acd8a7b784f7b3d6014 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 17 May 2024 13:04:21 -0400 Subject: [PATCH 0057/2119] Fix 8688h4bwg --- packages/phoenix/src/main_puter.js | 1 - 1 file changed, 1 deletion(-) diff --git a/packages/phoenix/src/main_puter.js b/packages/phoenix/src/main_puter.js index a7449c4530..2102fc0781 100644 --- a/packages/phoenix/src/main_puter.js +++ b/packages/phoenix/src/main_puter.js @@ -62,7 +62,6 @@ window.main_shell = async () => { if ( config['puter.auth.token'] ) { await puterSDK.setAuthToken(config['puter.auth.token']); } - await puterSDK.setAPIOrigin(config['puter.api_origin']); const ptt = new XDocumentPTT(terminal); await launchPuterShell(new Context({ From 639e40d355c6603b4815ada86d1b2a7d58e3e37b Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 17 May 2024 13:26:44 -0400 Subject: [PATCH 0058/2119] Phoenix shell deployment update --- packages/phoenix/config/release.js | 3 +-- packages/phoenix/tools/build_tar.sh | 8 ++++---- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/packages/phoenix/config/release.js b/packages/phoenix/config/release.js index 45e3cbc474..03352ff379 100644 --- a/packages/phoenix/config/release.js +++ b/packages/phoenix/config/release.js @@ -17,7 +17,6 @@ * along with this program. If not, see . */ globalThis.__CONFIG__ = { - origin: location.origin, - 'shell.href': location.origin + '/puter-shell/', + origin: "https://xd.puter.sh", sdk_url: 'https://puter.com/puter.js/v2', }; diff --git a/packages/phoenix/tools/build_tar.sh b/packages/phoenix/tools/build_tar.sh index c064787ba0..274e192434 100755 --- a/packages/phoenix/tools/build_tar.sh +++ b/packages/phoenix/tools/build_tar.sh @@ -15,7 +15,7 @@ mkdir -p release/puter-shell cp -r ./dist/* ./release -cd ../dev-puter-shell -npx rollup -c rollup.config.js -cp -r ./dist/* ../phoenix/release/puter-shell -cd - +# cd ../dev-puter-shell +# npx rollup -c rollup.config.js +# cp -r ./dist/* ../phoenix/release/puter-shell +# cd - From 8cca06799142753b0fec8b6316f77e5bbb7c0972 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 17 May 2024 22:55:40 -0400 Subject: [PATCH 0059/2119] Fix 8688ha84v --- packages/backend/src/routers/_default.js | 9 ++++++++- packages/backend/src/routers/change_email.js | 15 +++++++++++++++ packages/backend/src/routers/confirm-email.js | 17 +++++++++++++++++ 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/routers/_default.js b/packages/backend/src/routers/_default.js index ebbe2bdfba..3579e533e4 100644 --- a/packages/backend/src/routers/_default.js +++ b/packages/backend/src/routers/_default.js @@ -209,7 +209,7 @@ router.all('*', async function(req, res, next) { const {get_user} = require('../helpers') // get user - const user = await get_user({uuid: req.query.user_uuid}) + const user = await get_user({uuid: req.query.user_uuid, force: true}) // more validation if(user === undefined || user === null || user === false) @@ -220,6 +220,13 @@ router.all('*', async function(req, res, next) { h += '

invalid token.

'; // mark user as confirmed else{ + // If other users have the same unconfirmed email, revoke it + await db.write( + 'UPDATE `user` SET `unconfirmed_change_email` = NULL, `change_email_confirm_token` = NULL WHERE `unconfirmed_change_email` = ?', + [user.email], + ); + + // update user await db.write( "UPDATE `user` SET `email_confirmed` = 1, `requires_email_confirmation` = 0 WHERE id = ?", [user.id] diff --git a/packages/backend/src/routers/change_email.js b/packages/backend/src/routers/change_email.js index 5a6f81edd0..9ff54301e9 100644 --- a/packages/backend/src/routers/change_email.js +++ b/packages/backend/src/routers/change_email.js @@ -53,6 +53,21 @@ const CHANGE_EMAIL_CONFIRM = eggspress('/change_email/confirm', { throw APIError.create('token_invalid'); } + // Scenario: email was confirmed on another account already + const rows2 = await db.read( + 'SELECT `id` FROM `user` WHERE `email` = ?', + [rows[0].unconfirmed_change_email] + ); + if ( rows2.length > 0 ) { + throw APIError.create('email_already_in_use'); + } + + // If other users have the same unconfirmed email, revoke it + await db.write( + 'UPDATE `user` SET `unconfirmed_change_email` = NULL, `change_email_confirm_token` = NULL WHERE `unconfirmed_change_email` = ?', + [rows[0].unconfirmed_change_email] + ); + const new_email = rows[0].unconfirmed_change_email; await db.write( diff --git a/packages/backend/src/routers/confirm-email.js b/packages/backend/src/routers/confirm-email.js index 023205cd36..839ebb2e52 100644 --- a/packages/backend/src/routers/confirm-email.js +++ b/packages/backend/src/routers/confirm-email.js @@ -22,6 +22,7 @@ const { invalidate_cached_user } = require('../helpers'); const router = new express.Router(); const auth = require('../middleware/auth.js'); const { DB_WRITE } = require('../services/database/consts'); +const APIError = require('../api/APIError.js'); // -----------------------------------------------------------------------// // POST /confirm-email @@ -48,6 +49,22 @@ router.post('/confirm-email', auth, express.json(), async (req, res, next)=>{ // Set expiry for rate limit kv.expire(`confirm-email|${req.ip}|${req.body.email ?? req.body.username}`, 60 * 10, 'NX') + // Scenario: email was confirmed on another account already + const rows = await db.read( + 'SELECT `id` FROM `user` WHERE `email` = ? AND `email_confirmed` = 1', + [req.body.email], + ); + if ( rows.length > 0 ) { + APIError.create('email_already_in_use').write(res); + return; + } + + // If other users have the same unconfirmed email, revoke it + await db.write( + 'UPDATE `user` SET `unconfirmed_change_email` = NULL, `change_email_confirm_token` = NULL WHERE `unconfirmed_change_email` = ?', + [req.user.email], + ); + if(req.body.code === req.user.email_confirm_code) { await db.write( "UPDATE `user` SET `email_confirmed` = 1, `requires_email_confirmation` = 0 WHERE id = ? LIMIT 1", From cc45a08388e460f4c30961de4db47675227b8f0d Mon Sep 17 00:00:00 2001 From: Karan Parmar Date: Sun, 19 May 2024 11:39:21 +0530 Subject: [PATCH 0060/2119] updated the github links displayed in the Terminal welcome message --- packages/phoenix/src/puter-shell/main.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/packages/phoenix/src/puter-shell/main.js b/packages/phoenix/src/puter-shell/main.js index f0e85f6d14..87f95f9315 100644 --- a/packages/phoenix/src/puter-shell/main.js +++ b/packages/phoenix/src/puter-shell/main.js @@ -45,8 +45,8 @@ const decorator_registry = { }; const GH_LINK = { - 'terminal': 'https://github.com/HeyPuter/terminal', - 'phoenix': 'https://github.com/HeyPuter/phoenix', + 'terminal': 'https://github.com/HeyPuter/puter/tree/main/packages/terminal', + 'phoenix': 'https://github.com/HeyPuter/puter/tree/main/packages/phoenix', }; export const launchPuterShell = async (ctx) => { From e798576a871bda3b7a2d0cf75581740bac0da106 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Thu, 16 May 2024 10:11:20 +0100 Subject: [PATCH 0061/2119] Move PosixError into puter-js-common The in-progress git client also needs to use this. puter-js-common uses commonjs modules, so it had to be adjusted for that. --- .../phoenix/src/platform/node/filesystem.js | 2 +- .../phoenix/src/platform/puter/filesystem.js | 2 +- .../src/puter-shell/coreutils/errno.js | 2 +- .../src/puter-shell/coreutils/touch.js | 2 +- packages/phoenix/test/coreutils/errno.js | 2 +- .../src}/PosixError.js | 19 +++++++++++++------ 6 files changed, 18 insertions(+), 11 deletions(-) rename packages/{phoenix/src/platform => puter-js-common/src}/PosixError.js (94%) diff --git a/packages/phoenix/src/platform/node/filesystem.js b/packages/phoenix/src/platform/node/filesystem.js index 85b9e84ccc..d8ae99943d 100644 --- a/packages/phoenix/src/platform/node/filesystem.js +++ b/packages/phoenix/src/platform/node/filesystem.js @@ -20,7 +20,7 @@ import fs from 'fs'; import path_ from 'path'; import modeString from 'fs-mode-to-string'; -import { ErrorCodes, PosixError } from '../PosixError.js'; +import { ErrorCodes, PosixError } from '@heyputer/puter-js-common/src/PosixError.js'; function convertNodeError(e) { switch (e.code) { diff --git a/packages/phoenix/src/platform/puter/filesystem.js b/packages/phoenix/src/platform/puter/filesystem.js index ca60e2fe94..4227156190 100644 --- a/packages/phoenix/src/platform/puter/filesystem.js +++ b/packages/phoenix/src/platform/puter/filesystem.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { ErrorCodes, PosixError } from '../PosixError.js'; +import { ErrorCodes, PosixError } from '@heyputer/puter-js-common/src/PosixError.js'; function convertPuterError(e) { // Handle Puter SDK errors diff --git a/packages/phoenix/src/puter-shell/coreutils/errno.js b/packages/phoenix/src/puter-shell/coreutils/errno.js index dd36d8dd46..db74b2f685 100644 --- a/packages/phoenix/src/puter-shell/coreutils/errno.js +++ b/packages/phoenix/src/puter-shell/coreutils/errno.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { ErrorCodes, ErrorMetadata, errorFromIntegerCode } from '../../platform/PosixError.js'; +import { ErrorCodes, ErrorMetadata, errorFromIntegerCode } from '@heyputer/puter-js-common/src/PosixError.js'; import { Exit } from './coreutil_lib/exit.js'; const maxErrorNameLength = Object.keys(ErrorCodes) diff --git a/packages/phoenix/src/puter-shell/coreutils/touch.js b/packages/phoenix/src/puter-shell/coreutils/touch.js index 8f15f13c6e..5b32067ad0 100644 --- a/packages/phoenix/src/puter-shell/coreutils/touch.js +++ b/packages/phoenix/src/puter-shell/coreutils/touch.js @@ -18,7 +18,7 @@ */ import { Exit } from './coreutil_lib/exit.js'; import { resolveRelativePath } from '../../util/path.js'; -import { ErrorCodes } from '../../platform/PosixError.js'; +import { ErrorCodes } from '@heyputer/puter-js-common/src/PosixError.js'; export default { name: 'touch', diff --git a/packages/phoenix/test/coreutils/errno.js b/packages/phoenix/test/coreutils/errno.js index fbb63b53b9..34fc786763 100644 --- a/packages/phoenix/test/coreutils/errno.js +++ b/packages/phoenix/test/coreutils/errno.js @@ -19,7 +19,7 @@ import assert from 'assert'; import { MakeTestContext } from './harness.js' import builtins from '../../src/puter-shell/coreutils/__exports__.js'; -import { ErrorCodes, ErrorMetadata } from '../../src/platform/PosixError.js'; +import { ErrorCodes, ErrorMetadata } from '@heyputer/puter-js-common/src/PosixError.js'; export const runErrnoTests = () => { describe('errno', function () { diff --git a/packages/phoenix/src/platform/PosixError.js b/packages/puter-js-common/src/PosixError.js similarity index 94% rename from packages/phoenix/src/platform/PosixError.js rename to packages/puter-js-common/src/PosixError.js index 0fc136a509..3d026b8cea 100644 --- a/packages/phoenix/src/platform/PosixError.js +++ b/packages/puter-js-common/src/PosixError.js @@ -1,9 +1,9 @@ /* * Copyright (C) 2024 Puter Technologies Inc. * - * This file is part of Phoenix Shell. + * This file is part of Puter. * - * Phoenix Shell is free software: you can redistribute it and/or modify + * Puter 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. @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -export const ErrorCodes = { +const ErrorCodes = { EACCES: Symbol.for('EACCES'), EADDRINUSE: Symbol.for('EADDRINUSE'), ECONNREFUSED: Symbol.for('ECONNREFUSED'), @@ -37,7 +37,7 @@ export const ErrorCodes = { }; // Codes taken from `errno` on Linux. -export const ErrorMetadata = new Map([ +const ErrorMetadata = new Map([ [ErrorCodes.EPERM, { code: 1, description: 'Operation not permitted' }], [ErrorCodes.ENOENT, { code: 2, description: 'File or directory not found' }], [ErrorCodes.EIO, { code: 5, description: 'IO error' }], @@ -57,7 +57,7 @@ export const ErrorMetadata = new Map([ [ErrorCodes.ECONNREFUSED, { code: 111, description: 'Connection refused' }], ]); -export const errorFromIntegerCode = (code) => { +const errorFromIntegerCode = (code) => { for (const [errorCode, metadata] of ErrorMetadata) { if (metadata.code === code) { return errorCode; @@ -66,7 +66,7 @@ export const errorFromIntegerCode = (code) => { return undefined; }; -export class PosixError extends Error { +class PosixError extends Error { // posixErrorCode can be either a string, or one of the ErrorCodes above. // If message is undefined, a default message will be used. constructor(posixErrorCode, message) { @@ -141,3 +141,10 @@ export class PosixError extends Error { return new PosixError(ErrorCodes.ETIMEDOUT, message); } } + +module.exports = { + ErrorCodes, + ErrorMetadata, + errorFromIntegerCode, + PosixError, +} From 017077f8cbf796ac9391dc6bb54474e3471fb4fa Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Thu, 16 May 2024 10:29:14 +0100 Subject: [PATCH 0062/2119] Move error-conversion functions into PosixError Specifically, this makes the Puter->PosixError conversion available to the in-progress git client. --- .../phoenix/src/platform/node/filesystem.js | 25 +--- .../phoenix/src/platform/puter/filesystem.js | 102 +------------- packages/phoenix/test/coreutils/errno.js | 3 +- packages/puter-js-common/src/PosixError.js | 130 ++++++++++++++++++ 4 files changed, 134 insertions(+), 126 deletions(-) diff --git a/packages/phoenix/src/platform/node/filesystem.js b/packages/phoenix/src/platform/node/filesystem.js index d8ae99943d..17e30710c8 100644 --- a/packages/phoenix/src/platform/node/filesystem.js +++ b/packages/phoenix/src/platform/node/filesystem.js @@ -22,29 +22,6 @@ import path_ from 'path'; import modeString from 'fs-mode-to-string'; import { ErrorCodes, PosixError } from '@heyputer/puter-js-common/src/PosixError.js'; -function convertNodeError(e) { - switch (e.code) { - case 'EACCES': return new PosixError(ErrorCodes.EACCES, e.message); - case 'EADDRINUSE': return new PosixError(ErrorCodes.EADDRINUSE, e.message); - case 'ECONNREFUSED': return new PosixError(ErrorCodes.ECONNREFUSED, e.message); - case 'ECONNRESET': return new PosixError(ErrorCodes.ECONNRESET, e.message); - case 'EEXIST': return new PosixError(ErrorCodes.EEXIST, e.message); - case 'EIO': return new PosixError(ErrorCodes.EIO, e.message); - case 'EISDIR': return new PosixError(ErrorCodes.EISDIR, e.message); - case 'EMFILE': return new PosixError(ErrorCodes.EMFILE, e.message); - case 'ENOENT': return new PosixError(ErrorCodes.ENOENT, e.message); - case 'ENOTDIR': return new PosixError(ErrorCodes.ENOTDIR, e.message); - case 'ENOTEMPTY': return new PosixError(ErrorCodes.ENOTEMPTY, e.message); - // ENOTFOUND is Node-specific. ECONNREFUSED is similar enough. - case 'ENOTFOUND': return new PosixError(ErrorCodes.ECONNREFUSED, e.message); - case 'EPERM': return new PosixError(ErrorCodes.EPERM, e.message); - case 'EPIPE': return new PosixError(ErrorCodes.EPIPE, e.message); - case 'ETIMEDOUT': return new PosixError(ErrorCodes.ETIMEDOUT, e.message); - } - // Some other kind of error - return e; -} - // DRY: Almost the same as puter/filesystem.js function wrapAPIs(apis) { for (const method in apis) { @@ -56,7 +33,7 @@ function wrapAPIs(apis) { try { return await original(...args); } catch (e) { - throw convertNodeError(e); + throw PosixError.fromNodeJSError(e); } }; } diff --git a/packages/phoenix/src/platform/puter/filesystem.js b/packages/phoenix/src/platform/puter/filesystem.js index 4227156190..3ce632ec07 100644 --- a/packages/phoenix/src/platform/puter/filesystem.js +++ b/packages/phoenix/src/platform/puter/filesystem.js @@ -18,106 +18,6 @@ */ import { ErrorCodes, PosixError } from '@heyputer/puter-js-common/src/PosixError.js'; -function convertPuterError(e) { - // Handle Puter SDK errors - switch (e.code) { - case 'item_with_same_name_exists': return new PosixError(ErrorCodes.EEXIST, e.message); - case 'cannot_move_item_into_itself': return new PosixError(ErrorCodes.EPERM, e.message); - case 'cannot_copy_item_into_itself': return new PosixError(ErrorCodes.EPERM, e.message); - case 'cannot_move_to_root': return new PosixError(ErrorCodes.EACCES, e.message); - case 'cannot_copy_to_root': return new PosixError(ErrorCodes.EACCES, e.message); - case 'cannot_write_to_root': return new PosixError(ErrorCodes.EACCES, e.message); - case 'cannot_overwrite_a_directory': return new PosixError(ErrorCodes.EPERM, e.message); - case 'cannot_read_a_directory': return new PosixError(ErrorCodes.EISDIR, e.message); - case 'source_and_dest_are_the_same': return new PosixError(ErrorCodes.EPERM, e.message); - case 'dest_is_not_a_directory': return new PosixError(ErrorCodes.ENOTDIR, e.message); - case 'dest_does_not_exist': return new PosixError(ErrorCodes.ENOENT, e.message); - case 'source_does_not_exist': return new PosixError(ErrorCodes.ENOENT, e.message); - case 'subject_does_not_exist': return new PosixError(ErrorCodes.ENOENT, e.message); - case 'shortcut_target_not_found': return new PosixError(ErrorCodes.ENOENT, e.message); - case 'shortcut_target_is_a_directory': return new PosixError(ErrorCodes.EISDIR, e.message); - case 'shortcut_target_is_a_file': return new PosixError(ErrorCodes.ENOTDIR, e.message); - case 'forbidden': return new PosixError(ErrorCodes.EPERM, e.message); - case 'immutable': return new PosixError(ErrorCodes.EACCES, e.message); - case 'field_empty': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'field_missing': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'xor_field_missing': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'field_only_valid_with_other_field': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'invalid_id': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'field_invalid': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'field_immutable': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'field_too_long': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'field_too_short': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'already_in_use': return new PosixError(ErrorCodes.EINVAL, e.message); // Not sure what this one is - case 'invalid_file_name': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'storage_limit_reached': return new PosixError(ErrorCodes.ENOSPC, e.message); - case 'internal_error': return new PosixError(ErrorCodes.ECONNRESET, e.message); // This isn't quite right - case 'response_timeout': return new PosixError(ErrorCodes.ETIMEDOUT, e.message); - case 'file_too_large': return new PosixError(ErrorCodes.EFBIG, e.message); - case 'thumbnail_too_large': return new PosixError(ErrorCodes.EFBIG, e.message); - case 'upload_failed': return new PosixError(ErrorCodes.ECONNRESET, e.message); // This isn't quite right - case 'missing_expected_metadata': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'overwrite_and_dedupe_exclusive': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'not_empty': return new PosixError(ErrorCodes.ENOTEMPTY, e.message); - - // Write - case 'offset_without_existing_file': return new PosixError(ErrorCodes.ENOENT, e.message); - case 'offset_requires_overwrite': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'offset_requires_stream': return new PosixError(ErrorCodes.EPERM, e.message); - - // Batch - case 'batch_too_many_files': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'batch_missing_file': return new PosixError(ErrorCodes.EINVAL, e.message); - - // Open - case 'no_suitable_app': break; - case 'app_does_not_exist': break; - - // Apps - case 'app_name_already_in_use': break; - - // Subdomains - case 'subdomain_limit_reached': break; - case 'subdomain_reserved': break; - - // Users - case 'email_already_in_use': break; - case 'username_already_in_use': break; - case 'too_many_username_changes': break; - case 'token_invalid': break; - - // drivers - case 'interface_not_found': break; - case 'no_implementation_available': break; - case 'method_not_found': break; - case 'missing_required_argument': break; - case 'argument_consolidation_failed': break; - - // SLA - case 'rate_limit_exceeded': break; - case 'monthly_limit_exceeded': break; - case 'server_rate_exceeded': break; - - // auth - case 'token_missing': break; - case 'token_auth_failed': break; - case 'token_unsupported': break; - case 'account_suspended': break; - case 'permission_denied': break; - case 'access_token_empty_permissions': break; - - // Object Mapping - case 'field_not_allowed_for_create': break; - case 'field_required_for_update': break; - case 'entity_not_found': break; - - // Chat - case 'max_tokens_exceeded': break; - } - // Some other kind of error - return e; -} - // DRY: Almost the same as node/filesystem.js function wrapAPIs(apis) { for (const method in apis) { @@ -129,7 +29,7 @@ function wrapAPIs(apis) { try { return await original(...args); } catch (e) { - throw convertPuterError(e); + throw PosixError.fromPuterAPIError(e); } }; } diff --git a/packages/phoenix/test/coreutils/errno.js b/packages/phoenix/test/coreutils/errno.js index 34fc786763..0191125bac 100644 --- a/packages/phoenix/test/coreutils/errno.js +++ b/packages/phoenix/test/coreutils/errno.js @@ -100,7 +100,8 @@ export const runErrnoTests = () => { 'EADDRINUSE 98 Address already in use\n' + 'ECONNRESET 104 Connection reset\n' + 'ETIMEDOUT 110 Connection timed out\n' + - 'ECONNREFUSED 111 Connection refused\n', + 'ECONNREFUSED 111 Connection refused\n' + + 'EUNKNOWN -1 Unknown error\n', expectedStderr: '', expectedFail: false, }, diff --git a/packages/puter-js-common/src/PosixError.js b/packages/puter-js-common/src/PosixError.js index 3d026b8cea..47178832be 100644 --- a/packages/puter-js-common/src/PosixError.js +++ b/packages/puter-js-common/src/PosixError.js @@ -34,6 +34,9 @@ const ErrorCodes = { EPERM: Symbol.for('EPERM'), EPIPE: Symbol.for('EPIPE'), ETIMEDOUT: Symbol.for('ETIMEDOUT'), + + // For when we need to convert errors that we don't recognise + EUNKNOWN: Symbol.for('EUNKNOWN'), }; // Codes taken from `errno` on Linux. @@ -55,6 +58,8 @@ const ErrorMetadata = new Map([ [ErrorCodes.ECONNRESET, { code: 104, description: 'Connection reset'}], [ErrorCodes.ETIMEDOUT, { code: 110, description: 'Connection timed out' }], [ErrorCodes.ECONNREFUSED, { code: 111, description: 'Connection refused' }], + + [ErrorCodes.EUNKNOWN, { code: -1, description: 'Unknown error' }], ]); const errorFromIntegerCode = (code) => { @@ -86,6 +91,131 @@ class PosixError extends Error { this.posixCode = posixCode; } + static fromNodeJSError(e) { + switch (e.code) { + case 'EACCES': return new PosixError(ErrorCodes.EACCES, e.message); + case 'EADDRINUSE': return new PosixError(ErrorCodes.EADDRINUSE, e.message); + case 'ECONNREFUSED': return new PosixError(ErrorCodes.ECONNREFUSED, e.message); + case 'ECONNRESET': return new PosixError(ErrorCodes.ECONNRESET, e.message); + case 'EEXIST': return new PosixError(ErrorCodes.EEXIST, e.message); + case 'EIO': return new PosixError(ErrorCodes.EIO, e.message); + case 'EISDIR': return new PosixError(ErrorCodes.EISDIR, e.message); + case 'EMFILE': return new PosixError(ErrorCodes.EMFILE, e.message); + case 'ENOENT': return new PosixError(ErrorCodes.ENOENT, e.message); + case 'ENOTDIR': return new PosixError(ErrorCodes.ENOTDIR, e.message); + case 'ENOTEMPTY': return new PosixError(ErrorCodes.ENOTEMPTY, e.message); + // ENOTFOUND is Node-specific. ECONNREFUSED is similar enough. + case 'ENOTFOUND': return new PosixError(ErrorCodes.ECONNREFUSED, e.message); + case 'EPERM': return new PosixError(ErrorCodes.EPERM, e.message); + case 'EPIPE': return new PosixError(ErrorCodes.EPIPE, e.message); + case 'ETIMEDOUT': return new PosixError(ErrorCodes.ETIMEDOUT, e.message); + } + // Some other kind of error + return new PosixError(ErrorCodes.EUNKNOWN, e.message); + } + + static fromPuterAPIError(e) { + // Handle Puter SDK errors + switch (e.code) { + case 'item_with_same_name_exists': return new PosixError(ErrorCodes.EEXIST, e.message); + case 'cannot_move_item_into_itself': return new PosixError(ErrorCodes.EPERM, e.message); + case 'cannot_copy_item_into_itself': return new PosixError(ErrorCodes.EPERM, e.message); + case 'cannot_move_to_root': return new PosixError(ErrorCodes.EACCES, e.message); + case 'cannot_copy_to_root': return new PosixError(ErrorCodes.EACCES, e.message); + case 'cannot_write_to_root': return new PosixError(ErrorCodes.EACCES, e.message); + case 'cannot_overwrite_a_directory': return new PosixError(ErrorCodes.EPERM, e.message); + case 'cannot_read_a_directory': return new PosixError(ErrorCodes.EISDIR, e.message); + case 'source_and_dest_are_the_same': return new PosixError(ErrorCodes.EPERM, e.message); + case 'dest_is_not_a_directory': return new PosixError(ErrorCodes.ENOTDIR, e.message); + case 'dest_does_not_exist': return new PosixError(ErrorCodes.ENOENT, e.message); + case 'source_does_not_exist': return new PosixError(ErrorCodes.ENOENT, e.message); + case 'subject_does_not_exist': return new PosixError(ErrorCodes.ENOENT, e.message); + case 'shortcut_target_not_found': return new PosixError(ErrorCodes.ENOENT, e.message); + case 'shortcut_target_is_a_directory': return new PosixError(ErrorCodes.EISDIR, e.message); + case 'shortcut_target_is_a_file': return new PosixError(ErrorCodes.ENOTDIR, e.message); + case 'forbidden': return new PosixError(ErrorCodes.EPERM, e.message); + case 'immutable': return new PosixError(ErrorCodes.EACCES, e.message); + case 'field_empty': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'field_missing': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'xor_field_missing': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'field_only_valid_with_other_field': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'invalid_id': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'field_invalid': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'field_immutable': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'field_too_long': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'field_too_short': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'already_in_use': return new PosixError(ErrorCodes.EINVAL, e.message); // Not sure what this one is + case 'invalid_file_name': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'storage_limit_reached': return new PosixError(ErrorCodes.ENOSPC, e.message); + case 'internal_error': return new PosixError(ErrorCodes.ECONNRESET, e.message); // This isn't quite right + case 'response_timeout': return new PosixError(ErrorCodes.ETIMEDOUT, e.message); + case 'file_too_large': return new PosixError(ErrorCodes.EFBIG, e.message); + case 'thumbnail_too_large': return new PosixError(ErrorCodes.EFBIG, e.message); + case 'upload_failed': return new PosixError(ErrorCodes.ECONNRESET, e.message); // This isn't quite right + case 'missing_expected_metadata': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'overwrite_and_dedupe_exclusive': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'not_empty': return new PosixError(ErrorCodes.ENOTEMPTY, e.message); + + // Write + case 'offset_without_existing_file': return new PosixError(ErrorCodes.ENOENT, e.message); + case 'offset_requires_overwrite': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'offset_requires_stream': return new PosixError(ErrorCodes.EPERM, e.message); + + // Batch + case 'batch_too_many_files': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'batch_missing_file': return new PosixError(ErrorCodes.EINVAL, e.message); + + // TODO: Associate more of these with posix error codes + + // Open + case 'no_suitable_app': break; + case 'app_does_not_exist': break; + + // Apps + case 'app_name_already_in_use': break; + + // Subdomains + case 'subdomain_limit_reached': break; + case 'subdomain_reserved': break; + + // Users + case 'email_already_in_use': break; + case 'username_already_in_use': break; + case 'too_many_username_changes': break; + case 'token_invalid': break; + + // drivers + case 'interface_not_found': break; + case 'no_implementation_available': break; + case 'method_not_found': break; + case 'missing_required_argument': break; + case 'argument_consolidation_failed': break; + + // SLA + case 'rate_limit_exceeded': break; + case 'monthly_limit_exceeded': break; + case 'server_rate_exceeded': break; + + // auth + case 'token_missing': break; + case 'token_auth_failed': break; + case 'token_unsupported': break; + case 'account_suspended': break; + case 'permission_denied': break; + case 'access_token_empty_permissions': break; + + // Object Mapping + case 'field_not_allowed_for_create': break; + case 'field_required_for_update': break; + case 'entity_not_found': break; + + // Chat + case 'max_tokens_exceeded': break; + } + // Some other kind of error + return new PosixError(ErrorCodes.EUNKNOWN, e.message); + } + // // Helpers for constructing a PosixError when you don't already have an error message. // From acf7eabef9343a7cc2f0487fe60260bbea2b2f05 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Thu, 16 May 2024 10:46:52 +0100 Subject: [PATCH 0063/2119] Expose POSIX error name as PosixError.code This matches the behaviour of Node.JS's errors, and some libraries expect it. --- packages/puter-js-common/src/PosixError.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/puter-js-common/src/PosixError.js b/packages/puter-js-common/src/PosixError.js index 47178832be..7b94d837b6 100644 --- a/packages/puter-js-common/src/PosixError.js +++ b/packages/puter-js-common/src/PosixError.js @@ -89,6 +89,7 @@ class PosixError extends Error { super(message ?? ErrorMetadata.get(posixCode).description); this.posixCode = posixCode; + this.code = posixCode.description; } static fromNodeJSError(e) { From 90463a07323335198d64ef9013adb22c10fa0e03 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 21 May 2024 17:25:28 -0400 Subject: [PATCH 0064/2119] Add support for webhook endpoints --- packages/backend/src/services/BaseService.js | 2 +- packages/backend/src/services/Container.js | 2 +- packages/backend/src/services/WebServerService.js | 12 ++++++++++-- 3 files changed, 12 insertions(+), 4 deletions(-) diff --git a/packages/backend/src/services/BaseService.js b/packages/backend/src/services/BaseService.js index d19d362f77..da6c6bae6f 100644 --- a/packages/backend/src/services/BaseService.js +++ b/packages/backend/src/services/BaseService.js @@ -51,7 +51,7 @@ class BaseService extends AdvancedBase { async __on (id, args) { const handler = this.__get_event_handler(id); - return await handler(id, args); + return await handler(id, ...args); } __get_event_handler (id) { diff --git a/packages/backend/src/services/Container.js b/packages/backend/src/services/Container.js index ee85eb9b93..341aa38765 100644 --- a/packages/backend/src/services/Container.js +++ b/packages/backend/src/services/Container.js @@ -113,7 +113,7 @@ class Container { const promises = []; for ( const k in this.instances_ ) { if ( this.instances_[k].__on ) { - promises.push(this.instances_[k].__on(id, ...args)); + promises.push(this.instances_[k].__on(id, args)); } } await Promise.all(promises); diff --git a/packages/backend/src/services/WebServerService.js b/packages/backend/src/services/WebServerService.js index cecbd3eaef..dcd136ce49 100644 --- a/packages/backend/src/services/WebServerService.js +++ b/packages/backend/src/services/WebServerService.js @@ -46,7 +46,10 @@ class WebServerService extends BaseService { const app = this.app; const services = this.services; await services.emit('install.middlewares.context-aware', { app }); - await services.emit('install.routes', { app }); + await services.emit('install.routes', { + app, + router_webhooks: this.router_webhooks, + }); await services.emit('install.routes-gui', { app }); } @@ -123,7 +126,7 @@ class WebServerService extends BaseService { ports_to_try = null; // GC const url = config.origin; - + this.startup_widget = () => { const link = `\x1B[34;1m${osclink(url)}\x1B[0m`; const lines = [ @@ -320,6 +323,11 @@ class WebServerService extends BaseService { } }) + // Web hooks need a router that occurs before JSON parse middleware + // so that signatures of the raw JSON can be verified + this.router_webhooks = express.Router(); + app.use(this.router_webhooks); + app.use(express.json({limit: '50mb'})); const cookieParser = require('cookie-parser'); From 1f6a2093fb0462ee3ddf682c3a55fc0697fb32b5 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 21 May 2024 18:46:34 -0400 Subject: [PATCH 0065/2119] Disallow negative size values --- packages/backend/src/api/APIError.js | 4 ++++ packages/backend/src/routers/filesystem_api/batch/all.js | 6 +++++- 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/api/APIError.js b/packages/backend/src/api/APIError.js index fee79b9a86..738f3b5a7d 100644 --- a/packages/backend/src/api/APIError.js +++ b/packages/backend/src/api/APIError.js @@ -220,6 +220,10 @@ module.exports = class APIError { status: 400, message: 'Missing fileinfo entry or BLOB for operation.', }, + 'invalid_file_metadata': { + status: 400, + message: 'Invalid file metadata.', + }, // Open 'no_suitable_app': { diff --git a/packages/backend/src/routers/filesystem_api/batch/all.js b/packages/backend/src/routers/filesystem_api/batch/all.js index f09b6d45f1..7438334d8b 100644 --- a/packages/backend/src/routers/filesystem_api/batch/all.js +++ b/packages/backend/src/routers/filesystem_api/batch/all.js @@ -192,7 +192,11 @@ module.exports = eggspress('/batch', { } if ( fieldname === 'fileinfo' ) { - fileinfos.push(JSON.parse(value)); + const fileinfo = JSON.parse(value); + if ( fileinfo.size < 0 ) { + throw APIError.create('invalid_file_metadata'); + } + fileinfos.push(fileinfo); return; } From e43b21387ca8d9861f604ff209bea431c3960474 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Thu, 16 May 2024 10:11:20 +0100 Subject: [PATCH 0066/2119] Move PosixError into puter-js-common The in-progress git client also needs to use this. puter-js-common uses commonjs modules, so it had to be adjusted for that. --- .../phoenix/src/platform/node/filesystem.js | 2 +- .../phoenix/src/platform/puter/filesystem.js | 2 +- .../src/puter-shell/coreutils/errno.js | 2 +- .../src/puter-shell/coreutils/touch.js | 2 +- packages/phoenix/test/coreutils/errno.js | 2 +- .../src}/PosixError.js | 19 +++++++++++++------ 6 files changed, 18 insertions(+), 11 deletions(-) rename packages/{phoenix/src/platform => puter-js-common/src}/PosixError.js (94%) diff --git a/packages/phoenix/src/platform/node/filesystem.js b/packages/phoenix/src/platform/node/filesystem.js index 85b9e84ccc..d8ae99943d 100644 --- a/packages/phoenix/src/platform/node/filesystem.js +++ b/packages/phoenix/src/platform/node/filesystem.js @@ -20,7 +20,7 @@ import fs from 'fs'; import path_ from 'path'; import modeString from 'fs-mode-to-string'; -import { ErrorCodes, PosixError } from '../PosixError.js'; +import { ErrorCodes, PosixError } from '@heyputer/puter-js-common/src/PosixError.js'; function convertNodeError(e) { switch (e.code) { diff --git a/packages/phoenix/src/platform/puter/filesystem.js b/packages/phoenix/src/platform/puter/filesystem.js index ca60e2fe94..4227156190 100644 --- a/packages/phoenix/src/platform/puter/filesystem.js +++ b/packages/phoenix/src/platform/puter/filesystem.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { ErrorCodes, PosixError } from '../PosixError.js'; +import { ErrorCodes, PosixError } from '@heyputer/puter-js-common/src/PosixError.js'; function convertPuterError(e) { // Handle Puter SDK errors diff --git a/packages/phoenix/src/puter-shell/coreutils/errno.js b/packages/phoenix/src/puter-shell/coreutils/errno.js index dd36d8dd46..db74b2f685 100644 --- a/packages/phoenix/src/puter-shell/coreutils/errno.js +++ b/packages/phoenix/src/puter-shell/coreutils/errno.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { ErrorCodes, ErrorMetadata, errorFromIntegerCode } from '../../platform/PosixError.js'; +import { ErrorCodes, ErrorMetadata, errorFromIntegerCode } from '@heyputer/puter-js-common/src/PosixError.js'; import { Exit } from './coreutil_lib/exit.js'; const maxErrorNameLength = Object.keys(ErrorCodes) diff --git a/packages/phoenix/src/puter-shell/coreutils/touch.js b/packages/phoenix/src/puter-shell/coreutils/touch.js index 8f15f13c6e..5b32067ad0 100644 --- a/packages/phoenix/src/puter-shell/coreutils/touch.js +++ b/packages/phoenix/src/puter-shell/coreutils/touch.js @@ -18,7 +18,7 @@ */ import { Exit } from './coreutil_lib/exit.js'; import { resolveRelativePath } from '../../util/path.js'; -import { ErrorCodes } from '../../platform/PosixError.js'; +import { ErrorCodes } from '@heyputer/puter-js-common/src/PosixError.js'; export default { name: 'touch', diff --git a/packages/phoenix/test/coreutils/errno.js b/packages/phoenix/test/coreutils/errno.js index fbb63b53b9..34fc786763 100644 --- a/packages/phoenix/test/coreutils/errno.js +++ b/packages/phoenix/test/coreutils/errno.js @@ -19,7 +19,7 @@ import assert from 'assert'; import { MakeTestContext } from './harness.js' import builtins from '../../src/puter-shell/coreutils/__exports__.js'; -import { ErrorCodes, ErrorMetadata } from '../../src/platform/PosixError.js'; +import { ErrorCodes, ErrorMetadata } from '@heyputer/puter-js-common/src/PosixError.js'; export const runErrnoTests = () => { describe('errno', function () { diff --git a/packages/phoenix/src/platform/PosixError.js b/packages/puter-js-common/src/PosixError.js similarity index 94% rename from packages/phoenix/src/platform/PosixError.js rename to packages/puter-js-common/src/PosixError.js index 0fc136a509..3d026b8cea 100644 --- a/packages/phoenix/src/platform/PosixError.js +++ b/packages/puter-js-common/src/PosixError.js @@ -1,9 +1,9 @@ /* * Copyright (C) 2024 Puter Technologies Inc. * - * This file is part of Phoenix Shell. + * This file is part of Puter. * - * Phoenix Shell is free software: you can redistribute it and/or modify + * Puter 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. @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -export const ErrorCodes = { +const ErrorCodes = { EACCES: Symbol.for('EACCES'), EADDRINUSE: Symbol.for('EADDRINUSE'), ECONNREFUSED: Symbol.for('ECONNREFUSED'), @@ -37,7 +37,7 @@ export const ErrorCodes = { }; // Codes taken from `errno` on Linux. -export const ErrorMetadata = new Map([ +const ErrorMetadata = new Map([ [ErrorCodes.EPERM, { code: 1, description: 'Operation not permitted' }], [ErrorCodes.ENOENT, { code: 2, description: 'File or directory not found' }], [ErrorCodes.EIO, { code: 5, description: 'IO error' }], @@ -57,7 +57,7 @@ export const ErrorMetadata = new Map([ [ErrorCodes.ECONNREFUSED, { code: 111, description: 'Connection refused' }], ]); -export const errorFromIntegerCode = (code) => { +const errorFromIntegerCode = (code) => { for (const [errorCode, metadata] of ErrorMetadata) { if (metadata.code === code) { return errorCode; @@ -66,7 +66,7 @@ export const errorFromIntegerCode = (code) => { return undefined; }; -export class PosixError extends Error { +class PosixError extends Error { // posixErrorCode can be either a string, or one of the ErrorCodes above. // If message is undefined, a default message will be used. constructor(posixErrorCode, message) { @@ -141,3 +141,10 @@ export class PosixError extends Error { return new PosixError(ErrorCodes.ETIMEDOUT, message); } } + +module.exports = { + ErrorCodes, + ErrorMetadata, + errorFromIntegerCode, + PosixError, +} From 8098dc9dccc3b38fed1da30bf872a009c37ca90b Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Thu, 16 May 2024 10:29:14 +0100 Subject: [PATCH 0067/2119] Move error-conversion functions into PosixError Specifically, this makes the Puter->PosixError conversion available to the in-progress git client. --- .../phoenix/src/platform/node/filesystem.js | 25 +--- .../phoenix/src/platform/puter/filesystem.js | 102 +------------- packages/phoenix/test/coreutils/errno.js | 3 +- packages/puter-js-common/src/PosixError.js | 130 ++++++++++++++++++ 4 files changed, 134 insertions(+), 126 deletions(-) diff --git a/packages/phoenix/src/platform/node/filesystem.js b/packages/phoenix/src/platform/node/filesystem.js index d8ae99943d..17e30710c8 100644 --- a/packages/phoenix/src/platform/node/filesystem.js +++ b/packages/phoenix/src/platform/node/filesystem.js @@ -22,29 +22,6 @@ import path_ from 'path'; import modeString from 'fs-mode-to-string'; import { ErrorCodes, PosixError } from '@heyputer/puter-js-common/src/PosixError.js'; -function convertNodeError(e) { - switch (e.code) { - case 'EACCES': return new PosixError(ErrorCodes.EACCES, e.message); - case 'EADDRINUSE': return new PosixError(ErrorCodes.EADDRINUSE, e.message); - case 'ECONNREFUSED': return new PosixError(ErrorCodes.ECONNREFUSED, e.message); - case 'ECONNRESET': return new PosixError(ErrorCodes.ECONNRESET, e.message); - case 'EEXIST': return new PosixError(ErrorCodes.EEXIST, e.message); - case 'EIO': return new PosixError(ErrorCodes.EIO, e.message); - case 'EISDIR': return new PosixError(ErrorCodes.EISDIR, e.message); - case 'EMFILE': return new PosixError(ErrorCodes.EMFILE, e.message); - case 'ENOENT': return new PosixError(ErrorCodes.ENOENT, e.message); - case 'ENOTDIR': return new PosixError(ErrorCodes.ENOTDIR, e.message); - case 'ENOTEMPTY': return new PosixError(ErrorCodes.ENOTEMPTY, e.message); - // ENOTFOUND is Node-specific. ECONNREFUSED is similar enough. - case 'ENOTFOUND': return new PosixError(ErrorCodes.ECONNREFUSED, e.message); - case 'EPERM': return new PosixError(ErrorCodes.EPERM, e.message); - case 'EPIPE': return new PosixError(ErrorCodes.EPIPE, e.message); - case 'ETIMEDOUT': return new PosixError(ErrorCodes.ETIMEDOUT, e.message); - } - // Some other kind of error - return e; -} - // DRY: Almost the same as puter/filesystem.js function wrapAPIs(apis) { for (const method in apis) { @@ -56,7 +33,7 @@ function wrapAPIs(apis) { try { return await original(...args); } catch (e) { - throw convertNodeError(e); + throw PosixError.fromNodeJSError(e); } }; } diff --git a/packages/phoenix/src/platform/puter/filesystem.js b/packages/phoenix/src/platform/puter/filesystem.js index 4227156190..3ce632ec07 100644 --- a/packages/phoenix/src/platform/puter/filesystem.js +++ b/packages/phoenix/src/platform/puter/filesystem.js @@ -18,106 +18,6 @@ */ import { ErrorCodes, PosixError } from '@heyputer/puter-js-common/src/PosixError.js'; -function convertPuterError(e) { - // Handle Puter SDK errors - switch (e.code) { - case 'item_with_same_name_exists': return new PosixError(ErrorCodes.EEXIST, e.message); - case 'cannot_move_item_into_itself': return new PosixError(ErrorCodes.EPERM, e.message); - case 'cannot_copy_item_into_itself': return new PosixError(ErrorCodes.EPERM, e.message); - case 'cannot_move_to_root': return new PosixError(ErrorCodes.EACCES, e.message); - case 'cannot_copy_to_root': return new PosixError(ErrorCodes.EACCES, e.message); - case 'cannot_write_to_root': return new PosixError(ErrorCodes.EACCES, e.message); - case 'cannot_overwrite_a_directory': return new PosixError(ErrorCodes.EPERM, e.message); - case 'cannot_read_a_directory': return new PosixError(ErrorCodes.EISDIR, e.message); - case 'source_and_dest_are_the_same': return new PosixError(ErrorCodes.EPERM, e.message); - case 'dest_is_not_a_directory': return new PosixError(ErrorCodes.ENOTDIR, e.message); - case 'dest_does_not_exist': return new PosixError(ErrorCodes.ENOENT, e.message); - case 'source_does_not_exist': return new PosixError(ErrorCodes.ENOENT, e.message); - case 'subject_does_not_exist': return new PosixError(ErrorCodes.ENOENT, e.message); - case 'shortcut_target_not_found': return new PosixError(ErrorCodes.ENOENT, e.message); - case 'shortcut_target_is_a_directory': return new PosixError(ErrorCodes.EISDIR, e.message); - case 'shortcut_target_is_a_file': return new PosixError(ErrorCodes.ENOTDIR, e.message); - case 'forbidden': return new PosixError(ErrorCodes.EPERM, e.message); - case 'immutable': return new PosixError(ErrorCodes.EACCES, e.message); - case 'field_empty': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'field_missing': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'xor_field_missing': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'field_only_valid_with_other_field': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'invalid_id': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'field_invalid': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'field_immutable': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'field_too_long': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'field_too_short': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'already_in_use': return new PosixError(ErrorCodes.EINVAL, e.message); // Not sure what this one is - case 'invalid_file_name': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'storage_limit_reached': return new PosixError(ErrorCodes.ENOSPC, e.message); - case 'internal_error': return new PosixError(ErrorCodes.ECONNRESET, e.message); // This isn't quite right - case 'response_timeout': return new PosixError(ErrorCodes.ETIMEDOUT, e.message); - case 'file_too_large': return new PosixError(ErrorCodes.EFBIG, e.message); - case 'thumbnail_too_large': return new PosixError(ErrorCodes.EFBIG, e.message); - case 'upload_failed': return new PosixError(ErrorCodes.ECONNRESET, e.message); // This isn't quite right - case 'missing_expected_metadata': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'overwrite_and_dedupe_exclusive': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'not_empty': return new PosixError(ErrorCodes.ENOTEMPTY, e.message); - - // Write - case 'offset_without_existing_file': return new PosixError(ErrorCodes.ENOENT, e.message); - case 'offset_requires_overwrite': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'offset_requires_stream': return new PosixError(ErrorCodes.EPERM, e.message); - - // Batch - case 'batch_too_many_files': return new PosixError(ErrorCodes.EINVAL, e.message); - case 'batch_missing_file': return new PosixError(ErrorCodes.EINVAL, e.message); - - // Open - case 'no_suitable_app': break; - case 'app_does_not_exist': break; - - // Apps - case 'app_name_already_in_use': break; - - // Subdomains - case 'subdomain_limit_reached': break; - case 'subdomain_reserved': break; - - // Users - case 'email_already_in_use': break; - case 'username_already_in_use': break; - case 'too_many_username_changes': break; - case 'token_invalid': break; - - // drivers - case 'interface_not_found': break; - case 'no_implementation_available': break; - case 'method_not_found': break; - case 'missing_required_argument': break; - case 'argument_consolidation_failed': break; - - // SLA - case 'rate_limit_exceeded': break; - case 'monthly_limit_exceeded': break; - case 'server_rate_exceeded': break; - - // auth - case 'token_missing': break; - case 'token_auth_failed': break; - case 'token_unsupported': break; - case 'account_suspended': break; - case 'permission_denied': break; - case 'access_token_empty_permissions': break; - - // Object Mapping - case 'field_not_allowed_for_create': break; - case 'field_required_for_update': break; - case 'entity_not_found': break; - - // Chat - case 'max_tokens_exceeded': break; - } - // Some other kind of error - return e; -} - // DRY: Almost the same as node/filesystem.js function wrapAPIs(apis) { for (const method in apis) { @@ -129,7 +29,7 @@ function wrapAPIs(apis) { try { return await original(...args); } catch (e) { - throw convertPuterError(e); + throw PosixError.fromPuterAPIError(e); } }; } diff --git a/packages/phoenix/test/coreutils/errno.js b/packages/phoenix/test/coreutils/errno.js index 34fc786763..0191125bac 100644 --- a/packages/phoenix/test/coreutils/errno.js +++ b/packages/phoenix/test/coreutils/errno.js @@ -100,7 +100,8 @@ export const runErrnoTests = () => { 'EADDRINUSE 98 Address already in use\n' + 'ECONNRESET 104 Connection reset\n' + 'ETIMEDOUT 110 Connection timed out\n' + - 'ECONNREFUSED 111 Connection refused\n', + 'ECONNREFUSED 111 Connection refused\n' + + 'EUNKNOWN -1 Unknown error\n', expectedStderr: '', expectedFail: false, }, diff --git a/packages/puter-js-common/src/PosixError.js b/packages/puter-js-common/src/PosixError.js index 3d026b8cea..47178832be 100644 --- a/packages/puter-js-common/src/PosixError.js +++ b/packages/puter-js-common/src/PosixError.js @@ -34,6 +34,9 @@ const ErrorCodes = { EPERM: Symbol.for('EPERM'), EPIPE: Symbol.for('EPIPE'), ETIMEDOUT: Symbol.for('ETIMEDOUT'), + + // For when we need to convert errors that we don't recognise + EUNKNOWN: Symbol.for('EUNKNOWN'), }; // Codes taken from `errno` on Linux. @@ -55,6 +58,8 @@ const ErrorMetadata = new Map([ [ErrorCodes.ECONNRESET, { code: 104, description: 'Connection reset'}], [ErrorCodes.ETIMEDOUT, { code: 110, description: 'Connection timed out' }], [ErrorCodes.ECONNREFUSED, { code: 111, description: 'Connection refused' }], + + [ErrorCodes.EUNKNOWN, { code: -1, description: 'Unknown error' }], ]); const errorFromIntegerCode = (code) => { @@ -86,6 +91,131 @@ class PosixError extends Error { this.posixCode = posixCode; } + static fromNodeJSError(e) { + switch (e.code) { + case 'EACCES': return new PosixError(ErrorCodes.EACCES, e.message); + case 'EADDRINUSE': return new PosixError(ErrorCodes.EADDRINUSE, e.message); + case 'ECONNREFUSED': return new PosixError(ErrorCodes.ECONNREFUSED, e.message); + case 'ECONNRESET': return new PosixError(ErrorCodes.ECONNRESET, e.message); + case 'EEXIST': return new PosixError(ErrorCodes.EEXIST, e.message); + case 'EIO': return new PosixError(ErrorCodes.EIO, e.message); + case 'EISDIR': return new PosixError(ErrorCodes.EISDIR, e.message); + case 'EMFILE': return new PosixError(ErrorCodes.EMFILE, e.message); + case 'ENOENT': return new PosixError(ErrorCodes.ENOENT, e.message); + case 'ENOTDIR': return new PosixError(ErrorCodes.ENOTDIR, e.message); + case 'ENOTEMPTY': return new PosixError(ErrorCodes.ENOTEMPTY, e.message); + // ENOTFOUND is Node-specific. ECONNREFUSED is similar enough. + case 'ENOTFOUND': return new PosixError(ErrorCodes.ECONNREFUSED, e.message); + case 'EPERM': return new PosixError(ErrorCodes.EPERM, e.message); + case 'EPIPE': return new PosixError(ErrorCodes.EPIPE, e.message); + case 'ETIMEDOUT': return new PosixError(ErrorCodes.ETIMEDOUT, e.message); + } + // Some other kind of error + return new PosixError(ErrorCodes.EUNKNOWN, e.message); + } + + static fromPuterAPIError(e) { + // Handle Puter SDK errors + switch (e.code) { + case 'item_with_same_name_exists': return new PosixError(ErrorCodes.EEXIST, e.message); + case 'cannot_move_item_into_itself': return new PosixError(ErrorCodes.EPERM, e.message); + case 'cannot_copy_item_into_itself': return new PosixError(ErrorCodes.EPERM, e.message); + case 'cannot_move_to_root': return new PosixError(ErrorCodes.EACCES, e.message); + case 'cannot_copy_to_root': return new PosixError(ErrorCodes.EACCES, e.message); + case 'cannot_write_to_root': return new PosixError(ErrorCodes.EACCES, e.message); + case 'cannot_overwrite_a_directory': return new PosixError(ErrorCodes.EPERM, e.message); + case 'cannot_read_a_directory': return new PosixError(ErrorCodes.EISDIR, e.message); + case 'source_and_dest_are_the_same': return new PosixError(ErrorCodes.EPERM, e.message); + case 'dest_is_not_a_directory': return new PosixError(ErrorCodes.ENOTDIR, e.message); + case 'dest_does_not_exist': return new PosixError(ErrorCodes.ENOENT, e.message); + case 'source_does_not_exist': return new PosixError(ErrorCodes.ENOENT, e.message); + case 'subject_does_not_exist': return new PosixError(ErrorCodes.ENOENT, e.message); + case 'shortcut_target_not_found': return new PosixError(ErrorCodes.ENOENT, e.message); + case 'shortcut_target_is_a_directory': return new PosixError(ErrorCodes.EISDIR, e.message); + case 'shortcut_target_is_a_file': return new PosixError(ErrorCodes.ENOTDIR, e.message); + case 'forbidden': return new PosixError(ErrorCodes.EPERM, e.message); + case 'immutable': return new PosixError(ErrorCodes.EACCES, e.message); + case 'field_empty': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'field_missing': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'xor_field_missing': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'field_only_valid_with_other_field': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'invalid_id': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'field_invalid': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'field_immutable': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'field_too_long': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'field_too_short': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'already_in_use': return new PosixError(ErrorCodes.EINVAL, e.message); // Not sure what this one is + case 'invalid_file_name': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'storage_limit_reached': return new PosixError(ErrorCodes.ENOSPC, e.message); + case 'internal_error': return new PosixError(ErrorCodes.ECONNRESET, e.message); // This isn't quite right + case 'response_timeout': return new PosixError(ErrorCodes.ETIMEDOUT, e.message); + case 'file_too_large': return new PosixError(ErrorCodes.EFBIG, e.message); + case 'thumbnail_too_large': return new PosixError(ErrorCodes.EFBIG, e.message); + case 'upload_failed': return new PosixError(ErrorCodes.ECONNRESET, e.message); // This isn't quite right + case 'missing_expected_metadata': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'overwrite_and_dedupe_exclusive': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'not_empty': return new PosixError(ErrorCodes.ENOTEMPTY, e.message); + + // Write + case 'offset_without_existing_file': return new PosixError(ErrorCodes.ENOENT, e.message); + case 'offset_requires_overwrite': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'offset_requires_stream': return new PosixError(ErrorCodes.EPERM, e.message); + + // Batch + case 'batch_too_many_files': return new PosixError(ErrorCodes.EINVAL, e.message); + case 'batch_missing_file': return new PosixError(ErrorCodes.EINVAL, e.message); + + // TODO: Associate more of these with posix error codes + + // Open + case 'no_suitable_app': break; + case 'app_does_not_exist': break; + + // Apps + case 'app_name_already_in_use': break; + + // Subdomains + case 'subdomain_limit_reached': break; + case 'subdomain_reserved': break; + + // Users + case 'email_already_in_use': break; + case 'username_already_in_use': break; + case 'too_many_username_changes': break; + case 'token_invalid': break; + + // drivers + case 'interface_not_found': break; + case 'no_implementation_available': break; + case 'method_not_found': break; + case 'missing_required_argument': break; + case 'argument_consolidation_failed': break; + + // SLA + case 'rate_limit_exceeded': break; + case 'monthly_limit_exceeded': break; + case 'server_rate_exceeded': break; + + // auth + case 'token_missing': break; + case 'token_auth_failed': break; + case 'token_unsupported': break; + case 'account_suspended': break; + case 'permission_denied': break; + case 'access_token_empty_permissions': break; + + // Object Mapping + case 'field_not_allowed_for_create': break; + case 'field_required_for_update': break; + case 'entity_not_found': break; + + // Chat + case 'max_tokens_exceeded': break; + } + // Some other kind of error + return new PosixError(ErrorCodes.EUNKNOWN, e.message); + } + // // Helpers for constructing a PosixError when you don't already have an error message. // From c08c8bd073ca0c9318f78b959ae3578c16558b53 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Thu, 16 May 2024 10:46:52 +0100 Subject: [PATCH 0068/2119] Expose POSIX error name as PosixError.code This matches the behaviour of Node.JS's errors, and some libraries expect it. --- packages/puter-js-common/src/PosixError.js | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/puter-js-common/src/PosixError.js b/packages/puter-js-common/src/PosixError.js index 47178832be..7b94d837b6 100644 --- a/packages/puter-js-common/src/PosixError.js +++ b/packages/puter-js-common/src/PosixError.js @@ -89,6 +89,7 @@ class PosixError extends Error { super(message ?? ErrorMetadata.get(posixCode).description); this.posixCode = posixCode; + this.code = posixCode.description; } static fromNodeJSError(e) { From bf33fd752da90f61a17568f3c9e48d4c1e14f673 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Wed, 15 May 2024 11:05:54 +0100 Subject: [PATCH 0069/2119] Remove outdated FIXMEs about consuming extra stdin data --- .../phoenix/src/puter-shell/providers/PathCommandProvider.js | 2 -- .../src/puter-shell/providers/PuterAppCommandProvider.js | 1 - 2 files changed, 3 deletions(-) diff --git a/packages/phoenix/src/puter-shell/providers/PathCommandProvider.js b/packages/phoenix/src/puter-shell/providers/PathCommandProvider.js index 7fd4eb7d7f..6b55a04478 100644 --- a/packages/phoenix/src/puter-shell/providers/PathCommandProvider.js +++ b/packages/phoenix/src/puter-shell/providers/PathCommandProvider.js @@ -83,7 +83,6 @@ function spawn_process(ctx, executablePath) { // Repeatedly copy data from stdin to the child, while it's running. let data, done; const next_data = async () => { - // FIXME: This waits for one more read() after we finish. ({ value: data, done } = await Promise.race([ exit_promise, sigint_promise, ctx.externs.in_.read(), ])); @@ -135,7 +134,6 @@ function spawn_pty(ctx, executablePath) { // Repeatedly copy data from stdin to the child, while it's running. let data, done; const next_data = async () => { - // FIXME: This waits for one more read() after we finish. ({ value: data, done } = await Promise.race([ exit_promise, sigint_promise, ctx.externs.in_.read(), ])); diff --git a/packages/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js b/packages/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js index 2467d78070..75bc2097b9 100644 --- a/packages/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js +++ b/packages/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js @@ -86,7 +86,6 @@ export class PuterAppCommandProvider { // DRY: Initially copied from PathCommandProvider let data, done; const next_data = async () => { - // FIXME: This waits for one more read() after we finish. ({ value: data, done } = await Promise.race([ app_close_promise, sigint_promise, ctx.externs.in_.read(), ])); From 8f1c4fcda98e72a7b970e8c6fc2fe39a5e012264 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Wed, 15 May 2024 11:31:00 +0100 Subject: [PATCH 0070/2119] feat(Phoenix): Pass command line arguments and ENV when launching apps --- .../src/puter-shell/providers/PuterAppCommandProvider.js | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/packages/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js b/packages/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js index 75bc2097b9..2c9e862bb1 100644 --- a/packages/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js +++ b/packages/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js @@ -50,9 +50,14 @@ export class PuterAppCommandProvider { return { name: id, path: path ?? 'Built-in Puter app', - // TODO: Parameters and options? + // TODO: Let apps expose option/positional definitions like builtins do, and parse them here? async execute(ctx) { - const args = {}; // TODO: Passed-in parameters and options would go here + const args = { + command_line: { + args: ctx.locals.args, + }, + env: {...ctx.env}, + }; const child = await puter.ui.launchApp(id, args); // Wait for app to close. From 0d2ffdb380991915265e9de36edd105d5ffc4701 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Wed, 15 May 2024 10:47:58 +0100 Subject: [PATCH 0071/2119] Add boilerplate for empty git app It does nothing but output a message to the console. --- package-lock.json | 1417 ++++++----------- packages/backend/src/SelfHostedModule.js | 13 + .../database/SqliteDatabaseAccessService.js | 7 +- .../sqlite_setup/0010_add-git-app.sql | 4 + packages/git/.gitignore | 2 + packages/git/LICENSE | 661 ++++++++ packages/git/README.md | 3 + packages/git/assets/index.html | 18 + packages/git/config/dev.js | 21 + packages/git/config/release.js | 21 + packages/git/package.json | 20 + packages/git/rollup.config.js | 53 + packages/git/src/main.js | 21 + 13 files changed, 1368 insertions(+), 893 deletions(-) create mode 100644 packages/backend/src/services/database/sqlite_setup/0010_add-git-app.sql create mode 100644 packages/git/.gitignore create mode 100644 packages/git/LICENSE create mode 100644 packages/git/README.md create mode 100644 packages/git/assets/index.html create mode 100644 packages/git/config/dev.js create mode 100644 packages/git/config/release.js create mode 100644 packages/git/package.json create mode 100644 packages/git/rollup.config.js create mode 100644 packages/git/src/main.js diff --git a/package-lock.json b/package-lock.json index 6f6c696e09..713fe84022 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3411,6 +3411,108 @@ "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==" }, + "node_modules/@rollup/plugin-commonjs": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-24.1.0.tgz", + "integrity": "sha512-eSL45hjhCWI0jCCXcNtLVqM5N1JlBGvlFfY0m6oOYnLCJ6N0qEXoZql4sY2MOUArzhH4SA/qBpTxvvZp2Sc+DQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "glob": "^8.0.3", + "is-reference": "1.2.1", + "magic-string": "^0.27.0" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.68.0||^3.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-node-resolve": { + "version": "15.2.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", + "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.2.1", + "is-module": "^1.0.0", + "resolve": "^1.22.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-replace": { + "version": "5.0.5", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.5.tgz", + "integrity": "sha512-rYO4fOi8lMaTg/z5Jb+hKnrHHVn8j2lwkqwyS4kTRhKyWOLf2wST2sWXr4WzWiTcoHTp2sTjqUbqIj2E39slKQ==", + "dev": true, + "dependencies": { + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.30.3" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, + "node_modules/@rollup/plugin-replace/node_modules/magic-string": { + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, + "node_modules/@rollup/pluginutils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", + "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", + "dev": true, + "dependencies": { + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=14.0.0" + }, + "peerDependencies": { + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } + } + }, "node_modules/@sideway/address": { "version": "4.1.5", "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", @@ -3676,6 +3778,25 @@ "@types/send": "*" } }, + "node_modules/@types/fs-extra": { + "version": "8.1.5", + "resolved": "https://registry.npmjs.org/@types/fs-extra/-/fs-extra-8.1.5.tgz", + "integrity": "sha512-0dzKcwO+S8s2kuF5Z9oUWatQJj5Uq/iqphEtE3GQJVRRYm/tD1LglU2UnXi2A8jLq5umkGouOXOR9y0n613ZwQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/@types/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-ZUxbzKl0IfJILTS6t7ip5fQQM/J3TJYubDm3nMbgubNNYS62eXeUpoLUC8/7fJNiFYHTrGPQn7hspDUzIHX3UA==", + "dev": true, + "dependencies": { + "@types/minimatch": "*", + "@types/node": "*" + } + }, "node_modules/@types/hapi__catbox": { "version": "10.2.6", "resolved": "https://registry.npmjs.org/@types/hapi__catbox/-/hapi__catbox-10.2.6.tgz", @@ -3791,6 +3912,12 @@ "resolved": "https://registry.npmjs.org/@types/mime-db/-/mime-db-1.43.5.tgz", "integrity": "sha512-/bfTiIUTNPUBnwnYvUxXAre5MhD88jgagLEQiQtIASjU+bwxd8kS/ASDA4a8ufd8m0Lheu6eeMJHEUpLHoJ28A==" }, + "node_modules/@types/minimatch": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/@types/minimatch/-/minimatch-5.1.2.tgz", + "integrity": "sha512-K0VQKziLUWkVKiRVrx4a40iPaxTUefQmjtkQofBkYRcoaaL/8rhwDWww9qWbrgicNOgnpIsMxyNIUM4+n6dUIA==", + "dev": true + }, "node_modules/@types/mysql": { "version": "2.15.22", "resolved": "https://registry.npmjs.org/@types/mysql/-/mysql-2.15.22.tgz", @@ -3844,6 +3971,12 @@ "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz", "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==" }, + "node_modules/@types/resolve": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/@types/resolve/-/resolve-1.20.2.tgz", + "integrity": "sha512-60BCwRFOZCQhDncwQdxxeOEEkbc5dIMccYLwbxsS4TUNeVECQ/pBJ0j09mrHOl/JJvpRPGwO9SvE4nR2Nb/a4Q==", + "dev": true + }, "node_modules/@types/send": { "version": "0.17.4", "resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.4.tgz", @@ -4384,6 +4517,15 @@ "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/asn1": { "version": "0.2.6", "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", @@ -4764,6 +4906,18 @@ "node": ">=10.0.0" } }, + "node_modules/builtin-modules": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-3.3.0.tgz", + "integrity": "sha512-zhaCDicdLuWN5UbN5IMnFqNMhNfo919sH85y2/ea+5Yg9TsTkeZxpL+JLbp6cgYFS4sRLp3YV4S6yDuqVWHYOw==", + "dev": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -5527,6 +5681,15 @@ "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", "dev": true }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/default-require-extensions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", @@ -5605,6 +5768,18 @@ "node": ">=0.3.1" } }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/dom-serializer": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", @@ -6039,6 +6214,12 @@ "node": ">=4.0" } }, + "node_modules/estree-walker": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/estree-walker/-/estree-walker-2.0.2.tgz", + "integrity": "sha512-Rfkk/Mp/DL7JVje3u18FxFujQlTNR2q6QfMSMB7AvCBx91NGj/ba3kCfza0f6dVDbw7YlRf/nDrn7pQrCCyQ/w==", + "dev": true + }, "node_modules/esutils": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", @@ -6177,6 +6358,22 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -6479,6 +6676,20 @@ "resolved": "https://registry.npmjs.org/fs-constants/-/fs-constants-1.0.0.tgz", "integrity": "sha512-y6OAwoSIf7FyjMIv94u+b5rdheZEjzR63GTyZJm5qh4Bi+2YgwLCcI/fPFZkL5PSixOt6ZNKm+w+Hfp/Bciwow==" }, + "node_modules/fs-extra": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-8.1.0.tgz", + "integrity": "sha512-yhlQgA6mnOJUKOsRUFsgJdQCvkKhcz8tlZG5HBQfReYZy46OwLcY+Zia0mtdHsOo9y/hP+CxMN0TU9QxoOtG4g==", + "dev": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^4.0.0", + "universalify": "^0.1.0" + }, + "engines": { + "node": ">=6 <7 || >=8" + } + }, "node_modules/fs-minipass": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", @@ -6667,6 +6878,10 @@ "omggif": "^1.0.10" } }, + "node_modules/git": { + "resolved": "packages/git", + "link": true + }, "node_modules/github-from-package": { "version": "0.0.0", "resolved": "https://registry.npmjs.org/github-from-package/-/github-from-package-0.0.0.tgz", @@ -6751,6 +6966,45 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/globby": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/globby/-/globby-10.0.1.tgz", + "integrity": "sha512-sSs4inE1FB2YQiymcmTv6NWENryABjUNPeWhOvmn4SjtKybglsyPZxFB3U1/+L1bYi0rNZDqCLlHyLYDl1Pq5A==", + "dev": true, + "dependencies": { + "@types/glob": "^7.1.1", + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.0.3", + "glob": "^7.1.3", + "ignore": "^5.1.1", + "merge2": "^1.2.3", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/globby/node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -7136,6 +7390,21 @@ "node": ">=8" } }, + "node_modules/is-builtin-module": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-3.2.1.tgz", + "integrity": "sha512-BSLE3HnV2syZ0FK0iMA/yUGplUeMmNz4AW5fnTunbCIqZi4vG3WjJT9FHMy5D69xmAYBHXQhJdALdpwVxV501A==", + "dev": true, + "dependencies": { + "builtin-modules": "^3.3.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-callable": { "version": "1.2.7", "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz", @@ -7204,6 +7473,12 @@ "node": ">=0.10.0" } }, + "node_modules/is-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", + "integrity": "sha512-51ypPSPCoTEIN9dy5Oy+h4pShgJmPCygKfyRCISBI+JoWT/2oJvK8QPxmwv7b/p239jXrm9M1mlQbyKJ5A152g==", + "dev": true + }, "node_modules/is-number": { "version": "7.0.0", "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", @@ -7242,6 +7517,15 @@ "node": ">=0.10.0" } }, + "node_modules/is-reference": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/is-reference/-/is-reference-1.2.1.tgz", + "integrity": "sha512-U82MsXXiFIrjCK4otLT+o2NA2Cd2g5MLoOVXUZjIOhLurrRxpEXzI8O0KZHr3IjLvlAH1kTPYSuqer5T9ZVBKQ==", + "dev": true, + "dependencies": { + "@types/estree": "*" + } + }, "node_modules/is-stream": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", @@ -7631,6 +7915,15 @@ "node": ">=6" } }, + "node_modules/jsonfile": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-4.0.0.tgz", + "integrity": "sha512-m6F1R3z8jjlf2imQHS2Qez5sjKWQzbuuhuJ/FKYFRZvPE3PuHcSMVZzfsLhGVOkfd20obL5SWEBew5ShlquNxg==", + "dev": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/jsonwebtoken": { "version": "9.0.2", "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", @@ -7955,6 +8248,18 @@ "yallist": "^3.0.2" } }, + "node_modules/magic-string": { + "version": "0.27.0", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.27.0.tgz", + "integrity": "sha512-8UnnX2PeRAPZuN12svgR9j7M1uWMovg/CEnIwIG0LFkXSJJe4PdfUGiTGl8V9bsBHFUtfVINcSyYxd7q+kx9fA==", + "dev": true, + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.13" + }, + "engines": { + "node": ">=12" + } + }, "node_modules/make-dir": { "version": "3.1.0", "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", @@ -8001,6 +8306,15 @@ "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", "dev": true }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, "node_modules/methods": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", @@ -9025,6 +9339,15 @@ "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/pathval": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", @@ -9712,23 +10035,70 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/run-parallel": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", - "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "node_modules/rollup": { + "version": "3.29.4", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", + "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", "dev": true, - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=14.18.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/rollup-plugin-copy": { + "version": "3.5.0", + "resolved": "https://registry.npmjs.org/rollup-plugin-copy/-/rollup-plugin-copy-3.5.0.tgz", + "integrity": "sha512-wI8D5dvYovRMx/YYKtUNt3Yxaw4ORC9xo6Gt9t22kveWz1enG9QrhVlagzwrxSC455xD1dHMKhIJkbsQ7d48BA==", + "dev": true, + "dependencies": { + "@types/fs-extra": "^8.0.1", + "colorette": "^1.1.0", + "fs-extra": "^8.1.0", + "globby": "10.0.1", + "is-plain-object": "^3.0.0" + }, + "engines": { + "node": ">=8.3" + } + }, + "node_modules/rollup-plugin-copy/node_modules/colorette": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-1.4.0.tgz", + "integrity": "sha512-Y2oEozpomLn7Q3HFP7dpww7AtMJplbM9lGZP6RDfHqmbeRjiwRg4n6VM6j4KLmRke85uWEI7JqF17f3pqdRA0g==", + "dev": true + }, + "node_modules/rollup-plugin-copy/node_modules/is-plain-object": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-3.0.1.tgz", + "integrity": "sha512-Xnpx182SBMrr/aBik8y+GuR4U1L9FqMSojwDQwPMmxyC6bvEqly9UBCxhauBF5vNh2gwWJNX6oDV7O+OM4z34g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" } ], "dependencies": { @@ -10090,6 +10460,15 @@ "node": ">=8" } }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, "node_modules/socket.io": { "version": "4.7.5", "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", @@ -10841,6 +11220,15 @@ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, + "node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "dev": true, + "engines": { + "node": ">= 4.0.0" + } + }, "node_modules/unpipe": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", @@ -11556,6 +11944,18 @@ "typescript": "^5.1.6" } }, + "packages/git": { + "version": "1.0.0", + "license": "AGPL-3.0-only", + "devDependencies": { + "@rollup/plugin-commonjs": "^24.1.0", + "@rollup/plugin-node-resolve": "^15.0.2", + "@rollup/plugin-replace": "^5.0.2", + "mocha": "^10.2.0", + "rollup": "^3.21.4", + "rollup-plugin-copy": "^3.4.0" + } + }, "packages/phoenix": { "name": "@heyputer/phoenix", "version": "0.0.0", @@ -11595,132 +11995,6 @@ "node": ">=14" } }, - "packages/phoenix/node_modules/@rollup/plugin-commonjs": { - "version": "24.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "commondir": "^1.0.1", - "estree-walker": "^2.0.2", - "glob": "^8.0.3", - "is-reference": "1.2.1", - "magic-string": "^0.27.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.68.0||^3.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "packages/phoenix/node_modules/@rollup/plugin-commonjs/node_modules/brace-expansion": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "packages/phoenix/node_modules/@rollup/plugin-commonjs/node_modules/glob": { - "version": "8.1.0", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^5.0.1", - "once": "^1.3.0" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "packages/phoenix/node_modules/@rollup/plugin-commonjs/node_modules/minimatch": { - "version": "5.1.6", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": ">=10" - } - }, - "packages/phoenix/node_modules/@rollup/plugin-node-resolve": { - "version": "15.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "@types/resolve": "1.20.2", - "deepmerge": "^4.2.2", - "is-builtin-module": "^3.2.1", - "is-module": "^1.0.0", - "resolve": "^1.22.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.78.0||^3.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "packages/phoenix/node_modules/@rollup/plugin-replace": { - "version": "5.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "magic-string": "^0.27.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "packages/phoenix/node_modules/@rollup/pluginutils": { - "version": "5.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, "packages/phoenix/node_modules/@sinonjs/fake-timers": { "version": "11.2.2", "license": "BSD-3-Clause", @@ -11728,33 +12002,6 @@ "@sinonjs/commons": "^3.0.0" } }, - "packages/phoenix/node_modules/@types/fs-extra": { - "version": "8.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "packages/phoenix/node_modules/@types/glob": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "packages/phoenix/node_modules/@types/minimatch": { - "version": "5.1.2", - "dev": true, - "license": "MIT" - }, - "packages/phoenix/node_modules/@types/resolve": { - "version": "1.20.2", - "dev": true, - "license": "MIT" - }, "packages/phoenix/node_modules/argle": { "version": "1.1.2", "license": "MIT", @@ -11763,34 +12010,6 @@ "lodash.isnumber": "^3.0.3" } }, - "packages/phoenix/node_modules/array-union": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "packages/phoenix/node_modules/brace-expansion": { - "version": "1.1.11", - "dev": true, - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" - } - }, - "packages/phoenix/node_modules/builtin-modules": { - "version": "3.3.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, "packages/phoenix/node_modules/capture-console": { "version": "1.0.2", "license": "MIT", @@ -11818,11 +12037,6 @@ "node": ">=0.8" } }, - "packages/phoenix/node_modules/colorette": { - "version": "1.4.0", - "dev": true, - "license": "MIT" - }, "packages/phoenix/node_modules/columnify": { "version": "1.6.0", "license": "MIT", @@ -11834,14 +12048,6 @@ "node": ">=8.0.0" } }, - "packages/phoenix/node_modules/deepmerge": { - "version": "4.3.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, "packages/phoenix/node_modules/defaults": { "version": "1.0.4", "license": "MIT", @@ -11852,617 +12058,160 @@ "url": "https://github.com/sponsors/sindresorhus" } }, - "packages/phoenix/node_modules/dir-glob": { - "version": "3.0.1", - "dev": true, + "packages/phoenix/node_modules/fs-mode-to-string": { + "version": "0.0.2", + "license": "MIT" + }, + "packages/phoenix/node_modules/has-flag": { + "version": "4.0.0", "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, "engines": { "node": ">=8" } }, - "packages/phoenix/node_modules/estree-walker": { - "version": "2.0.2", - "dev": true, - "license": "MIT" - }, - "packages/phoenix/node_modules/fast-glob": { - "version": "3.2.12", - "dev": true, - "license": "MIT", - "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" - }, - "engines": { - "node": ">=8.6.0" - } - }, - "packages/phoenix/node_modules/fs-extra": { - "version": "8.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" - }, - "engines": { - "node": ">=6 <7 || >=8" - } - }, - "packages/phoenix/node_modules/fs-mode-to-string": { - "version": "0.0.2", - "license": "MIT" - }, - "packages/phoenix/node_modules/glob": { - "version": "7.2.3", - "dev": true, - "license": "ISC", - "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "packages/phoenix/node_modules/globby": { - "version": "10.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/glob": "^7.1.1", - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.0.3", - "glob": "^7.1.3", - "ignore": "^5.1.1", - "merge2": "^1.2.3", - "slash": "^3.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "packages/phoenix/node_modules/has-flag": { - "version": "4.0.0", - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "packages/phoenix/node_modules/is-builtin-module": { - "version": "3.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "builtin-modules": "^3.3.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/phoenix/node_modules/is-module": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, - "packages/phoenix/node_modules/is-plain-object": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "packages/phoenix/node_modules/is-reference": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "*" - } - }, "packages/phoenix/node_modules/json-query": { "version": "2.2.2", "engines": { "node": "*" } - }, - "packages/phoenix/node_modules/jsonfile": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "packages/phoenix/node_modules/lodash.isfunction": { - "version": "3.0.9", - "license": "MIT" - }, - "packages/phoenix/node_modules/magic-string": { - "version": "0.27.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.13" - }, - "engines": { - "node": ">=12" - } - }, - "packages/phoenix/node_modules/merge2": { - "version": "1.4.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, - "packages/phoenix/node_modules/minimatch": { - "version": "3.1.2", - "dev": true, - "license": "ISC", - "dependencies": { - "brace-expansion": "^1.1.7" - }, - "engines": { - "node": "*" - } - }, - "packages/phoenix/node_modules/path-browserify": { - "version": "1.0.1", - "license": "MIT" - }, - "packages/phoenix/node_modules/path-type": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "packages/phoenix/node_modules/randomstring": { - "version": "1.3.0", - "license": "MIT", - "dependencies": { - "randombytes": "2.0.3" - }, - "bin": { - "randomstring": "bin/randomstring" - }, - "engines": { - "node": "*" - } - }, - "packages/phoenix/node_modules/randomstring/node_modules/randombytes": { - "version": "2.0.3", - "license": "MIT" - }, - "packages/phoenix/node_modules/rollup": { - "version": "3.21.4", - "dev": true, - "license": "MIT", - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=14.18.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "packages/phoenix/node_modules/rollup-plugin-copy": { - "version": "3.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/fs-extra": "^8.0.1", - "colorette": "^1.1.0", - "fs-extra": "^8.1.0", - "globby": "10.0.1", - "is-plain-object": "^3.0.0" - }, - "engines": { - "node": ">=8.3" - } - }, - "packages/phoenix/node_modules/sinon": { - "version": "17.0.1", - "license": "BSD-3-Clause", - "dependencies": { - "@sinonjs/commons": "^3.0.0", - "@sinonjs/fake-timers": "^11.2.2", - "@sinonjs/samsam": "^8.0.0", - "diff": "^5.1.0", - "nise": "^5.1.5", - "supports-color": "^7.2.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/sinon" - } - }, - "packages/phoenix/node_modules/sinon/node_modules/diff": { - "version": "5.2.0", - "license": "BSD-3-Clause", - "engines": { - "node": ">=0.3.1" - } - }, - "packages/phoenix/node_modules/sinon/node_modules/supports-color": { - "version": "7.2.0", - "license": "MIT", - "dependencies": { - "has-flag": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "packages/phoenix/node_modules/slash": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "packages/phoenix/node_modules/universalify": { - "version": "0.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, - "packages/phoenix/node_modules/wcwidth": { - "version": "1.0.1", - "license": "MIT", - "dependencies": { - "defaults": "^1.0.3" - } - }, - "packages/phoenix/packages/contextlink": { - "version": "0.0.0", - "extraneous": true, - "license": "AGPL-3.0-only", - "devDependencies": { - "mocha": "^10.2.0" - } - }, - "packages/phoenix/packages/pty": { - "name": "dev-pty", - "version": "0.0.0", - "extraneous": true, - "license": "AGPL-3.0-only" - }, - "packages/phoenix/packages/strataparse": { - "version": "0.0.0", - "extraneous": true, - "license": "AGPL-3.0-only" - }, - "packages/puter-js": { - "name": "@heyputer/puterjs", - "version": "1.0.0", - "license": "Apache-2.0", - "devDependencies": { - "concurrently": "^8.2.2", - "webpack-cli": "^5.1.4" - } - }, - "packages/puter-js-common": { - "name": "@heyputer/puter-js-common", - "version": "1.0.0", - "license": "UNLICENSED" - }, - "packages/terminal": { - "name": "@heyputer/terminal", - "version": "0.0.0", - "license": "AGPL-3.0-only", - "dependencies": { - "@xterm/addon-fit": "^0.10.0", - "@xterm/xterm": "^5.5.0" - }, - "devDependencies": { - "@rollup/plugin-commonjs": "^24.1.0", - "@rollup/plugin-node-resolve": "^15.0.2", - "@rollup/plugin-replace": "^5.0.2", - "http-server": "^14.1.1", - "mocha": "^10.2.0", - "rollup": "^3.21.4", - "rollup-plugin-copy": "^3.4.0" - } - }, - "packages/terminal/node_modules/@rollup/plugin-commonjs": { - "version": "24.1.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "commondir": "^1.0.1", - "estree-walker": "^2.0.2", - "glob": "^8.0.3", - "is-reference": "1.2.1", - "magic-string": "^0.27.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.68.0||^3.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "packages/terminal/node_modules/@rollup/plugin-node-resolve": { - "version": "15.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "@types/resolve": "1.20.2", - "deepmerge": "^4.2.2", - "is-builtin-module": "^3.2.1", - "is-module": "^1.0.0", - "resolve": "^1.22.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.78.0||^3.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "packages/terminal/node_modules/@rollup/plugin-replace": { - "version": "5.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "magic-string": "^0.27.0" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "packages/terminal/node_modules/@rollup/pluginutils": { - "version": "5.0.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^2.3.1" - }, - "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } - } - }, - "packages/terminal/node_modules/@types/fs-extra": { - "version": "8.1.2", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/node": "*" - } - }, - "packages/terminal/node_modules/@types/glob": { - "version": "7.2.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/minimatch": "*", - "@types/node": "*" - } - }, - "packages/terminal/node_modules/@types/minimatch": { - "version": "5.1.2", - "dev": true, - "license": "MIT" - }, - "packages/terminal/node_modules/@types/resolve": { - "version": "1.20.2", - "dev": true, - "license": "MIT" - }, - "packages/terminal/node_modules/array-union": { - "version": "2.1.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, - "packages/terminal/node_modules/async": { - "version": "2.6.4", - "dev": true, - "license": "MIT", - "dependencies": { - "lodash": "^4.17.14" - } - }, - "packages/terminal/node_modules/builtin-modules": { - "version": "3.3.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/terminal/node_modules/colorette": { - "version": "1.4.0", - "dev": true, - "license": "MIT" - }, - "packages/terminal/node_modules/corser": { - "version": "2.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 0.4.0" - } - }, - "packages/terminal/node_modules/deepmerge": { - "version": "4.3.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "packages/terminal/node_modules/dir-glob": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "dependencies": { - "path-type": "^4.0.0" - }, - "engines": { - "node": ">=8" - } - }, - "packages/terminal/node_modules/estree-walker": { - "version": "2.0.2", - "dev": true, + }, + "packages/phoenix/node_modules/lodash.isfunction": { + "version": "3.0.9", "license": "MIT" }, - "packages/terminal/node_modules/eventemitter3": { - "version": "4.0.7", - "dev": true, + "packages/phoenix/node_modules/path-browserify": { + "version": "1.0.1", "license": "MIT" }, - "packages/terminal/node_modules/fast-glob": { - "version": "3.2.12", - "dev": true, + "packages/phoenix/node_modules/randomstring": { + "version": "1.3.0", "license": "MIT", "dependencies": { - "@nodelib/fs.stat": "^2.0.2", - "@nodelib/fs.walk": "^1.2.3", - "glob-parent": "^5.1.2", - "merge2": "^1.3.0", - "micromatch": "^4.0.4" + "randombytes": "2.0.3" + }, + "bin": { + "randomstring": "bin/randomstring" }, "engines": { - "node": ">=8.6.0" + "node": "*" } }, - "packages/terminal/node_modules/fs-extra": { - "version": "8.1.0", - "dev": true, - "license": "MIT", + "packages/phoenix/node_modules/randomstring/node_modules/randombytes": { + "version": "2.0.3", + "license": "MIT" + }, + "packages/phoenix/node_modules/sinon": { + "version": "17.0.1", + "license": "BSD-3-Clause", "dependencies": { - "graceful-fs": "^4.2.0", - "jsonfile": "^4.0.0", - "universalify": "^0.1.0" + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^11.2.2", + "@sinonjs/samsam": "^8.0.0", + "diff": "^5.1.0", + "nise": "^5.1.5", + "supports-color": "^7.2.0" }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, + "packages/phoenix/node_modules/sinon/node_modules/diff": { + "version": "5.2.0", + "license": "BSD-3-Clause", "engines": { - "node": ">=6 <7 || >=8" + "node": ">=0.3.1" } }, - "packages/terminal/node_modules/globby": { - "version": "10.0.1", - "dev": true, + "packages/phoenix/node_modules/sinon/node_modules/supports-color": { + "version": "7.2.0", "license": "MIT", "dependencies": { - "@types/glob": "^7.1.1", - "array-union": "^2.1.0", - "dir-glob": "^3.0.1", - "fast-glob": "^3.0.3", - "glob": "^7.1.3", - "ignore": "^5.1.1", - "merge2": "^1.2.3", - "slash": "^3.0.0" + "has-flag": "^4.0.0" }, "engines": { "node": ">=8" } }, - "packages/terminal/node_modules/globby/node_modules/brace-expansion": { - "version": "1.1.11", - "dev": true, + "packages/phoenix/node_modules/wcwidth": { + "version": "1.0.1", "license": "MIT", "dependencies": { - "balanced-match": "^1.0.0", - "concat-map": "0.0.1" + "defaults": "^1.0.3" } }, - "packages/terminal/node_modules/globby/node_modules/glob": { - "version": "7.2.3", - "dev": true, - "license": "ISC", + "packages/phoenix/packages/contextlink": { + "version": "0.0.0", + "extraneous": true, + "license": "AGPL-3.0-only", + "devDependencies": { + "mocha": "^10.2.0" + } + }, + "packages/phoenix/packages/pty": { + "name": "dev-pty", + "version": "0.0.0", + "extraneous": true, + "license": "AGPL-3.0-only" + }, + "packages/phoenix/packages/strataparse": { + "version": "0.0.0", + "extraneous": true, + "license": "AGPL-3.0-only" + }, + "packages/puter-js": { + "name": "@heyputer/puterjs", + "version": "1.0.0", + "license": "Apache-2.0", + "devDependencies": { + "concurrently": "^8.2.2", + "webpack-cli": "^5.1.4" + } + }, + "packages/puter-js-common": { + "name": "@heyputer/puter-js-common", + "version": "1.0.0", + "license": "UNLICENSED" + }, + "packages/terminal": { + "name": "@heyputer/terminal", + "version": "0.0.0", + "license": "AGPL-3.0-only", "dependencies": { - "fs.realpath": "^1.0.0", - "inflight": "^1.0.4", - "inherits": "2", - "minimatch": "^3.1.1", - "once": "^1.3.0", - "path-is-absolute": "^1.0.0" - }, - "engines": { - "node": "*" + "@xterm/addon-fit": "^0.10.0", + "@xterm/xterm": "^5.5.0" }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "devDependencies": { + "@rollup/plugin-commonjs": "^24.1.0", + "@rollup/plugin-node-resolve": "^15.0.2", + "@rollup/plugin-replace": "^5.0.2", + "http-server": "^14.1.1", + "mocha": "^10.2.0", + "rollup": "^3.21.4", + "rollup-plugin-copy": "^3.4.0" } }, - "packages/terminal/node_modules/globby/node_modules/minimatch": { - "version": "3.1.2", + "packages/terminal/node_modules/async": { + "version": "2.6.4", "dev": true, - "license": "ISC", + "license": "MIT", "dependencies": { - "brace-expansion": "^1.1.7" - }, + "lodash": "^4.17.14" + } + }, + "packages/terminal/node_modules/corser": { + "version": "2.0.1", + "dev": true, + "license": "MIT", "engines": { - "node": "*" + "node": ">= 0.4.0" } }, + "packages/terminal/node_modules/eventemitter3": { + "version": "4.0.7", + "dev": true, + "license": "MIT" + }, "packages/terminal/node_modules/html-encoding-sniffer": { "version": "3.0.0", "dev": true, @@ -12524,68 +12273,6 @@ "node": ">=0.10.0" } }, - "packages/terminal/node_modules/is-builtin-module": { - "version": "3.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "builtin-modules": "^3.3.0" - }, - "engines": { - "node": ">=6" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "packages/terminal/node_modules/is-module": { - "version": "1.0.0", - "dev": true, - "license": "MIT" - }, - "packages/terminal/node_modules/is-plain-object": { - "version": "3.0.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=0.10.0" - } - }, - "packages/terminal/node_modules/is-reference": { - "version": "1.2.1", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/estree": "*" - } - }, - "packages/terminal/node_modules/jsonfile": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "optionalDependencies": { - "graceful-fs": "^4.1.6" - } - }, - "packages/terminal/node_modules/magic-string": { - "version": "0.27.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.13" - }, - "engines": { - "node": ">=12" - } - }, - "packages/terminal/node_modules/merge2": { - "version": "1.4.1", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 8" - } - }, "packages/terminal/node_modules/ms": { "version": "2.1.3", "dev": true, @@ -12599,14 +12286,6 @@ "opener": "bin/opener-bin.js" } }, - "packages/terminal/node_modules/path-type": { - "version": "4.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "packages/terminal/node_modules/portfinder": { "version": "1.0.32", "dev": true, @@ -12647,49 +12326,11 @@ "dev": true, "license": "MIT" }, - "packages/terminal/node_modules/rollup": { - "version": "3.23.0", - "dev": true, - "license": "MIT", - "bin": { - "rollup": "dist/bin/rollup" - }, - "engines": { - "node": ">=14.18.0", - "npm": ">=8.0.0" - }, - "optionalDependencies": { - "fsevents": "~2.3.2" - } - }, - "packages/terminal/node_modules/rollup-plugin-copy": { - "version": "3.4.0", - "dev": true, - "license": "MIT", - "dependencies": { - "@types/fs-extra": "^8.0.1", - "colorette": "^1.1.0", - "fs-extra": "^8.1.0", - "globby": "10.0.1", - "is-plain-object": "^3.0.0" - }, - "engines": { - "node": ">=8.3" - } - }, "packages/terminal/node_modules/secure-compare": { "version": "3.0.1", "dev": true, "license": "MIT" }, - "packages/terminal/node_modules/slash": { - "version": "3.0.0", - "dev": true, - "license": "MIT", - "engines": { - "node": ">=8" - } - }, "packages/terminal/node_modules/union": { "version": "0.5.0", "dev": true, @@ -12700,14 +12341,6 @@ "node": ">= 0.8.0" } }, - "packages/terminal/node_modules/universalify": { - "version": "0.1.2", - "dev": true, - "license": "MIT", - "engines": { - "node": ">= 4.0.0" - } - }, "packages/terminal/node_modules/url-join": { "version": "4.0.1", "dev": true, diff --git a/packages/backend/src/SelfHostedModule.js b/packages/backend/src/SelfHostedModule.js index adc375d08e..268ed09489 100644 --- a/packages/backend/src/SelfHostedModule.js +++ b/packages/backend/src/SelfHostedModule.js @@ -40,6 +40,15 @@ class SelfHostedModule extends AdvancedBase { PUTER_JS_URL: ({ global_config: config }) => config.origin + '/sdk/puter.dev.js', } }, + { + name: 'git:rollup-watch', + directory: 'packages/git', + command: 'npx', + args: ['rollup', '-c', 'rollup.config.js', '--watch'], + env: { + PUTER_JS_URL: ({ global_config: config }) => config.origin + '/sdk/puter.dev.js', + } + }, ], }); @@ -58,6 +67,10 @@ class SelfHostedModule extends AdvancedBase { prefix: '/builtin/phoenix', path: path_.resolve(__dirname, '../../../packages/phoenix/dist'), }, + { + prefix: '/builtin/git', + path: path_.resolve(__dirname, '../../../packages/git/dist'), + }, ], }); } diff --git a/packages/backend/src/services/database/SqliteDatabaseAccessService.js b/packages/backend/src/services/database/SqliteDatabaseAccessService.js index c39e4eff62..b1e76eb358 100644 --- a/packages/backend/src/services/database/SqliteDatabaseAccessService.js +++ b/packages/backend/src/services/database/SqliteDatabaseAccessService.js @@ -42,7 +42,7 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { this.db = new Database(this.config.path); // Database upgrade logic - const TARGET_VERSION = 7; + const TARGET_VERSION = 8; if ( do_setup ) { this.log.noticeme(`SETUP: creating database at ${this.config.path}`); @@ -56,6 +56,7 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { '0007_sessions.sql', '0008_otp.sql', '0009_app-prefix-fix.sql', + '0010_add-git-app.sql', ].map(p => path_.join(__dirname, 'sqlite_setup', p)); const fs = require('fs'); for ( const filename of sql_files ) { @@ -100,6 +101,10 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { upgrade_files.push('0009_app-prefix-fix.sql'); } + if ( user_version <= 7 ) { + upgrade_files.push('0010_add-git-app.sql'); + } + if ( upgrade_files.length > 0 ) { this.log.noticeme(`Database out of date: ${this.config.path}`); this.log.noticeme(`UPGRADING DATABASE: ${user_version} -> ${TARGET_VERSION}`); diff --git a/packages/backend/src/services/database/sqlite_setup/0010_add-git-app.sql b/packages/backend/src/services/database/sqlite_setup/0010_add-git-app.sql new file mode 100644 index 0000000000..d18583bec2 --- /dev/null +++ b/packages/backend/src/services/database/sqlite_setup/0010_add-git-app.sql @@ -0,0 +1,4 @@ +INSERT INTO `apps` + (`uid`, `owner_user_id`, `icon`, `name`, `title`, `description`, `godmode`, `background`, `maximize_on_start`, `index_url`, `approved_for_listing`, `approved_for_opening_items`, `approved_for_incentive_program`, `timestamp`, `last_review`, `tags`, `app_owner`) +VALUES + ('app-e3ac5486-da8c-42ad-8377-8728086e0980', 1, 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSI5MnB0IiBoZWlnaHQ9IjkycHQiIHZpZXdCb3g9IjAgMCA5MiA5MiI+PGRlZnM+PGNsaXBQYXRoIGlkPSJhIj48cGF0aCBkPSJNMCAuMTEzaDkxLjg4N1Y5MkgwWm0wIDAiLz48L2NsaXBQYXRoPjwvZGVmcz48ZyBjbGlwLXBhdGg9InVybCgjYSkiPjxwYXRoIHN0eWxlPSJzdHJva2U6bm9uZTtmaWxsLXJ1bGU6bm9uemVybztmaWxsOiNmMDNjMmU7ZmlsbC1vcGFjaXR5OjEiIGQ9Ik05MC4xNTYgNDEuOTY1IDUwLjAzNiAxLjg0OGE1LjkxOCA1LjkxOCAwIDAgMC04LjM3MiAwbC04LjMyOCA4LjMzMiAxMC41NjYgMTAuNTY2YTcuMDMgNy4wMyAwIDAgMSA3LjIzIDEuNjg0IDcuMDM0IDcuMDM0IDAgMCAxIDEuNjY5IDcuMjc3bDEwLjE4NyAxMC4xODRhNy4wMjggNy4wMjggMCAwIDEgNy4yNzggMS42NzIgNy4wNCA3LjA0IDAgMCAxIDAgOS45NTcgNy4wNSA3LjA1IDAgMCAxLTkuOTY1IDAgNy4wNDQgNy4wNDQgMCAwIDEtMS41MjgtNy42NmwtOS41LTkuNDk3VjU5LjM2YTcuMDQgNy4wNCAwIDAgMSAxLjg2IDExLjI5IDcuMDQgNy4wNCAwIDAgMS05Ljk1NyAwIDcuMDQgNy4wNCAwIDAgMSAwLTkuOTU4IDcuMDYgNy4wNiAwIDAgMSAyLjMwNC0xLjUzOVYzMy45MjZhNy4wNDkgNy4wNDkgMCAwIDEtMy44Mi05LjIzNEwyOS4yNDIgMTQuMjcyIDEuNzMgNDEuNzc3YTUuOTI1IDUuOTI1IDAgMCAwIDAgOC4zNzFMNDEuODUyIDkwLjI3YTUuOTI1IDUuOTI1IDAgMCAwIDguMzcgMGwzOS45MzQtMzkuOTM0YTUuOTI1IDUuOTI1IDAgMCAwIDAtOC4zNzEiLz48L2c+PC9zdmc+', 'git', 'Git', 'Puter Git client', 0, 1, 0, 'https://builtins.namespaces.puter.com/git', 1, 0, 0, '2024-05-15 10:33:00', NULL, 'productivity', NULL); \ No newline at end of file diff --git a/packages/git/.gitignore b/packages/git/.gitignore new file mode 100644 index 0000000000..04c01ba7ba --- /dev/null +++ b/packages/git/.gitignore @@ -0,0 +1,2 @@ +node_modules/ +dist/ \ No newline at end of file diff --git a/packages/git/LICENSE b/packages/git/LICENSE new file mode 100644 index 0000000000..0ad25db4bd --- /dev/null +++ b/packages/git/LICENSE @@ -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/packages/git/README.md b/packages/git/README.md new file mode 100644 index 0000000000..bd2a929066 --- /dev/null +++ b/packages/git/README.md @@ -0,0 +1,3 @@ +# Puter Git Client + +This is a git client running on the Puter filesystem, using [isomorphic-git](https://isomorphic-git.org). \ No newline at end of file diff --git a/packages/git/assets/index.html b/packages/git/assets/index.html new file mode 100644 index 0000000000..185253db78 --- /dev/null +++ b/packages/git/assets/index.html @@ -0,0 +1,18 @@ + + + + + Git client + + + + + + + This is a cli app so you shouldn't see this + + \ No newline at end of file diff --git a/packages/git/config/dev.js b/packages/git/config/dev.js new file mode 100644 index 0000000000..568e187537 --- /dev/null +++ b/packages/git/config/dev.js @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Phoenix Shell. + * + * Phoenix Shell 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 . + */ +globalThis.__CONFIG__ = { + sdk_url: 'http://puter.localhost:4100/sdk/puter.js', +}; diff --git a/packages/git/config/release.js b/packages/git/config/release.js new file mode 100644 index 0000000000..094a08d406 --- /dev/null +++ b/packages/git/config/release.js @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Phoenix Shell. + * + * Phoenix Shell 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 . + */ +globalThis.__CONFIG__ = { + sdk_url: 'https://puter.com/puter.js/v2', +}; diff --git a/packages/git/package.json b/packages/git/package.json new file mode 100644 index 0000000000..2e0f90e45c --- /dev/null +++ b/packages/git/package.json @@ -0,0 +1,20 @@ +{ + "name": "git", + "version": "1.0.0", + "description": "Git Client for Puter", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "author": "Puter Technologies Inc.", + "license": "AGPL-3.0-only", + "type": "module", + "devDependencies": { + "@rollup/plugin-commonjs": "^24.1.0", + "@rollup/plugin-node-resolve": "^15.0.2", + "@rollup/plugin-replace": "^5.0.2", + "mocha": "^10.2.0", + "rollup": "^3.21.4", + "rollup-plugin-copy": "^3.4.0" + } +} diff --git a/packages/git/rollup.config.js b/packages/git/rollup.config.js new file mode 100644 index 0000000000..9c0c6732ab --- /dev/null +++ b/packages/git/rollup.config.js @@ -0,0 +1,53 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Phoenix Shell. + * + * Phoenix Shell 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 . + */ +import { nodeResolve } from '@rollup/plugin-node-resolve' +import commonjs from '@rollup/plugin-commonjs'; +import copy from 'rollup-plugin-copy'; +import process from 'node:process'; + +const configFile = process.env.CONFIG_FILE ?? 'config/dev.js'; +await import(`./${configFile}`); + +export default { + input: "src/main.js", + output: { + file: "dist/bundle.js", + format: "iife" + }, + plugins: [ + nodeResolve({ + browser: true, + preferBuiltins: false, + }), + commonjs(), + copy({ + targets: [ + { + src: 'assets/index.html', + dest: 'dist', + transform: (contents, name) => { + return contents.toString().replace('__SDK_URL__', + process.env.PUTER_JS_URL ?? globalThis.__CONFIG__.sdk_url); + } + }, + { src: configFile, dest: 'dist', rename: 'config.js' } + ] + }), + ] +} diff --git a/packages/git/src/main.js b/packages/git/src/main.js new file mode 100644 index 0000000000..e871d539df --- /dev/null +++ b/packages/git/src/main.js @@ -0,0 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter's Git client. + * + * Puter's Git client 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 . + */ +window.main = () => { + console.log('Well hello friends!'); +} \ No newline at end of file From b75c42b39f09e63a4fb25485738f4285d6421ef4 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Thu, 16 May 2024 11:43:52 +0100 Subject: [PATCH 0072/2119] Implement Puter filesystem wrapper for git app --- packages/git/src/filesystem.js | 196 +++++++++++++++++++++++++++++++++ 1 file changed, 196 insertions(+) create mode 100644 packages/git/src/filesystem.js diff --git a/packages/git/src/filesystem.js b/packages/git/src/filesystem.js new file mode 100644 index 0000000000..88bf74db6a --- /dev/null +++ b/packages/git/src/filesystem.js @@ -0,0 +1,196 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter's Git client. + * + * Puter's Git client 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 . + */ +import { PosixError } from '@heyputer/puter-js-common/src/PosixError.js'; +import path_ from 'path-browserify'; + +let debug = false; + +// Takes a Puter stat() result and converts it to the format expected by isomorphic-git +const convert_stat = (stat, options) => { + // Puter returns the times as timestamps in seconds + const timestamp_date = (timestamp) => new Date(timestamp * 1000); + const timestamp_ms = (timestamp) => options.bigint ? BigInt(timestamp) * 1000n : timestamp * 1000; + const timestamp_ns = (timestamp) => options.bigint ? BigInt(timestamp) * 1000000n : undefined; + + // We don't record ctime, but the most recent of atime and mtime is a reasonable approximation + const ctime = Math.max(stat.accessed, stat.modified); + + const mode = (() => { + // Puter doesn't expose this, but we can approximate it based on the stats we have. + let user = stat.immutable ? 4 : 6; + let group = stat.immutable ? 4 : 6; + let other = stat.is_public ? 4 : 0; + // Octal number + return user << 6 | group << 3 | other; + })(); + + return { + dev: 1, // Puter doesn't expose this + ino: stat.id, + mode: mode, + nlink: 1, // Definition of hard-link number is platform-defined. Linux includes subdir count, Mac includes child count. + uid: stat.uid, + gid: stat.uid, // Puter doesn't have gids + rdev: 0, + size: stat.size, + blksize: 4096, // Abitrary! + blocks: Math.ceil(stat.size / 4096), + atime: timestamp_date(stat.accessed), + mtime: timestamp_date(stat.modified), + ctime: timestamp_date(ctime), + birthtime: timestamp_date(stat.created), + atimeMs: timestamp_ms(stat.accessed), + mtimeMs: timestamp_ms(stat.modified), + ctimeMs: timestamp_ms(ctime), + birthtimeMs: timestamp_ms(stat.created), + atimeNs: timestamp_ns(stat.accessed), + mtimeNs: timestamp_ns(stat.modified), + ctimeNs: timestamp_ns(ctime), + birthtimeNs: timestamp_ns(stat.created), + + isBlockDevice: () => false, + isCharacterDevice: () => false, + isDirectory: () => stat.is_dir, + isFIFO: () => false, + isFile: () => !stat.is_dir, + isSocket: () => false, + isSymbolicLink: () => stat.is_symlink, + }; +}; + +const adapt_path = (input_path) => { + if (input_path[0] === '/') return input_path; + return path_.relative(window.process.cwd(), input_path); +}; + +// Implements the API expected by isomorphic-git +// See: https://isomorphic-git.org/docs/en/fs#using-the-promise-api-preferred +export default { + enable_debugging: () => { debug = true; }, + promises: { + readFile: async (path, options = {}) => { + if (debug) console.trace('readFile', path, options); + // TODO: Obey options + try { + const blob = await puter.fs.read(adapt_path(path)); + if (options.encoding === 'utf8') + return await blob.text(); + return blob.arrayBuffer(); + } catch (e) { + throw PosixError.fromPuterAPIError(e); + } + }, + writeFile: async (path, data, options = {}) => { + if (debug) console.trace('writeFile', path, data, options); + // TODO: Obey options + + // Convert data into a type puter.fs.write() understands. + // Can be: | | | + // Puter supports: | | + if ( + data instanceof window.Buffer // Buffer + || ArrayBuffer.isView(data) // TypedArray + || data instanceof DataView // DataView + ) { + data = new File([data], path_.basename(path)); + } + + try { + return await puter.fs.write(adapt_path(path), data); + } catch (e) { + throw PosixError.fromPuterAPIError(e); + } + }, + unlink: async (path) => { + if (debug) console.trace('unlink', path); + // TODO: If `path` is a symlink, only remove the link + try { + return await puter.fs.delete(adapt_path(path), { recursive: false }); + } catch (e) { + throw PosixError.fromPuterAPIError(e); + } + }, + readdir: async (path, options = {}) => { + if (debug) console.trace('readdir', path, options); + // TODO: Obey options + try { + const results = await puter.fs.readdir(adapt_path(path)); + // Puter returns an array of stat entries, but we only want the file names + return results.map(it => path_.basename(it.path)); + } catch (e) { + throw PosixError.fromPuterAPIError(e); + } + }, + mkdir: async (path, mode) => { + if (debug) console.trace('mkdir', path, mode); + // NOTE: Puter filesystem doesn't have file permissions + try { + return await puter.fs.mkdir(adapt_path(path)); + } catch (e) { + throw PosixError.fromPuterAPIError(e); + } + }, + rmdir: async (path) => { + if (debug) console.trace('rmdir', path); + // TODO: Only delete dir if it's empty + try { + return await puter.fs.delete(adapt_path(path), { recursive: true }); + } catch (e) { + throw PosixError.fromPuterAPIError(e); + } + }, + stat: async (path, options = {}) => { + if (debug) console.trace('stat', path, options); + // TODO: Obey options + try { + return convert_stat(await puter.fs.stat(adapt_path(path)), options); + } catch (e) { + throw PosixError.fromPuterAPIError(e); + } + }, + lstat: async (path, options = {}) => { + if (debug) console.trace('lstat', path, options); + // TODO: Obey options + // TODO: Stat the link itself. + try { + return convert_stat(await puter.fs.stat(adapt_path(path)), options); + } catch (e) { + throw PosixError.fromPuterAPIError(e); + } + }, + readlink: async (path, options = {}) => { + if (debug) console.trace('readlink', path, options); + try { + const stat = await puter.fs.stat(adapt_path(path)); + return stat.symlink_path; + } catch (e) { + throw PosixError.fromPuterAPIError(e); + } + }, + symlink: async (target, path, type) => { + if (debug) console.trace('symlink', target, path, type); + // TODO: Add symlink creation to puter.fs API + throw PosixError.OperationNotPermitted({ message: 'Puter.fs API does not support creating symlinks' }); + }, + chmod: async (path, mode) => { + if (debug) console.trace('chmod', path, mode); + // NOTE: No-op, Puter doesn't have file permissions + }, + }, +}; \ No newline at end of file From 85b7587c42f7d21d76b6411e063c2dbf49ffb7c7 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Wed, 22 May 2024 11:03:09 +0100 Subject: [PATCH 0073/2119] Implement `git help`, `git version`, and subcommand infrastructure Each subcommand is its own file, modeled after Phoenix's coreutils. --- package-lock.json | 163 ++++++++++++++++++-- packages/git/package.json | 5 + packages/git/src/git-command-definition.js | 39 +++++ packages/git/src/help.js | 143 +++++++++++++++++ packages/git/src/main.js | 147 +++++++++++++++++- packages/git/src/subcommands/__exports__.js | 26 ++++ packages/git/src/subcommands/help.js | 67 ++++++++ packages/git/src/subcommands/version.js | 40 +++++ 8 files changed, 615 insertions(+), 15 deletions(-) create mode 100644 packages/git/src/git-command-definition.js create mode 100644 packages/git/src/help.js create mode 100644 packages/git/src/subcommands/__exports__.js create mode 100644 packages/git/src/subcommands/help.js create mode 100644 packages/git/src/subcommands/version.js diff --git a/package-lock.json b/package-lock.json index 713fe84022..912ca559c9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3357,6 +3357,14 @@ "node": ">=10.0.0" } }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "engines": { + "node": ">=14" + } + }, "node_modules/@protobufjs/aspromise": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", @@ -4547,6 +4555,11 @@ "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz", "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==" }, + "node_modules/async-lock": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/async-lock/-/async-lock-1.4.1.tgz", + "integrity": "sha512-Az2ZTpuytrtqENulXwO3GGv1Bztugx6TT37NIo7imr/Qo0gsYiGtSdBa2B6fsXhTpVZDNfu1Qn3pk531e3q+nQ==" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -5148,6 +5161,11 @@ "node": ">= 10.0" } }, + "node_modules/clean-git-ref": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/clean-git-ref/-/clean-git-ref-2.0.1.tgz", + "integrity": "sha512-bLSptAy2P0s6hU4PzuIMKmMJJSE6gLXGH1cntDu7bWJUksvuM+7ReOK61mozULErYvP6a15rnYl0zFDef+pyPw==" + }, "node_modules/clean-stack": { "version": "2.2.0", "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", @@ -5499,6 +5517,17 @@ "node": ">=10.0.0" } }, + "node_modules/crc-32": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz", + "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==", + "bin": { + "crc32": "bin/crc32.njs" + }, + "engines": { + "node": ">=0.8" + } + }, "node_modules/cross-fetch": { "version": "3.1.8", "resolved": "https://registry.npmjs.org/cross-fetch/-/cross-fetch-3.1.8.tgz", @@ -5768,6 +5797,11 @@ "node": ">=0.3.1" } }, + "node_modules/diff3": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/diff3/-/diff3-0.0.3.tgz", + "integrity": "sha512-iSq8ngPOt0K53A6eVr4d5Kn6GNrM2nQZtC740pzIriHtn4pOQ2lyzEXQMBeVcWERN0ye7fhBsk9PbLLQOnUx/g==" + }, "node_modules/dir-glob": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", @@ -7226,7 +7260,6 @@ "version": "5.3.1", "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", - "dev": true, "engines": { "node": ">= 4" } @@ -7615,6 +7648,43 @@ "whatwg-fetch": "^3.4.1" } }, + "node_modules/isomorphic-git": { + "version": "1.25.10", + "resolved": "https://registry.npmjs.org/isomorphic-git/-/isomorphic-git-1.25.10.tgz", + "integrity": "sha512-IxGiaKBwAdcgBXwIcxJU6rHLk+NrzYaaPKXXQffcA0GW3IUrQXdUPDXDo+hkGVcYruuz/7JlGBiuaeTCgIgivQ==", + "dependencies": { + "async-lock": "^1.4.1", + "clean-git-ref": "^2.0.1", + "crc-32": "^1.2.0", + "diff3": "0.0.3", + "ignore": "^5.1.4", + "minimisted": "^2.0.0", + "pako": "^1.0.10", + "pify": "^4.0.1", + "readable-stream": "^3.4.0", + "sha.js": "^2.4.9", + "simple-get": "^4.0.1" + }, + "bin": { + "isogit": "cli.cjs" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/isomorphic-git/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/istanbul-lib-coverage": { "version": "3.2.2", "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.2.tgz", @@ -8402,6 +8472,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/minimisted": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minimisted/-/minimisted-2.0.1.tgz", + "integrity": "sha512-1oPjfuLQa2caorJUM8HV8lGgWCc0qqAO1MNv/k05G4qslmsndV/5WdNZrqCiyqiz3wohia2Ij2B7w2Dr7/IyrA==", + "dependencies": { + "minimist": "^1.2.5" + } + }, "node_modules/minipass": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", @@ -9303,6 +9381,11 @@ "node": ">= 0.8" } }, + "node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" + }, "node_modules/path-exists": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", @@ -9423,6 +9506,14 @@ "url": "https://github.com/sponsors/jonschlinkert" } }, + "node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "engines": { + "node": ">=6" + } + }, "node_modules/pixelmatch": { "version": "4.0.2", "resolved": "https://registry.npmjs.org/pixelmatch/-/pixelmatch-4.0.2.tgz", @@ -10280,6 +10371,18 @@ "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, "node_modules/shallow-clone": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", @@ -11947,6 +12050,11 @@ "packages/git": { "version": "1.0.0", "license": "AGPL-3.0-only", + "dependencies": { + "@pkgjs/parseargs": "^0.11.0", + "buffer": "^6.0.3", + "isomorphic-git": "^1.25.10" + }, "devDependencies": { "@rollup/plugin-commonjs": "^24.1.0", "@rollup/plugin-node-resolve": "^15.0.2", @@ -11956,6 +12064,48 @@ "rollup-plugin-copy": "^3.4.0" } }, + "packages/git/node_modules/buffer": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz", + "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.2.1" + } + }, + "packages/git/node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "packages/phoenix": { "name": "@heyputer/phoenix", "version": "0.0.0", @@ -11988,13 +12138,6 @@ "node-pty": "^1.0.0" } }, - "packages/phoenix/node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "license": "MIT", - "engines": { - "node": ">=14" - } - }, "packages/phoenix/node_modules/@sinonjs/fake-timers": { "version": "11.2.2", "license": "BSD-3-Clause", @@ -12079,10 +12222,6 @@ "version": "3.0.9", "license": "MIT" }, - "packages/phoenix/node_modules/path-browserify": { - "version": "1.0.1", - "license": "MIT" - }, "packages/phoenix/node_modules/randomstring": { "version": "1.3.0", "license": "MIT", diff --git a/packages/git/package.json b/packages/git/package.json index 2e0f90e45c..30cac607d8 100644 --- a/packages/git/package.json +++ b/packages/git/package.json @@ -16,5 +16,10 @@ "mocha": "^10.2.0", "rollup": "^3.21.4", "rollup-plugin-copy": "^3.4.0" + }, + "dependencies": { + "@pkgjs/parseargs": "^0.11.0", + "buffer": "^6.0.3", + "isomorphic-git": "^1.25.10" } } diff --git a/packages/git/src/git-command-definition.js b/packages/git/src/git-command-definition.js new file mode 100644 index 0000000000..6ff37f0ab1 --- /dev/null +++ b/packages/git/src/git-command-definition.js @@ -0,0 +1,39 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter's Git client. + * + * Puter's Git client 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 . + */ + +/** + * The command definition for `git` itself, in the same format as subcommands. + */ +export default { + name: 'git', + usage: 'git [--version] [--help] [command] [command-args...]', + description: 'Git version-control client for Puter.', + args: { + options: { + help: { + description: 'Display help information for git itself, or a subcommand.', + type: 'boolean', + }, + version: { + description: 'Display version information about git.', + type: 'boolean', + }, + }, + }, +}; diff --git a/packages/git/src/help.js b/packages/git/src/help.js new file mode 100644 index 0000000000..bd0b9c02a0 --- /dev/null +++ b/packages/git/src/help.js @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter's Git client. + * + * Puter's Git client 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 . + */ + +/** + * Throw this from a subcommand's execute() in order to print its usage text to stderr. + * @type {symbol} + */ +export const SHOW_USAGE = Symbol('SHOW_USAGE'); + +/** + * Full manual page for the command. + * @param command + * @returns {string} + */ +export const produce_help_string = (command) => { + const { name, usage, description, args } = command; + const options = args?.options; + + let s = ''; + const indent = ' '; + + const heading = (text) => { + s += `\n\x1B[34;1m${text}:\x1B[0m\n` + }; + + heading('SYNOPSIS'); + if (!usage) { + s += `${indent}git ${name}\n`; + } else if (typeof usage === 'string') { + s += `${indent}${usage}\n`; + } else { + let first = true; + for (const usage_line of usage) { + if (first) { + first = false; + s += `${indent}${usage_line}\n`; + } else { + s += `${indent}${usage_line}\n`; + } + } + } + + if (description) { + heading('DESCRIPTION'); + s += `${indent}${description}\n`; + } + + if (typeof options === 'object' && Object.keys(options).length > 0) { + heading('OPTIONS'); + // Figure out how long each invocation is, so we can align the descriptions + for (const [name, option] of Object.entries(options)) { + // Invocation + s += indent; + if (option.short) + s += `-${option.short}, `; + s += `--${name}`; + if (option.type !== 'boolean') + s += ` <${option.type}>`; + s += '\n'; + + // Description + s += `${indent}${indent}${option.description}\n\n`; + } + } + + if (!s.endsWith('\n\n')) + s += '\n'; + + return s; +} + +/** + * Usage for the command, which is a short summary. + * @param command + * @returns {string} + */ +export const produce_usage_string = (command) => { + const { name, usage, args } = command; + const options = args?.options; + + let s = ''; + + // Usage + if (!usage) { + s += `usage: git ${name}\n`; + } else if (typeof usage === 'string') { + s += `usage: ${usage}\n`; + } else { + let first = true; + for (const usage_line of usage) { + if (first) { + first = false; + s += `usage: ${usage_line}\n`; + } else { + s += ` or: ${usage_line}\n`; + } + } + } + + // List of options + if (typeof options === 'object' && Object.keys(options).length > 0) { + // Figure out how long each invocation is, so we can align the descriptions + const option_strings = Object.entries(options).map(([name, option]) => { + let invocation = ''; + if (option.short) + invocation += `-${option.short}, `; + invocation += `--${name}`; + if (option.type !== 'boolean') + invocation += ` <${option.type}>`; + + return [invocation, option.description]; + }); + + const indent_size = 2 + option_strings.reduce( + (max_length, option) => Math.max(max_length, option[0].length), 0); + + s += '\n'; + for (const [invocation, description] of option_strings) { + s += ` ${invocation}`; + if (indent_size - invocation.length > 0) + s += ' '.repeat(indent_size - invocation.length); + s += `${description}\n`; + } + } + + return s; +} diff --git a/packages/git/src/main.js b/packages/git/src/main.js index e871d539df..adb1f744bc 100644 --- a/packages/git/src/main.js +++ b/packages/git/src/main.js @@ -16,6 +16,147 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -window.main = () => { - console.log('Well hello friends!'); -} \ No newline at end of file +import { parseArgs } from '@pkgjs/parseargs'; +import subcommands from './subcommands/__exports__.js'; +import git_command from './git-command-definition.js'; +import fs from './filesystem.js'; +import git from 'isomorphic-git'; +import { Buffer } from 'buffer'; +import { produce_usage_string, SHOW_USAGE } from './help.js'; + +const encoder = new TextEncoder(); + +window.Buffer = Buffer; + +window.main = async () => { + const shell = puter.ui.parentApp(); + if (!shell) { + await puter.ui.alert('Git must be run from a terminal. Try `git --help`'); + puter.exit(); + return; + } + + shell.on('close', () => { + console.log('Shell closed; exiting git...'); + puter.exit(); + }); + + const stdout = (message) => { + shell.postMessage({ + $: 'stdout', + data: encoder.encode(message + '\n'), + }); + }; + // TODO: Separate stderr message? + const stderr = stdout; + + const url_params = new URL(document.location).searchParams; + const puter_args = JSON.parse(url_params.get('puter.args')) ?? {}; + const { command_line, env } = puter_args; + + // isomorphic-git assumes the Node.js process object exists, + // so fill-in the parts it uses. + window.process = { + cwd: () => env.PWD, + platform: 'puter', + } + + // Git's command structure is a little unusual: + // > git [options-for-git] [subcommand [options-and-args-for-subcommand]] + // Also, a couple of options (--help and --version) are syntactic sugar for `help` and `version` subcommands. + // The approach here is to first try and parse these top-level options, and then based on that, run a subcommand. + + // If no raw args, just print help and exit + const raw_args = command_line?.args ?? []; + if (raw_args.length === 0) { + stdout(produce_usage_string(git_command)); + puter.exit(); + return; + } + + const { values: global_options, positionals: global_positionals } = parseArgs({ + options: git_command.args.options, + allowPositionals: true, + args: raw_args, + strict: false, + }); + + let subcommand_name = null; + let first_positional_is_subcommand = false; + if (global_options.help) { + subcommand_name = 'help'; + } else if (global_options.version) { + subcommand_name = 'version'; + } + + if (!subcommand_name) { + subcommand_name = global_positionals[0]; + first_positional_is_subcommand = true; + } + + // See if we're running a subcommand we recognize + let exit_code = 0; + const subcommand = subcommands[subcommand_name]; + if (!subcommand) { + stderr(`git: '${subcommand_name}' is not a recognized git command. See 'git --help'`); + puter.exit(1); + return; + } + + // Try and remove the subcommand positional arg, and any global options, from args. + const subcommand_args = raw_args; + const remove_arg = (arg) => { + const index = subcommand_args.indexOf(arg); + if (index >= 0) + subcommand_args.splice(index, 1); + + } + remove_arg('--help'); + remove_arg('--version'); + if (first_positional_is_subcommand) { + // TODO: This is not a 100% reliable way to do this, as it may also match the value of `--option-with-value value` + // But that's not a problem until we add some global options that take a value. + remove_arg(subcommand_name); + } + + // Parse the remaining args scoped to this subcommand, and run it. + let parsed_args; + try { + parsed_args = parseArgs({ + ...subcommand.args, + args: subcommand_args, + }); + } catch (e) { + stderr(produce_usage_string(subcommand)); + puter.exit(1); + return; + } + + const ctx = { + io: { + stdout, + stderr, + }, + fs, + args: { + options: parsed_args.values, + positionals: parsed_args.positionals, + }, + env, + }; + + try { + exit_code = await subcommand.execute(ctx) ?? 0; + } catch (e) { + if (e === SHOW_USAGE) { + stderr(produce_usage_string(subcommand)); + } else { + stderr(`fatal: ${e.message}`); + console.error(e); + } + exit_code = 1; + } + + // TODO: Support passing an exit code to puter.exit(); + puter.exit(exit_code); +} diff --git a/packages/git/src/subcommands/__exports__.js b/packages/git/src/subcommands/__exports__.js new file mode 100644 index 0000000000..1633f161ff --- /dev/null +++ b/packages/git/src/subcommands/__exports__.js @@ -0,0 +1,26 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Phoenix Shell. + * + * Phoenix Shell 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 . + */ +// Generated by /tools/gen.js +import module_help from './help.js' +import module_version from './version.js' + +export default { + "help": module_help, + "version": module_version, +}; diff --git a/packages/git/src/subcommands/help.js b/packages/git/src/subcommands/help.js new file mode 100644 index 0000000000..1a27f83159 --- /dev/null +++ b/packages/git/src/subcommands/help.js @@ -0,0 +1,67 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter's Git client. + * + * Puter's Git client 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 . + */ +import git from 'isomorphic-git'; +import { ErrorCodes } from '@heyputer/puter-js-common/src/PosixError.js'; +import subcommands from './__exports__.js'; +import git_command from '../git-command-definition.js'; +import { produce_help_string } from '../help.js'; + +export default { + name: 'help', + usage: ['git help [-a|--all]', 'git help '], + description: `Display help information for git itself, or a subcommand.`, + args: { + allowPositionals: true, + options: { + all: { + description: 'List all available subcommands.', + type: 'boolean', + } + }, + }, + execute: async (ctx) => { + const { io, fs, env, args } = ctx; + const { stdout, stderr } = io; + const { options, positionals } = args; + + if (options.all) { + stdout(`See 'git help ' for more information.\n`); + const max_name_length = Object.keys(subcommands).reduce((max, name) => Math.max(max, name.length), 0); + for (const [name, command] of Object.entries(subcommands)) { + stdout(` ${name} ${' '.repeat(Math.max(max_name_length - name.length, 0))} ${command.description || ''}`); + } + return; + } + + if (positionals.length > 0) { + // Try and display help page for the subcommand + const subcommand_name = positionals[0]; + const subcommand = subcommands[subcommand_name]; + if (!subcommand) + throw new Error(`No manual entry for ${subcommand_name}`); + + stdout(produce_help_string(subcommand)); + + return; + } + + // No subcommand name, so show general help + stdout(produce_help_string(git_command)); + } +} diff --git a/packages/git/src/subcommands/version.js b/packages/git/src/subcommands/version.js new file mode 100644 index 0000000000..2e639f0d00 --- /dev/null +++ b/packages/git/src/subcommands/version.js @@ -0,0 +1,40 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter's Git client. + * + * Puter's Git client 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 . + */ +import git from 'isomorphic-git'; +import path from 'path-browserify'; +import { ErrorCodes } from '@heyputer/puter-js-common/src/PosixError.js'; + +const VERSION = '1.0.0'; + +export default { + name: 'version', + usage: 'git version', + description: `Display version information about git.`, + args: { + allowPositionals: false, + options: {}, + }, + execute: async (ctx) => { + const { io, fs, env, args } = ctx; + const { stdout, stderr } = io; + const { options, positionals } = args; + + stdout(`Puter git version ${VERSION} (isomorphic git version ${git.version()})`); + } +} From 5e3db870ec33029b7aa47fc3e7dc0367cbcb6d01 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Wed, 22 May 2024 11:05:54 +0100 Subject: [PATCH 0074/2119] Implement `git init` --- packages/git/src/subcommands/__exports__.js | 2 + packages/git/src/subcommands/init.js | 97 +++++++++++++++++++++ 2 files changed, 99 insertions(+) create mode 100644 packages/git/src/subcommands/init.js diff --git a/packages/git/src/subcommands/__exports__.js b/packages/git/src/subcommands/__exports__.js index 1633f161ff..b16c5f6af5 100644 --- a/packages/git/src/subcommands/__exports__.js +++ b/packages/git/src/subcommands/__exports__.js @@ -18,9 +18,11 @@ */ // Generated by /tools/gen.js import module_help from './help.js' +import module_init from './init.js' import module_version from './version.js' export default { "help": module_help, + "init": module_init, "version": module_version, }; diff --git a/packages/git/src/subcommands/init.js b/packages/git/src/subcommands/init.js new file mode 100644 index 0000000000..cf211309a5 --- /dev/null +++ b/packages/git/src/subcommands/init.js @@ -0,0 +1,97 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter's Git client. + * + * Puter's Git client 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 . + */ +import git from 'isomorphic-git'; +import path from 'path-browserify'; +import { ErrorCodes } from '@heyputer/puter-js-common/src/PosixError.js'; + +export default { + name: 'init', + usage: 'git init [--bare] [--initial-branch=BRANCH] [--separate-git-dir=DIR]', + description: `Initialize or re-initialize a git repository.`, + args: { + allowPositionals: true, + options: { + 'bare': { + description: 'Create a bare repository', + type: 'boolean', + default: false, + }, + 'initial-branch': { + description: 'Name of the initial branch', + type: 'string', + short: 'b', + }, + 'separate-git-dir': { + description: 'Name of directory to store the git repository, instead of ./.git/', + type: 'string', + default: './.git', + }, + }, + }, + execute: async (ctx) => { + const { io, fs, env, args } = ctx; + const { stdout, stderr } = io; + const { options, positionals } = args; + + const [ directory, ...extra_positionals ] = positionals ?? []; + if (extra_positionals.length) { + stderr('Too many parameters'); + return 1; + } + + const dir = directory ? path.resolve(env.PWD, directory) : env.PWD; + const gitdir = path.resolve(dir, options['separate-git-dir']); + const dot_git_path = path.resolve(dir, './.git'); + + // Check if repo already initialized + let repo_exists = false; + try { + const stat = await fs.promises.stat(dot_git_path); + repo_exists = true; + } catch (e) { + if (e.posixCode === ErrorCodes.ENOENT) { + repo_exists = false; + } + } + + if (repo_exists) { + // TODO: `git init` in an existing repo re-initializes it without erasing anything. + // If the git dir provided is different than the existing one, it moves the contents to the new location. + // isomorphic-git does not seem to do this, and it's an unusual case, so for now we just prevent `git init` + // for existing repos. + stderr('Git repository already initialized'); + return 1; + } + + await git.init({ + fs, + bare: options.bare, + dir, + gitdir, + defaultBranch: options['initial-branch'], + }).then(() => { + // If we're using a different git dir, create a .git file pointing to it + if (gitdir !== dot_git_path) { + return fs.promises.writeFile(dot_git_path, `gitdir: ${gitdir}\n`, { encoding: 'utf8' }); + } + }); + + stdout(`Initialized empty git repository in ${gitdir}`); + } +} From 71873a9c276c01adf4aff838f19b790ac58bf246 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Fri, 17 May 2024 12:49:08 +0100 Subject: [PATCH 0075/2119] Add a helper function for finding the git repo --- packages/git/src/git-helpers.js | 72 +++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 packages/git/src/git-helpers.js diff --git a/packages/git/src/git-helpers.js b/packages/git/src/git-helpers.js new file mode 100644 index 0000000000..75fe87fad7 --- /dev/null +++ b/packages/git/src/git-helpers.js @@ -0,0 +1,72 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter's Git client. + * + * Puter's Git client 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 . + */ +import path from 'path-browserify'; + +/** + * Attempt to locate the git repository directory. + * @throws Error If no git repository could be found, or another error occurred. + * @param fs Filesystem API + * @param pwd Directory to search from + * @returns {Promise<{repository_dir: (string|*), git_dir: (string|string)}>} + */ +export const find_repo_root = async (fs, pwd) => { + if (!path.isAbsolute(pwd)) + throw new Error(`PWD is not absolute: ${pwd}`); + + let current_path = path.normalize(pwd); + while (true) { + let stat; + const current_git_path = path.resolve(current_path, './.git'); + try { + stat = await fs.promises.stat(current_git_path); + } catch (e) { + if (e.code === 'ENOENT') { + if (current_path === '/') + break; + + current_path = path.dirname(current_path); + continue; + } + + throw e; + } + + // If .git exists, we're probably in a git repo so call that good. + // TODO: The git cli seems to check other things, maybe try to match that behaviour. + + const result = { + repository_dir: current_path, + git_dir: current_git_path, + }; + + // Non-default-git-folder repos have .git as a text file containing the git dir path. + if (stat.isFile()) { + const contents = await fs.promises.readFile(current_git_path, { encoding: 'utf8' }); + // The format of .git is `gitdir: /path/to/git/dir` + const prefix = 'gitdir:'; + if (!contents.startsWith(prefix)) + throw new Error(`invalid gitfile format: ${current_git_path}`); + result.git_dir = contents.slice(prefix.length).trim(); + } + + return result; + } + + throw new Error('not a git repository (or any of the parent directories): .git'); +} From 5a308a2a53fa33c8aeb5058c00af6d2d226cdcb4 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Fri, 17 May 2024 12:49:33 +0100 Subject: [PATCH 0076/2119] Implement `git status` --- packages/git/src/subcommands/__exports__.js | 2 + packages/git/src/subcommands/status.js | 141 ++++++++++++++++++++ 2 files changed, 143 insertions(+) create mode 100644 packages/git/src/subcommands/status.js diff --git a/packages/git/src/subcommands/__exports__.js b/packages/git/src/subcommands/__exports__.js index b16c5f6af5..e76cb70aeb 100644 --- a/packages/git/src/subcommands/__exports__.js +++ b/packages/git/src/subcommands/__exports__.js @@ -19,10 +19,12 @@ // Generated by /tools/gen.js import module_help from './help.js' import module_init from './init.js' +import module_status from './status.js' import module_version from './version.js' export default { "help": module_help, "init": module_init, + "status": module_status, "version": module_version, }; diff --git a/packages/git/src/subcommands/status.js b/packages/git/src/subcommands/status.js new file mode 100644 index 0000000000..3ad136be26 --- /dev/null +++ b/packages/git/src/subcommands/status.js @@ -0,0 +1,141 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter's Git client. + * + * Puter's Git client 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 . + */ +import git from 'isomorphic-git'; +import path from 'path-browserify'; +import { ErrorCodes } from '@heyputer/puter-js-common/src/PosixError.js'; +import { find_repo_root } from '../git-helpers.js'; + +export default { + name: 'status', + usage: 'git status', + description: 'Describe the status of the git working tree.', + args: { + allowPositionals: false, + options: { + }, + }, + execute: async (ctx) => { + const { io, fs, env, args } = ctx; + const { stdout, stderr } = io; + const { options, positionals } = args; + + const { repository_dir, git_dir } = await find_repo_root(fs, env.PWD); + + // Gather up file differences + const file_status = await git.statusMatrix({ + fs, + dir: repository_dir, + gitdir: git_dir, + ignored: false, + }); + + const staged = []; + const unstaged = []; + const untracked = []; + + const HEAD = 1; + const WORKDIR = 2; + const STAGE = 3; + + for (const file of file_status) { + const absolute_path = path.resolve(repository_dir, file[0]); + const relative_path = path.relative(env.PWD, absolute_path); + + const status_string = `${file[1]}${file[2]}${file[3]}`; + switch (status_string) { + case '020': // new, untracked + untracked.push(relative_path); + break; + case '022': // added, staged + staged.push([relative_path, 'added']); + break; + case '023': // added, staged, with unstaged changes + staged.push([relative_path, 'added']); + unstaged.push([relative_path, 'modified']); + break; + case '111': // unmodified + // Ignore it + break; + case '121': // modified, unstaged + unstaged.push([relative_path, 'modified']); + break; + case '122': // modified, staged + staged.push([relative_path, 'modified']); + break; + case '123': // modified, staged, with unstaged changes + staged.push([relative_path, 'modified']); + unstaged.push([relative_path, 'modified']); + break; + case '101': // deleted, unstaged + unstaged.push([relative_path, 'deleted']); + break; + case '100': // deleted, staged + staged.push([relative_path, 'deleted']); + break; + case '120': // deleted, staged, with unstaged-modified changes (new file of the same name) + case '110': // deleted, staged, with unstaged changes (new file of the same name) + staged.push([relative_path, 'deleted']); + unstaged.push([relative_path, 'added']); + break; + } + } + + // TODO: Short-format output + + const padding = (length) => { + if (length <= 0) return ''; + return ' '.repeat(length); + } + + const current_branch = await git.currentBranch({ + fs, + dir: repository_dir, + gitdir: git_dir, + }); + stdout(`On branch ${current_branch}\n`); + + if (staged.length) { + stdout('Changes to be committed:'); + for (const [file, change] of staged) { + stdout(` ${change}: ${padding(10 - change.length)}${file}`); + } + stdout(''); + } + + if (unstaged.length) { + stdout('Changes not staged for commit:'); + for (const [file, change] of unstaged) { + stdout(` ${change}: ${padding(10 - change.length)}${file}`); + } + stdout(''); + } + + if (untracked.length) { + stdout('Untracked files:'); + // TODO: Native git is smart enough to only list a top-level directory if all its contents are untracked + for (const file of untracked) { + stdout(` ${file}`); + } + } + + if (staged.length + unstaged.length + untracked.length === 0) { + stdout('nothing to commit, working tree clean'); + } + } +} From 32c172d1458ada4a024784baf9e8dec72aa0df33 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Fri, 17 May 2024 14:56:44 +0100 Subject: [PATCH 0077/2119] Implement `git add` --- packages/git/src/subcommands/__exports__.js | 2 + packages/git/src/subcommands/add.js | 55 +++++++++++++++++++++ 2 files changed, 57 insertions(+) create mode 100644 packages/git/src/subcommands/add.js diff --git a/packages/git/src/subcommands/__exports__.js b/packages/git/src/subcommands/__exports__.js index e76cb70aeb..4e89b78743 100644 --- a/packages/git/src/subcommands/__exports__.js +++ b/packages/git/src/subcommands/__exports__.js @@ -17,12 +17,14 @@ * along with this program. If not, see . */ // Generated by /tools/gen.js +import module_add from './add.js' import module_help from './help.js' import module_init from './init.js' import module_status from './status.js' import module_version from './version.js' export default { + "add": module_add, "help": module_help, "init": module_init, "status": module_status, diff --git a/packages/git/src/subcommands/add.js b/packages/git/src/subcommands/add.js new file mode 100644 index 0000000000..441576d097 --- /dev/null +++ b/packages/git/src/subcommands/add.js @@ -0,0 +1,55 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter's Git client. + * + * Puter's Git client 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 . + */ +import git from 'isomorphic-git'; +import path from 'path-browserify'; +import { ErrorCodes } from '@heyputer/puter-js-common/src/PosixError.js'; +import { find_repo_root } from '../git-helpers.js'; + +export default { + name: 'add', + usage: 'git add [--] [...]', + description: 'Add file contents to the index.', + args: { + allowPositionals: true, + options: { + }, + }, + execute: async (ctx) => { + const { io, fs, env, args } = ctx; + const { stdout, stderr } = io; + const { options, positionals } = args; + + const pathspecs = [...positionals]; + if (pathspecs.length === 0) { + stdout('Nothing specified, nothing added.'); + return; + } + + const { repository_dir, git_dir } = await find_repo_root(fs, env.PWD); + + await git.add({ + fs, + dir: repository_dir, + gitdir: git_dir, + ignored: false, + filepath: pathspecs, + parallel: true, + }); + } +} From b4e2ba4544e6b11adb490f972a0fe17f098e37af Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Fri, 17 May 2024 16:56:52 +0100 Subject: [PATCH 0078/2119] Implement `git commit` --- packages/git/src/git-helpers.js | 12 +++ packages/git/src/subcommands/__exports__.js | 2 + packages/git/src/subcommands/commit.js | 114 ++++++++++++++++++++ 3 files changed, 128 insertions(+) create mode 100644 packages/git/src/subcommands/commit.js diff --git a/packages/git/src/git-helpers.js b/packages/git/src/git-helpers.js index 75fe87fad7..87e0086227 100644 --- a/packages/git/src/git-helpers.js +++ b/packages/git/src/git-helpers.js @@ -70,3 +70,15 @@ export const find_repo_root = async (fs, pwd) => { throw new Error('not a git repository (or any of the parent directories): .git'); } + +/** + * Produce a shortened version of the given hash, which is still unique within the repo. + * TODO: Ensure that whatever we produce is unique within the repo. + * For now this is just a convenience function, so there's one place to change later. + * @param hash + * @returns {String} The shortened hash + */ +export const shorten_hash = (hash) => { + // TODO: Ensure that whatever we produce is unique within the repo + return hash.slice(0, 7); +} diff --git a/packages/git/src/subcommands/__exports__.js b/packages/git/src/subcommands/__exports__.js index 4e89b78743..a2fb2741a7 100644 --- a/packages/git/src/subcommands/__exports__.js +++ b/packages/git/src/subcommands/__exports__.js @@ -18,6 +18,7 @@ */ // Generated by /tools/gen.js import module_add from './add.js' +import module_commit from './commit.js' import module_help from './help.js' import module_init from './init.js' import module_status from './status.js' @@ -25,6 +26,7 @@ import module_version from './version.js' export default { "add": module_add, + "commit": module_commit, "help": module_help, "init": module_init, "status": module_status, diff --git a/packages/git/src/subcommands/commit.js b/packages/git/src/subcommands/commit.js new file mode 100644 index 0000000000..35ab9042db --- /dev/null +++ b/packages/git/src/subcommands/commit.js @@ -0,0 +1,114 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter's Git client. + * + * Puter's Git client 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 . + */ +import git from 'isomorphic-git'; +import path from 'path-browserify'; +import { ErrorCodes } from '@heyputer/puter-js-common/src/PosixError.js'; +import { find_repo_root, shorten_hash } from '../git-helpers.js'; + +export default { + name: 'commit', + usage: 'git commit [-m|--message ] [-a|--author ]', + description: 'Commit staged changes to the repository.', + args: { + allowPositionals: false, + options: { + message: { + description: 'Specify the commit message', + type: 'string', + short: 'm', + }, + author: { + description: 'Specify the commit author, as `A U Thor `', + type: 'string', + }, + }, + }, + execute: async (ctx) => { + const { io, fs, env, args } = ctx; + const { stdout, stderr } = io; + const { options, positionals } = args; + + if (!options.message) { + // TODO: Support opening a temporary file in an editor, + // where the user can edit the commit message if it's not specified. + stderr('You must specify a commit message with --message or -m'); + return 1; + } + + const { repository_dir, git_dir } = await find_repo_root(fs, env.PWD); + + let user_name; + let user_email; + + if (options.author) { + const author_regex = /(.+?)\s+<(.+)>/; + const matches = options.author.match(author_regex); + if (!matches) + throw new Error('Failed to parse author string'); + user_name = matches[1]; + user_email = matches[2]; + } else { + user_name = await git.getConfig({ + fs, + dir: repository_dir, + gitdir: git_dir, + path: 'user.name', + }); + user_email = await git.getConfig({ + fs, + dir: repository_dir, + gitdir: git_dir, + path: 'user.email', + }); + } + + if (!user_name || !user_email) { + throw new Error('Missing author information. Either provide --author="A " or set user.name and user.email in the git config'); + } + + const commit_hash = await git.commit({ + fs, + dir: repository_dir, + gitdir: git_dir, + message: options.message, + author: { + name: user_name, + email: user_email, + }, + }); + + const branch = await git.currentBranch({ + fs, + dir: repository_dir, + gitdir: git_dir, + }); + const commit_title = options.message.split('\n')[0]; + const short_hash = shorten_hash(commit_hash); + let output = `[${branch} ${short_hash}] ${commit_title}\n`; + // TODO: --amend prints out the date of the original commit here, as: + // ` Date: Fri May 17 15:45:47 2024 +0100` + // TODO: Print out file change count, insertion count, and deletion count + // (Seems if insertions and deletions are both 0, we should print both. + // Otherwise we just print nonzero ones.) + // TODO: Print out each file created or deleted. eg: + // create mode 100644 bar + // delete mode 100644 foo.txt + stdout(output); + } +} From 98c33fb3cc5973f242618937582d9cd7b0ec40ad Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Tue, 21 May 2024 16:19:14 +0100 Subject: [PATCH 0079/2119] Implement `git log` This is quite barebones for now. Commit formatting is done in a separate file, as this is used by other git commands, such as `show`. --- packages/git/src/format.js | 177 ++++++++++++++++++++ packages/git/src/subcommands/__exports__.js | 2 + packages/git/src/subcommands/log.js | 64 +++++++ 3 files changed, 243 insertions(+) create mode 100644 packages/git/src/format.js create mode 100644 packages/git/src/subcommands/log.js diff --git a/packages/git/src/format.js b/packages/git/src/format.js new file mode 100644 index 0000000000..fe79d5823c --- /dev/null +++ b/packages/git/src/format.js @@ -0,0 +1,177 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter's Git client. + * + * Puter's Git client 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 . + */ +import { shorten_hash } from './git-helpers.js'; + +export const commit_formatting_options = { + 'abbrev-commit': { + description: 'Display commit hashes in abbreviated form.', + type: 'boolean', + }, + 'no-abbrev-commit': { + description: 'Always show full commit hashes.', + type: 'boolean', + }, + 'format': { + description: 'Format to use for commits.', + type: 'string', + }, + 'oneline': { + description: 'Shorthand for "--format=oneline --abbrev-commit".', + type: 'boolean', + }, +}; + +/** + * Process command-line options related to commit formatting, and modify them in place. + * May throw if the options are in some way invalid. + * @param options Parsed command-line options, which will be modified in place. + */ +export const process_commit_formatting_options = (options) => { + if (options.oneline) { + options.format = 'oneline'; + options['abbrev-commit'] = true; + } + + options.short_hashes = (options['abbrev-commit'] === true) && (options['no-abbrev-commit'] !== true); + delete options['abbrev-commit']; + delete options['no-abbrev-commit']; + + if (!options.format) { + options.format = 'medium'; + } + if (!['oneline', 'short', 'medium', 'full', 'fuller', 'raw'].includes(options.format)) { + throw new Error(`Invalid --format format: ${options.format}`); + } +} + +/** + * Format the given oid hash, followed by any refs that point to it + * @param oid + * @param short_hashes Whwther to shorten the hash + * @returns {String} + */ +export const format_oid = (oid, { short_hashes = false } = {}) => { + // TODO: List refs at this commit, after the hash + return short_hashes ? shorten_hash(oid) : oid; +} + +/** + * Format the person's name and email as `${name} <${email}>` + * @param person + * @returns {`${string} <${string}>`} + */ +export const format_person = (person) => { + return `${person.name} <${person.email}>`; +} + +/** + * Format a date + * @param date + * @param options + * @returns {string} + */ +export const format_date = (date, options = {}) => { + // TODO: This needs to obey date-format options, and should show the correct timezone not UTC + return new Date(date.timestamp * 1000).toUTCString(); +} + +/** + * Format the date, according to the "raw" display format. + * @param owner + * @returns {`${string} ${string}${string}${string}`} + */ +export const format_timestamp_and_offset = (owner) => { + // FIXME: The timezone offset is inverted. + // Either this is correct here, or we should be inverting it when creating the commit - + // Isomorphic git uses (new Date()).timezoneOffset() there, which returns -60 for BST, which is UTC+0100 + const offset = -owner.timezoneOffset; + const offset_hours = Math.floor(offset / 60); + const offset_minutes = offset % 60; + const pad = (number) => `${Math.abs(number) < 10 ? '0' : ''}${Math.abs(number)}`; + return `${owner.timestamp} ${offset < 0 ? '-' : '+'}${pad(offset_hours)}${pad(offset_minutes)}`; +} + +/** + * Produce a string representation of a commit. + * @param commit A CommitObject + * @param oid Commit hash + * @param options Options returned by parsing the command arguments in `commit_formatting_options` + * @returns {string} + */ +export const format_commit = (commit, oid, options = {}) => { + const title_line = () => commit.message.split('\n')[0]; + + switch (options.format || 'medium') { + // TODO: Other formats + case 'oneline': + return `${format_oid(oid, options)} ${title_line()}`; + case 'short': { + let s = ''; + s += `commit ${format_oid(oid, options)}\n`; + s += `Author: ${format_person(commit.author)}\n`; + s += '\n'; + s += title_line(); + return s; + } + case 'medium': { + let s = ''; + s += `commit ${format_oid(oid, options)}\n`; + s += `Author: ${format_person(commit.author)}\n`; + s += `Date: ${format_date(commit.author)}\n`; + s += '\n'; + s += commit.message; + return s; + } + case 'full': { + let s = ''; + s += `commit ${format_oid(oid, options)}\n`; + s += `Author: ${format_person(commit.author)}\n`; + s += `Commit: ${format_person(commit.committer)}\n`; + s += '\n'; + s += commit.message; + return s; + } + case 'fuller': { + let s = ''; + s += `commit ${format_oid(oid, options)}\n`; + s += `Author: ${format_person(commit.author)}\n`; + s += `AuthorDate: ${format_date(commit.author)}\n`; + s += `Commit: ${format_person(commit.committer)}\n`; + s += `CommitDate: ${format_date(commit.committer)}\n`; + s += '\n'; + s += commit.message; + return s; + } + case 'raw': { + let s = ''; + s += `commit ${oid}\n`; + s += `tree ${commit.tree}\n`; + if (commit.parent[0]) + s += `parent ${commit.parent[0]}\n`; + s += `author ${format_person(commit.author)} ${format_timestamp_and_offset(commit.author)}\n`; + s += `committer ${format_person(commit.committer)} ${format_timestamp_and_offset(commit.committer)}\n`; + s += '\n'; + s += commit.message; + return s; + } + default: { + throw new Error(`Invalid --format format: ${options.format}`); + } + } +} diff --git a/packages/git/src/subcommands/__exports__.js b/packages/git/src/subcommands/__exports__.js index a2fb2741a7..25cdba9f24 100644 --- a/packages/git/src/subcommands/__exports__.js +++ b/packages/git/src/subcommands/__exports__.js @@ -21,6 +21,7 @@ import module_add from './add.js' import module_commit from './commit.js' import module_help from './help.js' import module_init from './init.js' +import module_log from './log.js' import module_status from './status.js' import module_version from './version.js' @@ -29,6 +30,7 @@ export default { "commit": module_commit, "help": module_help, "init": module_init, + "log": module_log, "status": module_status, "version": module_version, }; diff --git a/packages/git/src/subcommands/log.js b/packages/git/src/subcommands/log.js new file mode 100644 index 0000000000..dfe6f2407e --- /dev/null +++ b/packages/git/src/subcommands/log.js @@ -0,0 +1,64 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter's Git client. + * + * Puter's Git client 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 . + */ +import git from 'isomorphic-git'; +import { find_repo_root } from '../git-helpers.js'; +import { commit_formatting_options, format_commit, process_commit_formatting_options } from '../format.js'; + +export default { + name: 'log', + usage: 'git log [...] [--max-count ] ', + description: 'Show commit logs, starting at the given revision.', + args: { + allowPositionals: false, + options: { + ...commit_formatting_options, + 'max-count': { + description: 'Maximum number of commits to output.', + type: 'string', + short: 'n', + }, + }, + }, + execute: async (ctx) => { + const { io, fs, env, args } = ctx; + const { stdout, stderr } = io; + const { options, positionals } = args; + + process_commit_formatting_options(options); + + // TODO: Log of a specific file + // TODO: Log of a specific branch + // TODO: Log of a specific commit + + const depth = Number(options['max-count']) || undefined; + + const { repository_dir, git_dir } = await find_repo_root(fs, env.PWD); + + const log = await git.log({ + fs, + dir: repository_dir, + gitdir: git_dir, + depth, + }); + + for (const commit of log) { + stdout(format_commit(commit.commit, commit.oid, options)); + } + } +} From 0377015190b7c53edcc72ebd97510028688981fc Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Mon, 20 May 2024 16:13:34 +0100 Subject: [PATCH 0080/2119] Implement `git config` This is also basic: git config key # To read a value git config key value # To set a value git config --unset key # To delete a value As noted, --list is not possible to implement currently. --- packages/git/src/subcommands/__exports__.js | 2 + packages/git/src/subcommands/config.js | 77 +++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 packages/git/src/subcommands/config.js diff --git a/packages/git/src/subcommands/__exports__.js b/packages/git/src/subcommands/__exports__.js index 25cdba9f24..1785defe5c 100644 --- a/packages/git/src/subcommands/__exports__.js +++ b/packages/git/src/subcommands/__exports__.js @@ -19,6 +19,7 @@ // Generated by /tools/gen.js import module_add from './add.js' import module_commit from './commit.js' +import module_config from './config.js' import module_help from './help.js' import module_init from './init.js' import module_log from './log.js' @@ -28,6 +29,7 @@ import module_version from './version.js' export default { "add": module_add, "commit": module_commit, + "config": module_config, "help": module_help, "init": module_init, "log": module_log, diff --git a/packages/git/src/subcommands/config.js b/packages/git/src/subcommands/config.js new file mode 100644 index 0000000000..4c9da23ab1 --- /dev/null +++ b/packages/git/src/subcommands/config.js @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter's Git client. + * + * Puter's Git client 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 . + */ +import git from 'isomorphic-git'; +import { find_repo_root } from '../git-helpers.js'; +import { SHOW_USAGE } from '../help.js'; + +export default { + name: 'config', + usage: ['git config name', 'git config name value', 'git config --unset name'], + description: 'Get or set git configuration options.', + args: { + allowPositionals: true, + options: { + 'unset': { + description: 'Remove the matching line from the config.', + type: 'boolean', + }, + // TODO: --list, which doesn't have a isomorphic-git command yet. + // See https://github.com/isomorphic-git/isomorphic-git/issues/1917 + }, + }, + execute: async (ctx) => { + const { io, fs, env, args } = ctx; + const { stdout, stderr } = io; + const { options, positionals } = args; + + if (positionals.length === 0 || positionals.length > 2) + throw SHOW_USAGE; + + const key = positionals.shift(); + const value = positionals.shift(); + + const { repository_dir, git_dir } = await find_repo_root(fs, env.PWD); + + if (value || options.unset) { + // Set it + // TODO: If --unset AND we have a value, we should only remove an entry that has that value + await git.setConfig({ + fs, + dir: repository_dir, + gitdir: git_dir, + path: key, + value: options.unset ? undefined : value, + }); + return; + } + + // Get it + const result = await git.getConfig({ + fs, + dir: repository_dir, + gitdir: git_dir, + path: key, + }); + if (result === undefined) { + // Not found, so return 1 + return 1; + } + stdout(result); + } +} From 10f715f726c2626251608cbdd96abdce1134aca0 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Tue, 21 May 2024 14:57:39 +0100 Subject: [PATCH 0081/2119] Implement `git show` --- packages/git/src/format.js | 37 ++++++++ packages/git/src/subcommands/__exports__.js | 2 + packages/git/src/subcommands/show.js | 96 +++++++++++++++++++++ 3 files changed, 135 insertions(+) create mode 100644 packages/git/src/subcommands/show.js diff --git a/packages/git/src/format.js b/packages/git/src/format.js index fe79d5823c..967919f278 100644 --- a/packages/git/src/format.js +++ b/packages/git/src/format.js @@ -175,3 +175,40 @@ export const format_commit = (commit, oid, options = {}) => { } } } + +/** + * Produce a string representation of a tree. + * @param oid + * @param tree + * @param options + * @returns {string} + */ +export const format_tree = (oid, tree, options = {}) => { + let s = ''; + s += `tree ${oid}\n`; + s += '\n'; + for (const tree_entry of tree) { + s += `${tree_entry.path}\n`; + } + s += '\n'; + return s; +} + +/** + * Produce a string representation of a tag. + * Note that this only includes the tag itself, and not the tag's target, + * which must be separately retrieved and formatted. + * @param tag + * @param options + * @returns {string} + */ +export const format_tag = (tag, options = {}) => { + let s = ''; + s += `tag ${tag.tag}\n`; + s += `Tagger: ${format_person(tag.tagger)}\n`; + s += `Date: ${format_date(tag.tagger, options)}\n`; + if (tag.message) { + s += `\n${tag.message}\n\n`; + } + return s; +} diff --git a/packages/git/src/subcommands/__exports__.js b/packages/git/src/subcommands/__exports__.js index 1785defe5c..789c592a6c 100644 --- a/packages/git/src/subcommands/__exports__.js +++ b/packages/git/src/subcommands/__exports__.js @@ -23,6 +23,7 @@ import module_config from './config.js' import module_help from './help.js' import module_init from './init.js' import module_log from './log.js' +import module_show from './show.js' import module_status from './status.js' import module_version from './version.js' @@ -33,6 +34,7 @@ export default { "help": module_help, "init": module_init, "log": module_log, + "show": module_show, "status": module_status, "version": module_version, }; diff --git a/packages/git/src/subcommands/show.js b/packages/git/src/subcommands/show.js new file mode 100644 index 0000000000..ef89e23b78 --- /dev/null +++ b/packages/git/src/subcommands/show.js @@ -0,0 +1,96 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter's Git client. + * + * Puter's Git client 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 . + */ +import git from 'isomorphic-git'; +import { find_repo_root } from '../git-helpers.js'; +import { commit_formatting_options, process_commit_formatting_options, format_commit, format_tag, format_tree } from '../format.js'; + +export default { + name: 'show', + usage: 'git show [...] ', + description: 'Show information about an object (commit, tree, tag, blob, etc.) in git.', + args: { + allowPositionals: true, + options: { + ...commit_formatting_options, + }, + }, + execute: async (ctx) => { + const { io, fs, env, args } = ctx; + const { stdout, stderr } = io; + const { options, positionals } = args; + + process_commit_formatting_options(options); + + const { repository_dir, git_dir } = await find_repo_root(fs, env.PWD); + + const objects = [...positionals]; + + const cache = {}; + + const format_object = async (parsed_object, options) => { + switch (parsed_object.type) { + case 'blob': + return parsed_object.object; + case 'commit': + return format_commit(parsed_object.object, parsed_object.oid, options); + case 'tree': + return format_tree(parsed_object.oid, parsed_object.object, options); + case 'tag': { + const tag = parsed_object.object; + let s = format_tag(tag, options); + // Formatting a tag also outputs the formatted object it points to. + // That may also be a tag, so we recurse. + const target = await git.readObject({ + fs, + dir: repository_dir, + gitdir: git_dir, + oid: tag.object, + format: 'parsed', + cache, + }); + s += await format_object(target, options); + return s; + } + } + } + + for (const ref of objects) { + // Could be any ref, so first get the oid that's referred to. + const oid = await git.resolveRef({ + fs, + dir: repository_dir, + gitdir: git_dir, + ref, + }); + + // Then obtain the object and parse it. + const parsed_object = await git.readObject({ + fs, + dir: repository_dir, + gitdir: git_dir, + oid, + format: 'parsed', + cache, + }); + + // Then, print it out + stdout(await format_object(parsed_object, options)); + } + } +} From 7674da4cd225bcad34079251c5600fc32e32248b Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Thu, 23 May 2024 12:54:06 +0100 Subject: [PATCH 0082/2119] feat: Add exit status code to apps `puter.exit()` now takes a status code, similar to the exit status on desktop OSes. This is passed to the appClosed event, so that eg a parent app can know whether its child app ran successfully. --- packages/puter-js/src/index.js | 8 +++++++- packages/puter-js/src/modules/UI.js | 1 + src/IPC.js | 13 +++++++++++-- src/UI/UIWindow.js | 2 +- src/helpers.js | 4 +++- 5 files changed, 23 insertions(+), 5 deletions(-) diff --git a/packages/puter-js/src/index.js b/packages/puter-js/src/index.js index ac27108674..df4c55ee6e 100644 --- a/packages/puter-js/src/index.js +++ b/packages/puter-js/src/index.js @@ -262,10 +262,16 @@ window.puter = (function() { this.updateSubmodules(); } - exit = function() { + exit = function(statusCode = 0) { + if (statusCode && (typeof statusCode !== 'number')) { + console.warn('puter.exit() requires status code to be a number. Treating it as 1'); + statusCode = 1; + } + window.parent.postMessage({ msg: "exit", appInstanceID: this.appInstanceID, + statusCode, }, '*'); } diff --git a/packages/puter-js/src/modules/UI.js b/packages/puter-js/src/modules/UI.js index a8bf3c620e..7bf7e53c03 100644 --- a/packages/puter-js/src/modules/UI.js +++ b/packages/puter-js/src/modules/UI.js @@ -54,6 +54,7 @@ class AppConnection extends EventListener { this.#isOpen = false; this.emit('close', { appInstanceID: this.targetAppInstanceID, + statusCode: event.data.statusCode, }); } }); diff --git a/src/IPC.js b/src/IPC.js index a04cba01a2..28249782df 100644 --- a/src/IPC.js +++ b/src/IPC.js @@ -1201,6 +1201,15 @@ window.addEventListener('message', async (event) => { // exit //-------------------------------------------------------- else if(event.data.msg === 'exit'){ - $(window.window_for_app_instance(event.data.appInstanceID)).close({bypass_iframe_messaging: true}); + // Ensure status code is a number. Convert any truthy non-numbers to 1. + let status_code = event.data.statusCode ?? 0; + if (status_code && (typeof status_code !== 'number')) { + status_code = 1; + } + + $(window.window_for_app_instance(event.data.appInstanceID)).close({ + bypass_iframe_messaging: true, + status_code, + }); } -}); \ No newline at end of file +}); diff --git a/src/UI/UIWindow.js b/src/UI/UIWindow.js index 06def551a2..f8356b2084 100644 --- a/src/UI/UIWindow.js +++ b/src/UI/UIWindow.js @@ -2887,7 +2887,7 @@ $.fn.close = async function(options) { $(`.window[data-parent_uuid="${window_uuid}"]`).close(); // notify other apps that we're closing - window.report_app_closed(window_uuid); + window.report_app_closed(window_uuid, options.status_code ?? 0); // remove backdrop $(this).closest('.window-backdrop').remove(); diff --git a/src/helpers.js b/src/helpers.js index 5e15a53a2b..65f1c15599 100644 --- a/src/helpers.js +++ b/src/helpers.js @@ -3511,7 +3511,7 @@ window.report_app_launched = (instance_id, { uses_sdk = true }) => { }; // Run any callbacks to say that the app has closed -window.report_app_closed = (instance_id) => { +window.report_app_closed = (instance_id, status_code) => { const el_window = window.window_for_app_instance(instance_id); // notify parent app, if we have one, that we're closing @@ -3521,6 +3521,7 @@ window.report_app_closed = (instance_id) => { parent.contentWindow.postMessage({ msg: 'appClosed', appInstanceID: instance_id, + statusCode: status_code ?? 0, }, '*'); } @@ -3530,6 +3531,7 @@ window.report_app_closed = (instance_id) => { child.contentWindow.postMessage({ msg: 'appClosed', appInstanceID: instance_id, + statusCode: status_code ?? 0, }, '*'); }); From 5de305202656a172b187dac87543d6c1c69a2958 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Thu, 23 May 2024 12:55:53 +0100 Subject: [PATCH 0083/2119] feat(phoenix): Respond to exit status codes - Detect exit status of Puter apps, now that that's available. - Store the exit status of each pipeline. - Display a message when the exit status was non-zero. That message is temporary, until we have a better way of displaying or querying it, such as the `$?` shell variable. --- packages/phoenix/src/ansi-shell/ANSIShell.js | 8 ++++++++ .../phoenix/src/ansi-shell/pipeline/Pipeline.js | 17 +++++++++++------ .../providers/PuterAppCommandProvider.js | 9 ++++++--- 3 files changed, 25 insertions(+), 9 deletions(-) diff --git a/packages/phoenix/src/ansi-shell/ANSIShell.js b/packages/phoenix/src/ansi-shell/ANSIShell.js index 68f260a483..b1b4a1c749 100644 --- a/packages/phoenix/src/ansi-shell/ANSIShell.js +++ b/packages/phoenix/src/ansi-shell/ANSIShell.js @@ -160,6 +160,7 @@ export class ANSIShell extends EventTarget { } this.ctx.externs.out.write('error: ' + e.message + '\n'); console.log(e); + this.ctx.locals.exit = -1; return; } } @@ -225,6 +226,13 @@ export class ANSIShell extends EventTarget { const pipeline = await Pipeline.createFromAST(executionCtx, ast); await pipeline.execute(executionCtx); + + // Store exit code for the next pipeline + // TODO: This feels like a hacky way of doing this. + this.ctx.locals.exit = executionCtx.locals.exit; + if ( this.ctx.locals.exit ) { + this.ctx.externs.out.write(`Exited with code ${this.ctx.locals.exit}\n`); + } } expandPromptString (str) { diff --git a/packages/phoenix/src/ansi-shell/pipeline/Pipeline.js b/packages/phoenix/src/ansi-shell/pipeline/Pipeline.js index 186c8cab90..590d96e4b9 100644 --- a/packages/phoenix/src/ansi-shell/pipeline/Pipeline.js +++ b/packages/phoenix/src/ansi-shell/pipeline/Pipeline.js @@ -247,14 +247,14 @@ export class PreparedCommand { if ( ! ctx.cmdExecState.valid ) { ctx.locals.exit = -1; await ctx.externs.out.close(); - return; + return 1; } if ( ctx.cmdExecState.printHelpAndExit ) { ctx.locals.exit = 0; await printUsage(command, ctx.externs.out, ctx.vars); await ctx.externs.out.close(); - return; + return 0; } let execute = command.execute.bind(command); @@ -291,13 +291,14 @@ export class PreparedCommand { command.name + ': ' + e.message + '\x1B[0m\n' ); + exit_code = -1; } else { await ctx.externs.err.write( '\x1B[31;1m' + command.name + ': ' + e.toString() + '\x1B[0m\n' ); - ctx.locals.exit = -1; + exit_code = -1; } if ( ! (e instanceof Exit) ) console.error(e); } @@ -316,6 +317,8 @@ export class PreparedCommand { await filesystem.write(path, outputMemWriters[i].getAsBlob()); } + + return exit_code; } } @@ -348,7 +351,7 @@ export class Pipeline { const valve = new Coupler(nextIn, pipeline_input_pipe.in); nextIn = pipeline_input_pipe.out; - // TOOD: this will eventually defer piping of certain + // TODO: this will eventually defer piping of certain // sub-pipelines to the Puter Shell. for ( let i=0 ; i < preparedCommands.length ; i++ ) { @@ -381,9 +384,11 @@ export class Pipeline { const command = preparedCommands[i]; commandPromises.push(command.execute()); } - await Promise.all(commandPromises); + const results = await Promise.all(commandPromises); + // TODO: Consider what to do about intermediate exit codes + ctx.locals.exit = results[results.length-1]; await coupler.isDone; valve.close(); } -} \ No newline at end of file +} diff --git a/packages/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js b/packages/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js index 2467d78070..53875ea26b 100644 --- a/packages/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js +++ b/packages/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js @@ -57,9 +57,12 @@ export class PuterAppCommandProvider { // Wait for app to close. const app_close_promise = new Promise((resolve, reject) => { - child.on('close', () => { - // TODO: Exit codes for apps - resolve({ done: true }); + child.on('close', (data) => { + if ((data.statusCode ?? 0) != 0) { + reject(new Exit(data.statusCode)); + } else { + resolve({ done: true }); + } }); }); From 3184d3482c7b95c0fd1fc0745555ff82fc9a8c99 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Thu, 23 May 2024 15:27:15 +0100 Subject: [PATCH 0084/2119] feat(phoenix): Implement an `exit` builtin --- packages/phoenix/src/main_cli.js | 2 + packages/phoenix/src/main_puter.js | 2 + packages/phoenix/src/platform/node/system.js | 9 ++++ packages/phoenix/src/platform/puter/system.js | 7 +++ .../src/puter-shell/coreutils/__exports__.js | 2 + .../phoenix/src/puter-shell/coreutils/exit.js | 48 +++++++++++++++++++ 6 files changed, 70 insertions(+) create mode 100644 packages/phoenix/src/platform/node/system.js create mode 100644 packages/phoenix/src/platform/puter/system.js create mode 100644 packages/phoenix/src/puter-shell/coreutils/exit.js diff --git a/packages/phoenix/src/main_cli.js b/packages/phoenix/src/main_cli.js index 9f3106c32f..1f1808eeee 100644 --- a/packages/phoenix/src/main_cli.js +++ b/packages/phoenix/src/main_cli.js @@ -21,6 +21,7 @@ import { launchPuterShell } from './puter-shell/main.js'; import { NodeStdioPTT } from './pty/NodeStdioPTT.js'; import { CreateFilesystemProvider } from './platform/node/filesystem.js'; import { CreateEnvProvider } from './platform/node/env.js'; +import { CreateSystemProvider } from './platform/node/system.js'; import { parseArgs } from '@pkgjs/parseargs'; import capcon from 'capture-console'; import fs from 'fs'; @@ -64,6 +65,7 @@ const ctx = new Context({ name: 'node', filesystem: CreateFilesystemProvider(), env: CreateEnvProvider(), + system: CreateSystemProvider(), }), }); diff --git a/packages/phoenix/src/main_puter.js b/packages/phoenix/src/main_puter.js index 2102fc0781..73d03085ac 100644 --- a/packages/phoenix/src/main_puter.js +++ b/packages/phoenix/src/main_puter.js @@ -22,6 +22,7 @@ import { CreateFilesystemProvider } from './platform/puter/filesystem.js'; import { CreateDriversProvider } from './platform/puter/drivers.js'; import { XDocumentPTT } from './pty/XDocumentPTT.js'; import { CreateEnvProvider } from './platform/puter/env.js'; +import { CreateSystemProvider } from './platform/puter/system.js'; window.main_shell = async () => { const config = {}; @@ -73,6 +74,7 @@ window.main_shell = async () => { filesystem: CreateFilesystemProvider({ puterSDK }), drivers: CreateDriversProvider({ puterSDK }), env: CreateEnvProvider({ config }), + system: CreateSystemProvider({ puterSDK }) }), })); }; diff --git a/packages/phoenix/src/platform/node/system.js b/packages/phoenix/src/platform/node/system.js new file mode 100644 index 0000000000..ec83ebfe6f --- /dev/null +++ b/packages/phoenix/src/platform/node/system.js @@ -0,0 +1,9 @@ +import process from 'node:process'; + +export const CreateSystemProvider = () => { + return { + exit: (code) => { + process.exit(code); + }, + } +} diff --git a/packages/phoenix/src/platform/puter/system.js b/packages/phoenix/src/platform/puter/system.js new file mode 100644 index 0000000000..320ec73a73 --- /dev/null +++ b/packages/phoenix/src/platform/puter/system.js @@ -0,0 +1,7 @@ +export const CreateSystemProvider = ({ puterSDK }) => { + return { + exit: (code) => { + puterSDK.exit(code); + }, + } +} diff --git a/packages/phoenix/src/puter-shell/coreutils/__exports__.js b/packages/phoenix/src/puter-shell/coreutils/__exports__.js index 2ff3c9d217..7d35eb963e 100644 --- a/packages/phoenix/src/puter-shell/coreutils/__exports__.js +++ b/packages/phoenix/src/puter-shell/coreutils/__exports__.js @@ -31,6 +31,7 @@ import module_dirname from './dirname.js' import module_echo from './echo.js' import module_env from './env.js' import module_errno from './errno.js' +import module_exit from './exit.js' import module_false from './false.js' import module_grep from './grep.js' import module_head from './head.js' @@ -75,6 +76,7 @@ export default { "echo": module_echo, "env": module_env, "errno": module_errno, + "exit": module_exit, "false": module_false, "grep": module_grep, "head": module_head, diff --git a/packages/phoenix/src/puter-shell/coreutils/exit.js b/packages/phoenix/src/puter-shell/coreutils/exit.js new file mode 100644 index 0000000000..a31649846e --- /dev/null +++ b/packages/phoenix/src/puter-shell/coreutils/exit.js @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Phoenix Shell. + * + * Phoenix Shell 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 . + */ +import { Exit } from './coreutil_lib/exit.js'; + +export default { + name: 'exit', + usage: 'exit [CODE]', + description: 'Exit the shell and return the given CODE. If no argument is given, uses the most recent return code.', + args: { + $: 'simple-parser', + allowPositionals: true + }, + execute: async ctx => { + const { positionals, exit } = ctx.locals; + + let status_code = 0; + + if (positionals.length === 0) { + status_code = exit; + } else if (positionals.length === 1) { + const maybe_number = Number(positionals[0]); + if (Number.isInteger(maybe_number)) { + status_code = maybe_number; + } + } else { + await ctx.externs.err.write('exit: Too many arguments'); + throw new Exit(1); + } + + ctx.platform.system.exit(status_code); + } +}; From 4508bfac73eca8255ce3e11b0de8e835a84fd53d Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 23 May 2024 13:29:44 -0400 Subject: [PATCH 0085/2119] Fix cookie issue --- src/UI/UIWindowLogin.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/UI/UIWindowLogin.js b/src/UI/UIWindowLogin.js index 0885577a46..ba7e100294 100644 --- a/src/UI/UIWindowLogin.js +++ b/src/UI/UIWindowLogin.js @@ -199,7 +199,7 @@ async function UIWindowLogin(options){ let error_i18n_key = 'something_went_wrong'; if ( ! value ) return; try { - const resp = await fetch(`${window.api_origin}/login/otp`, { + const resp = await fetch(`${window.gui_origin}/login/otp`, { method: 'POST', headers: { 'Content-Type': 'application/json', From 103f9d209dd25aaad13eb204bae4542a8be79716 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 23 May 2024 14:32:24 -0700 Subject: [PATCH 0086/2119] Update README.md --- README.md | 5 ----- 1 file changed, 5 deletions(-) diff --git a/README.md b/README.md index 3283ee35c0..eb0df07015 100644 --- a/README.md +++ b/README.md @@ -19,11 +19,6 @@ Bug Bounty

-

- #1 on Hacker News - #1 on Hacker News -

-

screenshot


From c89b50bf31b3ef065ef0312c2666422f72f8d370 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 23 May 2024 17:02:45 -0400 Subject: [PATCH 0087/2119] Refactor gui loading --- packages/backend/src/CoreModule.js | 3 + packages/backend/src/config.js | 1 + packages/backend/src/routers/_default.js | 50 +--- .../src/services/PuterHomepageService.js | 229 ++++++++++++++++++ .../src/services/ServeLandingService.js | 5 + .../backend/src/temp/puter_page_loader.js | 181 -------------- puter-gui.json | 65 ++--- 7 files changed, 281 insertions(+), 253 deletions(-) create mode 100644 packages/backend/src/services/PuterHomepageService.js create mode 100644 packages/backend/src/services/ServeLandingService.js delete mode 100644 packages/backend/src/temp/puter_page_loader.js diff --git a/packages/backend/src/CoreModule.js b/packages/backend/src/CoreModule.js index eece920944..6ae1c420ac 100644 --- a/packages/backend/src/CoreModule.js +++ b/packages/backend/src/CoreModule.js @@ -213,6 +213,9 @@ const install = async ({ services, app }) => { const { LockService } = require('./services/LockService'); services.registerService('lock', LockService); + + const { PuterHomepageService } = require('./services/PuterHomepageService'); + services.registerService('puter-homepage', PuterHomepageService); } const install_legacy = async ({ services }) => { diff --git a/packages/backend/src/config.js b/packages/backend/src/config.js index bb0a0cf9ff..f37ee3b0cb 100644 --- a/packages/backend/src/config.js +++ b/packages/backend/src/config.js @@ -79,6 +79,7 @@ config.puter_hosted_data = { const path_ = require('path'); config.assets = { gui: path_.join(__dirname, '../../..'), + gui_profile: 'development', }; } diff --git a/packages/backend/src/routers/_default.js b/packages/backend/src/routers/_default.js index 3579e533e4..4e645b72dc 100644 --- a/packages/backend/src/routers/_default.js +++ b/packages/backend/src/routers/_default.js @@ -23,7 +23,6 @@ const router = express.Router(); const _path = require('path'); const _fs = require('fs'); const auth = require('../middleware/auth.js'); -const { generate_puter_page_html } = require('../temp/puter_page_loader'); const { Context } = require('../util/context'); const { DB_READ } = require('../services/database/consts'); const { PathBuilder } = require('../util/pathutil.js'); @@ -302,47 +301,14 @@ router.all('*', async function(req, res, next) { // index.js if(path === '/'){ - const APP_ORIGIN = config.origin; - const API_ORIGIN = config.api_base_url; - return res.send(generate_puter_page_html({ - env: config.env, - - app_origin: APP_ORIGIN, - api_origin: API_ORIGIN, - use_bundled_gui: config.use_bundled_gui, - - manifest, - gui_path: config.assets.gui, - - // page meta - meta: { - title: app_title, - description: description || config.short_description, - short_description: config.short_description, - company: 'Puter Technologies Inc.', - canonical_url: canonical_url, - }, - - // gui parameters - gui_params: { - app_name_regex: config.app_name_regex, - app_name_max_length: config.app_name_max_length, - app_title_max_length: config.app_title_max_length, - subdomain_regex: config.subdomain_regex, - subdomain_max_length: config.subdomain_max_length, - domain: config.domain, - protocol: config.protocol, - env: config.env, - api_base_url: config.api_base_url, - thumb_width: config.thumb_width, - thumb_height: config.thumb_height, - contact_email: config.contact_email, - max_fsentry_name_length: config.max_fsentry_name_length, - require_email_verification_to_publish_website: config.require_email_verification_to_publish_website, - short_description: config.short_description, - long_description: config.long_description, - }, - })); + const svc_puterHomepage = Context.get('services').get('puter-homepage'); + return svc_puterHomepage.send(res, { + title: app_title, + description: description || config.short_description, + short_description: config.short_description, + company: 'Puter Technologies Inc.', + canonical_url: canonical_url, + }); } // /dist/... diff --git a/packages/backend/src/services/PuterHomepageService.js b/packages/backend/src/services/PuterHomepageService.js new file mode 100644 index 0000000000..ca4317ba8b --- /dev/null +++ b/packages/backend/src/services/PuterHomepageService.js @@ -0,0 +1,229 @@ +const { PathBuilder } = require("../util/pathutil"); +const BaseService = require("./BaseService"); + +/** + * PuterHomepageService serves the initial HTML page that loads the Puter GUI + * and all of its assets. + */ +class PuterHomepageService extends BaseService { + static MODULES = { + fs: require('node:fs'), + } + + async _init () { + // Load manifest + const config = this.global_config; + const manifest_raw = this.modules.fs.readFileSync( + PathBuilder + .add(config.assets.gui, { allow_traversal: true }) + .add('puter-gui.json') + .build(), + 'utf8' + ); + const manifest_data = JSON.parse(manifest_raw); + this.manifest = manifest_data[config.assets.gui_profile]; + } + + async send (res, meta) { + const config = this.global_config; + + return res.send(this.generate_puter_page_html({ + env: config.env, + + app_origin: config.origin, + api_origin: config.api_base_url, + use_bundled_gui: config.use_bundled_gui, + + manifest: this.manifest, + gui_path: config.assets.gui, + + // page meta + meta, + + // gui parameters + gui_params: { + app_name_regex: config.app_name_regex, + app_name_max_length: config.app_name_max_length, + app_title_max_length: config.app_title_max_length, + subdomain_regex: config.subdomain_regex, + subdomain_max_length: config.subdomain_max_length, + domain: config.domain, + protocol: config.protocol, + env: config.env, + api_base_url: config.api_base_url, + thumb_width: config.thumb_width, + thumb_height: config.thumb_height, + contact_email: config.contact_email, + max_fsentry_name_length: config.max_fsentry_name_length, + require_email_verification_to_publish_website: config.require_email_verification_to_publish_website, + short_description: config.short_description, + long_description: config.long_description, + }, + })); + } + + generate_puter_page_html ({ + env, + + manifest, + gui_path, + use_bundled_gui, + + app_origin, + api_origin, + + meta, + + gui_params, + }) { + const require = this.require; + const {encode} = require('html-entities'); + const path_ = require('path'); + const fs_ = require('fs'); + + const e = encode; + + const { + title, + description, + short_description, + company, + canonical_url, + } = meta; + + gui_params = { + ...meta, + ...gui_params, + app_origin, + api_origin, + gui_origin: app_origin, + }; + + const asset_dir = env === 'dev' + ? '/src' : '/dist' ; + // const asset_dir = '/dist'; + + gui_params.asset_dir = asset_dir; + + const bundled = env != 'dev' || use_bundled_gui; + + return ` + + + + ${e(title)} + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + ${ + ((!bundled && manifest?.css_paths) + ? manifest.css_paths.map(path => `\n`) + : []).join('') + } + + + + + + ${ + use_bundled_gui + ? `` + : '' + } + ${ + ((!bundled && manifest?.lib_paths) + ? manifest.lib_paths.map(path => `\n`) + : []).join('') + } + + + + ${ + ((!bundled && manifest?.js_paths) + ? manifest.js_paths.map(path => `\n`) + : []).join('') + } + + + + + + + + `; + }; +} + +module.exports = { + PuterHomepageService +}; diff --git a/packages/backend/src/services/ServeLandingService.js b/packages/backend/src/services/ServeLandingService.js new file mode 100644 index 0000000000..f1c9cd9f85 --- /dev/null +++ b/packages/backend/src/services/ServeLandingService.js @@ -0,0 +1,5 @@ + +/** + * ServeLandingService is for "landing" pages, like payment success or failure. + */ +class ServceLandingService {} diff --git a/packages/backend/src/temp/puter_page_loader.js b/packages/backend/src/temp/puter_page_loader.js deleted file mode 100644 index e0ed4b8a37..0000000000 --- a/packages/backend/src/temp/puter_page_loader.js +++ /dev/null @@ -1,181 +0,0 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ -const {encode} = require('html-entities'); -const path_ = require('path'); -const fs_ = require('fs'); - -const generate_puter_page_html = ({ - env, - - manifest, - gui_path, - use_bundled_gui, - - app_origin, - api_origin, - - meta, - - gui_params, -}) => { - const e = encode; - - const { - title, - description, - short_description, - company, - canonical_url, - } = meta; - - gui_params = { - ...meta, - ...gui_params, - app_origin, - api_origin, - gui_origin: app_origin, - }; - - const asset_dir = env === 'dev' - ? '/src' : '/dist' ; - // const asset_dir = '/dist'; - - gui_params.asset_dir = asset_dir; - - const bundled = env != 'dev' || use_bundled_gui; - - return ` - - - - ${e(title)} - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - ${ - ((!bundled && manifest?.css_paths) - ? manifest.css_paths.map(path => `\n`) - : []).join('') - } - - - - - - ${ - use_bundled_gui - ? `` - : '' - } - ${ - ((!bundled && manifest?.lib_paths) - ? manifest.lib_paths.map(path => `\n`) - : []).join('') - } - - - - ${ - ((!bundled && manifest?.js_paths) - ? manifest.js_paths.map(path => `\n`) - : []).join('') - } - - - - - - - -`; -}; - -module.exports = { - generate_puter_page_html, -}; diff --git a/puter-gui.json b/puter-gui.json index af7691d9fd..5f15a36dc1 100644 --- a/puter-gui.json +++ b/puter-gui.json @@ -1,32 +1,37 @@ { - "index": "/src/index.js", - "lib_paths": [ - "/lib/jquery-3.6.1/jquery-3.6.1.min.js", - "/lib/viselect.min.js", - "/lib/FileSaver.min.js", - "/lib/socket.io/socket.io.min.js", - "/lib/qrcode.min.js", - "/lib/jquery-ui-1.13.2/jquery-ui.min.js", - "/lib/lodash@4.17.21.min.js", - "/lib/jquery.dragster.js", - "/lib/jquery.menu-aim.js", - "/lib/html-entities.js", - "/lib/timeago.min.js", - "/lib/iro.min.js", - "/lib/isMobile.min.js", - "/lib/jszip-3.10.1.min.js" - ], - "css_paths": [ - "/css/normalize.css", - "/lib/jquery-ui-1.13.2/jquery-ui.min.css", - "/css/style.css", - "/css/theme.css" - ], - "js_paths": [ - "/src/initgui.js", - "/src/helpers.js", - "/src/IPC.js", - "/src/globals.js", - "/src/i18n/i18n.js" - ] + "development": { + "index": "/src/index.js", + "lib_paths": [ + "/lib/jquery-3.6.1/jquery-3.6.1.min.js", + "/lib/viselect.min.js", + "/lib/FileSaver.min.js", + "/lib/socket.io/socket.io.min.js", + "/lib/qrcode.min.js", + "/lib/jquery-ui-1.13.2/jquery-ui.min.js", + "/lib/lodash@4.17.21.min.js", + "/lib/jquery.dragster.js", + "/lib/jquery.menu-aim.js", + "/lib/html-entities.js", + "/lib/timeago.min.js", + "/lib/iro.min.js", + "/lib/isMobile.min.js", + "/lib/jszip-3.10.1.min.js" + ], + "css_paths": [ + "/css/normalize.css", + "/lib/jquery-ui-1.13.2/jquery-ui.min.css", + "/css/style.css", + "/css/theme.css" + ], + "js_paths": [ + "/src/initgui.js", + "/src/helpers.js", + "/src/IPC.js", + "/src/globals.js", + "/src/i18n/i18n.js" + ] + }, + "bundle": { + "index": ["/dist/gui.js", false] + } } From 5042d49935baa310e94315131280f62159c44182 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 23 May 2024 18:40:41 -0400 Subject: [PATCH 0088/2119] Simplify debugging runtime config object changes --- packages/backend/src/config.js | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/packages/backend/src/config.js b/packages/backend/src/config.js index f37ee3b0cb..0ba65cceb5 100644 --- a/packages/backend/src/config.js +++ b/packages/backend/src/config.js @@ -175,9 +175,25 @@ const config_pointer = {}; // We'd like to store values changed at runtime separately // for easier runtime debugging { - const config_runtime_values = {}; + const config_runtime_values = { + $: 'runtime-values' + }; config_runtime_values.__proto__ = config_to_export; config_to_export = config_runtime_values + + // These can be difficult to find and cause painful + // confusing issues, so we log any time this happens + config_to_export = new Proxy(config_to_export, { + set: (target, prop, value, receiver) => { + console.log( + '\x1B[36;1mCONFIGURATION MUTATED AT RUNTIME\x1B[0m', + prop, 'to', value + ); + // console.log(new Error('stack trace to find configuration mutation')); + target[prop] = value; + return true; + } + }) } -module.exports = config_to_export; \ No newline at end of file +module.exports = config_to_export; From a1cfe7aef2f801b158a586ac3b151eed778cc97a Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 23 May 2024 18:41:34 -0400 Subject: [PATCH 0089/2119] Allow services to register additional js files for gui --- .../backend/src/services/PuterHomepageService.js | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/packages/backend/src/services/PuterHomepageService.js b/packages/backend/src/services/PuterHomepageService.js index ca4317ba8b..003f11cf92 100644 --- a/packages/backend/src/services/PuterHomepageService.js +++ b/packages/backend/src/services/PuterHomepageService.js @@ -10,6 +10,10 @@ class PuterHomepageService extends BaseService { fs: require('node:fs'), } + _construct () { + this.service_scripts = []; + } + async _init () { // Load manifest const config = this.global_config; @@ -24,9 +28,12 @@ class PuterHomepageService extends BaseService { this.manifest = manifest_data[config.assets.gui_profile]; } + register_script (url) { + this.service_scripts.push(url); + } + async send (res, meta) { const config = this.global_config; - return res.send(this.generate_puter_page_html({ env: config.env, @@ -205,6 +212,11 @@ class PuterHomepageService extends BaseService { ? manifest.js_paths.map(path => `\n`) : []).join('') } + ${ + this.service_scripts + .map(path => `\n`) + .join('') + } From f8525c6f6c3c96b7794c0ba265c6f8a305712a47 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Fri, 24 May 2024 10:28:22 +0100 Subject: [PATCH 0090/2119] Rename newparser to Parsely We're going to actually use this so let's give it a more permanent name. --- packages/phoenix/packages/{newparser => parsely}/exports.js | 0 packages/phoenix/packages/{newparser => parsely}/lib.js | 0 .../packages/{newparser => parsely}/parsers/combinators.js | 0 .../packages/{newparser => parsely}/parsers/terminals.js | 0 .../phoenix/src/puter-shell/coreutils/concept-parser.js | 6 +++--- 5 files changed, 3 insertions(+), 3 deletions(-) rename packages/phoenix/packages/{newparser => parsely}/exports.js (100%) rename packages/phoenix/packages/{newparser => parsely}/lib.js (100%) rename packages/phoenix/packages/{newparser => parsely}/parsers/combinators.js (100%) rename packages/phoenix/packages/{newparser => parsely}/parsers/terminals.js (100%) diff --git a/packages/phoenix/packages/newparser/exports.js b/packages/phoenix/packages/parsely/exports.js similarity index 100% rename from packages/phoenix/packages/newparser/exports.js rename to packages/phoenix/packages/parsely/exports.js diff --git a/packages/phoenix/packages/newparser/lib.js b/packages/phoenix/packages/parsely/lib.js similarity index 100% rename from packages/phoenix/packages/newparser/lib.js rename to packages/phoenix/packages/parsely/lib.js diff --git a/packages/phoenix/packages/newparser/parsers/combinators.js b/packages/phoenix/packages/parsely/parsers/combinators.js similarity index 100% rename from packages/phoenix/packages/newparser/parsers/combinators.js rename to packages/phoenix/packages/parsely/parsers/combinators.js diff --git a/packages/phoenix/packages/newparser/parsers/terminals.js b/packages/phoenix/packages/parsely/parsers/terminals.js similarity index 100% rename from packages/phoenix/packages/newparser/parsers/terminals.js rename to packages/phoenix/packages/parsely/parsers/terminals.js diff --git a/packages/phoenix/src/puter-shell/coreutils/concept-parser.js b/packages/phoenix/src/puter-shell/coreutils/concept-parser.js index 3188822032..b61928f09c 100644 --- a/packages/phoenix/src/puter-shell/coreutils/concept-parser.js +++ b/packages/phoenix/src/puter-shell/coreutils/concept-parser.js @@ -1,5 +1,5 @@ -import { GrammarContext, standard_parsers } from '../../../packages/newparser/exports.js'; -import { Parser, UNRECOGNIZED, VALUE } from '../../../packages/newparser/lib.js'; +import { GrammarContext, standard_parsers } from '../../../packages/parsely/exports.js'; +import { Parser, UNRECOGNIZED, VALUE } from '../../../packages/parsely/lib.js'; class NumberParser extends Parser { static data = { @@ -317,4 +317,4 @@ export default { await err.write(e.stack + '\n'); } } -} \ No newline at end of file +} From 837ec683718c2e537752c5237dad02a3e7fa95ca Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Fri, 24 May 2024 11:49:56 +0100 Subject: [PATCH 0091/2119] Reorganize and document Parsely classes - lib.js only holds Parser so rename it parser.js - Move Symbol and None into terminals.js - Briefly document all parser classes --- packages/phoenix/packages/parsely/exports.js | 41 +++++---------- .../packages/parsely/{lib.js => parser.js} | 6 +++ .../packages/parsely/parsers/combinators.js | 32 ++++++++---- .../packages/parsely/parsers/terminals.js | 51 ++++++++++++++++++- .../puter-shell/coreutils/concept-parser.js | 2 +- 5 files changed, 91 insertions(+), 41 deletions(-) rename packages/phoenix/packages/parsely/{lib.js => parser.js} (75%) diff --git a/packages/phoenix/packages/parsely/exports.js b/packages/phoenix/packages/parsely/exports.js index dfab21853a..b5c1985a93 100644 --- a/packages/phoenix/packages/parsely/exports.js +++ b/packages/phoenix/packages/parsely/exports.js @@ -1,31 +1,6 @@ -import { adapt_parser, INVALID, Parser, UNRECOGNIZED, VALUE } from './lib.js'; -import { Discard, FirstMatch, None, Optional, Repeat, Sequence } from './parsers/combinators.js'; -import { Literal, StringOf } from './parsers/terminals.js'; - -class Symbol extends Parser { - _create(symbolName) { - this.symbolName = symbolName; - } - - _parse (stream) { - const parser = this.symbol_registry[this.symbolName]; - if ( ! parser ) { - throw new Error(`No symbol defined named '${this.symbolName}'`); - } - const subStream = stream.fork(); - const result = parser.parse(subStream); - console.log(`Result of parsing symbol('${this.symbolName}'):`, result); - if ( result.status === UNRECOGNIZED ) { - return UNRECOGNIZED; - } - if ( result.status === INVALID ) { - return { status: INVALID, value: result }; - } - stream.join(subStream); - result.$ = this.symbolName; - return result; - } -} +import { adapt_parser, VALUE } from './parser.js'; +import { Discard, FirstMatch, Optional, Repeat, Sequence } from './parsers/combinators.js'; +import { Literal, None, StringOf, Symbol } from './parsers/terminals.js'; class ParserWithAction { #parser; @@ -55,6 +30,12 @@ export class GrammarContext { return new GrammarContext({...this.parsers, ...more_parsers}); } + /** + * Construct a parsing function for the given grammar. + * @param grammar An object of symbol-names to a DSL for parsing that symbol. + * @param actions An object of symbol-names to a function run to process the symbol after it has been parsed. + * @returns {function(*, *, {must_consume_all_input?: boolean}=): *} A function to run the parser. Throws if parsing fails. + */ define_parser (grammar, actions) { const symbol_registry = {}; const api = {}; @@ -81,7 +62,9 @@ export class GrammarContext { if (!entry_parser) { throw new Error(`Entry symbol '${entry_symbol}' not found in grammar.`); } - return entry_parser.parse(stream); + const result = entry_parser.parse(stream); + // TODO: Ensure all the stream has been consumed + return result; }; } } diff --git a/packages/phoenix/packages/parsely/lib.js b/packages/phoenix/packages/parsely/parser.js similarity index 75% rename from packages/phoenix/packages/parsely/lib.js rename to packages/phoenix/packages/parsely/parser.js index 89f185e038..c588ccf12f 100644 --- a/packages/phoenix/packages/parsely/lib.js +++ b/packages/phoenix/packages/parsely/parser.js @@ -4,6 +4,12 @@ export const UNRECOGNIZED = Symbol('unrecognized'); export const INVALID = Symbol('invalid'); export const VALUE = Symbol('value'); +/** + * Base class for parsers. + * To implement your own, subclass it and define these methods: + * - _create(): Acts as the constructor + * - _parse(stream): Performs the parsing on the stream, and returns either UNRECOGNIZED, INVALID, or a result object. + */ export class Parser { result (o) { if (o.value && o.value.$discard) { diff --git a/packages/phoenix/packages/parsely/parsers/combinators.js b/packages/phoenix/packages/parsely/parsers/combinators.js index 54b23c058a..5078b6a53c 100644 --- a/packages/phoenix/packages/parsely/parsers/combinators.js +++ b/packages/phoenix/packages/parsely/parsers/combinators.js @@ -1,5 +1,9 @@ -import { INVALID, UNRECOGNIZED, VALUE, adapt_parser, Parser } from '../lib.js'; +import { adapt_parser, INVALID, Parser, UNRECOGNIZED, VALUE } from '../parser.js'; +/** + * Runs its child parser, and discards its result. + * @param parser Child parser + */ export class Discard extends Parser { _create (parser) { this.parser = adapt_parser(parser); @@ -19,6 +23,10 @@ export class Discard extends Parser { } } +/** + * Runs its child parsers in order, and returns the first successful result. + * @param parsers Child parsers + */ export class FirstMatch extends Parser { _create (...parsers) { this.parsers = parsers.map(adapt_parser); @@ -42,14 +50,10 @@ export class FirstMatch extends Parser { } } -export class None extends Parser { - _create () {} - - _parse (stream) { - return { status: VALUE, $: 'none', $discard: true }; - } -} - +/** + * Runs its child parser, and then returns its result, or nothing. + * @param parser Child parser + */ export class Optional extends Parser { _create (parser) { this.parser = adapt_parser(parser); @@ -66,6 +70,12 @@ export class Optional extends Parser { } } +/** + * Parses a repeated sequence of values with separators between them. + * @param value_parser Parser for the value + * @param separator_parser Parser for the separator + * @param trailing Whether to allow a trailing separator + */ export class Repeat extends Parser { _create (value_parser, separator_parser, { trailing = false } = {}) { this.value_parser = adapt_parser(value_parser); @@ -114,6 +124,10 @@ export class Repeat extends Parser { } } +/** + * Runs a sequence of child parsers, and returns their result as an array if they all succeed. + * @param parsers Child parsers + */ export class Sequence extends Parser { _create (...parsers) { this.parsers = parsers.map(adapt_parser); diff --git a/packages/phoenix/packages/parsely/parsers/terminals.js b/packages/phoenix/packages/parsely/parsers/terminals.js index 4a82cd1471..712c688fd6 100644 --- a/packages/phoenix/packages/parsely/parsers/terminals.js +++ b/packages/phoenix/packages/parsely/parsers/terminals.js @@ -1,5 +1,9 @@ -import { Parser, UNRECOGNIZED, VALUE } from '../lib.js'; +import { INVALID, Parser, UNRECOGNIZED, VALUE } from '../parser.js'; +/** + * Parses a literal value. + * @param value The value to parse + */ export class Literal extends Parser { _create (value) { this.value = value; @@ -18,6 +22,10 @@ export class Literal extends Parser { } } +/** + * Parses a string composed of the given values. + * @param values An array of strings that will be parsed as the result. + */ export class StringOf extends Parser { _create (values) { this.values = values; @@ -43,4 +51,43 @@ export class StringOf extends Parser { stream.join(subStream); return { status: VALUE, $: 'stringOf', value: text }; } -} \ No newline at end of file +} + +/** + * Parses an object defined by the symbol registry. + * @param symbolName The name of the symbol to parse. + */ +export class Symbol extends Parser { + _create(symbolName) { + this.symbolName = symbolName; + } + + _parse (stream) { + const parser = this.symbol_registry[this.symbolName]; + if ( ! parser ) { + throw new Error(`No symbol defined named '${this.symbolName}'`); + } + const subStream = stream.fork(); + const result = parser.parse(subStream); + if ( result.status === UNRECOGNIZED ) { + return UNRECOGNIZED; + } + if ( result.status === INVALID ) { + return { status: INVALID, value: result }; + } + stream.join(subStream); + result.$ = this.symbolName; + return result; + } +} + +/** + * Does no parsing and returns a discarded result. + */ +export class None extends Parser { + _create () {} + + _parse (stream) { + return { status: VALUE, $: 'none', $discard: true }; + } +} diff --git a/packages/phoenix/src/puter-shell/coreutils/concept-parser.js b/packages/phoenix/src/puter-shell/coreutils/concept-parser.js index b61928f09c..7036fab451 100644 --- a/packages/phoenix/src/puter-shell/coreutils/concept-parser.js +++ b/packages/phoenix/src/puter-shell/coreutils/concept-parser.js @@ -1,5 +1,5 @@ import { GrammarContext, standard_parsers } from '../../../packages/parsely/exports.js'; -import { Parser, UNRECOGNIZED, VALUE } from '../../../packages/parsely/lib.js'; +import { Parser, UNRECOGNIZED, VALUE } from '../../../packages/parsely/parser.js'; class NumberParser extends Parser { static data = { From 873dee7e511d4ede74536750e16915da1a8bc18f Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Fri, 24 May 2024 13:29:26 +0100 Subject: [PATCH 0092/2119] Implement 'trailing' parameter for repeat() parser --- .../packages/parsely/parsers/combinators.js | 67 +++++++++++-------- 1 file changed, 38 insertions(+), 29 deletions(-) diff --git a/packages/phoenix/packages/parsely/parsers/combinators.js b/packages/phoenix/packages/parsely/parsers/combinators.js index 5078b6a53c..b597e85762 100644 --- a/packages/phoenix/packages/parsely/parsers/combinators.js +++ b/packages/phoenix/packages/parsely/parsers/combinators.js @@ -73,7 +73,7 @@ export class Optional extends Parser { /** * Parses a repeated sequence of values with separators between them. * @param value_parser Parser for the value - * @param separator_parser Parser for the separator + * @param separator_parser Parser for the separator, optional * @param trailing Whether to allow a trailing separator */ export class Repeat extends Parser { @@ -85,40 +85,49 @@ export class Repeat extends Parser { _parse (stream) { const results = []; - for ( ;; ) { - const subStream = stream.fork(); + const subStream = stream.fork(); - // Value - const result = this.value_parser.parse(subStream); - if ( result.status === UNRECOGNIZED ) { - break; - } - if ( result.status === INVALID ) { - return { status: INVALID, value: result }; - } - stream.join(subStream); - if ( ! result.$discard ) results.push(result); + // Parse first value + const result = this.value_parser.parse(subStream); + if ( result.status === INVALID ) + return { status: INVALID, value: result }; - // Separator - if ( ! this.separator_parser ) { - continue; - } - const separatorResult = this.separator_parser.parse(subStream); - if ( separatorResult.status === UNRECOGNIZED ) { - break; - } - if ( separatorResult.status === INVALID ) { - return { status: INVALID, value: separatorResult }; - } + if ( result.status === VALUE ) { stream.join(subStream); - if ( ! result.$discard ) results.push(separatorResult); - - // TODO: Detect trailing separator and reject it if trailing==false + if (!result.$discard) results.push(result); + + // Repeatedly parse + for (;;) { + // Separator + if (!this.separator_parser) + continue; + + const separatorResult = this.separator_parser.parse(subStream); + if (separatorResult.status === UNRECOGNIZED) + break; + if (separatorResult.status === INVALID) + return { status: INVALID, value: separatorResult }; + stream.join(subStream); + if (!separatorResult.$discard) results.push(separatorResult); + + // Value + const result = this.value_parser.parse(subStream); + if (result.status === UNRECOGNIZED) { + // If we failed to parse a value, we have a trailing separator + if (this.trailing === false) + return { status: INVALID, value: result }; + break; + } + if (result.status === INVALID) + return { status: INVALID, value: result }; + + stream.join(subStream); + if (!result.$discard) results.push(result); + } } - if ( results.length === 0 ) { + if ( results.length === 0 ) return UNRECOGNIZED; - } return { status: VALUE, value: results }; } From 0bc4c3fde2a1e6137b08a9285b7d8f028456b4ae Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Fri, 24 May 2024 14:41:07 +0100 Subject: [PATCH 0093/2119] Move StringStream into Parsely --- packages/phoenix/packages/parsely/streams.js | 52 +++++++++++++++++++ .../puter-shell/coreutils/concept-parser.js | 35 +------------ 2 files changed, 53 insertions(+), 34 deletions(-) create mode 100644 packages/phoenix/packages/parsely/streams.js diff --git a/packages/phoenix/packages/parsely/streams.js b/packages/phoenix/packages/parsely/streams.js new file mode 100644 index 0000000000..23254b624b --- /dev/null +++ b/packages/phoenix/packages/parsely/streams.js @@ -0,0 +1,52 @@ +/** + * Base class for input streams. + * Defines which methods are expected for any stream implementations. + */ +export class ParserStream { + value_at (index) { throw new Error(`${this.constructor.name}.value_at() not implemented`); } + look () { throw new Error(`${this.constructor.name}.look() not implemented`); } + next () { throw new Error(`${this.constructor.name}.next() not implemented`); } + fork () { throw new Error(`${this.constructor.name}.fork() not implemented`); } + join () { throw new Error(`${this.constructor.name}.join() not implemented`); } + + is_eof () { + return this.look().done; + } +} + +/** + * ParserStream that takes a string, and processes it character by character. + */ +export class StringStream extends ParserStream { + constructor (str, startIndex = 0) { + super(); + this.str = str; + this.i = startIndex; + } + + value_at (index) { + if ( index >= this.str.length ) { + return { done: true, value: undefined }; + } + + return { done: false, value: this.str[index] }; + } + + look () { + return this.value_at(this.i); + } + + next () { + const result = this.value_at(this.i); + this.i++; + return result; + } + + fork () { + return new StringStream(this.str, this.i); + } + + join (forked) { + this.i = forked.i; + } +} diff --git a/packages/phoenix/src/puter-shell/coreutils/concept-parser.js b/packages/phoenix/src/puter-shell/coreutils/concept-parser.js index 7036fab451..a24b611d8d 100644 --- a/packages/phoenix/src/puter-shell/coreutils/concept-parser.js +++ b/packages/phoenix/src/puter-shell/coreutils/concept-parser.js @@ -1,5 +1,6 @@ import { GrammarContext, standard_parsers } from '../../../packages/parsely/exports.js'; import { Parser, UNRECOGNIZED, VALUE } from '../../../packages/parsely/parser.js'; +import { StringStream } from '../../../packages/parsely/streams.js'; class NumberParser extends Parser { static data = { @@ -163,39 +164,6 @@ class StringParser extends Parser { } } -class StringStream { - constructor (str, startIndex = 0) { - this.str = str; - this.i = startIndex; - } - - value_at (index) { - if ( index >= this.str.length ) { - return { done: true, value: undefined }; - } - - return { done: false, value: this.str[index] }; - } - - look () { - return this.value_at(this.i); - } - - next () { - const result = this.value_at(this.i); - this.i++; - return result; - } - - fork () { - return new StringStream(this.str, this.i); - } - - join (forked) { - this.i = forked.i; - } -} - export default { name: 'concept-parser', args: { @@ -305,7 +273,6 @@ export default { whitespace: _ => {}, }); - // TODO: What do we want our streams to be like? const input = ctx.locals.positionals.shift(); const stream = new StringStream(input); try { From d3dff8c20edec15ed15b4ed0fbb84dbd7375266b Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Fri, 24 May 2024 14:41:13 +0100 Subject: [PATCH 0094/2119] Throw errors if parsing fails Not consuming all input is now treated as an error, unless the `must_consume_all_input` flag is set to false when parsing. --- packages/phoenix/packages/parsely/exports.js | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/packages/phoenix/packages/parsely/exports.js b/packages/phoenix/packages/parsely/exports.js index b5c1985a93..b729a589a9 100644 --- a/packages/phoenix/packages/parsely/exports.js +++ b/packages/phoenix/packages/parsely/exports.js @@ -57,13 +57,22 @@ export class GrammarContext { } } - return (stream, entry_symbol) => { + return (stream, entry_symbol, { must_consume_all_input = true } = {}) => { const entry_parser = symbol_registry[entry_symbol]; if (!entry_parser) { throw new Error(`Entry symbol '${entry_symbol}' not found in grammar.`); } const result = entry_parser.parse(stream); - // TODO: Ensure all the stream has been consumed + + if (result.status !== VALUE) { + throw new Error('Failed to parse input against grammar.'); + } + + // Ensure the entire stream is consumed. + if (must_consume_all_input && !stream.is_eof()) { + throw new Error('Parsing did not consume all input.'); + } + return result; }; } From 7fccf79591de916b63e39b858644f7b91d11b852 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Fri, 24 May 2024 15:57:59 +0100 Subject: [PATCH 0095/2119] Make stringOf() take a callback instead of an array of accepted values THe `a.stringOf(' \r\n\t'.split('')),` pattern works fine for small sets of characters, but is horrible for situations like "any alphanumeric". Instead, let's make it take a callback function that is run on each character. --- packages/phoenix/packages/parsely/parsers/terminals.js | 10 +++++----- .../src/puter-shell/coreutils/concept-parser.js | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/packages/phoenix/packages/parsely/parsers/terminals.js b/packages/phoenix/packages/parsely/parsers/terminals.js index 712c688fd6..10936540e7 100644 --- a/packages/phoenix/packages/parsely/parsers/terminals.js +++ b/packages/phoenix/packages/parsely/parsers/terminals.js @@ -23,12 +23,12 @@ export class Literal extends Parser { } /** - * Parses a string composed of the given values. - * @param values An array of strings that will be parsed as the result. + * Parses matching characters as a string. + * @param test Function that takes a character, and returns whether to include it. */ export class StringOf extends Parser { - _create (values) { - this.values = values; + _create (test) { + this.test = test; } _parse (stream) { @@ -38,7 +38,7 @@ export class StringOf extends Parser { while (true) { let { done, value } = subStream.look(); if ( done ) break; - if ( ! this.values.includes(value) ) break; + if ( ! this.test(value) ) break; subStream.next(); text += value; diff --git a/packages/phoenix/src/puter-shell/coreutils/concept-parser.js b/packages/phoenix/src/puter-shell/coreutils/concept-parser.js index a24b611d8d..64369858bf 100644 --- a/packages/phoenix/src/puter-shell/coreutils/concept-parser.js +++ b/packages/phoenix/src/puter-shell/coreutils/concept-parser.js @@ -232,7 +232,7 @@ export default { number: a => new NumberParser(), string: a => new StringParser(), whitespace: a => a.optional( - a.stringOf(' \r\n\t'.split('')), + a.stringOf(c => ' \r\n\t'.includes(c)), ), }, { element: it => it[0].value, From 03123faa8acf1e23f1eb1936906b365788a24e63 Mon Sep 17 00:00:00 2001 From: Sam Atkins Date: Fri, 24 May 2024 12:06:10 +0100 Subject: [PATCH 0096/2119] Finish concept JSON parser This now can parse JSON correctly in various configurations. --- .../puter-shell/coreutils/concept-parser.js | 44 +++++++------------ 1 file changed, 16 insertions(+), 28 deletions(-) diff --git a/packages/phoenix/src/puter-shell/coreutils/concept-parser.js b/packages/phoenix/src/puter-shell/coreutils/concept-parser.js index 64369858bf..968c3928ed 100644 --- a/packages/phoenix/src/puter-shell/coreutils/concept-parser.js +++ b/packages/phoenix/src/puter-shell/coreutils/concept-parser.js @@ -172,15 +172,13 @@ export default { }, execute: async ctx => { const { in_, out, err } = ctx.externs; - await out.write("STARTING CONCEPT PARSER\n"); const grammar_context = new GrammarContext(standard_parsers()); - await out.write("Constructed a grammar context\n"); const parser = grammar_context.define_parser({ element: a => a.sequence( - a.symbol('whitespace'), + a.optional(a.symbol('whitespace')), a.symbol('value'), - a.symbol('whitespace'), + a.optional(a.symbol('whitespace')), ), value: a => a.firstMatch( a.symbol('object'), @@ -193,37 +191,33 @@ export default { ), array: a => a.sequence( a.literal('['), - a.symbol('whitespace'), - a.optional( + a.firstMatch( a.repeat( a.symbol('element'), a.literal(','), - { trailing: true }, + { trailing: false }, ), + a.optional(a.symbol('whitespace')), ), - a.symbol('whitespace'), a.literal(']'), ), member: a => a.sequence( - a.symbol('whitespace'), + a.optional(a.symbol('whitespace')), a.symbol('string'), - a.symbol('whitespace'), + a.optional(a.symbol('whitespace')), a.literal(':'), - a.symbol('whitespace'), - a.symbol('value'), - a.symbol('whitespace'), + a.symbol('element'), ), object: a => a.sequence( a.literal('{'), - a.symbol('whitespace'), - a.optional( + a.firstMatch( a.repeat( a.symbol('member'), a.literal(','), - { trailing: true }, + { trailing: false }, ), + a.optional(a.symbol('whitespace')), ), - a.symbol('whitespace'), a.literal('}'), ), true: a => a.literal('true'), @@ -231,37 +225,31 @@ export default { null: a => a.literal('null'), number: a => new NumberParser(), string: a => new StringParser(), - whitespace: a => a.optional( - a.stringOf(c => ' \r\n\t'.includes(c)), - ), + whitespace: a => a.stringOf(c => ' \r\n\t'.includes(c)), }, { - element: it => it[0].value, + element: it => it.filter(it => it.$ === 'value')[0].value, value: it => it, array: it => { // A parsed array contains 3 values: `[`, the entries array, and `]`, so we only care about index 1. // If it's less than 3, there were no entries. if (it.length < 3) return []; return (it[1].value || []) - .filter(it => it.$ !== 'literal') + .filter(it => it.$ === 'element') .map(it => it.value); }, member: it => { - // A parsed member contains 3 values: a name, `:`, and a value. - const [ name_part, colon, value_part ] = it; + const [ name_part, value_part ] = it.filter(it => it.$ === 'string' || it.$ === 'element'); return { name: name_part.value, value: value_part.value }; }, object: it => { - console.log('OBJECT!!!!'); - console.log(it[1]); // A parsed object contains 3 values: `{`, the members array, and `}`, so we only care about index 1. // If it's less than 3, there were no members. if (it.length < 3) return {}; const result = {}; - // FIXME: This is all wrong!!! (it[1].value || []) .filter(it => it.$ === 'member') .forEach(it => { - result[it.name] = it.value; + result[it.value.name] = it.value.value; }); return result; }, From 5146dc498150144fe3aa86a8b939aeec5309f916 Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Wed, 22 May 2024 16:17:06 +0000 Subject: [PATCH 0097/2119] chore(main): release 2.3.0 --- CHANGELOG.md | 49 +++++++++++++++++++++++++++++++++++++++++++++++ package-lock.json | 4 ++-- package.json | 2 +- 3 files changed, 52 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index ed23b9f9c1..fd4860f7b9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,54 @@ # Changelog +## 2.3.0 (2024-05-22) + + +### Features + +* add /healthcheck endpoint ([c166560](https://github.com/HeyPuter/puter/commit/c166560ff4ab5a453d3ec4f97326c995deb7f522)) +* Add command names to phoenix tab-completion ([cf0eee1](https://github.com/HeyPuter/puter/commit/cf0eee1fa35328e05aefc8a425b5977efe5f4ec9)) +* add option to change desktop background to default ([03f05f3](https://github.com/HeyPuter/puter/commit/03f05f316f11e8afe5fcee40b2b80a0de5e6826f)) +* allow apps to add a menubar via puter.js ([331d9e7](https://github.com/HeyPuter/puter/commit/331d9e75428ec7609394f59b1755374c7340f83e)) +* Allow querying puter-apps driver by partial app names ([dc5b010](https://github.com/HeyPuter/puter/commit/dc5b010d0913d2151b4851f8da5df72d2c8f42e7)) +* Display upload errors in UIWindowProgress dialog ([edebbee](https://github.com/HeyPuter/puter/commit/edebbee9e7e9efbb33bf709b637c103be40d15a8)) +* Implement 'Like' predicate in entity storage ([a854a0d](https://github.com/HeyPuter/puter/commit/a854a0dc0aa79a31695db833184c5ca3698632a9)) +* improve password recovery experience ([04432df](https://github.com/HeyPuter/puter/commit/04432df5540811710ce1cc47ce6c136e5453bccb)) +* **security:** add ip rate limiting ([ccf1afc](https://github.com/HeyPuter/puter/commit/ccf1afc93c24ee7f9a126216209a185d6b4d9fe4)) +* Show "Deleting /foo" in progress window when deleting files ([f07c13a](https://github.com/HeyPuter/puter/commit/f07c13a50cee790eec44bce2f6e56fbcbf73f9b0)) + + +### Bug Fixes + +* Add missing file extension to 0009_app-prefix-fix.sql in DB init ([a8160a8](https://github.com/HeyPuter/puter/commit/a8160a8cdcdd6aff98728a6f1643d93386e6bb5a)) +* Add missing TextEncoder to PTT ([8d4a1e0](https://github.com/HeyPuter/puter/commit/8d4a1e0ed3872e2c82b9e4be9b6d8b359e9cea09)) +* Correct APIError imports ([062e23b](https://github.com/HeyPuter/puter/commit/062e23b5c9673db1f8b0ff0469289d52dd1e3f99)) +* Correct grep output when asking for line numbers ([c8a20ca](https://github.com/HeyPuter/puter/commit/c8a20cadbfd539d185d32f4558916825fcf265ba)) +* Correct inverted instanceof check in SignalReader.read() ([d4c2b49](https://github.com/HeyPuter/puter/commit/d4c2b492ef4864804776d3cb7d24797fdc536886)) +* Correct variables used in errors in sign.js ([fa7c6be](https://github.com/HeyPuter/puter/commit/fa7c6bee9699527028be0ae9759155bc67c52324)) +* Eliminates duplicate translation keys ([5800350](https://github.com/HeyPuter/puter/commit/5800350b253994dea410afff64e3df2a171e7775)) +* fix error handling for outdated node versions ([4c1d5a4](https://github.com/HeyPuter/puter/commit/4c1d5a4b6d009ce075897d499d3517219bd745a4)) +* Fix phoenix app prefix and TokenService test ([afb9d86](https://github.com/HeyPuter/puter/commit/afb9d866b5091058711db931cde904947e661c15)) +* increase QR code size ([d2de46e](https://github.com/HeyPuter/puter/commit/d2de46edfbc05d132d5c929f6935b82515fbbda0)) +* Make PathCommandProvider reject queries with path separators ([d733119](https://github.com/HeyPuter/puter/commit/d73311945610417a1ebc7bb0723ced0a599594b4)) +* Make url variable accessible to all users of it ([2f30ae7](https://github.com/HeyPuter/puter/commit/2f30ae7a825adcd8da95888c38fe39c34acee0ff)) +* Only run Component initialization functions once ([5b43358](https://github.com/HeyPuter/puter/commit/5b43358219402bee3eadf4a0f184a4b924d3293b)) +* Parse octal echo escapes ([6ad8f5e](https://github.com/HeyPuter/puter/commit/6ad8f5e06abd050d319271f818d72debf5bc8e44)) +* reduce token lengths ([5a76bad](https://github.com/HeyPuter/puter/commit/5a76bad28dfd8ec89a309941e410a54927fae22d)) +* reliability issue :bug: ([1d546d9](https://github.com/HeyPuter/puter/commit/1d546d9ef70ef9066ad5838e9782ae330d289f29)) +* Remove null or duplicate app entries from suggest_app_for_fsentry() ([6900233](https://github.com/HeyPuter/puter/commit/6900233c5aaa2d1a49f495e9f9a060796757a91e)) +* **security:** always use application/octet-stream ([74e213a](https://github.com/HeyPuter/puter/commit/74e213a534dbf2844c8cebeee7eb59ec70de306e)) +* **security:** Fix session revocation ([eb166a6](https://github.com/HeyPuter/puter/commit/eb166a67a9f0caf4fd77f9e27dc8209c2fc51f4c)) +* **security:** Move token for socket.io to request body ([49b257e](https://github.com/HeyPuter/puter/commit/49b257ecffbb1e12090b86a67528a5ad09da69db)) +* **security:** Prevent email enumeration ([ed70314](https://github.com/HeyPuter/puter/commit/ed703146863f896df76c98fad7127c6748c0ef9b)) +* **security:** skip cache when checking old passwd ([7800ef6](https://github.com/HeyPuter/puter/commit/7800ef61029c8d1ba47491b4028a0cb972298725)) +* **Terminal:** Accept input from Chrome on Android ([4ef3e53](https://github.com/HeyPuter/puter/commit/4ef3e53de34f0097950a7e707ca2483863beafb5)) +* test release-please action [#3](https://github.com/HeyPuter/puter/issues/3) ([8fb0a66](https://github.com/HeyPuter/puter/commit/8fb0a66ef21921990e564e5f61c0e80e7f929dc7)) +* test release-please action [#4](https://github.com/HeyPuter/puter/issues/4) ([f392de7](https://github.com/HeyPuter/puter/commit/f392de722a5232b622ed91b656a31cdc443c2e84)) +* typographical error :bug: ([2949f71](https://github.com/HeyPuter/puter/commit/2949f71691eb0a258888c5d2a5bb496d2fe64a23)) +* typographical errors :bug: ([4d30740](https://github.com/HeyPuter/puter/commit/4d30740198402cd1cc61b9ea4c45e006b69ec87e)) +* Use correct variable for version number ([52d5299](https://github.com/HeyPuter/puter/commit/52d52993744dffa9f7f59a232da5df9077560731)) +* use primary read in signup ([30f17ad](https://github.com/HeyPuter/puter/commit/30f17ade3a893d2283316e581836607e2029f9b9)) + ## [2.2.0](https://github.com/HeyPuter/puter/compare/v2.1.1...v2.2.0) (2024-04-23) diff --git a/package-lock.json b/package-lock.json index 6f6c696e09..505fa8870c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "puter.com", - "version": "2.2.0", + "version": "2.3.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "puter.com", - "version": "2.2.0", + "version": "1.0.0", "hasInstallScript": true, "license": "AGPL-3.0-only", "workspaces": [ diff --git a/package.json b/package.json index 203820aa9d..5bac1de7ea 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "puter.com", - "version": "2.2.0", + "version": "2.3.0", "author": "Puter Technologies Inc.", "license": "AGPL-3.0-only", "description": "Desktop environment in the browser!", From 94e9f8fd346d04216e66aad9bd6fff1cab13739c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20Dub=C3=A9?= Date: Fri, 24 May 2024 16:37:01 -0400 Subject: [PATCH 0098/2119] Update docker-image.yaml --- .github/workflows/docker-image.yaml | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docker-image.yaml b/.github/workflows/docker-image.yaml index fd5b1986d5..e04136a8ca 100644 --- a/.github/workflows/docker-image.yaml +++ b/.github/workflows/docker-image.yaml @@ -4,9 +4,10 @@ name: Docker Image CI # Configures this workflow to run every time a change is pushed to the # branch called `main`. on: - push: - tags: - - '*.*.*' + workflow_dispatch: + # push: + # tags: + # - '*.*.*' # branches: # - 'release' @@ -81,4 +82,4 @@ jobs: tags: ${{ steps.meta.outputs.tags }} labels: ${{ steps.meta.outputs.labels }} cache-from: type=gha - cache-to: type=gha,mode=max \ No newline at end of file + cache-to: type=gha,mode=max From 6ed9f0a01d1c2c0970ef3cbf2638476ad63856f9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20Dub=C3=A9?= Date: Fri, 24 May 2024 16:41:20 -0400 Subject: [PATCH 0099/2119] Update docker-image.yaml --- .github/workflows/docker-image.yaml | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.github/workflows/docker-image.yaml b/.github/workflows/docker-image.yaml index e04136a8ca..57750cca1d 100644 --- a/.github/workflows/docker-image.yaml +++ b/.github/workflows/docker-image.yaml @@ -5,6 +5,10 @@ name: Docker Image CI # branch called `main`. on: workflow_dispatch: + inputs: + version: + major: + minor: # push: # tags: # - '*.*.*' From 4d91ef14f4ab5bed5b2b32e2a39b1800039c1bc0 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20Dub=C3=A9?= Date: Fri, 24 May 2024 16:49:43 -0400 Subject: [PATCH 0100/2119] Update docker-image.yaml --- .github/workflows/docker-image.yaml | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker-image.yaml b/.github/workflows/docker-image.yaml index 57750cca1d..543819af26 100644 --- a/.github/workflows/docker-image.yaml +++ b/.github/workflows/docker-image.yaml @@ -7,8 +7,14 @@ on: workflow_dispatch: inputs: version: + description: 'Version WITHOUT leading "v"' + required: true major: + description: 'Major version component (redundant, but needed)' + required: true minor: + description: 'Minor version component (redundant, but needed)' + required: true # push: # tags: # - '*.*.*' @@ -65,8 +71,8 @@ jobs: with: images: "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" tags: | - type=semver,pattern={{version}} - type=semver,pattern={{major}}.{{minor}} + type=semver,pattern={{github.event.inputs.version}} + type=semver,pattern={{github.event.inputs.major}}.{{github.event.inputs.minor}} # This step uses the `docker/build-push-action` action to build the # image, based on your repository's `Dockerfile`. If the build succeeds, From f20870544d9c1903eb2676eb828e1e026a68d52e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20Dub=C3=A9?= Date: Fri, 24 May 2024 16:53:13 -0400 Subject: [PATCH 0101/2119] Update docker-image.yaml --- .github/workflows/docker-image.yaml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/docker-image.yaml b/.github/workflows/docker-image.yaml index 543819af26..cc57e5f9c3 100644 --- a/.github/workflows/docker-image.yaml +++ b/.github/workflows/docker-image.yaml @@ -71,8 +71,8 @@ jobs: with: images: "${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}" tags: | - type=semver,pattern={{github.event.inputs.version}} - type=semver,pattern={{github.event.inputs.major}}.{{github.event.inputs.minor}} + type=semver,pattern=${{github.event.inputs.version}} + type=semver,pattern=${{github.event.inputs.major}}.${{github.event.inputs.minor}} # This step uses the `docker/build-push-action` action to build the # image, based on your repository's `Dockerfile`. If the build succeeds, From cbfad2ef7adc66974e61734782040038b9f5fb79 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 24 May 2024 19:29:07 -0400 Subject: [PATCH 0102/2119] refactor(gui): add service scripts --- .../src/services/PuterHomepageService.js | 11 ++++--- src/UI/Settings/UIWindowSettings.js | 19 ++--------- src/index.js | 17 ++++++++++ src/initgui.js | 23 ++++++++++++- src/services/SettingsService.js | 32 +++++++++++++++++++ 5 files changed, 80 insertions(+), 22 deletions(-) create mode 100644 src/services/SettingsService.js diff --git a/packages/backend/src/services/PuterHomepageService.js b/packages/backend/src/services/PuterHomepageService.js index 003f11cf92..8f8f1fbd6c 100644 --- a/packages/backend/src/services/PuterHomepageService.js +++ b/packages/backend/src/services/PuterHomepageService.js @@ -212,11 +212,6 @@ class PuterHomepageService extends BaseService { ? manifest.js_paths.map(path => `\n`) : []).join('') } - ${ - this.service_scripts - .map(path => `\n`) - .join('') - } @@ -229,6 +224,12 @@ class PuterHomepageService extends BaseService { }); }); + + ${ + this.service_scripts + .map(path => `\n`) + .join('') + } diff --git a/src/UI/Settings/UIWindowSettings.js b/src/UI/Settings/UIWindowSettings.js index 133cca3073..832ea8f6ab 100644 --- a/src/UI/Settings/UIWindowSettings.js +++ b/src/UI/Settings/UIWindowSettings.js @@ -18,27 +18,14 @@ */ import UIWindow from '../UIWindow.js' -import AboutTab from './UITabAbout.js'; -import UsageTab from './UITabUsage.js'; -import AccountTab from './UITabAccount.js'; -import SecurityTab from './UITabSecurity.js'; -import PersonalizationTab from './UITabPersonalization.js'; -import LanguageTab from './UITabLanguage.js'; -import ClockTab from './UITabClock.js'; async function UIWindowSettings(options){ return new Promise(async (resolve) => { options = options ?? {}; - const tabs = [ - AboutTab, - UsageTab, - AccountTab, - SecurityTab, - PersonalizationTab, - LanguageTab, - ClockTab, - ]; + const svc_settings = globalThis.services.get('settings'); + + const tabs = svc_settings.get_tabs(); let h = ''; diff --git a/src/index.js b/src/index.js index f3f3c0fe3c..887193616a 100644 --- a/src/index.js +++ b/src/index.js @@ -16,6 +16,23 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ +window.service_script_api_promise = (() => { + let resolve, reject; + const promise = new Promise((res, rej) => { + resolve = res; + reject = rej; + }); + promise.resolve = resolve; + promise.reject = reject; + return promise; +})(); +window.service_script = async fn => { + try { + await fn(await window.service_script_api_promise); + } catch (e) { + console.error('service_script(ERROR)', e); + } +}; window.puter_gui_enabled = true; /** diff --git a/src/initgui.js b/src/initgui.js index 1cfcd517e2..8c7d086d83 100644 --- a/src/initgui.js +++ b/src/initgui.js @@ -39,28 +39,49 @@ import { BroadcastService } from './services/BroadcastService.js'; import { ProcessService } from './services/ProcessService.js'; import { PROCESS_RUNNING } from './definitions.js'; import { LocaleService } from './services/LocaleService.js'; +import { SettingsService } from './services/SettingsService.js'; const launch_services = async function () { + // === Services Data Structures === const services_l_ = []; const services_m_ = {}; globalThis.services = { get: (name) => services_m_[name], }; - const register = (name, instance) => { services_l_.push([name, instance]); services_m_[name] = instance; } + // === Hooks for Service Scripts from Backend === + const service_script_deferred = { services: [], on_ready: [] }; + const service_script_api = { + register: (...a) => service_script_deferred.services.push(a), + on_ready: fn => service_script_deferred.on_ready.push(fn), + }; + globalThis.service_script_api_promise.resolve(service_script_api); + + // === Builtin Services === register('broadcast', new BroadcastService()); register('theme', new ThemeService()); register('process', new ProcessService()); register('locale', new LocaleService()); + register('settings', new SettingsService()); + + // === Service-Script Services === + for (const [name, script] of service_script_deferred.services) { + register(name, script); + } for (const [_, instance] of services_l_) { await instance.init(); } + // === Service-Script Ready === + for (const fn of service_script_deferred.on_ready) { + await fn(); + } + // Set init process status { const svc_process = globalThis.services.get('process'); diff --git a/src/services/SettingsService.js b/src/services/SettingsService.js new file mode 100644 index 0000000000..3470fdce83 --- /dev/null +++ b/src/services/SettingsService.js @@ -0,0 +1,32 @@ +import { Service } from "../definitions.js"; + +import AboutTab from '../UI/Settings/UITabAbout.js'; +import UsageTab from '../UI/Settings/UITabUsage.js'; +import AccountTab from '../UI/Settings/UITabAccount.js'; +import SecurityTab from '../UI/Settings/UITabSecurity.js'; +import PersonalizationTab from '../UI/Settings/UITabPersonalization.js'; +import LanguageTag from '../UI/Settings/UITabLanguage.js'; +import ClockTab from '../UI/Settings/UITabClock.js'; + +export class SettingsService extends Service { + #tabs = []; + async _init () { + ;[ + AboutTab, + UsageTab, + AccountTab, + SecurityTab, + PersonalizationTab, + LanguageTag, + ClockTab, + ].forEach(tab => { + this.register_tab(tab); + }); + } + get_tabs () { + return this.#tabs; + } + register_tab (tab) { + this.#tabs.push(tab); + } +} From 06f41659f54617eeb41954d6a2ca98dfeb57b2ec Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sat, 25 May 2024 17:20:22 -0400 Subject: [PATCH 0103/2119] Add function to import UIWindow from service scripts --- src/initgui.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/initgui.js b/src/initgui.js index 8c7d086d83..9e079e7185 100644 --- a/src/initgui.js +++ b/src/initgui.js @@ -40,6 +40,7 @@ import { ProcessService } from './services/ProcessService.js'; import { PROCESS_RUNNING } from './definitions.js'; import { LocaleService } from './services/LocaleService.js'; import { SettingsService } from './services/SettingsService.js'; +import UIComponentWindow from './UI/UIComponentWindow.js'; const launch_services = async function () { // === Services Data Structures === @@ -58,6 +59,9 @@ const launch_services = async function () { const service_script_api = { register: (...a) => service_script_deferred.services.push(a), on_ready: fn => service_script_deferred.on_ready.push(fn), + // Some files can't be imported by service scripts, + // so this hack makes that possible. + use: name => ({ UIWindow, UIComponentWindow })[name], }; globalThis.service_script_api_promise.resolve(service_script_api); From c0cb1cd2b886d78bd3b2396586a5d0087b5a2cd3 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sun, 26 May 2024 00:31:51 -0400 Subject: [PATCH 0104/2119] refactor: add GetUserService --- packages/backend/src/CoreModule.js | 3 + packages/backend/src/helpers.js | 61 +------------ .../backend/src/services/GetUserService.js | 89 +++++++++++++++++++ 3 files changed, 94 insertions(+), 59 deletions(-) create mode 100644 packages/backend/src/services/GetUserService.js diff --git a/packages/backend/src/CoreModule.js b/packages/backend/src/CoreModule.js index 6ae1c420ac..c16ef57fee 100644 --- a/packages/backend/src/CoreModule.js +++ b/packages/backend/src/CoreModule.js @@ -216,6 +216,9 @@ const install = async ({ services, app }) => { const { PuterHomepageService } = require('./services/PuterHomepageService'); services.registerService('puter-homepage', PuterHomepageService); + + const { GetUserService } = require('./services/GetUserService'); + services.registerService('get-user', GetUserService); } const install_legacy = async ({ services }) => { diff --git a/packages/backend/src/helpers.js b/packages/backend/src/helpers.js index e2b80964bf..3ceb9efc6a 100644 --- a/packages/backend/src/helpers.js +++ b/packages/backend/src/helpers.js @@ -176,65 +176,8 @@ async function id2uuid(id){ * @param {string} options - `options` * @returns {Promise} */ - async function get_user(options){ - /** @type BaseDatabaseAccessService */ - const db = services.get('database').get(DB_READ, 'filesystem'); - - let user; - - const cached = options.cached ?? true; - - if ( cached && ! options.force ) { - if (options.username) user = kv.get('users:username:' + options.username); - else if (options.email) user = kv.get('users:email:' + options.email); - else if (options.uuid) user = kv.get('users:uuid:' + options.uuid); - else if (options.id) user = kv.get('users:id:' + options.id); - else if (options.referral_code) user = kv.get('users:referral_code:' + options.referral_code); - - if ( user ) return user; - } - - if ( ! options.force ) { - if(options.username) - user = await db.read("SELECT * FROM `user` WHERE `username` = ? LIMIT 1", [options.username]); - else if(options.email) - user = await db.read("SELECT * FROM `user` WHERE `email` = ? LIMIT 1", [options.email]); - else if(options.uuid) - user = await db.read("SELECT * FROM `user` WHERE `uuid` = ? LIMIT 1", [options.uuid]); - else if(options.id) - user = await db.read("SELECT * FROM `user` WHERE `id` = ? LIMIT 1", [options.id]); - else if(options.referral_code) - user = await db.read("SELECT * FROM `user` WHERE `referral_code` = ? LIMIT 1", [options.referral_code]); - } - - if(!user || !user[0]){ - if(options.username) - user = await db.pread("SELECT * FROM `user` WHERE `username` = ? LIMIT 1", [options.username]) - else if(options.email) - user = await db.pread("SELECT * FROM `user` WHERE `email` = ? LIMIT 1", [options.email]); - else if(options.uuid) - user = await db.pread("SELECT * FROM `user` WHERE `uuid` = ? LIMIT 1", [options.uuid]); - else if(options.id) - user = await db.pread("SELECT * FROM `user` WHERE `id` = ? LIMIT 1", [options.id]); - else if(options.referral_code) - user = await db.pread("SELECT * FROM `user` WHERE `referral_code` = ? LIMIT 1", [options.referral_code]); - } - - user = user ? user[0] : null; - - if ( ! user ) return user; - - try { - kv.set('users:username:' + user.username, user); - kv.set('users:email:' + user.email, user); - kv.set('users:uuid:' + user.uuid, user); - kv.set('users:id:' + user.id, user); - kv.set('users:referral_code:' + user.referral_code, user); - } catch (e) { - console.error(e); - } - - return user; +async function get_user(options) { + return await services.get('get-user').get_user(options); } /** diff --git a/packages/backend/src/services/GetUserService.js b/packages/backend/src/services/GetUserService.js new file mode 100644 index 0000000000..9c3e695e37 --- /dev/null +++ b/packages/backend/src/services/GetUserService.js @@ -0,0 +1,89 @@ +const BaseService = require("./BaseService"); +const { DB_READ } = require("./database/consts"); + +/** + * Get user by one of a variety of identifying properties. + * + * Pass `cached: false` to options to force a database read. + * Pass `force: true` to options to force a primary database read. + * + * This provides the functionality of `get_user` (helpers.js) + * as a service so that other services can register identifying + * properties for caching. + * + * The original `get_user` function now uses this service. + */ +class GetUserService extends BaseService { + _construct () { + this.id_properties = new Set(); + + this.id_properties.add('username'); + this.id_properties.add('uuid'); + this.id_properties.add('id'); + this.id_properties.add('email'); + this.id_properties.add('referral_code'); + } + async _init () { + } + async get_user (options) { + const services = this.services; + + /** @type BaseDatabaseAccessService */ + const db = services.get('database').get(DB_READ, 'filesystem'); + + const cached = options.cached ?? true; + + if ( cached && ! options.force ) { + for ( const prop of this.id_properties ) { + if ( options.hasOwnProperty(prop) ) { + const user = kv.get(`users:${prop}:${options[prop]}`); + if ( user ) return user; + } + } + } + + let user; + + if ( ! options.force ) { + for ( const prop of this.id_properties ) { + if ( options.hasOwnProperty(prop) ) { + [user] = await db.read(`SELECT * FROM \`user\` WHERE \`${prop}\` = ? LIMIT 1`, [options[prop]]); + if ( user ) break; + } + } + } + + if ( ! user || ! user[0] ) { + for ( const prop of this.id_properties ) { + if ( options.hasOwnProperty(prop) ) { + [user] = await db.pread(`SELECT * FROM \`user\` WHERE \`${prop}\` = ? LIMIT 1`, [options[prop]]); + if ( user ) break; + } + } + } + + if ( ! user ) return null; + + try { + for ( const prop of this.id_properties ) { + if ( user[prop] ) { + kv.set(`users:${prop}:${user[prop]}`, user); + } + } + // kv.set('users:username:' + user.username, user); + // kv.set('users:email:' + user.email, user); + // kv.set('users:uuid:' + user.uuid, user); + // kv.set('users:id:' + user.id, user); + // kv.set('users:referral_code:' + user.referral_code, user); + } catch (e) { + console.error(e); + } + + return user; + } + register_id_property (prop) { + this.id_properties.add(prop); + } +} + +module.exports = { GetUserService }; \ No newline at end of file From 51bac4486f01ee7f0b97a82ade3a36d929a2682f Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 27 May 2024 21:14:10 -0400 Subject: [PATCH 0105/2119] Add class registry (first pass) In the first pass I add a `register` method and update `defineComponent` so it calls `register` as well. This made it possible to create a proof-of-concept for registered classes. Additionally ExportService was added to expose registered classes to service scripts. This first pass works, but it would be better if all types of classes (components or otherwise) were registered via the same method. --- .../src/services/PuterHomepageService.js | 22 +++++++++++ src/UI/Components/Button.js | 4 +- src/UI/Components/CodeEntryView.js | 4 +- src/UI/Components/ConfirmationsView.js | 4 +- src/UI/Components/Flexer.js | 4 +- src/UI/Components/JustHTML.js | 4 +- src/UI/Components/PasswordEntry.js | 4 +- src/UI/Components/QRCode.js | 4 +- src/UI/Components/RecoveryCodeEntryView.js | 3 +- src/UI/Components/RecoveryCodesView.js | 4 +- src/UI/Components/Slider.js | 4 +- src/UI/Components/StepHeading.js | 4 +- src/UI/Components/StepView.js | 4 +- src/UI/Components/StringView.js | 4 +- src/UI/Components/Table.js | 4 +- src/UI/Components/TestView.js | 4 +- src/UI/UIWindowTaskManager.js | 7 +++- src/definitions.js | 4 ++ src/index.js | 17 --------- src/initgui.js | 18 ++++++++- src/services/ExportService.js | 24 ++++++++++++ src/util/Component.js | 38 +++++++++++++++++-- src/util/TeePromise.js | 4 ++ src/util/register.js | 17 +++++++++ 24 files changed, 170 insertions(+), 40 deletions(-) create mode 100644 src/services/ExportService.js create mode 100644 src/util/register.js diff --git a/packages/backend/src/services/PuterHomepageService.js b/packages/backend/src/services/PuterHomepageService.js index 8f8f1fbd6c..2c8f8fe738 100644 --- a/packages/backend/src/services/PuterHomepageService.js +++ b/packages/backend/src/services/PuterHomepageService.js @@ -161,6 +161,28 @@ class PuterHomepageService extends BaseService { + + ${ ((!bundled && manifest?.css_paths) diff --git a/src/UI/Components/Button.js b/src/UI/Components/Button.js index 9950f51eed..4b7436a2ba 100644 --- a/src/UI/Components/Button.js +++ b/src/UI/Components/Button.js @@ -1,6 +1,8 @@ import { Component, defineComponent } from "../../util/Component.js"; export default class Button extends Component { + static ID = 'ui.component.Button'; + static PROPERTIES = { label: { value: 'Test Label' }, on_click: { value: null }, @@ -65,4 +67,4 @@ export default class Button extends Component { } } -defineComponent('c-button', Button); +defineComponent(Button); diff --git a/src/UI/Components/CodeEntryView.js b/src/UI/Components/CodeEntryView.js index a4d0c53820..6d218353c2 100644 --- a/src/UI/Components/CodeEntryView.js +++ b/src/UI/Components/CodeEntryView.js @@ -1,6 +1,8 @@ import { Component, defineComponent } from "../../util/Component.js"; export default class CodeEntryView extends Component { + static ID = 'ui.component.CodeEntryView'; + static PROPERTIES = { value: {}, error: {}, @@ -215,4 +217,4 @@ export default class CodeEntryView extends Component { } } -defineComponent('c-code-entry-view', CodeEntryView); +defineComponent(CodeEntryView); diff --git a/src/UI/Components/ConfirmationsView.js b/src/UI/Components/ConfirmationsView.js index 19ec4d3e90..73e17b0cdb 100644 --- a/src/UI/Components/ConfirmationsView.js +++ b/src/UI/Components/ConfirmationsView.js @@ -4,6 +4,8 @@ import { Component, defineComponent } from "../../util/Component.js"; * Display a list of checkboxes for the user to confirm. */ export default class ConfirmationsView extends Component { + static ID = 'ui.component.ConfirmationsView'; + static PROPERTIES = { confirmations: { description: 'The list of confirmations to display', @@ -58,4 +60,4 @@ export default class ConfirmationsView extends Component { } } -defineComponent('c-confirmations-view', ConfirmationsView); +defineComponent(ConfirmationsView); diff --git a/src/UI/Components/Flexer.js b/src/UI/Components/Flexer.js index 838be891c9..cce4af7be5 100644 --- a/src/UI/Components/Flexer.js +++ b/src/UI/Components/Flexer.js @@ -5,6 +5,8 @@ import { Component, defineComponent } from "../../util/Component.js"; * treated as a component. */ export default class Flexer extends Component { + static ID = 'ui.component.Flexer'; + static PROPERTIES = { children: {}, gap: { value: '20pt' }, @@ -38,4 +40,4 @@ export default class Flexer extends Component { } } -defineComponent('c-flexer', Flexer); +defineComponent(Flexer); diff --git a/src/UI/Components/JustHTML.js b/src/UI/Components/JustHTML.js index 36e17db59b..bc896583c9 100644 --- a/src/UI/Components/JustHTML.js +++ b/src/UI/Components/JustHTML.js @@ -4,6 +4,8 @@ import { Component, defineComponent } from "../../util/Component.js"; * Allows using an HTML string as a component. */ export default class JustHTML extends Component { + static ID = 'ui.component.JustHTML'; + static PROPERTIES = { html: { value: '' } }; create_template ({ template }) { $(template).html(``); @@ -15,4 +17,4 @@ export default class JustHTML extends Component { } } -defineComponent('c-just-html', JustHTML); +defineComponent(JustHTML); diff --git a/src/UI/Components/PasswordEntry.js b/src/UI/Components/PasswordEntry.js index cbacdffea4..7cd6afa32f 100644 --- a/src/UI/Components/PasswordEntry.js +++ b/src/UI/Components/PasswordEntry.js @@ -1,6 +1,8 @@ import { Component, defineComponent } from "../../util/Component.js"; export default class PasswordEntry extends Component { + static ID = 'ui.component.PasswordEntry'; + static PROPERTIES = { spec: {}, value: {}, @@ -133,4 +135,4 @@ export default class PasswordEntry extends Component { } } -defineComponent('c-password-entry', PasswordEntry); +defineComponent(PasswordEntry); diff --git a/src/UI/Components/QRCode.js b/src/UI/Components/QRCode.js index bb974d99f6..b5c698dd06 100644 --- a/src/UI/Components/QRCode.js +++ b/src/UI/Components/QRCode.js @@ -2,6 +2,8 @@ import { Component, defineComponent } from "../../util/Component.js"; import UIComponentWindow from "../UIComponentWindow.js"; export default class QRCodeView extends Component { + static ID = 'ui.component.QRCodeView'; + static PROPERTIES = { value: { description: 'The text to encode in the QR code', @@ -78,4 +80,4 @@ export default class QRCodeView extends Component { } } -defineComponent('c-qr-code', QRCodeView); +defineComponent(QRCodeView); diff --git a/src/UI/Components/RecoveryCodeEntryView.js b/src/UI/Components/RecoveryCodeEntryView.js index b17d27e184..7b63b63d1e 100644 --- a/src/UI/Components/RecoveryCodeEntryView.js +++ b/src/UI/Components/RecoveryCodeEntryView.js @@ -1,6 +1,7 @@ import { Component, defineComponent } from "../../util/Component.js"; export default class RecoveryCodeEntryView extends Component { + static ID = 'ui.component.RecoveryCodeEntryView'; static PROPERTIES = { value: {}, length: { value: 8 }, @@ -84,4 +85,4 @@ export default class RecoveryCodeEntryView extends Component { } } -defineComponent('c-recovery-code-entry', RecoveryCodeEntryView); +defineComponent(RecoveryCodeEntryView); diff --git a/src/UI/Components/RecoveryCodesView.js b/src/UI/Components/RecoveryCodesView.js index e72bd37f14..89fac698fc 100644 --- a/src/UI/Components/RecoveryCodesView.js +++ b/src/UI/Components/RecoveryCodesView.js @@ -1,6 +1,8 @@ import { Component, defineComponent } from "../../util/Component.js"; export default class RecoveryCodesView extends Component { + static ID = 'ui.component.RecoveryCodesView'; + static PROPERTIES = { values: { description: 'The recovery codes to display', @@ -91,4 +93,4 @@ export default class RecoveryCodesView extends Component { } } -defineComponent('c-recovery-codes-view', RecoveryCodesView); +defineComponent(RecoveryCodesView); diff --git a/src/UI/Components/Slider.js b/src/UI/Components/Slider.js index 18281d80df..64e68fe9fb 100644 --- a/src/UI/Components/Slider.js +++ b/src/UI/Components/Slider.js @@ -22,6 +22,8 @@ import { Component, defineComponent } from "../../util/Component.js"; * Slider: A labeled slider input. */ export default class Slider extends Component { + static ID = 'ui.component.Slider'; + static PROPERTIES = { name: { value: null }, label: { value: null }, @@ -111,4 +113,4 @@ export default class Slider extends Component { } } -defineComponent('c-slider', Slider); +defineComponent(Slider); diff --git a/src/UI/Components/StepHeading.js b/src/UI/Components/StepHeading.js index b095d8320b..fbfcd4e6f9 100644 --- a/src/UI/Components/StepHeading.js +++ b/src/UI/Components/StepHeading.js @@ -6,6 +6,8 @@ import { Component, defineComponent } from "../../util/Component.js"; * optimized for single-digit numbers. */ export default class StepHeading extends Component { + static ID = 'ui.component.StepHeading'; + static PROPERTIES = { symbol: { description: 'The symbol to display', @@ -58,4 +60,4 @@ export default class StepHeading extends Component { } } -defineComponent('c-step-heading', StepHeading); +defineComponent(StepHeading); diff --git a/src/UI/Components/StepView.js b/src/UI/Components/StepView.js index 4bc98e7779..dc35968612 100644 --- a/src/UI/Components/StepView.js +++ b/src/UI/Components/StepView.js @@ -1,6 +1,8 @@ import { Component, defineComponent } from "../../util/Component.js"; export default class StepView extends Component { + static ID = 'ui.component.StepView'; + static PROPERTIES = { children: {}, done: { value: false }, @@ -64,4 +66,4 @@ export default class StepView extends Component { } } -defineComponent('c-step-view', StepView); +defineComponent(StepView); diff --git a/src/UI/Components/StringView.js b/src/UI/Components/StringView.js index a41552c622..a4a6765238 100644 --- a/src/UI/Components/StringView.js +++ b/src/UI/Components/StringView.js @@ -5,6 +5,8 @@ import { Component, defineComponent } from "../../util/Component.js"; * specified style. */ export default class StringView extends Component { + static ID = 'ui.component.StringView'; + static PROPERTIES = { text: { value: '' }, heading: { value: 0 }, @@ -42,4 +44,4 @@ export default class StringView extends Component { } } -defineComponent('c-string-view', StringView); +defineComponent(StringView); diff --git a/src/UI/Components/Table.js b/src/UI/Components/Table.js index 865aa7c4cf..0b1ba6b3b9 100644 --- a/src/UI/Components/Table.js +++ b/src/UI/Components/Table.js @@ -4,6 +4,8 @@ import { Component, defineComponent } from "../../util/Component.js"; * A table with a sticky header */ export default class Table extends Component { + static ID = 'ui.component.Table'; + static PROPERTIES = { headings: { value: [] }, scale: { value: '2pt' }, @@ -80,4 +82,4 @@ export default class Table extends Component { } } -defineComponent('c-table', Table); +defineComponent(Table); diff --git a/src/UI/Components/TestView.js b/src/UI/Components/TestView.js index 9fd76a3caa..59121f46fd 100644 --- a/src/UI/Components/TestView.js +++ b/src/UI/Components/TestView.js @@ -4,6 +4,8 @@ import { Component, defineComponent } from "../../util/Component.js"; * A simple component when you just need to test something. */ export default class TestView extends Component { + static ID = 'ui.component.TestView'; + static CSS = ` div { background-color: lightblue; @@ -19,4 +21,4 @@ export default class TestView extends Component { } } -defineComponent('c-test-view', TestView); +defineComponent(TestView); diff --git a/src/UI/UIWindowTaskManager.js b/src/UI/UIWindowTaskManager.js index 7cb2b392ac..c92756e5c9 100644 --- a/src/UI/UIWindowTaskManager.js +++ b/src/UI/UIWindowTaskManager.js @@ -49,6 +49,7 @@ const end_process = async (uuid, force) => { }; class TaskManagerTable extends Component { + static ID = 'ui.component.TaskManagerTable'; static PROPERTIES = { tasks: { value: [] }, }; @@ -157,9 +158,11 @@ class TaskManagerTable extends Component { return rows; }; } -defineComponent('c-task-manager-table', TaskManagerTable); +defineComponent(TaskManagerTable); class TaskManagerRow extends Component { + static ID = 'ui.component.TaskManagerRow'; + static PROPERTIES = { name: {}, uuid: {}, @@ -291,7 +294,7 @@ class TaskManagerRow extends Component { }); } } -defineComponent('c-task-manager-row', TaskManagerRow); +defineComponent(TaskManagerRow); const UIWindowTaskManager = async function UIWindowTaskManager () { const svc_process = globalThis.services.get('process'); diff --git a/src/definitions.js b/src/definitions.js index 9a6a84c459..90bc50e1f1 100644 --- a/src/definitions.js +++ b/src/definitions.js @@ -17,6 +17,10 @@ * along with this program. If not, see . */ export class Service { + construct () { + if ( ! this._construct ) return; + return this._construct(); + } init (...a) { if ( ! this._init ) return; return this._init(...a) diff --git a/src/index.js b/src/index.js index 887193616a..f3f3c0fe3c 100644 --- a/src/index.js +++ b/src/index.js @@ -16,23 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -window.service_script_api_promise = (() => { - let resolve, reject; - const promise = new Promise((res, rej) => { - resolve = res; - reject = rej; - }); - promise.resolve = resolve; - promise.reject = reject; - return promise; -})(); -window.service_script = async fn => { - try { - await fn(await window.service_script_api_promise); - } catch (e) { - console.error('service_script(ERROR)', e); - } -}; window.puter_gui_enabled = true; /** diff --git a/src/initgui.js b/src/initgui.js index 9e079e7185..9a9c654c4e 100644 --- a/src/initgui.js +++ b/src/initgui.js @@ -40,7 +40,9 @@ import { ProcessService } from './services/ProcessService.js'; import { PROCESS_RUNNING } from './definitions.js'; import { LocaleService } from './services/LocaleService.js'; import { SettingsService } from './services/SettingsService.js'; +import { ExportService } from './services/ExportService.js'; import UIComponentWindow from './UI/UIComponentWindow.js'; +import Spinner from './UI/Components/Spinner.js'; const launch_services = async function () { // === Services Data Structures === @@ -54,6 +56,9 @@ const launch_services = async function () { services_m_[name] = instance; } + const svc_export = new ExportService(); + svc_export.register('UIComponentWindow', UIComponentWindow); + // === Hooks for Service Scripts from Backend === const service_script_deferred = { services: [], on_ready: [] }; const service_script_api = { @@ -61,7 +66,9 @@ const launch_services = async function () { on_ready: fn => service_script_deferred.on_ready.push(fn), // Some files can't be imported by service scripts, // so this hack makes that possible. - use: name => ({ UIWindow, UIComponentWindow })[name], + use: svc_export.get.bind(svc_export), + exp: svc_export.register.bind(svc_export), + // use: name => ({ UIWindow, UIComponentWindow })[name], }; globalThis.service_script_api_promise.resolve(service_script_api); @@ -71,6 +78,7 @@ const launch_services = async function () { register('process', new ProcessService()); register('locale', new LocaleService()); register('settings', new SettingsService()); + register('export', svc_export); // === Service-Script Services === for (const [name, script] of service_script_deferred.services) { @@ -78,7 +86,13 @@ const launch_services = async function () { } for (const [_, instance] of services_l_) { - await instance.init(); + await instance.construct(); + } + + for (const [_, instance] of services_l_) { + await instance.init({ + services: globalThis.services, + }); } // === Service-Script Ready === diff --git a/src/services/ExportService.js b/src/services/ExportService.js new file mode 100644 index 0000000000..f05f7e7791 --- /dev/null +++ b/src/services/ExportService.js @@ -0,0 +1,24 @@ +import { Service } from "../definitions.js"; + +/** + * This service is responsible for exporting definitions to the + * service script SDK. This is the SDK that services provided by + * the backend will use. + */ +export class ExportService extends Service { + constructor () { + super(); + this.exports_ = {}; + } + + register (name, definition) { + this.exports_[name] = definition; + } + + get (name) { + if ( name ) { + return this.exports_[name]; + } + return this.exports_; + } +} diff --git a/src/util/Component.js b/src/util/Component.js index 40839c86a8..76ed132d9b 100644 --- a/src/util/Component.js +++ b/src/util/Component.js @@ -1,4 +1,5 @@ import ValueHolder from "./ValueHolder.js"; +import { register } from "./register.js"; export class Component extends HTMLElement { #has_created_element = false; @@ -146,10 +147,39 @@ export class Component extends HTMLElement { } } -export const defineComponent = (name, component) => { - // TODO: This is necessary because files can be loaded from - // both `/src/UI` and `/UI` in the URL; we need to fix that - if ( ! customElements.get(name) ) { +// TODO: move this somewhere more useful +function is_subclass(subclass, superclass) { + if (subclass === superclass) return true; + + let proto = subclass.prototype; + while (proto) { + if (proto === superclass.prototype) return true; + proto = Object.getPrototypeOf(proto); + } + + return false; +} + +export const defineComponent = (component) => { + // Web components need tags (despite that we never use the tags) + // because it was designed this way. + if ( is_subclass(component, HTMLElement) ) { + console.log('defining', component); + let name = component.ID; + name = 'c-' + name.split('.').pop().toLowerCase(); + // TODO: This is necessary because files can be loaded from + // both `/src/UI` and `/UI` in the URL; we need to fix that + console.log('[maybe] defining', name, 'as', component); + if ( customElements.get(name) ) return; + + console.log('[surely] defining', name, 'as', component); + customElements.define(name, component); + component.defined_as = name; } + + // Service scripts aren't able to import anything when the + // GUI code is bundled, so we need to use a custom export + // mechanism for them. + register(component); }; diff --git a/src/util/TeePromise.js b/src/util/TeePromise.js index 94f9b9d6f2..5192ee6ac0 100644 --- a/src/util/TeePromise.js +++ b/src/util/TeePromise.js @@ -1,3 +1,5 @@ +import { register } from "./register.js"; + export default class TeePromise { static STATUS_PENDING = {}; static STATUS_RUNNING = {}; @@ -41,3 +43,5 @@ export default class TeePromise { return this.then(fn); } } + +register(TeePromise, 'TeePromise'); \ No newline at end of file diff --git a/src/util/register.js b/src/util/register.js new file mode 100644 index 0000000000..5da2d37288 --- /dev/null +++ b/src/util/register.js @@ -0,0 +1,17 @@ +/** + * register registers a class with things that need classes + * to be registered. When in doubt, register your class. + * + * More specifically this function is here to handle such + * situations as service scripts not being able to import + * classes when the frontend is bundled. + * + * @param {*} cls + * @param {*} opt_name + */ +export const register = (cls, opt_name) => { + (async () => { + const api = await globalThis.service_script_api_promise; + api.exp(opt_name || cls.ID.split('.').pop(), cls); + })() +}; From 4e3a24e6093e279e210765e07e436f4e63b74072 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 28 May 2024 15:51:22 -0400 Subject: [PATCH 0106/2119] fix: check subdomain earlier for /apps --- packages/backend/src/middleware/subdomain.js | 27 ++++++++++++++++++++ packages/backend/src/routers/apps.js | 15 +++++++---- 2 files changed, 37 insertions(+), 5 deletions(-) create mode 100644 packages/backend/src/middleware/subdomain.js diff --git a/packages/backend/src/middleware/subdomain.js b/packages/backend/src/middleware/subdomain.js new file mode 100644 index 0000000000..fcb4a8ecd9 --- /dev/null +++ b/packages/backend/src/middleware/subdomain.js @@ -0,0 +1,27 @@ +/** + * This middleware checks the subdomain, and if the subdomain doesn't + * match it calls `next('route')` to skip the current route. + * Be sure to use this before any middleware that might erroneously + * block the request. + * + * @param {string|string[]} allowedSubdomains - The subdomain to allow; + * if an array, any of the subdomains in the array will be allowed. + * + * @returns {function} - An express middleware function + */ +const subdomain = allowedSubdomains => { + if ( ! Array.isArray(allowedSubdomains) ) { + allowedSubdomains = [allowedSubdomains]; + } + return async (req, res, next) => { + // Note: at the time of implementing this, there is a config + // option called `experimental_no_subdomain` that is designed + // to lie and tell us the subdomain is `api` when it's not. + const actual_subdomain = require('../helpers').subdomain(req); + if ( ! allowedSubdomains.includes(actual_subdomain) ) { + next('route'); + } + }; +} + +module.exports = subdomain; diff --git a/packages/backend/src/routers/apps.js b/packages/backend/src/routers/apps.js index 17572c1fcc..1aa5896ebe 100644 --- a/packages/backend/src/routers/apps.js +++ b/packages/backend/src/routers/apps.js @@ -23,14 +23,15 @@ const auth = require('../middleware/auth.js'); const config = require('../config'); const { app_name_exists, refresh_apps_cache, chkperm, convert_path_to_fsentry, get_app } = require('../helpers'); const { DB_WRITE, DB_READ } = require('../services/database/consts.js'); +const subdomain = require('../middleware/subdomain.js'); // -----------------------------------------------------------------------// // GET /apps // -----------------------------------------------------------------------// -router.get('/apps', auth, express.json({limit: '50mb'}), async (req, res, next)=>{ - // check subdomain - if(require('../helpers').subdomain(req) !== 'api') - next(); +router.get('/apps', + subdomain('api'), + auth, express.json({limit: '50mb'}), async (req, res, next)=>{ + // /!\ open brace on end of previous line // check if user is verified if((config.strict_email_verification_required || req.user.requires_email_confirmation) && !req.user.email_confirmed) @@ -88,7 +89,11 @@ router.get('/apps', auth, express.json({limit: '50mb'}), async (req, res, next)= // -----------------------------------------------------------------------// // GET /apps/:name(s) // -----------------------------------------------------------------------// -router.get('/apps/:name', auth, express.json({limit: '50mb'}), async (req, res, next)=>{ +router.get('/apps/:name', + subdomain('api'), + auth, express.json({limit: '50mb'}), async (req, res, next)=>{ + // /!\ open brace on end of previous line + // check subdomain if(require('../helpers').subdomain(req) !== 'api') next(); From cd574c87ef56349431d4ebb622fccfa8dc2094d3 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 28 May 2024 16:10:43 -0400 Subject: [PATCH 0107/2119] Fix the previous fix --- packages/backend/src/middleware/subdomain.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/packages/backend/src/middleware/subdomain.js b/packages/backend/src/middleware/subdomain.js index fcb4a8ecd9..6735b8c13a 100644 --- a/packages/backend/src/middleware/subdomain.js +++ b/packages/backend/src/middleware/subdomain.js @@ -20,7 +20,10 @@ const subdomain = allowedSubdomains => { const actual_subdomain = require('../helpers').subdomain(req); if ( ! allowedSubdomains.includes(actual_subdomain) ) { next('route'); + return; } + + next(); }; } From e050506a0510fc723ebc542d26f84da5351f63a2 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 28 May 2024 18:12:07 -0400 Subject: [PATCH 0108/2119] Add class registry (second pass) ExportService gets removed and instead a global class registry is added. The `init.js` file is split into `init_sync.js` and `init_async.js` so that synchronous code that isn't dependent on imports is guarenteed to run before initgui.js. The globalThis scope and service-script API now expose `def`, a function for registering class definitions, and `use`, a function for obtaining registered classes. --- .../src/services/PuterHomepageService.js | 15 ++- puter-gui.json | 3 +- src/UI/Components/Button.js | 8 +- src/UI/Components/CodeEntryView.js | 8 +- src/UI/Components/ConfirmationsView.js | 8 +- src/UI/Components/Flexer.js | 8 +- src/UI/Components/JustHTML.js | 8 +- src/UI/Components/PasswordEntry.js | 8 +- src/UI/Components/QRCode.js | 8 +- src/UI/Components/RecoveryCodeEntryView.js | 8 +- src/UI/Components/RecoveryCodesView.js | 8 +- src/UI/Components/Slider.js | 8 +- src/UI/Components/Spinner.js | 41 ++++++ src/UI/Components/StepHeading.js | 8 +- src/UI/Components/StepView.js | 8 +- src/UI/Components/StringView.js | 8 +- src/UI/Components/Table.js | 8 +- src/UI/Components/TestView.js | 8 +- src/index.js | 1 + src/init_async.js | 8 ++ src/init_sync.js | 119 ++++++++++++++++++ src/initgui.js | 11 +- src/services/ExportService.js | 24 ---- src/static-assets.js | 2 + src/util/Component.js | 52 ++++---- src/util/TeePromise.js | 8 +- src/util/register.js | 17 --- 27 files changed, 265 insertions(+), 156 deletions(-) create mode 100644 src/UI/Components/Spinner.js create mode 100644 src/init_async.js create mode 100644 src/init_sync.js delete mode 100644 src/services/ExportService.js delete mode 100644 src/util/register.js diff --git a/packages/backend/src/services/PuterHomepageService.js b/packages/backend/src/services/PuterHomepageService.js index 2c8f8fe738..a32c017ff3 100644 --- a/packages/backend/src/services/PuterHomepageService.js +++ b/packages/backend/src/services/PuterHomepageService.js @@ -114,6 +114,12 @@ class PuterHomepageService extends BaseService { const bundled = env != 'dev' || use_bundled_gui; + const writeScriptTag = path => + `\n` + ; + return ` @@ -231,13 +237,16 @@ class PuterHomepageService extends BaseService { ${ ((!bundled && manifest?.js_paths) - ? manifest.js_paths.map(path => `\n`) + ? manifest.js_paths.map(path => writeScriptTag(path)) : []).join('') } - + - + + + + + + + + + \ No newline at end of file diff --git a/src/dev-center/js/dev-center.js b/src/dev-center/js/dev-center.js new file mode 100644 index 0000000000..c154f26ce3 --- /dev/null +++ b/src/dev-center/js/dev-center.js @@ -0,0 +1,1844 @@ +/** + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ + +let URLParams = new URLSearchParams(window.location.search); +let domain = 'puter.com', authUsername; +let source_path +let apps = []; +let sortBy = 'created_at'; +let sortDirection = 'desc'; +const dev_center_uid = 'app-240a43f4-43b1-49bc-b9fc-c8ae719dab77'; +let developer; +let activeTab = 'apps'; +let currently_editing_app; +let dropped_items; +let search_query; + +const deploying_spinner = ``; +const loading_spinner = ``; +const drop_area_placeholder = `

Drop your app folder and files here to deploy.

HTML, JS, CSS, ...

`; +const index_missing_error = `Please upload an 'index.html' file or if you're uploading a directory, make sure it contains an 'index.html' file at its root.` + +// authUsername +if (URLParams.has('puter.auth.username')) { + authUsername = URLParams.get('puter.auth.username'); +} else { + //todo error and terminate +} + +// source_path +if (URLParams.has('source_path')) { + source_path = URLParams.get('source_path'); +} else { + source_path = null; +} + +// domain and APIOrigin +if (URLParams.has('puter.domain')) { + domain = URLParams.get('puter.domain') +} + +$(document).ready(function () { + $('#loading').show(); + + // get dev profile + setTimeout(function () { + puter.ui.onLaunchedWithItems(async function (items) { + source_path = items[0].path; + // if source_path is provided, this means that the user is creating a new app/updating an existing app + // by deploying an existing Puter folder. So we create the app and deploy it. + if (source_path) { + // todo if there are no apps, go straight to creating a new app + $('.insta-deploy-modal').get(0).showModal(); + // set item name + $('.insta-deploy-item-name').html(html_encode(items[0].name)); + } + }) + + puter.apps.getDeveloperProfile(async function (dev_profile) { + developer = dev_profile; + if (dev_profile.approved_for_incentive_program && !dev_profile.joined_incentive_program) { + $('#join-incentive-program').show(); + } + + // show earn money c2a only if dev is not approved for incentive program or has already joined + if (!dev_profile.approved_for_incentive_program || dev_profile.joined_incentive_program) { + puter.kv.get('earn-money-c2a-closed').then((value) => { + if (value?.result || value === true || value === "true") + return; + + $('#earn-money').get(0).showModal(); + }); + } + + // get apps + puter.apps.list().then((resp) => { + apps = resp; + + // hide loading + $('#loading').hide(); + + // set apps + if (apps.length > 0) { + if (activeTab === 'apps') { + $('#no-apps-notice').hide(); + $('#app-list').show(); + } + $('.app-card').remove(); + apps.forEach(app => { + $('#app-list-table > tbody').append(generate_app_card(app)); + }); + sort_apps(); + } else { + $('#no-apps-notice').show(); + } + }) + // show payout method tab if dev has joined incentive program + if (dev_profile.joined_incentive_program) { + $('.tab-btn[data-tab="payout-method"]').show(); + $('#payout-method-email').html(dev_profile.paypal); + } + }) + }, 1000); +}); + +function refresh_app_list(show_loading = false) { + if (show_loading) + $('#loading').show(); + // get apps + setTimeout(function () { + puter.apps.list().then((apps_res) => { + $('#loading').hide(); + apps = apps_res; + if (apps.length > 0) { + if (activeTab === 'apps') { + $('#no-apps-notice').hide(); + $('#app-list').show(); + } + $('.app-card').remove(); + apps.forEach(app => { + $('#app-list-table > tbody').append(generate_app_card(app)); + }); + sort_apps(); + } else { + $('#no-apps-notice').show(); + $('#app-list').hide() + } + }) + }, show_loading ? 1000 : 0); +} + +$(document).on('click', '.tab-btn', function (e) { + $('section:not(.sidebar)').hide(); + $('.tab-btn').removeClass('active'); + $(this).addClass('active'); + $('section[data-tab="' + $(this).attr('data-tab') + '"]').show(); + + // ------------------------------ + // Apps tab + // ------------------------------ + if ($(this).attr('data-tab') === 'apps') { + refresh_app_list(); + activeTab = 'apps'; + } + // ------------------------------ + // Payout Method tab + // ------------------------------ + else if ($(this).attr('data-tab') === 'payout-method') { + activeTab = 'payout-method'; + $('#loading').show(); + setTimeout(function () { + puter.apps.getDeveloperProfile(function (dev_profile) { + // show payout method tab if dev has joined incentive program + if (dev_profile.joined_incentive_program) { + $('#payout-method-email').html(dev_profile.paypal); + } + $('#loading').hide(); + if (activeTab === 'payout-method') + $('#tab-payout-method').show(); + }) + }, 1000); + } +}) + +$(document).on('click', '.create-an-app-btn', async function (e) { + let title = await puter.ui.prompt('Please enter a title for your app:', 'My Awesome App'); + + if (title.length > 60) { + puter.ui.alert(`Title cannot be longer than 60.`, [ + { + label: 'Ok', + }, + ]); + // todo go back to create an app prompt and prefill the title input with the title the user entered + return; + } + else if (title) { + create_app(title); + } +}) + +async function create_app(title, source_path = null, items = null) { + // name + let name = slugify(title + '-' + Math.random().toString(36).substring(2), { + lower: true, + strict: true, + }); + + // icon + let icon = await getBase64ImageFromUrl('./img/app.svg'); + + // open the 'Creting new app...' modal + let start_ts = Date.now(); + $('.new-app-modal').get(0).showModal(); + + //---------------------------------------------------- + // Create app + //---------------------------------------------------- + puter.apps.create({ + title: title, + name: name, + indexURL: 'https://dev-center.puter.com/coming-soon.html', + icon: icon, + description: ' ', + maximizeOnStart: false, + background: false, + }) + .then(async (app) => { + let app_dir; + // ---------------------------------------------------- + // Create app directory in AppData + // ---------------------------------------------------- + app_dir = await puter.fs.mkdir( + `/${authUsername}/AppData/${dev_center_uid}/${app.uid}`, + { overwrite: true, recursive: true, rename: false } + ); + // ---------------------------------------------------- + // Create a router for the app with a fresh hostname + // ---------------------------------------------------- + const route = await puter.hosting.create(name, app_dir.path); + + // ---------------------------------------------------- + // Update the app with the new hostname + // ---------------------------------------------------- + puter.apps.update(app.name, { + title: title, + name: name, + indexURL: source_path ? `https://${name}.puter.site` : 'https://dev-center.puter.com/coming-soon.html', + icon: icon, + description: ' ', + maximizeOnStart: false, + background: false, + }).then(async (app) => { + // refresh app list + puter.apps.list().then(async (resp) => { + apps = resp; + // Close the 'Creting new app...' modal + // but make sure it was shown for at least 2 seconds + setTimeout(() => { + // open edit app section + edit_app_section(app.name); + // set drop area if source_path was provided or items were dropped + if (source_path || items) { + $('.drop-area').removeClass('drop-area-hover'); + $('.drop-area').addClass('drop-area-ready-to-deploy'); + } + $('.new-app-modal').get(0).close(); + // deploy app if source_path was provided + if (source_path) { + deploy(app, source_path); + } else if (items) { + deploy(app, items); + } + + }, (Date.now() - start_ts) > 2000 ? 1 : 2000 - (Date.now() - start_ts)); + }) + }).catch(async (err) => { + console.log(err); + }) + // ---------------------------------------------------- + // Create a "shortcut" on the desktop + // ---------------------------------------------------- + puter.fs.upload(new File([], app.title), + `/${authUsername}/Desktop`, + { + name: app.title, + dedupeName: true, + overwrite: false, + appUID: app.uid, + } + ) + }).catch(async (err) => { + $('#create-app-error').show(); + $('#create-app-error').html(err.message); + // scroll to top so that user sees error message + document.body.scrollTop = document.documentElement.scrollTop = 0; + }) +} + +$(document).on('click', '.deploy-btn', function (e) { + deploy(currently_editing_app, dropped_items); +}) + +$(document).on('click', '.edit-app, .got-to-edit-app', function (e) { + const cur_app_name = $(this).attr('data-app-name') + edit_app_section(cur_app_name); +}) + +$(document).on('click', '.delete-app', async function (e) { + let app_uid = $(this).attr('data-app-uid'); + let app_title = $(this).attr('data-app-title'); + let app_name = $(this).attr('data-app-name'); + + // confirm delete + const alert_resp = await puter.ui.alert(`Are you sure you want to premanently delete "${html_encode(app_title)}"?`, + [ + { + label: 'Yes, delete permanently', + value: 'delete', + type: 'danger', + }, + { + label: 'Cancel' + }, + ] + ); + + if (alert_resp === 'delete') { + let init_ts = Date.now(); + $('.deleting-app-modal')?.get(0)?.showModal(); + puter.apps.delete(app_name).then(async (app) => { + setTimeout(() => { + $('.deleting-app-modal')?.get(0)?.close(); + $(`.app-card[data-uid="${app_uid}"]`).fadeOut(200, function name(params) { + $(this).remove(); + if ($(`.app-card`).length === 0) { + $('section:not(.sidebar)').hide(); + $('#no-apps-notice').show(); + } else { + $('section:not(.sidebar)').hide(); + $('#app-list').show(); + } + }); + }, + // make sure the modal was shown for at least 2 seconds + (Date.now() - init_ts) > 2000 ? 1 : 2000 - (Date.now() - init_ts)); + + // get app directory + puter.fs.stat({ + path: `/${authUsername}/AppData/${dev_center_uid}/${app_uid}`, + returnSubdomains: true, + }).then(async (stat) => { + // delete subdomain associated with the app dir + puter.hosting.delete(stat.subdomains[0].subdomain) + // delete app directory + puter.fs.delete( + `/${authUsername}/AppData/${dev_center_uid}/${app_uid}`, + { recursive: true } + ) + }) + }).catch(async (err) => { + setTimeout(() => { + + $('.deleting-app-modal')?.get(0)?.close(); + puter.ui.alert(err?.message, [ + { + label: 'Ok', + }, + ]); + }, + // make sure the modal was shown for at least 2 seconds + (Date.now() - init_ts) > 2000 ? 1 : 2000 - (Date.now() - init_ts)); + }) + } +}) + +// generate app link +function applink(app) { + return `https://${domain}/app/${app.name}`; +} + +//---------------------------------------------------- +// Generate the 'App Settings' section +//---------------------------------------------------- +function generate_edit_app_section(app) { + if(app.result) + app = app.result; + + let h = ``; + h += ` +
+
+ +

${html_encode(app.title)}

+
+ Open + + Add Shortcut to Desktop + + Delete +
+ ${html_encode(applink(app))} +
+ +
+ +
    +
  • Deploy
  • +
  • Settings
  • +
+ +
+
+ New version deployed successfully 🎉× +

Give it a try!

+
+
${drop_area_placeholder}
+ +
+ +
+
+
+
App has been successfully updated.×
+ + + + + + + + + + + + + + +
+ + +
+ +
+ + +
+ +
+ + +
+ + +
+
Change App Icon
+
+ Remove icon + + + + + +

A comma-separated list of file type specifiers. For example if you include .txt, your apps could be opened when a user clicks on a TXT file.

+ + + +
+
+ ` + return h; +} + +async function edit_app_section(cur_app_name) { + $('section:not(.sidebar)').hide(); + $('.tab-btn').removeClass('active'); + $('.tab-btn[data-tab="apps"]').addClass('active'); + + let cur_app = await puter.apps.get(cur_app_name); + currently_editing_app = cur_app; + + // generate edit app section + let edit_app_section_html = generate_edit_app_section(cur_app); + $('#edit-app').html(edit_app_section_html); + $('#edit-app').show(); + + // -------------------------------------------------------- + // Dragster + // -------------------------------------------------------- + let drop_area_content = drop_area_placeholder; + + $('.drop-area').dragster({ + enter: function (dragsterEvent, event) { + drop_area_content = $('.drop-area').html(); + $('.drop-area').addClass('drop-area-hover'); + $('.drop-area').html(drop_area_placeholder); + }, + leave: function (dragsterEvent, event) { + $('.drop-area').html(drop_area_content); + $('.drop-area').removeClass('drop-area-hover'); + }, + drop: async function (dragsterEvent, event) { + const e = event.originalEvent; + e.stopPropagation(); + e.preventDefault(); + + // hide previous success message + $('.deploy-success-msg').fadeOut(); + + // remove hover class + $('.drop-area').removeClass('drop-area-hover'); + + //---------------------------------------------------- + // Puter items dropped + //---------------------------------------------------- + if (e.detail?.items?.length > 0) { + let items = e.detail.items; + + // ---------------------------------------------------- + // one file dropped + // ---------------------------------------------------- + if (items.length === 1 && !items[0].isDirectory) { + if (items[0].name.toLowerCase() === 'index.html') { + dropped_items = items[0].path; + $('.drop-area').removeClass('drop-area-hover'); + $('.drop-area').addClass('drop-area-ready-to-deploy'); + drop_area_content = `

index.html

Ready to deploy 🚀

`; + $('.drop-area').html(drop_area_content); + + // enable deploy button + $('.deploy-btn').removeClass('disabled'); + + } else { + puter.ui.alert(`You need to have an index.html file in your deployment.`, [ + { + label: 'Ok', + }, + ]); + $('.drop-area').removeClass('drop-area-ready-to-deploy'); + $('.deploy-btn').addClass('disabled'); + dropped_items = []; + } + return; + } + // ---------------------------------------------------- + // one directory dropped + // ---------------------------------------------------- + else if (items.length === 1 && items[0].isDirectory) { + let children = await puter.fs.readdir(items[0].path); + // check if index.html exists, if found, deploy entire directory + for (let child of children) { + if (child.name === 'index.html') { + // deploy(currently_editing_app, items[0].path); + dropped_items = items[0].path; + let rootItems = ''; + + if (children.length === 1) + rootItems = children[0].name; + else if (children.length === 2) + rootItems = children[0].name + ', ' + children[1].name; + else if (children.length === 3) + rootItems = children[0].name + ', ' + children[1].name + ', and' + children[1].name; + else if (children.length > 3) + rootItems = children[0].name + ', ' + children[1].name + ', and ' + (children.length - 2) + ' more item' + (children.length - 2 > 1 ? 's' : ''); + + $('.drop-area').removeClass('drop-area-hover'); + $('.drop-area').addClass('drop-area-ready-to-deploy'); + drop_area_content = `

${rootItems}

Ready to deploy 🚀

`; + $('.drop-area').html(drop_area_content); + + // enable deploy button + $('.deploy-btn').removeClass('disabled'); + return; + } + } + + // no index.html in directory + puter.ui.alert(index_missing_error, [ + { + label: 'Ok', + }, + ]); + $('.drop-area').removeClass('drop-area-ready-to-deploy'); + $('.deploy-btn').addClass('disabled'); + dropped_items = []; + } + + return false; + } + + //----------------------------------------------------------------------------- + // Local items dropped + //----------------------------------------------------------------------------- + if (!e.dataTransfer || !e.dataTransfer.items || e.dataTransfer.items.length === 0) + return; + + // get dropped items + dropped_items = await puter.ui.getEntriesFromDataTransferItems(e.dataTransfer.items); + + // generate a flat array of full paths from the dropped items + let paths = []; + for (let item of dropped_items) { + paths.push('/' + (item.fullPath ?? item.filepath)); + } + + // generate a directory tree from the paths + let tree = generateDirTree(paths); + + dropped_items = setRootDirTree(tree, dropped_items); + + // alert if no index.html in root + if (!hasRootIndexHtml(tree)) { + puter.ui.alert(index_missing_error, [ + { + label: 'Ok', + }, + ]); + $('.drop-area').removeClass('drop-area-ready-to-deploy'); + $('.deploy-btn').addClass('disabled'); + dropped_items = []; + return; + } + + // Get all keys (directories and files) in the root + const rootKeys = Object.keys(tree); + + // generate a list of items in the root in the form of a string (e.g. /index.html, /css/style.css) with maximum of 3 items + let rootItems = ''; + + if (rootKeys.length === 1) + rootItems = rootKeys[0]; + else if (rootKeys.length === 2) + rootItems = rootKeys[0] + ', ' + rootKeys[1]; + else if (rootKeys.length === 3) + rootItems = rootKeys[0] + ', ' + rootKeys[1] + ', and' + rootKeys[1]; + else if (rootKeys.length > 3) + rootItems = rootKeys[0] + ', ' + rootKeys[1] + ', and ' + (rootKeys.length - 2) + ' more item' + (rootKeys.length - 2 > 1 ? 's' : ''); + + $('.drop-area').removeClass('drop-area-hover'); + $('.drop-area').addClass('drop-area-ready-to-deploy'); + drop_area_content = `

${rootItems}

Ready to deploy 🚀

`; + $('.drop-area').html(drop_area_content); + + // enable deploy button + $('.deploy-btn').removeClass('disabled'); + + return false; + } + }); + + // Focus on the first input + $('#edit-app-title').focus(); +} + +$('.jip-submit-btn').on('click', async function (e) { + const first_name = $('#jip-first-name').val(); + const last_name = $('#jip-last-name').val(); + const paypal = $('#jip-paypal').val(); + let error; + + if (first_name === '' || last_name === '' || paypal === '') + error = `All fields are required.`; + else if (first_name.length > 100) + error = `First Name cannot be longer than ${100}.`; + else if (last_name.length > 100) + error = `Last Name cannot be longer than ${100}.`; + else if (paypal.length > 100) + error = `Paypal cannot be longer than ${100}.`; + // check if email is valid + else if (!validateEmail(paypal)) + error = `Paypal email must be a valid email address.`; + + // error? + if (error) { + $('#jip-error').show(); + $('#jip-error').html(error); + document.body.scrollTop = document.documentElement.scrollTop = 0; + return; + } + + // disable submit button + $('.jip-submit-btn').prop('disabled', true); + + $.ajax({ + url: puter.APIOrigin + "/jip", + type: 'POST', + async: true, + contentType: "application/json", + data: JSON.stringify({ + first_name: first_name, + last_name: last_name, + paypal: paypal, + }), + headers: { + "Authorization": "Bearer " + puter.authToken + }, + success: function () { + $('#jip-success').show(); + $('#jip-form').hide(); + //enable submit button + $('.jip-submit-btn').prop('disabled', false); + // update dev profile + $('#payout-method-email').html(paypal); + // show payout method tab + $('.tab-btn[data-tab="payout-method"]').show(); + }, + error: function (err) { + $('#jip-error').show(); + $('#jip-error').html(err.message); + // scroll to top so that user sees error message + document.body.scrollTop = document.documentElement.scrollTop = 0; + // enable submit button + $('.jip-submit-btn').prop('disabled', false); + } + }) +}) + +$(document).on('click', '.edit-app-save-btn', async function (e) { + const title = $('#edit-app-title').val(); + const name = $('#edit-app-name').val(); + const index_url = $('#edit-app-index-url').val(); + const description = $('#edit-app-description').val(); + const uid = $('#edit-app-uid').val(); + let filetype_associations = $('#edit-app-filetype-associations').val(); + + let icon; + + let error; + + //validation + if (title === '') + error = `Title is required.`; + else if (title.length > 60) + error = `Title cannot be longer than ${60}.`; + else if (name === '') + error = `Name is required.`; + else if (name.length > 60) + error = `Name cannot be longer than ${60}.`; + else if (index_url === '') + error = `Index URL is required.`; + else if (!name.match(/^[a-zA-Z0-9-_-]+$/)) + error = `Name can only contain letters, numbers, dash (-) and underscore (_).`; + else if (!is_valid_url(index_url)) + error = `Index URL must be a valid url.`; + else if (!index_url.toLowerCase().startsWith('https://') && !index_url.toLowerCase().startsWith('http://')) + error = `Index URL must start with 'https://' or 'http://'.`; + + // download icon from URL + else { + let icon_url = $('#edit-app-icon').attr('data-url'); + let icon_base64 = $('#edit-app-icon').attr('data-base64'); + + if(icon_base64){ + icon = icon_base64; + }else if (icon_url) { + icon = await getBase64ImageFromUrl(icon_url); + let app_max_icon_size = 5 * 1024 * 1024; + if (icon.length > app_max_icon_size) + error = `Icon cannot be larger than ${byte_format(app_max_icon_size)}`; + // make sure icon is an image + else if (!icon.startsWith('data:image/') && !icon.startsWith('data:application/octet-stream')) + error = `Icon must be an image.`; + }else{ + icon = null; + } + } + + // error? + if (error) { + $('#edit-app-error').show(); + $('#edit-app-error').html(error); + document.body.scrollTop = document.documentElement.scrollTop = 0; + return; + } + + // parse filetype_associations + filetype_associations = filetype_associations.split(',').map(element => element.trim()); + // disable submit button + $('.edit-app-save-btn').prop('disabled', true); + + puter.apps.update(currently_editing_app.name, { + title: title, + name: name, + indexURL: index_url, + icon: icon, + description: description, + maximizeOnStart: $('#edit-app-maximize-on-start').is(":checked"), + background: $('#edit-app-background').is(":checked"), + metadata: { + fullpage_on_landing: $('#edit-app-fullpage-on-landing').is(":checked"), + }, + filetypeAssociations: filetype_associations, + }).then(async (app) => { + currently_editing_app = app; + $('#edit-app-error').hide(); + $('#edit-app-success').show(); + document.body.scrollTop = document.documentElement.scrollTop = 0; + // Re-enable submit button + $('.edit-app-save-btn').prop('disabled', false); + // Update open-app-btn + $(`.open-app-btn[data-app-uid="${uid}"]`).attr('data-app-name', app.name); + // Update title + $(`.app-title[data-uid="${uid}"]`).html(html_encode(app.title)); + // Update app link + $(`.app-url[data-uid="${uid}"]`).html(applink(app)); + $(`.app-url[data-uid="${uid}"]`).attr('href', applink(app)); + // Update icons + $(`.app-icon[data-uid="${uid}"]`).attr('src', html_encode(app.icon ? app.icon : './img/app.svg')); + $(`[data-app-uid="${uid}"]`).attr('data-app-title', html_encode(app.title)); + $(`[data-app-name="${uid}"]`).attr('data-app-name', html_encode(app.name)); + }).catch((err) => { + + $('#edit-app-success').hide(); + $('#edit-app-error').show(); + $('#edit-app-error').html(err.error?.message); + // scroll to top so that user sees error message + document.body.scrollTop = document.documentElement.scrollTop = 0; + // re-enable submit button + $('.edit-app-save-btn').prop('disabled', false); + }) +}) + +$(document).on('click', '.open-app-btn', async function (e) { + puter.ui.launchApp($(this).attr('data-app-name')) +}) + +$('#earn-money-c2a-close').click(async function (e) { + $('#earn-money').get(0).close(); + puter.kv.set('earn-money-c2a-closed', 'true') +}) + +$('#earn-money::backdrop').click(async function (e) { + alert(); + $('#earn-money').get(0).close(); + puter.kv.set('earn-money-c2a-closed', 'true') +}) + + + +$(document).on('click', '.edit-app-open-app-btn', async function (e) { + puter.ui.launchApp($(this).attr('data-app-name')) +}) + +$(document).on('click', '.delete-app-settings', async function (e) { + let app_uid = $(this).attr('data-app-uid'); + let app_name = $(this).attr('data-app-name'); + let app_title = $(this).attr('data-app-title'); + + // confirm delete + const alert_resp = await puter.ui.alert(`Are you sure you want to premanently delete "${html_encode(app_title)}"?`, + [ + { + label: 'Yes, delete permanently', + value: 'delete', + type: 'danger', + }, + { + label: 'Cancel' + }, + ] + ); + + if (alert_resp === 'delete') { + let init_ts = Date.now(); + $('.deleting-app-modal')?.get(0)?.showModal(); + puter.apps.delete(app_name).then(async (app) => { + setTimeout(() => { + $('.deleting-app-modal')?.get(0)?.close(); + $('.back-to-main-btn').trigger('click'); + }, + // make sure the modal was shown for at least 2 seconds + (Date.now() - init_ts) > 2000 ? 1 : 2000 - (Date.now() - init_ts)); + // get app directory + puter.fs.stat({ + path: `/${authUsername}/AppData/${dev_center_uid}/${app_uid}`, + returnSubdomains: true, + }).then(async (stat) => { + // delete subdomain associated with the app dir + puter.hosting.delete(stat.subdomains[0].subdomain) + // delete app directory + puter.fs.delete( + `/${authUsername}/AppData/${dev_center_uid}/${app_uid}`, + { recursive: true } + ) + }) + }).catch(async (err) => { + setTimeout(() => { + $('.deleting-app-modal')?.get(0)?.close(); + puter.ui.alert(err?.message, [ + { + label: 'Ok', + }, + ]); + }, + (Date.now() - init_ts) > 2000 ? 1 : (2000 - (Date.now() - init_ts))); + }) + } +}) + +$(document).on('click', '.edit-app', async function (e) { + $('#edit-app-uid').val($(this).attr('data-app-uid')); +}) + +$(document).on('click', '.back-to-main-btn', function (e) { + $('section:not(.sidebar)').hide(); + $('.tab-btn').removeClass('active'); + $('.tab-btn[data-tab="apps"]').addClass('active'); + + // get apps + $('#loading').show(); + setTimeout(function () { + puter.apps.list().then((apps_res) => { + $('#loading').hide(); + apps = apps_res; + if (apps.length > 0) { + if (activeTab === 'apps') { + $('#no-apps-notice').hide(); + $('#app-list').show(); + } + $('.app-card').remove(); + apps.forEach(app => { + $('#app-list-table > tbody').append(generate_app_card(app)); + }); + sort_apps() + } else + $('#no-apps-notice').show(); + }) + }, 1000); +}) + +// https://stackoverflow.com/a/43467144/1764493 +function is_valid_url(string) { + let url; + + try { + url = new URL(string); + } catch (_) { + return false; + } + + return url.protocol === "http:" || url.protocol === "https:"; +} + +$(document).on('click', '#edit-app-icon-delete', async function (e) { + $('#edit-app-icon').css('background-image', ``); + $('#edit-app-icon').removeAttr('data-url'); + $('#edit-app-icon').removeAttr('data-base64'); + $('#edit-app-icon-delete').hide(); +}) + +$(document).on('click', '#edit-app-icon', async function (e) { + const res2 = await puter.ui.showOpenFilePicker({ + accept: "image/*", + }); + + const icon = await puter.fs.read(res2.path); + // convert blob to base64 + const reader = new FileReader(); + reader.readAsDataURL(icon); + + reader.onloadend = function () { + let image = reader.result; + // Get file extension + let fileExtension = res2.name.split('.').pop(); + // Get MIME type + let mimeType = getMimeType(fileExtension); + // Replace MIME type in the data URL + image = image.replace('data:application/octet-stream;base64', `data:image/${mimeType};base64`); + + $('#edit-app-icon').css('background-image', `url(${image})`); + $('#edit-app-icon').attr('data-base64', image); + $('#edit-app-icon-delete').show(); + } +}) + +async function getBase64ImageFromUrl(imageUrl) { + var res = await fetch(imageUrl); + var blob = await res.blob(); + + return new Promise((resolve, reject) => { + var reader = new FileReader(); + reader.addEventListener("load", function () { + resolve(reader.result); + }, false); + + reader.onerror = () => { + return reject(this); + }; + reader.readAsDataURL(blob); + }) +} + +function generate_app_card(app) { + let h = ``; + h += ``; + // check box + h += ``; + h += `
`; + h += ``; + h += `
`; + h += ``; + // App info + h += ``; + // Icon + h += `
`; + // Info + h += `
`; + // Title + h += `

${html_encode(app.title)}

`; + h += `${html_encode(applink(app))}`; + + // toolbar + h += `
`; + + // Open + h += `Open`; + h += ``; + + // Settings + h += `Settings`; + h += ``; + + // add to desktop + h += `Add Shortcut to Desktop` + h += ``; + + // Delete + h += `Delete`; + h += `
`; + h += ``; + + // users count + h += ``; + h += `${number_format((app.stats.referral_count ?? 0) + app.stats.user_count)}`; + h += ``; + + // opens + h += ``; + h += `${number_format(app.stats.open_count)}`; + h += ``; + + // Created + h += ``; + h += `${moment(app.created_at).format('MMM Do, YYYY')}`; + h += ``; + + h += ``; + // // Open App + // h += ``; + // // Settings + // h += ``; + // "Approved for incentive program" + if (app.approved_for_incentive_program) + h += `✔ Incentive Program`; + h += ``; + h += ``; + return h; +} + + +/** + * Formats a binary-byte integer into the human-readable form with units. + * + * @param {integer} bytes + * @returns + */ +window.byte_format = (bytes) => { + const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; + if (bytes === 0) return '0 Byte'; + const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); + return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i]; +}; + +function validateEmail(email) { + var re = /\S+@\S+\.\S+/; + return re.test(email); +} + +/** + * Formats a number with grouped thousands. + * + * @param {number|string} number - The number to be formatted. If a string is provided, it must only contain numerical characters, plus and minus signs, and the letter 'E' or 'e' (for scientific notation). + * @param {number} decimals - The number of decimal points. If a non-finite number is provided, it defaults to 0. + * @param {string} [dec_point='.'] - The character used for the decimal point. Defaults to '.' if not provided. + * @param {string} [thousands_sep=','] - The character used for the thousands separator. Defaults to ',' if not provided. + * @returns {string} The formatted number with grouped thousands, using the specified decimal point and thousands separator characters. + * @throws {TypeError} If the `number` parameter cannot be converted to a finite number, or if the `decimals` parameter is non-finite and cannot be converted to an absolute number. + */ +function number_format(number, decimals, dec_point, thousands_sep) { + // Strip all characters but numerical ones. + number = (number + '').replace(/[^0-9+\-Ee.]/g, ''); + var n = !isFinite(+number) ? 0 : +number, + prec = !isFinite(+decimals) ? 0 : Math.abs(decimals), + sep = (typeof thousands_sep === 'undefined') ? ',' : thousands_sep, + dec = (typeof dec_point === 'undefined') ? '.' : dec_point, + s = '', + toFixedFix = function (n, prec) { + var k = Math.pow(10, prec); + return '' + Math.round(n * k) / k; + }; + // Fix for IE parseFloat(0.55).toFixed(0) = 0; + s = (prec ? toFixedFix(n, prec) : '' + Math.round(n)).split('.'); + if (s[0].length > 3) { + s[0] = s[0].replace(/\B(?=(?:\d{3})+(?!\d))/g, sep); + } + if ((s[1] || '').length < prec) { + s[1] = s[1] || ''; + s[1] += new Array(prec - s[1].length + 1).join('0'); + } + return s.join(dec); +} + +$(document).on('click', '.close-message', function () { + $($(this).attr('data-target')).fadeOut(); +}); + +$('th.sort').on('click', function (e) { + // determine what column to sort by + const sortByColumn = $(this).attr('data-column'); + + // toggle sort direction + if (sortByColumn === sortBy) { + if (sortDirection === 'asc') + sortDirection = 'desc'; + else + sortDirection = 'asc'; + } + else { + sortBy = sortByColumn; + sortDirection = 'desc'; + } + + // update arrow + $('.sort-arrow').css('display', 'none'); + $('#app-list-table').find('th').removeClass('sorted'); + $(this).find('.sort-arrow-' + sortDirection).css('display', 'inline'); + $(this).addClass('sorted'); + + sort_apps(); +}); + +function sort_apps() { + let sorted_apps; + + // sort + if (sortDirection === 'asc') + sorted_apps = apps.sort((a, b) => a[sortBy] > b[sortBy] ? 1 : -1); + else + sorted_apps = apps.sort((a, b) => a[sortBy] < b[sortBy] ? 1 : -1); + + // refresh app list + $('.app-card').remove(); + sorted_apps.forEach(app => { + $('#app-list-table > tbody').append(generate_app_card(app)); + }); + + // show apps that match search_query and hide apps that don't + if (search_query) { + // show apps that match search_query and hide apps that don't + apps.forEach((app) => { + if (app.title.toLowerCase().includes(search_query.toLowerCase())) { + $(`.app-card[data-name="${html_encode(app.name)}"]`).show(); + } else { + $(`.app-card[data-name="${html_encode(app.name)}"]`).hide(); + } + }) + } +} + +window.deploy = async function (app, items) { + let appdata_dir, current_app_dir; + + // disable deploy button + $('.deploy-btn').addClass('disabled'); + + // change drop area text + $('.drop-area').html(deploying_spinner + '
Deploying (0%)
'); + + if (typeof items === 'string' && (items.startsWith('/') || items.startsWith('~'))) { + $('.drop-area').removeClass('drop-area-hover'); + $('.drop-area').addClass('drop-area-ready-to-deploy'); + } + + // -------------------------------------------------------------------- + // Get current directory, we need to delete the existing hostname + // later on + // -------------------------------------------------------------------- + try { + current_app_dir = await puter.fs.stat({ + path: `/${authUsername}/AppData/${dev_center_uid}/${app.uid ?? app.uuid}`, + returnSubdomains: true + }); + } catch (err) { + console.log(err); + } + + // -------------------------------------------------------------------- + // Delete existing hostnames attached to this app directory if they exist + // -------------------------------------------------------------------- + if (current_app_dir?.subdomains.length > 0) { + for (let subdomain of current_app_dir?.subdomains) { + puter.hosting.delete(subdomain.subdomain) + } + } + + // -------------------------------------------------------------------- + // Delete existing app directory + // -------------------------------------------------------------------- + try { + await puter.fs.delete(current_app_dir.path) + } catch (err) { + console.log(err); + } + + // -------------------------------------------------------------------- + // Make an app directory under AppData + // if the directory already exists, it should be overwritten + // -------------------------------------------------------------------- + try { + appdata_dir = await puter.fs.mkdir( + // path + `/${authUsername}/AppData/${dev_center_uid}/${app.uid ?? app.uuid}`, + // options + { overwrite: true, recursive: true, rename: false } + ) + } catch (err) { + console.log(err); + } + + // -------------------------------------------------------------------- + // (A) Puter Items: If 'items' is a string and starts with /, it's a path to a Puter item + // -------------------------------------------------------------------- + if (typeof items === 'string' && (items.startsWith('/') || items.startsWith('~'))) { + // perform stat on 'items' + const stat = await puter.fs.stat(items); + + // Puter Directory + // Perform readdir on 'items' + // todo there is apparently a bug in Puter where sometimes path is literally missing from the items + // returned by readdir. This is the 'path' that readdit didn't return a path for: "~/Desktop/particle-clicker-master" + if (stat.is_dir) { + const files = await puter.fs.readdir(items); + // copy the 'files' to the app directory + if (files.length > 0) { + for (let file of files) { + // perform copy + await puter.fs.copy( + file.path, + appdata_dir.path, + { overwrite: true } + ); + // update progress + $('.deploy-percent').text(`(${Math.round((files.indexOf(file) / files.length) * 100)}%)`); + } + } + } + // Puter File + else { + // copy the 'files' to the app directory + await puter.fs.copy( + items, + appdata_dir.path, + { overwrite: true } + ); + } + + // generate new hostname with a random suffix + let hostname = `${currently_editing_app.name}-${(Math.random() + 1).toString(36).substring(7)}`; + + // -------------------------------------------------------------------- + // Create a router for the app with the fresh hostname + // we change hostname every time to prevent caching issues + // -------------------------------------------------------------------- + puter.hosting.create(hostname, appdata_dir.path).then(async (res) => { + // TODO this endpoint needs to be able to update only the specified fields + puter.apps.update(currently_editing_app.name, { + indexURL: `https://${hostname}.puter.site`, + title: currently_editing_app.title, + name: currently_editing_app.name, + icon: currently_editing_app.icon, + description: currently_editing_app.description, + maximizeOnStart: currently_editing_app.maximize_on_start, + background: currently_editing_app.background, + filetypeAssociations: currently_editing_app.filetype_associations, + }) + // set the 'Index URL' field for the 'Settings' tab + $('#edit-app-index-url').val(`https://${hostname}.puter.site`); + // show success message + $('.deploy-success-msg').show(); + // reset drop area + reset_drop_area(); + }) + } + + // -------------------------------------------------------------------- + // (B) Local Items: Upload new deploy + // -------------------------------------------------------------------- + else { + puter.fs.upload( + items, + `/${authUsername}/AppData/${dev_center_uid}/${currently_editing_app.uid}`, + { + dedupeName: false, + overwrite: false, + parsedDataTransferItems: true, + createMissingAncestors: true, + progress: function (operation_id, op_progress) { + $('.deploy-percent').text(`(${op_progress}%)`); + }, + }).then(async (uploaded) => { + // new hostname + let hostname = `${currently_editing_app.name}-${(Math.random() + 1).toString(36).substring(7)}`; + + // ---------------------------------------- + // Create a router for the app with a fresh hostname + // we change hostname every time to prevent caching issues + // ---------------------------------------- + puter.hosting.create(hostname, appdata_dir.path).then(async (res) => { + // TODO this endpoint needs to be able to update only the specified fields + puter.apps.update(currently_editing_app.name, { + indexURL: `https://${hostname}.puter.site`, + title: currently_editing_app.title, + name: currently_editing_app.name, + icon: currently_editing_app.icon, + description: currently_editing_app.description, + maximizeOnStart: currently_editing_app.maximize_on_start, + background: currently_editing_app.background, + filetypeAssociations: currently_editing_app.filetype_associations, + }) + // set the 'Index URL' field for the 'Settings' tab + $('#edit-app-index-url').val(`https://${hostname}.puter.site`); + // show success message + $('.deploy-success-msg').show(); + // reset drop area + reset_drop_area() + }) + }) + } +} + +$(document).on('click', '.section-tab-btn', function (e) { + // hide all tabs + $('.section-tab').hide(); + // show section + $('.section-tab[data-tab="' + $(this).attr('data-tab') + '"]').show(); + // remove active class from all tab buttons + $('.section-tab-btn').removeClass('active'); + // add active class to clicked tab button + $(this).addClass('active'); +}) + +function generateDirTree(paths) { + const root = {}; + + for (let path of paths) { + let parts = path.split('/'); + let currentNode = root; + for (let part of parts) { + if (!part) continue; // skip empty parts, especially leading one + if (!currentNode[part]) { + currentNode[part] = {}; + } + currentNode = currentNode[part]; + } + } + + return root; +} + +function setRootDirTree(tree, items) { + // Get all keys (directories and files) in the root + const rootKeys = Object.keys(tree); + + // If there's only one object in the root, check if it's non-empty and return it + if (rootKeys.length === 1 && typeof tree[rootKeys[0]] === 'object' && Object.keys(tree[rootKeys[0]]).length > 0) { + let newItems = []; + for (let item of items) { + if (item.fullPath) + item.finalPath = item.fullPath.replace(rootKeys[0], ''); + else if (item.path) + item.path = item.path.replace(rootKeys[0], ''); + else + item.filepath = item.filepath.replace(rootKeys[0], ''); + + newItems.push(item); + } + return newItems; + } else { + return items; + } +} + +function hasRootIndexHtml(tree) { + // Check if index.html exists in the root + if (tree['index.html']) { + return true; + } + + // Get all keys (directories and files) in the root + const rootKeys = Object.keys(tree); + + // If there's only one directory in the root, check if index.html exists in that directory + if (rootKeys.length === 1 && typeof tree[rootKeys[0]] === 'object' && tree[rootKeys[0]]['index.html']) { + return true; + } + + return false; +} + +$(document).on('click', '.close-success-msg', function (e) { + $(this).closest('div').fadeOut(); +}) + +$(document).on('click', '.open-app', function (e) { + puter.ui.launchApp($(this).attr('data-app-name')); +}) + +$(document).on('click', '.insta-deploy-to-new-app', async function (e) { + $('.insta-deploy-modal').get(0).close(); + let title = await puter.ui.prompt('Please enter a title for your app:', 'My Awesome App'); + + if (title.length > 60) { + puter.ui.alert(`Title cannot be longer than 60.`, [ + { + label: 'Ok', + }, + ]); + // todo go back to create an app prompt and prefill the title input with the title the user entered + $('.insta-deploy-modal').get(0).showModal(); + } + else if (title) { + if (source_path) { + create_app(title, source_path); + source_path = null; + } else { + create_app(title, null, dropped_items); + dropped_items = null; + } + } else + $('.insta-deploy-modal').get(0).showModal(); + + return; + +}) + +$(document).on('click', '.insta-deploy-to-existing-app', function (e) { + $('.insta-deploy-modal').get(0).close(); + $('.insta-deploy-existing-app-select').get(0).showModal(); + $('.insta-deploy-existing-app-list').html(`
${loading_spinner}
`); + puter.apps.list().then((apps) => { + setTimeout(() => { + $('.insta-deploy-existing-app-list').html(''); + if (apps.length === 0) + $('.insta-deploy-existing-app-list').html(` +
+ + You have no existing apps. +
+ `); + else { + for (let app of apps) { + $('.insta-deploy-existing-app-list').append( + `
+ + ${html_encode(app.title)} +
+ ${number_format((app.stats.referral_count ?? 0) + app.stats.user_count)} + ${number_format(app.stats.open_count)} +
+
` + ); + } + } + }, 500); + }) + + // todo reset .insta-deploy-existing-app-list on close +}) + +$(document).on('click', '.insta-deploy-app-selector', function (e) { + $('.insta-deploy-app-selector').removeClass('active'); + $(this).addClass('active'); + + // enable deploy button + $('.insta-deploy-existing-app-deploy-btn').removeClass('disabled'); +}) + +$(document).on('click', '.insta-deploy-existing-app-deploy-btn', function (e) { + $('.insta-deploy-existing-app-deploy-btn').addClass('disabled'); + $('.insta-deploy-existing-app-select')?.get(0)?.close(); + // load the 'App Settings' section + edit_app_section($('.insta-deploy-app-selector.active').attr('data-name')); + + $('.drop-area').removeClass('drop-area-hover'); + $('.drop-area').addClass('drop-area-ready-to-deploy'); + let drop_area_content = `

Ready to deploy 🚀

`; + $('.drop-area').html(drop_area_content); + + // deploy + deploy({ uid: $(e.target).attr('data-uid') }, source_path ?? dropped_items); + $('.insta-deploy-existing-app-list').html(''); +}) + +$(document).on('click', '.insta-deploy-cancel', function (e) { + $(this).closest('dialog')?.get(0)?.close(); +}) +$(document).on('click', '.insta-deploy-existing-app-back', function (e) { + $('.insta-deploy-existing-app-select')?.get(0)?.close(); + $('.insta-deploy-modal')?.get(0)?.showModal(); + // disable deploy button + $('.insta-deploy-existing-app-deploy-btn').addClass('disabled'); + + // todo disable the 'an existing app' option if there are no existing apps +}) + + +$(document).on('click', '.add-app-to-desktop', function (e) { + let app_title = $(this).attr('data-app-title'); + let app_uid = $(this).attr('data-app-uid'); + + puter.fs.upload( + new File([], app_title), + `/${authUsername}/Desktop`, + { + name: app_title, + dedupeName: true, + overwrite: false, + appUID: app_uid, + }).then(async (uploaded) => { + puter.ui.alert(`"${app_title}" shortcut has been added to your desktop.`, [ + { + label: 'Ok', + type: 'primary', + }, + ], { + type: 'success', + }); + }) + +}) + +function reset_drop_area() { + dropped_items = null; + $('.drop-area').html(drop_area_placeholder); + $('.drop-area').removeClass('drop-area-ready-to-deploy'); + $('.deploy-btn').addClass('disabled'); +} + +$('body').on('dragover', function (event) { + // skip if the user is dragging something over the drop area + if ($(event.target).hasClass('drop-area')) + return; + + event.preventDefault(); // Prevent the default behavior + event.stopPropagation(); // Stop the event from propagating +}); + +// Developers can drop items anywhere on the page to deploy them +$('body').on('drop', async function (event) { + // skip if the user is dragging something over the drop area + if ($(event.target).hasClass('drop-area')) + return; + + // prevent default behavior + event.preventDefault(); + event.stopPropagation(); + + // retrieve puter items from the event + if (event.detail?.items?.length > 0) { + dropped_items = event.detail.items; + source_path = dropped_items[0].path; + // by deploying an existing Puter folder. So we create the app and deploy it. + if (source_path) { + // todo if there are no apps, go straight to creating a new app + $('.insta-deploy-modal').get(0).showModal(); + // set item name + $('.insta-deploy-item-name').html(html_encode(dropped_items[0].name)); + } + } + //----------------------------------------------------------------------------- + // Local items dropped + //----------------------------------------------------------------------------- + const e = event.originalEvent; + if (!e.dataTransfer || !e.dataTransfer.items || e.dataTransfer.items.length === 0) + return; + + // Get dropped items + dropped_items = await puter.ui.getEntriesFromDataTransferItems(e.dataTransfer.items); + + // Generate a flat array of full paths from the dropped items + let paths = []; + for (let item of dropped_items) { + paths.push('/' + (item.fullPath ?? item.filepath)); + } + + // Generate a directory tree from the paths + let tree = generateDirTree(paths); + + dropped_items = setRootDirTree(tree, dropped_items); + + // Alert if no index.html in root + if (!hasRootIndexHtml(tree)) { + puter.ui.alert(index_missing_error, [ + { + label: 'Ok', + }, + ]); + $('.drop-area').removeClass('drop-area-ready-to-deploy'); + $('.deploy-btn').addClass('disabled'); + dropped_items = []; + return; + } + + // Get all keys (directories and files) in the root + const rootKeys = Object.keys(tree); + + // Generate a list of items in the root in the form of a string (e.g. /index.html, /css/style.css) with maximum of 3 items + let rootItems = ''; + + if (rootKeys.length === 1) + rootItems = rootKeys[0]; + else if (rootKeys.length === 2) + rootItems = rootKeys[0] + ', ' + rootKeys[1]; + else if (rootKeys.length === 3) + rootItems = rootKeys[0] + ', ' + rootKeys[1] + ', and' + rootKeys[1]; + else if (rootKeys.length > 3) + rootItems = rootKeys[0] + ', ' + rootKeys[1] + ', and ' + (rootKeys.length - 2) + ' more item' + (rootKeys.length - 2 > 1 ? 's' : ''); + + // Show insta-deploy modal + $('.insta-deploy-modal').get(0)?.showModal(); + + // Set item name + $('.insta-deploy-item-name').html(html_encode(rootItems)); +}); + +$('.insta-deploy-existing-app-select').on('close', function (e) { + $('.insta-deploy-existing-app-list').html(''); +}) + +$('.refresh-app-list').on('click', function (e) { + $('.loading-modal').get(0)?.showModal(); + + puter.apps.list().then((resp) => { + setTimeout(() => { + apps = resp; + + $('.app-card').remove(); + apps.forEach(app => { + $('#app-list-table > tbody').append(generate_app_card(app)); + }); + + // preserve search query + if (search_query) { + // show apps that match search_query and hide apps that don't + apps.forEach((app) => { + if (app.title.toLowerCase().includes(search_query.toLowerCase())) { + $(`.app-card[data-name="${app.name}"]`).show(); + } else { + $(`.app-card[data-name="${app.name}"]`).hide(); + } + }) + } + + // preserve sort + sort_apps(); + + $('.loading-modal').get(0).close(); + }, 1000); + }) +}) + +$(document).on('click', '.search', function (e) { + e.stopPropagation(); + e.preventDefault(); + // don't let click bubble up to window + e.stopImmediatePropagation(); +}) + +$(document).on('input change keyup keypress keydown paste cut', '.search', function (e) { + // search apps for query + search_query = $(this).val().toLowerCase(); + if (search_query === '') { + // hide 'clear search' button + $('.search-clear').hide(); + // show all apps again + $(`.app-card`).show(); + } else { + // show 'clear search' button + $('.search-clear').show(); + // show apps that match search_query and hide apps that don't + apps.forEach((app) => { + if (app.title.toLowerCase().includes(search_query.toLowerCase())) { + $(`.app-card[data-name="${app.name}"]`).show(); + } else { + $(`.app-card[data-name="${app.name}"]`).hide(); + } + }) + } +}) + +$(document).on('click', '.search-clear', function (e) { + $('.search').val(''); + $('.search').trigger('change'); + $('.search').focus(); + search_query = ''; +}) + +$(document).on('change', '.app-checkbox', function (e) { + // determine if select-all checkbox should be checked, indeterminate, or unchecked + if ($('.app-checkbox:checked').length === $('.app-checkbox').length) { + $('.select-all-apps').prop('indeterminate', false); + $('.select-all-apps').prop('checked', true); + } else if ($('.app-checkbox:checked').length > 0) { + $('.select-all-apps').prop('indeterminate', true); + $('.select-all-apps').prop('checked', false); + } + else { + $('.select-all-apps').prop('indeterminate', false); + $('.select-all-apps').prop('checked', false); + } + + // activate row + if ($(this).is(':checked')) + $(this).closest('tr').addClass('active'); + else + $(this).closest('tr').removeClass('active'); + + // enable delete button if at least one checkbox is checked + if ($('.app-checkbox:checked').length > 0) + $('.delete-apps-btn').removeClass('disabled'); + else + $('.delete-apps-btn').addClass('disabled'); + +}) + +$(document).on('click', '.delete-apps-btn', async function (e) { + // show confirmation alert + let resp = await puter.ui.alert(`Are you sure you want to delete the selected apps?`, [ + { + label: 'Delete', + type: 'danger', + value: 'delete', + }, + { + label: 'Cancel', + }, + ], { + type: 'warning', + }); + + if (resp === 'delete') { + // disable delete button + $('.delete-apps-btn').addClass('disabled'); + + // show 'deleting' modal + $('.deleting-app-modal')?.get(0)?.showModal(); + + let start_ts = Date.now(); + const apps = $('.app-checkbox:checked').toArray(); + + // delete all checked apps + for (let app of apps) { + // get app uid + const app_uid = $(app).attr('data-app-uid'); + const app_name = $(app).attr('data-app-name'); + + // delete app + await puter.apps.delete(app_name) + + // remove app card + $(`.app-card[data-uid="${app_uid}"]`).fadeOut(200, function name(params) { + $(this).remove(); + if ($(`.app-card`).length === 0) { + $('section:not(.sidebar)').hide(); + $('#no-apps-notice').show(); + } else { + $('section:not(.sidebar)').hide(); + $('#app-list').show(); + } + }); + + try{ + // get app directory + const stat = await puter.fs.stat({ + path: `/${authUsername}/AppData/${dev_center_uid}/${app_uid}`, + returnSubdomains: true + }); + // delete subdomain associated with the app directory + if(stat?.subdomains[0]?.subdomain){ + await puter.hosting.delete(stat.subdomains[0].subdomain) + } + // delete app directory + await puter.fs.delete( + `/${authUsername}/AppData/${dev_center_uid}/${app_uid}`, + { recursive: true } + ) + } catch(err) { + console.log(err); + } + } + + // close 'deleting' modal + setTimeout(() => { + $('.deleting-app-modal')?.get(0)?.close(); + // uncheck all checkboxes + $('.app-checkbox').prop('checked', false); + // disable delete button + $('.delete-apps-btn').addClass('disabled'); + // reset the 'select all' checkbox + $('.select-all-apps').prop('indeterminate', false); + $('.select-all-apps').prop('checked', false); + }, (start_ts - Date.now()) > 500 ? 0 : 500); + } +}) + +$(document).on('change', '.select-all-apps', function (e) { + if ($(this).is(':checked')) { + $('.app-checkbox').prop('checked', true); + $('.app-card').addClass('active'); + $('.delete-apps-btn').removeClass('disabled'); + } else { + $('.app-checkbox').prop('checked', false); + $('.app-card').removeClass('active'); + $('.delete-apps-btn').addClass('disabled'); + } +}) + +// Function to map file extensions to MIME types +function getMimeType(extension) { + const mimeTypes = { + jpg: 'jpeg', + jpeg: 'jpeg', + png: 'png', + gif: 'gif', + bmp: 'bmp', + webp: 'webp', + svg: 'svg+xml', + tiff: 'tiff', + ico: 'vnd.microsoft.icon' + }; + + return mimeTypes[extension.toLowerCase()] || 'octet-stream'; +} \ No newline at end of file diff --git a/src/dev-center/js/html-entities.js b/src/dev-center/js/html-entities.js new file mode 100644 index 0000000000..c233cb01ee --- /dev/null +++ b/src/dev-center/js/html-entities.js @@ -0,0 +1 @@ +(()=>{"use strict";var r,e={563:function(r,e,a){var t=this&&this.__assign||function(){return(t=Object.assign||function(r){for(var e,a=1,t=arguments.length;a'"&]/g,nonAscii:/(?:[<>'"&\u0080-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/g,nonAsciiPrintable:/(?:[<>'"&\x01-\x08\x11-\x15\x17-\x1F\x7f-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/g,extensive:/(?:[\x01-\x0c\x0e-\x1f\x21-\x2c\x2e-\x2f\x3a-\x40\x5b-\x60\x7b-\x7d\x7f-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/g},n={mode:"specialChars",level:"all",numeric:"decimal"};e.encode=function(r,e){var a=void 0===(u=(c=void 0===e?n:e).mode)?"specialChars":u,t=void 0===(m=c.numeric)?"decimal":m,o=c.level;if(!r)return"";var c,u,p=i[a],d=s[void 0===o?"all":o].characters,g="hexadecimal"===t;if(p.lastIndex=0,c=p.exec(r)){u="";var m=0;do{m!==c.index&&(u+=r.substring(m,c.index));var f=d[o=c[0]];if(!f){var h=o.length>1?l.getCodePoint(o,0):o.charCodeAt(0);f=(g?"&#x"+h.toString(16):"&#"+h)+";"}u+=f,m=c.index+o.length}while(c=p.exec(r));m!==r.length&&(u+=r.substring(m))}else u=r;return u};var u={scope:"body",level:"all"},p=/&(?:#\d+|#[xX][\da-fA-F]+|[0-9a-zA-Z]+);/g,d=/&(?:#\d+|#[xX][\da-fA-F]+|[0-9a-zA-Z]+)[;=]?/g,g={xml:{strict:p,attribute:d,body:o.bodyRegExps.xml},html4:{strict:p,attribute:d,body:o.bodyRegExps.html4},html5:{strict:p,attribute:d,body:o.bodyRegExps.html5}},m=t(t({},g),{all:g.html5}),f=String.fromCharCode,h=f(65533),b={level:"all"};e.decodeEntity=function(r,e){var a=void 0===(t=(void 0===e?b:e).level)?"all":t;if(!r)return"";var t=r,o=(r[r.length-1],s[a].entities[r]);if(o)t=o;else if("&"===r[0]&&"#"===r[1]){var i=r[2],n="x"==i||"X"==i?parseInt(r.substr(3),16):parseInt(r.substr(2));t=n>=1114111?h:n>65535?l.fromCodePoint(n):f(c.numericUnicodeMap[n]||n)}return t},e.decode=function(r,e){var a=void 0===e?u:e,t=a.level,o=void 0===t?"all":t,i=a.scope,n=void 0===i?"xml"===o?"strict":"body":i;if(!r)return"";var p=m[o][n],d=s[o].entities,g="attribute"===n,b="strict"===n;p.lastIndex=0;var v,q=p.exec(r);if(q){v="";var y=0;do{y!==q.index&&(v+=r.substring(y,q.index));var w=q[0],x=w,A=w[w.length-1];if(g&&"="===A)x=w;else if(b&&";"!==A)x=w;else{var E=d[w];if(E)x=E;else if("&"===w[0]&&"#"===w[1]){var D=w[2],k="x"==D||"X"==D?parseInt(w.substr(3),16):parseInt(w.substr(2));x=k>=1114111?h:k>65535?l.fromCodePoint(k):f(c.numericUnicodeMap[k]||k)}}v+=x,y=q.index+w.length}while(q=p.exec(r));y!==r.length&&(v+=r.substring(y))}else v=r;return v}},81:(r,e)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.bodyRegExps={xml:/&(?:#\d+|#[xX][\da-fA-F]+|[0-9a-zA-Z]+);?/g,html4:/&(?:nbsp|iexcl|cent|pound|curren|yen|brvbar|sect|uml|copy|ordf|laquo|not|shy|reg|macr|deg|plusmn|sup2|sup3|acute|micro|para|middot|cedil|sup1|ordm|raquo|frac14|frac12|frac34|iquest|Agrave|Aacute|Acirc|Atilde|Auml|Aring|AElig|Ccedil|Egrave|Eacute|Ecirc|Euml|Igrave|Iacute|Icirc|Iuml|ETH|Ntilde|Ograve|Oacute|Ocirc|Otilde|Ouml|times|Oslash|Ugrave|Uacute|Ucirc|Uuml|Yacute|THORN|szlig|agrave|aacute|acirc|atilde|auml|aring|aelig|ccedil|egrave|eacute|ecirc|euml|igrave|iacute|icirc|iuml|eth|ntilde|ograve|oacute|ocirc|otilde|ouml|divide|oslash|ugrave|uacute|ucirc|uuml|yacute|thorn|yuml|quot|amp|lt|gt|#\d+|#[xX][\da-fA-F]+|[0-9a-zA-Z]+);?/g,html5:/&(?:AElig|AMP|Aacute|Acirc|Agrave|Aring|Atilde|Auml|COPY|Ccedil|ETH|Eacute|Ecirc|Egrave|Euml|GT|Iacute|Icirc|Igrave|Iuml|LT|Ntilde|Oacute|Ocirc|Ograve|Oslash|Otilde|Ouml|QUOT|REG|THORN|Uacute|Ucirc|Ugrave|Uuml|Yacute|aacute|acirc|acute|aelig|agrave|amp|aring|atilde|auml|brvbar|ccedil|cedil|cent|copy|curren|deg|divide|eacute|ecirc|egrave|eth|euml|frac12|frac14|frac34|gt|iacute|icirc|iexcl|igrave|iquest|iuml|laquo|lt|macr|micro|middot|nbsp|not|ntilde|oacute|ocirc|ograve|ordf|ordm|oslash|otilde|ouml|para|plusmn|pound|quot|raquo|reg|sect|shy|sup1|sup2|sup3|szlig|thorn|times|uacute|ucirc|ugrave|uml|uuml|yacute|yen|yuml|#\d+|#[xX][\da-fA-F]+|[0-9a-zA-Z]+);?/g},e.namedReferences={xml:{entities:{"<":"<",">":">",""":'"',"'":"'","&":"&"},characters:{"<":"<",">":">",'"':""","'":"'","&":"&"}},html4:{entities:{"'":"'"," ":" "," ":" ","¡":"¡","¡":"¡","¢":"¢","¢":"¢","£":"£","£":"£","¤":"¤","¤":"¤","¥":"¥","¥":"¥","¦":"¦","¦":"¦","§":"§","§":"§","¨":"¨","¨":"¨","©":"©","©":"©","ª":"ª","ª":"ª","«":"«","«":"«","¬":"¬","¬":"¬","­":"­","­":"­","®":"®","®":"®","¯":"¯","¯":"¯","°":"°","°":"°","±":"±","±":"±","²":"²","²":"²","³":"³","³":"³","´":"´","´":"´","µ":"µ","µ":"µ","¶":"¶","¶":"¶","·":"·","·":"·","¸":"¸","¸":"¸","¹":"¹","¹":"¹","º":"º","º":"º","»":"»","»":"»","¼":"¼","¼":"¼","½":"½","½":"½","¾":"¾","¾":"¾","¿":"¿","¿":"¿","À":"À","À":"À","Á":"Á","Á":"Á","Â":"Â","Â":"Â","Ã":"Ã","Ã":"Ã","Ä":"Ä","Ä":"Ä","Å":"Å","Å":"Å","Æ":"Æ","Æ":"Æ","Ç":"Ç","Ç":"Ç","È":"È","È":"È","É":"É","É":"É","Ê":"Ê","Ê":"Ê","Ë":"Ë","Ë":"Ë","Ì":"Ì","Ì":"Ì","Í":"Í","Í":"Í","Î":"Î","Î":"Î","Ï":"Ï","Ï":"Ï","Ð":"Ð","Ð":"Ð","Ñ":"Ñ","Ñ":"Ñ","Ò":"Ò","Ò":"Ò","Ó":"Ó","Ó":"Ó","Ô":"Ô","Ô":"Ô","Õ":"Õ","Õ":"Õ","Ö":"Ö","Ö":"Ö","×":"×","×":"×","Ø":"Ø","Ø":"Ø","Ù":"Ù","Ù":"Ù","Ú":"Ú","Ú":"Ú","Û":"Û","Û":"Û","Ü":"Ü","Ü":"Ü","Ý":"Ý","Ý":"Ý","Þ":"Þ","Þ":"Þ","ß":"ß","ß":"ß","à":"à","à":"à","á":"á","á":"á","â":"â","â":"â","ã":"ã","ã":"ã","ä":"ä","ä":"ä","å":"å","å":"å","æ":"æ","æ":"æ","ç":"ç","ç":"ç","è":"è","è":"è","é":"é","é":"é","ê":"ê","ê":"ê","ë":"ë","ë":"ë","ì":"ì","ì":"ì","í":"í","í":"í","î":"î","î":"î","ï":"ï","ï":"ï","ð":"ð","ð":"ð","ñ":"ñ","ñ":"ñ","ò":"ò","ò":"ò","ó":"ó","ó":"ó","ô":"ô","ô":"ô","õ":"õ","õ":"õ","ö":"ö","ö":"ö","÷":"÷","÷":"÷","ø":"ø","ø":"ø","ù":"ù","ù":"ù","ú":"ú","ú":"ú","û":"û","û":"û","ü":"ü","ü":"ü","ý":"ý","ý":"ý","þ":"þ","þ":"þ","ÿ":"ÿ","ÿ":"ÿ",""":'"',""":'"',"&":"&","&":"&","<":"<","<":"<",">":">",">":">","Œ":"Œ","œ":"œ","Š":"Š","š":"š","Ÿ":"Ÿ","ˆ":"ˆ","˜":"˜"," ":" "," ":" "," ":" ","‌":"‌","‍":"‍","‎":"‎","‏":"‏","–":"–","—":"—","‘":"‘","’":"’","‚":"‚","“":"“","”":"”","„":"„","†":"†","‡":"‡","‰":"‰","‹":"‹","›":"›","€":"€","ƒ":"ƒ","Α":"Α","Β":"Β","Γ":"Γ","Δ":"Δ","Ε":"Ε","Ζ":"Ζ","Η":"Η","Θ":"Θ","Ι":"Ι","Κ":"Κ","Λ":"Λ","Μ":"Μ","Ν":"Ν","Ξ":"Ξ","Ο":"Ο","Π":"Π","Ρ":"Ρ","Σ":"Σ","Τ":"Τ","Υ":"Υ","Φ":"Φ","Χ":"Χ","Ψ":"Ψ","Ω":"Ω","α":"α","β":"β","γ":"γ","δ":"δ","ε":"ε","ζ":"ζ","η":"η","θ":"θ","ι":"ι","κ":"κ","λ":"λ","μ":"μ","ν":"ν","ξ":"ξ","ο":"ο","π":"π","ρ":"ρ","ς":"ς","σ":"σ","τ":"τ","υ":"υ","φ":"φ","χ":"χ","ψ":"ψ","ω":"ω","ϑ":"ϑ","ϒ":"ϒ","ϖ":"ϖ","•":"•","…":"…","′":"′","″":"″","‾":"‾","⁄":"⁄","℘":"℘","ℑ":"ℑ","ℜ":"ℜ","™":"™","ℵ":"ℵ","←":"←","↑":"↑","→":"→","↓":"↓","↔":"↔","↵":"↵","⇐":"⇐","⇑":"⇑","⇒":"⇒","⇓":"⇓","⇔":"⇔","∀":"∀","∂":"∂","∃":"∃","∅":"∅","∇":"∇","∈":"∈","∉":"∉","∋":"∋","∏":"∏","∑":"∑","−":"−","∗":"∗","√":"√","∝":"∝","∞":"∞","∠":"∠","∧":"∧","∨":"∨","∩":"∩","∪":"∪","∫":"∫","∴":"∴","∼":"∼","≅":"≅","≈":"≈","≠":"≠","≡":"≡","≤":"≤","≥":"≥","⊂":"⊂","⊃":"⊃","⊄":"⊄","⊆":"⊆","⊇":"⊇","⊕":"⊕","⊗":"⊗","⊥":"⊥","⋅":"⋅","⌈":"⌈","⌉":"⌉","⌊":"⌊","⌋":"⌋","⟨":"〈","⟩":"〉","◊":"◊","♠":"♠","♣":"♣","♥":"♥","♦":"♦"},characters:{"'":"'"," ":" ","¡":"¡","¢":"¢","£":"£","¤":"¤","¥":"¥","¦":"¦","§":"§","¨":"¨","©":"©",ª:"ª","«":"«","¬":"¬","­":"­","®":"®","¯":"¯","°":"°","±":"±","²":"²","³":"³","´":"´",µ:"µ","¶":"¶","·":"·","¸":"¸","¹":"¹",º:"º","»":"»","¼":"¼","½":"½","¾":"¾","¿":"¿",À:"À",Á:"Á",Â:"Â",Ã:"Ã",Ä:"Ä",Å:"Å",Æ:"Æ",Ç:"Ç",È:"È",É:"É",Ê:"Ê",Ë:"Ë",Ì:"Ì",Í:"Í",Î:"Î",Ï:"Ï",Ð:"Ð",Ñ:"Ñ",Ò:"Ò",Ó:"Ó",Ô:"Ô",Õ:"Õ",Ö:"Ö","×":"×",Ø:"Ø",Ù:"Ù",Ú:"Ú",Û:"Û",Ü:"Ü",Ý:"Ý",Þ:"Þ",ß:"ß",à:"à",á:"á",â:"â",ã:"ã",ä:"ä",å:"å",æ:"æ",ç:"ç",è:"è",é:"é",ê:"ê",ë:"ë",ì:"ì",í:"í",î:"î",ï:"ï",ð:"ð",ñ:"ñ",ò:"ò",ó:"ó",ô:"ô",õ:"õ",ö:"ö","÷":"÷",ø:"ø",ù:"ù",ú:"ú",û:"û",ü:"ü",ý:"ý",þ:"þ",ÿ:"ÿ",'"':""","&":"&","<":"<",">":">",Œ:"Œ",œ:"œ",Š:"Š",š:"š",Ÿ:"Ÿ",ˆ:"ˆ","˜":"˜"," ":" "," ":" "," ":" ","‌":"‌","‍":"‍","‎":"‎","‏":"‏","–":"–","—":"—","‘":"‘","’":"’","‚":"‚","“":"“","”":"”","„":"„","†":"†","‡":"‡","‰":"‰","‹":"‹","›":"›","€":"€",ƒ:"ƒ",Α:"Α",Β:"Β",Γ:"Γ",Δ:"Δ",Ε:"Ε",Ζ:"Ζ",Η:"Η",Θ:"Θ",Ι:"Ι",Κ:"Κ",Λ:"Λ",Μ:"Μ",Ν:"Ν",Ξ:"Ξ",Ο:"Ο",Π:"Π",Ρ:"Ρ",Σ:"Σ",Τ:"Τ",Υ:"Υ",Φ:"Φ",Χ:"Χ",Ψ:"Ψ",Ω:"Ω",α:"α",β:"β",γ:"γ",δ:"δ",ε:"ε",ζ:"ζ",η:"η",θ:"θ",ι:"ι",κ:"κ",λ:"λ",μ:"μ",ν:"ν",ξ:"ξ",ο:"ο",π:"π",ρ:"ρ",ς:"ς",σ:"σ",τ:"τ",υ:"υ",φ:"φ",χ:"χ",ψ:"ψ",ω:"ω",ϑ:"ϑ",ϒ:"ϒ",ϖ:"ϖ","•":"•","…":"…","′":"′","″":"″","‾":"‾","⁄":"⁄",℘:"℘",ℑ:"ℑ",ℜ:"ℜ","™":"™",ℵ:"ℵ","←":"←","↑":"↑","→":"→","↓":"↓","↔":"↔","↵":"↵","⇐":"⇐","⇑":"⇑","⇒":"⇒","⇓":"⇓","⇔":"⇔","∀":"∀","∂":"∂","∃":"∃","∅":"∅","∇":"∇","∈":"∈","∉":"∉","∋":"∋","∏":"∏","∑":"∑","−":"−","∗":"∗","√":"√","∝":"∝","∞":"∞","∠":"∠","∧":"∧","∨":"∨","∩":"∩","∪":"∪","∫":"∫","∴":"∴","∼":"∼","≅":"≅","≈":"≈","≠":"≠","≡":"≡","≤":"≤","≥":"≥","⊂":"⊂","⊃":"⊃","⊄":"⊄","⊆":"⊆","⊇":"⊇","⊕":"⊕","⊗":"⊗","⊥":"⊥","⋅":"⋅","⌈":"⌈","⌉":"⌉","⌊":"⌊","⌋":"⌋","〈":"⟨","〉":"⟩","◊":"◊","♠":"♠","♣":"♣","♥":"♥","♦":"♦"}},html5:{entities:{"Æ":"Æ","Æ":"Æ","&":"&","&":"&","Á":"Á","Á":"Á","Ă":"Ă","Â":"Â","Â":"Â","А":"А","𝔄":"𝔄","À":"À","À":"À","Α":"Α","Ā":"Ā","⩓":"⩓","Ą":"Ą","𝔸":"𝔸","⁡":"⁡","Å":"Å","Å":"Å","𝒜":"𝒜","≔":"≔","Ã":"Ã","Ã":"Ã","Ä":"Ä","Ä":"Ä","∖":"∖","⫧":"⫧","⌆":"⌆","Б":"Б","∵":"∵","ℬ":"ℬ","Β":"Β","𝔅":"𝔅","𝔹":"𝔹","˘":"˘","ℬ":"ℬ","≎":"≎","Ч":"Ч","©":"©","©":"©","Ć":"Ć","⋒":"⋒","ⅅ":"ⅅ","ℭ":"ℭ","Č":"Č","Ç":"Ç","Ç":"Ç","Ĉ":"Ĉ","∰":"∰","Ċ":"Ċ","¸":"¸","·":"·","ℭ":"ℭ","Χ":"Χ","⊙":"⊙","⊖":"⊖","⊕":"⊕","⊗":"⊗","∲":"∲","”":"”","’":"’","∷":"∷","⩴":"⩴","≡":"≡","∯":"∯","∮":"∮","ℂ":"ℂ","∐":"∐","∳":"∳","⨯":"⨯","𝒞":"𝒞","⋓":"⋓","≍":"≍","ⅅ":"ⅅ","⤑":"⤑","Ђ":"Ђ","Ѕ":"Ѕ","Џ":"Џ","‡":"‡","↡":"↡","⫤":"⫤","Ď":"Ď","Д":"Д","∇":"∇","Δ":"Δ","𝔇":"𝔇","´":"´","˙":"˙","˝":"˝","`":"`","˜":"˜","⋄":"⋄","ⅆ":"ⅆ","𝔻":"𝔻","¨":"¨","⃜":"⃜","≐":"≐","∯":"∯","¨":"¨","⇓":"⇓","⇐":"⇐","⇔":"⇔","⫤":"⫤","⟸":"⟸","⟺":"⟺","⟹":"⟹","⇒":"⇒","⊨":"⊨","⇑":"⇑","⇕":"⇕","∥":"∥","↓":"↓","⤓":"⤓","⇵":"⇵","̑":"̑","⥐":"⥐","⥞":"⥞","↽":"↽","⥖":"⥖","⥟":"⥟","⇁":"⇁","⥗":"⥗","⊤":"⊤","↧":"↧","⇓":"⇓","𝒟":"𝒟","Đ":"Đ","Ŋ":"Ŋ","Ð":"Ð","Ð":"Ð","É":"É","É":"É","Ě":"Ě","Ê":"Ê","Ê":"Ê","Э":"Э","Ė":"Ė","𝔈":"𝔈","È":"È","È":"È","∈":"∈","Ē":"Ē","◻":"◻","▫":"▫","Ę":"Ę","𝔼":"𝔼","Ε":"Ε","⩵":"⩵","≂":"≂","⇌":"⇌","ℰ":"ℰ","⩳":"⩳","Η":"Η","Ë":"Ë","Ë":"Ë","∃":"∃","ⅇ":"ⅇ","Ф":"Ф","𝔉":"𝔉","◼":"◼","▪":"▪","𝔽":"𝔽","∀":"∀","ℱ":"ℱ","ℱ":"ℱ","Ѓ":"Ѓ",">":">",">":">","Γ":"Γ","Ϝ":"Ϝ","Ğ":"Ğ","Ģ":"Ģ","Ĝ":"Ĝ","Г":"Г","Ġ":"Ġ","𝔊":"𝔊","⋙":"⋙","𝔾":"𝔾","≥":"≥","⋛":"⋛","≧":"≧","⪢":"⪢","≷":"≷","⩾":"⩾","≳":"≳","𝒢":"𝒢","≫":"≫","Ъ":"Ъ","ˇ":"ˇ","^":"^","Ĥ":"Ĥ","ℌ":"ℌ","ℋ":"ℋ","ℍ":"ℍ","─":"─","ℋ":"ℋ","Ħ":"Ħ","≎":"≎","≏":"≏","Е":"Е","IJ":"IJ","Ё":"Ё","Í":"Í","Í":"Í","Î":"Î","Î":"Î","И":"И","İ":"İ","ℑ":"ℑ","Ì":"Ì","Ì":"Ì","ℑ":"ℑ","Ī":"Ī","ⅈ":"ⅈ","⇒":"⇒","∬":"∬","∫":"∫","⋂":"⋂","⁣":"⁣","⁢":"⁢","Į":"Į","𝕀":"𝕀","Ι":"Ι","ℐ":"ℐ","Ĩ":"Ĩ","І":"І","Ï":"Ï","Ï":"Ï","Ĵ":"Ĵ","Й":"Й","𝔍":"𝔍","𝕁":"𝕁","𝒥":"𝒥","Ј":"Ј","Є":"Є","Х":"Х","Ќ":"Ќ","Κ":"Κ","Ķ":"Ķ","К":"К","𝔎":"𝔎","𝕂":"𝕂","𝒦":"𝒦","Љ":"Љ","<":"<","<":"<","Ĺ":"Ĺ","Λ":"Λ","⟪":"⟪","ℒ":"ℒ","↞":"↞","Ľ":"Ľ","Ļ":"Ļ","Л":"Л","⟨":"⟨","←":"←","⇤":"⇤","⇆":"⇆","⌈":"⌈","⟦":"⟦","⥡":"⥡","⇃":"⇃","⥙":"⥙","⌊":"⌊","↔":"↔","⥎":"⥎","⊣":"⊣","↤":"↤","⥚":"⥚","⊲":"⊲","⧏":"⧏","⊴":"⊴","⥑":"⥑","⥠":"⥠","↿":"↿","⥘":"⥘","↼":"↼","⥒":"⥒","⇐":"⇐","⇔":"⇔","⋚":"⋚","≦":"≦","≶":"≶","⪡":"⪡","⩽":"⩽","≲":"≲","𝔏":"𝔏","⋘":"⋘","⇚":"⇚","Ŀ":"Ŀ","⟵":"⟵","⟷":"⟷","⟶":"⟶","⟸":"⟸","⟺":"⟺","⟹":"⟹","𝕃":"𝕃","↙":"↙","↘":"↘","ℒ":"ℒ","↰":"↰","Ł":"Ł","≪":"≪","⤅":"⤅","М":"М"," ":" ","ℳ":"ℳ","𝔐":"𝔐","∓":"∓","𝕄":"𝕄","ℳ":"ℳ","Μ":"Μ","Њ":"Њ","Ń":"Ń","Ň":"Ň","Ņ":"Ņ","Н":"Н","​":"​","​":"​","​":"​","​":"​","≫":"≫","≪":"≪"," ":"\n","𝔑":"𝔑","⁠":"⁠"," ":" ","ℕ":"ℕ","⫬":"⫬","≢":"≢","≭":"≭","∦":"∦","∉":"∉","≠":"≠","≂̸":"≂̸","∄":"∄","≯":"≯","≱":"≱","≧̸":"≧̸","≫̸":"≫̸","≹":"≹","⩾̸":"⩾̸","≵":"≵","≎̸":"≎̸","≏̸":"≏̸","⋪":"⋪","⧏̸":"⧏̸","⋬":"⋬","≮":"≮","≰":"≰","≸":"≸","≪̸":"≪̸","⩽̸":"⩽̸","≴":"≴","⪢̸":"⪢̸","⪡̸":"⪡̸","⊀":"⊀","⪯̸":"⪯̸","⋠":"⋠","∌":"∌","⋫":"⋫","⧐̸":"⧐̸","⋭":"⋭","⊏̸":"⊏̸","⋢":"⋢","⊐̸":"⊐̸","⋣":"⋣","⊂⃒":"⊂⃒","⊈":"⊈","⊁":"⊁","⪰̸":"⪰̸","⋡":"⋡","≿̸":"≿̸","⊃⃒":"⊃⃒","⊉":"⊉","≁":"≁","≄":"≄","≇":"≇","≉":"≉","∤":"∤","𝒩":"𝒩","Ñ":"Ñ","Ñ":"Ñ","Ν":"Ν","Œ":"Œ","Ó":"Ó","Ó":"Ó","Ô":"Ô","Ô":"Ô","О":"О","Ő":"Ő","𝔒":"𝔒","Ò":"Ò","Ò":"Ò","Ō":"Ō","Ω":"Ω","Ο":"Ο","𝕆":"𝕆","“":"“","‘":"‘","⩔":"⩔","𝒪":"𝒪","Ø":"Ø","Ø":"Ø","Õ":"Õ","Õ":"Õ","⨷":"⨷","Ö":"Ö","Ö":"Ö","‾":"‾","⏞":"⏞","⎴":"⎴","⏜":"⏜","∂":"∂","П":"П","𝔓":"𝔓","Φ":"Φ","Π":"Π","±":"±","ℌ":"ℌ","ℙ":"ℙ","⪻":"⪻","≺":"≺","⪯":"⪯","≼":"≼","≾":"≾","″":"″","∏":"∏","∷":"∷","∝":"∝","𝒫":"𝒫","Ψ":"Ψ",""":'"',""":'"',"𝔔":"𝔔","ℚ":"ℚ","𝒬":"𝒬","⤐":"⤐","®":"®","®":"®","Ŕ":"Ŕ","⟫":"⟫","↠":"↠","⤖":"⤖","Ř":"Ř","Ŗ":"Ŗ","Р":"Р","ℜ":"ℜ","∋":"∋","⇋":"⇋","⥯":"⥯","ℜ":"ℜ","Ρ":"Ρ","⟩":"⟩","→":"→","⇥":"⇥","⇄":"⇄","⌉":"⌉","⟧":"⟧","⥝":"⥝","⇂":"⇂","⥕":"⥕","⌋":"⌋","⊢":"⊢","↦":"↦","⥛":"⥛","⊳":"⊳","⧐":"⧐","⊵":"⊵","⥏":"⥏","⥜":"⥜","↾":"↾","⥔":"⥔","⇀":"⇀","⥓":"⥓","⇒":"⇒","ℝ":"ℝ","⥰":"⥰","⇛":"⇛","ℛ":"ℛ","↱":"↱","⧴":"⧴","Щ":"Щ","Ш":"Ш","Ь":"Ь","Ś":"Ś","⪼":"⪼","Š":"Š","Ş":"Ş","Ŝ":"Ŝ","С":"С","𝔖":"𝔖","↓":"↓","←":"←","→":"→","↑":"↑","Σ":"Σ","∘":"∘","𝕊":"𝕊","√":"√","□":"□","⊓":"⊓","⊏":"⊏","⊑":"⊑","⊐":"⊐","⊒":"⊒","⊔":"⊔","𝒮":"𝒮","⋆":"⋆","⋐":"⋐","⋐":"⋐","⊆":"⊆","≻":"≻","⪰":"⪰","≽":"≽","≿":"≿","∋":"∋","∑":"∑","⋑":"⋑","⊃":"⊃","⊇":"⊇","⋑":"⋑","Þ":"Þ","Þ":"Þ","™":"™","Ћ":"Ћ","Ц":"Ц"," ":"\t","Τ":"Τ","Ť":"Ť","Ţ":"Ţ","Т":"Т","𝔗":"𝔗","∴":"∴","Θ":"Θ","  ":"  "," ":" ","∼":"∼","≃":"≃","≅":"≅","≈":"≈","𝕋":"𝕋","⃛":"⃛","𝒯":"𝒯","Ŧ":"Ŧ","Ú":"Ú","Ú":"Ú","↟":"↟","⥉":"⥉","Ў":"Ў","Ŭ":"Ŭ","Û":"Û","Û":"Û","У":"У","Ű":"Ű","𝔘":"𝔘","Ù":"Ù","Ù":"Ù","Ū":"Ū","_":"_","⏟":"⏟","⎵":"⎵","⏝":"⏝","⋃":"⋃","⊎":"⊎","Ų":"Ų","𝕌":"𝕌","↑":"↑","⤒":"⤒","⇅":"⇅","↕":"↕","⥮":"⥮","⊥":"⊥","↥":"↥","⇑":"⇑","⇕":"⇕","↖":"↖","↗":"↗","ϒ":"ϒ","Υ":"Υ","Ů":"Ů","𝒰":"𝒰","Ũ":"Ũ","Ü":"Ü","Ü":"Ü","⊫":"⊫","⫫":"⫫","В":"В","⊩":"⊩","⫦":"⫦","⋁":"⋁","‖":"‖","‖":"‖","∣":"∣","|":"|","❘":"❘","≀":"≀"," ":" ","𝔙":"𝔙","𝕍":"𝕍","𝒱":"𝒱","⊪":"⊪","Ŵ":"Ŵ","⋀":"⋀","𝔚":"𝔚","𝕎":"𝕎","𝒲":"𝒲","𝔛":"𝔛","Ξ":"Ξ","𝕏":"𝕏","𝒳":"𝒳","Я":"Я","Ї":"Ї","Ю":"Ю","Ý":"Ý","Ý":"Ý","Ŷ":"Ŷ","Ы":"Ы","𝔜":"𝔜","𝕐":"𝕐","𝒴":"𝒴","Ÿ":"Ÿ","Ж":"Ж","Ź":"Ź","Ž":"Ž","З":"З","Ż":"Ż","​":"​","Ζ":"Ζ","ℨ":"ℨ","ℤ":"ℤ","𝒵":"𝒵","á":"á","á":"á","ă":"ă","∾":"∾","∾̳":"∾̳","∿":"∿","â":"â","â":"â","´":"´","´":"´","а":"а","æ":"æ","æ":"æ","⁡":"⁡","𝔞":"𝔞","à":"à","à":"à","ℵ":"ℵ","ℵ":"ℵ","α":"α","ā":"ā","⨿":"⨿","&":"&","&":"&","∧":"∧","⩕":"⩕","⩜":"⩜","⩘":"⩘","⩚":"⩚","∠":"∠","⦤":"⦤","∠":"∠","∡":"∡","⦨":"⦨","⦩":"⦩","⦪":"⦪","⦫":"⦫","⦬":"⦬","⦭":"⦭","⦮":"⦮","⦯":"⦯","∟":"∟","⊾":"⊾","⦝":"⦝","∢":"∢","Å":"Å","⍼":"⍼","ą":"ą","𝕒":"𝕒","≈":"≈","⩰":"⩰","⩯":"⩯","≊":"≊","≋":"≋","'":"'","≈":"≈","≊":"≊","å":"å","å":"å","𝒶":"𝒶","*":"*","≈":"≈","≍":"≍","ã":"ã","ã":"ã","ä":"ä","ä":"ä","∳":"∳","⨑":"⨑","⫭":"⫭","≌":"≌","϶":"϶","‵":"‵","∽":"∽","⋍":"⋍","⊽":"⊽","⌅":"⌅","⌅":"⌅","⎵":"⎵","⎶":"⎶","≌":"≌","б":"б","„":"„","∵":"∵","∵":"∵","⦰":"⦰","϶":"϶","ℬ":"ℬ","β":"β","ℶ":"ℶ","≬":"≬","𝔟":"𝔟","⋂":"⋂","◯":"◯","⋃":"⋃","⨀":"⨀","⨁":"⨁","⨂":"⨂","⨆":"⨆","★":"★","▽":"▽","△":"△","⨄":"⨄","⋁":"⋁","⋀":"⋀","⤍":"⤍","⧫":"⧫","▪":"▪","▴":"▴","▾":"▾","◂":"◂","▸":"▸","␣":"␣","▒":"▒","░":"░","▓":"▓","█":"█","=⃥":"=⃥","≡⃥":"≡⃥","⌐":"⌐","𝕓":"𝕓","⊥":"⊥","⊥":"⊥","⋈":"⋈","╗":"╗","╔":"╔","╖":"╖","╓":"╓","═":"═","╦":"╦","╩":"╩","╤":"╤","╧":"╧","╝":"╝","╚":"╚","╜":"╜","╙":"╙","║":"║","╬":"╬","╣":"╣","╠":"╠","╫":"╫","╢":"╢","╟":"╟","⧉":"⧉","╕":"╕","╒":"╒","┐":"┐","┌":"┌","─":"─","╥":"╥","╨":"╨","┬":"┬","┴":"┴","⊟":"⊟","⊞":"⊞","⊠":"⊠","╛":"╛","╘":"╘","┘":"┘","└":"└","│":"│","╪":"╪","╡":"╡","╞":"╞","┼":"┼","┤":"┤","├":"├","‵":"‵","˘":"˘","¦":"¦","¦":"¦","𝒷":"𝒷","⁏":"⁏","∽":"∽","⋍":"⋍","\":"\\","⧅":"⧅","⟈":"⟈","•":"•","•":"•","≎":"≎","⪮":"⪮","≏":"≏","≏":"≏","ć":"ć","∩":"∩","⩄":"⩄","⩉":"⩉","⩋":"⩋","⩇":"⩇","⩀":"⩀","∩︀":"∩︀","⁁":"⁁","ˇ":"ˇ","⩍":"⩍","č":"č","ç":"ç","ç":"ç","ĉ":"ĉ","⩌":"⩌","⩐":"⩐","ċ":"ċ","¸":"¸","¸":"¸","⦲":"⦲","¢":"¢","¢":"¢","·":"·","𝔠":"𝔠","ч":"ч","✓":"✓","✓":"✓","χ":"χ","○":"○","⧃":"⧃","ˆ":"ˆ","≗":"≗","↺":"↺","↻":"↻","®":"®","Ⓢ":"Ⓢ","⊛":"⊛","⊚":"⊚","⊝":"⊝","≗":"≗","⨐":"⨐","⫯":"⫯","⧂":"⧂","♣":"♣","♣":"♣",":":":","≔":"≔","≔":"≔",",":",","@":"@","∁":"∁","∘":"∘","∁":"∁","ℂ":"ℂ","≅":"≅","⩭":"⩭","∮":"∮","𝕔":"𝕔","∐":"∐","©":"©","©":"©","℗":"℗","↵":"↵","✗":"✗","𝒸":"𝒸","⫏":"⫏","⫑":"⫑","⫐":"⫐","⫒":"⫒","⋯":"⋯","⤸":"⤸","⤵":"⤵","⋞":"⋞","⋟":"⋟","↶":"↶","⤽":"⤽","∪":"∪","⩈":"⩈","⩆":"⩆","⩊":"⩊","⊍":"⊍","⩅":"⩅","∪︀":"∪︀","↷":"↷","⤼":"⤼","⋞":"⋞","⋟":"⋟","⋎":"⋎","⋏":"⋏","¤":"¤","¤":"¤","↶":"↶","↷":"↷","⋎":"⋎","⋏":"⋏","∲":"∲","∱":"∱","⌭":"⌭","⇓":"⇓","⥥":"⥥","†":"†","ℸ":"ℸ","↓":"↓","‐":"‐","⊣":"⊣","⤏":"⤏","˝":"˝","ď":"ď","д":"д","ⅆ":"ⅆ","‡":"‡","⇊":"⇊","⩷":"⩷","°":"°","°":"°","δ":"δ","⦱":"⦱","⥿":"⥿","𝔡":"𝔡","⇃":"⇃","⇂":"⇂","⋄":"⋄","⋄":"⋄","♦":"♦","♦":"♦","¨":"¨","ϝ":"ϝ","⋲":"⋲","÷":"÷","÷":"÷","÷":"÷","⋇":"⋇","⋇":"⋇","ђ":"ђ","⌞":"⌞","⌍":"⌍","$":"$","𝕕":"𝕕","˙":"˙","≐":"≐","≑":"≑","∸":"∸","∔":"∔","⊡":"⊡","⌆":"⌆","↓":"↓","⇊":"⇊","⇃":"⇃","⇂":"⇂","⤐":"⤐","⌟":"⌟","⌌":"⌌","𝒹":"𝒹","ѕ":"ѕ","⧶":"⧶","đ":"đ","⋱":"⋱","▿":"▿","▾":"▾","⇵":"⇵","⥯":"⥯","⦦":"⦦","џ":"џ","⟿":"⟿","⩷":"⩷","≑":"≑","é":"é","é":"é","⩮":"⩮","ě":"ě","≖":"≖","ê":"ê","ê":"ê","≕":"≕","э":"э","ė":"ė","ⅇ":"ⅇ","≒":"≒","𝔢":"𝔢","⪚":"⪚","è":"è","è":"è","⪖":"⪖","⪘":"⪘","⪙":"⪙","⏧":"⏧","ℓ":"ℓ","⪕":"⪕","⪗":"⪗","ē":"ē","∅":"∅","∅":"∅","∅":"∅"," ":" "," ":" "," ":" ","ŋ":"ŋ"," ":" ","ę":"ę","𝕖":"𝕖","⋕":"⋕","⧣":"⧣","⩱":"⩱","ε":"ε","ε":"ε","ϵ":"ϵ","≖":"≖","≕":"≕","≂":"≂","⪖":"⪖","⪕":"⪕","=":"=","≟":"≟","≡":"≡","⩸":"⩸","⧥":"⧥","≓":"≓","⥱":"⥱","ℯ":"ℯ","≐":"≐","≂":"≂","η":"η","ð":"ð","ð":"ð","ë":"ë","ë":"ë","€":"€","!":"!","∃":"∃","ℰ":"ℰ","ⅇ":"ⅇ","≒":"≒","ф":"ф","♀":"♀","ffi":"ffi","ff":"ff","ffl":"ffl","𝔣":"𝔣","fi":"fi","fj":"fj","♭":"♭","fl":"fl","▱":"▱","ƒ":"ƒ","𝕗":"𝕗","∀":"∀","⋔":"⋔","⫙":"⫙","⨍":"⨍","½":"½","½":"½","⅓":"⅓","¼":"¼","¼":"¼","⅕":"⅕","⅙":"⅙","⅛":"⅛","⅔":"⅔","⅖":"⅖","¾":"¾","¾":"¾","⅗":"⅗","⅜":"⅜","⅘":"⅘","⅚":"⅚","⅝":"⅝","⅞":"⅞","⁄":"⁄","⌢":"⌢","𝒻":"𝒻","≧":"≧","⪌":"⪌","ǵ":"ǵ","γ":"γ","ϝ":"ϝ","⪆":"⪆","ğ":"ğ","ĝ":"ĝ","г":"г","ġ":"ġ","≥":"≥","⋛":"⋛","≥":"≥","≧":"≧","⩾":"⩾","⩾":"⩾","⪩":"⪩","⪀":"⪀","⪂":"⪂","⪄":"⪄","⋛︀":"⋛︀","⪔":"⪔","𝔤":"𝔤","≫":"≫","⋙":"⋙","ℷ":"ℷ","ѓ":"ѓ","≷":"≷","⪒":"⪒","⪥":"⪥","⪤":"⪤","≩":"≩","⪊":"⪊","⪊":"⪊","⪈":"⪈","⪈":"⪈","≩":"≩","⋧":"⋧","𝕘":"𝕘","`":"`","ℊ":"ℊ","≳":"≳","⪎":"⪎","⪐":"⪐",">":">",">":">","⪧":"⪧","⩺":"⩺","⋗":"⋗","⦕":"⦕","⩼":"⩼","⪆":"⪆","⥸":"⥸","⋗":"⋗","⋛":"⋛","⪌":"⪌","≷":"≷","≳":"≳","≩︀":"≩︀","≩︀":"≩︀","⇔":"⇔"," ":" ","½":"½","ℋ":"ℋ","ъ":"ъ","↔":"↔","⥈":"⥈","↭":"↭","ℏ":"ℏ","ĥ":"ĥ","♥":"♥","♥":"♥","…":"…","⊹":"⊹","𝔥":"𝔥","⤥":"⤥","⤦":"⤦","⇿":"⇿","∻":"∻","↩":"↩","↪":"↪","𝕙":"𝕙","―":"―","𝒽":"𝒽","ℏ":"ℏ","ħ":"ħ","⁃":"⁃","‐":"‐","í":"í","í":"í","⁣":"⁣","î":"î","î":"î","и":"и","е":"е","¡":"¡","¡":"¡","⇔":"⇔","𝔦":"𝔦","ì":"ì","ì":"ì","ⅈ":"ⅈ","⨌":"⨌","∭":"∭","⧜":"⧜","℩":"℩","ij":"ij","ī":"ī","ℑ":"ℑ","ℐ":"ℐ","ℑ":"ℑ","ı":"ı","⊷":"⊷","Ƶ":"Ƶ","∈":"∈","℅":"℅","∞":"∞","⧝":"⧝","ı":"ı","∫":"∫","⊺":"⊺","ℤ":"ℤ","⊺":"⊺","⨗":"⨗","⨼":"⨼","ё":"ё","į":"į","𝕚":"𝕚","ι":"ι","⨼":"⨼","¿":"¿","¿":"¿","𝒾":"𝒾","∈":"∈","⋹":"⋹","⋵":"⋵","⋴":"⋴","⋳":"⋳","∈":"∈","⁢":"⁢","ĩ":"ĩ","і":"і","ï":"ï","ï":"ï","ĵ":"ĵ","й":"й","𝔧":"𝔧","ȷ":"ȷ","𝕛":"𝕛","𝒿":"𝒿","ј":"ј","є":"є","κ":"κ","ϰ":"ϰ","ķ":"ķ","к":"к","𝔨":"𝔨","ĸ":"ĸ","х":"х","ќ":"ќ","𝕜":"𝕜","𝓀":"𝓀","⇚":"⇚","⇐":"⇐","⤛":"⤛","⤎":"⤎","≦":"≦","⪋":"⪋","⥢":"⥢","ĺ":"ĺ","⦴":"⦴","ℒ":"ℒ","λ":"λ","⟨":"⟨","⦑":"⦑","⟨":"⟨","⪅":"⪅","«":"«","«":"«","←":"←","⇤":"⇤","⤟":"⤟","⤝":"⤝","↩":"↩","↫":"↫","⤹":"⤹","⥳":"⥳","↢":"↢","⪫":"⪫","⤙":"⤙","⪭":"⪭","⪭︀":"⪭︀","⤌":"⤌","❲":"❲","{":"{","[":"[","⦋":"⦋","⦏":"⦏","⦍":"⦍","ľ":"ľ","ļ":"ļ","⌈":"⌈","{":"{","л":"л","⤶":"⤶","“":"“","„":"„","⥧":"⥧","⥋":"⥋","↲":"↲","≤":"≤","←":"←","↢":"↢","↽":"↽","↼":"↼","⇇":"⇇","↔":"↔","⇆":"⇆","⇋":"⇋","↭":"↭","⋋":"⋋","⋚":"⋚","≤":"≤","≦":"≦","⩽":"⩽","⩽":"⩽","⪨":"⪨","⩿":"⩿","⪁":"⪁","⪃":"⪃","⋚︀":"⋚︀","⪓":"⪓","⪅":"⪅","⋖":"⋖","⋚":"⋚","⪋":"⪋","≶":"≶","≲":"≲","⥼":"⥼","⌊":"⌊","𝔩":"𝔩","≶":"≶","⪑":"⪑","↽":"↽","↼":"↼","⥪":"⥪","▄":"▄","љ":"љ","≪":"≪","⇇":"⇇","⌞":"⌞","⥫":"⥫","◺":"◺","ŀ":"ŀ","⎰":"⎰","⎰":"⎰","≨":"≨","⪉":"⪉","⪉":"⪉","⪇":"⪇","⪇":"⪇","≨":"≨","⋦":"⋦","⟬":"⟬","⇽":"⇽","⟦":"⟦","⟵":"⟵","⟷":"⟷","⟼":"⟼","⟶":"⟶","↫":"↫","↬":"↬","⦅":"⦅","𝕝":"𝕝","⨭":"⨭","⨴":"⨴","∗":"∗","_":"_","◊":"◊","◊":"◊","⧫":"⧫","(":"(","⦓":"⦓","⇆":"⇆","⌟":"⌟","⇋":"⇋","⥭":"⥭","‎":"‎","⊿":"⊿","‹":"‹","𝓁":"𝓁","↰":"↰","≲":"≲","⪍":"⪍","⪏":"⪏","[":"[","‘":"‘","‚":"‚","ł":"ł","<":"<","<":"<","⪦":"⪦","⩹":"⩹","⋖":"⋖","⋋":"⋋","⋉":"⋉","⥶":"⥶","⩻":"⩻","⦖":"⦖","◃":"◃","⊴":"⊴","◂":"◂","⥊":"⥊","⥦":"⥦","≨︀":"≨︀","≨︀":"≨︀","∺":"∺","¯":"¯","¯":"¯","♂":"♂","✠":"✠","✠":"✠","↦":"↦","↦":"↦","↧":"↧","↤":"↤","↥":"↥","▮":"▮","⨩":"⨩","м":"м","—":"—","∡":"∡","𝔪":"𝔪","℧":"℧","µ":"µ","µ":"µ","∣":"∣","*":"*","⫰":"⫰","·":"·","·":"·","−":"−","⊟":"⊟","∸":"∸","⨪":"⨪","⫛":"⫛","…":"…","∓":"∓","⊧":"⊧","𝕞":"𝕞","∓":"∓","𝓂":"𝓂","∾":"∾","μ":"μ","⊸":"⊸","⊸":"⊸","⋙̸":"⋙̸","≫⃒":"≫⃒","≫̸":"≫̸","⇍":"⇍","⇎":"⇎","⋘̸":"⋘̸","≪⃒":"≪⃒","≪̸":"≪̸","⇏":"⇏","⊯":"⊯","⊮":"⊮","∇":"∇","ń":"ń","∠⃒":"∠⃒","≉":"≉","⩰̸":"⩰̸","≋̸":"≋̸","ʼn":"ʼn","≉":"≉","♮":"♮","♮":"♮","ℕ":"ℕ"," ":" "," ":" ","≎̸":"≎̸","≏̸":"≏̸","⩃":"⩃","ň":"ň","ņ":"ņ","≇":"≇","⩭̸":"⩭̸","⩂":"⩂","н":"н","–":"–","≠":"≠","⇗":"⇗","⤤":"⤤","↗":"↗","↗":"↗","≐̸":"≐̸","≢":"≢","⤨":"⤨","≂̸":"≂̸","∄":"∄","∄":"∄","𝔫":"𝔫","≧̸":"≧̸","≱":"≱","≱":"≱","≧̸":"≧̸","⩾̸":"⩾̸","⩾̸":"⩾̸","≵":"≵","≯":"≯","≯":"≯","⇎":"⇎","↮":"↮","⫲":"⫲","∋":"∋","⋼":"⋼","⋺":"⋺","∋":"∋","њ":"њ","⇍":"⇍","≦̸":"≦̸","↚":"↚","‥":"‥","≰":"≰","↚":"↚","↮":"↮","≰":"≰","≦̸":"≦̸","⩽̸":"⩽̸","⩽̸":"⩽̸","≮":"≮","≴":"≴","≮":"≮","⋪":"⋪","⋬":"⋬","∤":"∤","𝕟":"𝕟","¬":"¬","¬":"¬","∉":"∉","⋹̸":"⋹̸","⋵̸":"⋵̸","∉":"∉","⋷":"⋷","⋶":"⋶","∌":"∌","∌":"∌","⋾":"⋾","⋽":"⋽","∦":"∦","∦":"∦","⫽⃥":"⫽⃥","∂̸":"∂̸","⨔":"⨔","⊀":"⊀","⋠":"⋠","⪯̸":"⪯̸","⊀":"⊀","⪯̸":"⪯̸","⇏":"⇏","↛":"↛","⤳̸":"⤳̸","↝̸":"↝̸","↛":"↛","⋫":"⋫","⋭":"⋭","⊁":"⊁","⋡":"⋡","⪰̸":"⪰̸","𝓃":"𝓃","∤":"∤","∦":"∦","≁":"≁","≄":"≄","≄":"≄","∤":"∤","∦":"∦","⋢":"⋢","⋣":"⋣","⊄":"⊄","⫅̸":"⫅̸","⊈":"⊈","⊂⃒":"⊂⃒","⊈":"⊈","⫅̸":"⫅̸","⊁":"⊁","⪰̸":"⪰̸","⊅":"⊅","⫆̸":"⫆̸","⊉":"⊉","⊃⃒":"⊃⃒","⊉":"⊉","⫆̸":"⫆̸","≹":"≹","ñ":"ñ","ñ":"ñ","≸":"≸","⋪":"⋪","⋬":"⋬","⋫":"⋫","⋭":"⋭","ν":"ν","#":"#","№":"№"," ":" ","⊭":"⊭","⤄":"⤄","≍⃒":"≍⃒","⊬":"⊬","≥⃒":"≥⃒",">⃒":">⃒","⧞":"⧞","⤂":"⤂","≤⃒":"≤⃒","<⃒":"<⃒","⊴⃒":"⊴⃒","⤃":"⤃","⊵⃒":"⊵⃒","∼⃒":"∼⃒","⇖":"⇖","⤣":"⤣","↖":"↖","↖":"↖","⤧":"⤧","Ⓢ":"Ⓢ","ó":"ó","ó":"ó","⊛":"⊛","⊚":"⊚","ô":"ô","ô":"ô","о":"о","⊝":"⊝","ő":"ő","⨸":"⨸","⊙":"⊙","⦼":"⦼","œ":"œ","⦿":"⦿","𝔬":"𝔬","˛":"˛","ò":"ò","ò":"ò","⧁":"⧁","⦵":"⦵","Ω":"Ω","∮":"∮","↺":"↺","⦾":"⦾","⦻":"⦻","‾":"‾","⧀":"⧀","ō":"ō","ω":"ω","ο":"ο","⦶":"⦶","⊖":"⊖","𝕠":"𝕠","⦷":"⦷","⦹":"⦹","⊕":"⊕","∨":"∨","↻":"↻","⩝":"⩝","ℴ":"ℴ","ℴ":"ℴ","ª":"ª","ª":"ª","º":"º","º":"º","⊶":"⊶","⩖":"⩖","⩗":"⩗","⩛":"⩛","ℴ":"ℴ","ø":"ø","ø":"ø","⊘":"⊘","õ":"õ","õ":"õ","⊗":"⊗","⨶":"⨶","ö":"ö","ö":"ö","⌽":"⌽","∥":"∥","¶":"¶","¶":"¶","∥":"∥","⫳":"⫳","⫽":"⫽","∂":"∂","п":"п","%":"%",".":".","‰":"‰","⊥":"⊥","‱":"‱","𝔭":"𝔭","φ":"φ","ϕ":"ϕ","ℳ":"ℳ","☎":"☎","π":"π","⋔":"⋔","ϖ":"ϖ","ℏ":"ℏ","ℎ":"ℎ","ℏ":"ℏ","+":"+","⨣":"⨣","⊞":"⊞","⨢":"⨢","∔":"∔","⨥":"⨥","⩲":"⩲","±":"±","±":"±","⨦":"⨦","⨧":"⨧","±":"±","⨕":"⨕","𝕡":"𝕡","£":"£","£":"£","≺":"≺","⪳":"⪳","⪷":"⪷","≼":"≼","⪯":"⪯","≺":"≺","⪷":"⪷","≼":"≼","⪯":"⪯","⪹":"⪹","⪵":"⪵","⋨":"⋨","≾":"≾","′":"′","ℙ":"ℙ","⪵":"⪵","⪹":"⪹","⋨":"⋨","∏":"∏","⌮":"⌮","⌒":"⌒","⌓":"⌓","∝":"∝","∝":"∝","≾":"≾","⊰":"⊰","𝓅":"𝓅","ψ":"ψ"," ":" ","𝔮":"𝔮","⨌":"⨌","𝕢":"𝕢","⁗":"⁗","𝓆":"𝓆","ℍ":"ℍ","⨖":"⨖","?":"?","≟":"≟",""":'"',""":'"',"⇛":"⇛","⇒":"⇒","⤜":"⤜","⤏":"⤏","⥤":"⥤","∽̱":"∽̱","ŕ":"ŕ","√":"√","⦳":"⦳","⟩":"⟩","⦒":"⦒","⦥":"⦥","⟩":"⟩","»":"»","»":"»","→":"→","⥵":"⥵","⇥":"⇥","⤠":"⤠","⤳":"⤳","⤞":"⤞","↪":"↪","↬":"↬","⥅":"⥅","⥴":"⥴","↣":"↣","↝":"↝","⤚":"⤚","∶":"∶","ℚ":"ℚ","⤍":"⤍","❳":"❳","}":"}","]":"]","⦌":"⦌","⦎":"⦎","⦐":"⦐","ř":"ř","ŗ":"ŗ","⌉":"⌉","}":"}","р":"р","⤷":"⤷","⥩":"⥩","”":"”","”":"”","↳":"↳","ℜ":"ℜ","ℛ":"ℛ","ℜ":"ℜ","ℝ":"ℝ","▭":"▭","®":"®","®":"®","⥽":"⥽","⌋":"⌋","𝔯":"𝔯","⇁":"⇁","⇀":"⇀","⥬":"⥬","ρ":"ρ","ϱ":"ϱ","→":"→","↣":"↣","⇁":"⇁","⇀":"⇀","⇄":"⇄","⇌":"⇌","⇉":"⇉","↝":"↝","⋌":"⋌","˚":"˚","≓":"≓","⇄":"⇄","⇌":"⇌","‏":"‏","⎱":"⎱","⎱":"⎱","⫮":"⫮","⟭":"⟭","⇾":"⇾","⟧":"⟧","⦆":"⦆","𝕣":"𝕣","⨮":"⨮","⨵":"⨵",")":")","⦔":"⦔","⨒":"⨒","⇉":"⇉","›":"›","𝓇":"𝓇","↱":"↱","]":"]","’":"’","’":"’","⋌":"⋌","⋊":"⋊","▹":"▹","⊵":"⊵","▸":"▸","⧎":"⧎","⥨":"⥨","℞":"℞","ś":"ś","‚":"‚","≻":"≻","⪴":"⪴","⪸":"⪸","š":"š","≽":"≽","⪰":"⪰","ş":"ş","ŝ":"ŝ","⪶":"⪶","⪺":"⪺","⋩":"⋩","⨓":"⨓","≿":"≿","с":"с","⋅":"⋅","⊡":"⊡","⩦":"⩦","⇘":"⇘","⤥":"⤥","↘":"↘","↘":"↘","§":"§","§":"§",";":";","⤩":"⤩","∖":"∖","∖":"∖","✶":"✶","𝔰":"𝔰","⌢":"⌢","♯":"♯","щ":"щ","ш":"ш","∣":"∣","∥":"∥","­":"­","­":"­","σ":"σ","ς":"ς","ς":"ς","∼":"∼","⩪":"⩪","≃":"≃","≃":"≃","⪞":"⪞","⪠":"⪠","⪝":"⪝","⪟":"⪟","≆":"≆","⨤":"⨤","⥲":"⥲","←":"←","∖":"∖","⨳":"⨳","⧤":"⧤","∣":"∣","⌣":"⌣","⪪":"⪪","⪬":"⪬","⪬︀":"⪬︀","ь":"ь","/":"/","⧄":"⧄","⌿":"⌿","𝕤":"𝕤","♠":"♠","♠":"♠","∥":"∥","⊓":"⊓","⊓︀":"⊓︀","⊔":"⊔","⊔︀":"⊔︀","⊏":"⊏","⊑":"⊑","⊏":"⊏","⊑":"⊑","⊐":"⊐","⊒":"⊒","⊐":"⊐","⊒":"⊒","□":"□","□":"□","▪":"▪","▪":"▪","→":"→","𝓈":"𝓈","∖":"∖","⌣":"⌣","⋆":"⋆","☆":"☆","★":"★","ϵ":"ϵ","ϕ":"ϕ","¯":"¯","⊂":"⊂","⫅":"⫅","⪽":"⪽","⊆":"⊆","⫃":"⫃","⫁":"⫁","⫋":"⫋","⊊":"⊊","⪿":"⪿","⥹":"⥹","⊂":"⊂","⊆":"⊆","⫅":"⫅","⊊":"⊊","⫋":"⫋","⫇":"⫇","⫕":"⫕","⫓":"⫓","≻":"≻","⪸":"⪸","≽":"≽","⪰":"⪰","⪺":"⪺","⪶":"⪶","⋩":"⋩","≿":"≿","∑":"∑","♪":"♪","¹":"¹","¹":"¹","²":"²","²":"²","³":"³","³":"³","⊃":"⊃","⫆":"⫆","⪾":"⪾","⫘":"⫘","⊇":"⊇","⫄":"⫄","⟉":"⟉","⫗":"⫗","⥻":"⥻","⫂":"⫂","⫌":"⫌","⊋":"⊋","⫀":"⫀","⊃":"⊃","⊇":"⊇","⫆":"⫆","⊋":"⊋","⫌":"⫌","⫈":"⫈","⫔":"⫔","⫖":"⫖","⇙":"⇙","⤦":"⤦","↙":"↙","↙":"↙","⤪":"⤪","ß":"ß","ß":"ß","⌖":"⌖","τ":"τ","⎴":"⎴","ť":"ť","ţ":"ţ","т":"т","⃛":"⃛","⌕":"⌕","𝔱":"𝔱","∴":"∴","∴":"∴","θ":"θ","ϑ":"ϑ","ϑ":"ϑ","≈":"≈","∼":"∼"," ":" ","≈":"≈","∼":"∼","þ":"þ","þ":"þ","˜":"˜","×":"×","×":"×","⊠":"⊠","⨱":"⨱","⨰":"⨰","∭":"∭","⤨":"⤨","⊤":"⊤","⌶":"⌶","⫱":"⫱","𝕥":"𝕥","⫚":"⫚","⤩":"⤩","‴":"‴","™":"™","▵":"▵","▿":"▿","◃":"◃","⊴":"⊴","≜":"≜","▹":"▹","⊵":"⊵","◬":"◬","≜":"≜","⨺":"⨺","⨹":"⨹","⧍":"⧍","⨻":"⨻","⏢":"⏢","𝓉":"𝓉","ц":"ц","ћ":"ћ","ŧ":"ŧ","≬":"≬","↞":"↞","↠":"↠","⇑":"⇑","⥣":"⥣","ú":"ú","ú":"ú","↑":"↑","ў":"ў","ŭ":"ŭ","û":"û","û":"û","у":"у","⇅":"⇅","ű":"ű","⥮":"⥮","⥾":"⥾","𝔲":"𝔲","ù":"ù","ù":"ù","↿":"↿","↾":"↾","▀":"▀","⌜":"⌜","⌜":"⌜","⌏":"⌏","◸":"◸","ū":"ū","¨":"¨","¨":"¨","ų":"ų","𝕦":"𝕦","↑":"↑","↕":"↕","↿":"↿","↾":"↾","⊎":"⊎","υ":"υ","ϒ":"ϒ","υ":"υ","⇈":"⇈","⌝":"⌝","⌝":"⌝","⌎":"⌎","ů":"ů","◹":"◹","𝓊":"𝓊","⋰":"⋰","ũ":"ũ","▵":"▵","▴":"▴","⇈":"⇈","ü":"ü","ü":"ü","⦧":"⦧","⇕":"⇕","⫨":"⫨","⫩":"⫩","⊨":"⊨","⦜":"⦜","ϵ":"ϵ","ϰ":"ϰ","∅":"∅","ϕ":"ϕ","ϖ":"ϖ","∝":"∝","↕":"↕","ϱ":"ϱ","ς":"ς","⊊︀":"⊊︀","⫋︀":"⫋︀","⊋︀":"⊋︀","⫌︀":"⫌︀","ϑ":"ϑ","⊲":"⊲","⊳":"⊳","в":"в","⊢":"⊢","∨":"∨","⊻":"⊻","≚":"≚","⋮":"⋮","|":"|","|":"|","𝔳":"𝔳","⊲":"⊲","⊂⃒":"⊂⃒","⊃⃒":"⊃⃒","𝕧":"𝕧","∝":"∝","⊳":"⊳","𝓋":"𝓋","⫋︀":"⫋︀","⊊︀":"⊊︀","⫌︀":"⫌︀","⊋︀":"⊋︀","⦚":"⦚","ŵ":"ŵ","⩟":"⩟","∧":"∧","≙":"≙","℘":"℘","𝔴":"𝔴","𝕨":"𝕨","℘":"℘","≀":"≀","≀":"≀","𝓌":"𝓌","⋂":"⋂","◯":"◯","⋃":"⋃","▽":"▽","𝔵":"𝔵","⟺":"⟺","⟷":"⟷","ξ":"ξ","⟸":"⟸","⟵":"⟵","⟼":"⟼","⋻":"⋻","⨀":"⨀","𝕩":"𝕩","⨁":"⨁","⨂":"⨂","⟹":"⟹","⟶":"⟶","𝓍":"𝓍","⨆":"⨆","⨄":"⨄","△":"△","⋁":"⋁","⋀":"⋀","ý":"ý","ý":"ý","я":"я","ŷ":"ŷ","ы":"ы","¥":"¥","¥":"¥","𝔶":"𝔶","ї":"ї","𝕪":"𝕪","𝓎":"𝓎","ю":"ю","ÿ":"ÿ","ÿ":"ÿ","ź":"ź","ž":"ž","з":"з","ż":"ż","ℨ":"ℨ","ζ":"ζ","𝔷":"𝔷","ж":"ж","⇝":"⇝","𝕫":"𝕫","𝓏":"𝓏","‍":"‍","‌":"‌"},characters:{Æ:"Æ","&":"&",Á:"Á",Ă:"Ă",Â:"Â",А:"А",𝔄:"𝔄",À:"À",Α:"Α",Ā:"Ā","⩓":"⩓",Ą:"Ą",𝔸:"𝔸","⁡":"⁡",Å:"Å",𝒜:"𝒜","≔":"≔",Ã:"Ã",Ä:"Ä","∖":"∖","⫧":"⫧","⌆":"⌆",Б:"Б","∵":"∵",ℬ:"ℬ",Β:"Β",𝔅:"𝔅",𝔹:"𝔹","˘":"˘","≎":"≎",Ч:"Ч","©":"©",Ć:"Ć","⋒":"⋒",ⅅ:"ⅅ",ℭ:"ℭ",Č:"Č",Ç:"Ç",Ĉ:"Ĉ","∰":"∰",Ċ:"Ċ","¸":"¸","·":"·",Χ:"Χ","⊙":"⊙","⊖":"⊖","⊕":"⊕","⊗":"⊗","∲":"∲","”":"”","’":"’","∷":"∷","⩴":"⩴","≡":"≡","∯":"∯","∮":"∮",ℂ:"ℂ","∐":"∐","∳":"∳","⨯":"⨯",𝒞:"𝒞","⋓":"⋓","≍":"≍","⤑":"⤑",Ђ:"Ђ",Ѕ:"Ѕ",Џ:"Џ","‡":"‡","↡":"↡","⫤":"⫤",Ď:"Ď",Д:"Д","∇":"∇",Δ:"Δ",𝔇:"𝔇","´":"´","˙":"˙","˝":"˝","`":"`","˜":"˜","⋄":"⋄",ⅆ:"ⅆ",𝔻:"𝔻","¨":"¨","⃜":"⃜","≐":"≐","⇓":"⇓","⇐":"⇐","⇔":"⇔","⟸":"⟸","⟺":"⟺","⟹":"⟹","⇒":"⇒","⊨":"⊨","⇑":"⇑","⇕":"⇕","∥":"∥","↓":"↓","⤓":"⤓","⇵":"⇵","̑":"̑","⥐":"⥐","⥞":"⥞","↽":"↽","⥖":"⥖","⥟":"⥟","⇁":"⇁","⥗":"⥗","⊤":"⊤","↧":"↧",𝒟:"𝒟",Đ:"Đ",Ŋ:"Ŋ",Ð:"Ð",É:"É",Ě:"Ě",Ê:"Ê",Э:"Э",Ė:"Ė",𝔈:"𝔈",È:"È","∈":"∈",Ē:"Ē","◻":"◻","▫":"▫",Ę:"Ę",𝔼:"𝔼",Ε:"Ε","⩵":"⩵","≂":"≂","⇌":"⇌",ℰ:"ℰ","⩳":"⩳",Η:"Η",Ë:"Ë","∃":"∃",ⅇ:"ⅇ",Ф:"Ф",𝔉:"𝔉","◼":"◼","▪":"▪",𝔽:"𝔽","∀":"∀",ℱ:"ℱ",Ѓ:"Ѓ",">":">",Γ:"Γ",Ϝ:"Ϝ",Ğ:"Ğ",Ģ:"Ģ",Ĝ:"Ĝ",Г:"Г",Ġ:"Ġ",𝔊:"𝔊","⋙":"⋙",𝔾:"𝔾","≥":"≥","⋛":"⋛","≧":"≧","⪢":"⪢","≷":"≷","⩾":"⩾","≳":"≳",𝒢:"𝒢","≫":"≫",Ъ:"Ъ",ˇ:"ˇ","^":"^",Ĥ:"Ĥ",ℌ:"ℌ",ℋ:"ℋ",ℍ:"ℍ","─":"─",Ħ:"Ħ","≏":"≏",Е:"Е",IJ:"IJ",Ё:"Ё",Í:"Í",Î:"Î",И:"И",İ:"İ",ℑ:"ℑ",Ì:"Ì",Ī:"Ī",ⅈ:"ⅈ","∬":"∬","∫":"∫","⋂":"⋂","⁣":"⁣","⁢":"⁢",Į:"Į",𝕀:"𝕀",Ι:"Ι",ℐ:"ℐ",Ĩ:"Ĩ",І:"І",Ï:"Ï",Ĵ:"Ĵ",Й:"Й",𝔍:"𝔍",𝕁:"𝕁",𝒥:"𝒥",Ј:"Ј",Є:"Є",Х:"Х",Ќ:"Ќ",Κ:"Κ",Ķ:"Ķ",К:"К",𝔎:"𝔎",𝕂:"𝕂",𝒦:"𝒦",Љ:"Љ","<":"<",Ĺ:"Ĺ",Λ:"Λ","⟪":"⟪",ℒ:"ℒ","↞":"↞",Ľ:"Ľ",Ļ:"Ļ",Л:"Л","⟨":"⟨","←":"←","⇤":"⇤","⇆":"⇆","⌈":"⌈","⟦":"⟦","⥡":"⥡","⇃":"⇃","⥙":"⥙","⌊":"⌊","↔":"↔","⥎":"⥎","⊣":"⊣","↤":"↤","⥚":"⥚","⊲":"⊲","⧏":"⧏","⊴":"⊴","⥑":"⥑","⥠":"⥠","↿":"↿","⥘":"⥘","↼":"↼","⥒":"⥒","⋚":"⋚","≦":"≦","≶":"≶","⪡":"⪡","⩽":"⩽","≲":"≲",𝔏:"𝔏","⋘":"⋘","⇚":"⇚",Ŀ:"Ŀ","⟵":"⟵","⟷":"⟷","⟶":"⟶",𝕃:"𝕃","↙":"↙","↘":"↘","↰":"↰",Ł:"Ł","≪":"≪","⤅":"⤅",М:"М"," ":" ",ℳ:"ℳ",𝔐:"𝔐","∓":"∓",𝕄:"𝕄",Μ:"Μ",Њ:"Њ",Ń:"Ń",Ň:"Ň",Ņ:"Ņ",Н:"Н","​":"​","\n":" ",𝔑:"𝔑","⁠":"⁠"," ":" ",ℕ:"ℕ","⫬":"⫬","≢":"≢","≭":"≭","∦":"∦","∉":"∉","≠":"≠","≂̸":"≂̸","∄":"∄","≯":"≯","≱":"≱","≧̸":"≧̸","≫̸":"≫̸","≹":"≹","⩾̸":"⩾̸","≵":"≵","≎̸":"≎̸","≏̸":"≏̸","⋪":"⋪","⧏̸":"⧏̸","⋬":"⋬","≮":"≮","≰":"≰","≸":"≸","≪̸":"≪̸","⩽̸":"⩽̸","≴":"≴","⪢̸":"⪢̸","⪡̸":"⪡̸","⊀":"⊀","⪯̸":"⪯̸","⋠":"⋠","∌":"∌","⋫":"⋫","⧐̸":"⧐̸","⋭":"⋭","⊏̸":"⊏̸","⋢":"⋢","⊐̸":"⊐̸","⋣":"⋣","⊂⃒":"⊂⃒","⊈":"⊈","⊁":"⊁","⪰̸":"⪰̸","⋡":"⋡","≿̸":"≿̸","⊃⃒":"⊃⃒","⊉":"⊉","≁":"≁","≄":"≄","≇":"≇","≉":"≉","∤":"∤",𝒩:"𝒩",Ñ:"Ñ",Ν:"Ν",Œ:"Œ",Ó:"Ó",Ô:"Ô",О:"О",Ő:"Ő",𝔒:"𝔒",Ò:"Ò",Ō:"Ō",Ω:"Ω",Ο:"Ο",𝕆:"𝕆","“":"“","‘":"‘","⩔":"⩔",𝒪:"𝒪",Ø:"Ø",Õ:"Õ","⨷":"⨷",Ö:"Ö","‾":"‾","⏞":"⏞","⎴":"⎴","⏜":"⏜","∂":"∂",П:"П",𝔓:"𝔓",Φ:"Φ",Π:"Π","±":"±",ℙ:"ℙ","⪻":"⪻","≺":"≺","⪯":"⪯","≼":"≼","≾":"≾","″":"″","∏":"∏","∝":"∝",𝒫:"𝒫",Ψ:"Ψ",'"':""",𝔔:"𝔔",ℚ:"ℚ",𝒬:"𝒬","⤐":"⤐","®":"®",Ŕ:"Ŕ","⟫":"⟫","↠":"↠","⤖":"⤖",Ř:"Ř",Ŗ:"Ŗ",Р:"Р",ℜ:"ℜ","∋":"∋","⇋":"⇋","⥯":"⥯",Ρ:"Ρ","⟩":"⟩","→":"→","⇥":"⇥","⇄":"⇄","⌉":"⌉","⟧":"⟧","⥝":"⥝","⇂":"⇂","⥕":"⥕","⌋":"⌋","⊢":"⊢","↦":"↦","⥛":"⥛","⊳":"⊳","⧐":"⧐","⊵":"⊵","⥏":"⥏","⥜":"⥜","↾":"↾","⥔":"⥔","⇀":"⇀","⥓":"⥓",ℝ:"ℝ","⥰":"⥰","⇛":"⇛",ℛ:"ℛ","↱":"↱","⧴":"⧴",Щ:"Щ",Ш:"Ш",Ь:"Ь",Ś:"Ś","⪼":"⪼",Š:"Š",Ş:"Ş",Ŝ:"Ŝ",С:"С",𝔖:"𝔖","↑":"↑",Σ:"Σ","∘":"∘",𝕊:"𝕊","√":"√","□":"□","⊓":"⊓","⊏":"⊏","⊑":"⊑","⊐":"⊐","⊒":"⊒","⊔":"⊔",𝒮:"𝒮","⋆":"⋆","⋐":"⋐","⊆":"⊆","≻":"≻","⪰":"⪰","≽":"≽","≿":"≿","∑":"∑","⋑":"⋑","⊃":"⊃","⊇":"⊇",Þ:"Þ","™":"™",Ћ:"Ћ",Ц:"Ц","\t":" ",Τ:"Τ",Ť:"Ť",Ţ:"Ţ",Т:"Т",𝔗:"𝔗","∴":"∴",Θ:"Θ","  ":"  "," ":" ","∼":"∼","≃":"≃","≅":"≅","≈":"≈",𝕋:"𝕋","⃛":"⃛",𝒯:"𝒯",Ŧ:"Ŧ",Ú:"Ú","↟":"↟","⥉":"⥉",Ў:"Ў",Ŭ:"Ŭ",Û:"Û",У:"У",Ű:"Ű",𝔘:"𝔘",Ù:"Ù",Ū:"Ū",_:"_","⏟":"⏟","⎵":"⎵","⏝":"⏝","⋃":"⋃","⊎":"⊎",Ų:"Ų",𝕌:"𝕌","⤒":"⤒","⇅":"⇅","↕":"↕","⥮":"⥮","⊥":"⊥","↥":"↥","↖":"↖","↗":"↗",ϒ:"ϒ",Υ:"Υ",Ů:"Ů",𝒰:"𝒰",Ũ:"Ũ",Ü:"Ü","⊫":"⊫","⫫":"⫫",В:"В","⊩":"⊩","⫦":"⫦","⋁":"⋁","‖":"‖","∣":"∣","|":"|","❘":"❘","≀":"≀"," ":" ",𝔙:"𝔙",𝕍:"𝕍",𝒱:"𝒱","⊪":"⊪",Ŵ:"Ŵ","⋀":"⋀",𝔚:"𝔚",𝕎:"𝕎",𝒲:"𝒲",𝔛:"𝔛",Ξ:"Ξ",𝕏:"𝕏",𝒳:"𝒳",Я:"Я",Ї:"Ї",Ю:"Ю",Ý:"Ý",Ŷ:"Ŷ",Ы:"Ы",𝔜:"𝔜",𝕐:"𝕐",𝒴:"𝒴",Ÿ:"Ÿ",Ж:"Ж",Ź:"Ź",Ž:"Ž",З:"З",Ż:"Ż",Ζ:"Ζ",ℨ:"ℨ",ℤ:"ℤ",𝒵:"𝒵",á:"á",ă:"ă","∾":"∾","∾̳":"∾̳","∿":"∿",â:"â",а:"а",æ:"æ",𝔞:"𝔞",à:"à",ℵ:"ℵ",α:"α",ā:"ā","⨿":"⨿","∧":"∧","⩕":"⩕","⩜":"⩜","⩘":"⩘","⩚":"⩚","∠":"∠","⦤":"⦤","∡":"∡","⦨":"⦨","⦩":"⦩","⦪":"⦪","⦫":"⦫","⦬":"⦬","⦭":"⦭","⦮":"⦮","⦯":"⦯","∟":"∟","⊾":"⊾","⦝":"⦝","∢":"∢","⍼":"⍼",ą:"ą",𝕒:"𝕒","⩰":"⩰","⩯":"⩯","≊":"≊","≋":"≋","'":"'",å:"å",𝒶:"𝒶","*":"*",ã:"ã",ä:"ä","⨑":"⨑","⫭":"⫭","≌":"≌","϶":"϶","‵":"‵","∽":"∽","⋍":"⋍","⊽":"⊽","⌅":"⌅","⎶":"⎶",б:"б","„":"„","⦰":"⦰",β:"β",ℶ:"ℶ","≬":"≬",𝔟:"𝔟","◯":"◯","⨀":"⨀","⨁":"⨁","⨂":"⨂","⨆":"⨆","★":"★","▽":"▽","△":"△","⨄":"⨄","⤍":"⤍","⧫":"⧫","▴":"▴","▾":"▾","◂":"◂","▸":"▸","␣":"␣","▒":"▒","░":"░","▓":"▓","█":"█","=⃥":"=⃥","≡⃥":"≡⃥","⌐":"⌐",𝕓:"𝕓","⋈":"⋈","╗":"╗","╔":"╔","╖":"╖","╓":"╓","═":"═","╦":"╦","╩":"╩","╤":"╤","╧":"╧","╝":"╝","╚":"╚","╜":"╜","╙":"╙","║":"║","╬":"╬","╣":"╣","╠":"╠","╫":"╫","╢":"╢","╟":"╟","⧉":"⧉","╕":"╕","╒":"╒","┐":"┐","┌":"┌","╥":"╥","╨":"╨","┬":"┬","┴":"┴","⊟":"⊟","⊞":"⊞","⊠":"⊠","╛":"╛","╘":"╘","┘":"┘","└":"└","│":"│","╪":"╪","╡":"╡","╞":"╞","┼":"┼","┤":"┤","├":"├","¦":"¦",𝒷:"𝒷","⁏":"⁏","\\":"\","⧅":"⧅","⟈":"⟈","•":"•","⪮":"⪮",ć:"ć","∩":"∩","⩄":"⩄","⩉":"⩉","⩋":"⩋","⩇":"⩇","⩀":"⩀","∩︀":"∩︀","⁁":"⁁","⩍":"⩍",č:"č",ç:"ç",ĉ:"ĉ","⩌":"⩌","⩐":"⩐",ċ:"ċ","⦲":"⦲","¢":"¢",𝔠:"𝔠",ч:"ч","✓":"✓",χ:"χ","○":"○","⧃":"⧃",ˆ:"ˆ","≗":"≗","↺":"↺","↻":"↻","Ⓢ":"Ⓢ","⊛":"⊛","⊚":"⊚","⊝":"⊝","⨐":"⨐","⫯":"⫯","⧂":"⧂","♣":"♣",":":":",",":",","@":"@","∁":"∁","⩭":"⩭",𝕔:"𝕔","℗":"℗","↵":"↵","✗":"✗",𝒸:"𝒸","⫏":"⫏","⫑":"⫑","⫐":"⫐","⫒":"⫒","⋯":"⋯","⤸":"⤸","⤵":"⤵","⋞":"⋞","⋟":"⋟","↶":"↶","⤽":"⤽","∪":"∪","⩈":"⩈","⩆":"⩆","⩊":"⩊","⊍":"⊍","⩅":"⩅","∪︀":"∪︀","↷":"↷","⤼":"⤼","⋎":"⋎","⋏":"⋏","¤":"¤","∱":"∱","⌭":"⌭","⥥":"⥥","†":"†",ℸ:"ℸ","‐":"‐","⤏":"⤏",ď:"ď",д:"д","⇊":"⇊","⩷":"⩷","°":"°",δ:"δ","⦱":"⦱","⥿":"⥿",𝔡:"𝔡","♦":"♦",ϝ:"ϝ","⋲":"⋲","÷":"÷","⋇":"⋇",ђ:"ђ","⌞":"⌞","⌍":"⌍",$:"$",𝕕:"𝕕","≑":"≑","∸":"∸","∔":"∔","⊡":"⊡","⌟":"⌟","⌌":"⌌",𝒹:"𝒹",ѕ:"ѕ","⧶":"⧶",đ:"đ","⋱":"⋱","▿":"▿","⦦":"⦦",џ:"џ","⟿":"⟿",é:"é","⩮":"⩮",ě:"ě","≖":"≖",ê:"ê","≕":"≕",э:"э",ė:"ė","≒":"≒",𝔢:"𝔢","⪚":"⪚",è:"è","⪖":"⪖","⪘":"⪘","⪙":"⪙","⏧":"⏧",ℓ:"ℓ","⪕":"⪕","⪗":"⪗",ē:"ē","∅":"∅"," ":" "," ":" "," ":" ",ŋ:"ŋ"," ":" ",ę:"ę",𝕖:"𝕖","⋕":"⋕","⧣":"⧣","⩱":"⩱",ε:"ε",ϵ:"ϵ","=":"=","≟":"≟","⩸":"⩸","⧥":"⧥","≓":"≓","⥱":"⥱",ℯ:"ℯ",η:"η",ð:"ð",ë:"ë","€":"€","!":"!",ф:"ф","♀":"♀",ffi:"ffi",ff:"ff",ffl:"ffl",𝔣:"𝔣",fi:"fi",fj:"fj","♭":"♭",fl:"fl","▱":"▱",ƒ:"ƒ",𝕗:"𝕗","⋔":"⋔","⫙":"⫙","⨍":"⨍","½":"½","⅓":"⅓","¼":"¼","⅕":"⅕","⅙":"⅙","⅛":"⅛","⅔":"⅔","⅖":"⅖","¾":"¾","⅗":"⅗","⅜":"⅜","⅘":"⅘","⅚":"⅚","⅝":"⅝","⅞":"⅞","⁄":"⁄","⌢":"⌢",𝒻:"𝒻","⪌":"⪌",ǵ:"ǵ",γ:"γ","⪆":"⪆",ğ:"ğ",ĝ:"ĝ",г:"г",ġ:"ġ","⪩":"⪩","⪀":"⪀","⪂":"⪂","⪄":"⪄","⋛︀":"⋛︀","⪔":"⪔",𝔤:"𝔤",ℷ:"ℷ",ѓ:"ѓ","⪒":"⪒","⪥":"⪥","⪤":"⪤","≩":"≩","⪊":"⪊","⪈":"⪈","⋧":"⋧",𝕘:"𝕘",ℊ:"ℊ","⪎":"⪎","⪐":"⪐","⪧":"⪧","⩺":"⩺","⋗":"⋗","⦕":"⦕","⩼":"⩼","⥸":"⥸","≩︀":"≩︀",ъ:"ъ","⥈":"⥈","↭":"↭",ℏ:"ℏ",ĥ:"ĥ","♥":"♥","…":"…","⊹":"⊹",𝔥:"𝔥","⤥":"⤥","⤦":"⤦","⇿":"⇿","∻":"∻","↩":"↩","↪":"↪",𝕙:"𝕙","―":"―",𝒽:"𝒽",ħ:"ħ","⁃":"⁃",í:"í",î:"î",и:"и",е:"е","¡":"¡",𝔦:"𝔦",ì:"ì","⨌":"⨌","∭":"∭","⧜":"⧜","℩":"℩",ij:"ij",ī:"ī",ı:"ı","⊷":"⊷",Ƶ:"Ƶ","℅":"℅","∞":"∞","⧝":"⧝","⊺":"⊺","⨗":"⨗","⨼":"⨼",ё:"ё",į:"į",𝕚:"𝕚",ι:"ι","¿":"¿",𝒾:"𝒾","⋹":"⋹","⋵":"⋵","⋴":"⋴","⋳":"⋳",ĩ:"ĩ",і:"і",ï:"ï",ĵ:"ĵ",й:"й",𝔧:"𝔧",ȷ:"ȷ",𝕛:"𝕛",𝒿:"𝒿",ј:"ј",є:"є",κ:"κ",ϰ:"ϰ",ķ:"ķ",к:"к",𝔨:"𝔨",ĸ:"ĸ",х:"х",ќ:"ќ",𝕜:"𝕜",𝓀:"𝓀","⤛":"⤛","⤎":"⤎","⪋":"⪋","⥢":"⥢",ĺ:"ĺ","⦴":"⦴",λ:"λ","⦑":"⦑","⪅":"⪅","«":"«","⤟":"⤟","⤝":"⤝","↫":"↫","⤹":"⤹","⥳":"⥳","↢":"↢","⪫":"⪫","⤙":"⤙","⪭":"⪭","⪭︀":"⪭︀","⤌":"⤌","❲":"❲","{":"{","[":"[","⦋":"⦋","⦏":"⦏","⦍":"⦍",ľ:"ľ",ļ:"ļ",л:"л","⤶":"⤶","⥧":"⥧","⥋":"⥋","↲":"↲","≤":"≤","⇇":"⇇","⋋":"⋋","⪨":"⪨","⩿":"⩿","⪁":"⪁","⪃":"⪃","⋚︀":"⋚︀","⪓":"⪓","⋖":"⋖","⥼":"⥼",𝔩:"𝔩","⪑":"⪑","⥪":"⥪","▄":"▄",љ:"љ","⥫":"⥫","◺":"◺",ŀ:"ŀ","⎰":"⎰","≨":"≨","⪉":"⪉","⪇":"⪇","⋦":"⋦","⟬":"⟬","⇽":"⇽","⟼":"⟼","↬":"↬","⦅":"⦅",𝕝:"𝕝","⨭":"⨭","⨴":"⨴","∗":"∗","◊":"◊","(":"(","⦓":"⦓","⥭":"⥭","‎":"‎","⊿":"⊿","‹":"‹",𝓁:"𝓁","⪍":"⪍","⪏":"⪏","‚":"‚",ł:"ł","⪦":"⪦","⩹":"⩹","⋉":"⋉","⥶":"⥶","⩻":"⩻","⦖":"⦖","◃":"◃","⥊":"⥊","⥦":"⥦","≨︀":"≨︀","∺":"∺","¯":"¯","♂":"♂","✠":"✠","▮":"▮","⨩":"⨩",м:"м","—":"—",𝔪:"𝔪","℧":"℧",µ:"µ","⫰":"⫰","−":"−","⨪":"⨪","⫛":"⫛","⊧":"⊧",𝕞:"𝕞",𝓂:"𝓂",μ:"μ","⊸":"⊸","⋙̸":"⋙̸","≫⃒":"≫⃒","⇍":"⇍","⇎":"⇎","⋘̸":"⋘̸","≪⃒":"≪⃒","⇏":"⇏","⊯":"⊯","⊮":"⊮",ń:"ń","∠⃒":"∠⃒","⩰̸":"⩰̸","≋̸":"≋̸",ʼn:"ʼn","♮":"♮","⩃":"⩃",ň:"ň",ņ:"ņ","⩭̸":"⩭̸","⩂":"⩂",н:"н","–":"–","⇗":"⇗","⤤":"⤤","≐̸":"≐̸","⤨":"⤨",𝔫:"𝔫","↮":"↮","⫲":"⫲","⋼":"⋼","⋺":"⋺",њ:"њ","≦̸":"≦̸","↚":"↚","‥":"‥",𝕟:"𝕟","¬":"¬","⋹̸":"⋹̸","⋵̸":"⋵̸","⋷":"⋷","⋶":"⋶","⋾":"⋾","⋽":"⋽","⫽⃥":"⫽⃥","∂̸":"∂̸","⨔":"⨔","↛":"↛","⤳̸":"⤳̸","↝̸":"↝̸",𝓃:"𝓃","⊄":"⊄","⫅̸":"⫅̸","⊅":"⊅","⫆̸":"⫆̸",ñ:"ñ",ν:"ν","#":"#","№":"№"," ":" ","⊭":"⊭","⤄":"⤄","≍⃒":"≍⃒","⊬":"⊬","≥⃒":"≥⃒",">⃒":">⃒","⧞":"⧞","⤂":"⤂","≤⃒":"≤⃒","<⃒":"<⃒","⊴⃒":"⊴⃒","⤃":"⤃","⊵⃒":"⊵⃒","∼⃒":"∼⃒","⇖":"⇖","⤣":"⤣","⤧":"⤧",ó:"ó",ô:"ô",о:"о",ő:"ő","⨸":"⨸","⦼":"⦼",œ:"œ","⦿":"⦿",𝔬:"𝔬","˛":"˛",ò:"ò","⧁":"⧁","⦵":"⦵","⦾":"⦾","⦻":"⦻","⧀":"⧀",ō:"ō",ω:"ω",ο:"ο","⦶":"⦶",𝕠:"𝕠","⦷":"⦷","⦹":"⦹","∨":"∨","⩝":"⩝",ℴ:"ℴ",ª:"ª",º:"º","⊶":"⊶","⩖":"⩖","⩗":"⩗","⩛":"⩛",ø:"ø","⊘":"⊘",õ:"õ","⨶":"⨶",ö:"ö","⌽":"⌽","¶":"¶","⫳":"⫳","⫽":"⫽",п:"п","%":"%",".":".","‰":"‰","‱":"‱",𝔭:"𝔭",φ:"φ",ϕ:"ϕ","☎":"☎",π:"π",ϖ:"ϖ",ℎ:"ℎ","+":"+","⨣":"⨣","⨢":"⨢","⨥":"⨥","⩲":"⩲","⨦":"⨦","⨧":"⨧","⨕":"⨕",𝕡:"𝕡","£":"£","⪳":"⪳","⪷":"⪷","⪹":"⪹","⪵":"⪵","⋨":"⋨","′":"′","⌮":"⌮","⌒":"⌒","⌓":"⌓","⊰":"⊰",𝓅:"𝓅",ψ:"ψ"," ":" ",𝔮:"𝔮",𝕢:"𝕢","⁗":"⁗",𝓆:"𝓆","⨖":"⨖","?":"?","⤜":"⤜","⥤":"⥤","∽̱":"∽̱",ŕ:"ŕ","⦳":"⦳","⦒":"⦒","⦥":"⦥","»":"»","⥵":"⥵","⤠":"⤠","⤳":"⤳","⤞":"⤞","⥅":"⥅","⥴":"⥴","↣":"↣","↝":"↝","⤚":"⤚","∶":"∶","❳":"❳","}":"}","]":"]","⦌":"⦌","⦎":"⦎","⦐":"⦐",ř:"ř",ŗ:"ŗ",р:"р","⤷":"⤷","⥩":"⥩","↳":"↳","▭":"▭","⥽":"⥽",𝔯:"𝔯","⥬":"⥬",ρ:"ρ",ϱ:"ϱ","⇉":"⇉","⋌":"⋌","˚":"˚","‏":"‏","⎱":"⎱","⫮":"⫮","⟭":"⟭","⇾":"⇾","⦆":"⦆",𝕣:"𝕣","⨮":"⨮","⨵":"⨵",")":")","⦔":"⦔","⨒":"⨒","›":"›",𝓇:"𝓇","⋊":"⋊","▹":"▹","⧎":"⧎","⥨":"⥨","℞":"℞",ś:"ś","⪴":"⪴","⪸":"⪸",š:"š",ş:"ş",ŝ:"ŝ","⪶":"⪶","⪺":"⪺","⋩":"⋩","⨓":"⨓",с:"с","⋅":"⋅","⩦":"⩦","⇘":"⇘","§":"§",";":";","⤩":"⤩","✶":"✶",𝔰:"𝔰","♯":"♯",щ:"щ",ш:"ш","­":"­",σ:"σ",ς:"ς","⩪":"⩪","⪞":"⪞","⪠":"⪠","⪝":"⪝","⪟":"⪟","≆":"≆","⨤":"⨤","⥲":"⥲","⨳":"⨳","⧤":"⧤","⌣":"⌣","⪪":"⪪","⪬":"⪬","⪬︀":"⪬︀",ь:"ь","/":"/","⧄":"⧄","⌿":"⌿",𝕤:"𝕤","♠":"♠","⊓︀":"⊓︀","⊔︀":"⊔︀",𝓈:"𝓈","☆":"☆","⊂":"⊂","⫅":"⫅","⪽":"⪽","⫃":"⫃","⫁":"⫁","⫋":"⫋","⊊":"⊊","⪿":"⪿","⥹":"⥹","⫇":"⫇","⫕":"⫕","⫓":"⫓","♪":"♪","¹":"¹","²":"²","³":"³","⫆":"⫆","⪾":"⪾","⫘":"⫘","⫄":"⫄","⟉":"⟉","⫗":"⫗","⥻":"⥻","⫂":"⫂","⫌":"⫌","⊋":"⊋","⫀":"⫀","⫈":"⫈","⫔":"⫔","⫖":"⫖","⇙":"⇙","⤪":"⤪",ß:"ß","⌖":"⌖",τ:"τ",ť:"ť",ţ:"ţ",т:"т","⌕":"⌕",𝔱:"𝔱",θ:"θ",ϑ:"ϑ",þ:"þ","×":"×","⨱":"⨱","⨰":"⨰","⌶":"⌶","⫱":"⫱",𝕥:"𝕥","⫚":"⫚","‴":"‴","▵":"▵","≜":"≜","◬":"◬","⨺":"⨺","⨹":"⨹","⧍":"⧍","⨻":"⨻","⏢":"⏢",𝓉:"𝓉",ц:"ц",ћ:"ћ",ŧ:"ŧ","⥣":"⥣",ú:"ú",ў:"ў",ŭ:"ŭ",û:"û",у:"у",ű:"ű","⥾":"⥾",𝔲:"𝔲",ù:"ù","▀":"▀","⌜":"⌜","⌏":"⌏","◸":"◸",ū:"ū",ų:"ų",𝕦:"𝕦",υ:"υ","⇈":"⇈","⌝":"⌝","⌎":"⌎",ů:"ů","◹":"◹",𝓊:"𝓊","⋰":"⋰",ũ:"ũ",ü:"ü","⦧":"⦧","⫨":"⫨","⫩":"⫩","⦜":"⦜","⊊︀":"⊊︀","⫋︀":"⫋︀","⊋︀":"⊋︀","⫌︀":"⫌︀",в:"в","⊻":"⊻","≚":"≚","⋮":"⋮",𝔳:"𝔳",𝕧:"𝕧",𝓋:"𝓋","⦚":"⦚",ŵ:"ŵ","⩟":"⩟","≙":"≙",℘:"℘",𝔴:"𝔴",𝕨:"𝕨",𝓌:"𝓌",𝔵:"𝔵",ξ:"ξ","⋻":"⋻",𝕩:"𝕩",𝓍:"𝓍",ý:"ý",я:"я",ŷ:"ŷ",ы:"ы","¥":"¥",𝔶:"𝔶",ї:"ї",𝕪:"𝕪",𝓎:"𝓎",ю:"ю",ÿ:"ÿ",ź:"ź",ž:"ž",з:"з",ż:"ż",ζ:"ζ",𝔷:"𝔷",ж:"ж","⇝":"⇝",𝕫:"𝕫",𝓏:"𝓏","‍":"‍","‌":"‌"}}}},687:(r,e)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.numericUnicodeMap={0:65533,128:8364,130:8218,131:402,132:8222,133:8230,134:8224,135:8225,136:710,137:8240,138:352,139:8249,140:338,142:381,145:8216,146:8217,147:8220,148:8221,149:8226,150:8211,151:8212,152:732,153:8482,154:353,155:8250,156:339,158:382,159:376}},967:(r,e)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.fromCodePoint=String.fromCodePoint||function(r){return String.fromCharCode(Math.floor((r-65536)/1024)+55296,(r-65536)%1024+56320)},e.getCodePoint=String.prototype.codePointAt?function(r,e){return r.codePointAt(e)}:function(r,e){return 1024*(r.charCodeAt(e)-55296)+r.charCodeAt(e+1)-56320+65536},e.highSurrogateFrom=55296,e.highSurrogateTo=56319}},a={};function t(r){var o=a[r];if(void 0!==o)return o.exports;var c=a[r]={exports:{}};return e[r].call(c.exports,c,c.exports,t),c.exports}t.n=r=>{var e=r&&r.__esModule?()=>r.default:()=>r;return t.d(e,{a:e}),e},t.d=(r,e)=>{for(var a in e)t.o(e,a)&&!t.o(r,a)&&Object.defineProperty(r,a,{enumerable:!0,get:e[a]})},t.o=(r,e)=>Object.prototype.hasOwnProperty.call(r,e),r=t(563),window.html_encode=r.encode,window.html_decode=r.decode})(); \ No newline at end of file diff --git a/src/dev-center/js/jquery-3.6.0.min.js b/src/dev-center/js/jquery-3.6.0.min.js new file mode 100644 index 0000000000..c4c6022f29 --- /dev/null +++ b/src/dev-center/js/jquery-3.6.0.min.js @@ -0,0 +1,2 @@ +/*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ +!function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0":"greater","|":"or","¢":"cent","£":"pound","¤":"currency","¥":"yen","©":"(c)","ª":"a","®":"(r)","º":"o","À":"A","Á":"A","Â":"A","Ã":"A","Ä":"A","Å":"A","Æ":"AE","Ç":"C","È":"E","É":"E","Ê":"E","Ë":"E","Ì":"I","Í":"I","Î":"I","Ï":"I","Ð":"D","Ñ":"N","Ò":"O","Ó":"O","Ô":"O","Õ":"O","Ö":"O","Ø":"O","Ù":"U","Ú":"U","Û":"U","Ü":"U","Ý":"Y","Þ":"TH","ß":"ss","à":"a","á":"a","â":"a","ã":"a","ä":"a","å":"a","æ":"ae","ç":"c","è":"e","é":"e","ê":"e","ë":"e","ì":"i","í":"i","î":"i","ï":"i","ð":"d","ñ":"n","ò":"o","ó":"o","ô":"o","õ":"o","ö":"o","ø":"o","ù":"u","ú":"u","û":"u","ü":"u","ý":"y","þ":"th","ÿ":"y","Ā":"A","ā":"a","Ă":"A","ă":"a","Ą":"A","ą":"a","Ć":"C","ć":"c","Č":"C","č":"c","Ď":"D","ď":"d","Đ":"DJ","đ":"dj","Ē":"E","ē":"e","Ė":"E","ė":"e","Ę":"e","ę":"e","Ě":"E","ě":"e","Ğ":"G","ğ":"g","Ģ":"G","ģ":"g","Ĩ":"I","ĩ":"i","Ī":"i","ī":"i","Į":"I","į":"i","İ":"I","ı":"i","Ķ":"k","ķ":"k","Ļ":"L","ļ":"l","Ľ":"L","ľ":"l","Ł":"L","ł":"l","Ń":"N","ń":"n","Ņ":"N","ņ":"n","Ň":"N","ň":"n","Ō":"O","ō":"o","Ő":"O","ő":"o","Œ":"OE","œ":"oe","Ŕ":"R","ŕ":"r","Ř":"R","ř":"r","Ś":"S","ś":"s","Ş":"S","ş":"s","Š":"S","š":"s","Ţ":"T","ţ":"t","Ť":"T","ť":"t","Ũ":"U","ũ":"u","Ū":"u","ū":"u","Ů":"U","ů":"u","Ű":"U","ű":"u","Ų":"U","ų":"u","Ŵ":"W","ŵ":"w","Ŷ":"Y","ŷ":"y","Ÿ":"Y","Ź":"Z","ź":"z","Ż":"Z","ż":"z","Ž":"Z","ž":"z","Ə":"E","ƒ":"f","Ơ":"O","ơ":"o","Ư":"U","ư":"u","Lj":"LJ","lj":"lj","Nj":"NJ","nj":"nj","Ș":"S","ș":"s","Ț":"T","ț":"t","ə":"e","˚":"o","Ά":"A","Έ":"E","Ή":"H","Ί":"I","Ό":"O","Ύ":"Y","Ώ":"W","ΐ":"i","Α":"A","Β":"B","Γ":"G","Δ":"D","Ε":"E","Ζ":"Z","Η":"H","Θ":"8","Ι":"I","Κ":"K","Λ":"L","Μ":"M","Ν":"N","Ξ":"3","Ο":"O","Π":"P","Ρ":"R","Σ":"S","Τ":"T","Υ":"Y","Φ":"F","Χ":"X","Ψ":"PS","Ω":"W","Ϊ":"I","Ϋ":"Y","ά":"a","έ":"e","ή":"h","ί":"i","ΰ":"y","α":"a","β":"b","γ":"g","δ":"d","ε":"e","ζ":"z","η":"h","θ":"8","ι":"i","κ":"k","λ":"l","μ":"m","ν":"n","ξ":"3","ο":"o","π":"p","ρ":"r","ς":"s","σ":"s","τ":"t","υ":"y","φ":"f","χ":"x","ψ":"ps","ω":"w","ϊ":"i","ϋ":"y","ό":"o","ύ":"y","ώ":"w","Ё":"Yo","Ђ":"DJ","Є":"Ye","І":"I","Ї":"Yi","Ј":"J","Љ":"LJ","Њ":"NJ","Ћ":"C","Џ":"DZ","А":"A","Б":"B","В":"V","Г":"G","Д":"D","Е":"E","Ж":"Zh","З":"Z","И":"I","Й":"J","К":"K","Л":"L","М":"M","Н":"N","О":"O","П":"P","Р":"R","С":"S","Т":"T","У":"U","Ф":"F","Х":"H","Ц":"C","Ч":"Ch","Ш":"Sh","Щ":"Sh","Ъ":"U","Ы":"Y","Ь":"","Э":"E","Ю":"Yu","Я":"Ya","а":"a","б":"b","в":"v","г":"g","д":"d","е":"e","ж":"zh","з":"z","и":"i","й":"j","к":"k","л":"l","м":"m","н":"n","о":"o","п":"p","р":"r","с":"s","т":"t","у":"u","ф":"f","х":"h","ц":"c","ч":"ch","ш":"sh","щ":"sh","ъ":"u","ы":"y","ь":"","э":"e","ю":"yu","я":"ya","ё":"yo","ђ":"dj","є":"ye","і":"i","ї":"yi","ј":"j","љ":"lj","њ":"nj","ћ":"c","ѝ":"u","џ":"dz","Ґ":"G","ґ":"g","Ғ":"GH","ғ":"gh","Қ":"KH","қ":"kh","Ң":"NG","ң":"ng","Ү":"UE","ү":"ue","Ұ":"U","ұ":"u","Һ":"H","һ":"h","Ә":"AE","ә":"ae","Ө":"OE","ө":"oe","Ա":"A","Բ":"B","Գ":"G","Դ":"D","Ե":"E","Զ":"Z","Է":"E\'","Ը":"Y\'","Թ":"T\'","Ժ":"JH","Ի":"I","Լ":"L","Խ":"X","Ծ":"C\'","Կ":"K","Հ":"H","Ձ":"D\'","Ղ":"GH","Ճ":"TW","Մ":"M","Յ":"Y","Ն":"N","Շ":"SH","Չ":"CH","Պ":"P","Ջ":"J","Ռ":"R\'","Ս":"S","Վ":"V","Տ":"T","Ր":"R","Ց":"C","Փ":"P\'","Ք":"Q\'","Օ":"O\'\'","Ֆ":"F","և":"EV","ء":"a","آ":"aa","أ":"a","ؤ":"u","إ":"i","ئ":"e","ا":"a","ب":"b","ة":"h","ت":"t","ث":"th","ج":"j","ح":"h","خ":"kh","د":"d","ذ":"th","ر":"r","ز":"z","س":"s","ش":"sh","ص":"s","ض":"dh","ط":"t","ظ":"z","ع":"a","غ":"gh","ف":"f","ق":"q","ك":"k","ل":"l","م":"m","ن":"n","ه":"h","و":"w","ى":"a","ي":"y","ً":"an","ٌ":"on","ٍ":"en","َ":"a","ُ":"u","ِ":"e","ْ":"","٠":"0","١":"1","٢":"2","٣":"3","٤":"4","٥":"5","٦":"6","٧":"7","٨":"8","٩":"9","پ":"p","چ":"ch","ژ":"zh","ک":"k","گ":"g","ی":"y","۰":"0","۱":"1","۲":"2","۳":"3","۴":"4","۵":"5","۶":"6","۷":"7","۸":"8","۹":"9","฿":"baht","ა":"a","ბ":"b","გ":"g","დ":"d","ე":"e","ვ":"v","ზ":"z","თ":"t","ი":"i","კ":"k","ლ":"l","მ":"m","ნ":"n","ო":"o","პ":"p","ჟ":"zh","რ":"r","ს":"s","ტ":"t","უ":"u","ფ":"f","ქ":"k","ღ":"gh","ყ":"q","შ":"sh","ჩ":"ch","ც":"ts","ძ":"dz","წ":"ts","ჭ":"ch","ხ":"kh","ჯ":"j","ჰ":"h","Ṣ":"S","ṣ":"s","Ẁ":"W","ẁ":"w","Ẃ":"W","ẃ":"w","Ẅ":"W","ẅ":"w","ẞ":"SS","Ạ":"A","ạ":"a","Ả":"A","ả":"a","Ấ":"A","ấ":"a","Ầ":"A","ầ":"a","Ẩ":"A","ẩ":"a","Ẫ":"A","ẫ":"a","Ậ":"A","ậ":"a","Ắ":"A","ắ":"a","Ằ":"A","ằ":"a","Ẳ":"A","ẳ":"a","Ẵ":"A","ẵ":"a","Ặ":"A","ặ":"a","Ẹ":"E","ẹ":"e","Ẻ":"E","ẻ":"e","Ẽ":"E","ẽ":"e","Ế":"E","ế":"e","Ề":"E","ề":"e","Ể":"E","ể":"e","Ễ":"E","ễ":"e","Ệ":"E","ệ":"e","Ỉ":"I","ỉ":"i","Ị":"I","ị":"i","Ọ":"O","ọ":"o","Ỏ":"O","ỏ":"o","Ố":"O","ố":"o","Ồ":"O","ồ":"o","Ổ":"O","ổ":"o","Ỗ":"O","ỗ":"o","Ộ":"O","ộ":"o","Ớ":"O","ớ":"o","Ờ":"O","ờ":"o","Ở":"O","ở":"o","Ỡ":"O","ỡ":"o","Ợ":"O","ợ":"o","Ụ":"U","ụ":"u","Ủ":"U","ủ":"u","Ứ":"U","ứ":"u","Ừ":"U","ừ":"u","Ử":"U","ử":"u","Ữ":"U","ữ":"u","Ự":"U","ự":"u","Ỳ":"Y","ỳ":"y","Ỵ":"Y","ỵ":"y","Ỷ":"Y","ỷ":"y","Ỹ":"Y","ỹ":"y","–":"-","‘":"\'","’":"\'","“":"\\\"","”":"\\\"","„":"\\\"","†":"+","•":"*","…":"...","₠":"ecu","₢":"cruzeiro","₣":"french franc","₤":"lira","₥":"mill","₦":"naira","₧":"peseta","₨":"rupee","₩":"won","₪":"new shequel","₫":"dong","€":"euro","₭":"kip","₮":"tugrik","₯":"drachma","₰":"penny","₱":"peso","₲":"guarani","₳":"austral","₴":"hryvnia","₵":"cedi","₸":"kazakhstani tenge","₹":"indian rupee","₺":"turkish lira","₽":"russian ruble","₿":"bitcoin","℠":"sm","™":"tm","∂":"d","∆":"delta","∑":"sum","∞":"infinity","♥":"love","元":"yuan","円":"yen","﷼":"rial","ﻵ":"laa","ﻷ":"laa","ﻹ":"lai","ﻻ":"la"}') + var locales = JSON.parse('{"bg":{"Й":"Y","Ц":"Ts","Щ":"Sht","Ъ":"A","Ь":"Y","й":"y","ц":"ts","щ":"sht","ъ":"a","ь":"y"},"de":{"Ä":"AE","ä":"ae","Ö":"OE","ö":"oe","Ü":"UE","ü":"ue","ß":"ss","%":"prozent","&":"und","|":"oder","∑":"summe","∞":"unendlich","♥":"liebe"},"es":{"%":"por ciento","&":"y","<":"menor que",">":"mayor que","|":"o","¢":"centavos","£":"libras","¤":"moneda","₣":"francos","∑":"suma","∞":"infinito","♥":"amor"},"fr":{"%":"pourcent","&":"et","<":"plus petit",">":"plus grand","|":"ou","¢":"centime","£":"livre","¤":"devise","₣":"franc","∑":"somme","∞":"infini","♥":"amour"},"pt":{"%":"porcento","&":"e","<":"menor",">":"maior","|":"ou","¢":"centavo","∑":"soma","£":"libra","∞":"infinito","♥":"amor"},"uk":{"И":"Y","и":"y","Й":"Y","й":"y","Ц":"Ts","ц":"ts","Х":"Kh","х":"kh","Щ":"Shch","щ":"shch","Г":"H","г":"h"},"vi":{"Đ":"D","đ":"d"},"da":{"Ø":"OE","ø":"oe","Å":"AA","å":"aa","%":"procent","&":"og","|":"eller","$":"dollar","<":"mindre end",">":"større end"},"nb":{"&":"og","Å":"AA","Æ":"AE","Ø":"OE","å":"aa","æ":"ae","ø":"oe"},"it":{"&":"e"},"nl":{"&":"en"},"sv":{"&":"och","Å":"AA","Ä":"AE","Ö":"OE","å":"aa","ä":"ae","ö":"oe"}}') + + function replace (string, options) { + if (typeof string !== 'string') { + throw new Error('slugify: string argument expected') + } + + options = (typeof options === 'string') + ? {replacement: options} + : options || {} + + var locale = locales[options.locale] || {} + + var replacement = options.replacement === undefined ? '-' : options.replacement + + var trim = options.trim === undefined ? true : options.trim + + var slug = string.normalize().split('') + // replace characters based on charMap + .reduce(function (result, ch) { + var appendChar = locale[ch] || charMap[ch] || ch; + if (appendChar === replacement) { + appendChar = ' '; + } + return result + appendChar + // remove not allowed characters + .replace(options.remove || /[^\w\s$*_+~.()'"!\-:@]+/g, '') + }, ''); + + if (options.strict) { + slug = slug.replace(/[^A-Za-z0-9\s]/g, ''); + } + + if (trim) { + slug = slug.trim() + } + + // Replace spaces with replacement character, treating multiple consecutive + // spaces as a single space. + slug = slug.replace(/\s+/g, replacement); + + if (options.lower) { + slug = slug.toLowerCase() + } + + return slug + } + + replace.extend = function (customMap) { + Object.assign(charMap, customMap) + } + + return replace +})) From e73d55b2c0b2cc47c945380da4cf20ae0a6e0fd3 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sun, 7 Jul 2024 19:22:26 -0700 Subject: [PATCH 0443/2119] Perform `getDeveloperProfile` only when on puter.com --- src/dev-center/js/dev-center.js | 76 +++++++++++++++++---------------- 1 file changed, 39 insertions(+), 37 deletions(-) diff --git a/src/dev-center/js/dev-center.js b/src/dev-center/js/dev-center.js index c154f26ce3..3153f95891 100644 --- a/src/dev-center/js/dev-center.js +++ b/src/dev-center/js/dev-center.js @@ -58,7 +58,7 @@ $(document).ready(function () { $('#loading').show(); // get dev profile - setTimeout(function () { + setTimeout(async function () { puter.ui.onLaunchedWithItems(async function (items) { source_path = items[0].path; // if source_path is provided, this means that the user is creating a new app/updating an existing app @@ -71,48 +71,50 @@ $(document).ready(function () { } }) - puter.apps.getDeveloperProfile(async function (dev_profile) { - developer = dev_profile; - if (dev_profile.approved_for_incentive_program && !dev_profile.joined_incentive_program) { - $('#join-incentive-program').show(); - } + if(domain === 'puter.com'){ + puter.apps.getDeveloperProfile(async function (dev_profile) { + developer = dev_profile; + if (dev_profile.approved_for_incentive_program && !dev_profile.joined_incentive_program) { + $('#join-incentive-program').show(); + } - // show earn money c2a only if dev is not approved for incentive program or has already joined - if (!dev_profile.approved_for_incentive_program || dev_profile.joined_incentive_program) { - puter.kv.get('earn-money-c2a-closed').then((value) => { - if (value?.result || value === true || value === "true") - return; + // show earn money c2a only if dev is not approved for incentive program or has already joined + if (!dev_profile.approved_for_incentive_program || dev_profile.joined_incentive_program) { + puter.kv.get('earn-money-c2a-closed').then((value) => { + if (value?.result || value === true || value === "true") + return; - $('#earn-money').get(0).showModal(); - }); - } + $('#earn-money').get(0).showModal(); + }); + } - // get apps - puter.apps.list().then((resp) => { - apps = resp; + // show payout method tab if dev has joined incentive program + if (dev_profile.joined_incentive_program) { + $('.tab-btn[data-tab="payout-method"]').show(); + $('#payout-method-email').html(dev_profile.paypal); + } + }) + } + // get apps + puter.apps.list().then((resp) => { + apps = resp; - // hide loading - $('#loading').hide(); + // hide loading + $('#loading').hide(); - // set apps - if (apps.length > 0) { - if (activeTab === 'apps') { - $('#no-apps-notice').hide(); - $('#app-list').show(); - } - $('.app-card').remove(); - apps.forEach(app => { - $('#app-list-table > tbody').append(generate_app_card(app)); - }); - sort_apps(); - } else { - $('#no-apps-notice').show(); + // set apps + if (apps.length > 0) { + if (activeTab === 'apps') { + $('#no-apps-notice').hide(); + $('#app-list').show(); } - }) - // show payout method tab if dev has joined incentive program - if (dev_profile.joined_incentive_program) { - $('.tab-btn[data-tab="payout-method"]').show(); - $('#payout-method-email').html(dev_profile.paypal); + $('.app-card').remove(); + apps.forEach(app => { + $('#app-list-table > tbody').append(generate_app_card(app)); + }); + sort_apps(); + } else { + $('#no-apps-notice').show(); } }) }, 1000); From 10f4d7d50ce9314f9c3888c74cb17c8ebbecee98 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sun, 7 Jul 2024 22:26:32 -0400 Subject: [PATCH 0444/2119] feat: register dev center to apps --- src/backend/src/SelfHostedModule.js | 4 +++ .../database/SqliteDatabaseAccessService.js | 7 ++++- .../database/sqlite_setup/0020_dev-center.sql | 27 +++++++++++++++++++ 3 files changed, 37 insertions(+), 1 deletion(-) create mode 100644 src/backend/src/services/database/sqlite_setup/0020_dev-center.sql diff --git a/src/backend/src/SelfHostedModule.js b/src/backend/src/SelfHostedModule.js index 339298c30f..9a9625a1b7 100644 --- a/src/backend/src/SelfHostedModule.js +++ b/src/backend/src/SelfHostedModule.js @@ -74,6 +74,10 @@ class SelfHostedModule extends AdvancedBase { prefix: '/builtin/git', path: path_.resolve(__dirname, '../../../src/git/dist'), }, + { + prefix: '/builtin/dev-center', + path: path_.resolve(__dirname, '../../../src/dev-center'), + }, ], }); diff --git a/src/backend/src/services/database/SqliteDatabaseAccessService.js b/src/backend/src/services/database/SqliteDatabaseAccessService.js index d82357b26c..d157354106 100644 --- a/src/backend/src/services/database/SqliteDatabaseAccessService.js +++ b/src/backend/src/services/database/SqliteDatabaseAccessService.js @@ -42,7 +42,7 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { this.db = new Database(this.config.path); // Database upgrade logic - const TARGET_VERSION = 17; + const TARGET_VERSION = 18; if ( do_setup ) { this.log.noticeme(`SETUP: creating database at ${this.config.path}`); @@ -66,6 +66,7 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { '0017_publicdirs.sql', '0018_fix-0003.sql', '0019_fix-0016.sql', + '0020_dev-center.sql', ].map(p => path_.join(__dirname, 'sqlite_setup', p)); const fs = require('fs'); for ( const filename of sql_files ) { @@ -150,6 +151,10 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { upgrade_files.push('0019_fix-0016.sql'); } + if ( user_version <= 17 ) { + upgrade_files.push('0020_dev-center.sql'); + } + if ( upgrade_files.length > 0 ) { this.log.noticeme(`Database out of date: ${this.config.path}`); this.log.noticeme(`UPGRADING DATABASE: ${user_version} -> ${TARGET_VERSION}`); diff --git a/src/backend/src/services/database/sqlite_setup/0020_dev-center.sql b/src/backend/src/services/database/sqlite_setup/0020_dev-center.sql new file mode 100644 index 0000000000..b82c0606a3 --- /dev/null +++ b/src/backend/src/services/database/sqlite_setup/0020_dev-center.sql @@ -0,0 +1,27 @@ +INSERT INTO `apps` ( + `uid`, + `owner_user_id`, + `icon`, + `name`, + `title`, + `description`, + `index_url`, + `approved_for_listing`, + `approved_for_opening_items`, + `approved_for_incentive_program`, + `timestamp`, + `last_review`, + `godmode` +) VALUES ( + 'app-0b37f054-07d4-4627-8765-11bd23e889d4', + 1, + 'data:image/svg+xml;base64,PD94bWwgdmVyc2lvbj0iMS4wIiBlbmNvZGluZz0idXRmLTgiPz4KPHN2ZyB3aWR0aD0iMTE2IiBoZWlnaHQ9IjEzNiIgdmlld0JveD0iMCAwIDExNiAxMTYiIGZpbGw9Im5vbmUiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+CiAgPHBhdGggZD0iTSAwLjEyOSA2Mi4wODYgTCAyOC4xMjkgNzQuMDg1IEwgMjguMTI5IDEwOC4wODUgTCAwLjEyOSA5Ni42NDQgTCAwLjEyOSA2Mi4wODYgWiIgc3R5bGU9ImZpbGw6IHJnYigxNjQsIDczLCA3MSk7Ii8+CiAgPHBhdGggZD0iTSAyOS4xMjkgMTA4LjA4NSBMIDU3LjEyOSA5Ni4wODUgTCA1Ny4xMjkgNjIuMDg2IEwgMjkuMTI5IDc0LjA4NSBMIDI5LjEyOSAxMDguMDg1IFoiIHN0eWxlPSJmaWxsOiByZ2IoMTM1LCA1OCwgNTgpOyIvPgogIDxwYXRoIGQ9Ik0gMC4xMjkgNjEuMTc5IEwgMjguNjI5IDczLjA4NSBMIDU3LjI3NiA2MS4xNzkgTCAyOS4xMjkgNTAuMDg2IEwgMC4xMjkgNjEuMTc5IFoiIHN0eWxlPSJmaWxsOiByZ2IoMTk2LCA4NSwgODUpOyIvPgogIDxwYXRoIGQ9Ik0gMjkuMTI5IDE0LjA4NiBMIDU3LjEyOSAyNi4wODYgTCA1Ny4xMjkgNTkuMDg2IEwgMjkuMTI5IDQ4LjA4NiBMIDI5LjEyOSAxNC4wODYgWiIgc3R5bGU9ImZpbGw6IHJnYig0MSwgMTE1LCAyMDIpOyIvPgogIDxwYXRoIGQ9Ik0gNTguMTI5IDU5LjA4NiBMIDg3LjEyOSA0OC4wODYgTCA4Ny4xMjkgMTQuMDg2IEwgNTguMTI5IDI2LjA4NiBMIDU4LjEyOSA1OS4wODYgWiIgc3R5bGU9ImZpbGw6IHJnYigzMiwgODksIDE1OCk7Ii8+CiAgPHBhdGggZD0iTSAyOS4xMjkgMTMuMDg2IEwgNTguMTI5IDI1LjA4NiBMIDg3LjEyOSAxMy4wODYgTCA1OC4xMjkgMS4wODYgTCAyOS4xMjkgMTMuMDg2IFoiIHN0eWxlPSJmaWxsOiByZ2IoNDcsIDEzNCwgMjM2KTsiLz4KICA8cGF0aCBkPSJNIDU5LjEyOSA2Mi4wODYgTCA4Ny4xMjkgNzQuMDg1IEwgODcuMTI5IDEwOC4wODUgTCA1OS4xMjkgOTYuMDg1IEwgNTkuMTI5IDYyLjA4NiBaIiBzdHlsZT0iZmlsbDogcmdiKDM0LCAxNzksIDApOyIvPgogIDxwYXRoIGQ9Ik0gODguMTI5IDEwOC4wODUgTCAxMTYuMTI5IDk2LjE1MSBMIDExNi4xMjkgNjIuMDg2IEwgODguMTI5IDc0LjA4NSBMIDg4LjEyOSAxMDguMDg1IFoiIHN0eWxlPSJmaWxsOiByZ2IoMjYsIDEzNiwgMCk7Ii8+CiAgPHBhdGggZD0iTSA1OS4xMjkgNjEuMDg2IEwgODcuNjI5IDczLjA4NSBMIDExNi4xMjkgNjEuMDg2IEwgODcuMTI5IDUwLjA4NiBMIDU5LjEyOSA2MS4wODYgWiIgc3R5bGU9ImZpbGw6IHJnYig0MCwgMjEzLCAwKTsiLz4KICA8ZGVmcy8+Cjwvc3ZnPg==', + 'dev-center', + 'Dev Center', + 'This is the app that makes apps', + 'https://builtins.namespaces.puter.com/dev-center', + 1, 1, 0, + '2020-01-01 00:00:00', + NULL, + 0 +); From a8474054ccb7b0ee39e289f036877e4ca86c0675 Mon Sep 17 00:00:00 2001 From: FusionZhu Date: Mon, 8 Jul 2024 10:27:53 +0800 Subject: [PATCH 0445/2119] improve Chinese translation fix issue 549 --- src/gui/src/i18n/translations/zh.js | 199 ++++++++++++++++++++++++++-- 1 file changed, 189 insertions(+), 10 deletions(-) diff --git a/src/gui/src/i18n/translations/zh.js b/src/gui/src/i18n/translations/zh.js index ee730ad719..e801e00d43 100644 --- a/src/gui/src/i18n/translations/zh.js +++ b/src/gui/src/i18n/translations/zh.js @@ -16,76 +16,156 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const zh = { name: "中文", english_name: "Chinese", code: "zh", dictionary: { + about: "关于我们", + account: "账号", + account_password: "账号密码验证", access_granted_to: "访问授权给", - add_existing_account: "添加现有帐户", + add_existing_account: "添加现有帐号", all_fields_required: '所有字段都是必需的。', + allow: '允许', apply: "应用", ascending: '升序', + associated_websites: "相关网站", + auto_arrange: '自动排序', background: "背景", browse: "浏览", cancel: '取消', center: '中心', change_desktop_background: '更改桌面背景…', + change_email: "更改邮箱", change_language: "更改语言", change_password: "更改密码", + change_ui_colors: "更改界面颜色", change_username: "更改用户名", + close: '关闭', close_all_windows: "关闭所有窗口", + close_all_windows_confirm: "确定要关闭所有窗口吗?", + close_all_windows_and_log_out: '关闭窗口并退出', + change_always_open_with: "以后都这样打开此类型的文件?", color: '颜色', - confirm_account_for_free_referral_storage_c2a: '创建帐户并确认您的电子邮件地址,以获得1 GB的免费存储空间。您的朋友也将获得1 GB的免费存储空间。', + confirm: '确认', + confirm_2fa_setup: '我已完成在身份验证应用中添加代码', + confirm_2fa_recovery: '我已完成保存恢复码到安全地方', + confirm_account_for_free_referral_storage_c2a: '创建帐号并确认您的电子邮件地址,以获得1 GB的免费存储空间。您的朋友也将获得1 GB的免费存储空间。', + confirm_code_generic_incorrect: "代码不正确!", + confirm_code_generic_too_many_requests: "请求太频繁,请过几分钟后再试。", + confirm_code_generic_submit: "提交代码", + confirm_code_generic_try_again: "重试", + confirm_code_generic_title: "确认代码", + confirm_code_2fa_instruction: "请输入从身份验证应用中获取的6位数字代码", + confirm_code_2fa_submit_btn: "提交", + confirm_code_2fa_title: "请输入二次身份验证码", + confirm_delete_multiple_items: '确定要永久删除这些文件?', + confirm_delete_single_item: '确定要永久删除这个文件?', + confirm_open_apps_log_out: '还有应用未关闭,您确定现在就要退出吗?', confirm_new_password: "确认新密码", + confirm_delete_user: "确认要删除此账号?所有相关文件和数据都将被清空,一旦删除不能恢复!", + confirm_delete_user_title: "确定删除账号?", + confirm_session_revoke: "确定要撤销?", + confirm_your_email_address: "请确认您的邮箱地址", contact_us: "联系我们", + contact_us_verification_required: "需要提供有效的邮箱地址以完成此操作", contain: '包含', continue: "继续", copy: '复制', copy_link: "复制链接", copying: "复制", + copying_file: "正在复制 %%", cover: '封面', create_account: "创建帐户", create_free_account: "创建免费帐户", create_shortcut: "创建快捷方式", + credits: "特别鸣谢", current_password: "当前密码", cut: '剪切', clock: "时间", clock_visible_hide: '隐藏 - 始终隐藏', clock_visible_show: '显示 - 始终显示', clock_visible_auto: '自动 - 默认值,全屏显示', + close_all: '关闭全部', + created: '已创建', date_modified: '修改日期', + default: '默认', delete: '删除', + delete_account: "删除账号", delete_permanently: "永久删除", + deleting_file: "正在删除文件 %%", deploy_as_app: '部署为应用', descending: '降序', + desktop: '桌面', desktop_background_fit: "适合", + developers: "开发人员", dir_published_as_website: `%strong% 已发布到:`, + disable_2fa: '关闭二次认证', + disable_2fa_confirm: "您确定要关闭二次认证?", + disable_2fa_instructions: "请输入您的密码以关闭二次认证", disassociate_dir: "取消关联目录", + documents: '文档', + dont_allow: '操作不允许!', download: '下载', + download_file: '下载文件', downloading: "下载", - email: "电子邮件", - email_or_username: "电子邮件或用户名", + email: "邮箱地址", + email_change_confirmation_sent: "确认邮件已发送到您的新邮箱,请按指令完成操作", + email_invalid: '邮箱地址未验证', + email_or_username: "邮箱地址或用户名", + email_required: '请输入有效的邮箱地址', empty_trash: '清空回收站', empty_trash_confirmation: `您确定要永久删除回收站中的项目吗?`, - emptying_trash: '清空回收站…', + emptying_trash: '正在清空回收站…', + enable_2fa: '启用二次身份验证', + end_hard: "强制关闭", + end_process_force_confirm: "您确定要强制关闭此程序吗?", + end_soft: "等待响应", + enlarged_qr_code: "放大二维码", + enter_password_to_confirm_delete_user: "请输入您的密码以确认删除账号", + error_message_is_missing: "未找到错误信息", + error_unknown_cause: "发生未知错误", + error_uploading_files: "上传文件失败", + favorites: "喜欢", feedback: "反馈", feedback_c2a: "请使用下面的表格向我们发送您的反馈、评论和错误报告。", feedback_sent_confirmation: "感谢您与我们联系。如果您的帐户关联有电子邮件,我们会尽快回复您。", + fit: "适应", + folder: '文件夹', + force_quit: '强制退出', forgot_pass_c2a: "忘记密码?", from: "从", - general: "一般", + general: "常用", get_a_copy_of_on_puter: `在 Puter.com 上获取 '%%' 的副本!`, get_copy_link: '获取复制链接', hide_all_windows: "隐藏所有窗口", + home: '主页', html_document: 'HTML 文档', + hue: '色调', image: '图像', + incorrect_password: "密码不正确", invite_link: "邀请链接", + item: '项目', items_in_trash_cannot_be_renamed: `此项目无法重命名,因为它在回收站中。要重命名此项目,请先将其拖出回收站。`, jpeg_image: 'JPEG 图像', - keep_in_taskbar: '保持在任务栏', + keep_in_taskbar: '固定在任务栏', + language: "语言", + license: "许可协议", + lightness: '明亮', + link_copied: "链接已复制", + loading: '正在加载', log_in: "登录", - log_out: '登出', + log_into_another_account_anyway: '强制切换账号', + log_out: '退出', + looks_good: "看起来不错!", + manage_sessions: "会话管理", + menubar_style: "菜单条样式", + menubar_style_desktop: "桌面", + menubar_style_system: "系统", + menubar_style_window: "窗口", + modified: '已修改', move: '移动', moving_file: "移动 %%", my_websites: "我的网站", @@ -97,9 +177,11 @@ const zh = { name_must_be_string: "名称只能是字符串。", name_too_long: `名称不能超过 %% 个字符。`, new: '新', + new_email: '新邮箱', new_folder: '新文件夹', new_password: "新密码", new_username: "新用户名", + no: '取消', no_dir_associated_with_site: '此地址没有关联的目录。', no_websites_published: "您尚未发布任何网站。", ok: '好的', @@ -107,20 +189,45 @@ const zh = { open_in_new_tab: "在新标签页中打开", open_in_new_window: "在新窗口中打开", open_with: "打开方式", + original_name: '原名', + original_path: '原路径', + oss_code_and_content: "开源软件和内容", password: "密码", password_changed: "密码已更改。", + password_recovery_rate_limit: "操作太频繁请几分钟后再试,请不要频繁刷新页面以避免再次遇到此问题", + password_recovery_token_invalid: "密码恢复令牌已过期", + password_recovery_unknown_error: "发生未知错误,请稍后再试", + password_required: '请输入密码', + password_strength_error: "密码必须包含至少8个字符且至少含有数字、大写字母、小写字母、特殊符号其中一种。", passwords_do_not_match: '`新密码` 和 `确认新密码` 不匹配。', paste: '粘贴', paste_into_folder: "粘贴到文件夹", + path: '路径', + personalization: "个性化", pick_name_for_website: "为您的网站选择一个名称:", picture: "图片", + pictures: '图片', + plural_suffix: '', powered_by_puter_js: `由 {{link=docs}}Puter.js{{/link}} 提供支持`, preparing: "准备中...", preparing_for_upload: "准备上传...", + print: '打印', + privacy: "隐私", + proceed_to_login: '完成登录', + proceed_with_account_deletion: "完成账号删除操作", + process_status_initializing: "初始化", + process_status_running: "运行中", + process_type_app: '应用', + process_type_init: '初始', + process_type_ui: '界面', properties: "属性", + public: '公开', publish: "发布", publish_as_website: '发布为网站', + puter_description: `Puter 是一个隐私优先的个人云,可将您的所有文件、应用程序和游戏保存在一个安全的地方,方便随时随地访问。`, + reading_file: "正在读取 %strong%", recent: "最近", + recommended: "推荐", recover_password: "找回密码", refer_friends_c2a: "每个创建并确认 Puter 帐户的朋友都会为您获得 1 GB。您的朋友也将获得 1 GB!", refer_friends_social_media_c2a: `在 Puter.com 上获取 1 GB 的免费存储空间!`, @@ -129,43 +236,115 @@ const zh = { remove_from_taskbar:'从任务栏中删除', rename: '重命名', repeat: '重复', + replace: '替换', + replace_all: '全部替换', resend_confirmation_code: "重新发送确认码", + reset_colors: "重置颜色", + restart_puter_confirm: "确定要重启Puter?", restore: "还原", + save: '保存', + saturation: '饱和度', + save_account: '保存账号', save_account_to_get_copy_link: "请创建帐户以继续。", save_account_to_publish: '请创建帐户以继续。', + save_session: '保存会话', save_session_c2a: '创建帐户以保存当前会话,避免丢失工作。', scan_qr_c2a: '扫描下面的代码以从其他设备登录此会话', + scan_qr_2fa: '请使用身份认证应用扫描二维码', + scan_qr_generic: '请使用您的手机或其它设备扫描二维码', + search: '查找', + seconds: '秒', + security: "安全", select: "选择", + selected: '已选择', select_color: '选择颜色…', + sessions: "会话", send: "发送", send_password_recovery_email: "发送密码恢复电子邮件", - session_saved: "感谢您创建帐户。此会话已保存。", + session_saved: "感谢您创建帐号。此会话已保存。", + settings: "设置", set_new_password: "设置新密码", + share: "分享", share_to: "分享到", + share_with: "分享:", + shortcut_to: "快捷方式", show_all_windows: "显示所有窗口", show_hidden: '显示隐藏', sign_in_with_puter: "使用 Puter 登录", sign_up: "注册", signing_in: "登录中…", size: '大小', + skip: '跳过', + something_went_wrong: "操作出差了!", sort_by: '排序方式', start: '开始', + status: "状态", + storage_usage: "存储使用量", + storage_puter_used: '被Puter使用', taking_longer_than_usual: '需要的时间比平时长一点。请稍等...', + task_manager: "任务管理器", + taskmgr_header_name: "状态", + taskmgr_header_status: "名称", + taskmgr_header_type: "类型", + terms: "条款", text_document: '文本文档', tos_fineprint: `点击“创建免费帐户”即表示您同意 Puter 的 {{link=terms}}服务条款{{/link}} 和 {{link=privacy}}隐私政策{{/link}}。`, + transparency: "透明度", trash: '回收站', + two_factor: '二次身份验证', + two_factor_disabled: '关闭二次身份验证', + two_factor_enabled: '启用二次身份验证', type: '类型', + type_confirm_to_delete_account: "请输入 confirm 以确认删除账号.", + ui_colors: "界面颜色", + ui_manage_sessions: "会话管理", + ui_revoke: "取消", undo: '撤销', + unlimited: '无限制', unzip: "解压缩", upload: '上传', upload_here: '在此上传', + usage: '用量', username: "用户名", username_changed: '用户名已成功更新。', - visibility: "可见性", + username_required: '请输入用户名', versions: "版本", + videos: '视频', + visibility: "可见性", + yes: '确定', yes_release_it: '是的,释放它', you_have_been_referred_to_puter_by_a_friend: "您已经被朋友推荐到 Puter!", zip: "压缩", + zipping_file: "正在压缩 %strong%", + + // === 2FA Setup === + setup2fa_1_step_heading: '打开你的身份验证应用', + setup2fa_1_instructions: ` + 你可以使用任何一种支持TOTP(基于时间的一次性密码生成)协议的应用. + 有很多应用可以选择,如果您不确定用哪一个可以使用 + Authy + 支持安卓和IOS设备 + `, + setup2fa_2_step_heading: '扫描二维码', + setup2fa_3_step_heading: '输入6位数字代码', + setup2fa_4_step_heading: '复制您的恢复码', + setup2fa_4_instructions: ` + 恢复码是在您无法使用手机或身份验证应用时唯一的访问账号凭证。 + 请妥善保存以免丢失 + `, + setup2fa_5_step_heading: '确认二次认证步骤', + setup2fa_5_confirmation_1: '我已经将恢复码妥善保存', + setup2fa_5_confirmation_2: '我已准备好启用二次认证', + setup2fa_5_button: '启用二次认证', + + // === 2FA Login === + login2fa_otp_title: '输入二次认证代码', + login2fa_otp_instructions: '请输入从身份验证应用获取的6位数字代码', + login2fa_recovery_title: '请输入恢复码', + login2fa_recovery_instructions: '请输入恢复码以访问您的账号', + login2fa_use_recovery_code: '使用恢复码', + login2fa_recovery_back: '后退', + login2fa_recovery_placeholder: '********', } }; From 283f409a662d126e7f3ce811f1467ac6fab9a522 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sun, 7 Jul 2024 22:35:45 -0400 Subject: [PATCH 0446/2119] fix: fix owner ids for default apps --- .../services/database/SqliteDatabaseAccessService.js | 7 ++++++- .../database/sqlite_setup/0021_app-owner-id.sql | 11 +++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 src/backend/src/services/database/sqlite_setup/0021_app-owner-id.sql diff --git a/src/backend/src/services/database/SqliteDatabaseAccessService.js b/src/backend/src/services/database/SqliteDatabaseAccessService.js index d157354106..f920df1e61 100644 --- a/src/backend/src/services/database/SqliteDatabaseAccessService.js +++ b/src/backend/src/services/database/SqliteDatabaseAccessService.js @@ -42,7 +42,7 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { this.db = new Database(this.config.path); // Database upgrade logic - const TARGET_VERSION = 18; + const TARGET_VERSION = 19; if ( do_setup ) { this.log.noticeme(`SETUP: creating database at ${this.config.path}`); @@ -67,6 +67,7 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { '0018_fix-0003.sql', '0019_fix-0016.sql', '0020_dev-center.sql', + '0021_app-owner-id.sql', ].map(p => path_.join(__dirname, 'sqlite_setup', p)); const fs = require('fs'); for ( const filename of sql_files ) { @@ -155,6 +156,10 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { upgrade_files.push('0020_dev-center.sql'); } + if ( user_version <= 18 ) { + upgrade_files.push('0021_app-owner-id.sql'); + } + if ( upgrade_files.length > 0 ) { this.log.noticeme(`Database out of date: ${this.config.path}`); this.log.noticeme(`UPGRADING DATABASE: ${user_version} -> ${TARGET_VERSION}`); diff --git a/src/backend/src/services/database/sqlite_setup/0021_app-owner-id.sql b/src/backend/src/services/database/sqlite_setup/0021_app-owner-id.sql new file mode 100644 index 0000000000..36196a96fd --- /dev/null +++ b/src/backend/src/services/database/sqlite_setup/0021_app-owner-id.sql @@ -0,0 +1,11 @@ +-- fixing owner IDs for default apps; +-- they should all be owned by 'default_user' + +UPDATE `apps` SET `owner_user_id`=1 WHERE `uid` IN +( + 'app-7870be61-8dff-4a99-af64-e9ae6811e367', + 'app-3920851d-bda8-479b-9407-8517293c7d44', + 'app-5584fbf7-ed69-41fc-99cd-85da21b1ef51', + 'app-11edfba2-1ed3-4e22-8573-47e88fb87d70', + 'app-7bdca1a4-6373-4c98-ad97-03ff2d608ca1' +); From fd39f92ea6c2602515ac31f810656f1a0659c90f Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sun, 7 Jul 2024 19:44:28 -0700 Subject: [PATCH 0447/2119] get username and appID from puter.js rather than iframe URL in Dev Center --- src/dev-center/js/dev-center.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/dev-center/js/dev-center.js b/src/dev-center/js/dev-center.js index 3153f95891..168c9da82e 100644 --- a/src/dev-center/js/dev-center.js +++ b/src/dev-center/js/dev-center.js @@ -23,7 +23,7 @@ let source_path let apps = []; let sortBy = 'created_at'; let sortDirection = 'desc'; -const dev_center_uid = 'app-240a43f4-43b1-49bc-b9fc-c8ae719dab77'; +const dev_center_uid = puter.appID; let developer; let activeTab = 'apps'; let currently_editing_app; @@ -33,14 +33,16 @@ let search_query; const deploying_spinner = ``; const loading_spinner = ``; const drop_area_placeholder = `

Drop your app folder and files here to deploy.

HTML, JS, CSS, ...

`; -const index_missing_error = `Please upload an 'index.html' file or if you're uploading a directory, make sure it contains an 'index.html' file at its root.` +const index_missing_error = `Please upload an 'index.html' file or if you're uploading a directory, make sure it contains an 'index.html' file at its root.`; // authUsername -if (URLParams.has('puter.auth.username')) { - authUsername = URLParams.get('puter.auth.username'); -} else { - //todo error and terminate -} +(async () => { + let user = await puter.auth.getUser(); + + if (user?.username) { + authUsername = user.username; + } +})() // source_path if (URLParams.has('source_path')) { From 4078a63fe1707ed5571387bf995247a113f44ee2 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sun, 7 Jul 2024 23:16:19 -0400 Subject: [PATCH 0448/2119] tweak: maximize dev center on start --- .../src/services/database/SqliteDatabaseAccessService.js | 7 ++++++- .../services/database/sqlite_setup/0022_dev-center-max.sql | 4 ++++ 2 files changed, 10 insertions(+), 1 deletion(-) create mode 100644 src/backend/src/services/database/sqlite_setup/0022_dev-center-max.sql diff --git a/src/backend/src/services/database/SqliteDatabaseAccessService.js b/src/backend/src/services/database/SqliteDatabaseAccessService.js index f920df1e61..7472d15700 100644 --- a/src/backend/src/services/database/SqliteDatabaseAccessService.js +++ b/src/backend/src/services/database/SqliteDatabaseAccessService.js @@ -42,7 +42,7 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { this.db = new Database(this.config.path); // Database upgrade logic - const TARGET_VERSION = 19; + const TARGET_VERSION = 20; if ( do_setup ) { this.log.noticeme(`SETUP: creating database at ${this.config.path}`); @@ -68,6 +68,7 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { '0019_fix-0016.sql', '0020_dev-center.sql', '0021_app-owner-id.sql', + '0022_dev-center-max.sql', ].map(p => path_.join(__dirname, 'sqlite_setup', p)); const fs = require('fs'); for ( const filename of sql_files ) { @@ -160,6 +161,10 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { upgrade_files.push('0021_app-owner-id.sql'); } + if ( user_version <= 19 ) { + upgrade_files.push('0022_dev-center-max.sql'); + } + if ( upgrade_files.length > 0 ) { this.log.noticeme(`Database out of date: ${this.config.path}`); this.log.noticeme(`UPGRADING DATABASE: ${user_version} -> ${TARGET_VERSION}`); diff --git a/src/backend/src/services/database/sqlite_setup/0022_dev-center-max.sql b/src/backend/src/services/database/sqlite_setup/0022_dev-center-max.sql new file mode 100644 index 0000000000..8aec8354d0 --- /dev/null +++ b/src/backend/src/services/database/sqlite_setup/0022_dev-center-max.sql @@ -0,0 +1,4 @@ +-- fixing owner IDs for default apps; +-- they should all be owned by 'default_user' + +UPDATE `apps` SET `maximize_on_start`=1 WHERE `uid`='app-0b37f054-07d4-4627-8765-11bd23e889d4'; From 594424444a57c277a22d51ce67522b2193d33a56 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sun, 7 Jul 2024 20:43:57 -0700 Subject: [PATCH 0449/2119] make Dev Center aware of the origin of the host environment --- src/dev-center/index.html | 2 +- src/dev-center/js/dev-center.js | 34 +++++++++++++++++++++++++------ src/gui/src/helpers/launch_app.js | 8 ++++++++ 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/src/dev-center/index.html b/src/dev-center/index.html index 26e191fd13..e69ecda565 100644 --- a/src/dev-center/index.html +++ b/src/dev-center/index.html @@ -245,7 +245,7 @@

My Apps

- + diff --git a/src/dev-center/js/dev-center.js b/src/dev-center/js/dev-center.js index 168c9da82e..b15da104fd 100644 --- a/src/dev-center/js/dev-center.js +++ b/src/dev-center/js/dev-center.js @@ -56,6 +56,28 @@ if (URLParams.has('puter.domain')) { domain = URLParams.get('puter.domain') } +// static hosting domain +let static_hosting_domain = 'puter.site'; +if(domain === 'puter.localhost'){ + static_hosting_domain = 'site.puter.localhost'; +} + +if (URLParams.has('puter.port') && URLParams.get('puter.port')) { + static_hosting_domain = static_hosting_domain + `:` + URLParams.get('puter.port'); +} + +// protocol +let protocol = 'https'; +if (URLParams.has('puter.protocol')) { + protocol = URLParams.get('puter.protocol'); +} + +// port +let port = ''; +if (URLParams.has('puter.port') && URLParams.get('puter.port')) { + port = URLParams.get('puter.port'); +} + $(document).ready(function () { $('#loading').show(); @@ -244,7 +266,7 @@ async function create_app(title, source_path = null, items = null) { puter.apps.update(app.name, { title: title, name: name, - indexURL: source_path ? `https://${name}.puter.site` : 'https://dev-center.puter.com/coming-soon.html', + indexURL: source_path ? protocol + `://${name}.` + static_hosting_domain : 'https://dev-center.puter.com/coming-soon.html', icon: icon, description: ' ', maximizeOnStart: false, @@ -375,7 +397,7 @@ $(document).on('click', '.delete-app', async function (e) { // generate app link function applink(app) { - return `https://${domain}/app/${app.name}`; + return protocol + `://${domain}${ port ? ':' + port : '' }/app/${app.name}`; } //---------------------------------------------------- @@ -1279,7 +1301,7 @@ window.deploy = async function (app, items) { puter.hosting.create(hostname, appdata_dir.path).then(async (res) => { // TODO this endpoint needs to be able to update only the specified fields puter.apps.update(currently_editing_app.name, { - indexURL: `https://${hostname}.puter.site`, + indexURL: protocol + `://${hostname}.` + static_hosting_domain, title: currently_editing_app.title, name: currently_editing_app.name, icon: currently_editing_app.icon, @@ -1289,7 +1311,7 @@ window.deploy = async function (app, items) { filetypeAssociations: currently_editing_app.filetype_associations, }) // set the 'Index URL' field for the 'Settings' tab - $('#edit-app-index-url').val(`https://${hostname}.puter.site`); + $('#edit-app-index-url').val(protocol + `://${hostname}.` + static_hosting_domain); // show success message $('.deploy-success-msg').show(); // reset drop area @@ -1323,7 +1345,7 @@ window.deploy = async function (app, items) { puter.hosting.create(hostname, appdata_dir.path).then(async (res) => { // TODO this endpoint needs to be able to update only the specified fields puter.apps.update(currently_editing_app.name, { - indexURL: `https://${hostname}.puter.site`, + indexURL: protocol + `://${hostname}.` + static_hosting_domain, title: currently_editing_app.title, name: currently_editing_app.name, icon: currently_editing_app.icon, @@ -1333,7 +1355,7 @@ window.deploy = async function (app, items) { filetypeAssociations: currently_editing_app.filetype_associations, }) // set the 'Index URL' field for the 'Settings' tab - $('#edit-app-index-url').val(`https://${hostname}.puter.site`); + $('#edit-app-index-url').val(protocol + `://${hostname}.` + static_hosting_domain); // show success message $('.deploy-success-msg').show(); // reset drop area diff --git a/src/gui/src/helpers/launch_app.js b/src/gui/src/helpers/launch_app.js index 79adde6153..d6dc6553fe 100644 --- a/src/gui/src/helpers/launch_app.js +++ b/src/gui/src/helpers/launch_app.js @@ -224,6 +224,14 @@ const launch_app = async (options)=>{ iframe_url.searchParams.append('puter.domain', window.app_domain); + // get URL parts + const url = new URL(window.location.href); + + iframe_url.searchParams.append('puter.origin', url.origin); + iframe_url.searchParams.append('puter.hostname', url.hostname); + iframe_url.searchParams.append('puter.port', url.port); + iframe_url.searchParams.append('puter.protocol', url.protocol.slice(0, -1)); + if(window.api_origin) iframe_url.searchParams.append('puter.api_origin', window.api_origin); From 6603c450936730f2aa18c4382b2ae6b8da4ebcda Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 8 Jul 2024 00:31:02 -0400 Subject: [PATCH 0450/2119] sync: update gui paths in Dockerfile --- Dockerfile | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/Dockerfile b/Dockerfile index 6d4e320fbd..8a6f8c489d 100644 --- a/Dockerfile +++ b/Dockerfile @@ -28,7 +28,7 @@ RUN npm cache clean --force \ && npm ci # Run the build command if necessary -RUN npm run build +RUN cd src/gui && npm run build && cd - # Production stage FROM node:21-alpine @@ -46,7 +46,7 @@ RUN mkdir -p /opt/puter/app WORKDIR /opt/puter/app # Copy built artifacts and necessary files from the build stage -COPY --from=build /app/dist ./dist +COPY --from=build /app/src/gui/dist ./dist COPY --from=build /app/node_modules ./node_modules COPY . . From 94c0449437ce4cb26d00a15a3f277bc7b09367b4 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 8 Jul 2024 00:31:18 -0400 Subject: [PATCH 0451/2119] fix: docker runtime fail because stdout columns --- src/backend/src/fun/dev-console-ui-utils.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/backend/src/fun/dev-console-ui-utils.js b/src/backend/src/fun/dev-console-ui-utils.js index 0956ae5e4a..c30a358c82 100644 --- a/src/backend/src/fun/dev-console-ui-utils.js +++ b/src/backend/src/fun/dev-console-ui-utils.js @@ -15,6 +15,23 @@ const surrounding_box = (col, lines, lengths) => { lengths = lines.map(line => stringLength(line)); } + const probably_docker = (() => { + try { + // I don't know what the value of this is in Docker, + // but what I do know is it'll throw an exception + // when I do this to it. + Array(process.stdout.columns - 1); + } catch (e) { + return true; + } + })(); + + if ( probably_docker ) { + // We just won't try to render any decoration on Docker; + // it's not worth potentially breaking the output. + return; + } + const max_length = process.stdout.columns - 6; // const max_length = Math.max(...lengths); From 1f8cd7f613e277138da9e51d629928a19143e32d Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sun, 7 Jul 2024 21:36:37 -0700 Subject: [PATCH 0452/2119] Create .eslintignore --- src/dev-center/.eslintignore | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 src/dev-center/.eslintignore diff --git a/src/dev-center/.eslintignore b/src/dev-center/.eslintignore new file mode 100644 index 0000000000..4ba8c1b3ac --- /dev/null +++ b/src/dev-center/.eslintignore @@ -0,0 +1,2 @@ +js/slugify.js +js/html-entities.js \ No newline at end of file From 58ff7c279d1ddc0e1947b6cb2cdddd145434818b Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sun, 7 Jul 2024 21:38:39 -0700 Subject: [PATCH 0453/2119] Update .eslintignore --- src/dev-center/.eslintignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dev-center/.eslintignore b/src/dev-center/.eslintignore index 4ba8c1b3ac..d79de46098 100644 --- a/src/dev-center/.eslintignore +++ b/src/dev-center/.eslintignore @@ -1,2 +1,2 @@ -js/slugify.js -js/html-entities.js \ No newline at end of file +./js/slugify.js +./js/html-entities.js \ No newline at end of file From cb8f0aa35951763f082befc8bfda495c9cd41963 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sun, 7 Jul 2024 21:40:53 -0700 Subject: [PATCH 0454/2119] wtf is wrong with eslint?! --- src/dev-center/.eslintignore | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/dev-center/.eslintignore b/src/dev-center/.eslintignore index d79de46098..9b9590a508 100644 --- a/src/dev-center/.eslintignore +++ b/src/dev-center/.eslintignore @@ -1,2 +1,2 @@ -./js/slugify.js -./js/html-entities.js \ No newline at end of file +/js/slugify.js +/js/html-entities.js \ No newline at end of file From 1f3eb08a706cfad67fb0d16141233df17f192d96 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 8 Jul 2024 00:53:40 -0400 Subject: [PATCH 0455/2119] chore: remove eslint --- .github/workflows/lint.yml | 33 --------------------------------- 1 file changed, 33 deletions(-) delete mode 100644 .github/workflows/lint.yml diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml deleted file mode 100644 index c0976139a3..0000000000 --- a/.github/workflows/lint.yml +++ /dev/null @@ -1,33 +0,0 @@ -# Lint PRs and pushes to the main branch - -name: Lint - -env: - NODE_VERSION: 21.x - # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ - -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] - -jobs: - build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v4 - - name: Use Node.js ${{ env.NODE_VERSION }} - uses: actions/setup-node@v4 - with: - node-version: ${{ env.NODE_VERSION }} - cache: 'npm' - cache-dependency-path: ./package-lock.json - - name: Install dependencies - run: npm ci - - name: Run ESLint - run: npx eslint - - name: Check translations - if: '!cancelled()' - run: npm run check-translations From 86fd2f4bc42c8bb953aea2f55fbe71b3e388efef Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Mon, 8 Jul 2024 10:06:09 -0700 Subject: [PATCH 0456/2119] Delete src/dev-center/.eslintignore --- src/dev-center/.eslintignore | 2 -- 1 file changed, 2 deletions(-) delete mode 100644 src/dev-center/.eslintignore diff --git a/src/dev-center/.eslintignore b/src/dev-center/.eslintignore deleted file mode 100644 index 9b9590a508..0000000000 --- a/src/dev-center/.eslintignore +++ /dev/null @@ -1,2 +0,0 @@ -/js/slugify.js -/js/html-entities.js \ No newline at end of file From c84e15ba20ce66873e84404eae97f2983f2b8e2f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" <41898282+github-actions[bot]@users.noreply.github.com> Date: Mon, 8 Jul 2024 04:33:23 +0000 Subject: [PATCH 0457/2119] chore(main): release 1.0.0 --- CHANGELOG.md | 147 ++++++++++++++++++++++++++++++++++++++++++++++ package-lock.json | 4 +- package.json | 2 +- 3 files changed, 150 insertions(+), 3 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index fd4860f7b9..5e14968776 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,152 @@ # Changelog +## 1.0.0 (2024-07-08) + + +### Features + +* add (pt-br) translation for system settings. ([77211c4](https://github.com/HeyPuter/puter/commit/77211c4f71b0285fb3060f7e5c8d493b4d7c4f0c)) +* add /group/list endpoint ([d55f38c](https://github.com/HeyPuter/puter/commit/d55f38ca68899c3574cfe328d2b206b1143ff0d4)) +* add /share/file-by-username endpoint ([5d214c7](https://github.com/HeyPuter/puter/commit/5d214c7b52887b594af6be497f1892baf7d77679)) +* add /sharelink/request endpoint ([742f625](https://github.com/HeyPuter/puter/commit/742f625309f9f4cfa70cf7d2fe5b03fd164913ea)) +* add /show urls ([079e25a](https://github.com/HeyPuter/puter/commit/079e25a9fe8e179f26d72378856058eb656e2314)) +* add app metadata ([f7216b9](https://github.com/HeyPuter/puter/commit/f7216b95672b38802b288ef5b022e947017ff311)) +* add appdata permission (if applicable) on app share ([9751fd9](https://github.com/HeyPuter/puter/commit/9751fd92a50e75385cffed0ca847d5076ba98c92)) +* add cookie for site token ([a813fbb](https://github.com/HeyPuter/puter/commit/a813fbbb88bcfb8b9a61976e2a4fc4aab943fc88)) +* add cross-server event broadcasting ([1207a15](https://github.com/HeyPuter/puter/commit/1207a158bdc88a90b14d31d03387ce353c176a9c)) +* add debug mod ([16b1649](https://github.com/HeyPuter/puter/commit/16b1649ff62fd87a4dda5d2e1c68941c864c5da4)) +* add endpoints for share tokens ([301ffaf](https://github.com/HeyPuter/puter/commit/301ffaf61dbb4fca1a855650ab80707ae6d9f602)) +* Add exit status code to apps ([7674da4](https://github.com/HeyPuter/puter/commit/7674da4cd225bcad34079251c5600fc32e32248b)) +* add external mod loading ([eb05fbd](https://github.com/HeyPuter/puter/commit/eb05fbd2dc4877553b5118a069a9afdc32bea137)) +* add group management endpoints ([4216346](https://github.com/HeyPuter/puter/commit/4216346384d90dcba429dbcb175e6f86482d19f4)) +* add group permission endpoints ([c374b0c](https://github.com/HeyPuter/puter/commit/c374b0cbca761e7c8a47d56a09551f2e9378066a)) +* add mark-read endpoint ([0101f42](https://github.com/HeyPuter/puter/commit/0101f425d480705c20df4919a76f66e987f5790f)) +* add permission rewriter for app by name ([16c4907](https://github.com/HeyPuter/puter/commit/16c4907be592dae31ed3c1aa3fac3b9655255d6f)) +* add protected apps ([f2f3d6f](https://github.com/HeyPuter/puter/commit/f2f3d6ff460932698fb8da7309fbce3e96132950)) +* add protected subdomains ([86fca17](https://github.com/HeyPuter/puter/commit/86fca17fb17c0c24397c29b49b133deadea1de8b)) +* add querystring-informed errors ([e7c0b83](https://github.com/HeyPuter/puter/commit/e7c0b8320a6829315d9154d6d513bab4491c47ea)) +* add readdir delegate for shares in a user directory ([8424d44](https://github.com/HeyPuter/puter/commit/8424d446099ac30ccf829c57d43eef1f235618e4)) +* add readdir delegate for sharing user homedirs ([19a5eb0](https://github.com/HeyPuter/puter/commit/19a5eb00763f3ac31df8483fb59cb7a96c448745)) +* add service for notifications ([a1e6887](https://github.com/HeyPuter/puter/commit/a1e6887bf93da21b9482040b3e30ee083fb23477)) +* add service to test file share logic ([332371f](https://github.com/HeyPuter/puter/commit/332371fccb198462948a440419adc7a26d671a23)) +* add share list to stat ([8c49ba2](https://github.com/HeyPuter/puter/commit/8c49ba2553ce6bee20eb5b6f2721bc80f639e98a)) +* add share service and share-by-email to /share ([db5990a](https://github.com/HeyPuter/puter/commit/db5990a98935817c0e16d30e921bb99c57a98fc8)) +* add subdomain permission (if applicable) on app share ([13e2f72](https://github.com/HeyPuter/puter/commit/13e2f72c9f33f485570f13f45341246b1a05879f)) +* add user-group permission check ([0014940](https://github.com/HeyPuter/puter/commit/00149402e041443aa3ac571fbe97a9a85f95564b)) +* **backend:** add script service ([30550fc](https://github.com/HeyPuter/puter/commit/30550fcddda18469735499546de502d29b85e2ad)) +* **backend:** Add tab completion to server console command arguments ([fa81dca](https://github.com/HeyPuter/puter/commit/fa81dca9507b7fa0f82099b75f2ab89c865626ac)) +* **backend:** Add tab-completion to server console command names ([e1e76c6](https://github.com/HeyPuter/puter/commit/e1e76c6be71fdeb3b6246307b626734d8dc26f86)) +* **backend:** add tip of day ([2d8e624](https://github.com/HeyPuter/puter/commit/2d8e6240c61dc6301f49cbdcd1c3b04736f9ca93)) +* **backend:** allow services to provide user properties ([522664d](https://github.com/HeyPuter/puter/commit/522664d415c33342500defec309c2ff15bc94804)) +* **backend:** allow services to provide whoami values ([fccabf1](https://github.com/HeyPuter/puter/commit/fccabf1bc0c4418f3599222616dd63bf98c14fe1)) +* **backend:** improve logger and reduce logs ([4bdad75](https://github.com/HeyPuter/puter/commit/4bdad75766d0617a164024b39b79bf5373c495a6)) +* Display app icon and description in embeds ([ef298ce](https://github.com/HeyPuter/puter/commit/ef298ce3aa3ce90224e883fb0ba33f9cd3a3da44)) +* get first test working on share-test service ([88d6bee](https://github.com/HeyPuter/puter/commit/88d6bee9546f36d689c53ec7fe95f01f772f5211)) +* **git:** Add --color and --no-color options ([d6dd1a5](https://github.com/HeyPuter/puter/commit/d6dd1a5bb0a2b2bba2cfe86d2e51ff2a6e42841c)) +* **git:** Add a --debug option, which sets the DEBUG global ([fa3df72](https://github.com/HeyPuter/puter/commit/fa3df72f6ed2d45a440ebc2aacbbae67bf042478)) +* **git:** Add authentication to clone, fetch, and pull. ([364d580](https://github.com/HeyPuter/puter/commit/364d580ff896691ee70d3735f495c720651a9f41)) +* **git:** Add diff display to `show` and `log` subcommands ([3cad1ec](https://github.com/HeyPuter/puter/commit/3cad1ec436f99a78f782ab9576325d4341284964)) +* **git:** Add start-revision and file arguments to `git log` ([49c2f16](https://github.com/HeyPuter/puter/commit/49c2f163515d2130c17a6f6a6a16bc27ea69336a)) +* **git:** Allow checking out a commit instead of a branch ([057b3ac](https://github.com/HeyPuter/puter/commit/057b3acf00af49c005b9bf7069c5d22983a32e1e)) +* **git:** Color output for `git status` files ([bab5204](https://github.com/HeyPuter/puter/commit/bab5204209aa2efc0c053643677a78db6ede0929)) +* **git:** Display file contents as a string for `git show FILE_OID` ([a680371](https://github.com/HeyPuter/puter/commit/a68037111a04580cfa2688694a68ef6ac7a495fa)) +* **git:** Display ref names in `git log` and `git show` ([45cdfcb](https://github.com/HeyPuter/puter/commit/45cdfcb5bfa66937b33054a127e0b17001f3faa4)) +* **git:** Format output closer to canonical git ([60976b1](https://github.com/HeyPuter/puter/commit/60976b1ed61984d9d290f3a0ae99dd97632e9909)) +* **git:** Handle detached HEAD in `git status` and `git branch --list` ([2c9b1a3](https://github.com/HeyPuter/puter/commit/2c9b1a3ffc3d5e282ffe5b83a86314e99445bbc6)) +* **git:** Implement `git branch` ([ad4f132](https://github.com/HeyPuter/puter/commit/ad4f13255d52f8226f22800c16b388cf0e6384d7)) +* **git:** Implement `git checkout` ([35e4453](https://github.com/HeyPuter/puter/commit/35e4453930bc4e151887f83c97efec19cc15da70)) +* **git:** Implement `git cherry-pick` ([2e4259d](https://github.com/HeyPuter/puter/commit/2e4259d267b3cfafd5cefc57a02643c6432fec4d)) +* **git:** Implement `git clone` ([95c8235](https://github.com/HeyPuter/puter/commit/95c8235a4a1fea39a46c40df04cb1004a2fe7b23)) +* **git:** Implement `git diff` ([622b6a9](https://github.com/HeyPuter/puter/commit/622b6a9b921c3c03efc0b519c9a26c6701d80e50)) +* **git:** Implement `git fetch` ([98a4b9e](https://github.com/HeyPuter/puter/commit/98a4b9ede39b94c0c6b6b8345d7551359961186a)) +* **git:** Implement `git pull` ([eb2b6a0](https://github.com/HeyPuter/puter/commit/eb2b6a08b03cee0612885412cd4b03c9564044e3)) +* **git:** Implement `git push` ([8c70229](https://github.com/HeyPuter/puter/commit/8c70229a188b743220db076a740a992fd7971301)) +* **git:** Implement `git remote` ([43ce0d5](https://github.com/HeyPuter/puter/commit/43ce0d5b45d4eb4f296afcaaa1ecadc125c53e89)) +* **git:** Implement `git restore` ([4ba8a32](https://github.com/HeyPuter/puter/commit/4ba8a32b45d395f28433572db5644d630776789e)) +* **git:** Make `git add` work for deleted files ([9551544](https://github.com/HeyPuter/puter/commit/955154468f48e45028dad2e916708d6a763affad)) +* **git:** Make shorten_hash() guaranteed to produce a unique hash ([dd10a37](https://github.com/HeyPuter/puter/commit/dd10a377493c0d8f10a1ac8779dc27f3f3bf6c37)) +* **git:** Resolve more forms of commit reference ([b6906bb](https://github.com/HeyPuter/puter/commit/b6906bbcaaa50fc8a8c60beb6d2d38bcb7dda758)) +* **git:** Understand references like `HEAD^` and `main~3` ([711dbc0](https://github.com/HeyPuter/puter/commit/711dbc0d2fde9c2ddc6c86f64fb4caa7837c9dcb)) +* implicit access from apps to shared appdata dirs ([31d4eb0](https://github.com/HeyPuter/puter/commit/31d4eb090efb340fdfb7cb6b751145e859624eeb)) +* introduce notification selection via driver ([c5334b0](https://github.com/HeyPuter/puter/commit/c5334b0e19cf9762f536ec482c3ff872e9c12399)) +* multi-recipient multi-file share endpoint ([846fdc2](https://github.com/HeyPuter/puter/commit/846fdc20d4a887a1f8a4f3bda4fafe41efab2733)) +* **parsely:** Add a fail() parser ([5656d9d](https://github.com/HeyPuter/puter/commit/5656d9d42f76202a534ad640d3a4e287e0e40418)) +* **parsely:** Add stringUntil() parser ([d46b043](https://github.com/HeyPuter/puter/commit/d46b043c5d16f1205d61de3f3ba43ed8ad7bff93)) +* **phoenix:** Add --dump and --file options to sed ([f250f86](https://github.com/HeyPuter/puter/commit/f250f86446a506f24fa2ad396328e3a2212a68d0)) +* **phoenix:** Add more commands to sed, including labels and branching ([306014a](https://github.com/HeyPuter/puter/commit/306014adc77a7ca155feb95d1146cb46ee075b52)) +* **phoenix:** Expose parsed arg tokens to apps that request them ([4067c82](https://github.com/HeyPuter/puter/commit/4067c82486c99cad20f41927ad39ebea438b717f)) +* **phoenix:** Implement an `exit` builtin ([3184d34](https://github.com/HeyPuter/puter/commit/3184d3482c7b95c0fd1fc0745555ff82fc9a8c99)) +* **phoenix:** Implement parsing of sed scripts ([0d4f907](https://github.com/HeyPuter/puter/commit/0d4f907b6675b15bd50a55f50aa28f0803b18b7b)) +* **phoenix:** Make `clear` clear scrollback unless `-x` is given ([75a989a](https://github.com/HeyPuter/puter/commit/75a989a7b69bfdfdf69e5f0365027c5b27d8bfc6)) +* **Phoenix:** Pass command line arguments and ENV when launching apps ([8f1c4fc](https://github.com/HeyPuter/puter/commit/8f1c4fcda98e72a7b970e8c6fc2fe39a5e012264)) +* **phoenix:** Respond to exit status codes ([5de3052](https://github.com/HeyPuter/puter/commit/5de305202656a172b187dac87543d6c1c69a2958)) +* **phoenix:** Show actual host name in prompt and neofetch ([4539408](https://github.com/HeyPuter/puter/commit/4539408a218a50244dc615cf7de56c29dcac53e6)) +* rate-limit for excessive groups ([4af279a](https://github.com/HeyPuter/puter/commit/4af279a72fc9de89ddc3ba51806ca3760a36265d)) +* re-send unreads on login ([02fc4d8](https://github.com/HeyPuter/puter/commit/02fc4d86b7166fb4803be5d28e2a593d6b7d9785)) +* register dev center to apps ([10f4d7d](https://github.com/HeyPuter/puter/commit/10f4d7d50ce9314f9c3888c74cb17c8ebbecee98)) +* send notification when file gets shared ([2f6c428](https://github.com/HeyPuter/puter/commit/2f6c428a403a006f7878861d2f0356c3294519be)) +* start directory index frame ([fb1e2f2](https://github.com/HeyPuter/puter/commit/fb1e2f21fb67aefe0602f6c978199c7cd019bbf7)) +* support canonical puter.js url in dev ([fd41ae2](https://github.com/HeyPuter/puter/commit/fd41ae217c7a9f7229326f62a829471580a744bd)) +* **ui:** add new components ([577bd59](https://github.com/HeyPuter/puter/commit/577bd59b6cc94810e851ad544f8234e25a4e6e27)) +* **ui:** add new components ([38ba425](https://github.com/HeyPuter/puter/commit/38ba42575ce9f3506f8ce219b9580202b3ed9993)) +* **ui:** allow component-based settings tabs ([1245960](https://github.com/HeyPuter/puter/commit/124596058a286241b51dd87ce2fc1a68478cb5b8)) +* update share endpoint to support more things ([dd5fde5](https://github.com/HeyPuter/puter/commit/dd5fde5130c1840ab598e6622766ae835142e58a)) + + +### Bug Fixes + +* add app_uid param to kv interface ([f7a0549](https://github.com/HeyPuter/puter/commit/f7a054956b8739a3bc305a49faee929ea0da1e15)) +* add missing columns for public directory update ([b10302a](https://github.com/HeyPuter/puter/commit/b10302ad744fd9c58f9735743e075815183c772c)) +* Add missing file extension to 0009_app-prefix-fix.sql in DB init ([a8160a8](https://github.com/HeyPuter/puter/commit/a8160a8cdcdd6aff98728a6f1643d93386e6bb5a)) +* add permission implicator for file modes ([e63ab3a](https://github.com/HeyPuter/puter/commit/e63ab3a67f6555eb13d6af477a8da9f1b54d6608)) +* add stream limit ([ceba309](https://github.com/HeyPuter/puter/commit/ceba309dbd4df89f310d1a530f939a5b7991f4c7)) +* **backend:** remove a bad thing that really doesn't work ([8d22276](https://github.com/HeyPuter/puter/commit/8d22276f13106f7642d11da30b1500817a20ad43)) +* bug introduced when refactoring /share to Sequence ([ecb9978](https://github.com/HeyPuter/puter/commit/ecb997885c1efb766827c84d2ffb8dc6ddabe992)) +* check subdomain earlier for /apps ([4e3a24e](https://github.com/HeyPuter/puter/commit/4e3a24e6093e279e210765e07e436f4e63b74072)) +* column nullability blunder ([1429d6f](https://github.com/HeyPuter/puter/commit/1429d6f57c67dff51fc41ca0c2868f8d000845f1)) +* Correct APIError imports ([062e23b](https://github.com/HeyPuter/puter/commit/062e23b5c9673db1f8b0ff0469289d52dd1e3f99)) +* correct shown flag behavior ([632c536](https://github.com/HeyPuter/puter/commit/632c5366161ff8fbbd4d60c61dfbe52dad488a2c)) +* database migration ([9b39309](https://github.com/HeyPuter/puter/commit/9b39309e18a2927d25fe794d91da4e4d068c4bca)) +* do not delegate to select on read like ever that is really dumb ([a2a10b9](https://github.com/HeyPuter/puter/commit/a2a10b94be59403e03fb08bec5d7c056ce5b554f)) +* docker runtime fail because stdout columns ([94c0449](https://github.com/HeyPuter/puter/commit/94c0449437ce4cb26d00a15a3f277bc7b09367b4)) +* fix issues with apps in /share endpoint ([0cf90ee](https://github.com/HeyPuter/puter/commit/0cf90ee39af6548d271dec45ed8ee9e6df1cd14d)) +* fix owner ids for default apps ([283f409](https://github.com/HeyPuter/puter/commit/283f409a662d126e7f3ce811f1467ac6fab9a522)) +* fix permission cascade properly this time ([de58866](https://github.com/HeyPuter/puter/commit/de5886698e1eae2b250baac174b57029f3244e96)) +* Fix phoenix app prefix and TokenService test ([afb9d86](https://github.com/HeyPuter/puter/commit/afb9d866b5091058711db931cde904947e661c15)) +* fix that fix ([b126b67](https://github.com/HeyPuter/puter/commit/b126b670940a0e20cfe7bd0eba3db891bab5c142)) +* fix typo ([ce328b7](https://github.com/HeyPuter/puter/commit/ce328b7245ad741b64c5885f64f806fc98a55d84)) +* **git:** Make git commit display detached HEAD correctly ([73d0f5a](https://github.com/HeyPuter/puter/commit/73d0f5a90cb5dcbadfc6d0fd22f14e8bc0e61f86)) +* group permission audit table ([7d2f6d2](https://github.com/HeyPuter/puter/commit/7d2f6d256f56e30d752e9999c6e8bde68f9d9637)) +* handle subpaths under another user ([d128cee](https://github.com/HeyPuter/puter/commit/d128ceed6f4928fa0793815feb2e2715cd273ff8)) +* handling of batch requests with zero files ([c0063a8](https://github.com/HeyPuter/puter/commit/c0063a871fd891a1774f1bee00e86170fed249fa)) +* i forgot to test reloading ([7eabb43](https://github.com/HeyPuter/puter/commit/7eabb43bd4257b4129d67eaeda2aa27e8268dc78)) +* improve console experience on mac ([15465bf](https://github.com/HeyPuter/puter/commit/15465bfc5035a64762f7c86a3d38af8be6be5b59)) +* incorrect error from suggested_apps ([b648817](https://github.com/HeyPuter/puter/commit/b648817f2743c2b6214ebe4177d921c9b9027594)) +* Make polyfilled import.meta.filename getter a valid function ([85c6798](https://github.com/HeyPuter/puter/commit/85c679844869b6b05fcbda231d8dc7026a66da97)) +* null email in request to /share ([bf63144](https://github.com/HeyPuter/puter/commit/bf63144f7a79c48bd650ae851ddd0c8a10d748c3)) +* Only run Component initialization functions once ([5b43358](https://github.com/HeyPuter/puter/commit/5b43358219402bee3eadf4a0f184a4b924d3293b)) +* oops ([a136ee5](https://github.com/HeyPuter/puter/commit/a136ee5edd3149798a0d82f494f423f503b65f00)) +* **parsely:** Make Repeat parser work when no separator is given ([9b4d16f](https://github.com/HeyPuter/puter/commit/9b4d16fbe9d5698c57f9da725a22b528a7d7cac2)) +* peers array assumption ([10cbf08](https://github.com/HeyPuter/puter/commit/10cbf08233620440aa39f5302deaac4f59f02247)) +* **phoenix:** Add missing newlines to sed command output ([e047b0b](https://github.com/HeyPuter/puter/commit/e047b0bf302284da61e677432e4cc25b531b24f2)) +* **phoenix:** Gracefully handle completing a non-existent path ([d76e713](https://github.com/HeyPuter/puter/commit/d76e7130cba9f0ca05940abafe4fd1a41464aa83)) +* property validation on some permission endpoints ([0855f2b](https://github.com/HeyPuter/puter/commit/0855f2b36eca3bbdaa8429cbde3aa1242e8e96ee)) +* readdir on file ([a72ec97](https://github.com/HeyPuter/puter/commit/a72ec9799ac3bd76ceafa22cce149e373a13f3b9)) +* remove last component when share URL is file ([1166e69](https://github.com/HeyPuter/puter/commit/1166e69c76688d1811701c56cd4df9d38e286793)) +* remove legacy permission check in stat ([f2c6e01](https://github.com/HeyPuter/puter/commit/f2c6e01296e4214336e63bc2d69bcbf17f59890f)) +* Remove null or duplicate app entries from suggest_app_for_fsentry() ([6900233](https://github.com/HeyPuter/puter/commit/6900233c5aaa2d1a49f495e9f9a060796757a91e)) +* **security:** Move token for socket.io to request body ([49b257e](https://github.com/HeyPuter/puter/commit/49b257ecffbb1e12090b86a67528a5ad09da69db)) +* switch share notif username to sender ([cd65217](https://github.com/HeyPuter/puter/commit/cd65217f5cda1c986ee231e2eeeef5abefa36ecb)) +* **Terminal:** Accept input from Chrome on Android ([4ef3e53](https://github.com/HeyPuter/puter/commit/4ef3e53de34f0097950a7e707ca2483863beafb5)) +* Throw an error when readdir is called on a non-directory ([46eb4ed](https://github.com/HeyPuter/puter/commit/46eb4ed2b96c235e10e15645a30d2f192a1af0de)) +* type error in puter-site ([d96f924](https://github.com/HeyPuter/puter/commit/d96f924cad7a13ea6e9084bb0ebb79ecc5fcb8a3)) +* ui color input attributes ([d9c4fbb](https://github.com/HeyPuter/puter/commit/d9c4fbbd1dcce12ee05ee33652a5fa518196463d)) +* **ui:** improve Component base class ([f8780d0](https://github.com/HeyPuter/puter/commit/f8780d032b10138851c22af53b8610c578139acc)) +* update email share object ([9033f6f](https://github.com/HeyPuter/puter/commit/9033f6f8c74ef8739294d640ac1c7eba95519bbd)) +* update PD alert custom details ([2f16322](https://github.com/HeyPuter/puter/commit/2f163221bdde09425cae11ef7f8e4eb0b10c7103)) +* update test kernel ([55c609b](https://github.com/HeyPuter/puter/commit/55c609b3fec4ef018febc6e88c44a6277960d728)) +* validate size metadata ([2008db0](https://github.com/HeyPuter/puter/commit/2008db08524259264a0c8186a34fc75d7a133f5f)) + ## 2.3.0 (2024-05-22) diff --git a/package-lock.json b/package-lock.json index e09fb8ad03..3954e7fa84 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "puter.com", - "version": "2.3.0", + "version": "1.0.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "puter.com", - "version": "2.3.0", + "version": "1.0.0", "license": "AGPL-3.0-only", "workspaces": [ "src/*" diff --git a/package.json b/package.json index e5cef97af1..7241c5f84a 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "puter.com", - "version": "2.3.0", + "version": "1.0.0", "author": "Puter Technologies Inc.", "license": "AGPL-3.0-only", "description": "Desktop environment in the browser!", From 1f659f7c016c8357f9f2608caa12b4f6ab31408a Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 8 Jul 2024 13:45:57 -0400 Subject: [PATCH 0458/2119] chore: fix release-please version --- CHANGELOG.md | 2 +- src/gui/src/package.json | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 5e14968776..95e49d11f8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,6 +1,6 @@ # Changelog -## 1.0.0 (2024-07-08) +## 2.4.0 (2024-07-08) ### Features diff --git a/src/gui/src/package.json b/src/gui/src/package.json index e6e0bc5815..e273f7ce9e 100644 --- a/src/gui/src/package.json +++ b/src/gui/src/package.json @@ -1,6 +1,6 @@ { "name": "@heyputer/gui", - "version": "2.3.0", + "version": "2.4.0", "author": "Puter Technologies Inc.", "license": "AGPL-3.0-only", "description": "Desktop environment in the browser!", From 883601142873f10d69c84874499065a7d29af054 Mon Sep 17 00:00:00 2001 From: Oleh Brusentsov Date: Mon, 8 Jul 2024 20:44:53 +0200 Subject: [PATCH 0459/2119] Russian translation fixed --- src/gui/src/i18n/translations/ru.js | 123 +++++++++++++++--- src/gui/src/i18n/translations/translations.js | 1 + src/gui/src/i18n/translations/ua.js | 0 3 files changed, 105 insertions(+), 19 deletions(-) create mode 100644 src/gui/src/i18n/translations/ua.js diff --git a/src/gui/src/i18n/translations/ru.js b/src/gui/src/i18n/translations/ru.js index 77779cdf13..f5cb9b28f9 100644 --- a/src/gui/src/i18n/translations/ru.js +++ b/src/gui/src/i18n/translations/ru.js @@ -22,12 +22,15 @@ const ru = { code: "ru", dictionary: { about: "О системе", - account: "Учетная Запись", - access_granted_to: "Доступ Предоставлен", - add_existing_account: "Добавить Существующую Учетную Запись", + account: "Учетная запись", + account_password: "Проверить пароль учётной записи", + access_granted_to: "Доступ предоставлен", + add_existing_account: "Добавить существующую учетную запись", all_fields_required: 'Все поля обязательны.', + allow: "Позволить", apply: "Применить", ascending: 'По возрастанию', + associated_websites: "Ассоциированные веб-сайты", auto_arrange: 'Автоупорядочивание', background: "Фон", browse: "Пролистать", @@ -40,26 +43,39 @@ const ru = { change_ui_colors: "Сменить Тему Оформления", change_username: "Сменить Имя Пользователя", close: 'Закрыть', - close_all_windows: "Закрыть Все Окна", + close_all_windows: "Закрыть все Окна", close_all_windows_confirm: "Вы уверены, что хотите закрыть все окна?", close_all_windows_and_log_out: 'Закрыть Окна и Выйти', change_always_open_with: "Хотите всегда открывать файлы этого типа в", color: 'Цвет', - hue: 'Цветовая Гамма', + confirm: "Подтвердить", + confirm_2fa_setup: "Я добавил код в своё приложение для аутентификации", + confirm_2fa_recovery: "Я сохранил свои коды для восстановления в безопасном месте", confirm_account_for_free_referral_storage_c2a: 'Создайте учетную запись и подтвердите свой адрес электронной почты, чтобы получить 1 Гб бесплатного дискового пространства. Ваш друг также получит 1 Гб бесплатного дискового пространства.', + confirm_code_generic_incorrect: "Код неверен", + confirm_code_generic_too_many_requests: "Слишком много запросов. Пожалуйста, подождите несколько минут", + confirm_code_generic_submit: "Принять код", + confirm_code_generic_try_again: "Попробовать снова", + confirm_code_generic_title: "Ввести код подтверждения", + confirm_code_2fa_instruction: "Введите шестизначный код из вашего приложения для аутентификации.", + confirm_code_2fa_submit_btn: "Принять", + confirm_code_2fa_title: "Введите код для двухфакторной аутентификации", confirm_delete_multiple_items: 'Вы уверены, что хотите навсегда удалить эти элементы?', confirm_delete_single_item: 'Вы уверены, что хотите навсегда удалить этот элемент?', confirm_open_apps_log_out: 'У вас имеются открытые приложения. Вы уверены, что хотите выйти из системы?', - confirm_new_password: "Подтвердите Новый Пароль", + confirm_new_password: "Подтвердите новый пароль", confirm_delete_user: "Вы уверены, что хотите удалить свою учетную запись? Все ваши файлы и данные будут удалены безвозвратно. Это действие нельзя отменить.", - confirm_delete_user_title: "Удалить Учетную Запись?", + confirm_delete_user_title: "Удалить учетную запись?", confirm_session_revoke: "Вы уверены, что хотите отозвать эту сессию?", + confirm_your_email_address: "Подтвердить адрес электронной почты", contact_us: "Связаться с нами", + contact_us_verification_required:"Вам необходимо иметь подтвержденный адрес электронной почты для использования этой функции", contain: 'Содержание', continue: "Продолжить", copy: 'Копировать', copy_link: "Копировать Ссылку", copying: "Копируется", + copying_file:"Копируется %%", cover: 'Обложка', create_account: "Создать Учетную Запись", create_free_account: "Создать Бесплатную Учетную Запись", @@ -70,7 +86,9 @@ const ru = { clock: "Часы", clock_visible_hide: 'Скрыть - Всегда скрыто', clock_visible_show: 'Показать - Всегда на виду', - clock_visible_auto: 'Авто - По Умолчанию, видно только в полноэкранном режиме.', + clock_visible_auto: 'Авто - По Умолчанию, видно только в полноэкранном режиме', + close_all: "Закрыть все", + created: "Создано", date_modified: 'Дата изменения', default: 'По умолчанию', delete: 'Удалить', @@ -78,10 +96,16 @@ const ru = { delete_permanently: "Удалить Безвозвратно", deploy_as_app: 'Развернуть как приложение', descending: 'По убыванию', + desktop: "Рабочий стол", desktop_background_fit: "Вместить", developers: "Разработчики", dir_published_as_website: `%strong% опубликован в:`, - disassociate_dir: "Отключать Директорию", + disable_2fa: "Отключить двухфакторную аутентификацию", + disable_2fa_confirm: "Вы уверены что хотите отключить двухфакторную аутентификацию?", + disable_2fa_instructions: "Введите ваш пароль для отключения двухфакторной аутентификации", + disassociate_dir: "Отключить Директорию", + documents: "Документы", + dont_allow: "Не разрешать", download: 'Загрузить', download_file: 'Загрузить Файл', downloading: "Загружается", @@ -93,38 +117,53 @@ const ru = { empty_trash: 'Очистить Корзину', empty_trash_confirmation: `Вы уверены, что хотите навсегда удалить элементы из Корзины?`, emptying_trash: 'Очистка Корзины…', - end_hard: "Закрыть жестко", + enable_2fa: "Включить двухфакторную аутентификацию", + end_hard: "Закрыть жестко", //принудительно end_process_force_confirm: "Вы уверены, что хотите принудительно завершить этот процесс?", - end_soft: "Закрыть мягко", + end_soft: "Закрыть мягко", + enlarged_qr_code: "Увеличить QR код", enter_password_to_confirm_delete_user: "Введите пароль для подтверждения удаления учетной записи", + error_message_is_missing: "Сообщение об ошибке отсутствует", + error_unknown_cause: "Произошла неизвестная ошибка", + error_uploading_files: "Сбой загрузки файлов", + favorites: "Избранное", feedback: "Обратная связь", feedback_c2a: "Пожалуйста, используйте форму ниже, чтобы отправить нам свои отзывы, комментарии и сообщения об ошибках.", feedback_sent_confirmation: "Спасибо, что связались с нами. Если у вас есть электронная почта, связанная с вашим аккаунтом, мы ответим вам как можно скорее.", fit: "Вместить", + folder: "Папка", force_quit: 'Принудительно Закрыть', forgot_pass_c2a: "Забыли пароль?", from: "От", general: "Общий", get_a_copy_of_on_puter: `Получите копию '%%' на Puter.com!`, get_copy_link: 'Получить Ссылку для Копирования', - hide_all_windows: "Скрыть Все Окна", + hide_all_windows: "Скрыть все окна", + home: "Домой", html_document: 'HTML документ', + hue: 'Цветовая Гамма', image: 'Изображение', incorrect_password: "Неверный пароль", invite_link: "Пригласительная ссылка", - item: 'элемент', + item: 'Элемент', items_in_trash_cannot_be_renamed: `Этот элемент нельзя переименовать, потому что он находится в Корзине. Чтобы переименовать этот элемент, сначала перетащите его из Корзины.`, jpeg_image: 'JPEG изображение', keep_in_taskbar: 'Сохранить на Панели Задач', language: "Язык", license: "Лицензия", - lightness: 'Легкость', + lightness: 'Легкость', //нужен контекст link_copied: "Ссылка скопирована", loading: 'Загружается', log_in: "Войти", log_into_another_account_anyway: 'Все-равно войти в другой аккаунт', log_out: 'Выйти', + looks_good: "Выглядит хорошо!", manage_sessions: "Управление Сеансами", + menubar_style: "Стиль Меню", + menubar_style_desktop: "Рабочего стола", + menubar_style_system: "Системы", + menubar_style_window: "Окна", + modified: "Изменено", move: 'Переместить', moving_file: "Перемещается %%", my_websites: "Мои Сайты", @@ -148,6 +187,8 @@ const ru = { open_in_new_tab: "Открыть в Новой Вкладке", open_in_new_window: "Открыть в Новом Окне", open_with: "Открыть с помощью", + original_name: "Оригинальное имя", + original_path: "Оригинальный путь", oss_code_and_content: "Программное обеспечение и контент с открытым исходным кодом", password: "Пароль", password_changed: "Пароль изменен.", @@ -159,26 +200,31 @@ const ru = { passwords_do_not_match: 'Поля `Новый Пароль` и `Подтвердите Новый Пароль` не совпадают.', paste: 'Вставить', paste_into_folder: "Вставить в Папку", + path: "Путь", personalization: "Персонализация", pick_name_for_website: "Выберите имя для вашего сайта:", picture: "Изображение", - plural_suffix: 's', + pictures: "Изображения", + plural_suffix: 's', //?? в русском языке это или И или Ы powered_by_puter_js: `Создано на {{link=docs}}Puter.js{{/link}}`, preparing: "Подготовка...", preparing_for_upload: "Подготовка к загрузке...", privacy: "Конфиденциальность", - proceed_to_login: 'Перейти ко входу', + proceed_to_login: 'Перейти к Входу', proceed_with_account_deletion: "Продолжить Удаление Учетной Записи", process_status_initializing: "Инициализация", process_status_running: "Выполняется", process_type_app: 'Прил', process_type_init: 'Иниц', - process_type_ui: 'UI', + process_type_ui: 'Пользовательский интерфейс', properties: "Свойства", + public: "Общий", publish: "Опубликовать", publish_as_website: 'Опубликовать как сайт', puter_description: `Puter — это персональное облако, обеспечивающее конфиденциальность, позволяющее хранить все ваши файлы, приложения и игры в одном безопасном месте, доступном из любого места в любое время.`, + reading_file: "Чтение файла", recent: "Недавний", + recommended: "Рекомендованный", recover_password: "Восстановить Пароль", refer_friends_c2a: "Получите 1 ГБ за каждого друга, который создаст и подтвердит учетную запись на Puter. Ваш друг тоже получит 1 ГБ!", refer_friends_social_media_c2a: `Получите 1 ГБ бесплатного хранилища на Puter.com!`, @@ -193,15 +239,19 @@ const ru = { reset_colors: "Сбросить Цвета", restart_puter_confirm: "Вы уверены, что хотите перезапустить Puter?", restore: "Восстановить", + save: "Сохранить", saturation: 'Насыщенность', - save_account: 'Сохранить учетную запись', + save_account: 'Сохранить Учетную запись', save_account_to_get_copy_link: "Пожалуйста, создайте учетную запись, чтобы продолжить.", save_account_to_publish: 'Пожалуйста, создайте учетную запись, чтобы продолжить.', save_session: 'Сохранить сеанс', save_session_c2a: 'Создайте учетную запись, чтобы сохранить текущий сеанс и не потерять данные.', scan_qr_c2a: 'Отсканируйте код ниже, чтобы войти в этот сеанс с других устройств', + scan_qr_2fa: "Отсканируйте код с помощью вашего приложения для аутентификации", scan_qr_generic: 'Отсканируйте этот QR-код с помощью телефона или другого устройства', + search: "Поиск", seconds: 'секунды', + security: "Безопасность", select: "Выбрать", selected: 'выбрано', select_color: 'Выбрать цвет…', @@ -212,6 +262,8 @@ const ru = { settings: "Настройки", set_new_password: "Установить Новый Пароль", share_to: "Поделиться с", + share_with: "Поделиться с", + shortcut_to: "Ярлык для", show_all_windows: "Показать Все Окна", show_hidden: 'Показать скрытые', sign_in_with_puter: "Войти с Puter", @@ -234,8 +286,11 @@ const ru = { tos_fineprint: `Нажимая 'Создать бесплатную учетную запись', вы соглашаетесь с {{link=terms}}Условиями Использования{{/link}} и {{link=privacy}}Политикой Конфиденциальности{{/link}} Puter.`, transparency: "Прозрачность", trash: 'Корзина', + two_factor: "Двухфакторная аутентификация", + two_factor_disabled: "Двухфакторная аутентификация отключена", + two_factor_enabled:"Двухфакторная аутентификация включена", type: 'Тип', - type_confirm_to_delete_account: "Введите 'подтвердить', чтобы удалить учетную запись.", + type_confirm_to_delete_account: "Введите 'Подтвердить', чтобы удалить учетную запись.", ui_colors: "Цвета UI", ui_manage_sessions: "Менеджер Сеансов", ui_revoke: "Отозвать", @@ -249,11 +304,41 @@ const ru = { username_changed: 'Имя Пользователя успешно обновлено.', username_required: 'Требуется имя Пользователя.', versions: "Версии", + videos: "Видео", visibility: 'Видимость', yes: 'Да', yes_release_it: 'Да, освободить.', you_have_been_referred_to_puter_by_a_friend: "Вы были приглашены в Puter другом!", zip: "Заархивировать", + zipping_file: "Архивация %strong%", + +// === 2FA Setup === + setup2fa_1_step_heading: 'Откройте ваше приложение для аутентификации', + setup2fa_1_instructions: ` + Вы можете использовать любое приложение, которое поддерживает Одноразовый Пароль, на основе времени. + Их множество, но если вы не уверены в выборе + Authy + является прекрасным вариантом для Android и iOS. + `, + setup2fa_2_step_heading: 'Отсканируйте QR код', + setup2fa_3_step_heading: 'Введите шестизначный код', + setup2fa_4_step_heading: 'Скопируйте ваши коды восстановления', + setup2fa_4_instructions: ` + Эти коды восстановления являются единственным способом входа в Ваш аккаунт если вы потеряете телефон или не + сможете использовать приложение для аутентификации. Удостоверьтесь в их сохранности.`, + setup2fa_5_step_heading: 'Подтвердите настройку 2FA', + setup2fa_5_confirmation_1: 'Я сохранил свои коды в надежном месте', + setup2fa_5_confirmation_2: 'Я готов использовать 2FA', + setup2fa_5_button: 'Включить 2FA', + +// === 2FA Login === + login2fa_otp_title: 'Введите код 2FA', + login2fa_otp_instructions: 'Введите шестизначный код из вашего приложения дла аутентификации', + login2fa_recovery_title: 'Введите код восстановления', + login2fa_recovery_instructions: 'Введите один из кодов восстановления для доступа к учетной записи', + login2fa_use_recovery_code: 'Используйте код восстановления', + login2fa_recovery_back: 'Назад', + login2fa_recovery_placeholder: 'XXXXXXXX', } }; diff --git a/src/gui/src/i18n/translations/translations.js b/src/gui/src/i18n/translations/translations.js index 21a78e3e10..81c50d9140 100644 --- a/src/gui/src/i18n/translations/translations.js +++ b/src/gui/src/i18n/translations/translations.js @@ -42,6 +42,7 @@ import sv from './sv.js'; import th from './th.js'; import tr from './tr.js'; import ur from './ur.js'; +import ua from './ua.js'; import zh from './zh.js'; import zhtw from './zhtw.js'; import emoji from './emoji.js'; diff --git a/src/gui/src/i18n/translations/ua.js b/src/gui/src/i18n/translations/ua.js new file mode 100644 index 0000000000..e69de29bb2 From 17145d0be6a9a1445947cc0c4bec8f16a475144c Mon Sep 17 00:00:00 2001 From: Yuliya Tolstikova <66835926+julijatol@users.noreply.github.com> Date: Mon, 8 Jul 2024 15:12:48 -0400 Subject: [PATCH 0460/2119] Update ru.js issue #547 --- src/gui/src/i18n/translations/ru.js | 218 ++++++++++++++++++++-------- 1 file changed, 154 insertions(+), 64 deletions(-) diff --git a/src/gui/src/i18n/translations/ru.js b/src/gui/src/i18n/translations/ru.js index 77779cdf13..dadfe71231 100644 --- a/src/gui/src/i18n/translations/ru.js +++ b/src/gui/src/i18n/translations/ru.js @@ -22,98 +22,132 @@ const ru = { code: "ru", dictionary: { about: "О системе", - account: "Учетная Запись", - access_granted_to: "Доступ Предоставлен", - add_existing_account: "Добавить Существующую Учетную Запись", - all_fields_required: 'Все поля обязательны.', + account: "Учетная запись", + account_password: "Подтвердите пароль", + access_granted_to: "Доступ предоставлен", + add_existing_account: "Добавить существующую Учетную запись", + all_fields_required: 'Все поля обязательны для заполнения.', + allow: 'Разрешить', apply: "Применить", ascending: 'По возрастанию', + associated_websites: "Связанные сайты", auto_arrange: 'Автоупорядочивание', background: "Фон", browse: "Пролистать", cancel: 'Отмена', center: 'Отцентровать', change_desktop_background: 'Сменить фон рабочего стола…', - change_email: "Сменить Email", - change_language: "Сменить Язык", - change_password: "Сменить Пароль", - change_ui_colors: "Сменить Тему Оформления", - change_username: "Сменить Имя Пользователя", + change_email: "Изменить электронныю почту", + change_language: "Изменить язык", + change_password: "Изменить пароль", + change_ui_colors: "Изменить тему оформления", + change_username: "Изменить имя пользователя", close: 'Закрыть', - close_all_windows: "Закрыть Все Окна", + close_all_windows: "Закрыть все окна", close_all_windows_confirm: "Вы уверены, что хотите закрыть все окна?", - close_all_windows_and_log_out: 'Закрыть Окна и Выйти', - change_always_open_with: "Хотите всегда открывать файлы этого типа в", + close_all_windows_and_log_out: 'Закрыть все окна и выйти', + change_always_open_with: "Хотите всегда открывать файлы этого типа с помощью", color: 'Цвет', + confirm: 'Подтвердить', hue: 'Цветовая Гамма', + confirm_2fa_setup: 'Я добавил код в приложение для аутентификации', + confirm_2fa_recovery: 'Я сохранил коды восстановления доступа в безопасном месте', confirm_account_for_free_referral_storage_c2a: 'Создайте учетную запись и подтвердите свой адрес электронной почты, чтобы получить 1 Гб бесплатного дискового пространства. Ваш друг также получит 1 Гб бесплатного дискового пространства.', + confirm_code_generic_incorrect: "Неверный код.", + confirm_code_generic_too_many_requests: "Слишком много запросов. Пожалуйста, подождите несколько минут.", + confirm_code_generic_submit: "Отправить код", + confirm_code_generic_try_again: "Попробуйте снова", + confirm_code_generic_title: "Введите код подтверждения", + confirm_code_2fa_instruction: "Введите 6-значный код из приложения для аутентификации.", + confirm_code_2fa_submit_btn: "Отправить", + confirm_code_2fa_title: "Введите код аутентификации", confirm_delete_multiple_items: 'Вы уверены, что хотите навсегда удалить эти элементы?', confirm_delete_single_item: 'Вы уверены, что хотите навсегда удалить этот элемент?', confirm_open_apps_log_out: 'У вас имеются открытые приложения. Вы уверены, что хотите выйти из системы?', - confirm_new_password: "Подтвердите Новый Пароль", + confirm_new_password: "Подтвердите новый пароль", confirm_delete_user: "Вы уверены, что хотите удалить свою учетную запись? Все ваши файлы и данные будут удалены безвозвратно. Это действие нельзя отменить.", - confirm_delete_user_title: "Удалить Учетную Запись?", - confirm_session_revoke: "Вы уверены, что хотите отозвать эту сессию?", + confirm_delete_user_title: "Удалить учетную запись?", + confirm_session_revoke: "Вы уверены, что хотите отменить эту сессию?", contact_us: "Связаться с нами", + contact_us_verification_required: "Подтвердите адрес электронной почты чтобы продожить.", contain: 'Содержание', continue: "Продолжить", copy: 'Копировать', - copy_link: "Копировать Ссылку", - copying: "Копируется", + copy_link: "Скопировать ссылку", + copying: "Создаю копию", + copying_file: "Создаю копию %%", cover: 'Обложка', - create_account: "Создать Учетную Запись", - create_free_account: "Создать Бесплатную Учетную Запись", - create_shortcut: "Создать Ярлык", - credits: "Титры", - current_password: "Текущий Пароль", + create_account: "Создать учетную запись", + create_free_account: "Создать бесплатную учетную запись", + create_shortcut: "Создать ярлык", + credits: "Авторы", + current_password: "Текущий пароль", cut: 'Вырезать', clock: "Часы", clock_visible_hide: 'Скрыть - Всегда скрыто', clock_visible_show: 'Показать - Всегда на виду', clock_visible_auto: 'Авто - По Умолчанию, видно только в полноэкранном режиме.', + close_all: 'Закрыть все', + created: 'Создано', date_modified: 'Дата изменения', default: 'По умолчанию', delete: 'Удалить', - delete_account: "Удалить Учетную Запись", - delete_permanently: "Удалить Безвозвратно", + delete_account: "Удалить учетную запись", + delete_permanently: "Удалить безвозвратно", + deleting_file: "Удаление %%", deploy_as_app: 'Развернуть как приложение', descending: 'По убыванию', + desktop: 'Рабочий стол', desktop_background_fit: "Вместить", developers: "Разработчики", dir_published_as_website: `%strong% опубликован в:`, - disassociate_dir: "Отключать Директорию", + disable_2fa: 'Отключить двойную аутентификацию', + disable_2fa_confirm: "Вы уверены, что хотите отключить двойную аутентификацию?", + disable_2fa_instructions: "Введите пароль чтобы отключить двойную аутентификацию.", + disassociate_dir: "Отключить директорию", + documents: 'Документы', + dont_allow: 'Доступ запрещён', download: 'Загрузить', - download_file: 'Загрузить Файл', - downloading: "Загружается", - email: "Email", + download_file: 'Загрузить файл', + downloading: "Загрузка", + email: "Электронная почта", email_change_confirmation_sent: "На ваш новый адрес электронной почты было отправлено письмо с подтверждением. Пожалуйста, проверьте свой ящик электронной почты и следуйте инструкциям, чтобы завершить процесс.", email_invalid: 'Адрес электронной почты недействителен.', - email_or_username: "Email или Имя Пользователя", + email_or_username: "Email или Имя пользователя", email_required: 'Email обязателен.', - empty_trash: 'Очистить Корзину', + empty_trash: 'Очистить корзину', empty_trash_confirmation: `Вы уверены, что хотите навсегда удалить элементы из Корзины?`, emptying_trash: 'Очистка Корзины…', - end_hard: "Закрыть жестко", + enable_2fa: 'Включить двойную аутентификацию', + end_hard: "Принудительно закрыть", end_process_force_confirm: "Вы уверены, что хотите принудительно завершить этот процесс?", - end_soft: "Закрыть мягко", + end_soft: "Закрыть", + enlarged_qr_code: "Увеличить QR код", enter_password_to_confirm_delete_user: "Введите пароль для подтверждения удаления учетной записи", + error_message_is_missing: "Сообщение об ошибке отсутствует.", + error_unknown_cause: "Неизвестная ошибка.", + error_uploading_files: "Не удалось загрузить файлы", + favorites: "Избранное", feedback: "Обратная связь", feedback_c2a: "Пожалуйста, используйте форму ниже, чтобы отправить нам свои отзывы, комментарии и сообщения об ошибках.", feedback_sent_confirmation: "Спасибо, что связались с нами. Если у вас есть электронная почта, связанная с вашим аккаунтом, мы ответим вам как можно скорее.", fit: "Вместить", - force_quit: 'Принудительно Закрыть', + folder: 'Папка', + force_quit: 'Принудительно закрыть', forgot_pass_c2a: "Забыли пароль?", from: "От", - general: "Общий", + general: "Общее", get_a_copy_of_on_puter: `Получите копию '%%' на Puter.com!`, - get_copy_link: 'Получить Ссылку для Копирования', - hide_all_windows: "Скрыть Все Окна", + get_copy_link: 'Получить ссылку для копирования', + hide_all_windows: "Скрыть все окна", + home: 'Домой', html_document: 'HTML документ', + hue: 'Оттенок', image: 'Изображение', incorrect_password: "Неверный пароль", - invite_link: "Пригласительная ссылка", + invite_link: "Ссылка для приглашения", item: 'элемент', - items_in_trash_cannot_be_renamed: `Этот элемент нельзя переименовать, потому что он находится в Корзине. Чтобы переименовать этот элемент, сначала перетащите его из Корзины.`, + items_in_trash_cannot_be_renamed: `Этот элемент нельзя переименовать, потому что он находится в Корзине. Чтобы переименовать этот элемент, сначала перенесите его из Корзины.`, jpeg_image: 'JPEG изображение', keep_in_taskbar: 'Сохранить на Панели Задач', language: "Язык", @@ -124,9 +158,15 @@ const ru = { log_in: "Войти", log_into_another_account_anyway: 'Все-равно войти в другой аккаунт', log_out: 'Выйти', + looks_good: "Выглядит здорово!", manage_sessions: "Управление Сеансами", + menubar_style: "Стиль меню", + menubar_style_desktop: "Рабочий стол", + menubar_style_system: "Система", + menubar_style_window: "Окно", + modified: 'Изменено', move: 'Переместить', - moving_file: "Перемещается %%", + moving_file: "Перемещаю %%", my_websites: "Мои Сайты", name: 'Имя', name_cannot_be_empty: 'Имя не может быть пустым.', @@ -136,39 +176,44 @@ const ru = { name_must_be_string: "Имя может содержать только текстовые символы.", name_too_long: `Имя не может быть длинее %% символов.`, new: 'Новый', - new_email: 'Новый Email', + new_email: 'Новая электронная почта', new_folder: 'Новая папка', - new_password: "Новый Пароль", - new_username: "Новое Имя Пользователя", + new_password: "Новый пароль", + new_username: "Новое имя пользователя", no: 'Нет', no_dir_associated_with_site: 'Нет директории, связанной с этим адресом.', no_websites_published: "Вы еще не опубликовали ни одного сайта.", ok: 'OK', open: "Открыть", - open_in_new_tab: "Открыть в Новой Вкладке", - open_in_new_window: "Открыть в Новом Окне", + open_in_new_tab: "Открыть в новой вкладке", + open_in_new_window: "Открыть в новом окне", open_with: "Открыть с помощью", + original_name: 'Оригинальное имя', + original_path: 'Изначальный путь', oss_code_and_content: "Программное обеспечение и контент с открытым исходным кодом", password: "Пароль", password_changed: "Пароль изменен.", - password_recovery_rate_limit: "Вы достигли лимита; пожалуйста, подождите несколько минут. Чтобы предотвратить это в будущем, не перезагружайте страницу слишком много раз.", + password_recovery_rate_limit: "Вы достигли лимита. Пожалуйста, подождите несколько минут. Чтобы предотвратить это в будущем, не перезагружайте страницу слишком много раз.", password_recovery_token_invalid: "Этот токен восстановления пароля больше не действителен.", password_recovery_unknown_error: "Произошла неизвестная ошибка. Пожалуйста, повторите попытку позже.", - password_required: 'Необходим Пароль.', - password_strength_error: "Пароль должен иметь длину не менее 8 символов и содержать хотя бы одну заглавную букву, одну строчную букву, одну цифру и один специальный символ.", - passwords_do_not_match: 'Поля `Новый Пароль` и `Подтвердите Новый Пароль` не совпадают.', + password_required: 'Необходимо ввести пароль.', + password_strength_error: "Пароль должен иметь длину не менее 8 символов и содержать хотя бы одну заглавную букву, одну строчную букву, одну цифру и один специальный знак.", + passwords_do_not_match: 'Поля `Новый пароль` и `Подтвердите новый пароль` не совпадают.', paste: 'Вставить', - paste_into_folder: "Вставить в Папку", + paste_into_folder: "Вставить в папку", + path: 'Путь', personalization: "Персонализация", pick_name_for_website: "Выберите имя для вашего сайта:", picture: "Изображение", - plural_suffix: 's', + pictures: 'Изображения', + plural_suffix: 's', //does not exist in Russian language powered_by_puter_js: `Создано на {{link=docs}}Puter.js{{/link}}`, preparing: "Подготовка...", preparing_for_upload: "Подготовка к загрузке...", + print: 'Печать', privacy: "Конфиденциальность", proceed_to_login: 'Перейти ко входу', - proceed_with_account_deletion: "Продолжить Удаление Учетной Записи", + proceed_with_account_deletion: "Продолжить удаление учетной записи", process_status_initializing: "Инициализация", process_status_running: "Выполняется", process_type_app: 'Прил', @@ -176,23 +221,27 @@ const ru = { process_type_ui: 'UI', properties: "Свойства", publish: "Опубликовать", + public: 'Общий доступ', publish_as_website: 'Опубликовать как сайт', puter_description: `Puter — это персональное облако, обеспечивающее конфиденциальность, позволяющее хранить все ваши файлы, приложения и игры в одном безопасном месте, доступном из любого места в любое время.`, - recent: "Недавний", + reading_file: "Чтение %strong%", + recent: "Недавнее", + recommended: "Рекоммендации", recover_password: "Восстановить Пароль", refer_friends_c2a: "Получите 1 ГБ за каждого друга, который создаст и подтвердит учетную запись на Puter. Ваш друг тоже получит 1 ГБ!", refer_friends_social_media_c2a: `Получите 1 ГБ бесплатного хранилища на Puter.com!`, refresh: 'Обновить', release_address_confirmation: `Вы уверены, что хотите освободить этот адрес?`, - remove_from_taskbar:'Удалить с Панели Задач', + remove_from_taskbar:'Удалить из панели задач', rename: 'Переименовать', repeat: 'Повторить', replace: 'Заменить', - replace_all: 'Заменить Все', - resend_confirmation_code: "Повторно отправить Код Подтверждения", - reset_colors: "Сбросить Цвета", + replace_all: 'Заменить все', + resend_confirmation_code: "Повторно отправить код подтверждения", + reset_colors: "Сбросить цвета", restart_puter_confirm: "Вы уверены, что хотите перезапустить Puter?", restore: "Восстановить", + save: 'Сохранить', saturation: 'Насыщенность', save_account: 'Сохранить учетную запись', save_account_to_get_copy_link: "Пожалуйста, создайте учетную запись, чтобы продолжить.", @@ -200,8 +249,11 @@ const ru = { save_session: 'Сохранить сеанс', save_session_c2a: 'Создайте учетную запись, чтобы сохранить текущий сеанс и не потерять данные.', scan_qr_c2a: 'Отсканируйте код ниже, чтобы войти в этот сеанс с других устройств', + scan_qr_2fa: 'Отсканируйте QR-код с помощью приложения аутентификации', scan_qr_generic: 'Отсканируйте этот QR-код с помощью телефона или другого устройства', + search: 'Поиск', seconds: 'секунды', + security: "Безопасность", select: "Выбрать", selected: 'выбрано', select_color: 'Выбрать цвет…', @@ -210,8 +262,11 @@ const ru = { send_password_recovery_email: "Отправить электронное письмо для восстановления пароля", session_saved: "Благодарим вас за создание учетной записи. Этот сеанс сохранен.", settings: "Настройки", - set_new_password: "Установить Новый Пароль", - share_to: "Поделиться с", + set_new_password: "Установить новый пароль", + share: "Поделиться", + share_to: "Поделиться", + share_with: "Поделиться с: ", + shortcut_to: "Ярлык для", show_all_windows: "Показать Все Окна", show_hidden: 'Показать скрытые', sign_in_with_puter: "Войти с Puter", @@ -219,13 +274,14 @@ const ru = { signing_in: "Вход в систему…", size: 'Размер', skip: 'Пропустить', + something_went_wrong: "Что-то пошло не так.", sort_by: 'Отсортировать по', start: 'Начать', status: "Статус", storage_usage: "Использование хранилища", storage_puter_used: 'использовано Puter', - taking_longer_than_usual: 'Это занимает немного больше времени, чем обычно. пожалуйста, подождите...', - task_manager: "Диспетчер Задач", + taking_longer_than_usual: 'Это занимает немного больше времени чем обычно, пожалуйста, подождите...', + task_manager: "Диспетчер задач", taskmgr_header_name: "Имя", taskmgr_header_status: "Статус", taskmgr_header_type: "Тип", @@ -234,9 +290,12 @@ const ru = { tos_fineprint: `Нажимая 'Создать бесплатную учетную запись', вы соглашаетесь с {{link=terms}}Условиями Использования{{/link}} и {{link=privacy}}Политикой Конфиденциальности{{/link}} Puter.`, transparency: "Прозрачность", trash: 'Корзина', + two_factor: 'Двухфакторная аутентификация', + two_factor_disabled: 'Двухфакторная аутентификация отключена', + two_factor_enabled: 'Двухфакторная аутентификация включена', type: 'Тип', type_confirm_to_delete_account: "Введите 'подтвердить', чтобы удалить учетную запись.", - ui_colors: "Цвета UI", + ui_colors: "Цвета пользовательского интерфейса", ui_manage_sessions: "Менеджер Сеансов", ui_revoke: "Отозвать", undo: 'Отменить', @@ -245,15 +304,46 @@ const ru = { upload: 'Загрузить', upload_here: 'Загрузить здесь', usage: 'Использование', - username: "Имя Пользователя", - username_changed: 'Имя Пользователя успешно обновлено.', + username: "Имя пользователя", + username_changed: 'Имя пользователя успешно обновлено.', username_required: 'Требуется имя Пользователя.', versions: "Версии", + videos: 'Видео', visibility: 'Видимость', yes: 'Да', yes_release_it: 'Да, освободить.', you_have_been_referred_to_puter_by_a_friend: "Вы были приглашены в Puter другом!", - zip: "Заархивировать", + zip: "Добавить в архив", + zipping_file: "Добавление в архив %strong%", + + // === 2FA Setup === + setup2fa_1_step_heading: 'Откройте приложение для аутенцификации', + setup2fa_1_instructions: ` + Вы можете использовать любое приложение для аутентификации, поддерживающее протокол одноразового пароля на основе времени (TOTP). + Существует большой выбор приложений, но если вы не уверены, то + Authy + это хороший выбор для Android и iOS + `, + setup2fa_2_step_heading: 'Отсканируйте QR-код', + setup2fa_3_step_heading: 'Введите 6-значный код', + setup2fa_4_step_heading: 'Скопируйте коды восстановления', + setup2fa_4_instructions: ` + Эти коды восстановления — единственный способ получить доступ к вашей учетной записи, если вы потеряете свой телефон или не сможете использовать приложение для аутентификации. + Обязательно храните их в безопасном месте. + `, + setup2fa_5_step_heading: 'Подтвердите установку двухфакторной аутентификации', + setup2fa_5_confirmation_1: 'Я созранил коды восстановления в безопасном месте', + setup2fa_5_confirmation_2: 'Я готов включить двухфакторную аутентификацию', + setup2fa_5_button: 'Включить двухфакторную аутентификацию', + + // === 2FA Login === + login2fa_otp_title: 'Введите код двухфакторной аутентификации', + login2fa_otp_instructions: 'Введите 6-значный код из приложения для аутентификации', + login2fa_recovery_title: 'Введите код восстановления доступа', + login2fa_recovery_instructions: 'Введите один из кодов восстановления доступа чтобы получить доступ к учетной записи.', + login2fa_use_recovery_code: 'Используйте код восстановления доступа', + login2fa_recovery_back: 'Назад', + login2fa_recovery_placeholder: 'XXXXXXXX', } }; From 3ed7916856f03eafbe0891f2ab39c34d20d2bd24 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 8 Jul 2024 15:24:26 -0400 Subject: [PATCH 0461/2119] feat: JSON support for kv driver --- src/backend/src/drivers/DBKVStore.js | 18 ++++++++--- .../database/SqliteDatabaseAccessService.js | 7 ++++- .../database/sqlite_setup/0023_fix-kv.sql | 31 +++++++++++++++++++ 3 files changed, 51 insertions(+), 5 deletions(-) create mode 100644 src/backend/src/services/database/sqlite_setup/0023_fix-kv.sql diff --git a/src/backend/src/drivers/DBKVStore.js b/src/backend/src/drivers/DBKVStore.js index 2131e46a85..a4e2f05cca 100644 --- a/src/backend/src/drivers/DBKVStore.js +++ b/src/backend/src/drivers/DBKVStore.js @@ -58,6 +58,11 @@ class DBKVStore extends Driver { `SELECT * FROM kv WHERE user_id=? AND (app IS NULL OR app = 'global') AND kkey_hash=? LIMIT 1`, [ user.id, key_hash ] ); + + if ( kv[0] ) kv[0].value = db.case({ + mysql: () => kv[0].value, + otherwise: () => JSON.parse(kv[0].value ?? 'null'), + })(); return kv[0]?.value ?? null; }, @@ -74,10 +79,11 @@ class DBKVStore extends Driver { } // Validate the value - value = value === undefined ? null : String(value); + value = value === undefined ? null : value; if ( value !== null && - Buffer.byteLength(value, 'utf8') > config.kv_max_value_size + Buffer.byteLength(JSON.stringify(value), 'utf8') > + config.kv_max_value_size ) { throw new Error(`value is too large. Max size is ${config.kv_max_value_size}.`); } @@ -102,7 +108,8 @@ class DBKVStore extends Driver { sqlite: 'ON CONFLICT(user_id, app, kkey_hash) DO UPDATE SET value = excluded.value', }), [ - user.id, app?.uid ?? 'global', key_hash, key, value, + user.id, app?.uid ?? 'global', key_hash, key, + JSON.stringify(value), ...db.case({ mysql: [value], otherwise: [] }), ] ); @@ -164,7 +171,10 @@ class DBKVStore extends Driver { rows = rows.map(row => ({ key: row.kkey, - value: row.value, + value: db.case({ + mysql: () => row.value, + otherwise: () => JSON.parse(row.value ?? 'null') + })(), })); as = as || 'entries'; diff --git a/src/backend/src/services/database/SqliteDatabaseAccessService.js b/src/backend/src/services/database/SqliteDatabaseAccessService.js index 7472d15700..4d987c4067 100644 --- a/src/backend/src/services/database/SqliteDatabaseAccessService.js +++ b/src/backend/src/services/database/SqliteDatabaseAccessService.js @@ -42,7 +42,7 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { this.db = new Database(this.config.path); // Database upgrade logic - const TARGET_VERSION = 20; + const TARGET_VERSION = 21; if ( do_setup ) { this.log.noticeme(`SETUP: creating database at ${this.config.path}`); @@ -69,6 +69,7 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { '0020_dev-center.sql', '0021_app-owner-id.sql', '0022_dev-center-max.sql', + '0023_fix-kv.sql', ].map(p => path_.join(__dirname, 'sqlite_setup', p)); const fs = require('fs'); for ( const filename of sql_files ) { @@ -165,6 +166,10 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { upgrade_files.push('0022_dev-center-max.sql'); } + if ( user_version <= 20 ) { + upgrade_files.push('0023_fix-kv.sql'); + } + if ( upgrade_files.length > 0 ) { this.log.noticeme(`Database out of date: ${this.config.path}`); this.log.noticeme(`UPGRADING DATABASE: ${user_version} -> ${TARGET_VERSION}`); diff --git a/src/backend/src/services/database/sqlite_setup/0023_fix-kv.sql b/src/backend/src/services/database/sqlite_setup/0023_fix-kv.sql new file mode 100644 index 0000000000..9d76e6d0d8 --- /dev/null +++ b/src/backend/src/services/database/sqlite_setup/0023_fix-kv.sql @@ -0,0 +1,31 @@ +CREATE TABLE `new_kv` ( + `id` INTEGER PRIMARY KEY, + `app` char(40) DEFAULT NULL, + `user_id` int(10) NOT NULL, + `kkey_hash` bigint(20) NOT NULL, + `kkey` text NOT NULL, + `value` JSON, + `migrated` tinyint(1) DEFAULT '0', + UNIQUE (user_id, app, kkey_hash) +); + +INSERT INTO `new_kv` +( + `app`, + `user_id`, + `kkey_hash`, + `kkey`, + `value` +) +SELECT + `app`, + `user_id`, + `kkey_hash`, + `kkey`, + json_quote(value) +FROM `kv`; + +DROP TABLE `kv`; + +ALTER TABLE `new_kv` +RENAME TO `kv`; From e61039faf409b0ad85c7513b0123f3f2e92ebe32 Mon Sep 17 00:00:00 2001 From: Oleh Brusentsov Date: Mon, 8 Jul 2024 20:59:07 +0200 Subject: [PATCH 0462/2119] Ukrainian updated --- src/gui/src/i18n/translations/translations.js | 1 + src/gui/src/i18n/translations/ua.js | 335 ++++++++++++++++++ 2 files changed, 336 insertions(+) diff --git a/src/gui/src/i18n/translations/translations.js b/src/gui/src/i18n/translations/translations.js index 81c50d9140..4cd212972f 100644 --- a/src/gui/src/i18n/translations/translations.js +++ b/src/gui/src/i18n/translations/translations.js @@ -75,6 +75,7 @@ export default { sv, th, tr, + ua, zh, zhtw, ur, diff --git a/src/gui/src/i18n/translations/ua.js b/src/gui/src/i18n/translations/ua.js index e69de29bb2..3d59946c90 100644 --- a/src/gui/src/i18n/translations/ua.js +++ b/src/gui/src/i18n/translations/ua.js @@ -0,0 +1,335 @@ +/** + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ +const ua = { + name: "Українська", + english_name: "Ukrainian", + code: "ua", + dictionary: { + about: "Про систему", + account: "Обліковий запис", + account_password: "Перевірити пароль облікового запису", + access_granted_to: "Доступ надано", + add_existing_account: "Додати існуючий обліковий запис", + all_fields_required: 'Усі поля обов\'язкові.', + allow: "Дозволити", + apply: "Застосувати", + ascending: 'За зростанням', + associated_websites: "Асоційовані веб-сайти", + auto_arrange: 'Автоупорядкування', + background: "Фон", + browse: "Переглянути", + cancel: 'Відміна', + center: 'Відцентрувати', + change_desktop_background: 'Змінити фон робочого столу…', + change_email: "Змінити Email", + change_language: "Змінити Мову", + change_password: "Змінити Пароль", + change_ui_colors: "Змінити Тему Оформлення", + change_username: "Змінити Ім\'я Користувача", + close: 'Закрити', + close_all_windows: "Закрити всі Вікна", + close_all_windows_confirm: "Ви впевнені, що хочете закрити всі вікна?", + close_all_windows_and_log_out: 'Закрити Вікна і Вийти', + change_always_open_with: "Бажаєте завжди відкривати файли цього типу в", + color: 'Колір', + confirm: "Підтвердити", + confirm_2fa_setup: "Я додав код у свій додаток для аутентифікації", + confirm_2fa_recovery: "Я зберіг свої коди для відновлення в безпечному місці", + confirm_account_for_free_referral_storage_c2a: 'Створіть обліковий запис і підтвердіть свою електронну адресу, щоб отримати 1 Гб безкоштовного дискового простору. Ваш друг також отримає 1 Гб безкоштовного дискового простору.', + confirm_code_generic_incorrect: "Код невірний", + confirm_code_generic_too_many_requests: "Забагато запитів. Будь ласка, зачекайте кілька хвилин", + confirm_code_generic_submit: "Прийняти код", + confirm_code_generic_try_again: "Спробувати знову", + confirm_code_generic_title: "Ввести код підтвердження", + confirm_code_2fa_instruction: "Введіть шестизначний код з вашого додатка для аутентифікації.", + confirm_code_2fa_submit_btn: "Прийняти", + confirm_code_2fa_title: "Введіть код для двофакторної аутентифікації", + confirm_delete_multiple_items: 'Ви впевнені, що хочете назавжди видалити ці елементи?', + confirm_delete_single_item: 'Ви впевнені, що хочете назавжди видалити цей елемент?', + confirm_open_apps_log_out: 'У вас є відкриті додатки. Ви впевнені, що хочете вийти з системи?', + confirm_new_password: "Підтвердьте новий пароль", + confirm_delete_user: "Ви впевнені, що хочете видалити свій обліковий запис? Усі ваші файли та дані будуть видалені назавжди. Цю дію неможливо скасувати.", + confirm_delete_user_title: "Видалити обліковий запис?", + confirm_session_revoke: "Ви впевнені, що хочете відкликати цей сеанс?", + confirm_your_email_address: "Підтвердити електронну адресу", + contact_us: "Зв'яжіться з нами", + contact_us_verification_required:"Вам необхідно мати підтверджену електронну адресу для використання цієї функції", + contain: 'Зміст', + continue: "Продовжити", + copy: 'Копіювати', + copy_link: "Копіювати Посилання", + copying: "Копіюється", + copying_file:"Копіюється %%", + cover: 'Обкладинка', + create_account: "Створити Обліковий Запис", + create_free_account: "Створити Безкоштовний Обліковий Запис", + create_shortcut: "Створити Ярлик", + credits: "Титри", + current_password: "Поточний Пароль", + cut: 'Вирізати', + clock: "Годинник", + clock_visible_hide: 'Приховати - Завжди приховано', + clock_visible_show: 'Показати - Завжди на виду', + clock_visible_auto: 'Авто - За Замовчуванням, видно тільки у повноекранному режимі', + close_all: "Закрити все", + created: "Створено", + date_modified: 'Дата зміни', + default: 'За замовчуванням', + delete: 'Видалити', + delete_account: "Видалити Обліковий Запис", + delete_permanently: "Видалити Назавжди", + deploy_as_app: 'Розгорнути як додаток', + descending: 'За спаданням', + desktop: "Робочий стіл", + desktop_background_fit: "Вмістити", + developers: "Розробники", + dir_published_as_website: `%strong% опубліковано в:`, + disable_2fa: "Вимкнути двофакторну аутентифікацію", + disable_2fa_confirm: "Ви впевнені, що хочете вимкнути двофакторну аутентифікацію?", + disable_2fa_instructions: "Введіть ваш пароль для вимкнення двофакторної аутентифікації", + disassociate_dir: "Від'єднати Директорію", + documents: "Документи", + dont_allow: "Не дозволяти", + download: 'Завантажити', + download_file: 'Завантажити Файл', + downloading: "Завантажується", + email: "Email", + email_change_confirmation_sent: "На вашу нову електронну адресу було надіслано листа з підтвердженням. Будь ласка, перевірте свою поштову скриньку і дотримуйтесь інструкцій, щоб завершити процес.", + email_invalid: 'Електронна адреса недійсна.', + email_or_username: "Email або Ім'я Користувача", + email_required: 'Email обов\'язковий.', + empty_trash: 'Очистити Кошик', + empty_trash_confirmation: `Ви впевнені, що хочете назавжди видалити елементи з Кошика?`, + emptying_trash: 'Очищення Кошика…', + enable_2fa: "Увімкнути двофакторну аутентифікацію", + end_hard: "Закрити жорстко", + end_process_force_confirm: "Ви впевнені, що хочете примусово завершити цей процес?", + end_soft: "Закрити м'яко", + enlarged_qr_code: "Збільшити QR код", + enter_password_to_confirm_delete_user: "Введіть пароль для підтвердження видалення облікового запису", + error_message_is_missing: "Повідомлення про помилку відсутнє", + error_unknown_cause: "Сталася невідома помилка", + error_uploading_files: "Збій завантаження файлів", + favorites: "Вибране", + feedback: "Зворотній зв'язок", + feedback_c2a: "Будь ласка, скористайтеся формою нижче, щоб надіслати нам свої відгуки, коментарі та повідомлення про помилки.", + feedback_sent_confirmation: "Дякуємо, що зв'язалися з нами. Якщо у вас є електронна пошта, пов'язана з вашим обліковим записом, ми відповімо вам якомога швидше.", + fit: "Вмістити", + folder: "Папка", + force_quit: 'Примусово Закрити', + forgot_pass_c2a: "Забули пароль?", + from: "Від", + general: "Загальний", + get_a_copy_of_on_puter: `Отримайте копію '%%' на Puter.com!`, + get_copy_link: 'Отримати Посилання для Копіювання', + hide_all_windows: "Приховати всі вікна", + home: "Додому", + html_document: 'HTML документ', + hue: 'Колірна Гама', + image: 'Зображення', + incorrect_password: "Невірний пароль", + invite_link: "Невірне посилання", + item: 'Елемент', + items_in_trash_cannot_be_renamed: `Цей елемент неможливо переіменувати тому що він знаходиться у корзині. Спочатку + перетащіть його з корзини`, + jpeg_image: 'JPEG зображення', + keep_in_taskbar: 'Зберегти на Панелі Задач', + language: "Мова", + license: "Ліцензія", + lightness: 'Легкість', + link_copied: "Посилання скопійоване", + loading: 'Завантажується', + log_in: "Ввійти", + log_into_another_account_anyway: 'Все одно ввійти в інший аккаунт', + log_out: 'Вийти', + looks_good: "Гарно виглядає!", + manage_sessions: "Управління Сеансами", + menubar_style: "Стиль Меню", + menubar_style_desktop: "Робочого стола", + menubar_style_system: "Системи", + menubar_style_window: "Вікна", + modified: "Змінено", + move: 'Перемістити', + moving_file: "Переміщується %%", + my_websites: "Мої Сайти", + name: 'Ім\'я', + name_cannot_be_empty: 'Ім\'я не може бути порожнім.', + name_cannot_contain_double_period: "Ім'я не может бути '..' символом.", + name_cannot_contain_period: "Ім'я не може бути '.' символом.", + name_cannot_contain_slash: "Ім'я не може містити '/' символ.", + name_must_be_string: "Ім\'я може містити тільки текстові символи", + name_too_long: `Ім\'я не може бути більш ніж %% символів уздовж.`, + new: 'Новий', + new_email: 'Новий Email', + new_folder: 'Нова папка', + new_password: "Новий Пароль", + new_username: "Нове Ім'я Користувача", + no: 'Ні', + no_dir_associated_with_site: 'Немає директорії, пов\'язанної з цією адресою.', + no_websites_published: "Ви ще не опублікували жодного сайту.", + ok: 'OK', + open: "Відчинити", + open_in_new_tab: "Відчинити у Новій Вкладці", + open_in_new_window: "Відчинити у Новому Вікні", + open_with: "Відчинити за допомогою", + original_name: "Оригінальне Ім'я", + original_path: "Оригинальный путь", + oss_code_and_content: "Програмне забезпечення та контент з відкритим кодом", + password: "Пароль", + password_changed: "Пароль змінено.", + password_recovery_rate_limit: "Ви досягли ліміту; будь ласка, зачекайте кілька хвилин. Щоб уникнути цього в майбутньому, не перезавантажуйте сторінку занадто багато разів.", + password_recovery_token_invalid: "Цей токен відновлення пароля більше не дійсний.", + password_recovery_unknown_error: "Сталася невідома помилка. Будь ласка, спробуйте пізніше.", + password_required: 'Потрібен Пароль.', + password_strength_error: "Пароль має містити не менше 8 символів і включати хоча б одну велику літеру, одну малу літеру, одну цифру та один спеціальний символ.", + passwords_do_not_match: 'Поля Новий Пароль і Підтвердіть Новий Пароль не співпадають.', + paste: 'Вставити', + paste_into_folder: "Вставити в Папку", + path: "Шлях", + personalization: "Персоналізація", + pick_name_for_website: "Виберіть ім'я для вашого сайту:", + picture: "Зображення", + pictures: "Зображення", + plural_suffix: 's', + powered_by_puter_js: "Створено на {{link=docs}}Puter.js{{/link}}", + preparing: "Підготовка...", + preparing_for_upload: "Підготовка до завантаження...", + privacy: "Конфіденційність", + proceed_to_login: 'Перейти до Входу', + proceed_with_account_deletion: "Продовжити Видалення Облікового Запису", + process_status_initializing: "Ініціалізація", + process_status_running: "Виконується", + process_type_app: 'Дод.', + process_type_init: 'Ініц.', + process_type_ui: 'Інтерфейс користувача', + properties: "Властивості", + public: "Загальний", + publish: "Опублікувати", + publish_as_website: 'Опублікувати як сайт', + puter_description: "Puter — це персональна хмара, яка забезпечує конфіденційність, дозволяючи зберігати всі ваші файли, додатки та ігри в одному безпечному місці, доступному з будь-якого місця в будь-який час.", + reading_file: "Читання файлу", + recent: "Недавній", + recommended: "Рекомендований", + recover_password: "Відновити Пароль", + refer_friends_c2a: "Отримайте 1 ГБ за кожного друга, який створить і підтвердить обліковий запис на Puter. Ваш друг також отримає 1 ГБ!", + refer_friends_social_media_c2a: "Отримайте 1 ГБ безкоштовного сховища на Puter.com!", + refresh: 'Оновити', + release_address_confirmation: "Ви впевнені, що хочете звільнити цю адресу?", + remove_from_taskbar:'Видалити з Панелі Завдань', + rename: 'Перейменувати', + repeat: 'Повторити', + replace: 'Замінити', + replace_all: 'Замінити Все', + resend_confirmation_code: "Повторно надіслати Код Підтвердження", + reset_colors: "Скинути Кольори", + restart_puter_confirm: "Ви впевнені, що хочете перезапустити Puter?", + restore: "Відновити", + save: "Зберегти", + saturation: 'Насиченість', + save_account: 'Зберегти Обліковий запис', + save_account_to_get_copy_link: "Будь ласка, створіть обліковий запис, щоб продовжити.", + save_account_to_publish: 'Будь ласка, створіть обліковий запис, щоб продовжити.', + save_session: 'Зберегти сеанс', + save_session_c2a: 'Створіть обліковий запис, щоб зберегти поточний сеанс і не втратити дані.', + scan_qr_c2a: 'Скануйте код нижче, щоб увійти в цей сеанс з інших пристроїв', + scan_qr_2fa: "Скануйте код за допомогою вашого додатку для аутентифікації", + scan_qr_generic: 'Скануйте цей QR-код за допомогою телефону або іншого пристрою', + search: "Пошук", + seconds: 'секунди', + security: "Безпека", + select: "Вибрати", + selected: 'вибрано', + select_color: 'Вибрати колір…', + sessions: "Сеанси", + send: "Надіслати", + send_password_recovery_email: "Надіслати електронний лист для відновлення пароля", + session_saved: "Дякуємо вам за створення облікового запису. Цей сеанс збережено.", + settings: "Налаштування", + set_new_password: "Встановити Новий Пароль", + share_to: "Поділитися з", + share_with: "Поділитися з", + shortcut_to: "Ярлик для", + show_all_windows: "Показати Всі Вікна", + show_hidden: 'Показати приховані', + sign_in_with_puter: "Увійти з Puter", + sign_up: "Зареєструватися", + signing_in: "Вхід у систему…", + size: 'Розмір', + skip: 'Пропустити', + sort_by: 'Відсортувати за', + start: 'Почати', + status: "Статус", + storage_usage: "Використання сховища", + storage_puter_used: 'використано Puter', + taking_longer_than_usual: 'Це займає трохи більше часу, ніж зазвичай. будь ласка, зачекайте...', + task_manager: "Диспетчер Завдань", + taskmgr_header_name: "Ім'я", + taskmgr_header_status: "Статус", + taskmgr_header_type: "Тип", + terms: "Умови", + text_document: 'Текстовий документ', + tos_fineprint: "Натискаючи 'Створити безкоштовний обліковий запис', ви погоджуєтеся з {{link=terms}}Умовами Використання{{/link}} та {{link=privacy}}Політикою Конфіденційності{{/link}} Puter.", + transparency: "Прозорість", + trash: 'Кошик', + two_factor: "Двофакторна аутентифікація", + two_factor_disabled: "Двофакторна аутентифікація вимкнена", + two_factor_enabled:"Двофакторна аутентифікація увімкнена", + type: 'Тип', + type_confirm_to_delete_account: "Введіть 'Підтвердити', щоб видалити обліковий запис.", + ui_colors: "Кольори UI", + ui_manage_sessions: "Менеджер Сеансів", + ui_revoke: "Відкликати", + undo: 'Скасувати', + unlimited: 'Необмежено', + unzip: "Розпакувати", + upload: 'Завантажити', + upload_here: 'Завантажити тут', + usage: 'Використання', + username: "Ім'я Користувача", + username_changed: "Ім'я Користувача успішно оновлено.", + username_required: "Потрібно ім'я Користувача.", + versions: "Версії", + videos: "Відео", + visibility: 'Видимість', + yes: 'Так', + yes_release_it: 'Так, звільнити.', + you_have_been_referred_to_puter_by_a_friend: "Вас запросив друг у Puter!", + zip: "Архівувати", + zipping_file: "Архівування %strong%", + setup2fa_1_step_heading: 'Відкрийте ваш додаток для аутентифікації', + setup2fa_1_instructions: `Ви можете використовувати будь-який додаток, який підтримує Одноразовий Пароль на основі часу. Їх багато, але якщо ви не впевнені у виборі Authy є чудовим варіантом для Android і iOS.`, + setup2fa_2_step_heading: 'Скануйте QR код', + setup2fa_3_step_heading: 'Введіть шестизначний код', + setup2fa_4_step_heading: 'Скопіюйте ваші коди відновлення', + setup2fa_4_instructions: "Ці коди відновлення є єдиним способом входу у ваш обліковий запис, якщо ви втратите телефон або не зможете використовувати додаток для аутентифікації. Упевніться, що ви їх зберегли.", + setup2fa_5_step_heading: 'Підтвердьте налаштування 2FA', + setup2fa_5_confirmation_1: 'Я зберіг свої коди в надійному місці', + setup2fa_5_confirmation_2: 'Я готовий використовувати 2FA', + setup2fa_5_button: 'Увімкнути 2FA', + login2fa_otp_title: 'Введіть код 2FA', + login2fa_otp_instructions: 'Введіть шестизначний код з вашого додатку для аутентифікації', + login2fa_recovery_title: 'Введіть код відновлення', + login2fa_recovery_instructions: 'Введіть один з кодів відновлення для доступу до облікового запису', + login2fa_use_recovery_code: 'Використовуйте код відновлення', + login2fa_recovery_back: 'Назад', + login2fa_recovery_placeholder: 'XXXXXXXX', + } +} + +export default ua; From bffa192805216fc17045cd8d629f34784dca7f3f Mon Sep 17 00:00:00 2001 From: Med Elm Date: Mon, 8 Jul 2024 21:44:19 +0100 Subject: [PATCH 0463/2119] Update Arabic translations in src/gui/src/i18n/translations/ar.js to match English version in src/gui/src/i18n/translations/en.js --- src/gui/src/i18n/translations/ar.js | 475 +++++++++++++++++++--------- 1 file changed, 329 insertions(+), 146 deletions(-) diff --git a/src/gui/src/i18n/translations/ar.js b/src/gui/src/i18n/translations/ar.js index c429fd4858..16642a2b6b 100644 --- a/src/gui/src/i18n/translations/ar.js +++ b/src/gui/src/i18n/translations/ar.js @@ -16,153 +16,336 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const ar = { - name: "العربية", - english_name: "Arabic", - code: "ar", - dictionary: { - access_granted_to: "دخول مسموح به", - add_existing_account: "إضافة حساب موجود", - all_fields_required: 'يجب ملء كل الفراغات', - apply: "تطبيق ", - ascending: 'تصاعدي ', - background: "خلفية", - browse: "إبحث", - cancel: 'إلغاء', - center: 'وسط', - change_desktop_background: 'تغيير خلفية المكتب', - change_language: "تغيير اللغة", - change_password: "تغيير كلمة السر", - change_username: "تغيير إسم المستخدم", - close_all_windows: "غلق كل النوافذ", - color: 'اللون', - confirm_account_for_free_referral_storage_c2a: 'تأكيد الحساب لتخزين الإحالة المجانية ', - confirm_new_password: "تأكيد كلمة السر الجديدة", - contact_us: "اتصل بنا", - contain: 'إملء', - continue: "أكمل", - copy: 'أنسخ', - copy_link: "أنسخ الرابط", - copying: "ينسخ", - cover: 'غطاء', + +const en = { + name: "العربية", + english_name: "Arabic", + code: "ar", + dictionary: { + about: "حول", + account: "حساب", + account_password: "تحقق من كلمة مرور الحساب", + access_granted_to: "تم منح الوصول إلى", + add_existing_account: "إضافة حساب موجود", + all_fields_required: "جميع الحقول مطلوبة.", + allow: "السماح", + apply: "تطبيق", + ascending: "تصاعدي", + associated_websites: "المواقع المرتبطة", + auto_arrange: "ترتيب تلقائي", + background: "خلفية", + browse: "تصفح", + cancel: "إلغاء", + center: "مركز", + change_desktop_background: "تغيير خلفية سطح المكتب...", + change_email: "تغيير البريد الإلكتروني", + change_language: "تغيير اللغة", + change_password: "تغيير كلمة المرور", + change_ui_colors: "تغيير ألوان واجهة المستخدم", + change_username: "تغيير اسم المستخدم", + close: "إغلاق", + close_all_windows: "إغلاق جميع النوافذ", + close_all_windows_confirm: "هل أنت متأكد أنك تريد إغلاق جميع النوافذ؟", + close_all_windows_and_log_out: "إغلاق النوافذ وتسجيل الخروج", + change_always_open_with: "هل تريد دائمًا فتح هذا النوع من الملفات باستخدام", + color: "لون", + confirm: "تأكيد", + confirm_2fa_setup: "لقد أضفت الرمز إلى تطبيق المصادقة", + confirm_2fa_recovery: "لقد حفظت رموز الاسترداد في مكان آمن", + confirm_account_for_free_referral_storage_c2a: "أنشئ حسابًا وقم بتأكيد عنوان بريدك الإلكتروني للحصول على 1 جيجابايت من مساحة التخزين المجانية. سيحصل صديقك أيضًا على 1 جيجابايت من مساحة التخزين المجانية.", + confirm_code_generic_incorrect: "رمز غير صحيح." + confirm_code_generic_too_many_requests: "طلبات كثيرة جدًا. يرجى الانتظار بضع دقائق.", + confirm_code_generic_submit: "إرسال الرمز", + confirm_code_generic_try_again: "حاول مرة أخرى", + confirm_code_generic_title: "أدخل رمز التأكيد", + confirm_code_2fa_instruction: "أدخل الرمز المكون من 6 أرقام من تطبيق المصادقة الخاص بك.", + confirm_code_2fa_submit_btn: "إرسال", + confirm_code_2fa_title: "أدخل رمز المصادقة الثنائية", + confirm_delete_multiple_items: "هل أنت متأكد أنك تريد حذف هذه العناصر نهائيًا؟", + confirm_delete_single_item: "هل تريد حذف هذا العنصر نهائيًا؟", + confirm_open_apps_log_out: "لديك تطبيقات مفتوحة. هل أنت متأكد أنك تريد تسجيل الخروج؟", + confirm_new_password: "تأكيد كلمة المرور الجديدة", + confirm_delete_user: "هل أنت متأكد أنك تريد حذف حسابك؟ سيتم حذف جميع ملفاتك وبياناتك نهائيًا. لا يمكن التراجع عن هذا الإجراء.", + confirm_delete_user_title: "حذف الحساب؟", + confirm_session_revoke: "هل أنت متأكد أنك تريد إلغاء هذه الجلسة؟", + confirm_your_email_address: "تأكيد عنوان بريدك الإلكتروني", + contact_us: "اتصل بنا", + contact_us_verification_required: "يجب أن يكون لديك عنوان بريد إلكتروني مُؤكد لاستخدام هذه الخدمة.", + contain: "احتواء", + continue: "استمر", + copy: "نسخ", + copy_link: "نسخ الرابط", + copying: "جارٍ النسخ", + copying_file: "جارٍ نسخ %%", + cover: "تغطية", create_account: "إنشاء حساب", create_free_account: "إنشاء حساب مجاني", - create_shortcut: "تم تصميم المنتج", - current_password: "كلمة السر الحالية", - cut: 'إقطع', - date_modified: 'تغيير الوقت', - delete: 'حذف', - delete_permanently: "حذف دائم", - deploy_as_app: 'نشر كتطبيق', - descending: 'تنازلي', - desktop_background_fit: "خلفية سطح المكتب مناسبة", - dir_published_as_website: `:تم نشر الدليل كموقع ويب`, - disassociate_dir: "فصل الدليل", - download: 'تحميل ', - downloading: "جارى التحميل ", - email: "بريد إلكتروني", - email_or_username: "البريد الإلكتروني أو اسم المستخدم ", - empty_trash: 'سلة مهملات فارغة', - empty_trash_confirmation:'تأكيد إفراغ سلة المهملات ', - emptying_trash: 'إفراغ القمامة', - feedback: "تعليق ", - feedback_c2a: "تعليق ", - feedback_sent_confirmation: "أرسلت ردود الفعل التكوين ", - forgot_pass_c2a: "هل نسيت كلمة السر؟", - from: "من", - general: "عام ", - get_a_copy_of_on_puter: `الحصول على نسخة على جهاز الكمبيوتر`, - get_copy_link: 'الحصول على رابط النسخ', - hide_all_windows: "إخفاء كافة النوافذ ", - html_document: 'وثيقة أتش تي أم أل', - image: 'صورة', - invite_link: "رابط الدعوة", - items_in_trash_cannot_be_renamed: `لا يمكن إعادة تسمية العناصر الموجودة في سلة المهملات `, - jpeg_image: 'صورة j p e g', - keep_in_taskbar: 'احتفظ بها في شريط المهام ', - log_in: "تسجيل الدخول", - log_out: 'تسجيل خروج', - move: 'يتحرك', - moving_file: "متحرك %%", - my_websites: "مواقعي الإلكترونية ", - name: 'اسم', - name_cannot_be_empty: 'لا يمكن أن يكون الاسم فارغًا', - name_cannot_contain_double_period: "لا يمكن أن يحتوي الاسم على نقطة مزدوجة ", - name_cannot_contain_period: "لا يمكن أن يحتوي الاسم على فترة", - name_cannot_contain_slash: "لا يمكن أن يحتوي الاسم على شرطة مائلة", - name_must_be_string: "يجب أن يكون الاسم سلسلة", - name_too_long: `الاسم طويل جدًا`, - new: 'جديد', - new_folder: 'ملف جديد ', - new_password: "كلمة المرور الجديدة ", - new_username: "اسم مستخدم جديد ", - no_dir_associated_with_site: 'لا يوجد دليل مرتبط بالموقع', - no_websites_published: "لم يتم نشر أي مواقع", - ok: 'نعم', - open: "يفتح", - open_in_new_tab: "فتح في علامة تبويب جديدة", - open_in_new_window: "افتح في نافذة جديدة ", - open_with: "مفتوحة مع ", - password: "كلمة المرور ", - password_changed: "تم تغيير كلمة السر ", - passwords_do_not_match: 'كلمة المرور غير مطابقة', - paste: 'لصق', - paste_into_folder: "الصق داخل الملف", - pick_name_for_website: "اختيار اسم لموقع الويب ", - picture: "صورة ", - powered_by_puter_js: `مشغل بواسطة{{link=docs}}Puter.js{{/link}}`, - preparing: "إعداده", - preparing_for_upload: "التحضير للتحميل ", - properties: "ملكيات ", - publish: "ينشر", - publish_as_website: 'نشر كموقع على شبكة الإنترنت ', - recent: "مؤخرًا", - recover_password: "إستعادة كلمة المرور ", - refer_friends_c2a: "احصل على 1 جيجابايت لكل صديق يقوم بإنشاء حساب والتحقق منه مع Puter. صديقك يحصل على 1 غيغابايت أيضًا!", - refer_friends_social_media_c2a: `احصل على 1 غيغابايت من مساحة التخزين المجانية على موقع Puter.com!`, - refresh: 'ينعش ', - release_address_confirmation: `تأكيد عنوان الإصدار `, - remove_from_taskbar:'إزالة من شريط المهام ', - rename: 'إعادة تسمية', - repeat: 'تكرار', - resend_confirmation_code: "إعادة إرسال رمز التأكيد", - restore: "استرجاع", - save_account_to_get_copy_link: "حفظ الحساب للحصول على نسخة الرابط", - save_account_to_publish: 'حفظ الحساب للنشر', - save_session_c2a: 'حفظ جلسة ', - scan_qr_c2a: 'قم بمسح الرمز أدناه لتسجيل الدخول إلى هذه الجلسة من الأجهزة الأخرى', - select: "إختار", - select_color: 'إختر لون ', - send: "أرسل", - send_password_recovery_email: "إرسال بريد إلكتروني لاستعادة كلمة المرور", - session_saved: "تم حفظ الجلسة ", - set_new_password: "تعيين كلمة مرور جديدة ", - share_to: " شارك إلى", - show_all_windows: "إظهار كافة النوافذ ", - show_hidden: 'أظهر المخفي ', - sign_in_with_puter: "سجل الدخول ب Puter", - sign_up: "إشترك", - signing_in: "تسجيل الدخول", - size: 'الحجم', - sort_by: 'ترتيب حسب', - start: 'إبدأ ', - taking_longer_than_usual: 'يستغرق وقتا أطول من المعتاد ', - text_document: 'وثيقة نصية', - tos_fineprint: `بالنقر على "إنشاء حساب مجاني"، فإنك توافق على {{link=terms}}شروط الاستخدام{{/link}} و {{link=privacy}}حماية البيانات{{/link}}`, - trash: 'نفاية', - type: 'اكتب', - undo: 'الغاء التحميل', - unzip: "فك الضغط", - upload: 'رفع ', - upload_here: 'ارفع هنا', - username: "اسم المستخدم ", - username_changed: 'تم تغيير اسم المستخدم', - versions: "الإصدارات ", - yes_release_it: 'نعم أطلقه', - you_have_been_referred_to_puter_by_a_friend: "لقد تمت إحالتك إلى Puter بواسطة صديق!", - zip: "ملف مضغوط", - } + create_shortcut: "إنشاء اختصار", + credits: "الاعتمادات", + current_password: "كلمة المرور الحالية", + cut: "قص", + clock: "ساعة", + clock_visible_hide: "إخفاء - مخفية دائمًا", + clock_visible_show: "إظهار - مرئية دائمًا", + clock_visible_auto: "تلقائي - الافتراضي، مرئي فقط في وضع الشاشة الكاملة.", + close_all: "إغلاق الكل", + created: "تم الإنشاء", + date_modified: "تاريخ التعديل", + default: "افتراضي", + delete: "حذف", + delete_account: "حذف الحساب" + delete_permanently: "حذف نهائي", + deleting_file: "جارٍ حذف %%", + deploy_as_app: "نشر كتطبيق", + descending: "تنازلي", + desktop: "سطح المكتب", + desktop_background_fit: "ملائمة", + developers: "المطورين", + dir_published_as_website: "%strong% تم نشره إلى:", + disable_2fa: "تعطيل المصادقة الثنائية", + disable_2fa_confirm: "هل أنت متأكد أنك تريد تعطيل المصادقة الثنائية؟", + disable_2fa_instructions: "أدخل كلمة المرور لتعطيل المصادقة الثنائية.", + disassociate_dir: "فصل الدليل", + documents: "المستندات", + dont_allow: "عدم السماح", + download: "تنزيل", + download_file: "تنزيل الملف", + downloading: "جارٍ التنزيل", + email: "البريد الإلكتروني", + email_change_confirmation_sent: "تم إرسال بريد تأكيد إلى عنوان بريدك الإلكتروني الجديد. يرجى التحقق من صندوق الوارد واتباع التعليمات لإكمال العملية.", + email_invalid: "البريد الإلكتروني غير صالح.", + email_or_username: "البريد الإلكتروني أو اسم المستخدم", + email_required: "البريد الإلكتروني مطلوب.", + empty_trash: "إفراغ سلة المهملات", + empty_trash_confirmation: "هل أنت متأكد أنك تريد حذف العناصر في سلة المهملات نهائيًا؟", + emptying_trash: "جارٍ إفراغ سلة المهملات...", + enable_2fa: "تمكين المصادقة الثنائية", + end_hard: "إنهاء صعب", + end_process_force_confirm: "هل أنت متأكد أنك تريد إنهاء هذه العملية بالقوة؟", + end_soft: "إنهاء سلس", + enlarged_qr_code: "رمز QR مكبر", + enter_password_to_confirm_delete_user: "أدخل كلمة المرور لتأكيد حذف الحساب", + error_message_is_missing: "رسالة الخطأ مفقودة.", + error_unknown_cause: "حدث خطأ غير معروف.", + error_uploading_files: "فشل في تحميل الملفات", + favorites: "المفضلة", + feedback: "ملاحظات", + feedback_c2a: "يرجى استخدام النموذج أدناه لإرسال ملاحظاتك وتعليقاتك وتقرير الأخطاء.", + feedback_sent_confirmation: "شكرًا لتواصلك معنا. إذا كان لديك بريد إلكتروني مرتبط بحسابك، ستتلقى ردًا منا في أقرب وقت ممكن.", + fit: "ملائمة", + folder: "مجلد" + force_quit: "إنهاء بالقوة", + forgot_pass_c2a: "هل نسيت كلمة المرور؟", + from: "من", + general: "عام", + get_a_copy_of_on_puter: "احصل على نسخة من '%%' على Puter.com!", + get_copy_link: "احصل على رابط النسخ", + hide_all_windows: "إخفاء جميع النوافذ", + home: "الصفحة الرئيسية", + html_document: "مستند HTML", + hue: "درجة اللون", + image: "صورة", + incorrect_password: "كلمة مرور غير صحيحة", + invite_link: "رابط الدعوة", + item: "عنصر", + items_in_trash_cannot_be_renamed: "لا يمكن إعادة تسمية هذا العنصر لأنه في سلة المهملات. لإعادة تسمية هذا العنصر، اسحبه أولاً خارج سلة المهملات.", + jpeg_image: "صورة JPEG", + keep_in_taskbar: "الاحتفاظ في شريط المهام", + language: "اللغة", + license: "رخصة", + lightness: "إضاءة", + link_copied: "تم نسخ الرابط", + loading: "جارٍ التحميل", + log_in: "تسجيل الدخول", + log_into_another_account_anyway: "تسجيل الدخول إلى حساب آخر على أي حال", + log_out: "تسجيل الخروج", + looks_good: "يبدو جيدًا!", + manage_sessions: "إدارة الجلسات", + menubar_style: "نمط شريط القوائم", + menubar_style_desktop: "سطح المكتب", + menubar_style_system: "النظام", + menubar_style_window: "النافذة", + modified: "تم التعديل", + move: "نقل", + moving_file: "جارٍ نقل %%", + my_websites: "مواقعي الإلكترونية", + name: "اسم", + name_cannot_be_empty: "الاسم لا يمكن أن يكون فارغًا.", + name_cannot_contain_double_period: "الاسم لا يمكن أن يكون '..'.", + name_cannot_contain_period: "الاسم لا يمكن أن يكون '.'.", + name_cannot_contain_slash: "الاسم لا يمكن أن يحتوي على '/'." + name_must_be_string: "الاسم يجب أن يكون نصًا فقط.", + name_too_long: "الاسم لا يمكن أن يكون أطول من %% حرف.", + new: "جديد", + new_email: "البريد الإلكتروني الجديد", + new_folder: "مجلد جديد", + new_password: "كلمة المرور الجديدة", + new_username: "اسم المستخدم الجديد", + no: "لا", + no_dir_associated_with_site: "لا يوجد دليل مرتبط بهذا العنوان.", + no_websites_published: "لم تنشر أي مواقع إلكترونية بعد.", + ok: "موافق", + open: "فتح", + open_in_new_tab: "فتح في علامة تبويب جديدة", + open_in_new_window: "فتح في نافذة جديدة", + open_with: "فتح باستخدام", + original_name: "الاسم الأصلي", + original_path: "المسار الأصلي", + oss_code_and_content: "برامج ومحتوى مفتوح المصدر", + password: "كلمة المرور", + password_changed: "تم تغيير كلمة المرور.", + password_recovery_rate_limit: "لقد وصلت إلى الحد الأقصى؛ يرجى الانتظار بضع دقائق. لمنع حدوث ذلك في المستقبل، تجنب إعادة تحميل الصفحة كثيرًا.", + password_recovery_token_invalid: "رمز استعادة كلمة المرور لم يعد صالحًا.", + password_recovery_unknown_error: "حدث خطأ غير معروف. يرجى المحاولة مرة أخرى لاحقًا.", + password_required: "كلمة المرور مطلوبة.", + password_strength_error: "يجب أن تكون كلمة المرور بطول 8 أحرف على الأقل وتحتوي على حرف كبير واحد، حرف صغير واحد، رقم واحد، وحرف خاص واحد على الأقل.", + passwords_do_not_match: "`كلمة المرور الجديدة` و`تأكيد كلمة المرور الجديدة` غير متطابقتين.", + paste: "لصق", + paste_into_folder: "لصق في المجلد", + path: "المسار", + personalization: "تخصيص", + pick_name_for_website: "اختر اسمًا لموقعك الإلكتروني:", + picture: "صورة", + pictures: "الصور", + plural_suffix: "s", + powered_by_puter_js: "مدعوم بواسطة {{link=docs}}Puter.js{{/link}}", + preparing: "جارٍ التحضير...", + preparing_for_upload: "جارٍ التحضير للتحميل...", + print: "طباعة", + privacy: "الخصوصية", + proceed_to_login: "المتابعة لتسجيل الدخول", + proceed_with_account_deletion: "المتابعة مع حذف الحساب", + process_status_initializing: "جارٍ التهيئة", + process_status_running: "جارٍ التشغيل", + process_type_app: "تطبيق", + process_type_init: "تهيئة", + process_type_ui: "واجهة المستخدم", + properties: "الخصائص", + public: "عام", + publish: "نشر", + publish_as_website: "نشر كموقع إلكتروني", + puter_description: "Puter هو سحابة شخصية تركز على الخصوصية للحفاظ على جميع ملفاتك، تطبيقاتك، وألعابك في مكان آمن واحد، متاحة من أي مكان وفي أي وقت.", + reading_file: "جارٍ قراءة %strong%", + recent: "الأخيرة", + recommended: "مُوصى به", + recover_password: "استعادة كلمة المرور", + refer_friends_c2a: "احصل على 1 جيجابايت عن كل صديق ينشئ حسابًا ويؤكده على Puter. سيحصل صديقك على 1 جيجابايت أيضًا!", + refer_friends_social_media_c2a: "احصل على 1 جيجابايت من التخزين المجاني على Puter.com!", + refresh: "تحديث", + release_address_confirmation: "هل أنت متأكد أنك تريد تحرير هذا العنوان؟", + remove_from_taskbar: "إزالة من شريط المهام" + rename: "إعادة تسمية", + repeat: "تكرار", + replace: "استبدال", + replace_all: "استبدال الكل", + resend_confirmation_code: "إعادة إرسال رمز التأكيد", + reset_colors: "إعادة ضبط الألوان", + restart_puter_confirm: "هل أنت متأكد أنك تريد إعادة تشغيل Puter؟", + restore: "استعادة", + save: "حفظ", + saturation: "تشبع", + save_account: "حفظ الحساب", + save_account_to_get_copy_link: "يرجى إنشاء حساب للمتابعة.", + save_account_to_publish: "يرجى إنشاء حساب للمتابعة.", + save_session: "حفظ الجلسة", + save_session_c2a: "أنشئ حسابًا لحفظ جلستك الحالية وتجنب فقدان عملك.", + scan_qr_c2a: "امسح الرمز أدناه لتسجيل الدخول إلى هذه الجلسة من أجهزة أخرى", + scan_qr_2fa: "امسح رمز الاستجابة السريعة باستخدام تطبيق المصادقة الخاص بك", + scan_qr_generic: "امسح رمز الاستجابة السريعة هذا باستخدام هاتفك أو جهاز آخر", + search: "بحث", + seconds: "ثوانٍ", + security: "الأمان", + select: "تحديد", + selected: "محدد", + select_color: "اختر لونًا…", + sessions: "جلسات", + send: "إرسال", + send_password_recovery_email: "إرسال بريد استعادة كلمة المرور", + session_saved: "شكرًا لإنشاء حساب. تم حفظ هذه الجلسة.", + settings: "الإعدادات", + set_new_password: "تعيين كلمة مرور جديدة", + share: "مشاركة", + share_to: "مشاركة إلى", + share_with: "مشاركة مع:", + shortcut_to: "اختصار إلى", + show_all_windows: "عرض جميع النوافذ", + show_hidden: "إظهار المخفي", + sign_in_with_puter: "تسجيل الدخول باستخدام Puter", + sign_up: "تسجيل", + signing_in: "جارٍ تسجيل الدخول…", + size: "الحجم", + skip: "تخطي", + something_went_wrong: "حدث خطأ ما.", + sort_by: "فرز حسب", + start: "بدء", + status: "الحالة", + storage_usage: "استخدام التخزين", + storage_puter_used: "مستخدم بواسطة Puter", + taking_longer_than_usual: "يستغرق وقتًا أطول من المعتاد. يرجى الانتظار...", + task_manager: "مدير المهام", + taskmgr_header_name: "الاسم", + taskmgr_header_status: "الحالة", + taskmgr_header_type: "النوع", + terms: "الشروط", + text_document: "مستند نصي", + tos_fineprint: "بالنقر على 'إنشاء حساب مجاني' فإنك توافق على {{link=terms}}شروط الخدمة{{/link}} و{{link=privacy}}سياسة الخصوصية{{/link}} لـPuter.", + transparency: "الشفافية", + trash: "المهملات", + two_factor: "المصادقة الثنائية", + two_factor_disabled: "تم تعطيل المصادقة الثنائية", + two_factor_enabled: "تم تمكين المصادقة الثنائية" + type: "نوع", + type_confirm_to_delete_account: "اكتب 'تأكيد' لحذف حسابك.", + ui_colors: "ألوان واجهة المستخدم", + ui_manage_sessions: "مدير الجلسات", + ui_revoke: "إلغاء", + undo: "تراجع", + unlimited: "غير محدود", + unzip: "فك الضغط", + upload: "رفع", + upload_here: "ارفع هنا", + usage: "الاستخدام", + username: "اسم المستخدم", + username_changed: "تم تحديث اسم المستخدم بنجاح.", + username_required: "اسم المستخدم مطلوب.", + versions: "الإصدارات", + videos: "مقاطع الفيديو", + visibility: "الرؤية", + yes: "نعم", + yes_release_it: "نعم، أطلقه", + you_have_been_referred_to_puter_by_a_friend: "تم إحالتك إلى Puter بواسطة صديق!", + zip: "ضغط", + zipping_file: "جارٍ ضغط %strong%" + + // === 2FA Setup === + setup2fa_1_step_heading: "افتح تطبيق المصادقة الخاص بك", + setup2fa_1_instructions: ` + يمكنك استخدام أي تطبيق مصادقة يدعم بروتوكول كلمة المرور لمرة واحدة المعتمدة على الوقت (TOTP). + هناك العديد للاختيار من بينها، ولكن إذا كنت غير متأكد + Authy + هو خيار موثوق به لنظام Android و iOS. + `, + setup2fa_2_step_heading: "مسح رمز الاستجابة السريعة (QR code)", + setup2fa_3_step_heading: "أدخل الرمز المكون من 6 أرقام", + setup2fa_4_step_heading: "انسخ رموز الاسترداد الخاصة بك", + setup2fa_4_instructions: ` + هذه رموز الاسترداد هي الطريقة الوحيدة للوصول إلى حسابك إذا فقدت هاتفك أو لم تتمكن من استخدام تطبيق المصادقة الخاص بك. + تأكد من حفظها في مكان آمن. + `, + setup2fa_5_step_heading: "تأكيد إعداد المصادقة الثنائية (2FA)", + setup2fa_5_confirmation_1: "لقد قمت بحفظ رموز الاسترداد في مكان آمن", + setup2fa_5_confirmation_2: "أنا جاهز لتمكين المصادقة الثنائية (2FA)", + setup2fa_5_button: "تمكين المصادقة الثنائية (2FA)" + + // === 2FA Login === + login2fa_otp_title: "أدخل رمز المصادقة الثنائية (2FA)", + login2fa_otp_instructions: "أدخل الرمز المكون من 6 أرقام من تطبيق المصادقة الخاص بك.", + login2fa_recovery_title: "أدخل رمز الاسترداد", + login2fa_recovery_instructions: "أدخل أحد رموز الاسترداد الخاصة بك للوصول إلى حسابك.", + login2fa_use_recovery_code: "استخدام رمز الاسترداد", + login2fa_recovery_back: "الرجوع", + login2fa_recovery_placeholder: "XXXXXXXX" + } }; -export default ar; - +export default ar; \ No newline at end of file From 48f99fb8074d155422ab899ea3452eafce8d2e40 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 8 Jul 2024 16:56:36 -0400 Subject: [PATCH 0464/2119] dev: add script to replace release-please --- tools/gen-release-notes.js | 101 +++++++++++++++++++++++++++++++++++++ 1 file changed, 101 insertions(+) create mode 100644 tools/gen-release-notes.js diff --git a/tools/gen-release-notes.js b/tools/gen-release-notes.js new file mode 100644 index 0000000000..49987cd19f --- /dev/null +++ b/tools/gen-release-notes.js @@ -0,0 +1,101 @@ +import { simpleGit } from 'simple-git'; + +const REPO_URL = 'https://github.com/HeyPuter/puter'; + +const params = { + from: 'v2.3.0', + // from: 'v2.4.0', + to: 'v2.5.0', + date: '2024-07-08', +}; + +const git = simpleGit(); +const log = await git.log({ from: params.from }); +const commits = log.all; + +const CC_REGEX = /^([a-z]+)(\([a-z]+\))?:\s(.*)/; +const parse_conventional_commit = message => { + const parts = CC_REGEX.exec(message); + if ( ! parts ) return null; + let [match, type, scope, summary] = parts; + if ( ! match ) return null; + if ( scope ) scope = scope.slice(1, -1); + return { type, scope, summary }; +}; + +const types = { + feat: { + label: 'Features' + }, + fix: { + label: 'Bug Fixes' + } +}; + +const scopes = { + puter: { + label: 'Puter' + }, + phoenix: { + label: 'Phoenix Shell' + }, + git: { + label: 'Puter Git' + }, + backend: { + label: 'Backend' + }, + gui: { + label: 'GUI' + }, +}; + +const scope_aliases = { + main: 'puter', + ui: 'gui', + parsely: 'phoenix', +}; + +const data = {}; +const ensure_scope = name => { + if ( data[name] ) return; + const o = data[name] = {}; + for ( const k in types ) o[k] = []; +}; + +for ( const commit of commits ) { + const meta = parse_conventional_commit(commit.message); + if ( ! meta ) continue; + let scope = meta.scope ?? 'puter'; + while ( scope in scope_aliases ) { + scope = scope_aliases[scope]; + } + ensure_scope(scope); + if ( ! scopes[scope] ) { + console.log(commit); + throw new Error(`missing scope: ${scope}`); + } + + if ( types.hasOwnProperty(meta.type) ) { + data[scope][meta.type].push({ meta, commit }); + } +} + +let s = ''; +s += `## ${params.from} (${params.date})\n\n`; +for ( const scope_name in data ) { + const scope = data[scope_name]; + s += `### ${scopes[scope_name].label}\n\n`; + for ( const type_name in types ) { + const type = types[type_name]; + const items = scope[type_name]; + if ( items.length == 0 ) continue; + s += `#### ${type.label}\n\n`; + for ( const { meta, commit } of items ) { + const shorthash = commit.hash.slice(0,7) + s += `- ${meta.summary} ([${shorthash}](${REPO_URL}/commit/${commit.hash}))\n`; + } + } +} + +console.log(s); \ No newline at end of file From 42496f93194de5e57910ad6b1b6a5ecf96337fe2 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Mon, 8 Jul 2024 13:58:50 -0700 Subject: [PATCH 0465/2119] Add missing commas --- src/gui/src/i18n/translations/ar.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/gui/src/i18n/translations/ar.js b/src/gui/src/i18n/translations/ar.js index 16642a2b6b..b1492cddef 100644 --- a/src/gui/src/i18n/translations/ar.js +++ b/src/gui/src/i18n/translations/ar.js @@ -53,7 +53,7 @@ const en = { confirm_2fa_setup: "لقد أضفت الرمز إلى تطبيق المصادقة", confirm_2fa_recovery: "لقد حفظت رموز الاسترداد في مكان آمن", confirm_account_for_free_referral_storage_c2a: "أنشئ حسابًا وقم بتأكيد عنوان بريدك الإلكتروني للحصول على 1 جيجابايت من مساحة التخزين المجانية. سيحصل صديقك أيضًا على 1 جيجابايت من مساحة التخزين المجانية.", - confirm_code_generic_incorrect: "رمز غير صحيح." + confirm_code_generic_incorrect: "رمز غير صحيح.", confirm_code_generic_too_many_requests: "طلبات كثيرة جدًا. يرجى الانتظار بضع دقائق.", confirm_code_generic_submit: "إرسال الرمز", confirm_code_generic_try_again: "حاول مرة أخرى", @@ -93,7 +93,7 @@ const en = { date_modified: "تاريخ التعديل", default: "افتراضي", delete: "حذف", - delete_account: "حذف الحساب" + delete_account: "حذف الحساب", delete_permanently: "حذف نهائي", deleting_file: "جارٍ حذف %%", deploy_as_app: "نشر كتطبيق", @@ -133,7 +133,7 @@ const en = { feedback_c2a: "يرجى استخدام النموذج أدناه لإرسال ملاحظاتك وتعليقاتك وتقرير الأخطاء.", feedback_sent_confirmation: "شكرًا لتواصلك معنا. إذا كان لديك بريد إلكتروني مرتبط بحسابك، ستتلقى ردًا منا في أقرب وقت ممكن.", fit: "ملائمة", - folder: "مجلد" + folder: "مجلد", force_quit: "إنهاء بالقوة", forgot_pass_c2a: "هل نسيت كلمة المرور؟", from: "من", @@ -173,7 +173,7 @@ const en = { name_cannot_be_empty: "الاسم لا يمكن أن يكون فارغًا.", name_cannot_contain_double_period: "الاسم لا يمكن أن يكون '..'.", name_cannot_contain_period: "الاسم لا يمكن أن يكون '.'.", - name_cannot_contain_slash: "الاسم لا يمكن أن يحتوي على '/'." + name_cannot_contain_slash: "الاسم لا يمكن أن يحتوي على '/'.", name_must_be_string: "الاسم يجب أن يكون نصًا فقط.", name_too_long: "الاسم لا يمكن أن يكون أطول من %% حرف.", new: "جديد", @@ -233,7 +233,7 @@ const en = { refer_friends_social_media_c2a: "احصل على 1 جيجابايت من التخزين المجاني على Puter.com!", refresh: "تحديث", release_address_confirmation: "هل أنت متأكد أنك تريد تحرير هذا العنوان؟", - remove_from_taskbar: "إزالة من شريط المهام" + remove_from_taskbar: "إزالة من شريط المهام", rename: "إعادة تسمية", repeat: "تكرار", replace: "استبدال", @@ -293,7 +293,7 @@ const en = { trash: "المهملات", two_factor: "المصادقة الثنائية", two_factor_disabled: "تم تعطيل المصادقة الثنائية", - two_factor_enabled: "تم تمكين المصادقة الثنائية" + two_factor_enabled: "تم تمكين المصادقة الثنائية", type: "نوع", type_confirm_to_delete_account: "اكتب 'تأكيد' لحذف حسابك.", ui_colors: "ألوان واجهة المستخدم", @@ -315,7 +315,7 @@ const en = { yes_release_it: "نعم، أطلقه", you_have_been_referred_to_puter_by_a_friend: "تم إحالتك إلى Puter بواسطة صديق!", zip: "ضغط", - zipping_file: "جارٍ ضغط %strong%" + zipping_file: "جارٍ ضغط %strong%", // === 2FA Setup === setup2fa_1_step_heading: "افتح تطبيق المصادقة الخاص بك", @@ -335,7 +335,7 @@ const en = { setup2fa_5_step_heading: "تأكيد إعداد المصادقة الثنائية (2FA)", setup2fa_5_confirmation_1: "لقد قمت بحفظ رموز الاسترداد في مكان آمن", setup2fa_5_confirmation_2: "أنا جاهز لتمكين المصادقة الثنائية (2FA)", - setup2fa_5_button: "تمكين المصادقة الثنائية (2FA)" + setup2fa_5_button: "تمكين المصادقة الثنائية (2FA)", // === 2FA Login === login2fa_otp_title: "أدخل رمز المصادقة الثنائية (2FA)", From fe5be7f3cf7f336730137293ba86a637e8d8591d Mon Sep 17 00:00:00 2001 From: Med Elm Date: Mon, 8 Jul 2024 21:44:19 +0100 Subject: [PATCH 0466/2119] Update Arabic translations in src/gui/src/i18n/translations/ar.js to match English version in src/gui/src/i18n/translations/en.js --- src/gui/src/i18n/translations/ar.js | 475 +++++++++++++++++++--------- 1 file changed, 329 insertions(+), 146 deletions(-) diff --git a/src/gui/src/i18n/translations/ar.js b/src/gui/src/i18n/translations/ar.js index c429fd4858..16642a2b6b 100644 --- a/src/gui/src/i18n/translations/ar.js +++ b/src/gui/src/i18n/translations/ar.js @@ -16,153 +16,336 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const ar = { - name: "العربية", - english_name: "Arabic", - code: "ar", - dictionary: { - access_granted_to: "دخول مسموح به", - add_existing_account: "إضافة حساب موجود", - all_fields_required: 'يجب ملء كل الفراغات', - apply: "تطبيق ", - ascending: 'تصاعدي ', - background: "خلفية", - browse: "إبحث", - cancel: 'إلغاء', - center: 'وسط', - change_desktop_background: 'تغيير خلفية المكتب', - change_language: "تغيير اللغة", - change_password: "تغيير كلمة السر", - change_username: "تغيير إسم المستخدم", - close_all_windows: "غلق كل النوافذ", - color: 'اللون', - confirm_account_for_free_referral_storage_c2a: 'تأكيد الحساب لتخزين الإحالة المجانية ', - confirm_new_password: "تأكيد كلمة السر الجديدة", - contact_us: "اتصل بنا", - contain: 'إملء', - continue: "أكمل", - copy: 'أنسخ', - copy_link: "أنسخ الرابط", - copying: "ينسخ", - cover: 'غطاء', + +const en = { + name: "العربية", + english_name: "Arabic", + code: "ar", + dictionary: { + about: "حول", + account: "حساب", + account_password: "تحقق من كلمة مرور الحساب", + access_granted_to: "تم منح الوصول إلى", + add_existing_account: "إضافة حساب موجود", + all_fields_required: "جميع الحقول مطلوبة.", + allow: "السماح", + apply: "تطبيق", + ascending: "تصاعدي", + associated_websites: "المواقع المرتبطة", + auto_arrange: "ترتيب تلقائي", + background: "خلفية", + browse: "تصفح", + cancel: "إلغاء", + center: "مركز", + change_desktop_background: "تغيير خلفية سطح المكتب...", + change_email: "تغيير البريد الإلكتروني", + change_language: "تغيير اللغة", + change_password: "تغيير كلمة المرور", + change_ui_colors: "تغيير ألوان واجهة المستخدم", + change_username: "تغيير اسم المستخدم", + close: "إغلاق", + close_all_windows: "إغلاق جميع النوافذ", + close_all_windows_confirm: "هل أنت متأكد أنك تريد إغلاق جميع النوافذ؟", + close_all_windows_and_log_out: "إغلاق النوافذ وتسجيل الخروج", + change_always_open_with: "هل تريد دائمًا فتح هذا النوع من الملفات باستخدام", + color: "لون", + confirm: "تأكيد", + confirm_2fa_setup: "لقد أضفت الرمز إلى تطبيق المصادقة", + confirm_2fa_recovery: "لقد حفظت رموز الاسترداد في مكان آمن", + confirm_account_for_free_referral_storage_c2a: "أنشئ حسابًا وقم بتأكيد عنوان بريدك الإلكتروني للحصول على 1 جيجابايت من مساحة التخزين المجانية. سيحصل صديقك أيضًا على 1 جيجابايت من مساحة التخزين المجانية.", + confirm_code_generic_incorrect: "رمز غير صحيح." + confirm_code_generic_too_many_requests: "طلبات كثيرة جدًا. يرجى الانتظار بضع دقائق.", + confirm_code_generic_submit: "إرسال الرمز", + confirm_code_generic_try_again: "حاول مرة أخرى", + confirm_code_generic_title: "أدخل رمز التأكيد", + confirm_code_2fa_instruction: "أدخل الرمز المكون من 6 أرقام من تطبيق المصادقة الخاص بك.", + confirm_code_2fa_submit_btn: "إرسال", + confirm_code_2fa_title: "أدخل رمز المصادقة الثنائية", + confirm_delete_multiple_items: "هل أنت متأكد أنك تريد حذف هذه العناصر نهائيًا؟", + confirm_delete_single_item: "هل تريد حذف هذا العنصر نهائيًا؟", + confirm_open_apps_log_out: "لديك تطبيقات مفتوحة. هل أنت متأكد أنك تريد تسجيل الخروج؟", + confirm_new_password: "تأكيد كلمة المرور الجديدة", + confirm_delete_user: "هل أنت متأكد أنك تريد حذف حسابك؟ سيتم حذف جميع ملفاتك وبياناتك نهائيًا. لا يمكن التراجع عن هذا الإجراء.", + confirm_delete_user_title: "حذف الحساب؟", + confirm_session_revoke: "هل أنت متأكد أنك تريد إلغاء هذه الجلسة؟", + confirm_your_email_address: "تأكيد عنوان بريدك الإلكتروني", + contact_us: "اتصل بنا", + contact_us_verification_required: "يجب أن يكون لديك عنوان بريد إلكتروني مُؤكد لاستخدام هذه الخدمة.", + contain: "احتواء", + continue: "استمر", + copy: "نسخ", + copy_link: "نسخ الرابط", + copying: "جارٍ النسخ", + copying_file: "جارٍ نسخ %%", + cover: "تغطية", create_account: "إنشاء حساب", create_free_account: "إنشاء حساب مجاني", - create_shortcut: "تم تصميم المنتج", - current_password: "كلمة السر الحالية", - cut: 'إقطع', - date_modified: 'تغيير الوقت', - delete: 'حذف', - delete_permanently: "حذف دائم", - deploy_as_app: 'نشر كتطبيق', - descending: 'تنازلي', - desktop_background_fit: "خلفية سطح المكتب مناسبة", - dir_published_as_website: `:تم نشر الدليل كموقع ويب`, - disassociate_dir: "فصل الدليل", - download: 'تحميل ', - downloading: "جارى التحميل ", - email: "بريد إلكتروني", - email_or_username: "البريد الإلكتروني أو اسم المستخدم ", - empty_trash: 'سلة مهملات فارغة', - empty_trash_confirmation:'تأكيد إفراغ سلة المهملات ', - emptying_trash: 'إفراغ القمامة', - feedback: "تعليق ", - feedback_c2a: "تعليق ", - feedback_sent_confirmation: "أرسلت ردود الفعل التكوين ", - forgot_pass_c2a: "هل نسيت كلمة السر؟", - from: "من", - general: "عام ", - get_a_copy_of_on_puter: `الحصول على نسخة على جهاز الكمبيوتر`, - get_copy_link: 'الحصول على رابط النسخ', - hide_all_windows: "إخفاء كافة النوافذ ", - html_document: 'وثيقة أتش تي أم أل', - image: 'صورة', - invite_link: "رابط الدعوة", - items_in_trash_cannot_be_renamed: `لا يمكن إعادة تسمية العناصر الموجودة في سلة المهملات `, - jpeg_image: 'صورة j p e g', - keep_in_taskbar: 'احتفظ بها في شريط المهام ', - log_in: "تسجيل الدخول", - log_out: 'تسجيل خروج', - move: 'يتحرك', - moving_file: "متحرك %%", - my_websites: "مواقعي الإلكترونية ", - name: 'اسم', - name_cannot_be_empty: 'لا يمكن أن يكون الاسم فارغًا', - name_cannot_contain_double_period: "لا يمكن أن يحتوي الاسم على نقطة مزدوجة ", - name_cannot_contain_period: "لا يمكن أن يحتوي الاسم على فترة", - name_cannot_contain_slash: "لا يمكن أن يحتوي الاسم على شرطة مائلة", - name_must_be_string: "يجب أن يكون الاسم سلسلة", - name_too_long: `الاسم طويل جدًا`, - new: 'جديد', - new_folder: 'ملف جديد ', - new_password: "كلمة المرور الجديدة ", - new_username: "اسم مستخدم جديد ", - no_dir_associated_with_site: 'لا يوجد دليل مرتبط بالموقع', - no_websites_published: "لم يتم نشر أي مواقع", - ok: 'نعم', - open: "يفتح", - open_in_new_tab: "فتح في علامة تبويب جديدة", - open_in_new_window: "افتح في نافذة جديدة ", - open_with: "مفتوحة مع ", - password: "كلمة المرور ", - password_changed: "تم تغيير كلمة السر ", - passwords_do_not_match: 'كلمة المرور غير مطابقة', - paste: 'لصق', - paste_into_folder: "الصق داخل الملف", - pick_name_for_website: "اختيار اسم لموقع الويب ", - picture: "صورة ", - powered_by_puter_js: `مشغل بواسطة{{link=docs}}Puter.js{{/link}}`, - preparing: "إعداده", - preparing_for_upload: "التحضير للتحميل ", - properties: "ملكيات ", - publish: "ينشر", - publish_as_website: 'نشر كموقع على شبكة الإنترنت ', - recent: "مؤخرًا", - recover_password: "إستعادة كلمة المرور ", - refer_friends_c2a: "احصل على 1 جيجابايت لكل صديق يقوم بإنشاء حساب والتحقق منه مع Puter. صديقك يحصل على 1 غيغابايت أيضًا!", - refer_friends_social_media_c2a: `احصل على 1 غيغابايت من مساحة التخزين المجانية على موقع Puter.com!`, - refresh: 'ينعش ', - release_address_confirmation: `تأكيد عنوان الإصدار `, - remove_from_taskbar:'إزالة من شريط المهام ', - rename: 'إعادة تسمية', - repeat: 'تكرار', - resend_confirmation_code: "إعادة إرسال رمز التأكيد", - restore: "استرجاع", - save_account_to_get_copy_link: "حفظ الحساب للحصول على نسخة الرابط", - save_account_to_publish: 'حفظ الحساب للنشر', - save_session_c2a: 'حفظ جلسة ', - scan_qr_c2a: 'قم بمسح الرمز أدناه لتسجيل الدخول إلى هذه الجلسة من الأجهزة الأخرى', - select: "إختار", - select_color: 'إختر لون ', - send: "أرسل", - send_password_recovery_email: "إرسال بريد إلكتروني لاستعادة كلمة المرور", - session_saved: "تم حفظ الجلسة ", - set_new_password: "تعيين كلمة مرور جديدة ", - share_to: " شارك إلى", - show_all_windows: "إظهار كافة النوافذ ", - show_hidden: 'أظهر المخفي ', - sign_in_with_puter: "سجل الدخول ب Puter", - sign_up: "إشترك", - signing_in: "تسجيل الدخول", - size: 'الحجم', - sort_by: 'ترتيب حسب', - start: 'إبدأ ', - taking_longer_than_usual: 'يستغرق وقتا أطول من المعتاد ', - text_document: 'وثيقة نصية', - tos_fineprint: `بالنقر على "إنشاء حساب مجاني"، فإنك توافق على {{link=terms}}شروط الاستخدام{{/link}} و {{link=privacy}}حماية البيانات{{/link}}`, - trash: 'نفاية', - type: 'اكتب', - undo: 'الغاء التحميل', - unzip: "فك الضغط", - upload: 'رفع ', - upload_here: 'ارفع هنا', - username: "اسم المستخدم ", - username_changed: 'تم تغيير اسم المستخدم', - versions: "الإصدارات ", - yes_release_it: 'نعم أطلقه', - you_have_been_referred_to_puter_by_a_friend: "لقد تمت إحالتك إلى Puter بواسطة صديق!", - zip: "ملف مضغوط", - } + create_shortcut: "إنشاء اختصار", + credits: "الاعتمادات", + current_password: "كلمة المرور الحالية", + cut: "قص", + clock: "ساعة", + clock_visible_hide: "إخفاء - مخفية دائمًا", + clock_visible_show: "إظهار - مرئية دائمًا", + clock_visible_auto: "تلقائي - الافتراضي، مرئي فقط في وضع الشاشة الكاملة.", + close_all: "إغلاق الكل", + created: "تم الإنشاء", + date_modified: "تاريخ التعديل", + default: "افتراضي", + delete: "حذف", + delete_account: "حذف الحساب" + delete_permanently: "حذف نهائي", + deleting_file: "جارٍ حذف %%", + deploy_as_app: "نشر كتطبيق", + descending: "تنازلي", + desktop: "سطح المكتب", + desktop_background_fit: "ملائمة", + developers: "المطورين", + dir_published_as_website: "%strong% تم نشره إلى:", + disable_2fa: "تعطيل المصادقة الثنائية", + disable_2fa_confirm: "هل أنت متأكد أنك تريد تعطيل المصادقة الثنائية؟", + disable_2fa_instructions: "أدخل كلمة المرور لتعطيل المصادقة الثنائية.", + disassociate_dir: "فصل الدليل", + documents: "المستندات", + dont_allow: "عدم السماح", + download: "تنزيل", + download_file: "تنزيل الملف", + downloading: "جارٍ التنزيل", + email: "البريد الإلكتروني", + email_change_confirmation_sent: "تم إرسال بريد تأكيد إلى عنوان بريدك الإلكتروني الجديد. يرجى التحقق من صندوق الوارد واتباع التعليمات لإكمال العملية.", + email_invalid: "البريد الإلكتروني غير صالح.", + email_or_username: "البريد الإلكتروني أو اسم المستخدم", + email_required: "البريد الإلكتروني مطلوب.", + empty_trash: "إفراغ سلة المهملات", + empty_trash_confirmation: "هل أنت متأكد أنك تريد حذف العناصر في سلة المهملات نهائيًا؟", + emptying_trash: "جارٍ إفراغ سلة المهملات...", + enable_2fa: "تمكين المصادقة الثنائية", + end_hard: "إنهاء صعب", + end_process_force_confirm: "هل أنت متأكد أنك تريد إنهاء هذه العملية بالقوة؟", + end_soft: "إنهاء سلس", + enlarged_qr_code: "رمز QR مكبر", + enter_password_to_confirm_delete_user: "أدخل كلمة المرور لتأكيد حذف الحساب", + error_message_is_missing: "رسالة الخطأ مفقودة.", + error_unknown_cause: "حدث خطأ غير معروف.", + error_uploading_files: "فشل في تحميل الملفات", + favorites: "المفضلة", + feedback: "ملاحظات", + feedback_c2a: "يرجى استخدام النموذج أدناه لإرسال ملاحظاتك وتعليقاتك وتقرير الأخطاء.", + feedback_sent_confirmation: "شكرًا لتواصلك معنا. إذا كان لديك بريد إلكتروني مرتبط بحسابك، ستتلقى ردًا منا في أقرب وقت ممكن.", + fit: "ملائمة", + folder: "مجلد" + force_quit: "إنهاء بالقوة", + forgot_pass_c2a: "هل نسيت كلمة المرور؟", + from: "من", + general: "عام", + get_a_copy_of_on_puter: "احصل على نسخة من '%%' على Puter.com!", + get_copy_link: "احصل على رابط النسخ", + hide_all_windows: "إخفاء جميع النوافذ", + home: "الصفحة الرئيسية", + html_document: "مستند HTML", + hue: "درجة اللون", + image: "صورة", + incorrect_password: "كلمة مرور غير صحيحة", + invite_link: "رابط الدعوة", + item: "عنصر", + items_in_trash_cannot_be_renamed: "لا يمكن إعادة تسمية هذا العنصر لأنه في سلة المهملات. لإعادة تسمية هذا العنصر، اسحبه أولاً خارج سلة المهملات.", + jpeg_image: "صورة JPEG", + keep_in_taskbar: "الاحتفاظ في شريط المهام", + language: "اللغة", + license: "رخصة", + lightness: "إضاءة", + link_copied: "تم نسخ الرابط", + loading: "جارٍ التحميل", + log_in: "تسجيل الدخول", + log_into_another_account_anyway: "تسجيل الدخول إلى حساب آخر على أي حال", + log_out: "تسجيل الخروج", + looks_good: "يبدو جيدًا!", + manage_sessions: "إدارة الجلسات", + menubar_style: "نمط شريط القوائم", + menubar_style_desktop: "سطح المكتب", + menubar_style_system: "النظام", + menubar_style_window: "النافذة", + modified: "تم التعديل", + move: "نقل", + moving_file: "جارٍ نقل %%", + my_websites: "مواقعي الإلكترونية", + name: "اسم", + name_cannot_be_empty: "الاسم لا يمكن أن يكون فارغًا.", + name_cannot_contain_double_period: "الاسم لا يمكن أن يكون '..'.", + name_cannot_contain_period: "الاسم لا يمكن أن يكون '.'.", + name_cannot_contain_slash: "الاسم لا يمكن أن يحتوي على '/'." + name_must_be_string: "الاسم يجب أن يكون نصًا فقط.", + name_too_long: "الاسم لا يمكن أن يكون أطول من %% حرف.", + new: "جديد", + new_email: "البريد الإلكتروني الجديد", + new_folder: "مجلد جديد", + new_password: "كلمة المرور الجديدة", + new_username: "اسم المستخدم الجديد", + no: "لا", + no_dir_associated_with_site: "لا يوجد دليل مرتبط بهذا العنوان.", + no_websites_published: "لم تنشر أي مواقع إلكترونية بعد.", + ok: "موافق", + open: "فتح", + open_in_new_tab: "فتح في علامة تبويب جديدة", + open_in_new_window: "فتح في نافذة جديدة", + open_with: "فتح باستخدام", + original_name: "الاسم الأصلي", + original_path: "المسار الأصلي", + oss_code_and_content: "برامج ومحتوى مفتوح المصدر", + password: "كلمة المرور", + password_changed: "تم تغيير كلمة المرور.", + password_recovery_rate_limit: "لقد وصلت إلى الحد الأقصى؛ يرجى الانتظار بضع دقائق. لمنع حدوث ذلك في المستقبل، تجنب إعادة تحميل الصفحة كثيرًا.", + password_recovery_token_invalid: "رمز استعادة كلمة المرور لم يعد صالحًا.", + password_recovery_unknown_error: "حدث خطأ غير معروف. يرجى المحاولة مرة أخرى لاحقًا.", + password_required: "كلمة المرور مطلوبة.", + password_strength_error: "يجب أن تكون كلمة المرور بطول 8 أحرف على الأقل وتحتوي على حرف كبير واحد، حرف صغير واحد، رقم واحد، وحرف خاص واحد على الأقل.", + passwords_do_not_match: "`كلمة المرور الجديدة` و`تأكيد كلمة المرور الجديدة` غير متطابقتين.", + paste: "لصق", + paste_into_folder: "لصق في المجلد", + path: "المسار", + personalization: "تخصيص", + pick_name_for_website: "اختر اسمًا لموقعك الإلكتروني:", + picture: "صورة", + pictures: "الصور", + plural_suffix: "s", + powered_by_puter_js: "مدعوم بواسطة {{link=docs}}Puter.js{{/link}}", + preparing: "جارٍ التحضير...", + preparing_for_upload: "جارٍ التحضير للتحميل...", + print: "طباعة", + privacy: "الخصوصية", + proceed_to_login: "المتابعة لتسجيل الدخول", + proceed_with_account_deletion: "المتابعة مع حذف الحساب", + process_status_initializing: "جارٍ التهيئة", + process_status_running: "جارٍ التشغيل", + process_type_app: "تطبيق", + process_type_init: "تهيئة", + process_type_ui: "واجهة المستخدم", + properties: "الخصائص", + public: "عام", + publish: "نشر", + publish_as_website: "نشر كموقع إلكتروني", + puter_description: "Puter هو سحابة شخصية تركز على الخصوصية للحفاظ على جميع ملفاتك، تطبيقاتك، وألعابك في مكان آمن واحد، متاحة من أي مكان وفي أي وقت.", + reading_file: "جارٍ قراءة %strong%", + recent: "الأخيرة", + recommended: "مُوصى به", + recover_password: "استعادة كلمة المرور", + refer_friends_c2a: "احصل على 1 جيجابايت عن كل صديق ينشئ حسابًا ويؤكده على Puter. سيحصل صديقك على 1 جيجابايت أيضًا!", + refer_friends_social_media_c2a: "احصل على 1 جيجابايت من التخزين المجاني على Puter.com!", + refresh: "تحديث", + release_address_confirmation: "هل أنت متأكد أنك تريد تحرير هذا العنوان؟", + remove_from_taskbar: "إزالة من شريط المهام" + rename: "إعادة تسمية", + repeat: "تكرار", + replace: "استبدال", + replace_all: "استبدال الكل", + resend_confirmation_code: "إعادة إرسال رمز التأكيد", + reset_colors: "إعادة ضبط الألوان", + restart_puter_confirm: "هل أنت متأكد أنك تريد إعادة تشغيل Puter؟", + restore: "استعادة", + save: "حفظ", + saturation: "تشبع", + save_account: "حفظ الحساب", + save_account_to_get_copy_link: "يرجى إنشاء حساب للمتابعة.", + save_account_to_publish: "يرجى إنشاء حساب للمتابعة.", + save_session: "حفظ الجلسة", + save_session_c2a: "أنشئ حسابًا لحفظ جلستك الحالية وتجنب فقدان عملك.", + scan_qr_c2a: "امسح الرمز أدناه لتسجيل الدخول إلى هذه الجلسة من أجهزة أخرى", + scan_qr_2fa: "امسح رمز الاستجابة السريعة باستخدام تطبيق المصادقة الخاص بك", + scan_qr_generic: "امسح رمز الاستجابة السريعة هذا باستخدام هاتفك أو جهاز آخر", + search: "بحث", + seconds: "ثوانٍ", + security: "الأمان", + select: "تحديد", + selected: "محدد", + select_color: "اختر لونًا…", + sessions: "جلسات", + send: "إرسال", + send_password_recovery_email: "إرسال بريد استعادة كلمة المرور", + session_saved: "شكرًا لإنشاء حساب. تم حفظ هذه الجلسة.", + settings: "الإعدادات", + set_new_password: "تعيين كلمة مرور جديدة", + share: "مشاركة", + share_to: "مشاركة إلى", + share_with: "مشاركة مع:", + shortcut_to: "اختصار إلى", + show_all_windows: "عرض جميع النوافذ", + show_hidden: "إظهار المخفي", + sign_in_with_puter: "تسجيل الدخول باستخدام Puter", + sign_up: "تسجيل", + signing_in: "جارٍ تسجيل الدخول…", + size: "الحجم", + skip: "تخطي", + something_went_wrong: "حدث خطأ ما.", + sort_by: "فرز حسب", + start: "بدء", + status: "الحالة", + storage_usage: "استخدام التخزين", + storage_puter_used: "مستخدم بواسطة Puter", + taking_longer_than_usual: "يستغرق وقتًا أطول من المعتاد. يرجى الانتظار...", + task_manager: "مدير المهام", + taskmgr_header_name: "الاسم", + taskmgr_header_status: "الحالة", + taskmgr_header_type: "النوع", + terms: "الشروط", + text_document: "مستند نصي", + tos_fineprint: "بالنقر على 'إنشاء حساب مجاني' فإنك توافق على {{link=terms}}شروط الخدمة{{/link}} و{{link=privacy}}سياسة الخصوصية{{/link}} لـPuter.", + transparency: "الشفافية", + trash: "المهملات", + two_factor: "المصادقة الثنائية", + two_factor_disabled: "تم تعطيل المصادقة الثنائية", + two_factor_enabled: "تم تمكين المصادقة الثنائية" + type: "نوع", + type_confirm_to_delete_account: "اكتب 'تأكيد' لحذف حسابك.", + ui_colors: "ألوان واجهة المستخدم", + ui_manage_sessions: "مدير الجلسات", + ui_revoke: "إلغاء", + undo: "تراجع", + unlimited: "غير محدود", + unzip: "فك الضغط", + upload: "رفع", + upload_here: "ارفع هنا", + usage: "الاستخدام", + username: "اسم المستخدم", + username_changed: "تم تحديث اسم المستخدم بنجاح.", + username_required: "اسم المستخدم مطلوب.", + versions: "الإصدارات", + videos: "مقاطع الفيديو", + visibility: "الرؤية", + yes: "نعم", + yes_release_it: "نعم، أطلقه", + you_have_been_referred_to_puter_by_a_friend: "تم إحالتك إلى Puter بواسطة صديق!", + zip: "ضغط", + zipping_file: "جارٍ ضغط %strong%" + + // === 2FA Setup === + setup2fa_1_step_heading: "افتح تطبيق المصادقة الخاص بك", + setup2fa_1_instructions: ` + يمكنك استخدام أي تطبيق مصادقة يدعم بروتوكول كلمة المرور لمرة واحدة المعتمدة على الوقت (TOTP). + هناك العديد للاختيار من بينها، ولكن إذا كنت غير متأكد + Authy + هو خيار موثوق به لنظام Android و iOS. + `, + setup2fa_2_step_heading: "مسح رمز الاستجابة السريعة (QR code)", + setup2fa_3_step_heading: "أدخل الرمز المكون من 6 أرقام", + setup2fa_4_step_heading: "انسخ رموز الاسترداد الخاصة بك", + setup2fa_4_instructions: ` + هذه رموز الاسترداد هي الطريقة الوحيدة للوصول إلى حسابك إذا فقدت هاتفك أو لم تتمكن من استخدام تطبيق المصادقة الخاص بك. + تأكد من حفظها في مكان آمن. + `, + setup2fa_5_step_heading: "تأكيد إعداد المصادقة الثنائية (2FA)", + setup2fa_5_confirmation_1: "لقد قمت بحفظ رموز الاسترداد في مكان آمن", + setup2fa_5_confirmation_2: "أنا جاهز لتمكين المصادقة الثنائية (2FA)", + setup2fa_5_button: "تمكين المصادقة الثنائية (2FA)" + + // === 2FA Login === + login2fa_otp_title: "أدخل رمز المصادقة الثنائية (2FA)", + login2fa_otp_instructions: "أدخل الرمز المكون من 6 أرقام من تطبيق المصادقة الخاص بك.", + login2fa_recovery_title: "أدخل رمز الاسترداد", + login2fa_recovery_instructions: "أدخل أحد رموز الاسترداد الخاصة بك للوصول إلى حسابك.", + login2fa_use_recovery_code: "استخدام رمز الاسترداد", + login2fa_recovery_back: "الرجوع", + login2fa_recovery_placeholder: "XXXXXXXX" + } }; -export default ar; - +export default ar; \ No newline at end of file From 8bdd489eafc55e4e2540a8f9b29aee2249f7f6a1 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Mon, 8 Jul 2024 13:58:50 -0700 Subject: [PATCH 0467/2119] Add missing commas --- src/gui/src/i18n/translations/ar.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/gui/src/i18n/translations/ar.js b/src/gui/src/i18n/translations/ar.js index 16642a2b6b..b1492cddef 100644 --- a/src/gui/src/i18n/translations/ar.js +++ b/src/gui/src/i18n/translations/ar.js @@ -53,7 +53,7 @@ const en = { confirm_2fa_setup: "لقد أضفت الرمز إلى تطبيق المصادقة", confirm_2fa_recovery: "لقد حفظت رموز الاسترداد في مكان آمن", confirm_account_for_free_referral_storage_c2a: "أنشئ حسابًا وقم بتأكيد عنوان بريدك الإلكتروني للحصول على 1 جيجابايت من مساحة التخزين المجانية. سيحصل صديقك أيضًا على 1 جيجابايت من مساحة التخزين المجانية.", - confirm_code_generic_incorrect: "رمز غير صحيح." + confirm_code_generic_incorrect: "رمز غير صحيح.", confirm_code_generic_too_many_requests: "طلبات كثيرة جدًا. يرجى الانتظار بضع دقائق.", confirm_code_generic_submit: "إرسال الرمز", confirm_code_generic_try_again: "حاول مرة أخرى", @@ -93,7 +93,7 @@ const en = { date_modified: "تاريخ التعديل", default: "افتراضي", delete: "حذف", - delete_account: "حذف الحساب" + delete_account: "حذف الحساب", delete_permanently: "حذف نهائي", deleting_file: "جارٍ حذف %%", deploy_as_app: "نشر كتطبيق", @@ -133,7 +133,7 @@ const en = { feedback_c2a: "يرجى استخدام النموذج أدناه لإرسال ملاحظاتك وتعليقاتك وتقرير الأخطاء.", feedback_sent_confirmation: "شكرًا لتواصلك معنا. إذا كان لديك بريد إلكتروني مرتبط بحسابك، ستتلقى ردًا منا في أقرب وقت ممكن.", fit: "ملائمة", - folder: "مجلد" + folder: "مجلد", force_quit: "إنهاء بالقوة", forgot_pass_c2a: "هل نسيت كلمة المرور؟", from: "من", @@ -173,7 +173,7 @@ const en = { name_cannot_be_empty: "الاسم لا يمكن أن يكون فارغًا.", name_cannot_contain_double_period: "الاسم لا يمكن أن يكون '..'.", name_cannot_contain_period: "الاسم لا يمكن أن يكون '.'.", - name_cannot_contain_slash: "الاسم لا يمكن أن يحتوي على '/'." + name_cannot_contain_slash: "الاسم لا يمكن أن يحتوي على '/'.", name_must_be_string: "الاسم يجب أن يكون نصًا فقط.", name_too_long: "الاسم لا يمكن أن يكون أطول من %% حرف.", new: "جديد", @@ -233,7 +233,7 @@ const en = { refer_friends_social_media_c2a: "احصل على 1 جيجابايت من التخزين المجاني على Puter.com!", refresh: "تحديث", release_address_confirmation: "هل أنت متأكد أنك تريد تحرير هذا العنوان؟", - remove_from_taskbar: "إزالة من شريط المهام" + remove_from_taskbar: "إزالة من شريط المهام", rename: "إعادة تسمية", repeat: "تكرار", replace: "استبدال", @@ -293,7 +293,7 @@ const en = { trash: "المهملات", two_factor: "المصادقة الثنائية", two_factor_disabled: "تم تعطيل المصادقة الثنائية", - two_factor_enabled: "تم تمكين المصادقة الثنائية" + two_factor_enabled: "تم تمكين المصادقة الثنائية", type: "نوع", type_confirm_to_delete_account: "اكتب 'تأكيد' لحذف حسابك.", ui_colors: "ألوان واجهة المستخدم", @@ -315,7 +315,7 @@ const en = { yes_release_it: "نعم، أطلقه", you_have_been_referred_to_puter_by_a_friend: "تم إحالتك إلى Puter بواسطة صديق!", zip: "ضغط", - zipping_file: "جارٍ ضغط %strong%" + zipping_file: "جارٍ ضغط %strong%", // === 2FA Setup === setup2fa_1_step_heading: "افتح تطبيق المصادقة الخاص بك", @@ -335,7 +335,7 @@ const en = { setup2fa_5_step_heading: "تأكيد إعداد المصادقة الثنائية (2FA)", setup2fa_5_confirmation_1: "لقد قمت بحفظ رموز الاسترداد في مكان آمن", setup2fa_5_confirmation_2: "أنا جاهز لتمكين المصادقة الثنائية (2FA)", - setup2fa_5_button: "تمكين المصادقة الثنائية (2FA)" + setup2fa_5_button: "تمكين المصادقة الثنائية (2FA)", // === 2FA Login === login2fa_otp_title: "أدخل رمز المصادقة الثنائية (2FA)", From 7d92304e7fc81be29acb52acf90d080005b48818 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Mon, 8 Jul 2024 13:59:45 -0700 Subject: [PATCH 0468/2119] Update ar.js --- src/gui/src/i18n/translations/ar.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/ar.js b/src/gui/src/i18n/translations/ar.js index b1492cddef..6cf2074fcc 100644 --- a/src/gui/src/i18n/translations/ar.js +++ b/src/gui/src/i18n/translations/ar.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ -const en = { +const ar = { name: "العربية", english_name: "Arabic", code: "ar", From a9338b45c1f896abf9e7a07cceff4b73913c2d8e Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 8 Jul 2024 17:31:50 -0400 Subject: [PATCH 0469/2119] chore: update package.json --- package-lock.json | 44 ++++++++++++++++++++++++++++++++++++++++++++ package.json | 1 + 2 files changed, 45 insertions(+) diff --git a/package-lock.json b/package-lock.json index 3954e7fa84..7c07f6b964 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13,6 +13,7 @@ ], "dependencies": { "json-colorizer": "^3.0.1", + "simple-git": "^3.25.0", "string-template": "^1.0.0", "uuid": "^9.0.1" }, @@ -1731,6 +1732,19 @@ "url": "https://opencollective.com/js-sdsl" } }, + "node_modules/@kwsites/file-exists": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", + "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "dependencies": { + "debug": "^4.1.1" + } + }, + "node_modules/@kwsites/promise-deferred": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", + "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" + }, "node_modules/@mapbox/node-pre-gyp": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", @@ -11741,6 +11755,36 @@ "simple-concat": "^1.0.0" } }, + "node_modules/simple-git": { + "version": "3.25.0", + "resolved": "https://registry.npmjs.org/simple-git/-/simple-git-3.25.0.tgz", + "integrity": "sha512-KIY5sBnzc4yEcJXW7Tdv4viEz8KyG+nU0hay+DWZasvdFOYKeUZ6Xc25LUHHjw0tinPT7O1eY6pzX7pRT1K8rw==", + "dependencies": { + "@kwsites/file-exists": "^1.1.1", + "@kwsites/promise-deferred": "^1.1.1", + "debug": "^4.3.5" + }, + "funding": { + "type": "github", + "url": "https://github.com/steveukx/git-js?sponsor=1" + } + }, + "node_modules/simple-git/node_modules/debug": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz", + "integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/simple-swizzle": { "version": "0.2.2", "resolved": "https://registry.npmjs.org/simple-swizzle/-/simple-swizzle-0.2.2.tgz", diff --git a/package.json b/package.json index 7241c5f84a..a2df75b9d6 100644 --- a/package.json +++ b/package.json @@ -43,6 +43,7 @@ }, "dependencies": { "json-colorizer": "^3.0.1", + "simple-git": "^3.25.0", "string-template": "^1.0.0", "uuid": "^9.0.1" } From 42a6b3938a588b8b4d1bd976c37e9c6e58408c75 Mon Sep 17 00:00:00 2001 From: Matheus Carvalho Date: Mon, 8 Jul 2024 18:33:39 -0300 Subject: [PATCH 0470/2119] feat: update BR translation --- src/gui/src/i18n/translations/br.js | 447 ++++++++++++++++++---------- 1 file changed, 288 insertions(+), 159 deletions(-) diff --git a/src/gui/src/i18n/translations/br.js b/src/gui/src/i18n/translations/br.js index 6959b0cfb7..b9c4089350 100644 --- a/src/gui/src/i18n/translations/br.js +++ b/src/gui/src/i18n/translations/br.js @@ -16,207 +16,336 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const br = { - name: "Português (Brasil)", - english_name: "Portuguese (Brazil)", - code: "br", - dictionary: { - about: "Sobre", - access_granted_to: "Acesso garantido a", + name: "Português (Brasil)", + english_name: "Portuguese (Brazil)", + code: "br", + dictionary: { + about: "Sobre", account: "Conta", - add_existing_account: "Incluir Conta Existente", + account_password: "Verificar Senha da Conta", + access_granted_to: "Acesso Concedido Para", + add_existing_account: "Adicionar Conta Existente", all_fields_required: 'Todos os campos são obrigatórios.', + allow: 'Permitir', apply: "Aplicar", ascending: 'Ascendente', - auto_arrange: 'Auto Organizar', - background: "Tela de Fundo", - browse: "Pesquisar", + associated_websites: "Sites Associados", + auto_arrange: 'Organizar Automaticamente', + background: "Plano de Fundo", + browse: "Navegar", cancel: 'Cancelar', - center: 'Centrar', - change_always_open_with: "Quer sempre abrir arquivos deste tipo com", - change_desktop_background: 'Alterar Tela de Fundo', - change_language: "Alterar a Língua", - change_password: "Alterar a Senha", - change_ui_colors: "Alterar Cores da Interface", - change_username: "Alterar Nome de Utilizador", - clock: "Relógio", - close_all_windows_and_log_out: 'Fechar Janelas e Sair', + center: 'Centralizar', + change_desktop_background: 'Mudar plano de fundo da área de trabalho…', + change_email: "Mudar Email", + change_language: "Mudar Idioma", + change_password: "Mudar Senha", + change_ui_colors: "Mudar Cores da Interface", + change_username: "Mudar Nome de Usuário", + close: 'Fechar', close_all_windows: "Fechar Todas as Janelas", + close_all_windows_confirm: "Tem certeza de que deseja fechar todas as janelas?", + close_all_windows_and_log_out: 'Fechar Janelas e Sair', + change_always_open_with: "Deseja sempre abrir este tipo de arquivo com", color: 'Cor', - confirm_account_for_free_referral_storage_c2a: 'Crie uma conta e confirme o endereço do email para receber 1 GB de armazenamento gratuito. Seu amigo receberá 1 GB de armazenamento gratuito também.', - confirm_delete_multiple_items: 'Quer apagar estes itens permanentemente?', - confirm_delete_single_item: 'Quer apagar este item permanentemente?', - confirm_delete_user: "Você quer excluir sua conta? Todos os arquivos e informações poderão ser destruídas permanentemente. Esta operação não pode ser desfeita.", - confirm_new_password: "Confirme sua Nova Senha", - confirm_open_apps_log_out: 'Você possui aplicações abertas. Quer mesmo fechar sua sessão?', - contact_us: "Contate-nos", - contain: 'Contém', - continue: "Continua", - copy_link: "Copia Link", - copy: 'Copia', + confirm: 'Confirmar', + confirm_2fa_setup: 'Adicionei o código ao meu aplicativo autenticador', + confirm_2fa_recovery: 'Salvei meus códigos de recuperação em um local seguro', + confirm_account_for_free_referral_storage_c2a: 'Crie uma conta e confirme seu endereço de e-mail para receber 1 GB de armazenamento gratuito. Seu amigo também receberá 1 GB de armazenamento gratuito.', + confirm_code_generic_incorrect: "Código Incorreto.", + confirm_code_generic_too_many_requests: "Muitas solicitações. Por favor, aguarde alguns minutos.", + confirm_code_generic_submit: "Enviar Código", + confirm_code_generic_try_again: "Tente Novamente", + confirm_code_generic_title: "Digite o Código de Confirmação", + confirm_code_2fa_instruction: "Digite o código de 6 dígitos do seu aplicativo autenticador.", + confirm_code_2fa_submit_btn: "Enviar", + confirm_code_2fa_title: "Digite o Código 2FA", + confirm_delete_multiple_items: 'Tem certeza de que deseja excluir permanentemente estes itens?', + confirm_delete_single_item: 'Deseja excluir permanentemente este item?', + confirm_open_apps_log_out: 'Você tem aplicativos abertos. Tem certeza de que deseja sair?', + confirm_new_password: "Confirmar Nova Senha", + confirm_delete_user: "Tem certeza de que deseja excluir sua conta? Todos os seus arquivos e dados serão permanentemente excluídos. Esta ação não pode ser desfeita.", + confirm_delete_user_title: "Excluir Conta?", + confirm_session_revoke: "Tem certeza de que deseja revogar esta sessão?", + confirm_your_email_address: "Confirme Seu Endereço de Email", + contact_us: "Fale Conosco", + contact_us_verification_required: "Você deve ter um endereço de e-mail verificado para usar isto.", + contain: 'Conter', + continue: "Continuar", + copy: 'Copiar', + copy_link: "Copiar Link", copying: "Copiando", - cover: 'Capa', + copying_file: "Copiando %%", + cover: 'Cobrir', create_account: "Criar Conta", create_free_account: "Criar Conta Gratuita", create_shortcut: "Criar Atalho", credits: "Créditos", current_password: "Senha Atual", - cut: 'Cortar', - date_modified: 'Data alterada', + cut: 'Recortar', + clock: "Relógio", + clock_visible_hide: 'Ocultar - Sempre oculto', + clock_visible_show: 'Mostrar - Sempre visível', + clock_visible_auto: 'Auto - Padrão, visível apenas no modo de tela cheia.', + close_all: 'Fechar Tudo', + created: 'Criado', + date_modified: 'Data de modificação', + default: 'Padrão', + delete: 'Excluir', delete_account: "Excluir Conta", delete_permanently: "Excluir Permanentemente", - delete: 'Excluir', - deploy_as_app: 'Publicar como aplicativo', + deleting_file: "Excluindo %%", + deploy_as_app: 'Implantar como aplicativo', descending: 'Descendente', - desktop_background_fit: "Caber Exatamente", + desktop: 'Área de Trabalho', + desktop_background_fit: "Ajustar", developers: "Desenvolvedores", - dir_published_as_website: `%strong% foi publicado para:`, + dir_published_as_website: `%strong% foi publicado em:`, + disable_2fa: 'Desativar 2FA', + disable_2fa_confirm: "Tem certeza de que deseja desativar 2FA?", + disable_2fa_instructions: "Digite sua senha para desativar 2FA.", disassociate_dir: "Desassociar Diretório", - download_file: 'Download de Arquivo', - download: 'Download', - downloading: "Efectuando o Download", - email_or_username: "Email ou Nome de Utilizador", + documents: 'Documentos', + dont_allow: 'Não Permitir', + download: 'Baixar', + download_file: 'Baixar Arquivo', + downloading: "Baixando", email: "Email", - empty_trash_confirmation: `Você quer apagar os itens do Lixo permanentemente?`, - empty_trash: 'Esvaziar Lixo', - emptying_trash: 'Limpando o Lixoh…', - enter_password_to_confirm_delete_user: "Entre sua senha para confirmar a exclusão da conta", + email_change_confirmation_sent: "Um e-mail de confirmação foi enviado para seu novo endereço de e-mail. Por favor, verifique sua caixa de entrada e siga as instruções para concluir o processo.", + email_invalid: 'Email inválido.', + email_or_username: "Email ou Nome de Usuário", + email_required: 'Email é obrigatório.', + empty_trash: 'Esvaziar Lixeira', + empty_trash_confirmation: `Tem certeza de que deseja excluir permanentemente os itens na Lixeira?`, + emptying_trash: 'Esvaziando Lixeira…', + enable_2fa: 'Ativar 2FA', + end_hard: "Finalizar Forçadamente", + end_process_force_confirm: "Tem certeza de que deseja finalizar forçadamente este processo?", + end_soft: "Finalizar Suavemente", + enlarged_qr_code: "Código QR Ampliado", + enter_password_to_confirm_delete_user: "Digite sua senha para confirmar a exclusão da conta", + error_message_is_missing: "Mensagem de erro está ausente.", + error_unknown_cause: "Ocorreu um erro desconhecido.", + error_uploading_files: "Falha ao carregar arquivos", favorites: "Favoritos", - feedback_c2a: "Favor usar o formulário abaixo para enviar seus comentários e comunicados.", - feedback_sent_confirmation: "Obrigado por nos contactar. Se tiver email associado a esta conta, esperamos nos ver novamente.", feedback: "Feedback", + feedback_c2a: "Por favor, use o formulário abaixo para nos enviar seu feedback, comentários e relatórios de bugs.", + feedback_sent_confirmation: "Obrigado por nos contatar. Se você tiver um e-mail associado à sua conta, você receberá uma resposta nossa o mais rápido possível.", + fit: "Ajustar", + folder: 'Pasta', + force_quit: 'Forçar Encerrar', forgot_pass_c2a: "Esqueceu a senha?", from: "De", general: "Geral", - get_a_copy_of_on_puter: `Obter uma cópia de '%%' no Puter.com!`, - get_copy_link: 'Copiar Link', + get_a_copy_of_on_puter: `Obtenha uma cópia de '%%' em Puter.com!`, + get_copy_link: 'Obter Link de Cópia', hide_all_windows: "Ocultar Todas as Janelas", - home: "Início", + home: 'Início', html_document: 'Documento HTML', + hue: 'Matiz', image: 'Imagem', - invite_link: "Link do Convite", + incorrect_password: "Senha incorreta", + invite_link: "Link de Convite", item: 'item', - items_in_trash_cannot_be_renamed: `Item não pode ser renomeado porque está no lixo. Para renomear, arraste-o para fora do Lixo.`, + items_in_trash_cannot_be_renamed: `Este item não pode ser renomeado porque está na lixeira. Para renomear este item, primeiro arraste-o para fora da Lixeira.`, jpeg_image: 'Imagem JPEG', - keep_in_taskbar: 'Armazenar na Barra de Tarefas', + keep_in_taskbar: 'Manter na Barra de Tarefas', language: "Idioma", license: "Licença", + lightness: 'Luminosidade', + link_copied: "Link copiado", loading: 'Carregando', log_in: "Entrar", - log_into_another_account_anyway: 'Entrar com outra conta de qualquer maneira', + log_into_another_account_anyway: 'Entrar em outra conta de qualquer maneira', log_out: 'Sair', - manage_sessions: 'Gerenciar Sessões', - menubar_style_desktop: "Desktop", + looks_good: "Parece bom!", + manage_sessions: "Gerenciar Sessões", + menubar_style: "Estilo da Barra de Menus", + menubar_style_desktop: "Área de Trabalho", menubar_style_system: "Sistema", menubar_style_window: "Janela", - menubar_style: "Estilo da Barra de Menu", + modified: 'Modificado', move: 'Mover', moving_file: "Movendo %%", my_websites: "Meus Sites", - name_cannot_be_empty: 'Nome não pode ser vazio.', - name_cannot_contain_double_period: "Nome não pode conter o caracters '..'.", - name_cannot_contain_period: "Nome não pode conter o caracter '.'.", - name_cannot_contain_slash: "Nome não pode conter o caracter '/'.", - name_must_be_string: "Nome tem que ser apenas texto.", - name_too_long: `Nome não pode ter mais que %% characters.`, name: 'Nome', - new_folder: 'Nova Pasta', - new_password: "Nova Senha", - new_username: "Novo Utilizador", + name_cannot_be_empty: 'O nome não pode estar vazio.', + name_cannot_contain_double_period: "O nome não pode ser o caractere '..'.", + name_cannot_contain_period: "O nome não pode ser o caractere '.'.", + name_cannot_contain_slash: "O nome não pode conter o caractere '/'.", + name_must_be_string: "O nome só pode ser uma string.", + name_too_long: `O nome não pode ter mais de %% caracteres.`, new: 'Novo', - no_dir_associated_with_site: 'Não existe diretório associado com este endereço.', - no_websites_published: "Você ainda não publicou sites.", - no: 'Não', - ok: 'OK', - open_in_new_tab: "Abrir em Nova Aba", - open_in_new_window: "Abrir em Nova Janela", - open_with: "Abrir Com", - open: "Abrir", - oss_code_and_content: "Software de Código Aberto", - password_changed: "Senha alterada.", - password: "Senha", - passwords_do_not_match: '`Nova Senha` e `Confirmação de Nova Senha` não conferem com idênticas.', - paste_into_folder: "Cole na Pasta", - paste: 'Colar', - personalization: "Personalização", - pick_name_for_website: "Escolha um nome para seu site:", - picture: "Imagem", - plural_suffix: 's', - powered_by_puter_js: `Criado por {{link=docs}}Puter.js{{/link}}`, - preparing_for_upload: "Preparando para o envio...", - preparing: "Preparando...", - privacy: "Privacidade", - proceed_to_login: 'Proceguir para a entrada', - proceed_with_account_deletion: "Prosseguir com Exclusão da Conta", - properties: "Propriedades", - publish_as_website: 'Publicar como Site', - publish: "Publicar", - puter_description: `Puter é uma nuvem pessoal que prioriza a privacidade para manter todos os seus arquivos, aplicativos e jogos em um local seguro, acessível de qualquer lugar e a qualquer hora.`, - recent: "Recentes", - recover_password: "Recuperar Senha", - refer_friends_c2a: "Obtenha 1 GB para cada amigo que criar e confirmar uma conta no Puter. Seu amigo ganhará 1 GB também!", - refer_friends_social_media_c2a: `Obternha 1 GB de armazenamento gratuito no Puter.com!`, - refresh: 'Atualizar', - release_address_confirmation: `Você deseja liberar este endereço?`, - remove_from_taskbar:'Remover da Barra de Tarefas', - rename: 'Renomear', - repeat: 'Repetir', - replace_all: 'Substituir Todas', - replace: 'Substituir', - resend_confirmation_code: "Re-enviar o Código de Confirmação", - restore: "Restaurar", - save_account_to_get_copy_link: "Favor criar uma conta para prosseguir.", - save_account_to_publish: 'Favor criar uma conta para prosseguir.', - save_account: 'Gravar conta', - save_session_c2a: 'Crie uma conta para gravar a sessão atual e evitar a perda de seu trabalho.', - save_session: 'Gravar sessão', - scan_qr_c2a: 'Escaneie o código abaixo para entrar nesta sessão com outros dispositivos', - search: "Pesquisar", - security: "Segurança", - select_color: 'Selecionar cor…', - select: "Selecionar", - selected: 'selecionado', - send_password_recovery_email: "Enviar Email de Recuperação de Senha", - send: "Enviar", - session_saved: "Obrigado por criar uma conta. Esta sessão foi gravada.", - sessions: 'Sessões', - set_new_password: "Informar Nova Senha", - settings: "Configurações", - share_to: "Partilhar com", - show_all_windows: "Exibir Todas as Janelas", - show_hidden: 'Exibir oculto', - sign_in_with_puter: "Entrar no Puter", - sign_up: "Registar", - signing_in: "Entrar…", - size: 'Tamanho', - skip: 'Pular', - sort_by: 'Organizar por', - start: 'Início', - status: "Status", - storage_usage: "Uso do Armazenamento", - taking_longer_than_usual: 'Está a levar mais tempo que o usual. Por favor, aguarde...', - terms: "Termos", - text_document: 'Documento de Texto', - tos_fineprint: `Clicando em 'Criar Conta Gratuita' você concorda com os {{link=terms}}Termos de Serviço{{/link}} e {{link=privacy}}Política de Privacidade{{/link}} do Puter.`, - trash: 'Lixo', - type_confirm_to_delete_account: "Digite 'confirm' para excluir sua conta.", - type: 'Tipo', - ui_colors: "Cores da Interface", - undo: 'Desfazer', - unlimited: 'Ilimitado', - unzip: "Deszipar", - upload_here: 'Enviar aqui', - upload: 'Enviar', - usage: 'Uso', - username_changed: 'Nome de Utilizador atualizado com sucesso.', - username: "Nome de Utilizador", - versions: "Versões", - visibility: "Visibilidade", - yes_release_it: 'Sim, Libere Isto', - yes: 'Sim', - you_have_been_referred_to_puter_by_a_friend: "Você indicou o Puter a um amigo!", - zip: "Zipar", - } + new_email: 'Novo Email', + new_folder: 'Nova pasta', + new_password: "Nova Senha", + new_username: "Novo Nome de Usuário", + "no": "Não", + "no_dir_associated_with_site": "Nenhum diretório associado a este endereço.", + "no_websites_published": "Você ainda não publicou nenhum site.", + "ok": "OK", + "open": "Abrir", + "open_in_new_tab": "Abrir em Nova Aba", + "open_in_new_window": "Abrir em Nova Janela", + "open_with": "Abrir Com", + "original_name": "Nome Original", + "original_path": "Caminho Original", + "oss_code_and_content": "Software e Conteúdo de Código Aberto", + "password": "Senha", + "password_changed": "Senha alterada.", + "password_recovery_rate_limit": "Você atingiu nosso limite de tentativas; por favor, aguarde alguns minutos. Para evitar isso no futuro, evite recarregar a página muitas vezes.", + "password_recovery_token_invalid": "Este token de recuperação de senha não é mais válido.", + "password_recovery_unknown_error": "Ocorreu um erro desconhecido. Por favor, tente novamente mais tarde.", + "password_required": "Senha é necessária.", + "password_strength_error": "A senha deve ter pelo menos 8 caracteres e conter pelo menos uma letra maiúscula, uma letra minúscula, um número e um caractere especial.", + "passwords_do_not_match": "`Nova Senha` e `Confirmar Nova Senha` não correspondem.", + "paste": "Colar", + "paste_into_folder": "Colar na Pasta", + "path": "Caminho", + "personalization": "Personalização", + "pick_name_for_website": "Escolha um nome para o seu site:", + "picture": "Imagem", + "pictures": "Imagens", + "plural_suffix": "s", + "powered_by_puter_js": "Desenvolvido por {{link=docs}}Puter.js{{/link}}", + "preparing": "Preparando...", + "preparing_for_upload": "Preparando para upload...", + "print": "Imprimir", + "privacy": "Privacidade", + "proceed_to_login": "Prossiga para o login", + "proceed_with_account_deletion": "Prosseguir com a Exclusão da Conta", + "process_status_initializing": "Inicializando", + "process_status_running": "Executando", + "process_type_app": "App", + "process_type_init": "Início", + "process_type_ui": "UI", + "properties": "Propriedades", + "public": "Público", + "publish": "Publicar", + "publish_as_website": "Publicar como site", + "puter_description": "Puter é uma nuvem pessoal que prioriza a privacidade para manter todos os seus arquivos, aplicativos e jogos em um lugar seguro, acessível de qualquer lugar a qualquer momento.", + "reading_file": "Lendo %strong%", + "recent": "Recente", + "recommended": "Recomendado", + "recover_password": "Recuperar Senha", + "refer_friends_c2a": "Ganhe 1 GB para cada amigo que criar e confirmar uma conta no Puter. Seu amigo também ganhará 1 GB!", + "refer_friends_social_media_c2a": "Ganhe 1 GB de armazenamento gratuito no Puter.com!", + "refresh": "Atualizar", + "release_address_confirmation": "Tem certeza de que deseja liberar este endereço?", + "remove_from_taskbar": "Remover da Barra de Tarefas", + "rename": "Renomear", + "repeat": "Repetir", + "replace": "Substituir", + "replace_all": "Substituir Todos", + "resend_confirmation_code": "Reenviar Código de Confirmação", + "reset_colors": "Redefinir Cores", + "restart_puter_confirm": "Tem certeza de que deseja reiniciar o Puter?", + "restore": "Restaurar", + "save": "Salvar", + "saturation": "Saturação", + "save_account": "Salvar conta", + "save_account_to_get_copy_link": "Por favor, crie uma conta para prosseguir.", + "save_account_to_publish": "Por favor, crie uma conta para prosseguir.", + "save_session": "Salvar sessão", + "save_session_c2a": "Crie uma conta para salvar sua sessão atual e evitar perder seu trabalho.", + "scan_qr_c2a": "Escaneie o código abaixo para fazer login nesta sessão a partir de outros dispositivos", + "scan_qr_2fa": "Escaneie o código QR com seu aplicativo autenticador", + "scan_qr_generic": "Escaneie este código QR usando seu telefone ou outro dispositivo", + "search": "Buscar", + "seconds": "segundos", + "security": "Segurança", + "select": "Selecionar", + "selected": "selecionado", + "select_color": "Selecionar cor…", + "sessions": "Sessões", + "send": "Enviar", + "send_password_recovery_email": "Enviar E-mail de Recuperação de Senha", + "session_saved": "Obrigado por criar uma conta. Esta sessão foi salva.", + "settings": "Configurações", + "set_new_password": "Definir Nova Senha", + "share": "Compartilhar", + "share_to": "Compartilhar para", + "share_with": "Compartilhar com:", + "shortcut_to": "Atalho para", + "show_all_windows": "Mostrar Todas as Janelas", + "show_hidden": "Mostrar ocultos", + "sign_in_with_puter": "Entrar com Puter", + "sign_up": "Cadastrar-se", + "signing_in": "Entrando...", + "size": "Tamanho", + "skip": "Pular", + "something_went_wrong": "Algo deu errado.", + "sort_by": "Ordenar por", + "start": "Iniciar", + "status": "Status", + "storage_usage": "Uso de Armazenamento", + "storage_puter_used": "usado pelo Puter", + "taking_longer_than_usual": "Levando um pouco mais de tempo do que o normal. Por favor, aguarde...", + "task_manager": "Gerenciador de Tarefas", + "taskmgr_header_name": "Nome", + "taskmgr_header_status": "Status", + "taskmgr_header_type": "Tipo", + "terms": "Termos", + "text_document": "Documento de texto", + "tos_fineprint": "Ao clicar em 'Criar Conta Gratuita' você concorda com os {{link=terms}}Termos de Serviço{{/link}} e a {{link=privacy}}Política de Privacidade{{/link}} do Puter.", + "transparency": "Transparência", + "trash": "Lixeira", + "two_factor": "Autenticação de Dois Fatores", + "two_factor_disabled": "2FA Desativada", + "two_factor_enabled": "2FA Ativada", + "type": "Tipo", + "type_confirm_to_delete_account": "Digite 'confirmar' para excluir sua conta.", + "ui_colors": "Cores da Interface", + "ui_manage_sessions": "Gerenciador de Sessões", + "ui_revoke": "Revogar", + "undo": "Desfazer", + "unlimited": "Ilimitado", + "unzip": "Descompactar", + "upload": "Upload", + "upload_here": "Fazer upload aqui", + "usage": "Uso", + "username": "Nome de Usuário", + "username_changed": "Nome de usuário atualizado com sucesso.", + "username_required": "Nome de usuário é necessário.", + "versions": "Versões", + "videos": "Vídeos", + "visibility": "Visibilidade", + "yes": "Sim", + "yes_release_it": "Sim, Liberar", + "you_have_been_referred_to_puter_by_a_friend": "Você foi indicado ao Puter por um amigo!", + "zip": "Compactar", + "zipping_file": "Compactando %strong%", + + // === 2FA Setup === + "setup2fa_1_step_heading": "Abra seu aplicativo autenticador", + "setup2fa_1_instructions": ` + Você pode usar qualquer aplicativo autenticador que suporte o protocolo de Senha de Uso Único com Base em Tempo (TOTP). + Existem muitas opções, mas se você não tiver certeza + Authy + é uma escolha sólida para Android e iOS. + `, + "setup2fa_2_step_heading": "Escaneie o código QR", + "setup2fa_3_step_heading": "Digite o código de 6 dígitos", + "setup2fa_4_step_heading": "Copie seus códigos de recuperação", + "setup2fa_4_instructions": ` + Esses códigos de recuperação são a única maneira de acessar sua conta se você perder seu telefone ou não puder usar seu aplicativo autenticador. + Certifique-se de armazená-los em um lugar seguro. + `, + "setup2fa_5_step_heading": "Confirme a configuração do 2FA", + "setup2fa_5_confirmation_1": "Salvei meus códigos de recuperação em um local seguro", + "setup2fa_5_confirmation_2": "Estou pronto para ativar o 2FA", + "setup2fa_5_button": "Ativar 2FA", + + // === 2FA Login === + "login2fa_otp_title": "Digite o Código 2FA", + "login2fa_otp_instructions": "Digite o código de 6 dígitos do seu aplicativo autenticador.", + "login2fa_recovery_title": "Digite um código de recuperação", + "login2fa_recovery_instructions": "Digite um dos seus códigos de recuperação para acessar sua conta.", + "login2fa_use_recovery_code": "Usar um código de recuperação", + "login2fa_recovery_back": "Voltar", + "login2fa_recovery_placeholder": "XXXXXXXX" + } }; export default br; From 535475b3c36a37e3319ed067a24fb671790dcda3 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Mon, 8 Jul 2024 17:33:09 -0700 Subject: [PATCH 0471/2119] Improve `getMimeType` to remove trailing dot in the extension if preset --- src/dev-center/js/dev-center.js | 58 +++++++++++++++++++-------------- 1 file changed, 34 insertions(+), 24 deletions(-) diff --git a/src/dev-center/js/dev-center.js b/src/dev-center/js/dev-center.js index b15da104fd..752b2ff9a3 100644 --- a/src/dev-center/js/dev-center.js +++ b/src/dev-center/js/dev-center.js @@ -62,6 +62,7 @@ if(domain === 'puter.localhost'){ static_hosting_domain = 'site.puter.localhost'; } +// port if (URLParams.has('puter.port') && URLParams.get('puter.port')) { static_hosting_domain = static_hosting_domain + `:` + URLParams.get('puter.port'); } @@ -81,7 +82,6 @@ if (URLParams.has('puter.port') && URLParams.get('puter.port')) { $(document).ready(function () { $('#loading').show(); - // get dev profile setTimeout(async function () { puter.ui.onLaunchedWithItems(async function (items) { source_path = items[0].path; @@ -95,6 +95,7 @@ $(document).ready(function () { } }) + // Get dev profile. This is only for puter.com for now as we don't have dev profiles in self-hosted Puter if(domain === 'puter.com'){ puter.apps.getDeveloperProfile(async function (dev_profile) { developer = dev_profile; @@ -119,7 +120,7 @@ $(document).ready(function () { } }) } - // get apps + // Get apps puter.apps.list().then((resp) => { apps = resp; @@ -176,16 +177,16 @@ $(document).on('click', '.tab-btn', function (e) { $(this).addClass('active'); $('section[data-tab="' + $(this).attr('data-tab') + '"]').show(); - // ------------------------------ + // --------------------------------------------------------------- // Apps tab - // ------------------------------ + // --------------------------------------------------------------- if ($(this).attr('data-tab') === 'apps') { refresh_app_list(); activeTab = 'apps'; } - // ------------------------------ + // --------------------------------------------------------------- // Payout Method tab - // ------------------------------ + // --------------------------------------------------------------- else if ($(this).attr('data-tab') === 'payout-method') { activeTab = 'payout-method'; $('#loading').show(); @@ -318,6 +319,7 @@ async function create_app(title, source_path = null, items = null) { }) } + $(document).on('click', '.deploy-btn', function (e) { deploy(currently_editing_app, dropped_items); }) @@ -856,8 +858,6 @@ $('#earn-money::backdrop').click(async function (e) { puter.kv.set('earn-money-c2a-closed', 'true') }) - - $(document).on('click', '.edit-app-open-app-btn', async function (e) { puter.ui.launchApp($(this).attr('data-app-name')) }) @@ -983,8 +983,10 @@ $(document).on('click', '#edit-app-icon', async function (e) { let image = reader.result; // Get file extension let fileExtension = res2.name.split('.').pop(); + // Get MIME type let mimeType = getMimeType(fileExtension); + // Replace MIME type in the data URL image = image.replace('data:application/octet-stream;base64', `data:image/${mimeType};base64`); @@ -1066,10 +1068,7 @@ function generate_app_card(app) { h += ``; h += ``; - // // Open App - // h += ``; - // // Settings - // h += ``; + // "Approved for incentive program" if (app.approved_for_incentive_program) h += ``; From d3a9ba847ad891d768199f90a7f5b1ab4a959e43 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Mon, 8 Jul 2024 22:23:02 -0700 Subject: [PATCH 0473/2119] Move icon credits to the GUI project directory --- README.md | 16 ---------------- src/gui/CREDITS.md | 13 +++++++++++++ 2 files changed, 13 insertions(+), 16 deletions(-) create mode 100644 src/gui/CREDITS.md diff --git a/README.md b/README.md index f2289243fa..8c04c14e04 100644 --- a/README.md +++ b/README.md @@ -100,19 +100,3 @@ This repository is licensed under AGPL-3.0; However, our SDK (puter.js) is also - [Tesla Model Y](https://twitter.com/HeyPuter/status/1772858333751636310) - [Nintendo Switch](https://twitter.com/HeyPuter/status/1780645795240538518) - [Steam Deck](https://twitter.com/everythingSung/status/1782162352403828793) - -
- -## Credits - -The default wallpaper is created by [Milad Fakurian](https://unsplash.com/photos/blue-orange-and-yellow-wallpaper-E8Ufcyxz514) and published on [Unsplash](https://unsplash.com/). - -Icons by [Papirus](https://github.com/PapirusDevelopmentTeam/papirus-icon-theme) under GPL-3.0 license. - -Icons by [Iconoir](https://iconoir.com/) under MIT license. - -Icons by [Elementary Icons](https://github.com/elementary/icons) under GPL-3.0 license. - -Icons by [Tabler Icons](https://tabler.io/) under MIT license. - -Icons by [bootstrap-icons](https://icons.getbootstrap.com/) under MIT license. diff --git a/src/gui/CREDITS.md b/src/gui/CREDITS.md new file mode 100644 index 0000000000..5f4260d3b7 --- /dev/null +++ b/src/gui/CREDITS.md @@ -0,0 +1,13 @@ +## Credits + +The default wallpaper is created by [Milad Fakurian](https://unsplash.com/photos/blue-orange-and-yellow-wallpaper-E8Ufcyxz514) and published on [Unsplash](https://unsplash.com/). + +Icons by [Papirus](https://github.com/PapirusDevelopmentTeam/papirus-icon-theme) under GPL-3.0 license. + +Icons by [Iconoir](https://iconoir.com/) under MIT license. + +Icons by [Elementary Icons](https://github.com/elementary/icons) under GPL-3.0 license. + +Icons by [Tabler Icons](https://tabler.io/) under MIT license. + +Icons by [bootstrap-icons](https://icons.getbootstrap.com/) under MIT license. From 47f76ccc8968cc92a88add99a3529939341ccb60 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 9 Jul 2024 03:15:42 -0400 Subject: [PATCH 0474/2119] dev: add file walker --- package.json | 3 +- tools/file-walker/package.json | 15 +++ tools/file-walker/test.js | 181 +++++++++++++++++++++++++++++++++ 3 files changed, 198 insertions(+), 1 deletion(-) create mode 100644 tools/file-walker/package.json create mode 100644 tools/file-walker/test.js diff --git a/package.json b/package.json index a2df75b9d6..2ac95fb530 100644 --- a/package.json +++ b/package.json @@ -32,7 +32,8 @@ "check-translations": "node tools/check-translations.js" }, "workspaces": [ - "src/*" + "src/*", + "tools/*" ], "nodemonConfig": { "ext": "js, json, mjs, jsx, svg, css", diff --git a/tools/file-walker/package.json b/tools/file-walker/package.json new file mode 100644 index 0000000000..c49603b1be --- /dev/null +++ b/tools/file-walker/package.json @@ -0,0 +1,15 @@ +{ + "name": "file-walker", + "version": "1.0.0", + "description": "", + "main": "test.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "AGPL-3.0-only", + "dependencies": { + } +} + diff --git a/tools/file-walker/test.js b/tools/file-walker/test.js new file mode 100644 index 0000000000..515ad1b3a3 --- /dev/null +++ b/tools/file-walker/test.js @@ -0,0 +1,181 @@ +const fs = require('fs'); +const fsp = fs.promises; +const path_ = require('path'); + +const hl_readdir = async path => { + const names = await fs.promises.readdir(path); + const entries = []; + + for ( const name of names ) { + // wet: copied from phoenix shell + const stat_path = path_.join(path, name); + const stat = await fs.promises.lstat(stat_path); + entries.push({ + name, + is_dir: stat.isDirectory(), + is_symlink: stat.isSymbolicLink(), + symlink_path: stat.isSymbolicLink() ? await fs.promises.readlink(stat_path) : null, + size: stat.size, + modified: stat.mtimeMs / 1000, + created: stat.ctimeMs / 1000, + accessed: stat.atimeMs / 1000, + mode: stat.mode, + uid: stat.uid, + gid: stat.gid, + }); + } + + return entries; +}; + +const walk = async function* walk (options, root_path, components = []) { + const current_path = path_.join(root_path, ...components); + const entries = await hl_readdir(current_path); + outer: + for ( const entry of entries ) { + entry.dirpath = current_path; + entry.path = path_.join(current_path, entry.name); + + // TODO: labelled break? + for ( const exclude_regex of (options.excludes ?? []) ) { + if ( exclude_regex.test(entry.path) ) { + continue outer; + } + } + + if ( ! options.pre_order ) yield entry; + if ( entry.is_dir ) { + yield* walk(options, root_path, [...components, entry.name]); + } + if ( options.pre_order ) yield entry; + } +}; + +const modes = { + primary_source_files: { + excludes: [ + ] + }, +}; + +const util = require('util'); +const exec = util.promisify(require('child_process').exec); + +async function git_blame(path) { + const abs_path = path_.resolve(path); + + try { + const { stdout } = await exec(`git blame -f "${abs_path}"`, { + maxBuffer: 1024 * 1024 + }); + + const blameLines = stdout.split('\n'); + const parsedBlame = blameLines + .map(line => { + if (!line.trim()) return null; + + // console.log(line); + const parts = line.split(/\s+/); + let [commitHash, path, author, timestamp, lineNumber, , ,] = parts; + author = author.slice(1); + + const o = { + commitHash, + author, + timestamp, + lineNumber: parseInt(lineNumber, 10), + }; + return o; + }) + .filter(item => item !== null) + ; + + return parsedBlame; + } catch (error) { + console.log('AZXV') + throw new Error(`Error executing git blame: ${error.message}`); + } +} + +// Example usage +const blame = async (path) => { + try { + const result = await git_blame(path); + // console.log('result?', result) + return result; + } catch ( e ) { + console.log('SKIPPED: ' + e.message); + } + return []; +} + +const walk_test = async () => { + // console.log(await hl_readdir('.')); + for await ( const value of walk({ + excludes: [ + /^\.git/, + /^volatile\//, + /^node_modules\//, + /\/node_modules$/, + /^node_modules$/, + /package-lock\.json/, + /^src\/gui\/dist/, + ] + }, '.') ) { + if ( ! value.is_dir ) continue; + console.log('value', value.path); + } +} + +const authors = {}; + +const blame_test = async () => { + // const results = await blame('src/backend/src/services/HostDiskUsageService.js'); + // const results = await blame('package.json'); + console.log('results', results) + return; + for ( const result of results ) { + if ( ! authors[result.author] ) { + authors[result.author] = { lines: 0 }; + } + authors[result.author].lines++; + } + + console.log('AUTHORS', authors); +} + + +/* +Contribution count function to test file walking and +git blame parsing. +*/ +const walk_and_blame = async () => { + // console.log(await hl_readdir('.')); + for await ( const value of walk({ + excludes: [ + /^\.git/, + /^volatile\//, + /^node_modules\//, + /\/node_modules$/, + /^node_modules$/, + /package-lock\.json/, + /src\/backend\/src\/public\/assets/, + /^src\/gui\/src\/lib/ + ] + }, '.') ) { + if ( value.is_dir ) continue; + console.log('value', value.path); + const results = await blame(value.path); + for ( const result of results ) { + if ( ! authors[result.author] ) { + authors[result.author] = { lines: 0 }; + } + authors[result.author].lines++; + } + } + console.log('AUTHORS', authors); +} + +const main = walk_and_blame; + +main(); From 0b39c76c4035c6c30c066d663fe0c7a0b324d225 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 9 Jul 2024 03:19:31 -0400 Subject: [PATCH 0475/2119] move: incubator to experiments This name is easier to understand and more generalizable. --- {incubator => experiments}/x86emu/.gitignore | 0 {incubator => experiments}/x86emu/LICENSE | 0 {incubator => experiments}/x86emu/README.md | 0 {incubator => experiments}/x86emu/imagegen/Dockerfile | 0 {incubator => experiments}/x86emu/imagegen/config/networking.sh | 0 {incubator => experiments}/x86emu/make_container/Dockerfile | 0 {incubator => experiments}/x86emu/sandbox/.clang-format | 0 {incubator => experiments}/x86emu/sandbox/canva.html | 0 {incubator => experiments}/x86emu/sandbox/fifotest.cpp | 0 {incubator => experiments}/x86emu/sandbox/sound.c | 0 {incubator => experiments}/x86emu/v86starter.sh | 0 {incubator => experiments}/x86emu/www/index.html | 0 {incubator => experiments}/x86emu/www/js/Instance.mjs | 0 {incubator => experiments}/x86emu/www/js/InstanceManager.mjs | 0 {incubator => experiments}/x86emu/www/js/V86Wrapper.mjs | 0 {incubator => experiments}/x86emu/www/main.js | 0 {incubator => experiments}/x86emu/www/package.json | 0 {incubator => experiments}/x86emu/www/static/.gitkeep | 0 {incubator => experiments}/x86emu/www/third-party/libv86.js | 0 {incubator => experiments}/x86emu/www/third-party/starter.js | 0 {incubator => experiments}/x86emu/www/third-party/xterm.css | 0 {incubator => experiments}/x86emu/www/third-party/xterm.js | 0 22 files changed, 0 insertions(+), 0 deletions(-) rename {incubator => experiments}/x86emu/.gitignore (100%) rename {incubator => experiments}/x86emu/LICENSE (100%) rename {incubator => experiments}/x86emu/README.md (100%) rename {incubator => experiments}/x86emu/imagegen/Dockerfile (100%) rename {incubator => experiments}/x86emu/imagegen/config/networking.sh (100%) rename {incubator => experiments}/x86emu/make_container/Dockerfile (100%) rename {incubator => experiments}/x86emu/sandbox/.clang-format (100%) rename {incubator => experiments}/x86emu/sandbox/canva.html (100%) rename {incubator => experiments}/x86emu/sandbox/fifotest.cpp (100%) rename {incubator => experiments}/x86emu/sandbox/sound.c (100%) rename {incubator => experiments}/x86emu/v86starter.sh (100%) rename {incubator => experiments}/x86emu/www/index.html (100%) rename {incubator => experiments}/x86emu/www/js/Instance.mjs (100%) rename {incubator => experiments}/x86emu/www/js/InstanceManager.mjs (100%) rename {incubator => experiments}/x86emu/www/js/V86Wrapper.mjs (100%) rename {incubator => experiments}/x86emu/www/main.js (100%) rename {incubator => experiments}/x86emu/www/package.json (100%) rename {incubator => experiments}/x86emu/www/static/.gitkeep (100%) rename {incubator => experiments}/x86emu/www/third-party/libv86.js (100%) rename {incubator => experiments}/x86emu/www/third-party/starter.js (100%) rename {incubator => experiments}/x86emu/www/third-party/xterm.css (100%) rename {incubator => experiments}/x86emu/www/third-party/xterm.js (100%) diff --git a/incubator/x86emu/.gitignore b/experiments/x86emu/.gitignore similarity index 100% rename from incubator/x86emu/.gitignore rename to experiments/x86emu/.gitignore diff --git a/incubator/x86emu/LICENSE b/experiments/x86emu/LICENSE similarity index 100% rename from incubator/x86emu/LICENSE rename to experiments/x86emu/LICENSE diff --git a/incubator/x86emu/README.md b/experiments/x86emu/README.md similarity index 100% rename from incubator/x86emu/README.md rename to experiments/x86emu/README.md diff --git a/incubator/x86emu/imagegen/Dockerfile b/experiments/x86emu/imagegen/Dockerfile similarity index 100% rename from incubator/x86emu/imagegen/Dockerfile rename to experiments/x86emu/imagegen/Dockerfile diff --git a/incubator/x86emu/imagegen/config/networking.sh b/experiments/x86emu/imagegen/config/networking.sh similarity index 100% rename from incubator/x86emu/imagegen/config/networking.sh rename to experiments/x86emu/imagegen/config/networking.sh diff --git a/incubator/x86emu/make_container/Dockerfile b/experiments/x86emu/make_container/Dockerfile similarity index 100% rename from incubator/x86emu/make_container/Dockerfile rename to experiments/x86emu/make_container/Dockerfile diff --git a/incubator/x86emu/sandbox/.clang-format b/experiments/x86emu/sandbox/.clang-format similarity index 100% rename from incubator/x86emu/sandbox/.clang-format rename to experiments/x86emu/sandbox/.clang-format diff --git a/incubator/x86emu/sandbox/canva.html b/experiments/x86emu/sandbox/canva.html similarity index 100% rename from incubator/x86emu/sandbox/canva.html rename to experiments/x86emu/sandbox/canva.html diff --git a/incubator/x86emu/sandbox/fifotest.cpp b/experiments/x86emu/sandbox/fifotest.cpp similarity index 100% rename from incubator/x86emu/sandbox/fifotest.cpp rename to experiments/x86emu/sandbox/fifotest.cpp diff --git a/incubator/x86emu/sandbox/sound.c b/experiments/x86emu/sandbox/sound.c similarity index 100% rename from incubator/x86emu/sandbox/sound.c rename to experiments/x86emu/sandbox/sound.c diff --git a/incubator/x86emu/v86starter.sh b/experiments/x86emu/v86starter.sh similarity index 100% rename from incubator/x86emu/v86starter.sh rename to experiments/x86emu/v86starter.sh diff --git a/incubator/x86emu/www/index.html b/experiments/x86emu/www/index.html similarity index 100% rename from incubator/x86emu/www/index.html rename to experiments/x86emu/www/index.html diff --git a/incubator/x86emu/www/js/Instance.mjs b/experiments/x86emu/www/js/Instance.mjs similarity index 100% rename from incubator/x86emu/www/js/Instance.mjs rename to experiments/x86emu/www/js/Instance.mjs diff --git a/incubator/x86emu/www/js/InstanceManager.mjs b/experiments/x86emu/www/js/InstanceManager.mjs similarity index 100% rename from incubator/x86emu/www/js/InstanceManager.mjs rename to experiments/x86emu/www/js/InstanceManager.mjs diff --git a/incubator/x86emu/www/js/V86Wrapper.mjs b/experiments/x86emu/www/js/V86Wrapper.mjs similarity index 100% rename from incubator/x86emu/www/js/V86Wrapper.mjs rename to experiments/x86emu/www/js/V86Wrapper.mjs diff --git a/incubator/x86emu/www/main.js b/experiments/x86emu/www/main.js similarity index 100% rename from incubator/x86emu/www/main.js rename to experiments/x86emu/www/main.js diff --git a/incubator/x86emu/www/package.json b/experiments/x86emu/www/package.json similarity index 100% rename from incubator/x86emu/www/package.json rename to experiments/x86emu/www/package.json diff --git a/incubator/x86emu/www/static/.gitkeep b/experiments/x86emu/www/static/.gitkeep similarity index 100% rename from incubator/x86emu/www/static/.gitkeep rename to experiments/x86emu/www/static/.gitkeep diff --git a/incubator/x86emu/www/third-party/libv86.js b/experiments/x86emu/www/third-party/libv86.js similarity index 100% rename from incubator/x86emu/www/third-party/libv86.js rename to experiments/x86emu/www/third-party/libv86.js diff --git a/incubator/x86emu/www/third-party/starter.js b/experiments/x86emu/www/third-party/starter.js similarity index 100% rename from incubator/x86emu/www/third-party/starter.js rename to experiments/x86emu/www/third-party/starter.js diff --git a/incubator/x86emu/www/third-party/xterm.css b/experiments/x86emu/www/third-party/xterm.css similarity index 100% rename from incubator/x86emu/www/third-party/xterm.css rename to experiments/x86emu/www/third-party/xterm.css diff --git a/incubator/x86emu/www/third-party/xterm.js b/experiments/x86emu/www/third-party/xterm.js similarity index 100% rename from incubator/x86emu/www/third-party/xterm.js rename to experiments/x86emu/www/third-party/xterm.js From 50036e954d55c73cd7c5c4c482a24d58d60edcbc Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 9 Jul 2024 03:40:34 -0400 Subject: [PATCH 0476/2119] dev: add js-parse-and-output experiment --- experiments/js-parse-and-output/README.md | 29 ++++ experiments/js-parse-and-output/package.json | 20 +++ experiments/js-parse-and-output/test.js | 37 +++++ package-lock.json | 134 ++++++++++++++++--- package.json | 3 +- 5 files changed, 203 insertions(+), 20 deletions(-) create mode 100644 experiments/js-parse-and-output/README.md create mode 100644 experiments/js-parse-and-output/package.json create mode 100644 experiments/js-parse-and-output/test.js diff --git a/experiments/js-parse-and-output/README.md b/experiments/js-parse-and-output/README.md new file mode 100644 index 0000000000..9c6e7fb900 --- /dev/null +++ b/experiments/js-parse-and-output/README.md @@ -0,0 +1,29 @@ +# Parsing Javascript and Generating it Back + +## What Purpose? + +This would be really useful for refactoring tools. I also want +automatic comments to be placed when certain features are used, +such as the [Sequence](../../src/backend/src/codex/Sequence.js) +class, since its usefulness won't be immediately apparent where +it appears in the source code. + +I turns out the state of affairs with respect to generating a +CST for javascript... [kind of sucks](https://github.com/benjamn/recast/issues/1412). +I hope that further discussion on the issue I linked renders the +previous statement ironic. + +## So, What Next? + +The options I see are: +1. Add support to recast to make use of @babel/parser tokens when + the `tokens: true` option is set. +2. Add a format-preserving outputter to @babel/outputter. + [this is being worked on](https://github.com/babel/rfcs/pull/15) +3. Wait for someone else to do either of the previous two things. +4. Write a CST parser for javascript. + +I'm going to start with option #3. It's very disappointing that +I don't have time to do #4, because I don't very much like solutions +#1 and #2; I like my CSTs to be more cohesive - a pyramid of meaning - +rather than lexer output dumped at the end of an AST. diff --git a/experiments/js-parse-and-output/package.json b/experiments/js-parse-and-output/package.json new file mode 100644 index 0000000000..e0ee5f7265 --- /dev/null +++ b/experiments/js-parse-and-output/package.json @@ -0,0 +1,20 @@ +{ + "name": "js-parse-and-output", + "version": "1.0.0", + "description": "", + "main": "test.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "AGPL-3.0-only", + "dependencies": { + "@babel/generator": "^7.24.7", + "@babel/parser": "^7.24.7", + "acorn": "^8.12.1", + "acorn-static-class-features": "^1.0.0", + "escodegen": "^2.1.0", + "recast": "^0.23.9" + } +} diff --git a/experiments/js-parse-and-output/test.js b/experiments/js-parse-and-output/test.js new file mode 100644 index 0000000000..3fa6568a55 --- /dev/null +++ b/experiments/js-parse-and-output/test.js @@ -0,0 +1,37 @@ +const babelParser = require('@babel/parser'); +const generate = (require('@babel/generator')).default; +const fs = require('fs'); + +const recast = require('recast'); + +const example = fs.readFileSync('./src/backend/src/filesystem/ll_operations/ll_read.js'); + +{ + const ast = recast.parse(example, { + parser: { + parse (source) { + return babelParser.parse(source, { + ranges: true, + tokens: true, + }); + }, + }, + }); + const { code } = recast.print(ast); +} + +{ + const ast = babelParser.parse('' + example, { + tokens: true, + }); + + console.log(JSON.stringify(ast, undefined, ' ')); +} + +/* +const { code } = generate(ast, { + retainLines: true, +}); +*/ + +// console.log(code); \ No newline at end of file diff --git a/package-lock.json b/package-lock.json index 7c07f6b964..73908b7721 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9,7 +9,9 @@ "version": "1.0.0", "license": "AGPL-3.0-only", "workspaces": [ - "src/*" + "src/*", + "tools/*", + "experiments/js-parse-and-output" ], "dependencies": { "json-colorizer": "^3.0.1", @@ -224,6 +226,18 @@ "extraneous": true, "license": "AGPL-3.0-only" }, + "experiments/js-parse-and-output": { + "version": "1.0.0", + "license": "AGPL-3.0-only", + "dependencies": { + "@babel/generator": "^7.24.7", + "@babel/parser": "^7.24.7", + "acorn": "^8.12.1", + "acorn-static-class-features": "^1.0.0", + "escodegen": "^2.1.0", + "recast": "^0.23.9" + } + }, "node_modules/@aashutoshrathi/word-wrap": { "version": "1.2.6", "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", @@ -323,7 +337,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", - "dev": true, "license": "MIT", "dependencies": { "@babel/types": "^7.24.7", @@ -467,7 +480,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -477,7 +489,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "dev": true, "license": "MIT", "engines": { "node": ">=6.9.0" @@ -582,7 +593,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", - "dev": true, "license": "MIT", "bin": { "parser": "bin/babel-parser.js" @@ -655,7 +665,6 @@ "version": "7.24.7", "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", - "dev": true, "license": "MIT", "dependencies": { "@babel/helper-string-parser": "^7.24.7", @@ -1668,7 +1677,6 @@ "version": "0.3.5", "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dev": true, "dependencies": { "@jridgewell/set-array": "^1.2.1", "@jridgewell/sourcemap-codec": "^1.4.10", @@ -1682,7 +1690,6 @@ "version": "3.1.2", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -1691,7 +1698,6 @@ "version": "1.2.1", "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", - "dev": true, "engines": { "node": ">=6.0.0" } @@ -1709,14 +1715,12 @@ "node_modules/@jridgewell/sourcemap-codec": { "version": "1.4.15", "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==", - "dev": true + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" }, "node_modules/@jridgewell/trace-mapping": { "version": "0.3.25", "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", - "dev": true, "dependencies": { "@jridgewell/resolve-uri": "^3.1.0", "@jridgewell/sourcemap-codec": "^1.4.14" @@ -4813,9 +4817,9 @@ } }, "node_modules/acorn": { - "version": "8.11.3", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", - "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "version": "8.12.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", + "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", "bin": { "acorn": "bin/acorn" }, @@ -4840,6 +4844,31 @@ "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" } }, + "node_modules/acorn-private-class-elements": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/acorn-private-class-elements/-/acorn-private-class-elements-1.0.0.tgz", + "integrity": "sha512-zYNcZtxKgVCg1brS39BEou86mIao1EV7eeREG+6WMwKbuYTeivRRs6S2XdWnboRde6G9wKh2w+WBydEyJsJ6mg==", + "engines": { + "node": ">=4.8.2" + }, + "peerDependencies": { + "acorn": "^6.1.0 || ^7 || ^8" + } + }, + "node_modules/acorn-static-class-features": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/acorn-static-class-features/-/acorn-static-class-features-1.0.0.tgz", + "integrity": "sha512-XZJECjbmMOKvMHiNzbiPXuXpLAJfN3dAKtfIYbk1eHiWdsutlek+gS7ND4B8yJ3oqvHo1NxfafnezVmq7NXK0A==", + "dependencies": { + "acorn-private-class-elements": "^1.0.0" + }, + "engines": { + "node": ">=4.8.2" + }, + "peerDependencies": { + "acorn": "^6.1.0 || ^7 || ^8" + } + }, "node_modules/agent-base": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", @@ -5114,6 +5143,17 @@ "node": "*" } }, + "node_modules/ast-types": { + "version": "0.16.1", + "resolved": "https://registry.npmjs.org/ast-types/-/ast-types-0.16.1.tgz", + "integrity": "sha512-6t10qk83GOG8p0vKmaCr8eiilZwO171AvbROMtvvNiwrTly62t+7XkA8RdIIVbpMhCASAsxgAzdRSwh6nw/5Dg==", + "dependencies": { + "tslib": "^2.0.1" + }, + "engines": { + "node": ">=4" + } + }, "node_modules/async": { "version": "2.6.4", "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", @@ -6852,6 +6892,34 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, "node_modules/eslint": { "version": "9.1.1", "resolved": "https://registry.npmjs.org/eslint/-/eslint-9.1.1.tgz", @@ -6995,7 +7063,6 @@ "version": "4.0.1", "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", - "dev": true, "license": "BSD-2-Clause", "bin": { "esparse": "bin/esparse.js", @@ -7067,7 +7134,6 @@ "version": "2.0.3", "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", - "dev": true, "engines": { "node": ">=0.10.0" } @@ -7309,6 +7375,10 @@ "integrity": "sha512-0Zt+s3L7Vf1biwWZ29aARiVYLx7iMGnEUl9x33fbB/j3jR81u/O2LbqK+Bm1CDSNDKVtJ/YjwY7TUd5SkeLQLw==", "license": "MIT" }, + "node_modules/file-walker": { + "resolved": "tools/file-walker", + "link": true + }, "node_modules/fill-range": { "version": "7.1.1", "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", @@ -8893,6 +8963,10 @@ "integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==", "license": "BSD-3-Clause" }, + "node_modules/js-parse-and-output": { + "resolved": "experiments/js-parse-and-output", + "link": true + }, "node_modules/js-sha256": { "version": "0.9.0", "resolved": "https://registry.npmjs.org/js-sha256/-/js-sha256-0.9.0.tgz", @@ -8922,7 +8996,6 @@ "version": "2.5.2", "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", - "dev": true, "license": "MIT", "bin": { "jsesc": "bin/jsesc" @@ -11178,6 +11251,21 @@ "node": ">=8.10.0" } }, + "node_modules/recast": { + "version": "0.23.9", + "resolved": "https://registry.npmjs.org/recast/-/recast-0.23.9.tgz", + "integrity": "sha512-Hx/BGIbwj+Des3+xy5uAtAbdCyqK9y9wbBcDFDYanLS9JnMqf7OeF87HQwUimE87OEc72mr6tkKUKMBBL+hF9Q==", + "dependencies": { + "ast-types": "^0.16.1", + "esprima": "~4.0.0", + "source-map": "~0.6.1", + "tiny-invariant": "^1.3.3", + "tslib": "^2.0.1" + }, + "engines": { + "node": ">= 4" + } + }, "node_modules/rechoir": { "version": "0.8.0", "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz", @@ -12444,6 +12532,11 @@ "integrity": "sha512-IjZc9KIotudix8bMaBW6QvMuq64BrJWFs1+4V0lXwWGQZwH+LnX87doAYhem4caOEusRP9/g6jVDQmZ8XOk1nw==", "license": "MIT" }, + "node_modules/tiny-invariant": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/tiny-invariant/-/tiny-invariant-1.3.3.tgz", + "integrity": "sha512-+FbBPE1o9QAYvviau/qC5SE3caw21q3xkvWKBtja5vgqOWIHHJ3ioaq1VPfn/Szqctz2bU/oYeKd9/z5BL+PVg==" + }, "node_modules/tinycolor2": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.6.0.tgz", @@ -12454,7 +12547,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", - "dev": true, "license": "MIT", "engines": { "node": ">=4" @@ -13897,6 +13989,10 @@ "src/useapi": { "version": "1.0.0", "license": "AGPL-3.0-only" + }, + "tools/file-walker": { + "version": "1.0.0", + "license": "AGPL-3.0-only" } } } diff --git a/package.json b/package.json index 2ac95fb530..dc4be8bc8a 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,8 @@ }, "workspaces": [ "src/*", - "tools/*" + "tools/*", + "experiments/js-parse-and-output" ], "nodemonConfig": { "ext": "js, json, mjs, jsx, svg, css", From a1ff3759318a89d763d41dee835098a30d315348 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 9 Jul 2024 03:40:46 -0400 Subject: [PATCH 0477/2119] doc: update comment_prefixes.md --- doc/contributors/comment_prefixes.md | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/doc/contributors/comment_prefixes.md b/doc/contributors/comment_prefixes.md index 084da611f2..eefb0e4af8 100644 --- a/doc/contributors/comment_prefixes.md +++ b/doc/contributors/comment_prefixes.md @@ -25,4 +25,6 @@ This document will be updated on an _as-needed_ basis. - `track:` is used to track common patterns. - Anything written after `track:` must be registered in [track-comments.md](../devmeta/track-comments.md) - +- `wet:` is usesd to track anything that doesn't adhere + to the DRY principle; the following message should describe + where similar code is \ No newline at end of file From 365d795c3fda8f0b6d2030df43dfb9a89fdf00db Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 9 Jul 2024 04:03:58 -0400 Subject: [PATCH 0478/2119] doc: omit cp of .env.example in local build instructions This command contradicts the statement that Puter will find the next available port when port 4100 is in use. --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index 8c04c14e04..55f828ad76 100644 --- a/README.md +++ b/README.md @@ -43,7 +43,6 @@ Puter is an advanced, open-source internet operating system designed to be featu ```bash git clone https://github.com/HeyPuter/puter cd puter -cp .env.example .env npm install npm start ``` From bda4aed2e875dd048b3f2891486d9845a08203c5 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 9 Jul 2024 04:10:33 -0400 Subject: [PATCH 0479/2119] chore: add missing license headers --- dev-server.js | 18 ++ experiments/js-parse-and-output/test.js | 18 ++ experiments/x86emu/www/main.js | 18 ++ experiments/x86emu/www/third-party/libv86.js | 18 ++ experiments/x86emu/www/third-party/starter.js | 18 ++ experiments/x86emu/www/third-party/xterm.css | 18 ++ experiments/x86emu/www/third-party/xterm.js | 18 ++ exports.js | 18 ++ l_checker_config.json | 5 +- .../kdmod/CustomPuterService.js | 18 ++ mods/mods_available/kdmod/ShareTestService.js | 18 ++ .../kdmod/data/sharetest_scenarios.js | 18 ++ mods/mods_available/kdmod/gui/main.js | 18 ++ mods/mods_available/kdmod/module.js | 18 ++ package-lock.json | 223 ++++++++++++++++++ package.json | 1 + run-selfhosted.js | 18 ++ src/backend/src/SelfHostedModule.js | 18 ++ src/backend/src/definitions/Library.js | 18 ++ src/backend/src/definitions/SimpleEntity.js | 18 ++ src/backend/src/entities/Group.js | 18 ++ .../filesystem/ll_operations/ll_listusers.js | 18 ++ .../filesystem/ll_operations/ll_readshares.js | 18 ++ src/backend/src/fun/dev-console-ui-utils.js | 18 ++ src/backend/src/fun/logos.js | 18 ++ src/backend/src/libraries/ArrayUtil.js | 18 ++ src/backend/src/libraries/LibTypeTagged.js | 18 ++ .../src/middleware/configurable_auth.js | 18 ++ src/backend/src/middleware/subdomain.js | 18 ++ .../src/om/entitystorage/OwnerLimitedES.js | 18 ++ .../src/om/entitystorage/ProtectedAppES.js | 18 ++ .../src/om/entitystorage/ReadOnlyES.js | 18 ++ src/backend/src/om/mappings/notification.js | 18 ++ src/backend/src/routers/auth/configure-2fa.js | 18 ++ .../src/routers/auth/delete-own-user.js | 18 ++ .../src/routers/auth/grant-user-group.js | 18 ++ .../src/routers/auth/grant-user-user.js | 18 ++ src/backend/src/routers/auth/list-sessions.js | 18 ++ .../src/routers/auth/revoke-session.js | 18 ++ .../src/routers/auth/revoke-user-group.js | 18 ++ .../src/routers/auth/revoke-user-user.js | 18 ++ src/backend/src/routers/down.js | 18 ++ .../routers/user-protected/change-email.js | 18 ++ .../routers/user-protected/change-password.js | 18 ++ .../src/routers/user-protected/disable-2fa.js | 18 ++ src/backend/src/services/AnomalyService.js | 18 ++ src/backend/src/services/BroadcastService.js | 18 ++ .../services/ComplainAboutVersionsService.js | 18 ++ .../src/services/DefaultUserService.js | 18 ++ .../src/services/DetailProviderService.js | 18 ++ src/backend/src/services/DevTODService.js | 18 ++ src/backend/src/services/DevWatcherService.js | 18 ++ src/backend/src/services/GetUserService.js | 18 ++ .../src/services/HostDiskUsageService.js | 18 ++ src/backend/src/services/LockService.js | 18 ++ src/backend/src/services/MountpointService.js | 18 ++ .../src/services/NotificationService.js | 18 ++ .../src/services/PermissionAPIService.js | 18 ++ .../src/services/ProtectedAppService.js | 18 ++ .../src/services/PuterHomepageService.js | 18 ++ src/backend/src/services/ScriptService.js | 18 ++ src/backend/src/services/SelfhostedService.js | 18 ++ .../src/services/ServeLandingService.js | 18 ++ .../src/services/ServeSingeFileService.js | 18 ++ .../src/services/ServeStaticFilesService.js | 18 ++ src/backend/src/services/ServicePatch.js | 18 ++ src/backend/src/services/SessionService.js | 18 ++ src/backend/src/services/ShareService.js | 18 ++ .../abuse-prevention/EdgeRateLimitService.js | 18 ++ .../src/services/auth/AntiCSRFService.js | 18 ++ src/backend/src/services/auth/GroupService.js | 18 ++ src/backend/src/services/auth/OTPService.js | 18 ++ src/backend/src/services/auth/TokenService.js | 18 ++ .../web/UserProtectedEndpointsService.js | 18 ++ .../sequence/check-user-permission.js | 18 ++ src/backend/src/structured/sequence/share.js | 18 ++ src/backend/src/util/configutil.js | 18 ++ src/backend/src/util/expressutil.js | 18 ++ src/backend/src/util/fnutil.js | 18 ++ src/backend/src/util/langutil.js | 18 ++ src/backend/src/util/pathutil.js | 18 ++ src/backend/src/util/validutil.js | 18 ++ src/backend/src/util/workutil.js | 18 ++ src/backend/tools/test.js | 18 ++ src/contextlink/context.js | 18 ++ src/contextlink/entry.js | 18 ++ src/contextlink/test/testcontext.js | 18 ++ src/dev-center/css/normalize.css | 18 ++ src/dev-center/css/style.css | 18 ++ src/dev-center/js/dev-center.js | 18 ++ src/dev-center/js/html-entities.js | 18 ++ src/dev-center/js/jquery-3.6.0.min.js | 18 ++ src/dev-center/js/jquery.dragster.js | 18 ++ src/dev-center/js/slugify.js | 18 ++ src/git/config/dev.js | 18 ++ src/git/config/release.js | 18 ++ src/git/rollup.config.js | 18 ++ src/git/src/auth.js | 18 ++ src/git/src/color.js | 18 ++ src/git/src/diff.js | 18 ++ src/git/src/filesystem.js | 18 ++ src/git/src/format.js | 18 ++ src/git/src/git-command-definition.js | 18 ++ src/git/src/git-helpers.js | 18 ++ src/git/src/help.js | 18 ++ src/git/src/main.js | 18 ++ src/git/src/refs.js | 18 ++ src/git/src/subcommands/__exports__.js | 18 ++ src/git/src/subcommands/add.js | 18 ++ src/git/src/subcommands/branch.js | 18 ++ src/git/src/subcommands/checkout.js | 18 ++ src/git/src/subcommands/cherry-pick.js | 18 ++ src/git/src/subcommands/clone.js | 18 ++ src/git/src/subcommands/commit.js | 18 ++ src/git/src/subcommands/config.js | 18 ++ src/git/src/subcommands/diff.js | 18 ++ src/git/src/subcommands/fetch.js | 18 ++ src/git/src/subcommands/help.js | 18 ++ src/git/src/subcommands/init.js | 18 ++ src/git/src/subcommands/log.js | 18 ++ src/git/src/subcommands/pull.js | 18 ++ src/git/src/subcommands/push.js | 18 ++ src/git/src/subcommands/remote.js | 18 ++ src/git/src/subcommands/restore.js | 18 ++ src/git/src/subcommands/show.js | 18 ++ src/git/src/subcommands/status.js | 18 ++ src/git/src/subcommands/version.js | 18 ++ src/gui/build.js | 18 ++ src/gui/src/IPC.js | 18 ++ src/gui/src/UI/Components/ActionCard.js | 18 ++ src/gui/src/UI/Components/Button.js | 18 ++ src/gui/src/UI/Components/CodeEntryView.js | 18 ++ .../src/UI/Components/ConfirmationsView.js | 18 ++ src/gui/src/UI/Components/Flexer.js | 18 ++ src/gui/src/UI/Components/Frame.js | 18 ++ src/gui/src/UI/Components/Glyph.js | 18 ++ src/gui/src/UI/Components/JustHTML.js | 18 ++ src/gui/src/UI/Components/NotifCard.js | 18 ++ src/gui/src/UI/Components/PasswordEntry.js | 18 ++ src/gui/src/UI/Components/QRCode.js | 18 ++ .../UI/Components/RecoveryCodeEntryView.js | 18 ++ .../src/UI/Components/RecoveryCodesView.js | 18 ++ src/gui/src/UI/Components/Slider.js | 18 ++ src/gui/src/UI/Components/Spinner.js | 18 ++ src/gui/src/UI/Components/StepHeading.js | 18 ++ src/gui/src/UI/Components/StepView.js | 18 ++ src/gui/src/UI/Components/StringView.js | 18 ++ src/gui/src/UI/Components/Table.js | 18 ++ src/gui/src/UI/Components/TestView.js | 18 ++ src/gui/src/UI/PuterDialog.js | 18 ++ src/gui/src/UI/Settings/UITabAbout.js | 18 ++ src/gui/src/UI/Settings/UITabAccount.js | 18 ++ src/gui/src/UI/Settings/UITabClock.js | 18 ++ src/gui/src/UI/Settings/UITabLanguage.js | 18 ++ .../src/UI/Settings/UITabPersonalization.js | 18 ++ src/gui/src/UI/Settings/UITabSecurity.js | 18 ++ src/gui/src/UI/Settings/UITabUsage.js | 18 ++ .../src/UI/Settings/UIWindowChangeEmail.js | 18 ++ .../Settings/UIWindowConfirmUserDeletion.js | 18 ++ .../Settings/UIWindowFinalizeUserDeletion.js | 18 ++ src/gui/src/UI/Settings/UIWindowSettings.js | 18 ++ src/gui/src/UI/UIAlert.js | 18 ++ src/gui/src/UI/UIComponentWindow.js | 18 ++ src/gui/src/UI/UIContextMenu.js | 18 ++ src/gui/src/UI/UIDesktop.js | 18 ++ src/gui/src/UI/UIItem.js | 18 ++ src/gui/src/UI/UINotification.js | 18 ++ src/gui/src/UI/UIPopover.js | 18 ++ src/gui/src/UI/UIPrompt.js | 18 ++ src/gui/src/UI/UITaskbar.js | 18 ++ src/gui/src/UI/UITaskbarItem.js | 18 ++ src/gui/src/UI/UIWindow.js | 18 ++ src/gui/src/UI/UIWindow2FASetup.js | 18 ++ src/gui/src/UI/UIWindowChangePassword.js | 18 ++ src/gui/src/UI/UIWindowChangeUsername.js | 18 ++ src/gui/src/UI/UIWindowClaimReferral.js | 18 ++ src/gui/src/UI/UIWindowColorPicker.js | 18 ++ src/gui/src/UI/UIWindowDesktopBGSettings.js | 18 ++ .../UI/UIWindowEmailConfirmationRequired.js | 18 ++ src/gui/src/UI/UIWindowFeedback.js | 18 ++ src/gui/src/UI/UIWindowFontPicker.js | 18 ++ src/gui/src/UI/UIWindowItemProperties.js | 18 ++ src/gui/src/UI/UIWindowLogin.js | 18 ++ src/gui/src/UI/UIWindowLoginInProgress.js | 18 ++ src/gui/src/UI/UIWindowManageSessions.js | 18 ++ src/gui/src/UI/UIWindowMyWebsites.js | 18 ++ src/gui/src/UI/UIWindowNewPassword.js | 18 ++ src/gui/src/UI/UIWindowProgress.js | 18 ++ src/gui/src/UI/UIWindowPublishWebsite.js | 18 ++ src/gui/src/UI/UIWindowQR.js | 18 ++ src/gui/src/UI/UIWindowRecoverPassword.js | 18 ++ src/gui/src/UI/UIWindowRefer.js | 18 ++ src/gui/src/UI/UIWindowRequestPermission.js | 18 ++ src/gui/src/UI/UIWindowSaveAccount.js | 18 ++ src/gui/src/UI/UIWindowSessionList.js | 18 ++ src/gui/src/UI/UIWindowShare.js | 18 ++ src/gui/src/UI/UIWindowSignup.js | 18 ++ src/gui/src/UI/UIWindowTaskManager.js | 18 ++ src/gui/src/UI/UIWindowThemeDialog.js | 18 ++ src/gui/src/css/normalize.css | 18 ++ src/gui/src/css/style.css | 18 ++ src/gui/src/css/theme.css | 18 ++ src/gui/src/definitions.js | 18 ++ src/gui/src/globals.js | 18 ++ src/gui/src/helpers.js | 18 ++ .../src/helpers/check_password_strength.js | 18 ++ src/gui/src/helpers/content_type_to_icon.js | 18 ++ .../determine_active_container_parent.js | 18 ++ src/gui/src/helpers/download.js | 18 ++ .../src/helpers/fixedEncodeURIComponent.js | 18 ++ .../helpers/get_html_element_from_options.js | 18 ++ src/gui/src/helpers/globToRegExp.js | 18 ++ src/gui/src/helpers/item_icon.js | 18 ++ src/gui/src/helpers/launch_app.js | 18 ++ src/gui/src/helpers/new_context_menu_item.js | 18 ++ src/gui/src/helpers/open_item.js | 18 ++ src/gui/src/helpers/refresh_item_container.js | 18 ++ src/gui/src/helpers/socialLink.js | 18 ++ src/gui/src/helpers/truncate_filename.js | 18 ++ .../helpers/update_last_touch_coordinates.js | 18 ++ src/gui/src/helpers/update_mouse_position.js | 18 ++ .../helpers/update_title_based_on_uploads.js | 18 ++ src/gui/src/helpers/update_username_in_gui.js | 18 ++ src/gui/src/i18n/i18n.js | 18 ++ src/gui/src/i18n/i18nChangeLanguage.js | 18 ++ src/gui/src/i18n/translations/ar.js | 18 ++ src/gui/src/i18n/translations/bn.js | 18 ++ src/gui/src/i18n/translations/br.js | 18 ++ src/gui/src/i18n/translations/da.js | 18 ++ src/gui/src/i18n/translations/de.js | 18 ++ src/gui/src/i18n/translations/emoji.js | 18 ++ src/gui/src/i18n/translations/en.js | 18 ++ src/gui/src/i18n/translations/es.js | 18 ++ src/gui/src/i18n/translations/fa.js | 18 ++ src/gui/src/i18n/translations/fi.js | 18 ++ src/gui/src/i18n/translations/fr.js | 18 ++ src/gui/src/i18n/translations/hi.js | 18 ++ src/gui/src/i18n/translations/hy.js | 18 ++ src/gui/src/i18n/translations/ig.js | 18 ++ src/gui/src/i18n/translations/it.js | 18 ++ src/gui/src/i18n/translations/ko.js | 18 ++ src/gui/src/i18n/translations/nb.js | 18 ++ src/gui/src/i18n/translations/nl.js | 18 ++ src/gui/src/i18n/translations/nn.js | 18 ++ src/gui/src/i18n/translations/pl.js | 18 ++ src/gui/src/i18n/translations/pt.js | 18 ++ src/gui/src/i18n/translations/ro.js | 18 ++ src/gui/src/i18n/translations/ru.js | 18 ++ src/gui/src/i18n/translations/sv.js | 18 ++ src/gui/src/i18n/translations/th.js | 18 ++ src/gui/src/i18n/translations/tr.js | 18 ++ src/gui/src/i18n/translations/translations.js | 18 ++ src/gui/src/i18n/translations/ua.js | 18 ++ src/gui/src/i18n/translations/ur.js | 18 ++ src/gui/src/i18n/translations/zh.js | 18 ++ src/gui/src/i18n/translations/zhtw.js | 18 ++ src/gui/src/index.js | 18 ++ src/gui/src/init_async.js | 18 ++ src/gui/src/init_sync.js | 18 ++ src/gui/src/initgui.js | 18 ++ src/gui/src/keyboard.js | 18 ++ src/gui/src/services/BroadcastService.js | 18 ++ .../src/services/ExportRegistrantService.js | 18 ++ src/gui/src/services/LaunchOnInitService.js | 18 ++ src/gui/src/services/LocaleService.js | 18 ++ src/gui/src/services/ProcessService.js | 18 ++ src/gui/src/services/SettingsService.js | 18 ++ src/gui/src/services/ThemeService.js | 18 ++ src/gui/src/static-assets.js | 18 ++ src/gui/src/util/Component.js | 18 ++ src/gui/src/util/Placeholder.js | 18 ++ src/gui/src/util/TeePromise.js | 18 ++ src/gui/src/util/ValueHolder.js | 18 ++ src/gui/utils.js | 18 ++ src/parsely/exports.js | 18 ++ src/parsely/parser.js | 18 ++ src/parsely/parsers/combinators.js | 18 ++ src/parsely/parsers/terminals.js | 18 ++ src/parsely/streams.js | 18 ++ src/phoenix/config/dev.js | 18 ++ src/phoenix/config/release.js | 18 ++ src/phoenix/doc/stash/SymbolParserImpl.js | 18 ++ src/phoenix/rollup.config.js | 18 ++ src/phoenix/src/ansi-shell/ANSIContext.js | 18 ++ src/phoenix/src/ansi-shell/ANSIShell.js | 18 ++ .../src/ansi-shell/ConcreteSyntaxError.js | 18 ++ .../ansi-shell/arg-parsers/simple-parser.js | 18 ++ .../src/ansi-shell/decorators/errors.js | 18 ++ .../src/ansi-shell/ioutil/ByteWriter.js | 18 ++ .../src/ansi-shell/ioutil/MemReader.js | 18 ++ .../src/ansi-shell/ioutil/MemWriter.js | 18 ++ .../src/ansi-shell/ioutil/MultiWriter.js | 18 ++ .../src/ansi-shell/ioutil/NullifyWriter.js | 18 ++ .../src/ansi-shell/ioutil/ProxyReader.js | 18 ++ .../src/ansi-shell/ioutil/ProxyWriter.js | 18 ++ .../src/ansi-shell/ioutil/SignalReader.js | 18 ++ .../src/ansi-shell/ioutil/SyncLinesReader.js | 18 ++ .../src/ansi-shell/parsing/PARSE_CONSTANTS.js | 18 ++ .../ansi-shell/parsing/PuterShellParser.js | 18 ++ .../parsing/UnquotedTokenParserImpl.js | 18 ++ .../src/ansi-shell/parsing/brainstorming.js | 18 ++ .../parsing/buildParserFirstHalf.js | 18 ++ .../parsing/buildParserSecondHalf.js | 18 ++ .../src/ansi-shell/pipeline/Coupler.js | 18 ++ src/phoenix/src/ansi-shell/pipeline/Pipe.js | 18 ++ .../src/ansi-shell/pipeline/Pipeline.js | 18 ++ .../src/ansi-shell/pipeline/iowrappers.js | 18 ++ .../src/ansi-shell/readline/history.js | 18 ++ .../src/ansi-shell/readline/readline.js | 18 ++ .../src/ansi-shell/readline/readtoken.js | 18 ++ .../src/ansi-shell/readline/rl_comprehend.js | 18 ++ .../ansi-shell/readline/rl_csi_handlers.js | 18 ++ .../src/ansi-shell/readline/rl_words.js | 18 ++ src/phoenix/src/ansi-shell/signals.js | 18 ++ src/phoenix/src/context/context.js | 18 ++ src/phoenix/src/main_cli.js | 18 ++ src/phoenix/src/main_puter.js | 18 ++ src/phoenix/src/meta/versions.js | 18 ++ src/phoenix/src/platform/node/env.js | 18 ++ src/phoenix/src/platform/node/filesystem.js | 18 ++ src/phoenix/src/platform/node/system.js | 18 ++ src/phoenix/src/platform/puter/drivers.js | 18 ++ src/phoenix/src/platform/puter/env.js | 18 ++ src/phoenix/src/platform/puter/filesystem.js | 18 ++ src/phoenix/src/platform/puter/system.js | 18 ++ src/phoenix/src/promise.js | 18 ++ src/phoenix/src/pty/NodeStdioPTT.js | 18 ++ src/phoenix/src/pty/XDocumentPTT.js | 18 ++ .../completers/CommandCompleter.js | 18 ++ .../puter-shell/completers/FileCompleter.js | 18 ++ .../puter-shell/completers/OptionCompleter.js | 18 ++ .../src/puter-shell/coreutils/__exports__.js | 18 ++ src/phoenix/src/puter-shell/coreutils/ai.js | 18 ++ .../src/puter-shell/coreutils/basename.js | 18 ++ src/phoenix/src/puter-shell/coreutils/cat.js | 18 ++ src/phoenix/src/puter-shell/coreutils/cd.js | 18 ++ .../src/puter-shell/coreutils/changelog.js | 18 ++ .../src/puter-shell/coreutils/clear.js | 18 ++ .../puter-shell/coreutils/concept-parser.js | 18 ++ .../coreutils/coreutil_lib/echo_escapes.js | 18 ++ .../coreutils/coreutil_lib/exit.js | 18 ++ .../coreutils/coreutil_lib/help.js | 18 ++ .../coreutils/coreutil_lib/validate.js | 18 ++ src/phoenix/src/puter-shell/coreutils/cp.js | 18 ++ src/phoenix/src/puter-shell/coreutils/date.js | 18 ++ .../src/puter-shell/coreutils/dcall.js | 18 ++ .../src/puter-shell/coreutils/dirname.js | 18 ++ src/phoenix/src/puter-shell/coreutils/echo.js | 18 ++ src/phoenix/src/puter-shell/coreutils/env.js | 18 ++ .../src/puter-shell/coreutils/errno.js | 18 ++ src/phoenix/src/puter-shell/coreutils/exit.js | 18 ++ .../src/puter-shell/coreutils/false.js | 18 ++ src/phoenix/src/puter-shell/coreutils/grep.js | 18 ++ src/phoenix/src/puter-shell/coreutils/head.js | 18 ++ src/phoenix/src/puter-shell/coreutils/help.js | 18 ++ src/phoenix/src/puter-shell/coreutils/jq.js | 18 ++ .../src/puter-shell/coreutils/login.js | 18 ++ src/phoenix/src/puter-shell/coreutils/ls.js | 18 ++ src/phoenix/src/puter-shell/coreutils/man.js | 18 ++ .../src/puter-shell/coreutils/mkdir.js | 18 ++ src/phoenix/src/puter-shell/coreutils/mv.js | 18 ++ .../src/puter-shell/coreutils/neofetch.js | 18 ++ .../src/puter-shell/coreutils/printf.js | 18 ++ .../src/puter-shell/coreutils/printhist.js | 18 ++ src/phoenix/src/puter-shell/coreutils/pwd.js | 18 ++ src/phoenix/src/puter-shell/coreutils/rm.js | 18 ++ .../src/puter-shell/coreutils/rmdir.js | 18 ++ .../src/puter-shell/coreutils/sample-data.js | 18 ++ src/phoenix/src/puter-shell/coreutils/sed.js | 18 ++ .../src/puter-shell/coreutils/sed/address.js | 18 ++ .../src/puter-shell/coreutils/sed/command.js | 18 ++ .../src/puter-shell/coreutils/sed/parser.js | 18 ++ .../src/puter-shell/coreutils/sed/script.js | 18 ++ .../src/puter-shell/coreutils/sed/utils.js | 18 ++ .../src/puter-shell/coreutils/sleep.js | 18 ++ src/phoenix/src/puter-shell/coreutils/sort.js | 18 ++ src/phoenix/src/puter-shell/coreutils/tail.js | 18 ++ src/phoenix/src/puter-shell/coreutils/test.js | 18 ++ .../src/puter-shell/coreutils/touch.js | 18 ++ src/phoenix/src/puter-shell/coreutils/true.js | 18 ++ .../src/puter-shell/coreutils/txt2img.js | 18 ++ .../src/puter-shell/coreutils/usages.js | 18 ++ src/phoenix/src/puter-shell/coreutils/wc.js | 18 ++ .../src/puter-shell/coreutils/which.js | 18 ++ src/phoenix/src/puter-shell/main.js | 18 ++ .../puter-shell/plugins/ChatHistoryPlugin.js | 18 ++ .../providers/BuiltinCommandProvider.js | 18 ++ .../providers/CompositeCommandProvider.js | 18 ++ .../providers/PathCommandProvider.js | 18 ++ .../providers/PuterAppCommandProvider.js | 18 ++ .../providers/ScriptCommandProvider.js | 18 ++ src/phoenix/src/util/bytes.js | 18 ++ src/phoenix/src/util/file.js | 18 ++ src/phoenix/src/util/lang.js | 18 ++ src/phoenix/src/util/log.js | 18 ++ src/phoenix/src/util/path.js | 18 ++ src/phoenix/src/util/singleton.js | 18 ++ src/phoenix/src/util/statemachine.js | 18 ++ src/phoenix/src/util/wrap-text.js | 18 ++ src/phoenix/test.js | 18 ++ src/phoenix/test/coreutils.test.js | 18 ++ src/phoenix/test/coreutils/basename.js | 18 ++ src/phoenix/test/coreutils/date.js | 18 ++ src/phoenix/test/coreutils/dirname.js | 18 ++ src/phoenix/test/coreutils/echo.js | 18 ++ src/phoenix/test/coreutils/env.js | 18 ++ src/phoenix/test/coreutils/errno.js | 18 ++ src/phoenix/test/coreutils/false.js | 18 ++ src/phoenix/test/coreutils/harness.js | 18 ++ src/phoenix/test/coreutils/head.js | 18 ++ src/phoenix/test/coreutils/printf.js | 18 ++ src/phoenix/test/coreutils/sleep.js | 18 ++ src/phoenix/test/coreutils/sort.js | 18 ++ src/phoenix/test/coreutils/tail.js | 18 ++ src/phoenix/test/coreutils/true.js | 18 ++ src/phoenix/test/coreutils/wc.js | 18 ++ src/phoenix/test/readtoken.js | 18 ++ src/phoenix/test/test-bytes.js | 18 ++ src/phoenix/test/test-stateful-processor.js | 18 ++ src/phoenix/test/wrap-text.js | 18 ++ src/phoenix/tools/gen.js | 18 ++ src/pty/exports.js | 18 ++ src/puter-js-common/index.js | 18 ++ src/puter-js-common/src/AdvancedBase.js | 18 ++ src/puter-js-common/src/PosixError.js | 18 ++ src/puter-js-common/src/bases/BasicBase.js | 18 ++ src/puter-js-common/src/bases/TraitBase.js | 18 ++ .../src/traits/NodeModuleDITrait.js | 18 ++ .../src/traits/PropertiesTrait.js | 18 ++ src/puter-js-common/test/test.js | 18 ++ src/puter-js/src/index.js | 18 ++ src/puter-js/src/modules/AI.js | 18 ++ src/puter-js/src/modules/Apps.js | 18 ++ src/puter-js/src/modules/Auth.js | 18 ++ src/puter-js/src/modules/Email.js | 18 ++ src/puter-js/src/modules/FSItem.js | 18 ++ src/puter-js/src/modules/FileSystem/index.js | 18 ++ .../src/modules/FileSystem/operations/copy.js | 18 ++ .../FileSystem/operations/deleteFSEntry.js | 18 ++ .../modules/FileSystem/operations/mkdir.js | 18 ++ .../src/modules/FileSystem/operations/move.js | 18 ++ .../src/modules/FileSystem/operations/read.js | 18 ++ .../modules/FileSystem/operations/readdir.js | 18 ++ .../modules/FileSystem/operations/rename.js | 18 ++ .../src/modules/FileSystem/operations/sign.js | 18 ++ .../modules/FileSystem/operations/space.js | 18 ++ .../src/modules/FileSystem/operations/stat.js | 18 ++ .../modules/FileSystem/operations/upload.js | 18 ++ .../modules/FileSystem/operations/write.js | 18 ++ .../FileSystem/utils/getAbsolutePathForApp.js | 18 ++ src/puter-js/src/modules/Hosting.js | 18 ++ src/puter-js/src/modules/KV.js | 18 ++ src/puter-js/src/modules/OS.js | 18 ++ src/puter-js/src/modules/PuterDialog.js | 18 ++ src/puter-js/src/modules/UI.js | 18 ++ src/puter-js/src/modules/Util.js | 18 ++ src/puter-js/test/fs.test.js | 18 ++ src/puter-js/test/kv.test.js | 18 ++ src/strataparse/dsl/ParserBuilder.js | 18 ++ src/strataparse/dsl/ParserRegistry.js | 18 ++ src/strataparse/exports.js | 18 ++ src/strataparse/parse.js | 18 ++ .../parse_impls/StrUntilParserImpl.js | 18 ++ src/strataparse/parse_impls/combinators.js | 18 ++ src/strataparse/parse_impls/literal.js | 18 ++ src/strataparse/parse_impls/whitespace.js | 18 ++ src/strataparse/strata.js | 18 ++ .../ContextSwitchingPStratumImpl.js | 18 ++ .../FirstRecognizedPStratumImpl.js | 18 ++ .../MergeWhitespacePStratumImpl.js | 18 ++ src/strataparse/strata_impls/terminals.js | 18 ++ src/terminal/config/dev.js | 18 ++ src/terminal/config/release.js | 18 ++ src/terminal/rollup.config.js | 18 ++ src/terminal/src/main.js | 18 ++ src/terminal/src/pty/PTT.js | 18 ++ src/terminal/src/pty/PTY.js | 18 ++ src/terminal/src/pty/XDocumentANSIShell.js | 18 ++ src/useapi/main.js | 18 ++ tools/check-translations.js | 18 ++ tools/file-walker/test.js | 18 ++ tools/gen-release-notes.js | 18 ++ 482 files changed, 8850 insertions(+), 1 deletion(-) diff --git a/dev-server.js b/dev-server.js index 357f680de7..9ba6367ec9 100644 --- a/dev-server.js +++ b/dev-server.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import express from "express"; import { generateDevHtml, build } from "./utils.js"; import { argv } from 'node:process'; diff --git a/experiments/js-parse-and-output/test.js b/experiments/js-parse-and-output/test.js index 3fa6568a55..50dac4c74b 100644 --- a/experiments/js-parse-and-output/test.js +++ b/experiments/js-parse-and-output/test.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const babelParser = require('@babel/parser'); const generate = (require('@babel/generator')).default; const fs = require('fs'); diff --git a/experiments/x86emu/www/main.js b/experiments/x86emu/www/main.js index ea5129f5b5..23e207f936 100755 --- a/experiments/x86emu/www/main.js +++ b/experiments/x86emu/www/main.js @@ -1,4 +1,22 @@ #!/usr/bin/env node +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ "use strict"; import('./js/InstanceManager.mjs').then(module => { diff --git a/experiments/x86emu/www/third-party/libv86.js b/experiments/x86emu/www/third-party/libv86.js index 2382f12537..91ccd9efbc 100644 --- a/experiments/x86emu/www/third-party/libv86.js +++ b/experiments/x86emu/www/third-party/libv86.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ ;(function(){'use strict';function ba(a,b){function c(x){x=x.toString(16);return"#"+"0".repeat(6-x.length)+x}function d(x,C,S,P){x.style.width="";x.style.height="";P&&(x.style.transform="");var aa=x.getBoundingClientRect();P?x.style.transform=(1===C?"":" scaleX("+C+")")+(1===S?"":" scaleY("+S+")"):(0===C%1&&0===S%1?(e.style.imageRendering="crisp-edges",e.style.imageRendering="pixelated",e.style["-ms-interpolation-mode"]="nearest-neighbor"):(e.style.imageRendering="",e.style["-ms-interpolation-mode"]=""),P=window.devicePixelRatio|| 1,0!==P%1&&(C/=P,S/=P));1!==C&&(x.style.width=aa.width*C+"px");1!==S&&(x.style.height=aa.height*S+"px")}console.assert(a,"1st argument must be a DOM container");var e=a.getElementsByTagName("canvas")[0],g=e.getContext("2d",{alpha:!1}),f=a.getElementsByTagName("div")[0],k=document.createElement("div"),l,m,n=1,p=1,t=1,q,z=!1,w,u,I,U=!1,ea=this;a=new Uint16Array([8962,199,252,233,226,228,224,229,231,234,235,232,239,238,236,196,197,201,230,198,244,246,242,251,249,255,214,220,162,163,165,8359,402,225, 237,243,250,241,209,170,186,191,8976,172,189,188,161,171,187,9617,9618,9619,9474,9508,9569,9570,9558,9557,9571,9553,9559,9565,9564,9563,9488,9492,9524,9516,9500,9472,9532,9566,9567,9562,9556,9577,9574,9568,9552,9580,9575,9576,9572,9573,9561,9560,9554,9555,9579,9578,9496,9484,9608,9604,9612,9616,9600,945,223,915,960,931,963,181,964,934,920,937,948,8734,966,949,8745,8801,177,8805,8804,8992,8993,247,8776,176,8729,183,8730,8319,178,9632,160]);for(var Ab=new Uint16Array([32,9786,9787,9829,9830,9827,9824, diff --git a/experiments/x86emu/www/third-party/starter.js b/experiments/x86emu/www/third-party/starter.js index b205dcf786..d72af4d29a 100644 --- a/experiments/x86emu/www/third-party/starter.js +++ b/experiments/x86emu/www/third-party/starter.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ "use strict"; /** diff --git a/experiments/x86emu/www/third-party/xterm.css b/experiments/x86emu/www/third-party/xterm.css index e97b643905..e5e3080072 100644 --- a/experiments/x86emu/www/third-party/xterm.css +++ b/experiments/x86emu/www/third-party/xterm.css @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (c) 2014 The xterm.js authors. All rights reserved. * Copyright (c) 2012-2013, Christopher Jeffrey (MIT License) diff --git a/experiments/x86emu/www/third-party/xterm.js b/experiments/x86emu/www/third-party/xterm.js index 4b20013f6d..e94184a3e1 100644 --- a/experiments/x86emu/www/third-party/xterm.js +++ b/experiments/x86emu/www/third-party/xterm.js @@ -1,2 +1,20 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ !function(e,t){if("object"==typeof exports&&"object"==typeof module)module.exports=t();else if("function"==typeof define&&define.amd)define([],t);else{var i=t();for(var s in i)("object"==typeof exports?exports:e)[s]=i[s]}}(globalThis,(()=>(()=>{"use strict";var e={4567:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.AccessibilityManager=void 0;const n=i(9042),o=i(9924),a=i(844),h=i(4725),c=i(2585),l=i(3656);let d=t.AccessibilityManager=class extends a.Disposable{constructor(e,t,i,s){super(),this._terminal=e,this._coreBrowserService=i,this._renderService=s,this._rowColumns=new WeakMap,this._liveRegionLineCount=0,this._charsToConsume=[],this._charsToAnnounce="",this._accessibilityContainer=this._coreBrowserService.mainDocument.createElement("div"),this._accessibilityContainer.classList.add("xterm-accessibility"),this._rowContainer=this._coreBrowserService.mainDocument.createElement("div"),this._rowContainer.setAttribute("role","list"),this._rowContainer.classList.add("xterm-accessibility-tree"),this._rowElements=[];for(let e=0;ethis._handleBoundaryFocus(e,0),this._bottomBoundaryFocusListener=e=>this._handleBoundaryFocus(e,1),this._rowElements[0].addEventListener("focus",this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._refreshRowsDimensions(),this._accessibilityContainer.appendChild(this._rowContainer),this._liveRegion=this._coreBrowserService.mainDocument.createElement("div"),this._liveRegion.classList.add("live-region"),this._liveRegion.setAttribute("aria-live","assertive"),this._accessibilityContainer.appendChild(this._liveRegion),this._liveRegionDebouncer=this.register(new o.TimeBasedDebouncer(this._renderRows.bind(this))),!this._terminal.element)throw new Error("Cannot enable accessibility before Terminal.open");this._terminal.element.insertAdjacentElement("afterbegin",this._accessibilityContainer),this.register(this._terminal.onResize((e=>this._handleResize(e.rows)))),this.register(this._terminal.onRender((e=>this._refreshRows(e.start,e.end)))),this.register(this._terminal.onScroll((()=>this._refreshRows()))),this.register(this._terminal.onA11yChar((e=>this._handleChar(e)))),this.register(this._terminal.onLineFeed((()=>this._handleChar("\n")))),this.register(this._terminal.onA11yTab((e=>this._handleTab(e)))),this.register(this._terminal.onKey((e=>this._handleKey(e.key)))),this.register(this._terminal.onBlur((()=>this._clearLiveRegion()))),this.register(this._renderService.onDimensionsChange((()=>this._refreshRowsDimensions()))),this.register((0,l.addDisposableDomListener)(document,"selectionchange",(()=>this._handleSelectionChange()))),this.register(this._coreBrowserService.onDprChange((()=>this._refreshRowsDimensions()))),this._refreshRows(),this.register((0,a.toDisposable)((()=>{this._accessibilityContainer.remove(),this._rowElements.length=0})))}_handleTab(e){for(let t=0;t0?this._charsToConsume.shift()!==e&&(this._charsToAnnounce+=e):this._charsToAnnounce+=e,"\n"===e&&(this._liveRegionLineCount++,21===this._liveRegionLineCount&&(this._liveRegion.textContent+=n.tooMuchOutput)))}_clearLiveRegion(){this._liveRegion.textContent="",this._liveRegionLineCount=0}_handleKey(e){this._clearLiveRegion(),/\p{Control}/u.test(e)||this._charsToConsume.push(e)}_refreshRows(e,t){this._liveRegionDebouncer.refresh(e,t,this._terminal.rows)}_renderRows(e,t){const i=this._terminal.buffer,s=i.lines.length.toString();for(let r=e;r<=t;r++){const e=i.lines.get(i.ydisp+r),t=[],n=e?.translateToString(!0,void 0,void 0,t)||"",o=(i.ydisp+r+1).toString(),a=this._rowElements[r];a&&(0===n.length?(a.innerText=" ",this._rowColumns.set(a,[0,1])):(a.textContent=n,this._rowColumns.set(a,t)),a.setAttribute("aria-posinset",o),a.setAttribute("aria-setsize",s))}this._announceCharacters()}_announceCharacters(){0!==this._charsToAnnounce.length&&(this._liveRegion.textContent+=this._charsToAnnounce,this._charsToAnnounce="")}_handleBoundaryFocus(e,t){const i=e.target,s=this._rowElements[0===t?1:this._rowElements.length-2];if(i.getAttribute("aria-posinset")===(0===t?"1":`${this._terminal.buffer.lines.length}`))return;if(e.relatedTarget!==s)return;let r,n;if(0===t?(r=i,n=this._rowElements.pop(),this._rowContainer.removeChild(n)):(r=this._rowElements.shift(),n=i,this._rowContainer.removeChild(r)),r.removeEventListener("focus",this._topBoundaryFocusListener),n.removeEventListener("focus",this._bottomBoundaryFocusListener),0===t){const e=this._createAccessibilityTreeNode();this._rowElements.unshift(e),this._rowContainer.insertAdjacentElement("afterbegin",e)}else{const e=this._createAccessibilityTreeNode();this._rowElements.push(e),this._rowContainer.appendChild(e)}this._rowElements[0].addEventListener("focus",this._topBoundaryFocusListener),this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._terminal.scrollLines(0===t?-1:1),this._rowElements[0===t?1:this._rowElements.length-2].focus(),e.preventDefault(),e.stopImmediatePropagation()}_handleSelectionChange(){if(0===this._rowElements.length)return;const e=document.getSelection();if(!e)return;if(e.isCollapsed)return void(this._rowContainer.contains(e.anchorNode)&&this._terminal.clearSelection());if(!e.anchorNode||!e.focusNode)return void console.error("anchorNode and/or focusNode are null");let t={node:e.anchorNode,offset:e.anchorOffset},i={node:e.focusNode,offset:e.focusOffset};if((t.node.compareDocumentPosition(i.node)&Node.DOCUMENT_POSITION_PRECEDING||t.node===i.node&&t.offset>i.offset)&&([t,i]=[i,t]),t.node.compareDocumentPosition(this._rowElements[0])&(Node.DOCUMENT_POSITION_CONTAINED_BY|Node.DOCUMENT_POSITION_FOLLOWING)&&(t={node:this._rowElements[0].childNodes[0],offset:0}),!this._rowContainer.contains(t.node))return;const s=this._rowElements.slice(-1)[0];if(i.node.compareDocumentPosition(s)&(Node.DOCUMENT_POSITION_CONTAINED_BY|Node.DOCUMENT_POSITION_PRECEDING)&&(i={node:s,offset:s.textContent?.length??0}),!this._rowContainer.contains(i.node))return;const r=({node:e,offset:t})=>{const i=e instanceof Text?e.parentNode:e;let s=parseInt(i?.getAttribute("aria-posinset"),10)-1;if(isNaN(s))return console.warn("row is invalid. Race condition?"),null;const r=this._rowColumns.get(i);if(!r)return console.warn("columns is null. Race condition?"),null;let n=t=this._terminal.cols&&(++s,n=0),{row:s,column:n}},n=r(t),o=r(i);if(n&&o){if(n.row>o.row||n.row===o.row&&n.column>=o.column)throw new Error("invalid range");this._terminal.select(n.column,n.row,(o.row-n.row)*this._terminal.cols-n.column+o.column)}}_handleResize(e){this._rowElements[this._rowElements.length-1].removeEventListener("focus",this._bottomBoundaryFocusListener);for(let e=this._rowContainer.children.length;ee;)this._rowContainer.removeChild(this._rowElements.pop());this._rowElements[this._rowElements.length-1].addEventListener("focus",this._bottomBoundaryFocusListener),this._refreshRowsDimensions()}_createAccessibilityTreeNode(){const e=this._coreBrowserService.mainDocument.createElement("div");return e.setAttribute("role","listitem"),e.tabIndex=-1,this._refreshRowDimensions(e),e}_refreshRowsDimensions(){if(this._renderService.dimensions.css.cell.height){this._accessibilityContainer.style.width=`${this._renderService.dimensions.css.canvas.width}px`,this._rowElements.length!==this._terminal.rows&&this._handleResize(this._terminal.rows);for(let e=0;e{function i(e){return e.replace(/\r?\n/g,"\r")}function s(e,t){return t?"[200~"+e+"[201~":e}function r(e,t,r,n){e=s(e=i(e),r.decPrivateModes.bracketedPasteMode&&!0!==n.rawOptions.ignoreBracketedPasteMode),r.triggerDataEvent(e,!0),t.value=""}function n(e,t,i){const s=i.getBoundingClientRect(),r=e.clientX-s.left-10,n=e.clientY-s.top-10;t.style.width="20px",t.style.height="20px",t.style.left=`${r}px`,t.style.top=`${n}px`,t.style.zIndex="1000",t.focus()}Object.defineProperty(t,"__esModule",{value:!0}),t.rightClickHandler=t.moveTextAreaUnderMouseCursor=t.paste=t.handlePasteEvent=t.copyHandler=t.bracketTextForPaste=t.prepareTextForTerminal=void 0,t.prepareTextForTerminal=i,t.bracketTextForPaste=s,t.copyHandler=function(e,t){e.clipboardData&&e.clipboardData.setData("text/plain",t.selectionText),e.preventDefault()},t.handlePasteEvent=function(e,t,i,s){e.stopPropagation(),e.clipboardData&&r(e.clipboardData.getData("text/plain"),t,i,s)},t.paste=r,t.moveTextAreaUnderMouseCursor=n,t.rightClickHandler=function(e,t,i,s,r){n(e,t,i),r&&s.rightClickSelect(e),t.value=s.selectionText,t.select()}},7239:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ColorContrastCache=void 0;const s=i(1505);t.ColorContrastCache=class{constructor(){this._color=new s.TwoKeyMap,this._css=new s.TwoKeyMap}setCss(e,t,i){this._css.set(e,t,i)}getCss(e,t){return this._css.get(e,t)}setColor(e,t,i){this._color.set(e,t,i)}getColor(e,t){return this._color.get(e,t)}clear(){this._color.clear(),this._css.clear()}}},3656:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.addDisposableDomListener=void 0,t.addDisposableDomListener=function(e,t,i,s){e.addEventListener(t,i,s);let r=!1;return{dispose:()=>{r||(r=!0,e.removeEventListener(t,i,s))}}}},3551:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.Linkifier=void 0;const n=i(3656),o=i(8460),a=i(844),h=i(2585),c=i(4725);let l=t.Linkifier=class extends a.Disposable{get currentLink(){return this._currentLink}constructor(e,t,i,s,r){super(),this._element=e,this._mouseService=t,this._renderService=i,this._bufferService=s,this._linkProviderService=r,this._linkCacheDisposables=[],this._isMouseOut=!0,this._wasResized=!1,this._activeLine=-1,this._onShowLinkUnderline=this.register(new o.EventEmitter),this.onShowLinkUnderline=this._onShowLinkUnderline.event,this._onHideLinkUnderline=this.register(new o.EventEmitter),this.onHideLinkUnderline=this._onHideLinkUnderline.event,this.register((0,a.getDisposeArrayDisposable)(this._linkCacheDisposables)),this.register((0,a.toDisposable)((()=>{this._lastMouseEvent=void 0,this._activeProviderReplies?.clear()}))),this.register(this._bufferService.onResize((()=>{this._clearCurrentLink(),this._wasResized=!0}))),this.register((0,n.addDisposableDomListener)(this._element,"mouseleave",(()=>{this._isMouseOut=!0,this._clearCurrentLink()}))),this.register((0,n.addDisposableDomListener)(this._element,"mousemove",this._handleMouseMove.bind(this))),this.register((0,n.addDisposableDomListener)(this._element,"mousedown",this._handleMouseDown.bind(this))),this.register((0,n.addDisposableDomListener)(this._element,"mouseup",this._handleMouseUp.bind(this)))}_handleMouseMove(e){this._lastMouseEvent=e;const t=this._positionFromMouseEvent(e,this._element,this._mouseService);if(!t)return;this._isMouseOut=!1;const i=e.composedPath();for(let e=0;e{e?.forEach((e=>{e.link.dispose&&e.link.dispose()}))})),this._activeProviderReplies=new Map,this._activeLine=e.y);let i=!1;for(const[s,r]of this._linkProviderService.linkProviders.entries())if(t){const t=this._activeProviderReplies?.get(s);t&&(i=this._checkLinkProviderResult(s,e,i))}else r.provideLinks(e.y,(t=>{if(this._isMouseOut)return;const r=t?.map((e=>({link:e})));this._activeProviderReplies?.set(s,r),i=this._checkLinkProviderResult(s,e,i),this._activeProviderReplies?.size===this._linkProviderService.linkProviders.length&&this._removeIntersectingLinks(e.y,this._activeProviderReplies)}))}_removeIntersectingLinks(e,t){const i=new Set;for(let s=0;se?this._bufferService.cols:s.link.range.end.x;for(let e=n;e<=o;e++){if(i.has(e)){r.splice(t--,1);break}i.add(e)}}}}_checkLinkProviderResult(e,t,i){if(!this._activeProviderReplies)return i;const s=this._activeProviderReplies.get(e);let r=!1;for(let t=0;tthis._linkAtPosition(e.link,t)));e&&(i=!0,this._handleNewLink(e))}if(this._activeProviderReplies.size===this._linkProviderService.linkProviders.length&&!i)for(let e=0;ethis._linkAtPosition(e.link,t)));if(s){i=!0,this._handleNewLink(s);break}}return i}_handleMouseDown(){this._mouseDownLink=this._currentLink}_handleMouseUp(e){if(!this._currentLink)return;const t=this._positionFromMouseEvent(e,this._element,this._mouseService);t&&this._mouseDownLink===this._currentLink&&this._linkAtPosition(this._currentLink.link,t)&&this._currentLink.link.activate(e,this._currentLink.link.text)}_clearCurrentLink(e,t){this._currentLink&&this._lastMouseEvent&&(!e||!t||this._currentLink.link.range.start.y>=e&&this._currentLink.link.range.end.y<=t)&&(this._linkLeave(this._element,this._currentLink.link,this._lastMouseEvent),this._currentLink=void 0,(0,a.disposeArray)(this._linkCacheDisposables))}_handleNewLink(e){if(!this._lastMouseEvent)return;const t=this._positionFromMouseEvent(this._lastMouseEvent,this._element,this._mouseService);t&&this._linkAtPosition(e.link,t)&&(this._currentLink=e,this._currentLink.state={decorations:{underline:void 0===e.link.decorations||e.link.decorations.underline,pointerCursor:void 0===e.link.decorations||e.link.decorations.pointerCursor},isHovered:!0},this._linkHover(this._element,e.link,this._lastMouseEvent),e.link.decorations={},Object.defineProperties(e.link.decorations,{pointerCursor:{get:()=>this._currentLink?.state?.decorations.pointerCursor,set:e=>{this._currentLink?.state&&this._currentLink.state.decorations.pointerCursor!==e&&(this._currentLink.state.decorations.pointerCursor=e,this._currentLink.state.isHovered&&this._element.classList.toggle("xterm-cursor-pointer",e))}},underline:{get:()=>this._currentLink?.state?.decorations.underline,set:t=>{this._currentLink?.state&&this._currentLink?.state?.decorations.underline!==t&&(this._currentLink.state.decorations.underline=t,this._currentLink.state.isHovered&&this._fireUnderlineEvent(e.link,t))}}}),this._linkCacheDisposables.push(this._renderService.onRenderedViewportChange((e=>{if(!this._currentLink)return;const t=0===e.start?0:e.start+1+this._bufferService.buffer.ydisp,i=this._bufferService.buffer.ydisp+1+e.end;if(this._currentLink.link.range.start.y>=t&&this._currentLink.link.range.end.y<=i&&(this._clearCurrentLink(t,i),this._lastMouseEvent)){const e=this._positionFromMouseEvent(this._lastMouseEvent,this._element,this._mouseService);e&&this._askForLink(e,!1)}}))))}_linkHover(e,t,i){this._currentLink?.state&&(this._currentLink.state.isHovered=!0,this._currentLink.state.decorations.underline&&this._fireUnderlineEvent(t,!0),this._currentLink.state.decorations.pointerCursor&&e.classList.add("xterm-cursor-pointer")),t.hover&&t.hover(i,t.text)}_fireUnderlineEvent(e,t){const i=e.range,s=this._bufferService.buffer.ydisp,r=this._createLinkUnderlineEvent(i.start.x-1,i.start.y-s-1,i.end.x,i.end.y-s-1,void 0);(t?this._onShowLinkUnderline:this._onHideLinkUnderline).fire(r)}_linkLeave(e,t,i){this._currentLink?.state&&(this._currentLink.state.isHovered=!1,this._currentLink.state.decorations.underline&&this._fireUnderlineEvent(t,!1),this._currentLink.state.decorations.pointerCursor&&e.classList.remove("xterm-cursor-pointer")),t.leave&&t.leave(i,t.text)}_linkAtPosition(e,t){const i=e.range.start.y*this._bufferService.cols+e.range.start.x,s=e.range.end.y*this._bufferService.cols+e.range.end.x,r=t.y*this._bufferService.cols+t.x;return i<=r&&r<=s}_positionFromMouseEvent(e,t,i){const s=i.getCoords(e,t,this._bufferService.cols,this._bufferService.rows);if(s)return{x:s[0],y:s[1]+this._bufferService.buffer.ydisp}}_createLinkUnderlineEvent(e,t,i,s,r){return{x1:e,y1:t,x2:i,y2:s,cols:this._bufferService.cols,fg:r}}};t.Linkifier=l=s([r(1,c.IMouseService),r(2,c.IRenderService),r(3,h.IBufferService),r(4,c.ILinkProviderService)],l)},9042:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.tooMuchOutput=t.promptLabel=void 0,t.promptLabel="Terminal input",t.tooMuchOutput="Too much output to announce, navigate to rows manually to read"},3730:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.OscLinkProvider=void 0;const n=i(511),o=i(2585);let a=t.OscLinkProvider=class{constructor(e,t,i){this._bufferService=e,this._optionsService=t,this._oscLinkService=i}provideLinks(e,t){const i=this._bufferService.buffer.lines.get(e-1);if(!i)return void t(void 0);const s=[],r=this._optionsService.rawOptions.linkHandler,o=new n.CellData,a=i.getTrimmedLength();let c=-1,l=-1,d=!1;for(let t=0;tr?r.activate(e,t,n):h(0,t),hover:(e,t)=>r?.hover?.(e,t,n),leave:(e,t)=>r?.leave?.(e,t,n)})}d=!1,o.hasExtendedAttrs()&&o.extended.urlId?(l=t,c=o.extended.urlId):(l=-1,c=-1)}}t(s)}};function h(e,t){if(confirm(`Do you want to navigate to ${t}?\n\nWARNING: This link could potentially be dangerous`)){const e=window.open();if(e){try{e.opener=null}catch{}e.location.href=t}else console.warn("Opening link blocked as opener could not be cleared")}}t.OscLinkProvider=a=s([r(0,o.IBufferService),r(1,o.IOptionsService),r(2,o.IOscLinkService)],a)},6193:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.RenderDebouncer=void 0,t.RenderDebouncer=class{constructor(e,t){this._renderCallback=e,this._coreBrowserService=t,this._refreshCallbacks=[]}dispose(){this._animationFrame&&(this._coreBrowserService.window.cancelAnimationFrame(this._animationFrame),this._animationFrame=void 0)}addRefreshCallback(e){return this._refreshCallbacks.push(e),this._animationFrame||(this._animationFrame=this._coreBrowserService.window.requestAnimationFrame((()=>this._innerRefresh()))),this._animationFrame}refresh(e,t,i){this._rowCount=i,e=void 0!==e?e:0,t=void 0!==t?t:this._rowCount-1,this._rowStart=void 0!==this._rowStart?Math.min(this._rowStart,e):e,this._rowEnd=void 0!==this._rowEnd?Math.max(this._rowEnd,t):t,this._animationFrame||(this._animationFrame=this._coreBrowserService.window.requestAnimationFrame((()=>this._innerRefresh())))}_innerRefresh(){if(this._animationFrame=void 0,void 0===this._rowStart||void 0===this._rowEnd||void 0===this._rowCount)return void this._runRefreshCallbacks();const e=Math.max(this._rowStart,0),t=Math.min(this._rowEnd,this._rowCount-1);this._rowStart=void 0,this._rowEnd=void 0,this._renderCallback(e,t),this._runRefreshCallbacks()}_runRefreshCallbacks(){for(const e of this._refreshCallbacks)e(0);this._refreshCallbacks=[]}}},3236:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Terminal=void 0;const s=i(3614),r=i(3656),n=i(3551),o=i(9042),a=i(3730),h=i(1680),c=i(3107),l=i(5744),d=i(2950),_=i(1296),u=i(428),f=i(4269),v=i(5114),p=i(8934),g=i(3230),m=i(9312),S=i(4725),C=i(6731),b=i(8055),w=i(8969),y=i(8460),E=i(844),k=i(6114),L=i(8437),D=i(2584),R=i(7399),x=i(5941),A=i(9074),B=i(2585),T=i(5435),M=i(4567),O=i(779);class P extends w.CoreTerminal{get onFocus(){return this._onFocus.event}get onBlur(){return this._onBlur.event}get onA11yChar(){return this._onA11yCharEmitter.event}get onA11yTab(){return this._onA11yTabEmitter.event}get onWillOpen(){return this._onWillOpen.event}constructor(e={}){super(e),this.browser=k,this._keyDownHandled=!1,this._keyDownSeen=!1,this._keyPressHandled=!1,this._unprocessedDeadKey=!1,this._accessibilityManager=this.register(new E.MutableDisposable),this._onCursorMove=this.register(new y.EventEmitter),this.onCursorMove=this._onCursorMove.event,this._onKey=this.register(new y.EventEmitter),this.onKey=this._onKey.event,this._onRender=this.register(new y.EventEmitter),this.onRender=this._onRender.event,this._onSelectionChange=this.register(new y.EventEmitter),this.onSelectionChange=this._onSelectionChange.event,this._onTitleChange=this.register(new y.EventEmitter),this.onTitleChange=this._onTitleChange.event,this._onBell=this.register(new y.EventEmitter),this.onBell=this._onBell.event,this._onFocus=this.register(new y.EventEmitter),this._onBlur=this.register(new y.EventEmitter),this._onA11yCharEmitter=this.register(new y.EventEmitter),this._onA11yTabEmitter=this.register(new y.EventEmitter),this._onWillOpen=this.register(new y.EventEmitter),this._setup(),this._decorationService=this._instantiationService.createInstance(A.DecorationService),this._instantiationService.setService(B.IDecorationService,this._decorationService),this._linkProviderService=this._instantiationService.createInstance(O.LinkProviderService),this._instantiationService.setService(S.ILinkProviderService,this._linkProviderService),this._linkProviderService.registerLinkProvider(this._instantiationService.createInstance(a.OscLinkProvider)),this.register(this._inputHandler.onRequestBell((()=>this._onBell.fire()))),this.register(this._inputHandler.onRequestRefreshRows(((e,t)=>this.refresh(e,t)))),this.register(this._inputHandler.onRequestSendFocus((()=>this._reportFocus()))),this.register(this._inputHandler.onRequestReset((()=>this.reset()))),this.register(this._inputHandler.onRequestWindowsOptionsReport((e=>this._reportWindowsOptions(e)))),this.register(this._inputHandler.onColor((e=>this._handleColorEvent(e)))),this.register((0,y.forwardEvent)(this._inputHandler.onCursorMove,this._onCursorMove)),this.register((0,y.forwardEvent)(this._inputHandler.onTitleChange,this._onTitleChange)),this.register((0,y.forwardEvent)(this._inputHandler.onA11yChar,this._onA11yCharEmitter)),this.register((0,y.forwardEvent)(this._inputHandler.onA11yTab,this._onA11yTabEmitter)),this.register(this._bufferService.onResize((e=>this._afterResize(e.cols,e.rows)))),this.register((0,E.toDisposable)((()=>{this._customKeyEventHandler=void 0,this.element?.parentNode?.removeChild(this.element)})))}_handleColorEvent(e){if(this._themeService)for(const t of e){let e,i="";switch(t.index){case 256:e="foreground",i="10";break;case 257:e="background",i="11";break;case 258:e="cursor",i="12";break;default:e="ansi",i="4;"+t.index}switch(t.type){case 0:const s=b.color.toColorRGB("ansi"===e?this._themeService.colors.ansi[t.index]:this._themeService.colors[e]);this.coreService.triggerDataEvent(`${D.C0.ESC}]${i};${(0,x.toRgbString)(s)}${D.C1_ESCAPED.ST}`);break;case 1:if("ansi"===e)this._themeService.modifyColors((e=>e.ansi[t.index]=b.channels.toColor(...t.color)));else{const i=e;this._themeService.modifyColors((e=>e[i]=b.channels.toColor(...t.color)))}break;case 2:this._themeService.restoreColor(t.index)}}}_setup(){super._setup(),this._customKeyEventHandler=void 0}get buffer(){return this.buffers.active}focus(){this.textarea&&this.textarea.focus({preventScroll:!0})}_handleScreenReaderModeOptionChange(e){e?!this._accessibilityManager.value&&this._renderService&&(this._accessibilityManager.value=this._instantiationService.createInstance(M.AccessibilityManager,this)):this._accessibilityManager.clear()}_handleTextAreaFocus(e){this.coreService.decPrivateModes.sendFocus&&this.coreService.triggerDataEvent(D.C0.ESC+"[I"),this.element.classList.add("focus"),this._showCursor(),this._onFocus.fire()}blur(){return this.textarea?.blur()}_handleTextAreaBlur(){this.textarea.value="",this.refresh(this.buffer.y,this.buffer.y),this.coreService.decPrivateModes.sendFocus&&this.coreService.triggerDataEvent(D.C0.ESC+"[O"),this.element.classList.remove("focus"),this._onBlur.fire()}_syncTextArea(){if(!this.textarea||!this.buffer.isCursorInViewport||this._compositionHelper.isComposing||!this._renderService)return;const e=this.buffer.ybase+this.buffer.y,t=this.buffer.lines.get(e);if(!t)return;const i=Math.min(this.buffer.x,this.cols-1),s=this._renderService.dimensions.css.cell.height,r=t.getWidth(i),n=this._renderService.dimensions.css.cell.width*r,o=this.buffer.y*this._renderService.dimensions.css.cell.height,a=i*this._renderService.dimensions.css.cell.width;this.textarea.style.left=a+"px",this.textarea.style.top=o+"px",this.textarea.style.width=n+"px",this.textarea.style.height=s+"px",this.textarea.style.lineHeight=s+"px",this.textarea.style.zIndex="-5"}_initGlobal(){this._bindKeys(),this.register((0,r.addDisposableDomListener)(this.element,"copy",(e=>{this.hasSelection()&&(0,s.copyHandler)(e,this._selectionService)})));const e=e=>(0,s.handlePasteEvent)(e,this.textarea,this.coreService,this.optionsService);this.register((0,r.addDisposableDomListener)(this.textarea,"paste",e)),this.register((0,r.addDisposableDomListener)(this.element,"paste",e)),k.isFirefox?this.register((0,r.addDisposableDomListener)(this.element,"mousedown",(e=>{2===e.button&&(0,s.rightClickHandler)(e,this.textarea,this.screenElement,this._selectionService,this.options.rightClickSelectsWord)}))):this.register((0,r.addDisposableDomListener)(this.element,"contextmenu",(e=>{(0,s.rightClickHandler)(e,this.textarea,this.screenElement,this._selectionService,this.options.rightClickSelectsWord)}))),k.isLinux&&this.register((0,r.addDisposableDomListener)(this.element,"auxclick",(e=>{1===e.button&&(0,s.moveTextAreaUnderMouseCursor)(e,this.textarea,this.screenElement)})))}_bindKeys(){this.register((0,r.addDisposableDomListener)(this.textarea,"keyup",(e=>this._keyUp(e)),!0)),this.register((0,r.addDisposableDomListener)(this.textarea,"keydown",(e=>this._keyDown(e)),!0)),this.register((0,r.addDisposableDomListener)(this.textarea,"keypress",(e=>this._keyPress(e)),!0)),this.register((0,r.addDisposableDomListener)(this.textarea,"compositionstart",(()=>this._compositionHelper.compositionstart()))),this.register((0,r.addDisposableDomListener)(this.textarea,"compositionupdate",(e=>this._compositionHelper.compositionupdate(e)))),this.register((0,r.addDisposableDomListener)(this.textarea,"compositionend",(()=>this._compositionHelper.compositionend()))),this.register((0,r.addDisposableDomListener)(this.textarea,"input",(e=>this._inputEvent(e)),!0)),this.register(this.onRender((()=>this._compositionHelper.updateCompositionElements())))}open(e){if(!e)throw new Error("Terminal requires a parent element.");if(e.isConnected||this._logService.debug("Terminal.open was called on an element that was not attached to the DOM"),this.element?.ownerDocument.defaultView&&this._coreBrowserService)return void(this.element.ownerDocument.defaultView!==this._coreBrowserService.window&&(this._coreBrowserService.window=this.element.ownerDocument.defaultView));this._document=e.ownerDocument,this.options.documentOverride&&this.options.documentOverride instanceof Document&&(this._document=this.optionsService.rawOptions.documentOverride),this.element=this._document.createElement("div"),this.element.dir="ltr",this.element.classList.add("terminal"),this.element.classList.add("xterm"),e.appendChild(this.element);const t=this._document.createDocumentFragment();this._viewportElement=this._document.createElement("div"),this._viewportElement.classList.add("xterm-viewport"),t.appendChild(this._viewportElement),this._viewportScrollArea=this._document.createElement("div"),this._viewportScrollArea.classList.add("xterm-scroll-area"),this._viewportElement.appendChild(this._viewportScrollArea),this.screenElement=this._document.createElement("div"),this.screenElement.classList.add("xterm-screen"),this.register((0,r.addDisposableDomListener)(this.screenElement,"mousemove",(e=>this.updateCursorStyle(e)))),this._helperContainer=this._document.createElement("div"),this._helperContainer.classList.add("xterm-helpers"),this.screenElement.appendChild(this._helperContainer),t.appendChild(this.screenElement),this.textarea=this._document.createElement("textarea"),this.textarea.classList.add("xterm-helper-textarea"),this.textarea.setAttribute("aria-label",o.promptLabel),k.isChromeOS||this.textarea.setAttribute("aria-multiline","false"),this.textarea.setAttribute("autocorrect","off"),this.textarea.setAttribute("autocapitalize","off"),this.textarea.setAttribute("spellcheck","false"),this.textarea.tabIndex=0,this._coreBrowserService=this.register(this._instantiationService.createInstance(v.CoreBrowserService,this.textarea,e.ownerDocument.defaultView??window,this._document??"undefined"!=typeof window?window.document:null)),this._instantiationService.setService(S.ICoreBrowserService,this._coreBrowserService),this.register((0,r.addDisposableDomListener)(this.textarea,"focus",(e=>this._handleTextAreaFocus(e)))),this.register((0,r.addDisposableDomListener)(this.textarea,"blur",(()=>this._handleTextAreaBlur()))),this._helperContainer.appendChild(this.textarea),this._charSizeService=this._instantiationService.createInstance(u.CharSizeService,this._document,this._helperContainer),this._instantiationService.setService(S.ICharSizeService,this._charSizeService),this._themeService=this._instantiationService.createInstance(C.ThemeService),this._instantiationService.setService(S.IThemeService,this._themeService),this._characterJoinerService=this._instantiationService.createInstance(f.CharacterJoinerService),this._instantiationService.setService(S.ICharacterJoinerService,this._characterJoinerService),this._renderService=this.register(this._instantiationService.createInstance(g.RenderService,this.rows,this.screenElement)),this._instantiationService.setService(S.IRenderService,this._renderService),this.register(this._renderService.onRenderedViewportChange((e=>this._onRender.fire(e)))),this.onResize((e=>this._renderService.resize(e.cols,e.rows))),this._compositionView=this._document.createElement("div"),this._compositionView.classList.add("composition-view"),this._compositionHelper=this._instantiationService.createInstance(d.CompositionHelper,this.textarea,this._compositionView),this._helperContainer.appendChild(this._compositionView),this._mouseService=this._instantiationService.createInstance(p.MouseService),this._instantiationService.setService(S.IMouseService,this._mouseService),this.linkifier=this.register(this._instantiationService.createInstance(n.Linkifier,this.screenElement)),this.element.appendChild(t);try{this._onWillOpen.fire(this.element)}catch{}this._renderService.hasRenderer()||this._renderService.setRenderer(this._createRenderer()),this.viewport=this._instantiationService.createInstance(h.Viewport,this._viewportElement,this._viewportScrollArea),this.viewport.onRequestScrollLines((e=>this.scrollLines(e.amount,e.suppressScrollEvent,1))),this.register(this._inputHandler.onRequestSyncScrollBar((()=>this.viewport.syncScrollArea()))),this.register(this.viewport),this.register(this.onCursorMove((()=>{this._renderService.handleCursorMove(),this._syncTextArea()}))),this.register(this.onResize((()=>this._renderService.handleResize(this.cols,this.rows)))),this.register(this.onBlur((()=>this._renderService.handleBlur()))),this.register(this.onFocus((()=>this._renderService.handleFocus()))),this.register(this._renderService.onDimensionsChange((()=>this.viewport.syncScrollArea()))),this._selectionService=this.register(this._instantiationService.createInstance(m.SelectionService,this.element,this.screenElement,this.linkifier)),this._instantiationService.setService(S.ISelectionService,this._selectionService),this.register(this._selectionService.onRequestScrollLines((e=>this.scrollLines(e.amount,e.suppressScrollEvent)))),this.register(this._selectionService.onSelectionChange((()=>this._onSelectionChange.fire()))),this.register(this._selectionService.onRequestRedraw((e=>this._renderService.handleSelectionChanged(e.start,e.end,e.columnSelectMode)))),this.register(this._selectionService.onLinuxMouseSelection((e=>{this.textarea.value=e,this.textarea.focus(),this.textarea.select()}))),this.register(this._onScroll.event((e=>{this.viewport.syncScrollArea(),this._selectionService.refresh()}))),this.register((0,r.addDisposableDomListener)(this._viewportElement,"scroll",(()=>this._selectionService.refresh()))),this.register(this._instantiationService.createInstance(c.BufferDecorationRenderer,this.screenElement)),this.register((0,r.addDisposableDomListener)(this.element,"mousedown",(e=>this._selectionService.handleMouseDown(e)))),this.coreMouseService.areMouseEventsActive?(this._selectionService.disable(),this.element.classList.add("enable-mouse-events")):this._selectionService.enable(),this.options.screenReaderMode&&(this._accessibilityManager.value=this._instantiationService.createInstance(M.AccessibilityManager,this)),this.register(this.optionsService.onSpecificOptionChange("screenReaderMode",(e=>this._handleScreenReaderModeOptionChange(e)))),this.options.overviewRulerWidth&&(this._overviewRulerRenderer=this.register(this._instantiationService.createInstance(l.OverviewRulerRenderer,this._viewportElement,this.screenElement))),this.optionsService.onSpecificOptionChange("overviewRulerWidth",(e=>{!this._overviewRulerRenderer&&e&&this._viewportElement&&this.screenElement&&(this._overviewRulerRenderer=this.register(this._instantiationService.createInstance(l.OverviewRulerRenderer,this._viewportElement,this.screenElement)))})),this._charSizeService.measure(),this.refresh(0,this.rows-1),this._initGlobal(),this.bindMouse()}_createRenderer(){return this._instantiationService.createInstance(_.DomRenderer,this,this._document,this.element,this.screenElement,this._viewportElement,this._helperContainer,this.linkifier)}bindMouse(){const e=this,t=this.element;function i(t){const i=e._mouseService.getMouseReportCoords(t,e.screenElement);if(!i)return!1;let s,r;switch(t.overrideType||t.type){case"mousemove":r=32,void 0===t.buttons?(s=3,void 0!==t.button&&(s=t.button<3?t.button:3)):s=1&t.buttons?0:4&t.buttons?1:2&t.buttons?2:3;break;case"mouseup":r=0,s=t.button<3?t.button:3;break;case"mousedown":r=1,s=t.button<3?t.button:3;break;case"wheel":if(e._customWheelEventHandler&&!1===e._customWheelEventHandler(t))return!1;if(0===e.viewport.getLinesScrolled(t))return!1;r=t.deltaY<0?0:1,s=4;break;default:return!1}return!(void 0===r||void 0===s||s>4)&&e.coreMouseService.triggerMouseEvent({col:i.col,row:i.row,x:i.x,y:i.y,button:s,action:r,ctrl:t.ctrlKey,alt:t.altKey,shift:t.shiftKey})}const s={mouseup:null,wheel:null,mousedrag:null,mousemove:null},n={mouseup:e=>(i(e),e.buttons||(this._document.removeEventListener("mouseup",s.mouseup),s.mousedrag&&this._document.removeEventListener("mousemove",s.mousedrag)),this.cancel(e)),wheel:e=>(i(e),this.cancel(e,!0)),mousedrag:e=>{e.buttons&&i(e)},mousemove:e=>{e.buttons||i(e)}};this.register(this.coreMouseService.onProtocolChange((e=>{e?("debug"===this.optionsService.rawOptions.logLevel&&this._logService.debug("Binding to mouse events:",this.coreMouseService.explainEvents(e)),this.element.classList.add("enable-mouse-events"),this._selectionService.disable()):(this._logService.debug("Unbinding from mouse events."),this.element.classList.remove("enable-mouse-events"),this._selectionService.enable()),8&e?s.mousemove||(t.addEventListener("mousemove",n.mousemove),s.mousemove=n.mousemove):(t.removeEventListener("mousemove",s.mousemove),s.mousemove=null),16&e?s.wheel||(t.addEventListener("wheel",n.wheel,{passive:!1}),s.wheel=n.wheel):(t.removeEventListener("wheel",s.wheel),s.wheel=null),2&e?s.mouseup||(s.mouseup=n.mouseup):(this._document.removeEventListener("mouseup",s.mouseup),s.mouseup=null),4&e?s.mousedrag||(s.mousedrag=n.mousedrag):(this._document.removeEventListener("mousemove",s.mousedrag),s.mousedrag=null)}))),this.coreMouseService.activeProtocol=this.coreMouseService.activeProtocol,this.register((0,r.addDisposableDomListener)(t,"mousedown",(e=>{if(e.preventDefault(),this.focus(),this.coreMouseService.areMouseEventsActive&&!this._selectionService.shouldForceSelection(e))return i(e),s.mouseup&&this._document.addEventListener("mouseup",s.mouseup),s.mousedrag&&this._document.addEventListener("mousemove",s.mousedrag),this.cancel(e)}))),this.register((0,r.addDisposableDomListener)(t,"wheel",(e=>{if(!s.wheel){if(this._customWheelEventHandler&&!1===this._customWheelEventHandler(e))return!1;if(!this.buffer.hasScrollback){const t=this.viewport.getLinesScrolled(e);if(0===t)return;const i=D.C0.ESC+(this.coreService.decPrivateModes.applicationCursorKeys?"O":"[")+(e.deltaY<0?"A":"B");let s="";for(let e=0;e{if(!this.coreMouseService.areMouseEventsActive)return this.viewport.handleTouchStart(e),this.cancel(e)}),{passive:!0})),this.register((0,r.addDisposableDomListener)(t,"touchmove",(e=>{if(!this.coreMouseService.areMouseEventsActive)return this.viewport.handleTouchMove(e)?void 0:this.cancel(e)}),{passive:!1}))}refresh(e,t){this._renderService?.refreshRows(e,t)}updateCursorStyle(e){this._selectionService?.shouldColumnSelect(e)?this.element.classList.add("column-select"):this.element.classList.remove("column-select")}_showCursor(){this.coreService.isCursorInitialized||(this.coreService.isCursorInitialized=!0,this.refresh(this.buffer.y,this.buffer.y))}scrollLines(e,t,i=0){1===i?(super.scrollLines(e,t,i),this.refresh(0,this.rows-1)):this.viewport?.scrollLines(e)}paste(e){(0,s.paste)(e,this.textarea,this.coreService,this.optionsService)}attachCustomKeyEventHandler(e){this._customKeyEventHandler=e}attachCustomWheelEventHandler(e){this._customWheelEventHandler=e}registerLinkProvider(e){return this._linkProviderService.registerLinkProvider(e)}registerCharacterJoiner(e){if(!this._characterJoinerService)throw new Error("Terminal must be opened first");const t=this._characterJoinerService.register(e);return this.refresh(0,this.rows-1),t}deregisterCharacterJoiner(e){if(!this._characterJoinerService)throw new Error("Terminal must be opened first");this._characterJoinerService.deregister(e)&&this.refresh(0,this.rows-1)}get markers(){return this.buffer.markers}registerMarker(e){return this.buffer.addMarker(this.buffer.ybase+this.buffer.y+e)}registerDecoration(e){return this._decorationService.registerDecoration(e)}hasSelection(){return!!this._selectionService&&this._selectionService.hasSelection}select(e,t,i){this._selectionService.setSelection(e,t,i)}getSelection(){return this._selectionService?this._selectionService.selectionText:""}getSelectionPosition(){if(this._selectionService&&this._selectionService.hasSelection)return{start:{x:this._selectionService.selectionStart[0],y:this._selectionService.selectionStart[1]},end:{x:this._selectionService.selectionEnd[0],y:this._selectionService.selectionEnd[1]}}}clearSelection(){this._selectionService?.clearSelection()}selectAll(){this._selectionService?.selectAll()}selectLines(e,t){this._selectionService?.selectLines(e,t)}_keyDown(e){if(this._keyDownHandled=!1,this._keyDownSeen=!0,this._customKeyEventHandler&&!1===this._customKeyEventHandler(e))return!1;const t=this.browser.isMac&&this.options.macOptionIsMeta&&e.altKey;if(!t&&!this._compositionHelper.keydown(e))return this.options.scrollOnUserInput&&this.buffer.ybase!==this.buffer.ydisp&&this.scrollToBottom(),!1;t||"Dead"!==e.key&&"AltGraph"!==e.key||(this._unprocessedDeadKey=!0);const i=(0,R.evaluateKeyboardEvent)(e,this.coreService.decPrivateModes.applicationCursorKeys,this.browser.isMac,this.options.macOptionIsMeta);if(this.updateCursorStyle(e),3===i.type||2===i.type){const t=this.rows-1;return this.scrollLines(2===i.type?-t:t),this.cancel(e,!0)}return 1===i.type&&this.selectAll(),!!this._isThirdLevelShift(this.browser,e)||(i.cancel&&this.cancel(e,!0),!i.key||!!(e.key&&!e.ctrlKey&&!e.altKey&&!e.metaKey&&1===e.key.length&&e.key.charCodeAt(0)>=65&&e.key.charCodeAt(0)<=90)||(this._unprocessedDeadKey?(this._unprocessedDeadKey=!1,!0):(i.key!==D.C0.ETX&&i.key!==D.C0.CR||(this.textarea.value=""),this._onKey.fire({key:i.key,domEvent:e}),this._showCursor(),this.coreService.triggerDataEvent(i.key,!0),!this.optionsService.rawOptions.screenReaderMode||e.altKey||e.ctrlKey?this.cancel(e,!0):void(this._keyDownHandled=!0))))}_isThirdLevelShift(e,t){const i=e.isMac&&!this.options.macOptionIsMeta&&t.altKey&&!t.ctrlKey&&!t.metaKey||e.isWindows&&t.altKey&&t.ctrlKey&&!t.metaKey||e.isWindows&&t.getModifierState("AltGraph");return"keypress"===t.type?i:i&&(!t.keyCode||t.keyCode>47)}_keyUp(e){this._keyDownSeen=!1,this._customKeyEventHandler&&!1===this._customKeyEventHandler(e)||(function(e){return 16===e.keyCode||17===e.keyCode||18===e.keyCode}(e)||this.focus(),this.updateCursorStyle(e),this._keyPressHandled=!1)}_keyPress(e){let t;if(this._keyPressHandled=!1,this._keyDownHandled)return!1;if(this._customKeyEventHandler&&!1===this._customKeyEventHandler(e))return!1;if(this.cancel(e),e.charCode)t=e.charCode;else if(null===e.which||void 0===e.which)t=e.keyCode;else{if(0===e.which||0===e.charCode)return!1;t=e.which}return!(!t||(e.altKey||e.ctrlKey||e.metaKey)&&!this._isThirdLevelShift(this.browser,e)||(t=String.fromCharCode(t),this._onKey.fire({key:t,domEvent:e}),this._showCursor(),this.coreService.triggerDataEvent(t,!0),this._keyPressHandled=!0,this._unprocessedDeadKey=!1,0))}_inputEvent(e){if(e.data&&"insertText"===e.inputType&&(!e.composed||!this._keyDownSeen)&&!this.optionsService.rawOptions.screenReaderMode){if(this._keyPressHandled)return!1;this._unprocessedDeadKey=!1;const t=e.data;return this.coreService.triggerDataEvent(t,!0),this.cancel(e),!0}return!1}resize(e,t){e!==this.cols||t!==this.rows?super.resize(e,t):this._charSizeService&&!this._charSizeService.hasValidSize&&this._charSizeService.measure()}_afterResize(e,t){this._charSizeService?.measure(),this.viewport?.syncScrollArea(!0)}clear(){if(0!==this.buffer.ybase||0!==this.buffer.y){this.buffer.clearAllMarkers(),this.buffer.lines.set(0,this.buffer.lines.get(this.buffer.ybase+this.buffer.y)),this.buffer.lines.length=1,this.buffer.ydisp=0,this.buffer.ybase=0,this.buffer.y=0;for(let e=1;e{Object.defineProperty(t,"__esModule",{value:!0}),t.TimeBasedDebouncer=void 0,t.TimeBasedDebouncer=class{constructor(e,t=1e3){this._renderCallback=e,this._debounceThresholdMS=t,this._lastRefreshMs=0,this._additionalRefreshRequested=!1}dispose(){this._refreshTimeoutID&&clearTimeout(this._refreshTimeoutID)}refresh(e,t,i){this._rowCount=i,e=void 0!==e?e:0,t=void 0!==t?t:this._rowCount-1,this._rowStart=void 0!==this._rowStart?Math.min(this._rowStart,e):e,this._rowEnd=void 0!==this._rowEnd?Math.max(this._rowEnd,t):t;const s=Date.now();if(s-this._lastRefreshMs>=this._debounceThresholdMS)this._lastRefreshMs=s,this._innerRefresh();else if(!this._additionalRefreshRequested){const e=s-this._lastRefreshMs,t=this._debounceThresholdMS-e;this._additionalRefreshRequested=!0,this._refreshTimeoutID=window.setTimeout((()=>{this._lastRefreshMs=Date.now(),this._innerRefresh(),this._additionalRefreshRequested=!1,this._refreshTimeoutID=void 0}),t)}}_innerRefresh(){if(void 0===this._rowStart||void 0===this._rowEnd||void 0===this._rowCount)return;const e=Math.max(this._rowStart,0),t=Math.min(this._rowEnd,this._rowCount-1);this._rowStart=void 0,this._rowEnd=void 0,this._renderCallback(e,t)}}},1680:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.Viewport=void 0;const n=i(3656),o=i(4725),a=i(8460),h=i(844),c=i(2585);let l=t.Viewport=class extends h.Disposable{constructor(e,t,i,s,r,o,h,c){super(),this._viewportElement=e,this._scrollArea=t,this._bufferService=i,this._optionsService=s,this._charSizeService=r,this._renderService=o,this._coreBrowserService=h,this.scrollBarWidth=0,this._currentRowHeight=0,this._currentDeviceCellHeight=0,this._lastRecordedBufferLength=0,this._lastRecordedViewportHeight=0,this._lastRecordedBufferHeight=0,this._lastTouchY=0,this._lastScrollTop=0,this._wheelPartialScroll=0,this._refreshAnimationFrame=null,this._ignoreNextScrollEvent=!1,this._smoothScrollState={startTime:0,origin:-1,target:-1},this._onRequestScrollLines=this.register(new a.EventEmitter),this.onRequestScrollLines=this._onRequestScrollLines.event,this.scrollBarWidth=this._viewportElement.offsetWidth-this._scrollArea.offsetWidth||15,this.register((0,n.addDisposableDomListener)(this._viewportElement,"scroll",this._handleScroll.bind(this))),this._activeBuffer=this._bufferService.buffer,this.register(this._bufferService.buffers.onBufferActivate((e=>this._activeBuffer=e.activeBuffer))),this._renderDimensions=this._renderService.dimensions,this.register(this._renderService.onDimensionsChange((e=>this._renderDimensions=e))),this._handleThemeChange(c.colors),this.register(c.onChangeColors((e=>this._handleThemeChange(e)))),this.register(this._optionsService.onSpecificOptionChange("scrollback",(()=>this.syncScrollArea()))),setTimeout((()=>this.syncScrollArea()))}_handleThemeChange(e){this._viewportElement.style.backgroundColor=e.background.css}reset(){this._currentRowHeight=0,this._currentDeviceCellHeight=0,this._lastRecordedBufferLength=0,this._lastRecordedViewportHeight=0,this._lastRecordedBufferHeight=0,this._lastTouchY=0,this._lastScrollTop=0,this._coreBrowserService.window.requestAnimationFrame((()=>this.syncScrollArea()))}_refresh(e){if(e)return this._innerRefresh(),void(null!==this._refreshAnimationFrame&&this._coreBrowserService.window.cancelAnimationFrame(this._refreshAnimationFrame));null===this._refreshAnimationFrame&&(this._refreshAnimationFrame=this._coreBrowserService.window.requestAnimationFrame((()=>this._innerRefresh())))}_innerRefresh(){if(this._charSizeService.height>0){this._currentRowHeight=this._renderDimensions.device.cell.height/this._coreBrowserService.dpr,this._currentDeviceCellHeight=this._renderDimensions.device.cell.height,this._lastRecordedViewportHeight=this._viewportElement.offsetHeight;const e=Math.round(this._currentRowHeight*this._lastRecordedBufferLength)+(this._lastRecordedViewportHeight-this._renderDimensions.css.canvas.height);this._lastRecordedBufferHeight!==e&&(this._lastRecordedBufferHeight=e,this._scrollArea.style.height=this._lastRecordedBufferHeight+"px")}const e=this._bufferService.buffer.ydisp*this._currentRowHeight;this._viewportElement.scrollTop!==e&&(this._ignoreNextScrollEvent=!0,this._viewportElement.scrollTop=e),this._refreshAnimationFrame=null}syncScrollArea(e=!1){if(this._lastRecordedBufferLength!==this._bufferService.buffer.lines.length)return this._lastRecordedBufferLength=this._bufferService.buffer.lines.length,void this._refresh(e);this._lastRecordedViewportHeight===this._renderService.dimensions.css.canvas.height&&this._lastScrollTop===this._activeBuffer.ydisp*this._currentRowHeight&&this._renderDimensions.device.cell.height===this._currentDeviceCellHeight||this._refresh(e)}_handleScroll(e){if(this._lastScrollTop=this._viewportElement.scrollTop,!this._viewportElement.offsetParent)return;if(this._ignoreNextScrollEvent)return this._ignoreNextScrollEvent=!1,void this._onRequestScrollLines.fire({amount:0,suppressScrollEvent:!0});const t=Math.round(this._lastScrollTop/this._currentRowHeight)-this._bufferService.buffer.ydisp;this._onRequestScrollLines.fire({amount:t,suppressScrollEvent:!0})}_smoothScroll(){if(this._isDisposed||-1===this._smoothScrollState.origin||-1===this._smoothScrollState.target)return;const e=this._smoothScrollPercent();this._viewportElement.scrollTop=this._smoothScrollState.origin+Math.round(e*(this._smoothScrollState.target-this._smoothScrollState.origin)),e<1?this._coreBrowserService.window.requestAnimationFrame((()=>this._smoothScroll())):this._clearSmoothScrollState()}_smoothScrollPercent(){return this._optionsService.rawOptions.smoothScrollDuration&&this._smoothScrollState.startTime?Math.max(Math.min((Date.now()-this._smoothScrollState.startTime)/this._optionsService.rawOptions.smoothScrollDuration,1),0):1}_clearSmoothScrollState(){this._smoothScrollState.startTime=0,this._smoothScrollState.origin=-1,this._smoothScrollState.target=-1}_bubbleScroll(e,t){const i=this._viewportElement.scrollTop+this._lastRecordedViewportHeight;return!(t<0&&0!==this._viewportElement.scrollTop||t>0&&i0&&(i=e),s=""}}return{bufferElements:r,cursorElement:i}}getLinesScrolled(e){if(0===e.deltaY||e.shiftKey)return 0;let t=this._applyScrollModifier(e.deltaY,e);return e.deltaMode===WheelEvent.DOM_DELTA_PIXEL?(t/=this._currentRowHeight+0,this._wheelPartialScroll+=t,t=Math.floor(Math.abs(this._wheelPartialScroll))*(this._wheelPartialScroll>0?1:-1),this._wheelPartialScroll%=1):e.deltaMode===WheelEvent.DOM_DELTA_PAGE&&(t*=this._bufferService.rows),t}_applyScrollModifier(e,t){const i=this._optionsService.rawOptions.fastScrollModifier;return"alt"===i&&t.altKey||"ctrl"===i&&t.ctrlKey||"shift"===i&&t.shiftKey?e*this._optionsService.rawOptions.fastScrollSensitivity*this._optionsService.rawOptions.scrollSensitivity:e*this._optionsService.rawOptions.scrollSensitivity}handleTouchStart(e){this._lastTouchY=e.touches[0].pageY}handleTouchMove(e){const t=this._lastTouchY-e.touches[0].pageY;return this._lastTouchY=e.touches[0].pageY,0!==t&&(this._viewportElement.scrollTop+=t,this._bubbleScroll(e,t))}};t.Viewport=l=s([r(2,c.IBufferService),r(3,c.IOptionsService),r(4,o.ICharSizeService),r(5,o.IRenderService),r(6,o.ICoreBrowserService),r(7,o.IThemeService)],l)},3107:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.BufferDecorationRenderer=void 0;const n=i(4725),o=i(844),a=i(2585);let h=t.BufferDecorationRenderer=class extends o.Disposable{constructor(e,t,i,s,r){super(),this._screenElement=e,this._bufferService=t,this._coreBrowserService=i,this._decorationService=s,this._renderService=r,this._decorationElements=new Map,this._altBufferIsActive=!1,this._dimensionsChanged=!1,this._container=document.createElement("div"),this._container.classList.add("xterm-decoration-container"),this._screenElement.appendChild(this._container),this.register(this._renderService.onRenderedViewportChange((()=>this._doRefreshDecorations()))),this.register(this._renderService.onDimensionsChange((()=>{this._dimensionsChanged=!0,this._queueRefresh()}))),this.register(this._coreBrowserService.onDprChange((()=>this._queueRefresh()))),this.register(this._bufferService.buffers.onBufferActivate((()=>{this._altBufferIsActive=this._bufferService.buffer===this._bufferService.buffers.alt}))),this.register(this._decorationService.onDecorationRegistered((()=>this._queueRefresh()))),this.register(this._decorationService.onDecorationRemoved((e=>this._removeDecoration(e)))),this.register((0,o.toDisposable)((()=>{this._container.remove(),this._decorationElements.clear()})))}_queueRefresh(){void 0===this._animationFrame&&(this._animationFrame=this._renderService.addRefreshCallback((()=>{this._doRefreshDecorations(),this._animationFrame=void 0})))}_doRefreshDecorations(){for(const e of this._decorationService.decorations)this._renderDecoration(e);this._dimensionsChanged=!1}_renderDecoration(e){this._refreshStyle(e),this._dimensionsChanged&&this._refreshXPosition(e)}_createElement(e){const t=this._coreBrowserService.mainDocument.createElement("div");t.classList.add("xterm-decoration"),t.classList.toggle("xterm-decoration-top-layer","top"===e?.options?.layer),t.style.width=`${Math.round((e.options.width||1)*this._renderService.dimensions.css.cell.width)}px`,t.style.height=(e.options.height||1)*this._renderService.dimensions.css.cell.height+"px",t.style.top=(e.marker.line-this._bufferService.buffers.active.ydisp)*this._renderService.dimensions.css.cell.height+"px",t.style.lineHeight=`${this._renderService.dimensions.css.cell.height}px`;const i=e.options.x??0;return i&&i>this._bufferService.cols&&(t.style.display="none"),this._refreshXPosition(e,t),t}_refreshStyle(e){const t=e.marker.line-this._bufferService.buffers.active.ydisp;if(t<0||t>=this._bufferService.rows)e.element&&(e.element.style.display="none",e.onRenderEmitter.fire(e.element));else{let i=this._decorationElements.get(e);i||(i=this._createElement(e),e.element=i,this._decorationElements.set(e,i),this._container.appendChild(i),e.onDispose((()=>{this._decorationElements.delete(e),i.remove()}))),i.style.top=t*this._renderService.dimensions.css.cell.height+"px",i.style.display=this._altBufferIsActive?"none":"block",e.onRenderEmitter.fire(i)}}_refreshXPosition(e,t=e.element){if(!t)return;const i=e.options.x??0;"right"===(e.options.anchor||"left")?t.style.right=i?i*this._renderService.dimensions.css.cell.width+"px":"":t.style.left=i?i*this._renderService.dimensions.css.cell.width+"px":""}_removeDecoration(e){this._decorationElements.get(e)?.remove(),this._decorationElements.delete(e),e.dispose()}};t.BufferDecorationRenderer=h=s([r(1,a.IBufferService),r(2,n.ICoreBrowserService),r(3,a.IDecorationService),r(4,n.IRenderService)],h)},5871:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ColorZoneStore=void 0,t.ColorZoneStore=class{constructor(){this._zones=[],this._zonePool=[],this._zonePoolIndex=0,this._linePadding={full:0,left:0,center:0,right:0}}get zones(){return this._zonePool.length=Math.min(this._zonePool.length,this._zones.length),this._zones}clear(){this._zones.length=0,this._zonePoolIndex=0}addDecoration(e){if(e.options.overviewRulerOptions){for(const t of this._zones)if(t.color===e.options.overviewRulerOptions.color&&t.position===e.options.overviewRulerOptions.position){if(this._lineIntersectsZone(t,e.marker.line))return;if(this._lineAdjacentToZone(t,e.marker.line,e.options.overviewRulerOptions.position))return void this._addLineToZone(t,e.marker.line)}if(this._zonePoolIndex=e.startBufferLine&&t<=e.endBufferLine}_lineAdjacentToZone(e,t,i){return t>=e.startBufferLine-this._linePadding[i||"full"]&&t<=e.endBufferLine+this._linePadding[i||"full"]}_addLineToZone(e,t){e.startBufferLine=Math.min(e.startBufferLine,t),e.endBufferLine=Math.max(e.endBufferLine,t)}}},5744:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.OverviewRulerRenderer=void 0;const n=i(5871),o=i(4725),a=i(844),h=i(2585),c={full:0,left:0,center:0,right:0},l={full:0,left:0,center:0,right:0},d={full:0,left:0,center:0,right:0};let _=t.OverviewRulerRenderer=class extends a.Disposable{get _width(){return this._optionsService.options.overviewRulerWidth||0}constructor(e,t,i,s,r,o,h){super(),this._viewportElement=e,this._screenElement=t,this._bufferService=i,this._decorationService=s,this._renderService=r,this._optionsService=o,this._coreBrowserService=h,this._colorZoneStore=new n.ColorZoneStore,this._shouldUpdateDimensions=!0,this._shouldUpdateAnchor=!0,this._lastKnownBufferLength=0,this._canvas=this._coreBrowserService.mainDocument.createElement("canvas"),this._canvas.classList.add("xterm-decoration-overview-ruler"),this._refreshCanvasDimensions(),this._viewportElement.parentElement?.insertBefore(this._canvas,this._viewportElement);const c=this._canvas.getContext("2d");if(!c)throw new Error("Ctx cannot be null");this._ctx=c,this._registerDecorationListeners(),this._registerBufferChangeListeners(),this._registerDimensionChangeListeners(),this.register((0,a.toDisposable)((()=>{this._canvas?.remove()})))}_registerDecorationListeners(){this.register(this._decorationService.onDecorationRegistered((()=>this._queueRefresh(void 0,!0)))),this.register(this._decorationService.onDecorationRemoved((()=>this._queueRefresh(void 0,!0))))}_registerBufferChangeListeners(){this.register(this._renderService.onRenderedViewportChange((()=>this._queueRefresh()))),this.register(this._bufferService.buffers.onBufferActivate((()=>{this._canvas.style.display=this._bufferService.buffer===this._bufferService.buffers.alt?"none":"block"}))),this.register(this._bufferService.onScroll((()=>{this._lastKnownBufferLength!==this._bufferService.buffers.normal.lines.length&&(this._refreshDrawHeightConstants(),this._refreshColorZonePadding())})))}_registerDimensionChangeListeners(){this.register(this._renderService.onRender((()=>{this._containerHeight&&this._containerHeight===this._screenElement.clientHeight||(this._queueRefresh(!0),this._containerHeight=this._screenElement.clientHeight)}))),this.register(this._optionsService.onSpecificOptionChange("overviewRulerWidth",(()=>this._queueRefresh(!0)))),this.register(this._coreBrowserService.onDprChange((()=>this._queueRefresh(!0)))),this._queueRefresh(!0)}_refreshDrawConstants(){const e=Math.floor(this._canvas.width/3),t=Math.ceil(this._canvas.width/3);l.full=this._canvas.width,l.left=e,l.center=t,l.right=e,this._refreshDrawHeightConstants(),d.full=0,d.left=0,d.center=l.left,d.right=l.left+l.center}_refreshDrawHeightConstants(){c.full=Math.round(2*this._coreBrowserService.dpr);const e=this._canvas.height/this._bufferService.buffer.lines.length,t=Math.round(Math.max(Math.min(e,12),6)*this._coreBrowserService.dpr);c.left=t,c.center=t,c.right=t}_refreshColorZonePadding(){this._colorZoneStore.setPadding({full:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*c.full),left:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*c.left),center:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*c.center),right:Math.floor(this._bufferService.buffers.active.lines.length/(this._canvas.height-1)*c.right)}),this._lastKnownBufferLength=this._bufferService.buffers.normal.lines.length}_refreshCanvasDimensions(){this._canvas.style.width=`${this._width}px`,this._canvas.width=Math.round(this._width*this._coreBrowserService.dpr),this._canvas.style.height=`${this._screenElement.clientHeight}px`,this._canvas.height=Math.round(this._screenElement.clientHeight*this._coreBrowserService.dpr),this._refreshDrawConstants(),this._refreshColorZonePadding()}_refreshDecorations(){this._shouldUpdateDimensions&&this._refreshCanvasDimensions(),this._ctx.clearRect(0,0,this._canvas.width,this._canvas.height),this._colorZoneStore.clear();for(const e of this._decorationService.decorations)this._colorZoneStore.addDecoration(e);this._ctx.lineWidth=1;const e=this._colorZoneStore.zones;for(const t of e)"full"!==t.position&&this._renderColorZone(t);for(const t of e)"full"===t.position&&this._renderColorZone(t);this._shouldUpdateDimensions=!1,this._shouldUpdateAnchor=!1}_renderColorZone(e){this._ctx.fillStyle=e.color,this._ctx.fillRect(d[e.position||"full"],Math.round((this._canvas.height-1)*(e.startBufferLine/this._bufferService.buffers.active.lines.length)-c[e.position||"full"]/2),l[e.position||"full"],Math.round((this._canvas.height-1)*((e.endBufferLine-e.startBufferLine)/this._bufferService.buffers.active.lines.length)+c[e.position||"full"]))}_queueRefresh(e,t){this._shouldUpdateDimensions=e||this._shouldUpdateDimensions,this._shouldUpdateAnchor=t||this._shouldUpdateAnchor,void 0===this._animationFrame&&(this._animationFrame=this._coreBrowserService.window.requestAnimationFrame((()=>{this._refreshDecorations(),this._animationFrame=void 0})))}};t.OverviewRulerRenderer=_=s([r(2,h.IBufferService),r(3,h.IDecorationService),r(4,o.IRenderService),r(5,h.IOptionsService),r(6,o.ICoreBrowserService)],_)},2950:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CompositionHelper=void 0;const n=i(4725),o=i(2585),a=i(2584);let h=t.CompositionHelper=class{get isComposing(){return this._isComposing}constructor(e,t,i,s,r,n){this._textarea=e,this._compositionView=t,this._bufferService=i,this._optionsService=s,this._coreService=r,this._renderService=n,this._isComposing=!1,this._isSendingComposition=!1,this._compositionPosition={start:0,end:0},this._dataAlreadySent=""}compositionstart(){this._isComposing=!0,this._compositionPosition.start=this._textarea.value.length,this._compositionView.textContent="",this._dataAlreadySent="",this._compositionView.classList.add("active")}compositionupdate(e){this._compositionView.textContent=e.data,this.updateCompositionElements(),setTimeout((()=>{this._compositionPosition.end=this._textarea.value.length}),0)}compositionend(){this._finalizeComposition(!0)}keydown(e){if(this._isComposing||this._isSendingComposition){if(229===e.keyCode)return!1;if(16===e.keyCode||17===e.keyCode||18===e.keyCode)return!1;this._finalizeComposition(!1)}return 229!==e.keyCode||(this._handleAnyTextareaChanges(),!1)}_finalizeComposition(e){if(this._compositionView.classList.remove("active"),this._isComposing=!1,e){const e={start:this._compositionPosition.start,end:this._compositionPosition.end};this._isSendingComposition=!0,setTimeout((()=>{if(this._isSendingComposition){let t;this._isSendingComposition=!1,e.start+=this._dataAlreadySent.length,t=this._isComposing?this._textarea.value.substring(e.start,e.end):this._textarea.value.substring(e.start),t.length>0&&this._coreService.triggerDataEvent(t,!0)}}),0)}else{this._isSendingComposition=!1;const e=this._textarea.value.substring(this._compositionPosition.start,this._compositionPosition.end);this._coreService.triggerDataEvent(e,!0)}}_handleAnyTextareaChanges(){const e=this._textarea.value;setTimeout((()=>{if(!this._isComposing){const t=this._textarea.value,i=t.replace(e,"");this._dataAlreadySent=i,t.length>e.length?this._coreService.triggerDataEvent(i,!0):t.lengththis.updateCompositionElements(!0)),0)}}};t.CompositionHelper=h=s([r(2,o.IBufferService),r(3,o.IOptionsService),r(4,o.ICoreService),r(5,n.IRenderService)],h)},9806:(e,t)=>{function i(e,t,i){const s=i.getBoundingClientRect(),r=e.getComputedStyle(i),n=parseInt(r.getPropertyValue("padding-left")),o=parseInt(r.getPropertyValue("padding-top"));return[t.clientX-s.left-n,t.clientY-s.top-o]}Object.defineProperty(t,"__esModule",{value:!0}),t.getCoords=t.getCoordsRelativeToElement=void 0,t.getCoordsRelativeToElement=i,t.getCoords=function(e,t,s,r,n,o,a,h,c){if(!o)return;const l=i(e,t,s);return l?(l[0]=Math.ceil((l[0]+(c?a/2:0))/a),l[1]=Math.ceil(l[1]/h),l[0]=Math.min(Math.max(l[0],1),r+(c?1:0)),l[1]=Math.min(Math.max(l[1],1),n),l):void 0}},9504:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.moveToCellSequence=void 0;const s=i(2584);function r(e,t,i,s){const r=e-n(e,i),a=t-n(t,i),l=Math.abs(r-a)-function(e,t,i){let s=0;const r=e-n(e,i),a=t-n(t,i);for(let n=0;n=0&&et?"A":"B"}function a(e,t,i,s,r,n){let o=e,a=t,h="";for(;o!==i||a!==s;)o+=r?1:-1,r&&o>n.cols-1?(h+=n.buffer.translateBufferLineToString(a,!1,e,o),o=0,e=0,a++):!r&&o<0&&(h+=n.buffer.translateBufferLineToString(a,!1,0,e+1),o=n.cols-1,e=o,a--);return h+n.buffer.translateBufferLineToString(a,!1,e,o)}function h(e,t){const i=t?"O":"[";return s.C0.ESC+i+e}function c(e,t){e=Math.floor(e);let i="";for(let s=0;s0?s-n(s,o):t;const _=s,u=function(e,t,i,s,o,a){let h;return h=r(i,s,o,a).length>0?s-n(s,o):t,e=i&&he?"D":"C",c(Math.abs(o-e),h(d,s));d=l>t?"D":"C";const _=Math.abs(l-t);return c(function(e,t){return t.cols-e}(l>t?e:o,i)+(_-1)*i.cols+1+((l>t?o:e)-1),h(d,s))}},1296:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.DomRenderer=void 0;const n=i(3787),o=i(2550),a=i(2223),h=i(6171),c=i(6052),l=i(4725),d=i(8055),_=i(8460),u=i(844),f=i(2585),v="xterm-dom-renderer-owner-",p="xterm-rows",g="xterm-fg-",m="xterm-bg-",S="xterm-focus",C="xterm-selection";let b=1,w=t.DomRenderer=class extends u.Disposable{constructor(e,t,i,s,r,a,l,d,f,g,m,S,w){super(),this._terminal=e,this._document=t,this._element=i,this._screenElement=s,this._viewportElement=r,this._helperContainer=a,this._linkifier2=l,this._charSizeService=f,this._optionsService=g,this._bufferService=m,this._coreBrowserService=S,this._themeService=w,this._terminalClass=b++,this._rowElements=[],this._selectionRenderModel=(0,c.createSelectionRenderModel)(),this.onRequestRedraw=this.register(new _.EventEmitter).event,this._rowContainer=this._document.createElement("div"),this._rowContainer.classList.add(p),this._rowContainer.style.lineHeight="normal",this._rowContainer.setAttribute("aria-hidden","true"),this._refreshRowElements(this._bufferService.cols,this._bufferService.rows),this._selectionContainer=this._document.createElement("div"),this._selectionContainer.classList.add(C),this._selectionContainer.setAttribute("aria-hidden","true"),this.dimensions=(0,h.createRenderDimensions)(),this._updateDimensions(),this.register(this._optionsService.onOptionChange((()=>this._handleOptionsChanged()))),this.register(this._themeService.onChangeColors((e=>this._injectCss(e)))),this._injectCss(this._themeService.colors),this._rowFactory=d.createInstance(n.DomRendererRowFactory,document),this._element.classList.add(v+this._terminalClass),this._screenElement.appendChild(this._rowContainer),this._screenElement.appendChild(this._selectionContainer),this.register(this._linkifier2.onShowLinkUnderline((e=>this._handleLinkHover(e)))),this.register(this._linkifier2.onHideLinkUnderline((e=>this._handleLinkLeave(e)))),this.register((0,u.toDisposable)((()=>{this._element.classList.remove(v+this._terminalClass),this._rowContainer.remove(),this._selectionContainer.remove(),this._widthCache.dispose(),this._themeStyleElement.remove(),this._dimensionsStyleElement.remove()}))),this._widthCache=new o.WidthCache(this._document,this._helperContainer),this._widthCache.setFont(this._optionsService.rawOptions.fontFamily,this._optionsService.rawOptions.fontSize,this._optionsService.rawOptions.fontWeight,this._optionsService.rawOptions.fontWeightBold),this._setDefaultSpacing()}_updateDimensions(){const e=this._coreBrowserService.dpr;this.dimensions.device.char.width=this._charSizeService.width*e,this.dimensions.device.char.height=Math.ceil(this._charSizeService.height*e),this.dimensions.device.cell.width=this.dimensions.device.char.width+Math.round(this._optionsService.rawOptions.letterSpacing),this.dimensions.device.cell.height=Math.floor(this.dimensions.device.char.height*this._optionsService.rawOptions.lineHeight),this.dimensions.device.char.left=0,this.dimensions.device.char.top=0,this.dimensions.device.canvas.width=this.dimensions.device.cell.width*this._bufferService.cols,this.dimensions.device.canvas.height=this.dimensions.device.cell.height*this._bufferService.rows,this.dimensions.css.canvas.width=Math.round(this.dimensions.device.canvas.width/e),this.dimensions.css.canvas.height=Math.round(this.dimensions.device.canvas.height/e),this.dimensions.css.cell.width=this.dimensions.css.canvas.width/this._bufferService.cols,this.dimensions.css.cell.height=this.dimensions.css.canvas.height/this._bufferService.rows;for(const e of this._rowElements)e.style.width=`${this.dimensions.css.canvas.width}px`,e.style.height=`${this.dimensions.css.cell.height}px`,e.style.lineHeight=`${this.dimensions.css.cell.height}px`,e.style.overflow="hidden";this._dimensionsStyleElement||(this._dimensionsStyleElement=this._document.createElement("style"),this._screenElement.appendChild(this._dimensionsStyleElement));const t=`${this._terminalSelector} .${p} span { display: inline-block; height: 100%; vertical-align: top;}`;this._dimensionsStyleElement.textContent=t,this._selectionContainer.style.height=this._viewportElement.style.height,this._screenElement.style.width=`${this.dimensions.css.canvas.width}px`,this._screenElement.style.height=`${this.dimensions.css.canvas.height}px`}_injectCss(e){this._themeStyleElement||(this._themeStyleElement=this._document.createElement("style"),this._screenElement.appendChild(this._themeStyleElement));let t=`${this._terminalSelector} .${p} { color: ${e.foreground.css}; font-family: ${this._optionsService.rawOptions.fontFamily}; font-size: ${this._optionsService.rawOptions.fontSize}px; font-kerning: none; white-space: pre}`;t+=`${this._terminalSelector} .${p} .xterm-dim { color: ${d.color.multiplyOpacity(e.foreground,.5).css};}`,t+=`${this._terminalSelector} span:not(.xterm-bold) { font-weight: ${this._optionsService.rawOptions.fontWeight};}${this._terminalSelector} span.xterm-bold { font-weight: ${this._optionsService.rawOptions.fontWeightBold};}${this._terminalSelector} span.xterm-italic { font-style: italic;}`,t+="@keyframes blink_box_shadow_"+this._terminalClass+" { 50% { border-bottom-style: hidden; }}",t+="@keyframes blink_block_"+this._terminalClass+" { 0% {"+` background-color: ${e.cursor.css};`+` color: ${e.cursorAccent.css}; } 50% { background-color: inherit;`+` color: ${e.cursor.css}; }}`,t+=`${this._terminalSelector} .${p}.${S} .xterm-cursor.xterm-cursor-blink:not(.xterm-cursor-block) { animation: blink_box_shadow_`+this._terminalClass+" 1s step-end infinite;}"+`${this._terminalSelector} .${p}.${S} .xterm-cursor.xterm-cursor-blink.xterm-cursor-block { animation: blink_block_`+this._terminalClass+" 1s step-end infinite;}"+`${this._terminalSelector} .${p} .xterm-cursor.xterm-cursor-block {`+` background-color: ${e.cursor.css} !important;`+` color: ${e.cursorAccent.css} !important;}`+`${this._terminalSelector} .${p} .xterm-cursor.xterm-cursor-outline {`+` outline: 1px solid ${e.cursor.css}; outline-offset: -1px;}`+`${this._terminalSelector} .${p} .xterm-cursor.xterm-cursor-bar {`+` box-shadow: ${this._optionsService.rawOptions.cursorWidth}px 0 0 ${e.cursor.css} inset;}`+`${this._terminalSelector} .${p} .xterm-cursor.xterm-cursor-underline {`+` border-bottom: 1px ${e.cursor.css}; border-bottom-style: solid; height: calc(100% - 1px);}`,t+=`${this._terminalSelector} .${C} { position: absolute; top: 0; left: 0; z-index: 1; pointer-events: none;}${this._terminalSelector}.focus .${C} div { position: absolute; background-color: ${e.selectionBackgroundOpaque.css};}${this._terminalSelector} .${C} div { position: absolute; background-color: ${e.selectionInactiveBackgroundOpaque.css};}`;for(const[i,s]of e.ansi.entries())t+=`${this._terminalSelector} .${g}${i} { color: ${s.css}; }${this._terminalSelector} .${g}${i}.xterm-dim { color: ${d.color.multiplyOpacity(s,.5).css}; }${this._terminalSelector} .${m}${i} { background-color: ${s.css}; }`;t+=`${this._terminalSelector} .${g}${a.INVERTED_DEFAULT_COLOR} { color: ${d.color.opaque(e.background).css}; }${this._terminalSelector} .${g}${a.INVERTED_DEFAULT_COLOR}.xterm-dim { color: ${d.color.multiplyOpacity(d.color.opaque(e.background),.5).css}; }${this._terminalSelector} .${m}${a.INVERTED_DEFAULT_COLOR} { background-color: ${e.foreground.css}; }`,this._themeStyleElement.textContent=t}_setDefaultSpacing(){const e=this.dimensions.css.cell.width-this._widthCache.get("W",!1,!1);this._rowContainer.style.letterSpacing=`${e}px`,this._rowFactory.defaultSpacing=e}handleDevicePixelRatioChange(){this._updateDimensions(),this._widthCache.clear(),this._setDefaultSpacing()}_refreshRowElements(e,t){for(let e=this._rowElements.length;e<=t;e++){const e=this._document.createElement("div");this._rowContainer.appendChild(e),this._rowElements.push(e)}for(;this._rowElements.length>t;)this._rowContainer.removeChild(this._rowElements.pop())}handleResize(e,t){this._refreshRowElements(e,t),this._updateDimensions(),this.handleSelectionChanged(this._selectionRenderModel.selectionStart,this._selectionRenderModel.selectionEnd,this._selectionRenderModel.columnSelectMode)}handleCharSizeChanged(){this._updateDimensions(),this._widthCache.clear(),this._setDefaultSpacing()}handleBlur(){this._rowContainer.classList.remove(S),this.renderRows(0,this._bufferService.rows-1)}handleFocus(){this._rowContainer.classList.add(S),this.renderRows(this._bufferService.buffer.y,this._bufferService.buffer.y)}handleSelectionChanged(e,t,i){if(this._selectionContainer.replaceChildren(),this._rowFactory.handleSelectionChanged(e,t,i),this.renderRows(0,this._bufferService.rows-1),!e||!t)return;this._selectionRenderModel.update(this._terminal,e,t,i);const s=this._selectionRenderModel.viewportStartRow,r=this._selectionRenderModel.viewportEndRow,n=this._selectionRenderModel.viewportCappedStartRow,o=this._selectionRenderModel.viewportCappedEndRow;if(n>=this._bufferService.rows||o<0)return;const a=this._document.createDocumentFragment();if(i){const i=e[0]>t[0];a.appendChild(this._createSelectionElement(n,i?t[0]:e[0],i?e[0]:t[0],o-n+1))}else{const i=s===n?e[0]:0,h=n===r?t[0]:this._bufferService.cols;a.appendChild(this._createSelectionElement(n,i,h));const c=o-n-1;if(a.appendChild(this._createSelectionElement(n+1,0,this._bufferService.cols,c)),n!==o){const e=r===o?t[0]:this._bufferService.cols;a.appendChild(this._createSelectionElement(o,0,e))}}this._selectionContainer.appendChild(a)}_createSelectionElement(e,t,i,s=1){const r=this._document.createElement("div"),n=t*this.dimensions.css.cell.width;let o=this.dimensions.css.cell.width*(i-t);return n+o>this.dimensions.css.canvas.width&&(o=this.dimensions.css.canvas.width-n),r.style.height=s*this.dimensions.css.cell.height+"px",r.style.top=e*this.dimensions.css.cell.height+"px",r.style.left=`${n}px`,r.style.width=`${o}px`,r}handleCursorMove(){}_handleOptionsChanged(){this._updateDimensions(),this._injectCss(this._themeService.colors),this._widthCache.setFont(this._optionsService.rawOptions.fontFamily,this._optionsService.rawOptions.fontSize,this._optionsService.rawOptions.fontWeight,this._optionsService.rawOptions.fontWeightBold),this._setDefaultSpacing()}clear(){for(const e of this._rowElements)e.replaceChildren()}renderRows(e,t){const i=this._bufferService.buffer,s=i.ybase+i.y,r=Math.min(i.x,this._bufferService.cols-1),n=this._optionsService.rawOptions.cursorBlink,o=this._optionsService.rawOptions.cursorStyle,a=this._optionsService.rawOptions.cursorInactiveStyle;for(let h=e;h<=t;h++){const e=h+i.ydisp,t=this._rowElements[h],c=i.lines.get(e);if(!t||!c)break;t.replaceChildren(...this._rowFactory.createRow(c,e,e===s,o,a,r,n,this.dimensions.css.cell.width,this._widthCache,-1,-1))}}get _terminalSelector(){return`.${v}${this._terminalClass}`}_handleLinkHover(e){this._setCellUnderline(e.x1,e.x2,e.y1,e.y2,e.cols,!0)}_handleLinkLeave(e){this._setCellUnderline(e.x1,e.x2,e.y1,e.y2,e.cols,!1)}_setCellUnderline(e,t,i,s,r,n){i<0&&(e=0),s<0&&(t=0);const o=this._bufferService.rows-1;i=Math.max(Math.min(i,o),0),s=Math.max(Math.min(s,o),0),r=Math.min(r,this._bufferService.cols);const a=this._bufferService.buffer,h=a.ybase+a.y,c=Math.min(a.x,r-1),l=this._optionsService.rawOptions.cursorBlink,d=this._optionsService.rawOptions.cursorStyle,_=this._optionsService.rawOptions.cursorInactiveStyle;for(let o=i;o<=s;++o){const u=o+a.ydisp,f=this._rowElements[o],v=a.lines.get(u);if(!f||!v)break;f.replaceChildren(...this._rowFactory.createRow(v,u,u===h,d,_,c,l,this.dimensions.css.cell.width,this._widthCache,n?o===i?e:0:-1,n?(o===s?t:r)-1:-1))}}};t.DomRenderer=w=s([r(7,f.IInstantiationService),r(8,l.ICharSizeService),r(9,f.IOptionsService),r(10,f.IBufferService),r(11,l.ICoreBrowserService),r(12,l.IThemeService)],w)},3787:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.DomRendererRowFactory=void 0;const n=i(2223),o=i(643),a=i(511),h=i(2585),c=i(8055),l=i(4725),d=i(4269),_=i(6171),u=i(3734);let f=t.DomRendererRowFactory=class{constructor(e,t,i,s,r,n,o){this._document=e,this._characterJoinerService=t,this._optionsService=i,this._coreBrowserService=s,this._coreService=r,this._decorationService=n,this._themeService=o,this._workCell=new a.CellData,this._columnSelectMode=!1,this.defaultSpacing=0}handleSelectionChanged(e,t,i){this._selectionStart=e,this._selectionEnd=t,this._columnSelectMode=i}createRow(e,t,i,s,r,a,h,l,_,f,p){const g=[],m=this._characterJoinerService.getJoinedCharacters(t),S=this._themeService.colors;let C,b=e.getNoBgTrimmedLength();i&&b0&&M===m[0][0]){O=!0;const t=m.shift();I=new d.JoinedCellData(this._workCell,e.translateToString(!0,t[0],t[1]),t[1]-t[0]),P=t[1]-1,b=I.getWidth()}const H=this._isCellInSelection(M,t),F=i&&M===a,W=T&&M>=f&&M<=p;let U=!1;this._decorationService.forEachDecorationAtCell(M,t,void 0,(e=>{U=!0}));let N=I.getChars()||o.WHITESPACE_CELL_CHAR;if(" "===N&&(I.isUnderline()||I.isOverline())&&(N=" "),A=b*l-_.get(N,I.isBold(),I.isItalic()),C){if(w&&(H&&x||!H&&!x&&I.bg===E)&&(H&&x&&S.selectionForeground||I.fg===k)&&I.extended.ext===L&&W===D&&A===R&&!F&&!O&&!U){I.isInvisible()?y+=o.WHITESPACE_CELL_CHAR:y+=N,w++;continue}w&&(C.textContent=y),C=this._document.createElement("span"),w=0,y=""}else C=this._document.createElement("span");if(E=I.bg,k=I.fg,L=I.extended.ext,D=W,R=A,x=H,O&&a>=M&&a<=P&&(a=M),!this._coreService.isCursorHidden&&F&&this._coreService.isCursorInitialized)if(B.push("xterm-cursor"),this._coreBrowserService.isFocused)h&&B.push("xterm-cursor-blink"),B.push("bar"===s?"xterm-cursor-bar":"underline"===s?"xterm-cursor-underline":"xterm-cursor-block");else if(r)switch(r){case"outline":B.push("xterm-cursor-outline");break;case"block":B.push("xterm-cursor-block");break;case"bar":B.push("xterm-cursor-bar");break;case"underline":B.push("xterm-cursor-underline")}if(I.isBold()&&B.push("xterm-bold"),I.isItalic()&&B.push("xterm-italic"),I.isDim()&&B.push("xterm-dim"),y=I.isInvisible()?o.WHITESPACE_CELL_CHAR:I.getChars()||o.WHITESPACE_CELL_CHAR,I.isUnderline()&&(B.push(`xterm-underline-${I.extended.underlineStyle}`)," "===y&&(y=" "),!I.isUnderlineColorDefault()))if(I.isUnderlineColorRGB())C.style.textDecorationColor=`rgb(${u.AttributeData.toColorRGB(I.getUnderlineColor()).join(",")})`;else{let e=I.getUnderlineColor();this._optionsService.rawOptions.drawBoldTextInBrightColors&&I.isBold()&&e<8&&(e+=8),C.style.textDecorationColor=S.ansi[e].css}I.isOverline()&&(B.push("xterm-overline")," "===y&&(y=" ")),I.isStrikethrough()&&B.push("xterm-strikethrough"),W&&(C.style.textDecoration="underline");let $=I.getFgColor(),j=I.getFgColorMode(),z=I.getBgColor(),K=I.getBgColorMode();const q=!!I.isInverse();if(q){const e=$;$=z,z=e;const t=j;j=K,K=t}let V,G,X,J=!1;switch(this._decorationService.forEachDecorationAtCell(M,t,void 0,(e=>{"top"!==e.options.layer&&J||(e.backgroundColorRGB&&(K=50331648,z=e.backgroundColorRGB.rgba>>8&16777215,V=e.backgroundColorRGB),e.foregroundColorRGB&&(j=50331648,$=e.foregroundColorRGB.rgba>>8&16777215,G=e.foregroundColorRGB),J="top"===e.options.layer)})),!J&&H&&(V=this._coreBrowserService.isFocused?S.selectionBackgroundOpaque:S.selectionInactiveBackgroundOpaque,z=V.rgba>>8&16777215,K=50331648,J=!0,S.selectionForeground&&(j=50331648,$=S.selectionForeground.rgba>>8&16777215,G=S.selectionForeground)),J&&B.push("xterm-decoration-top"),K){case 16777216:case 33554432:X=S.ansi[z],B.push(`xterm-bg-${z}`);break;case 50331648:X=c.channels.toColor(z>>16,z>>8&255,255&z),this._addStyle(C,`background-color:#${v((z>>>0).toString(16),"0",6)}`);break;default:q?(X=S.foreground,B.push(`xterm-bg-${n.INVERTED_DEFAULT_COLOR}`)):X=S.background}switch(V||I.isDim()&&(V=c.color.multiplyOpacity(X,.5)),j){case 16777216:case 33554432:I.isBold()&&$<8&&this._optionsService.rawOptions.drawBoldTextInBrightColors&&($+=8),this._applyMinimumContrast(C,X,S.ansi[$],I,V,void 0)||B.push(`xterm-fg-${$}`);break;case 50331648:const e=c.channels.toColor($>>16&255,$>>8&255,255&$);this._applyMinimumContrast(C,X,e,I,V,G)||this._addStyle(C,`color:#${v($.toString(16),"0",6)}`);break;default:this._applyMinimumContrast(C,X,S.foreground,I,V,G)||q&&B.push(`xterm-fg-${n.INVERTED_DEFAULT_COLOR}`)}B.length&&(C.className=B.join(" "),B.length=0),F||O||U?C.textContent=y:w++,A!==this.defaultSpacing&&(C.style.letterSpacing=`${A}px`),g.push(C),M=P}return C&&w&&(C.textContent=y),g}_applyMinimumContrast(e,t,i,s,r,n){if(1===this._optionsService.rawOptions.minimumContrastRatio||(0,_.treatGlyphAsBackgroundColor)(s.getCode()))return!1;const o=this._getContrastCache(s);let a;if(r||n||(a=o.getColor(t.rgba,i.rgba)),void 0===a){const e=this._optionsService.rawOptions.minimumContrastRatio/(s.isDim()?2:1);a=c.color.ensureContrastRatio(r||t,n||i,e),o.setColor((r||t).rgba,(n||i).rgba,a??null)}return!!a&&(this._addStyle(e,`color:${a.css}`),!0)}_getContrastCache(e){return e.isDim()?this._themeService.colors.halfContrastCache:this._themeService.colors.contrastCache}_addStyle(e,t){e.setAttribute("style",`${e.getAttribute("style")||""}${t};`)}_isCellInSelection(e,t){const i=this._selectionStart,s=this._selectionEnd;return!(!i||!s)&&(this._columnSelectMode?i[0]<=s[0]?e>=i[0]&&t>=i[1]&&e=i[1]&&e>=s[0]&&t<=s[1]:t>i[1]&&t=i[0]&&e=i[0])}};function v(e,t,i){for(;e.length{Object.defineProperty(t,"__esModule",{value:!0}),t.WidthCache=void 0,t.WidthCache=class{constructor(e,t){this._flat=new Float32Array(256),this._font="",this._fontSize=0,this._weight="normal",this._weightBold="bold",this._measureElements=[],this._container=e.createElement("div"),this._container.classList.add("xterm-width-cache-measure-container"),this._container.setAttribute("aria-hidden","true"),this._container.style.whiteSpace="pre",this._container.style.fontKerning="none";const i=e.createElement("span");i.classList.add("xterm-char-measure-element");const s=e.createElement("span");s.classList.add("xterm-char-measure-element"),s.style.fontWeight="bold";const r=e.createElement("span");r.classList.add("xterm-char-measure-element"),r.style.fontStyle="italic";const n=e.createElement("span");n.classList.add("xterm-char-measure-element"),n.style.fontWeight="bold",n.style.fontStyle="italic",this._measureElements=[i,s,r,n],this._container.appendChild(i),this._container.appendChild(s),this._container.appendChild(r),this._container.appendChild(n),t.appendChild(this._container),this.clear()}dispose(){this._container.remove(),this._measureElements.length=0,this._holey=void 0}clear(){this._flat.fill(-9999),this._holey=new Map}setFont(e,t,i,s){e===this._font&&t===this._fontSize&&i===this._weight&&s===this._weightBold||(this._font=e,this._fontSize=t,this._weight=i,this._weightBold=s,this._container.style.fontFamily=this._font,this._container.style.fontSize=`${this._fontSize}px`,this._measureElements[0].style.fontWeight=`${i}`,this._measureElements[1].style.fontWeight=`${s}`,this._measureElements[2].style.fontWeight=`${i}`,this._measureElements[3].style.fontWeight=`${s}`,this.clear())}get(e,t,i){let s=0;if(!t&&!i&&1===e.length&&(s=e.charCodeAt(0))<256){if(-9999!==this._flat[s])return this._flat[s];const t=this._measure(e,0);return t>0&&(this._flat[s]=t),t}let r=e;t&&(r+="B"),i&&(r+="I");let n=this._holey.get(r);if(void 0===n){let s=0;t&&(s|=1),i&&(s|=2),n=this._measure(e,s),n>0&&this._holey.set(r,n)}return n}_measure(e,t){const i=this._measureElements[t];return i.textContent=e.repeat(32),i.offsetWidth/32}}},2223:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.TEXT_BASELINE=t.DIM_OPACITY=t.INVERTED_DEFAULT_COLOR=void 0;const s=i(6114);t.INVERTED_DEFAULT_COLOR=257,t.DIM_OPACITY=.5,t.TEXT_BASELINE=s.isFirefox||s.isLegacyEdge?"bottom":"ideographic"},6171:(e,t)=>{function i(e){return 57508<=e&&e<=57558}Object.defineProperty(t,"__esModule",{value:!0}),t.computeNextVariantOffset=t.createRenderDimensions=t.treatGlyphAsBackgroundColor=t.isRestrictedPowerlineGlyph=t.isPowerlineGlyph=t.throwIfFalsy=void 0,t.throwIfFalsy=function(e){if(!e)throw new Error("value must not be falsy");return e},t.isPowerlineGlyph=i,t.isRestrictedPowerlineGlyph=function(e){return 57520<=e&&e<=57527},t.treatGlyphAsBackgroundColor=function(e){return i(e)||function(e){return 9472<=e&&e<=9631}(e)},t.createRenderDimensions=function(){return{css:{canvas:{width:0,height:0},cell:{width:0,height:0}},device:{canvas:{width:0,height:0},cell:{width:0,height:0},char:{width:0,height:0,left:0,top:0}}}},t.computeNextVariantOffset=function(e,t,i=0){return(e-(2*Math.round(t)-i))%(2*Math.round(t))}},6052:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.createSelectionRenderModel=void 0;class i{constructor(){this.clear()}clear(){this.hasSelection=!1,this.columnSelectMode=!1,this.viewportStartRow=0,this.viewportEndRow=0,this.viewportCappedStartRow=0,this.viewportCappedEndRow=0,this.startCol=0,this.endCol=0,this.selectionStart=void 0,this.selectionEnd=void 0}update(e,t,i,s=!1){if(this.selectionStart=t,this.selectionEnd=i,!t||!i||t[0]===i[0]&&t[1]===i[1])return void this.clear();const r=e.buffers.active.ydisp,n=t[1]-r,o=i[1]-r,a=Math.max(n,0),h=Math.min(o,e.rows-1);a>=e.rows||h<0?this.clear():(this.hasSelection=!0,this.columnSelectMode=s,this.viewportStartRow=n,this.viewportEndRow=o,this.viewportCappedStartRow=a,this.viewportCappedEndRow=h,this.startCol=t[0],this.endCol=i[0])}isCellSelected(e,t,i){return!!this.hasSelection&&(i-=e.buffer.active.viewportY,this.columnSelectMode?this.startCol<=this.endCol?t>=this.startCol&&i>=this.viewportCappedStartRow&&t=this.viewportCappedStartRow&&t>=this.endCol&&i<=this.viewportCappedEndRow:i>this.viewportStartRow&&i=this.startCol&&t=this.startCol)}}t.createSelectionRenderModel=function(){return new i}},456:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.SelectionModel=void 0,t.SelectionModel=class{constructor(e){this._bufferService=e,this.isSelectAllActive=!1,this.selectionStartLength=0}clearSelection(){this.selectionStart=void 0,this.selectionEnd=void 0,this.isSelectAllActive=!1,this.selectionStartLength=0}get finalSelectionStart(){return this.isSelectAllActive?[0,0]:this.selectionEnd&&this.selectionStart&&this.areSelectionValuesReversed()?this.selectionEnd:this.selectionStart}get finalSelectionEnd(){if(this.isSelectAllActive)return[this._bufferService.cols,this._bufferService.buffer.ybase+this._bufferService.rows-1];if(this.selectionStart){if(!this.selectionEnd||this.areSelectionValuesReversed()){const e=this.selectionStart[0]+this.selectionStartLength;return e>this._bufferService.cols?e%this._bufferService.cols==0?[this._bufferService.cols,this.selectionStart[1]+Math.floor(e/this._bufferService.cols)-1]:[e%this._bufferService.cols,this.selectionStart[1]+Math.floor(e/this._bufferService.cols)]:[e,this.selectionStart[1]]}if(this.selectionStartLength&&this.selectionEnd[1]===this.selectionStart[1]){const e=this.selectionStart[0]+this.selectionStartLength;return e>this._bufferService.cols?[e%this._bufferService.cols,this.selectionStart[1]+Math.floor(e/this._bufferService.cols)]:[Math.max(e,this.selectionEnd[0]),this.selectionEnd[1]]}return this.selectionEnd}}areSelectionValuesReversed(){const e=this.selectionStart,t=this.selectionEnd;return!(!e||!t)&&(e[1]>t[1]||e[1]===t[1]&&e[0]>t[0])}handleTrim(e){return this.selectionStart&&(this.selectionStart[1]-=e),this.selectionEnd&&(this.selectionEnd[1]-=e),this.selectionEnd&&this.selectionEnd[1]<0?(this.clearSelection(),!0):(this.selectionStart&&this.selectionStart[1]<0&&(this.selectionStart[1]=0),!1)}}},428:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CharSizeService=void 0;const n=i(2585),o=i(8460),a=i(844);let h=t.CharSizeService=class extends a.Disposable{get hasValidSize(){return this.width>0&&this.height>0}constructor(e,t,i){super(),this._optionsService=i,this.width=0,this.height=0,this._onCharSizeChange=this.register(new o.EventEmitter),this.onCharSizeChange=this._onCharSizeChange.event;try{this._measureStrategy=this.register(new d(this._optionsService))}catch{this._measureStrategy=this.register(new l(e,t,this._optionsService))}this.register(this._optionsService.onMultipleOptionChange(["fontFamily","fontSize"],(()=>this.measure())))}measure(){const e=this._measureStrategy.measure();e.width===this.width&&e.height===this.height||(this.width=e.width,this.height=e.height,this._onCharSizeChange.fire())}};t.CharSizeService=h=s([r(2,n.IOptionsService)],h);class c extends a.Disposable{constructor(){super(...arguments),this._result={width:0,height:0}}_validateAndSet(e,t){void 0!==e&&e>0&&void 0!==t&&t>0&&(this._result.width=e,this._result.height=t)}}class l extends c{constructor(e,t,i){super(),this._document=e,this._parentElement=t,this._optionsService=i,this._measureElement=this._document.createElement("span"),this._measureElement.classList.add("xterm-char-measure-element"),this._measureElement.textContent="W".repeat(32),this._measureElement.setAttribute("aria-hidden","true"),this._measureElement.style.whiteSpace="pre",this._measureElement.style.fontKerning="none",this._parentElement.appendChild(this._measureElement)}measure(){return this._measureElement.style.fontFamily=this._optionsService.rawOptions.fontFamily,this._measureElement.style.fontSize=`${this._optionsService.rawOptions.fontSize}px`,this._validateAndSet(Number(this._measureElement.offsetWidth)/32,Number(this._measureElement.offsetHeight)),this._result}}class d extends c{constructor(e){super(),this._optionsService=e,this._canvas=new OffscreenCanvas(100,100),this._ctx=this._canvas.getContext("2d");const t=this._ctx.measureText("W");if(!("width"in t&&"fontBoundingBoxAscent"in t&&"fontBoundingBoxDescent"in t))throw new Error("Required font metrics not supported")}measure(){this._ctx.font=`${this._optionsService.rawOptions.fontSize}px ${this._optionsService.rawOptions.fontFamily}`;const e=this._ctx.measureText("W");return this._validateAndSet(e.width,e.fontBoundingBoxAscent+e.fontBoundingBoxDescent),this._result}}},4269:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CharacterJoinerService=t.JoinedCellData=void 0;const n=i(3734),o=i(643),a=i(511),h=i(2585);class c extends n.AttributeData{constructor(e,t,i){super(),this.content=0,this.combinedData="",this.fg=e.fg,this.bg=e.bg,this.combinedData=t,this._width=i}isCombined(){return 2097152}getWidth(){return this._width}getChars(){return this.combinedData}getCode(){return 2097151}setFromCharData(e){throw new Error("not implemented")}getAsCharData(){return[this.fg,this.getChars(),this.getWidth(),this.getCode()]}}t.JoinedCellData=c;let l=t.CharacterJoinerService=class e{constructor(e){this._bufferService=e,this._characterJoiners=[],this._nextCharacterJoinerId=0,this._workCell=new a.CellData}register(e){const t={id:this._nextCharacterJoinerId++,handler:e};return this._characterJoiners.push(t),t.id}deregister(e){for(let t=0;t1){const e=this._getJoinedRanges(s,a,n,t,r);for(let t=0;t1){const e=this._getJoinedRanges(s,a,n,t,r);for(let t=0;t{Object.defineProperty(t,"__esModule",{value:!0}),t.CoreBrowserService=void 0;const s=i(844),r=i(8460),n=i(3656);class o extends s.Disposable{constructor(e,t,i){super(),this._textarea=e,this._window=t,this.mainDocument=i,this._isFocused=!1,this._cachedIsFocused=void 0,this._screenDprMonitor=new a(this._window),this._onDprChange=this.register(new r.EventEmitter),this.onDprChange=this._onDprChange.event,this._onWindowChange=this.register(new r.EventEmitter),this.onWindowChange=this._onWindowChange.event,this.register(this.onWindowChange((e=>this._screenDprMonitor.setWindow(e)))),this.register((0,r.forwardEvent)(this._screenDprMonitor.onDprChange,this._onDprChange)),this._textarea.addEventListener("focus",(()=>this._isFocused=!0)),this._textarea.addEventListener("blur",(()=>this._isFocused=!1))}get window(){return this._window}set window(e){this._window!==e&&(this._window=e,this._onWindowChange.fire(this._window))}get dpr(){return this.window.devicePixelRatio}get isFocused(){return void 0===this._cachedIsFocused&&(this._cachedIsFocused=this._isFocused&&this._textarea.ownerDocument.hasFocus(),queueMicrotask((()=>this._cachedIsFocused=void 0))),this._cachedIsFocused}}t.CoreBrowserService=o;class a extends s.Disposable{constructor(e){super(),this._parentWindow=e,this._windowResizeListener=this.register(new s.MutableDisposable),this._onDprChange=this.register(new r.EventEmitter),this.onDprChange=this._onDprChange.event,this._outerListener=()=>this._setDprAndFireIfDiffers(),this._currentDevicePixelRatio=this._parentWindow.devicePixelRatio,this._updateDpr(),this._setWindowResizeListener(),this.register((0,s.toDisposable)((()=>this.clearListener())))}setWindow(e){this._parentWindow=e,this._setWindowResizeListener(),this._setDprAndFireIfDiffers()}_setWindowResizeListener(){this._windowResizeListener.value=(0,n.addDisposableDomListener)(this._parentWindow,"resize",(()=>this._setDprAndFireIfDiffers()))}_setDprAndFireIfDiffers(){this._parentWindow.devicePixelRatio!==this._currentDevicePixelRatio&&this._onDprChange.fire(this._parentWindow.devicePixelRatio),this._updateDpr()}_updateDpr(){this._outerListener&&(this._resolutionMediaMatchList?.removeListener(this._outerListener),this._currentDevicePixelRatio=this._parentWindow.devicePixelRatio,this._resolutionMediaMatchList=this._parentWindow.matchMedia(`screen and (resolution: ${this._parentWindow.devicePixelRatio}dppx)`),this._resolutionMediaMatchList.addListener(this._outerListener))}clearListener(){this._resolutionMediaMatchList&&this._outerListener&&(this._resolutionMediaMatchList.removeListener(this._outerListener),this._resolutionMediaMatchList=void 0,this._outerListener=void 0)}}},779:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.LinkProviderService=void 0;const s=i(844);class r extends s.Disposable{constructor(){super(),this.linkProviders=[],this.register((0,s.toDisposable)((()=>this.linkProviders.length=0)))}registerLinkProvider(e){return this.linkProviders.push(e),{dispose:()=>{const t=this.linkProviders.indexOf(e);-1!==t&&this.linkProviders.splice(t,1)}}}}t.LinkProviderService=r},8934:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.MouseService=void 0;const n=i(4725),o=i(9806);let a=t.MouseService=class{constructor(e,t){this._renderService=e,this._charSizeService=t}getCoords(e,t,i,s,r){return(0,o.getCoords)(window,e,t,i,s,this._charSizeService.hasValidSize,this._renderService.dimensions.css.cell.width,this._renderService.dimensions.css.cell.height,r)}getMouseReportCoords(e,t){const i=(0,o.getCoordsRelativeToElement)(window,e,t);if(this._charSizeService.hasValidSize)return i[0]=Math.min(Math.max(i[0],0),this._renderService.dimensions.css.canvas.width-1),i[1]=Math.min(Math.max(i[1],0),this._renderService.dimensions.css.canvas.height-1),{col:Math.floor(i[0]/this._renderService.dimensions.css.cell.width),row:Math.floor(i[1]/this._renderService.dimensions.css.cell.height),x:Math.floor(i[0]),y:Math.floor(i[1])}}};t.MouseService=a=s([r(0,n.IRenderService),r(1,n.ICharSizeService)],a)},3230:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.RenderService=void 0;const n=i(6193),o=i(4725),a=i(8460),h=i(844),c=i(7226),l=i(2585);let d=t.RenderService=class extends h.Disposable{get dimensions(){return this._renderer.value.dimensions}constructor(e,t,i,s,r,o,l,d){super(),this._rowCount=e,this._charSizeService=s,this._renderer=this.register(new h.MutableDisposable),this._pausedResizeTask=new c.DebouncedIdleTask,this._observerDisposable=this.register(new h.MutableDisposable),this._isPaused=!1,this._needsFullRefresh=!1,this._isNextRenderRedrawOnly=!0,this._needsSelectionRefresh=!1,this._canvasWidth=0,this._canvasHeight=0,this._selectionState={start:void 0,end:void 0,columnSelectMode:!1},this._onDimensionsChange=this.register(new a.EventEmitter),this.onDimensionsChange=this._onDimensionsChange.event,this._onRenderedViewportChange=this.register(new a.EventEmitter),this.onRenderedViewportChange=this._onRenderedViewportChange.event,this._onRender=this.register(new a.EventEmitter),this.onRender=this._onRender.event,this._onRefreshRequest=this.register(new a.EventEmitter),this.onRefreshRequest=this._onRefreshRequest.event,this._renderDebouncer=new n.RenderDebouncer(((e,t)=>this._renderRows(e,t)),l),this.register(this._renderDebouncer),this.register(l.onDprChange((()=>this.handleDevicePixelRatioChange()))),this.register(o.onResize((()=>this._fullRefresh()))),this.register(o.buffers.onBufferActivate((()=>this._renderer.value?.clear()))),this.register(i.onOptionChange((()=>this._handleOptionsChanged()))),this.register(this._charSizeService.onCharSizeChange((()=>this.handleCharSizeChanged()))),this.register(r.onDecorationRegistered((()=>this._fullRefresh()))),this.register(r.onDecorationRemoved((()=>this._fullRefresh()))),this.register(i.onMultipleOptionChange(["customGlyphs","drawBoldTextInBrightColors","letterSpacing","lineHeight","fontFamily","fontSize","fontWeight","fontWeightBold","minimumContrastRatio"],(()=>{this.clear(),this.handleResize(o.cols,o.rows),this._fullRefresh()}))),this.register(i.onMultipleOptionChange(["cursorBlink","cursorStyle"],(()=>this.refreshRows(o.buffer.y,o.buffer.y,!0)))),this.register(d.onChangeColors((()=>this._fullRefresh()))),this._registerIntersectionObserver(l.window,t),this.register(l.onWindowChange((e=>this._registerIntersectionObserver(e,t))))}_registerIntersectionObserver(e,t){if("IntersectionObserver"in e){const i=new e.IntersectionObserver((e=>this._handleIntersectionChange(e[e.length-1])),{threshold:0});i.observe(t),this._observerDisposable.value=(0,h.toDisposable)((()=>i.disconnect()))}}_handleIntersectionChange(e){this._isPaused=void 0===e.isIntersecting?0===e.intersectionRatio:!e.isIntersecting,this._isPaused||this._charSizeService.hasValidSize||this._charSizeService.measure(),!this._isPaused&&this._needsFullRefresh&&(this._pausedResizeTask.flush(),this.refreshRows(0,this._rowCount-1),this._needsFullRefresh=!1)}refreshRows(e,t,i=!1){this._isPaused?this._needsFullRefresh=!0:(i||(this._isNextRenderRedrawOnly=!1),this._renderDebouncer.refresh(e,t,this._rowCount))}_renderRows(e,t){this._renderer.value&&(e=Math.min(e,this._rowCount-1),t=Math.min(t,this._rowCount-1),this._renderer.value.renderRows(e,t),this._needsSelectionRefresh&&(this._renderer.value.handleSelectionChanged(this._selectionState.start,this._selectionState.end,this._selectionState.columnSelectMode),this._needsSelectionRefresh=!1),this._isNextRenderRedrawOnly||this._onRenderedViewportChange.fire({start:e,end:t}),this._onRender.fire({start:e,end:t}),this._isNextRenderRedrawOnly=!0)}resize(e,t){this._rowCount=t,this._fireOnCanvasResize()}_handleOptionsChanged(){this._renderer.value&&(this.refreshRows(0,this._rowCount-1),this._fireOnCanvasResize())}_fireOnCanvasResize(){this._renderer.value&&(this._renderer.value.dimensions.css.canvas.width===this._canvasWidth&&this._renderer.value.dimensions.css.canvas.height===this._canvasHeight||this._onDimensionsChange.fire(this._renderer.value.dimensions))}hasRenderer(){return!!this._renderer.value}setRenderer(e){this._renderer.value=e,this._renderer.value&&(this._renderer.value.onRequestRedraw((e=>this.refreshRows(e.start,e.end,!0))),this._needsSelectionRefresh=!0,this._fullRefresh())}addRefreshCallback(e){return this._renderDebouncer.addRefreshCallback(e)}_fullRefresh(){this._isPaused?this._needsFullRefresh=!0:this.refreshRows(0,this._rowCount-1)}clearTextureAtlas(){this._renderer.value&&(this._renderer.value.clearTextureAtlas?.(),this._fullRefresh())}handleDevicePixelRatioChange(){this._charSizeService.measure(),this._renderer.value&&(this._renderer.value.handleDevicePixelRatioChange(),this.refreshRows(0,this._rowCount-1))}handleResize(e,t){this._renderer.value&&(this._isPaused?this._pausedResizeTask.set((()=>this._renderer.value?.handleResize(e,t))):this._renderer.value.handleResize(e,t),this._fullRefresh())}handleCharSizeChanged(){this._renderer.value?.handleCharSizeChanged()}handleBlur(){this._renderer.value?.handleBlur()}handleFocus(){this._renderer.value?.handleFocus()}handleSelectionChanged(e,t,i){this._selectionState.start=e,this._selectionState.end=t,this._selectionState.columnSelectMode=i,this._renderer.value?.handleSelectionChanged(e,t,i)}handleCursorMove(){this._renderer.value?.handleCursorMove()}clear(){this._renderer.value?.clear()}};t.RenderService=d=s([r(2,l.IOptionsService),r(3,o.ICharSizeService),r(4,l.IDecorationService),r(5,l.IBufferService),r(6,o.ICoreBrowserService),r(7,o.IThemeService)],d)},9312:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.SelectionService=void 0;const n=i(9806),o=i(9504),a=i(456),h=i(4725),c=i(8460),l=i(844),d=i(6114),_=i(4841),u=i(511),f=i(2585),v=String.fromCharCode(160),p=new RegExp(v,"g");let g=t.SelectionService=class extends l.Disposable{constructor(e,t,i,s,r,n,o,h,d){super(),this._element=e,this._screenElement=t,this._linkifier=i,this._bufferService=s,this._coreService=r,this._mouseService=n,this._optionsService=o,this._renderService=h,this._coreBrowserService=d,this._dragScrollAmount=0,this._enabled=!0,this._workCell=new u.CellData,this._mouseDownTimeStamp=0,this._oldHasSelection=!1,this._oldSelectionStart=void 0,this._oldSelectionEnd=void 0,this._onLinuxMouseSelection=this.register(new c.EventEmitter),this.onLinuxMouseSelection=this._onLinuxMouseSelection.event,this._onRedrawRequest=this.register(new c.EventEmitter),this.onRequestRedraw=this._onRedrawRequest.event,this._onSelectionChange=this.register(new c.EventEmitter),this.onSelectionChange=this._onSelectionChange.event,this._onRequestScrollLines=this.register(new c.EventEmitter),this.onRequestScrollLines=this._onRequestScrollLines.event,this._mouseMoveListener=e=>this._handleMouseMove(e),this._mouseUpListener=e=>this._handleMouseUp(e),this._coreService.onUserInput((()=>{this.hasSelection&&this.clearSelection()})),this._trimListener=this._bufferService.buffer.lines.onTrim((e=>this._handleTrim(e))),this.register(this._bufferService.buffers.onBufferActivate((e=>this._handleBufferActivate(e)))),this.enable(),this._model=new a.SelectionModel(this._bufferService),this._activeSelectionMode=0,this.register((0,l.toDisposable)((()=>{this._removeMouseDownListeners()})))}reset(){this.clearSelection()}disable(){this.clearSelection(),this._enabled=!1}enable(){this._enabled=!0}get selectionStart(){return this._model.finalSelectionStart}get selectionEnd(){return this._model.finalSelectionEnd}get hasSelection(){const e=this._model.finalSelectionStart,t=this._model.finalSelectionEnd;return!(!e||!t||e[0]===t[0]&&e[1]===t[1])}get selectionText(){const e=this._model.finalSelectionStart,t=this._model.finalSelectionEnd;if(!e||!t)return"";const i=this._bufferService.buffer,s=[];if(3===this._activeSelectionMode){if(e[0]===t[0])return"";const r=e[0]e.replace(p," "))).join(d.isWindows?"\r\n":"\n")}clearSelection(){this._model.clearSelection(),this._removeMouseDownListeners(),this.refresh(),this._onSelectionChange.fire()}refresh(e){this._refreshAnimationFrame||(this._refreshAnimationFrame=this._coreBrowserService.window.requestAnimationFrame((()=>this._refresh()))),d.isLinux&&e&&this.selectionText.length&&this._onLinuxMouseSelection.fire(this.selectionText)}_refresh(){this._refreshAnimationFrame=void 0,this._onRedrawRequest.fire({start:this._model.finalSelectionStart,end:this._model.finalSelectionEnd,columnSelectMode:3===this._activeSelectionMode})}_isClickInSelection(e){const t=this._getMouseBufferCoords(e),i=this._model.finalSelectionStart,s=this._model.finalSelectionEnd;return!!(i&&s&&t)&&this._areCoordsInSelection(t,i,s)}isCellInSelection(e,t){const i=this._model.finalSelectionStart,s=this._model.finalSelectionEnd;return!(!i||!s)&&this._areCoordsInSelection([e,t],i,s)}_areCoordsInSelection(e,t,i){return e[1]>t[1]&&e[1]=t[0]&&e[0]=t[0]}_selectWordAtCursor(e,t){const i=this._linkifier.currentLink?.link?.range;if(i)return this._model.selectionStart=[i.start.x-1,i.start.y-1],this._model.selectionStartLength=(0,_.getRangeLength)(i,this._bufferService.cols),this._model.selectionEnd=void 0,!0;const s=this._getMouseBufferCoords(e);return!!s&&(this._selectWordAt(s,t),this._model.selectionEnd=void 0,!0)}selectAll(){this._model.isSelectAllActive=!0,this.refresh(),this._onSelectionChange.fire()}selectLines(e,t){this._model.clearSelection(),e=Math.max(e,0),t=Math.min(t,this._bufferService.buffer.lines.length-1),this._model.selectionStart=[0,e],this._model.selectionEnd=[this._bufferService.cols,t],this.refresh(),this._onSelectionChange.fire()}_handleTrim(e){this._model.handleTrim(e)&&this.refresh()}_getMouseBufferCoords(e){const t=this._mouseService.getCoords(e,this._screenElement,this._bufferService.cols,this._bufferService.rows,!0);if(t)return t[0]--,t[1]--,t[1]+=this._bufferService.buffer.ydisp,t}_getMouseEventScrollAmount(e){let t=(0,n.getCoordsRelativeToElement)(this._coreBrowserService.window,e,this._screenElement)[1];const i=this._renderService.dimensions.css.canvas.height;return t>=0&&t<=i?0:(t>i&&(t-=i),t=Math.min(Math.max(t,-50),50),t/=50,t/Math.abs(t)+Math.round(14*t))}shouldForceSelection(e){return d.isMac?e.altKey&&this._optionsService.rawOptions.macOptionClickForcesSelection:e.shiftKey}handleMouseDown(e){if(this._mouseDownTimeStamp=e.timeStamp,(2!==e.button||!this.hasSelection)&&0===e.button){if(!this._enabled){if(!this.shouldForceSelection(e))return;e.stopPropagation()}e.preventDefault(),this._dragScrollAmount=0,this._enabled&&e.shiftKey?this._handleIncrementalClick(e):1===e.detail?this._handleSingleClick(e):2===e.detail?this._handleDoubleClick(e):3===e.detail&&this._handleTripleClick(e),this._addMouseDownListeners(),this.refresh(!0)}}_addMouseDownListeners(){this._screenElement.ownerDocument&&(this._screenElement.ownerDocument.addEventListener("mousemove",this._mouseMoveListener),this._screenElement.ownerDocument.addEventListener("mouseup",this._mouseUpListener)),this._dragScrollIntervalTimer=this._coreBrowserService.window.setInterval((()=>this._dragScroll()),50)}_removeMouseDownListeners(){this._screenElement.ownerDocument&&(this._screenElement.ownerDocument.removeEventListener("mousemove",this._mouseMoveListener),this._screenElement.ownerDocument.removeEventListener("mouseup",this._mouseUpListener)),this._coreBrowserService.window.clearInterval(this._dragScrollIntervalTimer),this._dragScrollIntervalTimer=void 0}_handleIncrementalClick(e){this._model.selectionStart&&(this._model.selectionEnd=this._getMouseBufferCoords(e))}_handleSingleClick(e){if(this._model.selectionStartLength=0,this._model.isSelectAllActive=!1,this._activeSelectionMode=this.shouldColumnSelect(e)?3:0,this._model.selectionStart=this._getMouseBufferCoords(e),!this._model.selectionStart)return;this._model.selectionEnd=void 0;const t=this._bufferService.buffer.lines.get(this._model.selectionStart[1]);t&&t.length!==this._model.selectionStart[0]&&0===t.hasWidth(this._model.selectionStart[0])&&this._model.selectionStart[0]++}_handleDoubleClick(e){this._selectWordAtCursor(e,!0)&&(this._activeSelectionMode=1)}_handleTripleClick(e){const t=this._getMouseBufferCoords(e);t&&(this._activeSelectionMode=2,this._selectLineAt(t[1]))}shouldColumnSelect(e){return e.altKey&&!(d.isMac&&this._optionsService.rawOptions.macOptionClickForcesSelection)}_handleMouseMove(e){if(e.stopImmediatePropagation(),!this._model.selectionStart)return;const t=this._model.selectionEnd?[this._model.selectionEnd[0],this._model.selectionEnd[1]]:null;if(this._model.selectionEnd=this._getMouseBufferCoords(e),!this._model.selectionEnd)return void this.refresh(!0);2===this._activeSelectionMode?this._model.selectionEnd[1]0?this._model.selectionEnd[0]=this._bufferService.cols:this._dragScrollAmount<0&&(this._model.selectionEnd[0]=0));const i=this._bufferService.buffer;if(this._model.selectionEnd[1]0?(3!==this._activeSelectionMode&&(this._model.selectionEnd[0]=this._bufferService.cols),this._model.selectionEnd[1]=Math.min(e.ydisp+this._bufferService.rows,e.lines.length-1)):(3!==this._activeSelectionMode&&(this._model.selectionEnd[0]=0),this._model.selectionEnd[1]=e.ydisp),this.refresh()}}_handleMouseUp(e){const t=e.timeStamp-this._mouseDownTimeStamp;if(this._removeMouseDownListeners(),this.selectionText.length<=1&&t<500&&e.altKey&&this._optionsService.rawOptions.altClickMovesCursor){if(this._bufferService.buffer.ybase===this._bufferService.buffer.ydisp){const t=this._mouseService.getCoords(e,this._element,this._bufferService.cols,this._bufferService.rows,!1);if(t&&void 0!==t[0]&&void 0!==t[1]){const e=(0,o.moveToCellSequence)(t[0]-1,t[1]-1,this._bufferService,this._coreService.decPrivateModes.applicationCursorKeys);this._coreService.triggerDataEvent(e,!0)}}}else this._fireEventIfSelectionChanged()}_fireEventIfSelectionChanged(){const e=this._model.finalSelectionStart,t=this._model.finalSelectionEnd,i=!(!e||!t||e[0]===t[0]&&e[1]===t[1]);i?e&&t&&(this._oldSelectionStart&&this._oldSelectionEnd&&e[0]===this._oldSelectionStart[0]&&e[1]===this._oldSelectionStart[1]&&t[0]===this._oldSelectionEnd[0]&&t[1]===this._oldSelectionEnd[1]||this._fireOnSelectionChange(e,t,i)):this._oldHasSelection&&this._fireOnSelectionChange(e,t,i)}_fireOnSelectionChange(e,t,i){this._oldSelectionStart=e,this._oldSelectionEnd=t,this._oldHasSelection=i,this._onSelectionChange.fire()}_handleBufferActivate(e){this.clearSelection(),this._trimListener.dispose(),this._trimListener=e.activeBuffer.lines.onTrim((e=>this._handleTrim(e)))}_convertViewportColToCharacterIndex(e,t){let i=t;for(let s=0;t>=s;s++){const r=e.loadCell(s,this._workCell).getChars().length;0===this._workCell.getWidth()?i--:r>1&&t!==s&&(i+=r-1)}return i}setSelection(e,t,i){this._model.clearSelection(),this._removeMouseDownListeners(),this._model.selectionStart=[e,t],this._model.selectionStartLength=i,this.refresh(),this._fireEventIfSelectionChanged()}rightClickSelect(e){this._isClickInSelection(e)||(this._selectWordAtCursor(e,!1)&&this.refresh(!0),this._fireEventIfSelectionChanged())}_getWordAt(e,t,i=!0,s=!0){if(e[0]>=this._bufferService.cols)return;const r=this._bufferService.buffer,n=r.lines.get(e[1]);if(!n)return;const o=r.translateBufferLineToString(e[1],!1);let a=this._convertViewportColToCharacterIndex(n,e[0]),h=a;const c=e[0]-a;let l=0,d=0,_=0,u=0;if(" "===o.charAt(a)){for(;a>0&&" "===o.charAt(a-1);)a--;for(;h1&&(u+=s-1,h+=s-1);t>0&&a>0&&!this._isCharWordSeparator(n.loadCell(t-1,this._workCell));){n.loadCell(t-1,this._workCell);const e=this._workCell.getChars().length;0===this._workCell.getWidth()?(l++,t--):e>1&&(_+=e-1,a-=e-1),a--,t--}for(;i1&&(u+=e-1,h+=e-1),h++,i++}}h++;let f=a+c-l+_,v=Math.min(this._bufferService.cols,h-a+l+d-_-u);if(t||""!==o.slice(a,h).trim()){if(i&&0===f&&32!==n.getCodePoint(0)){const t=r.lines.get(e[1]-1);if(t&&n.isWrapped&&32!==t.getCodePoint(this._bufferService.cols-1)){const t=this._getWordAt([this._bufferService.cols-1,e[1]-1],!1,!0,!1);if(t){const e=this._bufferService.cols-t.start;f-=e,v+=e}}}if(s&&f+v===this._bufferService.cols&&32!==n.getCodePoint(this._bufferService.cols-1)){const t=r.lines.get(e[1]+1);if(t?.isWrapped&&32!==t.getCodePoint(0)){const t=this._getWordAt([0,e[1]+1],!1,!1,!0);t&&(v+=t.length)}}return{start:f,length:v}}}_selectWordAt(e,t){const i=this._getWordAt(e,t);if(i){for(;i.start<0;)i.start+=this._bufferService.cols,e[1]--;this._model.selectionStart=[i.start,e[1]],this._model.selectionStartLength=i.length}}_selectToWordAt(e){const t=this._getWordAt(e,!0);if(t){let i=e[1];for(;t.start<0;)t.start+=this._bufferService.cols,i--;if(!this._model.areSelectionValuesReversed())for(;t.start+t.length>this._bufferService.cols;)t.length-=this._bufferService.cols,i++;this._model.selectionEnd=[this._model.areSelectionValuesReversed()?t.start:t.start+t.length,i]}}_isCharWordSeparator(e){return 0!==e.getWidth()&&this._optionsService.rawOptions.wordSeparator.indexOf(e.getChars())>=0}_selectLineAt(e){const t=this._bufferService.buffer.getWrappedRangeForLine(e),i={start:{x:0,y:t.first},end:{x:this._bufferService.cols-1,y:t.last}};this._model.selectionStart=[0,t.first],this._model.selectionEnd=void 0,this._model.selectionStartLength=(0,_.getRangeLength)(i,this._bufferService.cols)}};t.SelectionService=g=s([r(3,f.IBufferService),r(4,f.ICoreService),r(5,h.IMouseService),r(6,f.IOptionsService),r(7,h.IRenderService),r(8,h.ICoreBrowserService)],g)},4725:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ILinkProviderService=t.IThemeService=t.ICharacterJoinerService=t.ISelectionService=t.IRenderService=t.IMouseService=t.ICoreBrowserService=t.ICharSizeService=void 0;const s=i(8343);t.ICharSizeService=(0,s.createDecorator)("CharSizeService"),t.ICoreBrowserService=(0,s.createDecorator)("CoreBrowserService"),t.IMouseService=(0,s.createDecorator)("MouseService"),t.IRenderService=(0,s.createDecorator)("RenderService"),t.ISelectionService=(0,s.createDecorator)("SelectionService"),t.ICharacterJoinerService=(0,s.createDecorator)("CharacterJoinerService"),t.IThemeService=(0,s.createDecorator)("ThemeService"),t.ILinkProviderService=(0,s.createDecorator)("LinkProviderService")},6731:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.ThemeService=t.DEFAULT_ANSI_COLORS=void 0;const n=i(7239),o=i(8055),a=i(8460),h=i(844),c=i(2585),l=o.css.toColor("#ffffff"),d=o.css.toColor("#000000"),_=o.css.toColor("#ffffff"),u=o.css.toColor("#000000"),f={css:"rgba(255, 255, 255, 0.3)",rgba:4294967117};t.DEFAULT_ANSI_COLORS=Object.freeze((()=>{const e=[o.css.toColor("#2e3436"),o.css.toColor("#cc0000"),o.css.toColor("#4e9a06"),o.css.toColor("#c4a000"),o.css.toColor("#3465a4"),o.css.toColor("#75507b"),o.css.toColor("#06989a"),o.css.toColor("#d3d7cf"),o.css.toColor("#555753"),o.css.toColor("#ef2929"),o.css.toColor("#8ae234"),o.css.toColor("#fce94f"),o.css.toColor("#729fcf"),o.css.toColor("#ad7fa8"),o.css.toColor("#34e2e2"),o.css.toColor("#eeeeec")],t=[0,95,135,175,215,255];for(let i=0;i<216;i++){const s=t[i/36%6|0],r=t[i/6%6|0],n=t[i%6];e.push({css:o.channels.toCss(s,r,n),rgba:o.channels.toRgba(s,r,n)})}for(let t=0;t<24;t++){const i=8+10*t;e.push({css:o.channels.toCss(i,i,i),rgba:o.channels.toRgba(i,i,i)})}return e})());let v=t.ThemeService=class extends h.Disposable{get colors(){return this._colors}constructor(e){super(),this._optionsService=e,this._contrastCache=new n.ColorContrastCache,this._halfContrastCache=new n.ColorContrastCache,this._onChangeColors=this.register(new a.EventEmitter),this.onChangeColors=this._onChangeColors.event,this._colors={foreground:l,background:d,cursor:_,cursorAccent:u,selectionForeground:void 0,selectionBackgroundTransparent:f,selectionBackgroundOpaque:o.color.blend(d,f),selectionInactiveBackgroundTransparent:f,selectionInactiveBackgroundOpaque:o.color.blend(d,f),ansi:t.DEFAULT_ANSI_COLORS.slice(),contrastCache:this._contrastCache,halfContrastCache:this._halfContrastCache},this._updateRestoreColors(),this._setTheme(this._optionsService.rawOptions.theme),this.register(this._optionsService.onSpecificOptionChange("minimumContrastRatio",(()=>this._contrastCache.clear()))),this.register(this._optionsService.onSpecificOptionChange("theme",(()=>this._setTheme(this._optionsService.rawOptions.theme))))}_setTheme(e={}){const i=this._colors;if(i.foreground=p(e.foreground,l),i.background=p(e.background,d),i.cursor=p(e.cursor,_),i.cursorAccent=p(e.cursorAccent,u),i.selectionBackgroundTransparent=p(e.selectionBackground,f),i.selectionBackgroundOpaque=o.color.blend(i.background,i.selectionBackgroundTransparent),i.selectionInactiveBackgroundTransparent=p(e.selectionInactiveBackground,i.selectionBackgroundTransparent),i.selectionInactiveBackgroundOpaque=o.color.blend(i.background,i.selectionInactiveBackgroundTransparent),i.selectionForeground=e.selectionForeground?p(e.selectionForeground,o.NULL_COLOR):void 0,i.selectionForeground===o.NULL_COLOR&&(i.selectionForeground=void 0),o.color.isOpaque(i.selectionBackgroundTransparent)){const e=.3;i.selectionBackgroundTransparent=o.color.opacity(i.selectionBackgroundTransparent,e)}if(o.color.isOpaque(i.selectionInactiveBackgroundTransparent)){const e=.3;i.selectionInactiveBackgroundTransparent=o.color.opacity(i.selectionInactiveBackgroundTransparent,e)}if(i.ansi=t.DEFAULT_ANSI_COLORS.slice(),i.ansi[0]=p(e.black,t.DEFAULT_ANSI_COLORS[0]),i.ansi[1]=p(e.red,t.DEFAULT_ANSI_COLORS[1]),i.ansi[2]=p(e.green,t.DEFAULT_ANSI_COLORS[2]),i.ansi[3]=p(e.yellow,t.DEFAULT_ANSI_COLORS[3]),i.ansi[4]=p(e.blue,t.DEFAULT_ANSI_COLORS[4]),i.ansi[5]=p(e.magenta,t.DEFAULT_ANSI_COLORS[5]),i.ansi[6]=p(e.cyan,t.DEFAULT_ANSI_COLORS[6]),i.ansi[7]=p(e.white,t.DEFAULT_ANSI_COLORS[7]),i.ansi[8]=p(e.brightBlack,t.DEFAULT_ANSI_COLORS[8]),i.ansi[9]=p(e.brightRed,t.DEFAULT_ANSI_COLORS[9]),i.ansi[10]=p(e.brightGreen,t.DEFAULT_ANSI_COLORS[10]),i.ansi[11]=p(e.brightYellow,t.DEFAULT_ANSI_COLORS[11]),i.ansi[12]=p(e.brightBlue,t.DEFAULT_ANSI_COLORS[12]),i.ansi[13]=p(e.brightMagenta,t.DEFAULT_ANSI_COLORS[13]),i.ansi[14]=p(e.brightCyan,t.DEFAULT_ANSI_COLORS[14]),i.ansi[15]=p(e.brightWhite,t.DEFAULT_ANSI_COLORS[15]),e.extendedAnsi){const s=Math.min(i.ansi.length-16,e.extendedAnsi.length);for(let r=0;r{Object.defineProperty(t,"__esModule",{value:!0}),t.CircularList=void 0;const s=i(8460),r=i(844);class n extends r.Disposable{constructor(e){super(),this._maxLength=e,this.onDeleteEmitter=this.register(new s.EventEmitter),this.onDelete=this.onDeleteEmitter.event,this.onInsertEmitter=this.register(new s.EventEmitter),this.onInsert=this.onInsertEmitter.event,this.onTrimEmitter=this.register(new s.EventEmitter),this.onTrim=this.onTrimEmitter.event,this._array=new Array(this._maxLength),this._startIndex=0,this._length=0}get maxLength(){return this._maxLength}set maxLength(e){if(this._maxLength===e)return;const t=new Array(e);for(let i=0;ithis._length)for(let t=this._length;t=e;t--)this._array[this._getCyclicIndex(t+i.length)]=this._array[this._getCyclicIndex(t)];for(let t=0;tthis._maxLength){const e=this._length+i.length-this._maxLength;this._startIndex+=e,this._length=this._maxLength,this.onTrimEmitter.fire(e)}else this._length+=i.length}trimStart(e){e>this._length&&(e=this._length),this._startIndex+=e,this._length-=e,this.onTrimEmitter.fire(e)}shiftElements(e,t,i){if(!(t<=0)){if(e<0||e>=this._length)throw new Error("start argument out of range");if(e+i<0)throw new Error("Cannot shift elements in list beyond index 0");if(i>0){for(let s=t-1;s>=0;s--)this.set(e+s+i,this.get(e+s));const s=e+t+i-this._length;if(s>0)for(this._length+=s;this._length>this._maxLength;)this._length--,this._startIndex++,this.onTrimEmitter.fire(1)}else for(let s=0;s{Object.defineProperty(t,"__esModule",{value:!0}),t.clone=void 0,t.clone=function e(t,i=5){if("object"!=typeof t)return t;const s=Array.isArray(t)?[]:{};for(const r in t)s[r]=i<=1?t[r]:t[r]&&e(t[r],i-1);return s}},8055:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.contrastRatio=t.toPaddedHex=t.rgba=t.rgb=t.css=t.color=t.channels=t.NULL_COLOR=void 0;const s=i(6114);let r=0,n=0,o=0,a=0;var h,c,l,d,_;function u(e){const t=e.toString(16);return t.length<2?"0"+t:t}function f(e,t){return e>>0},e.toColor=function(t,i,s,r){return{css:e.toCss(t,i,s,r),rgba:e.toRgba(t,i,s,r)}}}(h||(t.channels=h={})),function(e){function t(e,t){return a=Math.round(255*t),[r,n,o]=_.toChannels(e.rgba),{css:h.toCss(r,n,o,a),rgba:h.toRgba(r,n,o,a)}}e.blend=function(e,t){if(a=(255&t.rgba)/255,1===a)return{css:t.css,rgba:t.rgba};const i=t.rgba>>24&255,s=t.rgba>>16&255,c=t.rgba>>8&255,l=e.rgba>>24&255,d=e.rgba>>16&255,_=e.rgba>>8&255;return r=l+Math.round((i-l)*a),n=d+Math.round((s-d)*a),o=_+Math.round((c-_)*a),{css:h.toCss(r,n,o),rgba:h.toRgba(r,n,o)}},e.isOpaque=function(e){return 255==(255&e.rgba)},e.ensureContrastRatio=function(e,t,i){const s=_.ensureContrastRatio(e.rgba,t.rgba,i);if(s)return h.toColor(s>>24&255,s>>16&255,s>>8&255)},e.opaque=function(e){const t=(255|e.rgba)>>>0;return[r,n,o]=_.toChannels(t),{css:h.toCss(r,n,o),rgba:t}},e.opacity=t,e.multiplyOpacity=function(e,i){return a=255&e.rgba,t(e,a*i/255)},e.toColorRGB=function(e){return[e.rgba>>24&255,e.rgba>>16&255,e.rgba>>8&255]}}(c||(t.color=c={})),function(e){let t,i;if(!s.isNode){const e=document.createElement("canvas");e.width=1,e.height=1;const s=e.getContext("2d",{willReadFrequently:!0});s&&(t=s,t.globalCompositeOperation="copy",i=t.createLinearGradient(0,0,1,1))}e.toColor=function(e){if(e.match(/#[\da-f]{3,8}/i))switch(e.length){case 4:return r=parseInt(e.slice(1,2).repeat(2),16),n=parseInt(e.slice(2,3).repeat(2),16),o=parseInt(e.slice(3,4).repeat(2),16),h.toColor(r,n,o);case 5:return r=parseInt(e.slice(1,2).repeat(2),16),n=parseInt(e.slice(2,3).repeat(2),16),o=parseInt(e.slice(3,4).repeat(2),16),a=parseInt(e.slice(4,5).repeat(2),16),h.toColor(r,n,o,a);case 7:return{css:e,rgba:(parseInt(e.slice(1),16)<<8|255)>>>0};case 9:return{css:e,rgba:parseInt(e.slice(1),16)>>>0}}const s=e.match(/rgba?\(\s*(\d{1,3})\s*,\s*(\d{1,3})\s*,\s*(\d{1,3})\s*(,\s*(0|1|\d?\.(\d+))\s*)?\)/);if(s)return r=parseInt(s[1]),n=parseInt(s[2]),o=parseInt(s[3]),a=Math.round(255*(void 0===s[5]?1:parseFloat(s[5]))),h.toColor(r,n,o,a);if(!t||!i)throw new Error("css.toColor: Unsupported css format");if(t.fillStyle=i,t.fillStyle=e,"string"!=typeof t.fillStyle)throw new Error("css.toColor: Unsupported css format");if(t.fillRect(0,0,1,1),[r,n,o,a]=t.getImageData(0,0,1,1).data,255!==a)throw new Error("css.toColor: Unsupported css format");return{rgba:h.toRgba(r,n,o,a),css:e}}}(l||(t.css=l={})),function(e){function t(e,t,i){const s=e/255,r=t/255,n=i/255;return.2126*(s<=.03928?s/12.92:Math.pow((s+.055)/1.055,2.4))+.7152*(r<=.03928?r/12.92:Math.pow((r+.055)/1.055,2.4))+.0722*(n<=.03928?n/12.92:Math.pow((n+.055)/1.055,2.4))}e.relativeLuminance=function(e){return t(e>>16&255,e>>8&255,255&e)},e.relativeLuminance2=t}(d||(t.rgb=d={})),function(e){function t(e,t,i){const s=e>>24&255,r=e>>16&255,n=e>>8&255;let o=t>>24&255,a=t>>16&255,h=t>>8&255,c=f(d.relativeLuminance2(o,a,h),d.relativeLuminance2(s,r,n));for(;c0||a>0||h>0);)o-=Math.max(0,Math.ceil(.1*o)),a-=Math.max(0,Math.ceil(.1*a)),h-=Math.max(0,Math.ceil(.1*h)),c=f(d.relativeLuminance2(o,a,h),d.relativeLuminance2(s,r,n));return(o<<24|a<<16|h<<8|255)>>>0}function i(e,t,i){const s=e>>24&255,r=e>>16&255,n=e>>8&255;let o=t>>24&255,a=t>>16&255,h=t>>8&255,c=f(d.relativeLuminance2(o,a,h),d.relativeLuminance2(s,r,n));for(;c>>0}e.blend=function(e,t){if(a=(255&t)/255,1===a)return t;const i=t>>24&255,s=t>>16&255,c=t>>8&255,l=e>>24&255,d=e>>16&255,_=e>>8&255;return r=l+Math.round((i-l)*a),n=d+Math.round((s-d)*a),o=_+Math.round((c-_)*a),h.toRgba(r,n,o)},e.ensureContrastRatio=function(e,s,r){const n=d.relativeLuminance(e>>8),o=d.relativeLuminance(s>>8);if(f(n,o)>8));if(af(n,d.relativeLuminance(t>>8))?o:t}return o}const a=i(e,s,r),h=f(n,d.relativeLuminance(a>>8));if(hf(n,d.relativeLuminance(i>>8))?a:i}return a}},e.reduceLuminance=t,e.increaseLuminance=i,e.toChannels=function(e){return[e>>24&255,e>>16&255,e>>8&255,255&e]}}(_||(t.rgba=_={})),t.toPaddedHex=u,t.contrastRatio=f},8969:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.CoreTerminal=void 0;const s=i(844),r=i(2585),n=i(4348),o=i(7866),a=i(744),h=i(7302),c=i(6975),l=i(8460),d=i(1753),_=i(1480),u=i(7994),f=i(9282),v=i(5435),p=i(5981),g=i(2660);let m=!1;class S extends s.Disposable{get onScroll(){return this._onScrollApi||(this._onScrollApi=this.register(new l.EventEmitter),this._onScroll.event((e=>{this._onScrollApi?.fire(e.position)}))),this._onScrollApi.event}get cols(){return this._bufferService.cols}get rows(){return this._bufferService.rows}get buffers(){return this._bufferService.buffers}get options(){return this.optionsService.options}set options(e){for(const t in e)this.optionsService.options[t]=e[t]}constructor(e){super(),this._windowsWrappingHeuristics=this.register(new s.MutableDisposable),this._onBinary=this.register(new l.EventEmitter),this.onBinary=this._onBinary.event,this._onData=this.register(new l.EventEmitter),this.onData=this._onData.event,this._onLineFeed=this.register(new l.EventEmitter),this.onLineFeed=this._onLineFeed.event,this._onResize=this.register(new l.EventEmitter),this.onResize=this._onResize.event,this._onWriteParsed=this.register(new l.EventEmitter),this.onWriteParsed=this._onWriteParsed.event,this._onScroll=this.register(new l.EventEmitter),this._instantiationService=new n.InstantiationService,this.optionsService=this.register(new h.OptionsService(e)),this._instantiationService.setService(r.IOptionsService,this.optionsService),this._bufferService=this.register(this._instantiationService.createInstance(a.BufferService)),this._instantiationService.setService(r.IBufferService,this._bufferService),this._logService=this.register(this._instantiationService.createInstance(o.LogService)),this._instantiationService.setService(r.ILogService,this._logService),this.coreService=this.register(this._instantiationService.createInstance(c.CoreService)),this._instantiationService.setService(r.ICoreService,this.coreService),this.coreMouseService=this.register(this._instantiationService.createInstance(d.CoreMouseService)),this._instantiationService.setService(r.ICoreMouseService,this.coreMouseService),this.unicodeService=this.register(this._instantiationService.createInstance(_.UnicodeService)),this._instantiationService.setService(r.IUnicodeService,this.unicodeService),this._charsetService=this._instantiationService.createInstance(u.CharsetService),this._instantiationService.setService(r.ICharsetService,this._charsetService),this._oscLinkService=this._instantiationService.createInstance(g.OscLinkService),this._instantiationService.setService(r.IOscLinkService,this._oscLinkService),this._inputHandler=this.register(new v.InputHandler(this._bufferService,this._charsetService,this.coreService,this._logService,this.optionsService,this._oscLinkService,this.coreMouseService,this.unicodeService)),this.register((0,l.forwardEvent)(this._inputHandler.onLineFeed,this._onLineFeed)),this.register(this._inputHandler),this.register((0,l.forwardEvent)(this._bufferService.onResize,this._onResize)),this.register((0,l.forwardEvent)(this.coreService.onData,this._onData)),this.register((0,l.forwardEvent)(this.coreService.onBinary,this._onBinary)),this.register(this.coreService.onRequestScrollToBottom((()=>this.scrollToBottom()))),this.register(this.coreService.onUserInput((()=>this._writeBuffer.handleUserInput()))),this.register(this.optionsService.onMultipleOptionChange(["windowsMode","windowsPty"],(()=>this._handleWindowsPtyOptionChange()))),this.register(this._bufferService.onScroll((e=>{this._onScroll.fire({position:this._bufferService.buffer.ydisp,source:0}),this._inputHandler.markRangeDirty(this._bufferService.buffer.scrollTop,this._bufferService.buffer.scrollBottom)}))),this.register(this._inputHandler.onScroll((e=>{this._onScroll.fire({position:this._bufferService.buffer.ydisp,source:0}),this._inputHandler.markRangeDirty(this._bufferService.buffer.scrollTop,this._bufferService.buffer.scrollBottom)}))),this._writeBuffer=this.register(new p.WriteBuffer(((e,t)=>this._inputHandler.parse(e,t)))),this.register((0,l.forwardEvent)(this._writeBuffer.onWriteParsed,this._onWriteParsed))}write(e,t){this._writeBuffer.write(e,t)}writeSync(e,t){this._logService.logLevel<=r.LogLevelEnum.WARN&&!m&&(this._logService.warn("writeSync is unreliable and will be removed soon."),m=!0),this._writeBuffer.writeSync(e,t)}input(e,t=!0){this.coreService.triggerDataEvent(e,t)}resize(e,t){isNaN(e)||isNaN(t)||(e=Math.max(e,a.MINIMUM_COLS),t=Math.max(t,a.MINIMUM_ROWS),this._bufferService.resize(e,t))}scroll(e,t=!1){this._bufferService.scroll(e,t)}scrollLines(e,t,i){this._bufferService.scrollLines(e,t,i)}scrollPages(e){this.scrollLines(e*(this.rows-1))}scrollToTop(){this.scrollLines(-this._bufferService.buffer.ydisp)}scrollToBottom(){this.scrollLines(this._bufferService.buffer.ybase-this._bufferService.buffer.ydisp)}scrollToLine(e){const t=e-this._bufferService.buffer.ydisp;0!==t&&this.scrollLines(t)}registerEscHandler(e,t){return this._inputHandler.registerEscHandler(e,t)}registerDcsHandler(e,t){return this._inputHandler.registerDcsHandler(e,t)}registerCsiHandler(e,t){return this._inputHandler.registerCsiHandler(e,t)}registerOscHandler(e,t){return this._inputHandler.registerOscHandler(e,t)}_setup(){this._handleWindowsPtyOptionChange()}reset(){this._inputHandler.reset(),this._bufferService.reset(),this._charsetService.reset(),this.coreService.reset(),this.coreMouseService.reset()}_handleWindowsPtyOptionChange(){let e=!1;const t=this.optionsService.rawOptions.windowsPty;t&&void 0!==t.buildNumber&&void 0!==t.buildNumber?e=!!("conpty"===t.backend&&t.buildNumber<21376):this.optionsService.rawOptions.windowsMode&&(e=!0),e?this._enableWindowsWrappingHeuristics():this._windowsWrappingHeuristics.clear()}_enableWindowsWrappingHeuristics(){if(!this._windowsWrappingHeuristics.value){const e=[];e.push(this.onLineFeed(f.updateWindowsModeWrappedState.bind(null,this._bufferService))),e.push(this.registerCsiHandler({final:"H"},(()=>((0,f.updateWindowsModeWrappedState)(this._bufferService),!1)))),this._windowsWrappingHeuristics.value=(0,s.toDisposable)((()=>{for(const t of e)t.dispose()}))}}}t.CoreTerminal=S},8460:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.runAndSubscribe=t.forwardEvent=t.EventEmitter=void 0,t.EventEmitter=class{constructor(){this._listeners=[],this._disposed=!1}get event(){return this._event||(this._event=e=>(this._listeners.push(e),{dispose:()=>{if(!this._disposed)for(let t=0;tt.fire(e)))},t.runAndSubscribe=function(e,t){return t(void 0),e((e=>t(e)))}},5435:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.InputHandler=t.WindowsOptionsReportType=void 0;const n=i(2584),o=i(7116),a=i(2015),h=i(844),c=i(482),l=i(8437),d=i(8460),_=i(643),u=i(511),f=i(3734),v=i(2585),p=i(1480),g=i(6242),m=i(6351),S=i(5941),C={"(":0,")":1,"*":2,"+":3,"-":1,".":2},b=131072;function w(e,t){if(e>24)return t.setWinLines||!1;switch(e){case 1:return!!t.restoreWin;case 2:return!!t.minimizeWin;case 3:return!!t.setWinPosition;case 4:return!!t.setWinSizePixels;case 5:return!!t.raiseWin;case 6:return!!t.lowerWin;case 7:return!!t.refreshWin;case 8:return!!t.setWinSizeChars;case 9:return!!t.maximizeWin;case 10:return!!t.fullscreenWin;case 11:return!!t.getWinState;case 13:return!!t.getWinPosition;case 14:return!!t.getWinSizePixels;case 15:return!!t.getScreenSizePixels;case 16:return!!t.getCellSizePixels;case 18:return!!t.getWinSizeChars;case 19:return!!t.getScreenSizeChars;case 20:return!!t.getIconTitle;case 21:return!!t.getWinTitle;case 22:return!!t.pushTitle;case 23:return!!t.popTitle;case 24:return!!t.setWinLines}return!1}var y;!function(e){e[e.GET_WIN_SIZE_PIXELS=0]="GET_WIN_SIZE_PIXELS",e[e.GET_CELL_SIZE_PIXELS=1]="GET_CELL_SIZE_PIXELS"}(y||(t.WindowsOptionsReportType=y={}));let E=0;class k extends h.Disposable{getAttrData(){return this._curAttrData}constructor(e,t,i,s,r,h,_,f,v=new a.EscapeSequenceParser){super(),this._bufferService=e,this._charsetService=t,this._coreService=i,this._logService=s,this._optionsService=r,this._oscLinkService=h,this._coreMouseService=_,this._unicodeService=f,this._parser=v,this._parseBuffer=new Uint32Array(4096),this._stringDecoder=new c.StringToUtf32,this._utf8Decoder=new c.Utf8ToUtf32,this._workCell=new u.CellData,this._windowTitle="",this._iconName="",this._windowTitleStack=[],this._iconNameStack=[],this._curAttrData=l.DEFAULT_ATTR_DATA.clone(),this._eraseAttrDataInternal=l.DEFAULT_ATTR_DATA.clone(),this._onRequestBell=this.register(new d.EventEmitter),this.onRequestBell=this._onRequestBell.event,this._onRequestRefreshRows=this.register(new d.EventEmitter),this.onRequestRefreshRows=this._onRequestRefreshRows.event,this._onRequestReset=this.register(new d.EventEmitter),this.onRequestReset=this._onRequestReset.event,this._onRequestSendFocus=this.register(new d.EventEmitter),this.onRequestSendFocus=this._onRequestSendFocus.event,this._onRequestSyncScrollBar=this.register(new d.EventEmitter),this.onRequestSyncScrollBar=this._onRequestSyncScrollBar.event,this._onRequestWindowsOptionsReport=this.register(new d.EventEmitter),this.onRequestWindowsOptionsReport=this._onRequestWindowsOptionsReport.event,this._onA11yChar=this.register(new d.EventEmitter),this.onA11yChar=this._onA11yChar.event,this._onA11yTab=this.register(new d.EventEmitter),this.onA11yTab=this._onA11yTab.event,this._onCursorMove=this.register(new d.EventEmitter),this.onCursorMove=this._onCursorMove.event,this._onLineFeed=this.register(new d.EventEmitter),this.onLineFeed=this._onLineFeed.event,this._onScroll=this.register(new d.EventEmitter),this.onScroll=this._onScroll.event,this._onTitleChange=this.register(new d.EventEmitter),this.onTitleChange=this._onTitleChange.event,this._onColor=this.register(new d.EventEmitter),this.onColor=this._onColor.event,this._parseStack={paused:!1,cursorStartX:0,cursorStartY:0,decodedLength:0,position:0},this._specialColors=[256,257,258],this.register(this._parser),this._dirtyRowTracker=new L(this._bufferService),this._activeBuffer=this._bufferService.buffer,this.register(this._bufferService.buffers.onBufferActivate((e=>this._activeBuffer=e.activeBuffer))),this._parser.setCsiHandlerFallback(((e,t)=>{this._logService.debug("Unknown CSI code: ",{identifier:this._parser.identToString(e),params:t.toArray()})})),this._parser.setEscHandlerFallback((e=>{this._logService.debug("Unknown ESC code: ",{identifier:this._parser.identToString(e)})})),this._parser.setExecuteHandlerFallback((e=>{this._logService.debug("Unknown EXECUTE code: ",{code:e})})),this._parser.setOscHandlerFallback(((e,t,i)=>{this._logService.debug("Unknown OSC code: ",{identifier:e,action:t,data:i})})),this._parser.setDcsHandlerFallback(((e,t,i)=>{"HOOK"===t&&(i=i.toArray()),this._logService.debug("Unknown DCS code: ",{identifier:this._parser.identToString(e),action:t,payload:i})})),this._parser.setPrintHandler(((e,t,i)=>this.print(e,t,i))),this._parser.registerCsiHandler({final:"@"},(e=>this.insertChars(e))),this._parser.registerCsiHandler({intermediates:" ",final:"@"},(e=>this.scrollLeft(e))),this._parser.registerCsiHandler({final:"A"},(e=>this.cursorUp(e))),this._parser.registerCsiHandler({intermediates:" ",final:"A"},(e=>this.scrollRight(e))),this._parser.registerCsiHandler({final:"B"},(e=>this.cursorDown(e))),this._parser.registerCsiHandler({final:"C"},(e=>this.cursorForward(e))),this._parser.registerCsiHandler({final:"D"},(e=>this.cursorBackward(e))),this._parser.registerCsiHandler({final:"E"},(e=>this.cursorNextLine(e))),this._parser.registerCsiHandler({final:"F"},(e=>this.cursorPrecedingLine(e))),this._parser.registerCsiHandler({final:"G"},(e=>this.cursorCharAbsolute(e))),this._parser.registerCsiHandler({final:"H"},(e=>this.cursorPosition(e))),this._parser.registerCsiHandler({final:"I"},(e=>this.cursorForwardTab(e))),this._parser.registerCsiHandler({final:"J"},(e=>this.eraseInDisplay(e,!1))),this._parser.registerCsiHandler({prefix:"?",final:"J"},(e=>this.eraseInDisplay(e,!0))),this._parser.registerCsiHandler({final:"K"},(e=>this.eraseInLine(e,!1))),this._parser.registerCsiHandler({prefix:"?",final:"K"},(e=>this.eraseInLine(e,!0))),this._parser.registerCsiHandler({final:"L"},(e=>this.insertLines(e))),this._parser.registerCsiHandler({final:"M"},(e=>this.deleteLines(e))),this._parser.registerCsiHandler({final:"P"},(e=>this.deleteChars(e))),this._parser.registerCsiHandler({final:"S"},(e=>this.scrollUp(e))),this._parser.registerCsiHandler({final:"T"},(e=>this.scrollDown(e))),this._parser.registerCsiHandler({final:"X"},(e=>this.eraseChars(e))),this._parser.registerCsiHandler({final:"Z"},(e=>this.cursorBackwardTab(e))),this._parser.registerCsiHandler({final:"`"},(e=>this.charPosAbsolute(e))),this._parser.registerCsiHandler({final:"a"},(e=>this.hPositionRelative(e))),this._parser.registerCsiHandler({final:"b"},(e=>this.repeatPrecedingCharacter(e))),this._parser.registerCsiHandler({final:"c"},(e=>this.sendDeviceAttributesPrimary(e))),this._parser.registerCsiHandler({prefix:">",final:"c"},(e=>this.sendDeviceAttributesSecondary(e))),this._parser.registerCsiHandler({final:"d"},(e=>this.linePosAbsolute(e))),this._parser.registerCsiHandler({final:"e"},(e=>this.vPositionRelative(e))),this._parser.registerCsiHandler({final:"f"},(e=>this.hVPosition(e))),this._parser.registerCsiHandler({final:"g"},(e=>this.tabClear(e))),this._parser.registerCsiHandler({final:"h"},(e=>this.setMode(e))),this._parser.registerCsiHandler({prefix:"?",final:"h"},(e=>this.setModePrivate(e))),this._parser.registerCsiHandler({final:"l"},(e=>this.resetMode(e))),this._parser.registerCsiHandler({prefix:"?",final:"l"},(e=>this.resetModePrivate(e))),this._parser.registerCsiHandler({final:"m"},(e=>this.charAttributes(e))),this._parser.registerCsiHandler({final:"n"},(e=>this.deviceStatus(e))),this._parser.registerCsiHandler({prefix:"?",final:"n"},(e=>this.deviceStatusPrivate(e))),this._parser.registerCsiHandler({intermediates:"!",final:"p"},(e=>this.softReset(e))),this._parser.registerCsiHandler({intermediates:" ",final:"q"},(e=>this.setCursorStyle(e))),this._parser.registerCsiHandler({final:"r"},(e=>this.setScrollRegion(e))),this._parser.registerCsiHandler({final:"s"},(e=>this.saveCursor(e))),this._parser.registerCsiHandler({final:"t"},(e=>this.windowOptions(e))),this._parser.registerCsiHandler({final:"u"},(e=>this.restoreCursor(e))),this._parser.registerCsiHandler({intermediates:"'",final:"}"},(e=>this.insertColumns(e))),this._parser.registerCsiHandler({intermediates:"'",final:"~"},(e=>this.deleteColumns(e))),this._parser.registerCsiHandler({intermediates:'"',final:"q"},(e=>this.selectProtected(e))),this._parser.registerCsiHandler({intermediates:"$",final:"p"},(e=>this.requestMode(e,!0))),this._parser.registerCsiHandler({prefix:"?",intermediates:"$",final:"p"},(e=>this.requestMode(e,!1))),this._parser.setExecuteHandler(n.C0.BEL,(()=>this.bell())),this._parser.setExecuteHandler(n.C0.LF,(()=>this.lineFeed())),this._parser.setExecuteHandler(n.C0.VT,(()=>this.lineFeed())),this._parser.setExecuteHandler(n.C0.FF,(()=>this.lineFeed())),this._parser.setExecuteHandler(n.C0.CR,(()=>this.carriageReturn())),this._parser.setExecuteHandler(n.C0.BS,(()=>this.backspace())),this._parser.setExecuteHandler(n.C0.HT,(()=>this.tab())),this._parser.setExecuteHandler(n.C0.SO,(()=>this.shiftOut())),this._parser.setExecuteHandler(n.C0.SI,(()=>this.shiftIn())),this._parser.setExecuteHandler(n.C1.IND,(()=>this.index())),this._parser.setExecuteHandler(n.C1.NEL,(()=>this.nextLine())),this._parser.setExecuteHandler(n.C1.HTS,(()=>this.tabSet())),this._parser.registerOscHandler(0,new g.OscHandler((e=>(this.setTitle(e),this.setIconName(e),!0)))),this._parser.registerOscHandler(1,new g.OscHandler((e=>this.setIconName(e)))),this._parser.registerOscHandler(2,new g.OscHandler((e=>this.setTitle(e)))),this._parser.registerOscHandler(4,new g.OscHandler((e=>this.setOrReportIndexedColor(e)))),this._parser.registerOscHandler(8,new g.OscHandler((e=>this.setHyperlink(e)))),this._parser.registerOscHandler(10,new g.OscHandler((e=>this.setOrReportFgColor(e)))),this._parser.registerOscHandler(11,new g.OscHandler((e=>this.setOrReportBgColor(e)))),this._parser.registerOscHandler(12,new g.OscHandler((e=>this.setOrReportCursorColor(e)))),this._parser.registerOscHandler(104,new g.OscHandler((e=>this.restoreIndexedColor(e)))),this._parser.registerOscHandler(110,new g.OscHandler((e=>this.restoreFgColor(e)))),this._parser.registerOscHandler(111,new g.OscHandler((e=>this.restoreBgColor(e)))),this._parser.registerOscHandler(112,new g.OscHandler((e=>this.restoreCursorColor(e)))),this._parser.registerEscHandler({final:"7"},(()=>this.saveCursor())),this._parser.registerEscHandler({final:"8"},(()=>this.restoreCursor())),this._parser.registerEscHandler({final:"D"},(()=>this.index())),this._parser.registerEscHandler({final:"E"},(()=>this.nextLine())),this._parser.registerEscHandler({final:"H"},(()=>this.tabSet())),this._parser.registerEscHandler({final:"M"},(()=>this.reverseIndex())),this._parser.registerEscHandler({final:"="},(()=>this.keypadApplicationMode())),this._parser.registerEscHandler({final:">"},(()=>this.keypadNumericMode())),this._parser.registerEscHandler({final:"c"},(()=>this.fullReset())),this._parser.registerEscHandler({final:"n"},(()=>this.setgLevel(2))),this._parser.registerEscHandler({final:"o"},(()=>this.setgLevel(3))),this._parser.registerEscHandler({final:"|"},(()=>this.setgLevel(3))),this._parser.registerEscHandler({final:"}"},(()=>this.setgLevel(2))),this._parser.registerEscHandler({final:"~"},(()=>this.setgLevel(1))),this._parser.registerEscHandler({intermediates:"%",final:"@"},(()=>this.selectDefaultCharset())),this._parser.registerEscHandler({intermediates:"%",final:"G"},(()=>this.selectDefaultCharset()));for(const e in o.CHARSETS)this._parser.registerEscHandler({intermediates:"(",final:e},(()=>this.selectCharset("("+e))),this._parser.registerEscHandler({intermediates:")",final:e},(()=>this.selectCharset(")"+e))),this._parser.registerEscHandler({intermediates:"*",final:e},(()=>this.selectCharset("*"+e))),this._parser.registerEscHandler({intermediates:"+",final:e},(()=>this.selectCharset("+"+e))),this._parser.registerEscHandler({intermediates:"-",final:e},(()=>this.selectCharset("-"+e))),this._parser.registerEscHandler({intermediates:".",final:e},(()=>this.selectCharset("."+e))),this._parser.registerEscHandler({intermediates:"/",final:e},(()=>this.selectCharset("/"+e)));this._parser.registerEscHandler({intermediates:"#",final:"8"},(()=>this.screenAlignmentPattern())),this._parser.setErrorHandler((e=>(this._logService.error("Parsing error: ",e),e))),this._parser.registerDcsHandler({intermediates:"$",final:"q"},new m.DcsHandler(((e,t)=>this.requestStatusString(e,t))))}_preserveStack(e,t,i,s){this._parseStack.paused=!0,this._parseStack.cursorStartX=e,this._parseStack.cursorStartY=t,this._parseStack.decodedLength=i,this._parseStack.position=s}_logSlowResolvingAsync(e){this._logService.logLevel<=v.LogLevelEnum.WARN&&Promise.race([e,new Promise(((e,t)=>setTimeout((()=>t("#SLOW_TIMEOUT")),5e3)))]).catch((e=>{if("#SLOW_TIMEOUT"!==e)throw e;console.warn("async parser handler taking longer than 5000 ms")}))}_getCurrentLinkId(){return this._curAttrData.extended.urlId}parse(e,t){let i,s=this._activeBuffer.x,r=this._activeBuffer.y,n=0;const o=this._parseStack.paused;if(o){if(i=this._parser.parse(this._parseBuffer,this._parseStack.decodedLength,t))return this._logSlowResolvingAsync(i),i;s=this._parseStack.cursorStartX,r=this._parseStack.cursorStartY,this._parseStack.paused=!1,e.length>b&&(n=this._parseStack.position+b)}if(this._logService.logLevel<=v.LogLevelEnum.DEBUG&&this._logService.debug("parsing data"+("string"==typeof e?` "${e}"`:` "${Array.prototype.map.call(e,(e=>String.fromCharCode(e))).join("")}"`),"string"==typeof e?e.split("").map((e=>e.charCodeAt(0))):e),this._parseBuffer.lengthb)for(let t=n;t0&&2===f.getWidth(this._activeBuffer.x-1)&&f.setCellFromCodepoint(this._activeBuffer.x-1,0,1,u);let v=this._parser.precedingJoinState;for(let g=t;ga)if(h){const e=f;let t=this._activeBuffer.x-m;for(this._activeBuffer.x=m,this._activeBuffer.y++,this._activeBuffer.y===this._activeBuffer.scrollBottom+1?(this._activeBuffer.y--,this._bufferService.scroll(this._eraseAttrData(),!0)):(this._activeBuffer.y>=this._bufferService.rows&&(this._activeBuffer.y=this._bufferService.rows-1),this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y).isWrapped=!0),f=this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y),m>0&&f instanceof l.BufferLine&&f.copyCellsFrom(e,t,0,m,!1);t=0;)f.setCellFromCodepoint(this._activeBuffer.x++,0,0,u)}else if(d&&(f.insertCells(this._activeBuffer.x,r-m,this._activeBuffer.getNullCell(u)),2===f.getWidth(a-1)&&f.setCellFromCodepoint(a-1,_.NULL_CELL_CODE,_.NULL_CELL_WIDTH,u)),f.setCellFromCodepoint(this._activeBuffer.x++,s,r,u),r>0)for(;--r;)f.setCellFromCodepoint(this._activeBuffer.x++,0,0,u)}this._parser.precedingJoinState=v,this._activeBuffer.x0&&0===f.getWidth(this._activeBuffer.x)&&!f.hasContent(this._activeBuffer.x)&&f.setCellFromCodepoint(this._activeBuffer.x,0,1,u),this._dirtyRowTracker.markDirty(this._activeBuffer.y)}registerCsiHandler(e,t){return"t"!==e.final||e.prefix||e.intermediates?this._parser.registerCsiHandler(e,t):this._parser.registerCsiHandler(e,(e=>!w(e.params[0],this._optionsService.rawOptions.windowOptions)||t(e)))}registerDcsHandler(e,t){return this._parser.registerDcsHandler(e,new m.DcsHandler(t))}registerEscHandler(e,t){return this._parser.registerEscHandler(e,t)}registerOscHandler(e,t){return this._parser.registerOscHandler(e,new g.OscHandler(t))}bell(){return this._onRequestBell.fire(),!0}lineFeed(){return this._dirtyRowTracker.markDirty(this._activeBuffer.y),this._optionsService.rawOptions.convertEol&&(this._activeBuffer.x=0),this._activeBuffer.y++,this._activeBuffer.y===this._activeBuffer.scrollBottom+1?(this._activeBuffer.y--,this._bufferService.scroll(this._eraseAttrData())):this._activeBuffer.y>=this._bufferService.rows?this._activeBuffer.y=this._bufferService.rows-1:this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y).isWrapped=!1,this._activeBuffer.x>=this._bufferService.cols&&this._activeBuffer.x--,this._dirtyRowTracker.markDirty(this._activeBuffer.y),this._onLineFeed.fire(),!0}carriageReturn(){return this._activeBuffer.x=0,!0}backspace(){if(!this._coreService.decPrivateModes.reverseWraparound)return this._restrictCursor(),this._activeBuffer.x>0&&this._activeBuffer.x--,!0;if(this._restrictCursor(this._bufferService.cols),this._activeBuffer.x>0)this._activeBuffer.x--;else if(0===this._activeBuffer.x&&this._activeBuffer.y>this._activeBuffer.scrollTop&&this._activeBuffer.y<=this._activeBuffer.scrollBottom&&this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y)?.isWrapped){this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y).isWrapped=!1,this._activeBuffer.y--,this._activeBuffer.x=this._bufferService.cols-1;const e=this._activeBuffer.lines.get(this._activeBuffer.ybase+this._activeBuffer.y);e.hasWidth(this._activeBuffer.x)&&!e.hasContent(this._activeBuffer.x)&&this._activeBuffer.x--}return this._restrictCursor(),!0}tab(){if(this._activeBuffer.x>=this._bufferService.cols)return!0;const e=this._activeBuffer.x;return this._activeBuffer.x=this._activeBuffer.nextStop(),this._optionsService.rawOptions.screenReaderMode&&this._onA11yTab.fire(this._activeBuffer.x-e),!0}shiftOut(){return this._charsetService.setgLevel(1),!0}shiftIn(){return this._charsetService.setgLevel(0),!0}_restrictCursor(e=this._bufferService.cols-1){this._activeBuffer.x=Math.min(e,Math.max(0,this._activeBuffer.x)),this._activeBuffer.y=this._coreService.decPrivateModes.origin?Math.min(this._activeBuffer.scrollBottom,Math.max(this._activeBuffer.scrollTop,this._activeBuffer.y)):Math.min(this._bufferService.rows-1,Math.max(0,this._activeBuffer.y)),this._dirtyRowTracker.markDirty(this._activeBuffer.y)}_setCursor(e,t){this._dirtyRowTracker.markDirty(this._activeBuffer.y),this._coreService.decPrivateModes.origin?(this._activeBuffer.x=e,this._activeBuffer.y=this._activeBuffer.scrollTop+t):(this._activeBuffer.x=e,this._activeBuffer.y=t),this._restrictCursor(),this._dirtyRowTracker.markDirty(this._activeBuffer.y)}_moveCursor(e,t){this._restrictCursor(),this._setCursor(this._activeBuffer.x+e,this._activeBuffer.y+t)}cursorUp(e){const t=this._activeBuffer.y-this._activeBuffer.scrollTop;return t>=0?this._moveCursor(0,-Math.min(t,e.params[0]||1)):this._moveCursor(0,-(e.params[0]||1)),!0}cursorDown(e){const t=this._activeBuffer.scrollBottom-this._activeBuffer.y;return t>=0?this._moveCursor(0,Math.min(t,e.params[0]||1)):this._moveCursor(0,e.params[0]||1),!0}cursorForward(e){return this._moveCursor(e.params[0]||1,0),!0}cursorBackward(e){return this._moveCursor(-(e.params[0]||1),0),!0}cursorNextLine(e){return this.cursorDown(e),this._activeBuffer.x=0,!0}cursorPrecedingLine(e){return this.cursorUp(e),this._activeBuffer.x=0,!0}cursorCharAbsolute(e){return this._setCursor((e.params[0]||1)-1,this._activeBuffer.y),!0}cursorPosition(e){return this._setCursor(e.length>=2?(e.params[1]||1)-1:0,(e.params[0]||1)-1),!0}charPosAbsolute(e){return this._setCursor((e.params[0]||1)-1,this._activeBuffer.y),!0}hPositionRelative(e){return this._moveCursor(e.params[0]||1,0),!0}linePosAbsolute(e){return this._setCursor(this._activeBuffer.x,(e.params[0]||1)-1),!0}vPositionRelative(e){return this._moveCursor(0,e.params[0]||1),!0}hVPosition(e){return this.cursorPosition(e),!0}tabClear(e){const t=e.params[0];return 0===t?delete this._activeBuffer.tabs[this._activeBuffer.x]:3===t&&(this._activeBuffer.tabs={}),!0}cursorForwardTab(e){if(this._activeBuffer.x>=this._bufferService.cols)return!0;let t=e.params[0]||1;for(;t--;)this._activeBuffer.x=this._activeBuffer.nextStop();return!0}cursorBackwardTab(e){if(this._activeBuffer.x>=this._bufferService.cols)return!0;let t=e.params[0]||1;for(;t--;)this._activeBuffer.x=this._activeBuffer.prevStop();return!0}selectProtected(e){const t=e.params[0];return 1===t&&(this._curAttrData.bg|=536870912),2!==t&&0!==t||(this._curAttrData.bg&=-536870913),!0}_eraseInBufferLine(e,t,i,s=!1,r=!1){const n=this._activeBuffer.lines.get(this._activeBuffer.ybase+e);n.replaceCells(t,i,this._activeBuffer.getNullCell(this._eraseAttrData()),r),s&&(n.isWrapped=!1)}_resetBufferLine(e,t=!1){const i=this._activeBuffer.lines.get(this._activeBuffer.ybase+e);i&&(i.fill(this._activeBuffer.getNullCell(this._eraseAttrData()),t),this._bufferService.buffer.clearMarkers(this._activeBuffer.ybase+e),i.isWrapped=!1)}eraseInDisplay(e,t=!1){let i;switch(this._restrictCursor(this._bufferService.cols),e.params[0]){case 0:for(i=this._activeBuffer.y,this._dirtyRowTracker.markDirty(i),this._eraseInBufferLine(i++,this._activeBuffer.x,this._bufferService.cols,0===this._activeBuffer.x,t);i=this._bufferService.cols&&(this._activeBuffer.lines.get(i+1).isWrapped=!1);i--;)this._resetBufferLine(i,t);this._dirtyRowTracker.markDirty(0);break;case 2:for(i=this._bufferService.rows,this._dirtyRowTracker.markDirty(i-1);i--;)this._resetBufferLine(i,t);this._dirtyRowTracker.markDirty(0);break;case 3:const e=this._activeBuffer.lines.length-this._bufferService.rows;e>0&&(this._activeBuffer.lines.trimStart(e),this._activeBuffer.ybase=Math.max(this._activeBuffer.ybase-e,0),this._activeBuffer.ydisp=Math.max(this._activeBuffer.ydisp-e,0),this._onScroll.fire(0))}return!0}eraseInLine(e,t=!1){switch(this._restrictCursor(this._bufferService.cols),e.params[0]){case 0:this._eraseInBufferLine(this._activeBuffer.y,this._activeBuffer.x,this._bufferService.cols,0===this._activeBuffer.x,t);break;case 1:this._eraseInBufferLine(this._activeBuffer.y,0,this._activeBuffer.x+1,!1,t);break;case 2:this._eraseInBufferLine(this._activeBuffer.y,0,this._bufferService.cols,!0,t)}return this._dirtyRowTracker.markDirty(this._activeBuffer.y),!0}insertLines(e){this._restrictCursor();let t=e.params[0]||1;if(this._activeBuffer.y>this._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.ythis._activeBuffer.scrollBottom||this._activeBuffer.y65535?2:1}let h=a;for(let e=1;e0||(this._is("xterm")||this._is("rxvt-unicode")||this._is("screen")?this._coreService.triggerDataEvent(n.C0.ESC+"[?1;2c"):this._is("linux")&&this._coreService.triggerDataEvent(n.C0.ESC+"[?6c")),!0}sendDeviceAttributesSecondary(e){return e.params[0]>0||(this._is("xterm")?this._coreService.triggerDataEvent(n.C0.ESC+"[>0;276;0c"):this._is("rxvt-unicode")?this._coreService.triggerDataEvent(n.C0.ESC+"[>85;95;0c"):this._is("linux")?this._coreService.triggerDataEvent(e.params[0]+"c"):this._is("screen")&&this._coreService.triggerDataEvent(n.C0.ESC+"[>83;40003;0c")),!0}_is(e){return 0===(this._optionsService.rawOptions.termName+"").indexOf(e)}setMode(e){for(let t=0;te?1:2,u=e.params[0];return f=u,v=t?2===u?4:4===u?_(o.modes.insertMode):12===u?3:20===u?_(d.convertEol):0:1===u?_(i.applicationCursorKeys):3===u?d.windowOptions.setWinLines?80===h?2:132===h?1:0:0:6===u?_(i.origin):7===u?_(i.wraparound):8===u?3:9===u?_("X10"===s):12===u?_(d.cursorBlink):25===u?_(!o.isCursorHidden):45===u?_(i.reverseWraparound):66===u?_(i.applicationKeypad):67===u?4:1e3===u?_("VT200"===s):1002===u?_("DRAG"===s):1003===u?_("ANY"===s):1004===u?_(i.sendFocus):1005===u?4:1006===u?_("SGR"===r):1015===u?4:1016===u?_("SGR_PIXELS"===r):1048===u?1:47===u||1047===u||1049===u?_(c===l):2004===u?_(i.bracketedPasteMode):0,o.triggerDataEvent(`${n.C0.ESC}[${t?"":"?"}${f};${v}$y`),!0;var f,v}_updateAttrColor(e,t,i,s,r){return 2===t?(e|=50331648,e&=-16777216,e|=f.AttributeData.fromColorRGB([i,s,r])):5===t&&(e&=-50331904,e|=33554432|255&i),e}_extractColor(e,t,i){const s=[0,0,-1,0,0,0];let r=0,n=0;do{if(s[n+r]=e.params[t+n],e.hasSubParams(t+n)){const i=e.getSubParams(t+n);let o=0;do{5===s[1]&&(r=1),s[n+o+1+r]=i[o]}while(++o=2||2===s[1]&&n+r>=5)break;s[1]&&(r=1)}while(++n+t5)&&(e=1),t.extended.underlineStyle=e,t.fg|=268435456,0===e&&(t.fg&=-268435457),t.updateExtended()}_processSGR0(e){e.fg=l.DEFAULT_ATTR_DATA.fg,e.bg=l.DEFAULT_ATTR_DATA.bg,e.extended=e.extended.clone(),e.extended.underlineStyle=0,e.extended.underlineColor&=-67108864,e.updateExtended()}charAttributes(e){if(1===e.length&&0===e.params[0])return this._processSGR0(this._curAttrData),!0;const t=e.length;let i;const s=this._curAttrData;for(let r=0;r=30&&i<=37?(s.fg&=-50331904,s.fg|=16777216|i-30):i>=40&&i<=47?(s.bg&=-50331904,s.bg|=16777216|i-40):i>=90&&i<=97?(s.fg&=-50331904,s.fg|=16777224|i-90):i>=100&&i<=107?(s.bg&=-50331904,s.bg|=16777224|i-100):0===i?this._processSGR0(s):1===i?s.fg|=134217728:3===i?s.bg|=67108864:4===i?(s.fg|=268435456,this._processUnderline(e.hasSubParams(r)?e.getSubParams(r)[0]:1,s)):5===i?s.fg|=536870912:7===i?s.fg|=67108864:8===i?s.fg|=1073741824:9===i?s.fg|=2147483648:2===i?s.bg|=134217728:21===i?this._processUnderline(2,s):22===i?(s.fg&=-134217729,s.bg&=-134217729):23===i?s.bg&=-67108865:24===i?(s.fg&=-268435457,this._processUnderline(0,s)):25===i?s.fg&=-536870913:27===i?s.fg&=-67108865:28===i?s.fg&=-1073741825:29===i?s.fg&=2147483647:39===i?(s.fg&=-67108864,s.fg|=16777215&l.DEFAULT_ATTR_DATA.fg):49===i?(s.bg&=-67108864,s.bg|=16777215&l.DEFAULT_ATTR_DATA.bg):38===i||48===i||58===i?r+=this._extractColor(e,r,s):53===i?s.bg|=1073741824:55===i?s.bg&=-1073741825:59===i?(s.extended=s.extended.clone(),s.extended.underlineColor=-1,s.updateExtended()):100===i?(s.fg&=-67108864,s.fg|=16777215&l.DEFAULT_ATTR_DATA.fg,s.bg&=-67108864,s.bg|=16777215&l.DEFAULT_ATTR_DATA.bg):this._logService.debug("Unknown SGR attribute: %d.",i);return!0}deviceStatus(e){switch(e.params[0]){case 5:this._coreService.triggerDataEvent(`${n.C0.ESC}[0n`);break;case 6:const e=this._activeBuffer.y+1,t=this._activeBuffer.x+1;this._coreService.triggerDataEvent(`${n.C0.ESC}[${e};${t}R`)}return!0}deviceStatusPrivate(e){if(6===e.params[0]){const e=this._activeBuffer.y+1,t=this._activeBuffer.x+1;this._coreService.triggerDataEvent(`${n.C0.ESC}[?${e};${t}R`)}return!0}softReset(e){return this._coreService.isCursorHidden=!1,this._onRequestSyncScrollBar.fire(),this._activeBuffer.scrollTop=0,this._activeBuffer.scrollBottom=this._bufferService.rows-1,this._curAttrData=l.DEFAULT_ATTR_DATA.clone(),this._coreService.reset(),this._charsetService.reset(),this._activeBuffer.savedX=0,this._activeBuffer.savedY=this._activeBuffer.ybase,this._activeBuffer.savedCurAttrData.fg=this._curAttrData.fg,this._activeBuffer.savedCurAttrData.bg=this._curAttrData.bg,this._activeBuffer.savedCharset=this._charsetService.charset,this._coreService.decPrivateModes.origin=!1,!0}setCursorStyle(e){const t=e.params[0]||1;switch(t){case 1:case 2:this._optionsService.options.cursorStyle="block";break;case 3:case 4:this._optionsService.options.cursorStyle="underline";break;case 5:case 6:this._optionsService.options.cursorStyle="bar"}const i=t%2==1;return this._optionsService.options.cursorBlink=i,!0}setScrollRegion(e){const t=e.params[0]||1;let i;return(e.length<2||(i=e.params[1])>this._bufferService.rows||0===i)&&(i=this._bufferService.rows),i>t&&(this._activeBuffer.scrollTop=t-1,this._activeBuffer.scrollBottom=i-1,this._setCursor(0,0)),!0}windowOptions(e){if(!w(e.params[0],this._optionsService.rawOptions.windowOptions))return!0;const t=e.length>1?e.params[1]:0;switch(e.params[0]){case 14:2!==t&&this._onRequestWindowsOptionsReport.fire(y.GET_WIN_SIZE_PIXELS);break;case 16:this._onRequestWindowsOptionsReport.fire(y.GET_CELL_SIZE_PIXELS);break;case 18:this._bufferService&&this._coreService.triggerDataEvent(`${n.C0.ESC}[8;${this._bufferService.rows};${this._bufferService.cols}t`);break;case 22:0!==t&&2!==t||(this._windowTitleStack.push(this._windowTitle),this._windowTitleStack.length>10&&this._windowTitleStack.shift()),0!==t&&1!==t||(this._iconNameStack.push(this._iconName),this._iconNameStack.length>10&&this._iconNameStack.shift());break;case 23:0!==t&&2!==t||this._windowTitleStack.length&&this.setTitle(this._windowTitleStack.pop()),0!==t&&1!==t||this._iconNameStack.length&&this.setIconName(this._iconNameStack.pop())}return!0}saveCursor(e){return this._activeBuffer.savedX=this._activeBuffer.x,this._activeBuffer.savedY=this._activeBuffer.ybase+this._activeBuffer.y,this._activeBuffer.savedCurAttrData.fg=this._curAttrData.fg,this._activeBuffer.savedCurAttrData.bg=this._curAttrData.bg,this._activeBuffer.savedCharset=this._charsetService.charset,!0}restoreCursor(e){return this._activeBuffer.x=this._activeBuffer.savedX||0,this._activeBuffer.y=Math.max(this._activeBuffer.savedY-this._activeBuffer.ybase,0),this._curAttrData.fg=this._activeBuffer.savedCurAttrData.fg,this._curAttrData.bg=this._activeBuffer.savedCurAttrData.bg,this._charsetService.charset=this._savedCharset,this._activeBuffer.savedCharset&&(this._charsetService.charset=this._activeBuffer.savedCharset),this._restrictCursor(),!0}setTitle(e){return this._windowTitle=e,this._onTitleChange.fire(e),!0}setIconName(e){return this._iconName=e,!0}setOrReportIndexedColor(e){const t=[],i=e.split(";");for(;i.length>1;){const e=i.shift(),s=i.shift();if(/^\d+$/.exec(e)){const i=parseInt(e);if(D(i))if("?"===s)t.push({type:0,index:i});else{const e=(0,S.parseColor)(s);e&&t.push({type:1,index:i,color:e})}}}return t.length&&this._onColor.fire(t),!0}setHyperlink(e){const t=e.split(";");return!(t.length<2)&&(t[1]?this._createHyperlink(t[0],t[1]):!t[0]&&this._finishHyperlink())}_createHyperlink(e,t){this._getCurrentLinkId()&&this._finishHyperlink();const i=e.split(":");let s;const r=i.findIndex((e=>e.startsWith("id=")));return-1!==r&&(s=i[r].slice(3)||void 0),this._curAttrData.extended=this._curAttrData.extended.clone(),this._curAttrData.extended.urlId=this._oscLinkService.registerLink({id:s,uri:t}),this._curAttrData.updateExtended(),!0}_finishHyperlink(){return this._curAttrData.extended=this._curAttrData.extended.clone(),this._curAttrData.extended.urlId=0,this._curAttrData.updateExtended(),!0}_setOrReportSpecialColor(e,t){const i=e.split(";");for(let e=0;e=this._specialColors.length);++e,++t)if("?"===i[e])this._onColor.fire([{type:0,index:this._specialColors[t]}]);else{const s=(0,S.parseColor)(i[e]);s&&this._onColor.fire([{type:1,index:this._specialColors[t],color:s}])}return!0}setOrReportFgColor(e){return this._setOrReportSpecialColor(e,0)}setOrReportBgColor(e){return this._setOrReportSpecialColor(e,1)}setOrReportCursorColor(e){return this._setOrReportSpecialColor(e,2)}restoreIndexedColor(e){if(!e)return this._onColor.fire([{type:2}]),!0;const t=[],i=e.split(";");for(let e=0;e=this._bufferService.rows&&(this._activeBuffer.y=this._bufferService.rows-1),this._restrictCursor(),!0}tabSet(){return this._activeBuffer.tabs[this._activeBuffer.x]=!0,!0}reverseIndex(){if(this._restrictCursor(),this._activeBuffer.y===this._activeBuffer.scrollTop){const e=this._activeBuffer.scrollBottom-this._activeBuffer.scrollTop;this._activeBuffer.lines.shiftElements(this._activeBuffer.ybase+this._activeBuffer.y,e,1),this._activeBuffer.lines.set(this._activeBuffer.ybase+this._activeBuffer.y,this._activeBuffer.getBlankLine(this._eraseAttrData())),this._dirtyRowTracker.markRangeDirty(this._activeBuffer.scrollTop,this._activeBuffer.scrollBottom)}else this._activeBuffer.y--,this._restrictCursor();return!0}fullReset(){return this._parser.reset(),this._onRequestReset.fire(),!0}reset(){this._curAttrData=l.DEFAULT_ATTR_DATA.clone(),this._eraseAttrDataInternal=l.DEFAULT_ATTR_DATA.clone()}_eraseAttrData(){return this._eraseAttrDataInternal.bg&=-67108864,this._eraseAttrDataInternal.bg|=67108863&this._curAttrData.bg,this._eraseAttrDataInternal}setgLevel(e){return this._charsetService.setgLevel(e),!0}screenAlignmentPattern(){const e=new u.CellData;e.content=1<<22|"E".charCodeAt(0),e.fg=this._curAttrData.fg,e.bg=this._curAttrData.bg,this._setCursor(0,0);for(let t=0;t(this._coreService.triggerDataEvent(`${n.C0.ESC}${e}${n.C0.ESC}\\`),!0))('"q'===e?`P1$r${this._curAttrData.isProtected()?1:0}"q`:'"p'===e?'P1$r61;1"p':"r"===e?`P1$r${i.scrollTop+1};${i.scrollBottom+1}r`:"m"===e?"P1$r0m":" q"===e?`P1$r${{block:2,underline:4,bar:6}[s.cursorStyle]-(s.cursorBlink?1:0)} q`:"P0$r")}markRangeDirty(e,t){this._dirtyRowTracker.markRangeDirty(e,t)}}t.InputHandler=k;let L=class{constructor(e){this._bufferService=e,this.clearRange()}clearRange(){this.start=this._bufferService.buffer.y,this.end=this._bufferService.buffer.y}markDirty(e){ethis.end&&(this.end=e)}markRangeDirty(e,t){e>t&&(E=e,e=t,t=E),ethis.end&&(this.end=t)}markAllDirty(){this.markRangeDirty(0,this._bufferService.rows-1)}};function D(e){return 0<=e&&e<256}L=s([r(0,v.IBufferService)],L)},844:(e,t)=>{function i(e){for(const t of e)t.dispose();e.length=0}Object.defineProperty(t,"__esModule",{value:!0}),t.getDisposeArrayDisposable=t.disposeArray=t.toDisposable=t.MutableDisposable=t.Disposable=void 0,t.Disposable=class{constructor(){this._disposables=[],this._isDisposed=!1}dispose(){this._isDisposed=!0;for(const e of this._disposables)e.dispose();this._disposables.length=0}register(e){return this._disposables.push(e),e}unregister(e){const t=this._disposables.indexOf(e);-1!==t&&this._disposables.splice(t,1)}},t.MutableDisposable=class{constructor(){this._isDisposed=!1}get value(){return this._isDisposed?void 0:this._value}set value(e){this._isDisposed||e===this._value||(this._value?.dispose(),this._value=e)}clear(){this.value=void 0}dispose(){this._isDisposed=!0,this._value?.dispose(),this._value=void 0}},t.toDisposable=function(e){return{dispose:e}},t.disposeArray=i,t.getDisposeArrayDisposable=function(e){return{dispose:()=>i(e)}}},1505:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.FourKeyMap=t.TwoKeyMap=void 0;class i{constructor(){this._data={}}set(e,t,i){this._data[e]||(this._data[e]={}),this._data[e][t]=i}get(e,t){return this._data[e]?this._data[e][t]:void 0}clear(){this._data={}}}t.TwoKeyMap=i,t.FourKeyMap=class{constructor(){this._data=new i}set(e,t,s,r,n){this._data.get(e,t)||this._data.set(e,t,new i),this._data.get(e,t).set(s,r,n)}get(e,t,i,s){return this._data.get(e,t)?.get(i,s)}clear(){this._data.clear()}}},6114:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.isChromeOS=t.isLinux=t.isWindows=t.isIphone=t.isIpad=t.isMac=t.getSafariVersion=t.isSafari=t.isLegacyEdge=t.isFirefox=t.isNode=void 0,t.isNode="undefined"!=typeof process;const i=t.isNode?"node":navigator.userAgent,s=t.isNode?"node":navigator.platform;t.isFirefox=i.includes("Firefox"),t.isLegacyEdge=i.includes("Edge"),t.isSafari=/^((?!chrome|android).)*safari/i.test(i),t.getSafariVersion=function(){if(!t.isSafari)return 0;const e=i.match(/Version\/(\d+)/);return null===e||e.length<2?0:parseInt(e[1])},t.isMac=["Macintosh","MacIntel","MacPPC","Mac68K"].includes(s),t.isIpad="iPad"===s,t.isIphone="iPhone"===s,t.isWindows=["Windows","Win16","Win32","WinCE"].includes(s),t.isLinux=s.indexOf("Linux")>=0,t.isChromeOS=/\bCrOS\b/.test(i)},6106:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.SortedList=void 0;let i=0;t.SortedList=class{constructor(e){this._getKey=e,this._array=[]}clear(){this._array.length=0}insert(e){0!==this._array.length?(i=this._search(this._getKey(e)),this._array.splice(i,0,e)):this._array.push(e)}delete(e){if(0===this._array.length)return!1;const t=this._getKey(e);if(void 0===t)return!1;if(i=this._search(t),-1===i)return!1;if(this._getKey(this._array[i])!==t)return!1;do{if(this._array[i]===e)return this._array.splice(i,1),!0}while(++i=this._array.length)&&this._getKey(this._array[i])===e))do{yield this._array[i]}while(++i=this._array.length)&&this._getKey(this._array[i])===e))do{t(this._array[i])}while(++i=t;){let s=t+i>>1;const r=this._getKey(this._array[s]);if(r>e)i=s-1;else{if(!(r0&&this._getKey(this._array[s-1])===e;)s--;return s}t=s+1}}return t}}},7226:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DebouncedIdleTask=t.IdleTaskQueue=t.PriorityTaskQueue=void 0;const s=i(6114);class r{constructor(){this._tasks=[],this._i=0}enqueue(e){this._tasks.push(e),this._start()}flush(){for(;this._ir)return s-t<-20&&console.warn(`task queue exceeded allotted deadline by ${Math.abs(Math.round(s-t))}ms`),void this._start();s=r}this.clear()}}class n extends r{_requestCallback(e){return setTimeout((()=>e(this._createDeadline(16))))}_cancelCallback(e){clearTimeout(e)}_createDeadline(e){const t=Date.now()+e;return{timeRemaining:()=>Math.max(0,t-Date.now())}}}t.PriorityTaskQueue=n,t.IdleTaskQueue=!s.isNode&&"requestIdleCallback"in window?class extends r{_requestCallback(e){return requestIdleCallback(e)}_cancelCallback(e){cancelIdleCallback(e)}}:n,t.DebouncedIdleTask=class{constructor(){this._queue=new t.IdleTaskQueue}set(e){this._queue.clear(),this._queue.enqueue(e)}flush(){this._queue.flush()}}},9282:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.updateWindowsModeWrappedState=void 0;const s=i(643);t.updateWindowsModeWrappedState=function(e){const t=e.buffer.lines.get(e.buffer.ybase+e.buffer.y-1),i=t?.get(e.cols-1),r=e.buffer.lines.get(e.buffer.ybase+e.buffer.y);r&&i&&(r.isWrapped=i[s.CHAR_DATA_CODE_INDEX]!==s.NULL_CELL_CODE&&i[s.CHAR_DATA_CODE_INDEX]!==s.WHITESPACE_CELL_CODE)}},3734:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ExtendedAttrs=t.AttributeData=void 0;class i{constructor(){this.fg=0,this.bg=0,this.extended=new s}static toColorRGB(e){return[e>>>16&255,e>>>8&255,255&e]}static fromColorRGB(e){return(255&e[0])<<16|(255&e[1])<<8|255&e[2]}clone(){const e=new i;return e.fg=this.fg,e.bg=this.bg,e.extended=this.extended.clone(),e}isInverse(){return 67108864&this.fg}isBold(){return 134217728&this.fg}isUnderline(){return this.hasExtendedAttrs()&&0!==this.extended.underlineStyle?1:268435456&this.fg}isBlink(){return 536870912&this.fg}isInvisible(){return 1073741824&this.fg}isItalic(){return 67108864&this.bg}isDim(){return 134217728&this.bg}isStrikethrough(){return 2147483648&this.fg}isProtected(){return 536870912&this.bg}isOverline(){return 1073741824&this.bg}getFgColorMode(){return 50331648&this.fg}getBgColorMode(){return 50331648&this.bg}isFgRGB(){return 50331648==(50331648&this.fg)}isBgRGB(){return 50331648==(50331648&this.bg)}isFgPalette(){return 16777216==(50331648&this.fg)||33554432==(50331648&this.fg)}isBgPalette(){return 16777216==(50331648&this.bg)||33554432==(50331648&this.bg)}isFgDefault(){return 0==(50331648&this.fg)}isBgDefault(){return 0==(50331648&this.bg)}isAttributeDefault(){return 0===this.fg&&0===this.bg}getFgColor(){switch(50331648&this.fg){case 16777216:case 33554432:return 255&this.fg;case 50331648:return 16777215&this.fg;default:return-1}}getBgColor(){switch(50331648&this.bg){case 16777216:case 33554432:return 255&this.bg;case 50331648:return 16777215&this.bg;default:return-1}}hasExtendedAttrs(){return 268435456&this.bg}updateExtended(){this.extended.isEmpty()?this.bg&=-268435457:this.bg|=268435456}getUnderlineColor(){if(268435456&this.bg&&~this.extended.underlineColor)switch(50331648&this.extended.underlineColor){case 16777216:case 33554432:return 255&this.extended.underlineColor;case 50331648:return 16777215&this.extended.underlineColor;default:return this.getFgColor()}return this.getFgColor()}getUnderlineColorMode(){return 268435456&this.bg&&~this.extended.underlineColor?50331648&this.extended.underlineColor:this.getFgColorMode()}isUnderlineColorRGB(){return 268435456&this.bg&&~this.extended.underlineColor?50331648==(50331648&this.extended.underlineColor):this.isFgRGB()}isUnderlineColorPalette(){return 268435456&this.bg&&~this.extended.underlineColor?16777216==(50331648&this.extended.underlineColor)||33554432==(50331648&this.extended.underlineColor):this.isFgPalette()}isUnderlineColorDefault(){return 268435456&this.bg&&~this.extended.underlineColor?0==(50331648&this.extended.underlineColor):this.isFgDefault()}getUnderlineStyle(){return 268435456&this.fg?268435456&this.bg?this.extended.underlineStyle:1:0}getUnderlineVariantOffset(){return this.extended.underlineVariantOffset}}t.AttributeData=i;class s{get ext(){return this._urlId?-469762049&this._ext|this.underlineStyle<<26:this._ext}set ext(e){this._ext=e}get underlineStyle(){return this._urlId?5:(469762048&this._ext)>>26}set underlineStyle(e){this._ext&=-469762049,this._ext|=e<<26&469762048}get underlineColor(){return 67108863&this._ext}set underlineColor(e){this._ext&=-67108864,this._ext|=67108863&e}get urlId(){return this._urlId}set urlId(e){this._urlId=e}get underlineVariantOffset(){const e=(3758096384&this._ext)>>29;return e<0?4294967288^e:e}set underlineVariantOffset(e){this._ext&=536870911,this._ext|=e<<29&3758096384}constructor(e=0,t=0){this._ext=0,this._urlId=0,this._ext=e,this._urlId=t}clone(){return new s(this._ext,this._urlId)}isEmpty(){return 0===this.underlineStyle&&0===this._urlId}}t.ExtendedAttrs=s},9092:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Buffer=t.MAX_BUFFER_SIZE=void 0;const s=i(6349),r=i(7226),n=i(3734),o=i(8437),a=i(4634),h=i(511),c=i(643),l=i(4863),d=i(7116);t.MAX_BUFFER_SIZE=4294967295,t.Buffer=class{constructor(e,t,i){this._hasScrollback=e,this._optionsService=t,this._bufferService=i,this.ydisp=0,this.ybase=0,this.y=0,this.x=0,this.tabs={},this.savedY=0,this.savedX=0,this.savedCurAttrData=o.DEFAULT_ATTR_DATA.clone(),this.savedCharset=d.DEFAULT_CHARSET,this.markers=[],this._nullCell=h.CellData.fromCharData([0,c.NULL_CELL_CHAR,c.NULL_CELL_WIDTH,c.NULL_CELL_CODE]),this._whitespaceCell=h.CellData.fromCharData([0,c.WHITESPACE_CELL_CHAR,c.WHITESPACE_CELL_WIDTH,c.WHITESPACE_CELL_CODE]),this._isClearing=!1,this._memoryCleanupQueue=new r.IdleTaskQueue,this._memoryCleanupPosition=0,this._cols=this._bufferService.cols,this._rows=this._bufferService.rows,this.lines=new s.CircularList(this._getCorrectBufferLength(this._rows)),this.scrollTop=0,this.scrollBottom=this._rows-1,this.setupTabStops()}getNullCell(e){return e?(this._nullCell.fg=e.fg,this._nullCell.bg=e.bg,this._nullCell.extended=e.extended):(this._nullCell.fg=0,this._nullCell.bg=0,this._nullCell.extended=new n.ExtendedAttrs),this._nullCell}getWhitespaceCell(e){return e?(this._whitespaceCell.fg=e.fg,this._whitespaceCell.bg=e.bg,this._whitespaceCell.extended=e.extended):(this._whitespaceCell.fg=0,this._whitespaceCell.bg=0,this._whitespaceCell.extended=new n.ExtendedAttrs),this._whitespaceCell}getBlankLine(e,t){return new o.BufferLine(this._bufferService.cols,this.getNullCell(e),t)}get hasScrollback(){return this._hasScrollback&&this.lines.maxLength>this._rows}get isCursorInViewport(){const e=this.ybase+this.y-this.ydisp;return e>=0&&et.MAX_BUFFER_SIZE?t.MAX_BUFFER_SIZE:i}fillViewportRows(e){if(0===this.lines.length){void 0===e&&(e=o.DEFAULT_ATTR_DATA);let t=this._rows;for(;t--;)this.lines.push(this.getBlankLine(e))}}clear(){this.ydisp=0,this.ybase=0,this.y=0,this.x=0,this.lines=new s.CircularList(this._getCorrectBufferLength(this._rows)),this.scrollTop=0,this.scrollBottom=this._rows-1,this.setupTabStops()}resize(e,t){const i=this.getNullCell(o.DEFAULT_ATTR_DATA);let s=0;const r=this._getCorrectBufferLength(t);if(r>this.lines.maxLength&&(this.lines.maxLength=r),this.lines.length>0){if(this._cols0&&this.lines.length<=this.ybase+this.y+n+1?(this.ybase--,n++,this.ydisp>0&&this.ydisp--):this.lines.push(new o.BufferLine(e,i)));else for(let e=this._rows;e>t;e--)this.lines.length>t+this.ybase&&(this.lines.length>this.ybase+this.y+1?this.lines.pop():(this.ybase++,this.ydisp++));if(r0&&(this.lines.trimStart(e),this.ybase=Math.max(this.ybase-e,0),this.ydisp=Math.max(this.ydisp-e,0),this.savedY=Math.max(this.savedY-e,0)),this.lines.maxLength=r}this.x=Math.min(this.x,e-1),this.y=Math.min(this.y,t-1),n&&(this.y+=n),this.savedX=Math.min(this.savedX,e-1),this.scrollTop=0}if(this.scrollBottom=t-1,this._isReflowEnabled&&(this._reflow(e,t),this._cols>e))for(let t=0;t.1*this.lines.length&&(this._memoryCleanupPosition=0,this._memoryCleanupQueue.enqueue((()=>this._batchedMemoryCleanup())))}_batchedMemoryCleanup(){let e=!0;this._memoryCleanupPosition>=this.lines.length&&(this._memoryCleanupPosition=0,e=!1);let t=0;for(;this._memoryCleanupPosition100)return!0;return e}get _isReflowEnabled(){const e=this._optionsService.rawOptions.windowsPty;return e&&e.buildNumber?this._hasScrollback&&"conpty"===e.backend&&e.buildNumber>=21376:this._hasScrollback&&!this._optionsService.rawOptions.windowsMode}_reflow(e,t){this._cols!==e&&(e>this._cols?this._reflowLarger(e,t):this._reflowSmaller(e,t))}_reflowLarger(e,t){const i=(0,a.reflowLargerGetLinesToRemove)(this.lines,this._cols,e,this.ybase+this.y,this.getNullCell(o.DEFAULT_ATTR_DATA));if(i.length>0){const s=(0,a.reflowLargerCreateNewLayout)(this.lines,i);(0,a.reflowLargerApplyNewLayout)(this.lines,s.layout),this._reflowLargerAdjustViewport(e,t,s.countRemoved)}}_reflowLargerAdjustViewport(e,t,i){const s=this.getNullCell(o.DEFAULT_ATTR_DATA);let r=i;for(;r-- >0;)0===this.ybase?(this.y>0&&this.y--,this.lines.length=0;n--){let h=this.lines.get(n);if(!h||!h.isWrapped&&h.getTrimmedLength()<=e)continue;const c=[h];for(;h.isWrapped&&n>0;)h=this.lines.get(--n),c.unshift(h);const l=this.ybase+this.y;if(l>=n&&l0&&(s.push({start:n+c.length+r,newLines:v}),r+=v.length),c.push(...v);let p=_.length-1,g=_[p];0===g&&(p--,g=_[p]);let m=c.length-u-1,S=d;for(;m>=0;){const e=Math.min(S,g);if(void 0===c[p])break;if(c[p].copyCellsFrom(c[m],S-e,g-e,e,!0),g-=e,0===g&&(p--,g=_[p]),S-=e,0===S){m--;const e=Math.max(m,0);S=(0,a.getWrappedLineTrimmedLength)(c,e,this._cols)}}for(let t=0;t0;)0===this.ybase?this.y0){const e=[],t=[];for(let e=0;e=0;c--)if(a&&a.start>n+h){for(let e=a.newLines.length-1;e>=0;e--)this.lines.set(c--,a.newLines[e]);c++,e.push({index:n+1,amount:a.newLines.length}),h+=a.newLines.length,a=s[++o]}else this.lines.set(c,t[n--]);let c=0;for(let t=e.length-1;t>=0;t--)e[t].index+=c,this.lines.onInsertEmitter.fire(e[t]),c+=e[t].amount;const l=Math.max(0,i+r-this.lines.maxLength);l>0&&this.lines.onTrimEmitter.fire(l)}}translateBufferLineToString(e,t,i=0,s){const r=this.lines.get(e);return r?r.translateToString(t,i,s):""}getWrappedRangeForLine(e){let t=e,i=e;for(;t>0&&this.lines.get(t).isWrapped;)t--;for(;i+10;);return e>=this._cols?this._cols-1:e<0?0:e}nextStop(e){for(null==e&&(e=this.x);!this.tabs[++e]&&e=this._cols?this._cols-1:e<0?0:e}clearMarkers(e){this._isClearing=!0;for(let t=0;t{t.line-=e,t.line<0&&t.dispose()}))),t.register(this.lines.onInsert((e=>{t.line>=e.index&&(t.line+=e.amount)}))),t.register(this.lines.onDelete((e=>{t.line>=e.index&&t.linee.index&&(t.line-=e.amount)}))),t.register(t.onDispose((()=>this._removeMarker(t)))),t}_removeMarker(e){this._isClearing||this.markers.splice(this.markers.indexOf(e),1)}}},8437:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferLine=t.DEFAULT_ATTR_DATA=void 0;const s=i(3734),r=i(511),n=i(643),o=i(482);t.DEFAULT_ATTR_DATA=Object.freeze(new s.AttributeData);let a=0;class h{constructor(e,t,i=!1){this.isWrapped=i,this._combined={},this._extendedAttrs={},this._data=new Uint32Array(3*e);const s=t||r.CellData.fromCharData([0,n.NULL_CELL_CHAR,n.NULL_CELL_WIDTH,n.NULL_CELL_CODE]);for(let t=0;t>22,2097152&t?this._combined[e].charCodeAt(this._combined[e].length-1):i]}set(e,t){this._data[3*e+1]=t[n.CHAR_DATA_ATTR_INDEX],t[n.CHAR_DATA_CHAR_INDEX].length>1?(this._combined[e]=t[1],this._data[3*e+0]=2097152|e|t[n.CHAR_DATA_WIDTH_INDEX]<<22):this._data[3*e+0]=t[n.CHAR_DATA_CHAR_INDEX].charCodeAt(0)|t[n.CHAR_DATA_WIDTH_INDEX]<<22}getWidth(e){return this._data[3*e+0]>>22}hasWidth(e){return 12582912&this._data[3*e+0]}getFg(e){return this._data[3*e+1]}getBg(e){return this._data[3*e+2]}hasContent(e){return 4194303&this._data[3*e+0]}getCodePoint(e){const t=this._data[3*e+0];return 2097152&t?this._combined[e].charCodeAt(this._combined[e].length-1):2097151&t}isCombined(e){return 2097152&this._data[3*e+0]}getString(e){const t=this._data[3*e+0];return 2097152&t?this._combined[e]:2097151&t?(0,o.stringFromCodePoint)(2097151&t):""}isProtected(e){return 536870912&this._data[3*e+2]}loadCell(e,t){return a=3*e,t.content=this._data[a+0],t.fg=this._data[a+1],t.bg=this._data[a+2],2097152&t.content&&(t.combinedData=this._combined[e]),268435456&t.bg&&(t.extended=this._extendedAttrs[e]),t}setCell(e,t){2097152&t.content&&(this._combined[e]=t.combinedData),268435456&t.bg&&(this._extendedAttrs[e]=t.extended),this._data[3*e+0]=t.content,this._data[3*e+1]=t.fg,this._data[3*e+2]=t.bg}setCellFromCodepoint(e,t,i,s){268435456&s.bg&&(this._extendedAttrs[e]=s.extended),this._data[3*e+0]=t|i<<22,this._data[3*e+1]=s.fg,this._data[3*e+2]=s.bg}addCodepointToCell(e,t,i){let s=this._data[3*e+0];2097152&s?this._combined[e]+=(0,o.stringFromCodePoint)(t):2097151&s?(this._combined[e]=(0,o.stringFromCodePoint)(2097151&s)+(0,o.stringFromCodePoint)(t),s&=-2097152,s|=2097152):s=t|1<<22,i&&(s&=-12582913,s|=i<<22),this._data[3*e+0]=s}insertCells(e,t,i){if((e%=this.length)&&2===this.getWidth(e-1)&&this.setCellFromCodepoint(e-1,0,1,i),t=0;--i)this.setCell(e+t+i,this.loadCell(e+i,s));for(let s=0;sthis.length){if(this._data.buffer.byteLength>=4*i)this._data=new Uint32Array(this._data.buffer,0,i);else{const e=new Uint32Array(i);e.set(this._data),this._data=e}for(let i=this.length;i=e&&delete this._combined[s]}const s=Object.keys(this._extendedAttrs);for(let t=0;t=e&&delete this._extendedAttrs[i]}}return this.length=e,4*i*2=0;--e)if(4194303&this._data[3*e+0])return e+(this._data[3*e+0]>>22);return 0}getNoBgTrimmedLength(){for(let e=this.length-1;e>=0;--e)if(4194303&this._data[3*e+0]||50331648&this._data[3*e+2])return e+(this._data[3*e+0]>>22);return 0}copyCellsFrom(e,t,i,s,r){const n=e._data;if(r)for(let r=s-1;r>=0;r--){for(let e=0;e<3;e++)this._data[3*(i+r)+e]=n[3*(t+r)+e];268435456&n[3*(t+r)+2]&&(this._extendedAttrs[i+r]=e._extendedAttrs[t+r])}else for(let r=0;r=t&&(this._combined[r-t+i]=e._combined[r])}}translateToString(e,t,i,s){t=t??0,i=i??this.length,e&&(i=Math.min(i,this.getTrimmedLength())),s&&(s.length=0);let r="";for(;t>22||1}return s&&s.push(t),r}}t.BufferLine=h},4841:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.getRangeLength=void 0,t.getRangeLength=function(e,t){if(e.start.y>e.end.y)throw new Error(`Buffer range end (${e.end.x}, ${e.end.y}) cannot be before start (${e.start.x}, ${e.start.y})`);return t*(e.end.y-e.start.y)+(e.end.x-e.start.x+1)}},4634:(e,t)=>{function i(e,t,i){if(t===e.length-1)return e[t].getTrimmedLength();const s=!e[t].hasContent(i-1)&&1===e[t].getWidth(i-1),r=2===e[t+1].getWidth(0);return s&&r?i-1:i}Object.defineProperty(t,"__esModule",{value:!0}),t.getWrappedLineTrimmedLength=t.reflowSmallerGetNewLineLengths=t.reflowLargerApplyNewLayout=t.reflowLargerCreateNewLayout=t.reflowLargerGetLinesToRemove=void 0,t.reflowLargerGetLinesToRemove=function(e,t,s,r,n){const o=[];for(let a=0;a=a&&r0&&(e>d||0===l[e].getTrimmedLength());e--)v++;v>0&&(o.push(a+l.length-v),o.push(v)),a+=l.length-1}return o},t.reflowLargerCreateNewLayout=function(e,t){const i=[];let s=0,r=t[s],n=0;for(let o=0;oi(e,r,t))).reduce(((e,t)=>e+t));let o=0,a=0,h=0;for(;hc&&(o-=c,a++);const l=2===e[a].getWidth(o-1);l&&o--;const d=l?s-1:s;r.push(d),h+=d}return r},t.getWrappedLineTrimmedLength=i},5295:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferSet=void 0;const s=i(8460),r=i(844),n=i(9092);class o extends r.Disposable{constructor(e,t){super(),this._optionsService=e,this._bufferService=t,this._onBufferActivate=this.register(new s.EventEmitter),this.onBufferActivate=this._onBufferActivate.event,this.reset(),this.register(this._optionsService.onSpecificOptionChange("scrollback",(()=>this.resize(this._bufferService.cols,this._bufferService.rows)))),this.register(this._optionsService.onSpecificOptionChange("tabStopWidth",(()=>this.setupTabStops())))}reset(){this._normal=new n.Buffer(!0,this._optionsService,this._bufferService),this._normal.fillViewportRows(),this._alt=new n.Buffer(!1,this._optionsService,this._bufferService),this._activeBuffer=this._normal,this._onBufferActivate.fire({activeBuffer:this._normal,inactiveBuffer:this._alt}),this.setupTabStops()}get alt(){return this._alt}get active(){return this._activeBuffer}get normal(){return this._normal}activateNormalBuffer(){this._activeBuffer!==this._normal&&(this._normal.x=this._alt.x,this._normal.y=this._alt.y,this._alt.clearAllMarkers(),this._alt.clear(),this._activeBuffer=this._normal,this._onBufferActivate.fire({activeBuffer:this._normal,inactiveBuffer:this._alt}))}activateAltBuffer(e){this._activeBuffer!==this._alt&&(this._alt.fillViewportRows(e),this._alt.x=this._normal.x,this._alt.y=this._normal.y,this._activeBuffer=this._alt,this._onBufferActivate.fire({activeBuffer:this._alt,inactiveBuffer:this._normal}))}resize(e,t){this._normal.resize(e,t),this._alt.resize(e,t),this.setupTabStops(e)}setupTabStops(e){this._normal.setupTabStops(e),this._alt.setupTabStops(e)}}t.BufferSet=o},511:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.CellData=void 0;const s=i(482),r=i(643),n=i(3734);class o extends n.AttributeData{constructor(){super(...arguments),this.content=0,this.fg=0,this.bg=0,this.extended=new n.ExtendedAttrs,this.combinedData=""}static fromCharData(e){const t=new o;return t.setFromCharData(e),t}isCombined(){return 2097152&this.content}getWidth(){return this.content>>22}getChars(){return 2097152&this.content?this.combinedData:2097151&this.content?(0,s.stringFromCodePoint)(2097151&this.content):""}getCode(){return this.isCombined()?this.combinedData.charCodeAt(this.combinedData.length-1):2097151&this.content}setFromCharData(e){this.fg=e[r.CHAR_DATA_ATTR_INDEX],this.bg=0;let t=!1;if(e[r.CHAR_DATA_CHAR_INDEX].length>2)t=!0;else if(2===e[r.CHAR_DATA_CHAR_INDEX].length){const i=e[r.CHAR_DATA_CHAR_INDEX].charCodeAt(0);if(55296<=i&&i<=56319){const s=e[r.CHAR_DATA_CHAR_INDEX].charCodeAt(1);56320<=s&&s<=57343?this.content=1024*(i-55296)+s-56320+65536|e[r.CHAR_DATA_WIDTH_INDEX]<<22:t=!0}else t=!0}else this.content=e[r.CHAR_DATA_CHAR_INDEX].charCodeAt(0)|e[r.CHAR_DATA_WIDTH_INDEX]<<22;t&&(this.combinedData=e[r.CHAR_DATA_CHAR_INDEX],this.content=2097152|e[r.CHAR_DATA_WIDTH_INDEX]<<22)}getAsCharData(){return[this.fg,this.getChars(),this.getWidth(),this.getCode()]}}t.CellData=o},643:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.WHITESPACE_CELL_CODE=t.WHITESPACE_CELL_WIDTH=t.WHITESPACE_CELL_CHAR=t.NULL_CELL_CODE=t.NULL_CELL_WIDTH=t.NULL_CELL_CHAR=t.CHAR_DATA_CODE_INDEX=t.CHAR_DATA_WIDTH_INDEX=t.CHAR_DATA_CHAR_INDEX=t.CHAR_DATA_ATTR_INDEX=t.DEFAULT_EXT=t.DEFAULT_ATTR=t.DEFAULT_COLOR=void 0,t.DEFAULT_COLOR=0,t.DEFAULT_ATTR=256|t.DEFAULT_COLOR<<9,t.DEFAULT_EXT=0,t.CHAR_DATA_ATTR_INDEX=0,t.CHAR_DATA_CHAR_INDEX=1,t.CHAR_DATA_WIDTH_INDEX=2,t.CHAR_DATA_CODE_INDEX=3,t.NULL_CELL_CHAR="",t.NULL_CELL_WIDTH=1,t.NULL_CELL_CODE=0,t.WHITESPACE_CELL_CHAR=" ",t.WHITESPACE_CELL_WIDTH=1,t.WHITESPACE_CELL_CODE=32},4863:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Marker=void 0;const s=i(8460),r=i(844);class n{get id(){return this._id}constructor(e){this.line=e,this.isDisposed=!1,this._disposables=[],this._id=n._nextId++,this._onDispose=this.register(new s.EventEmitter),this.onDispose=this._onDispose.event}dispose(){this.isDisposed||(this.isDisposed=!0,this.line=-1,this._onDispose.fire(),(0,r.disposeArray)(this._disposables),this._disposables.length=0)}register(e){return this._disposables.push(e),e}}t.Marker=n,n._nextId=1},7116:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DEFAULT_CHARSET=t.CHARSETS=void 0,t.CHARSETS={},t.DEFAULT_CHARSET=t.CHARSETS.B,t.CHARSETS[0]={"`":"◆",a:"▒",b:"␉",c:"␌",d:"␍",e:"␊",f:"°",g:"±",h:"␤",i:"␋",j:"┘",k:"┐",l:"┌",m:"└",n:"┼",o:"⎺",p:"⎻",q:"─",r:"⎼",s:"⎽",t:"├",u:"┤",v:"┴",w:"┬",x:"│",y:"≤",z:"≥","{":"π","|":"≠","}":"£","~":"·"},t.CHARSETS.A={"#":"£"},t.CHARSETS.B=void 0,t.CHARSETS[4]={"#":"£","@":"¾","[":"ij","\\":"½","]":"|","{":"¨","|":"f","}":"¼","~":"´"},t.CHARSETS.C=t.CHARSETS[5]={"[":"Ä","\\":"Ö","]":"Å","^":"Ü","`":"é","{":"ä","|":"ö","}":"å","~":"ü"},t.CHARSETS.R={"#":"£","@":"à","[":"°","\\":"ç","]":"§","{":"é","|":"ù","}":"è","~":"¨"},t.CHARSETS.Q={"@":"à","[":"â","\\":"ç","]":"ê","^":"î","`":"ô","{":"é","|":"ù","}":"è","~":"û"},t.CHARSETS.K={"@":"§","[":"Ä","\\":"Ö","]":"Ü","{":"ä","|":"ö","}":"ü","~":"ß"},t.CHARSETS.Y={"#":"£","@":"§","[":"°","\\":"ç","]":"é","`":"ù","{":"à","|":"ò","}":"è","~":"ì"},t.CHARSETS.E=t.CHARSETS[6]={"@":"Ä","[":"Æ","\\":"Ø","]":"Å","^":"Ü","`":"ä","{":"æ","|":"ø","}":"å","~":"ü"},t.CHARSETS.Z={"#":"£","@":"§","[":"¡","\\":"Ñ","]":"¿","{":"°","|":"ñ","}":"ç"},t.CHARSETS.H=t.CHARSETS[7]={"@":"É","[":"Ä","\\":"Ö","]":"Å","^":"Ü","`":"é","{":"ä","|":"ö","}":"å","~":"ü"},t.CHARSETS["="]={"#":"ù","@":"à","[":"é","\\":"ç","]":"ê","^":"î",_:"è","`":"ô","{":"ä","|":"ö","}":"ü","~":"û"}},2584:(e,t)=>{var i,s,r;Object.defineProperty(t,"__esModule",{value:!0}),t.C1_ESCAPED=t.C1=t.C0=void 0,function(e){e.NUL="\0",e.SOH="",e.STX="",e.ETX="",e.EOT="",e.ENQ="",e.ACK="",e.BEL="",e.BS="\b",e.HT="\t",e.LF="\n",e.VT="\v",e.FF="\f",e.CR="\r",e.SO="",e.SI="",e.DLE="",e.DC1="",e.DC2="",e.DC3="",e.DC4="",e.NAK="",e.SYN="",e.ETB="",e.CAN="",e.EM="",e.SUB="",e.ESC="",e.FS="",e.GS="",e.RS="",e.US="",e.SP=" ",e.DEL=""}(i||(t.C0=i={})),function(e){e.PAD="€",e.HOP="",e.BPH="‚",e.NBH="ƒ",e.IND="„",e.NEL="…",e.SSA="†",e.ESA="‡",e.HTS="ˆ",e.HTJ="‰",e.VTS="Š",e.PLD="‹",e.PLU="Œ",e.RI="",e.SS2="Ž",e.SS3="",e.DCS="",e.PU1="‘",e.PU2="’",e.STS="“",e.CCH="”",e.MW="•",e.SPA="–",e.EPA="—",e.SOS="˜",e.SGCI="™",e.SCI="š",e.CSI="›",e.ST="œ",e.OSC="",e.PM="ž",e.APC="Ÿ"}(s||(t.C1=s={})),function(e){e.ST=`${i.ESC}\\`}(r||(t.C1_ESCAPED=r={}))},7399:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.evaluateKeyboardEvent=void 0;const s=i(2584),r={48:["0",")"],49:["1","!"],50:["2","@"],51:["3","#"],52:["4","$"],53:["5","%"],54:["6","^"],55:["7","&"],56:["8","*"],57:["9","("],186:[";",":"],187:["=","+"],188:[",","<"],189:["-","_"],190:[".",">"],191:["/","?"],192:["`","~"],219:["[","{"],220:["\\","|"],221:["]","}"],222:["'",'"']};t.evaluateKeyboardEvent=function(e,t,i,n){const o={type:0,cancel:!1,key:void 0},a=(e.shiftKey?1:0)|(e.altKey?2:0)|(e.ctrlKey?4:0)|(e.metaKey?8:0);switch(e.keyCode){case 0:"UIKeyInputUpArrow"===e.key?o.key=t?s.C0.ESC+"OA":s.C0.ESC+"[A":"UIKeyInputLeftArrow"===e.key?o.key=t?s.C0.ESC+"OD":s.C0.ESC+"[D":"UIKeyInputRightArrow"===e.key?o.key=t?s.C0.ESC+"OC":s.C0.ESC+"[C":"UIKeyInputDownArrow"===e.key&&(o.key=t?s.C0.ESC+"OB":s.C0.ESC+"[B");break;case 8:o.key=e.ctrlKey?"\b":s.C0.DEL,e.altKey&&(o.key=s.C0.ESC+o.key);break;case 9:if(e.shiftKey){o.key=s.C0.ESC+"[Z";break}o.key=s.C0.HT,o.cancel=!0;break;case 13:o.key=e.altKey?s.C0.ESC+s.C0.CR:s.C0.CR,o.cancel=!0;break;case 27:o.key=s.C0.ESC,e.altKey&&(o.key=s.C0.ESC+s.C0.ESC),o.cancel=!0;break;case 37:if(e.metaKey)break;a?(o.key=s.C0.ESC+"[1;"+(a+1)+"D",o.key===s.C0.ESC+"[1;3D"&&(o.key=s.C0.ESC+(i?"b":"[1;5D"))):o.key=t?s.C0.ESC+"OD":s.C0.ESC+"[D";break;case 39:if(e.metaKey)break;a?(o.key=s.C0.ESC+"[1;"+(a+1)+"C",o.key===s.C0.ESC+"[1;3C"&&(o.key=s.C0.ESC+(i?"f":"[1;5C"))):o.key=t?s.C0.ESC+"OC":s.C0.ESC+"[C";break;case 38:if(e.metaKey)break;a?(o.key=s.C0.ESC+"[1;"+(a+1)+"A",i||o.key!==s.C0.ESC+"[1;3A"||(o.key=s.C0.ESC+"[1;5A")):o.key=t?s.C0.ESC+"OA":s.C0.ESC+"[A";break;case 40:if(e.metaKey)break;a?(o.key=s.C0.ESC+"[1;"+(a+1)+"B",i||o.key!==s.C0.ESC+"[1;3B"||(o.key=s.C0.ESC+"[1;5B")):o.key=t?s.C0.ESC+"OB":s.C0.ESC+"[B";break;case 45:e.shiftKey||e.ctrlKey||(o.key=s.C0.ESC+"[2~");break;case 46:o.key=a?s.C0.ESC+"[3;"+(a+1)+"~":s.C0.ESC+"[3~";break;case 36:o.key=a?s.C0.ESC+"[1;"+(a+1)+"H":t?s.C0.ESC+"OH":s.C0.ESC+"[H";break;case 35:o.key=a?s.C0.ESC+"[1;"+(a+1)+"F":t?s.C0.ESC+"OF":s.C0.ESC+"[F";break;case 33:e.shiftKey?o.type=2:e.ctrlKey?o.key=s.C0.ESC+"[5;"+(a+1)+"~":o.key=s.C0.ESC+"[5~";break;case 34:e.shiftKey?o.type=3:e.ctrlKey?o.key=s.C0.ESC+"[6;"+(a+1)+"~":o.key=s.C0.ESC+"[6~";break;case 112:o.key=a?s.C0.ESC+"[1;"+(a+1)+"P":s.C0.ESC+"OP";break;case 113:o.key=a?s.C0.ESC+"[1;"+(a+1)+"Q":s.C0.ESC+"OQ";break;case 114:o.key=a?s.C0.ESC+"[1;"+(a+1)+"R":s.C0.ESC+"OR";break;case 115:o.key=a?s.C0.ESC+"[1;"+(a+1)+"S":s.C0.ESC+"OS";break;case 116:o.key=a?s.C0.ESC+"[15;"+(a+1)+"~":s.C0.ESC+"[15~";break;case 117:o.key=a?s.C0.ESC+"[17;"+(a+1)+"~":s.C0.ESC+"[17~";break;case 118:o.key=a?s.C0.ESC+"[18;"+(a+1)+"~":s.C0.ESC+"[18~";break;case 119:o.key=a?s.C0.ESC+"[19;"+(a+1)+"~":s.C0.ESC+"[19~";break;case 120:o.key=a?s.C0.ESC+"[20;"+(a+1)+"~":s.C0.ESC+"[20~";break;case 121:o.key=a?s.C0.ESC+"[21;"+(a+1)+"~":s.C0.ESC+"[21~";break;case 122:o.key=a?s.C0.ESC+"[23;"+(a+1)+"~":s.C0.ESC+"[23~";break;case 123:o.key=a?s.C0.ESC+"[24;"+(a+1)+"~":s.C0.ESC+"[24~";break;default:if(!e.ctrlKey||e.shiftKey||e.altKey||e.metaKey)if(i&&!n||!e.altKey||e.metaKey)!i||e.altKey||e.ctrlKey||e.shiftKey||!e.metaKey?e.key&&!e.ctrlKey&&!e.altKey&&!e.metaKey&&e.keyCode>=48&&1===e.key.length?o.key=e.key:e.key&&e.ctrlKey&&("_"===e.key&&(o.key=s.C0.US),"@"===e.key&&(o.key=s.C0.NUL)):65===e.keyCode&&(o.type=1);else{const t=r[e.keyCode],i=t?.[e.shiftKey?1:0];if(i)o.key=s.C0.ESC+i;else if(e.keyCode>=65&&e.keyCode<=90){const t=e.ctrlKey?e.keyCode-64:e.keyCode+32;let i=String.fromCharCode(t);e.shiftKey&&(i=i.toUpperCase()),o.key=s.C0.ESC+i}else if(32===e.keyCode)o.key=s.C0.ESC+(e.ctrlKey?s.C0.NUL:" ");else if("Dead"===e.key&&e.code.startsWith("Key")){let t=e.code.slice(3,4);e.shiftKey||(t=t.toLowerCase()),o.key=s.C0.ESC+t,o.cancel=!0}}else e.keyCode>=65&&e.keyCode<=90?o.key=String.fromCharCode(e.keyCode-64):32===e.keyCode?o.key=s.C0.NUL:e.keyCode>=51&&e.keyCode<=55?o.key=String.fromCharCode(e.keyCode-51+27):56===e.keyCode?o.key=s.C0.DEL:219===e.keyCode?o.key=s.C0.ESC:220===e.keyCode?o.key=s.C0.FS:221===e.keyCode&&(o.key=s.C0.GS)}return o}},482:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Utf8ToUtf32=t.StringToUtf32=t.utf32ToString=t.stringFromCodePoint=void 0,t.stringFromCodePoint=function(e){return e>65535?(e-=65536,String.fromCharCode(55296+(e>>10))+String.fromCharCode(e%1024+56320)):String.fromCharCode(e)},t.utf32ToString=function(e,t=0,i=e.length){let s="";for(let r=t;r65535?(t-=65536,s+=String.fromCharCode(55296+(t>>10))+String.fromCharCode(t%1024+56320)):s+=String.fromCharCode(t)}return s},t.StringToUtf32=class{constructor(){this._interim=0}clear(){this._interim=0}decode(e,t){const i=e.length;if(!i)return 0;let s=0,r=0;if(this._interim){const i=e.charCodeAt(r++);56320<=i&&i<=57343?t[s++]=1024*(this._interim-55296)+i-56320+65536:(t[s++]=this._interim,t[s++]=i),this._interim=0}for(let n=r;n=i)return this._interim=r,s;const o=e.charCodeAt(n);56320<=o&&o<=57343?t[s++]=1024*(r-55296)+o-56320+65536:(t[s++]=r,t[s++]=o)}else 65279!==r&&(t[s++]=r)}return s}},t.Utf8ToUtf32=class{constructor(){this.interim=new Uint8Array(3)}clear(){this.interim.fill(0)}decode(e,t){const i=e.length;if(!i)return 0;let s,r,n,o,a=0,h=0,c=0;if(this.interim[0]){let s=!1,r=this.interim[0];r&=192==(224&r)?31:224==(240&r)?15:7;let n,o=0;for(;(n=63&this.interim[++o])&&o<4;)r<<=6,r|=n;const h=192==(224&this.interim[0])?2:224==(240&this.interim[0])?3:4,l=h-o;for(;c=i)return 0;if(n=e[c++],128!=(192&n)){c--,s=!0;break}this.interim[o++]=n,r<<=6,r|=63&n}s||(2===h?r<128?c--:t[a++]=r:3===h?r<2048||r>=55296&&r<=57343||65279===r||(t[a++]=r):r<65536||r>1114111||(t[a++]=r)),this.interim.fill(0)}const l=i-4;let d=c;for(;d=i)return this.interim[0]=s,a;if(r=e[d++],128!=(192&r)){d--;continue}if(h=(31&s)<<6|63&r,h<128){d--;continue}t[a++]=h}else if(224==(240&s)){if(d>=i)return this.interim[0]=s,a;if(r=e[d++],128!=(192&r)){d--;continue}if(d>=i)return this.interim[0]=s,this.interim[1]=r,a;if(n=e[d++],128!=(192&n)){d--;continue}if(h=(15&s)<<12|(63&r)<<6|63&n,h<2048||h>=55296&&h<=57343||65279===h)continue;t[a++]=h}else if(240==(248&s)){if(d>=i)return this.interim[0]=s,a;if(r=e[d++],128!=(192&r)){d--;continue}if(d>=i)return this.interim[0]=s,this.interim[1]=r,a;if(n=e[d++],128!=(192&n)){d--;continue}if(d>=i)return this.interim[0]=s,this.interim[1]=r,this.interim[2]=n,a;if(o=e[d++],128!=(192&o)){d--;continue}if(h=(7&s)<<18|(63&r)<<12|(63&n)<<6|63&o,h<65536||h>1114111)continue;t[a++]=h}}return a}}},225:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.UnicodeV6=void 0;const s=i(1480),r=[[768,879],[1155,1158],[1160,1161],[1425,1469],[1471,1471],[1473,1474],[1476,1477],[1479,1479],[1536,1539],[1552,1557],[1611,1630],[1648,1648],[1750,1764],[1767,1768],[1770,1773],[1807,1807],[1809,1809],[1840,1866],[1958,1968],[2027,2035],[2305,2306],[2364,2364],[2369,2376],[2381,2381],[2385,2388],[2402,2403],[2433,2433],[2492,2492],[2497,2500],[2509,2509],[2530,2531],[2561,2562],[2620,2620],[2625,2626],[2631,2632],[2635,2637],[2672,2673],[2689,2690],[2748,2748],[2753,2757],[2759,2760],[2765,2765],[2786,2787],[2817,2817],[2876,2876],[2879,2879],[2881,2883],[2893,2893],[2902,2902],[2946,2946],[3008,3008],[3021,3021],[3134,3136],[3142,3144],[3146,3149],[3157,3158],[3260,3260],[3263,3263],[3270,3270],[3276,3277],[3298,3299],[3393,3395],[3405,3405],[3530,3530],[3538,3540],[3542,3542],[3633,3633],[3636,3642],[3655,3662],[3761,3761],[3764,3769],[3771,3772],[3784,3789],[3864,3865],[3893,3893],[3895,3895],[3897,3897],[3953,3966],[3968,3972],[3974,3975],[3984,3991],[3993,4028],[4038,4038],[4141,4144],[4146,4146],[4150,4151],[4153,4153],[4184,4185],[4448,4607],[4959,4959],[5906,5908],[5938,5940],[5970,5971],[6002,6003],[6068,6069],[6071,6077],[6086,6086],[6089,6099],[6109,6109],[6155,6157],[6313,6313],[6432,6434],[6439,6440],[6450,6450],[6457,6459],[6679,6680],[6912,6915],[6964,6964],[6966,6970],[6972,6972],[6978,6978],[7019,7027],[7616,7626],[7678,7679],[8203,8207],[8234,8238],[8288,8291],[8298,8303],[8400,8431],[12330,12335],[12441,12442],[43014,43014],[43019,43019],[43045,43046],[64286,64286],[65024,65039],[65056,65059],[65279,65279],[65529,65531]],n=[[68097,68099],[68101,68102],[68108,68111],[68152,68154],[68159,68159],[119143,119145],[119155,119170],[119173,119179],[119210,119213],[119362,119364],[917505,917505],[917536,917631],[917760,917999]];let o;t.UnicodeV6=class{constructor(){if(this.version="6",!o){o=new Uint8Array(65536),o.fill(1),o[0]=0,o.fill(0,1,32),o.fill(0,127,160),o.fill(2,4352,4448),o[9001]=2,o[9002]=2,o.fill(2,11904,42192),o[12351]=1,o.fill(2,44032,55204),o.fill(2,63744,64256),o.fill(2,65040,65050),o.fill(2,65072,65136),o.fill(2,65280,65377),o.fill(2,65504,65511);for(let e=0;et[r][1])return!1;for(;r>=s;)if(i=s+r>>1,e>t[i][1])s=i+1;else{if(!(e=131072&&e<=196605||e>=196608&&e<=262141?2:1}charProperties(e,t){let i=this.wcwidth(e),r=0===i&&0!==t;if(r){const e=s.UnicodeService.extractWidth(t);0===e?r=!1:e>i&&(i=e)}return s.UnicodeService.createPropertyValue(0,i,r)}}},5981:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.WriteBuffer=void 0;const s=i(8460),r=i(844);class n extends r.Disposable{constructor(e){super(),this._action=e,this._writeBuffer=[],this._callbacks=[],this._pendingData=0,this._bufferOffset=0,this._isSyncWriting=!1,this._syncCalls=0,this._didUserInput=!1,this._onWriteParsed=this.register(new s.EventEmitter),this.onWriteParsed=this._onWriteParsed.event}handleUserInput(){this._didUserInput=!0}writeSync(e,t){if(void 0!==t&&this._syncCalls>t)return void(this._syncCalls=0);if(this._pendingData+=e.length,this._writeBuffer.push(e),this._callbacks.push(void 0),this._syncCalls++,this._isSyncWriting)return;let i;for(this._isSyncWriting=!0;i=this._writeBuffer.shift();){this._action(i);const e=this._callbacks.shift();e&&e()}this._pendingData=0,this._bufferOffset=2147483647,this._isSyncWriting=!1,this._syncCalls=0}write(e,t){if(this._pendingData>5e7)throw new Error("write data discarded, use flow control to avoid losing data");if(!this._writeBuffer.length){if(this._bufferOffset=0,this._didUserInput)return this._didUserInput=!1,this._pendingData+=e.length,this._writeBuffer.push(e),this._callbacks.push(t),void this._innerWrite();setTimeout((()=>this._innerWrite()))}this._pendingData+=e.length,this._writeBuffer.push(e),this._callbacks.push(t)}_innerWrite(e=0,t=!0){const i=e||Date.now();for(;this._writeBuffer.length>this._bufferOffset;){const e=this._writeBuffer[this._bufferOffset],s=this._action(e,t);if(s){const e=e=>Date.now()-i>=12?setTimeout((()=>this._innerWrite(0,e))):this._innerWrite(i,e);return void s.catch((e=>(queueMicrotask((()=>{throw e})),Promise.resolve(!1)))).then(e)}const r=this._callbacks[this._bufferOffset];if(r&&r(),this._bufferOffset++,this._pendingData-=e.length,Date.now()-i>=12)break}this._writeBuffer.length>this._bufferOffset?(this._bufferOffset>50&&(this._writeBuffer=this._writeBuffer.slice(this._bufferOffset),this._callbacks=this._callbacks.slice(this._bufferOffset),this._bufferOffset=0),setTimeout((()=>this._innerWrite()))):(this._writeBuffer.length=0,this._callbacks.length=0,this._pendingData=0,this._bufferOffset=0),this._onWriteParsed.fire()}}t.WriteBuffer=n},5941:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.toRgbString=t.parseColor=void 0;const i=/^([\da-f])\/([\da-f])\/([\da-f])$|^([\da-f]{2})\/([\da-f]{2})\/([\da-f]{2})$|^([\da-f]{3})\/([\da-f]{3})\/([\da-f]{3})$|^([\da-f]{4})\/([\da-f]{4})\/([\da-f]{4})$/,s=/^[\da-f]+$/;function r(e,t){const i=e.toString(16),s=i.length<2?"0"+i:i;switch(t){case 4:return i[0];case 8:return s;case 12:return(s+s).slice(0,3);default:return s+s}}t.parseColor=function(e){if(!e)return;let t=e.toLowerCase();if(0===t.indexOf("rgb:")){t=t.slice(4);const e=i.exec(t);if(e){const t=e[1]?15:e[4]?255:e[7]?4095:65535;return[Math.round(parseInt(e[1]||e[4]||e[7]||e[10],16)/t*255),Math.round(parseInt(e[2]||e[5]||e[8]||e[11],16)/t*255),Math.round(parseInt(e[3]||e[6]||e[9]||e[12],16)/t*255)]}}else if(0===t.indexOf("#")&&(t=t.slice(1),s.exec(t)&&[3,6,9,12].includes(t.length))){const e=t.length/3,i=[0,0,0];for(let s=0;s<3;++s){const r=parseInt(t.slice(e*s,e*s+e),16);i[s]=1===e?r<<4:2===e?r:3===e?r>>4:r>>8}return i}},t.toRgbString=function(e,t=16){const[i,s,n]=e;return`rgb:${r(i,t)}/${r(s,t)}/${r(n,t)}`}},5770:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.PAYLOAD_LIMIT=void 0,t.PAYLOAD_LIMIT=1e7},6351:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DcsHandler=t.DcsParser=void 0;const s=i(482),r=i(8742),n=i(5770),o=[];t.DcsParser=class{constructor(){this._handlers=Object.create(null),this._active=o,this._ident=0,this._handlerFb=()=>{},this._stack={paused:!1,loopPosition:0,fallThrough:!1}}dispose(){this._handlers=Object.create(null),this._handlerFb=()=>{},this._active=o}registerHandler(e,t){void 0===this._handlers[e]&&(this._handlers[e]=[]);const i=this._handlers[e];return i.push(t),{dispose:()=>{const e=i.indexOf(t);-1!==e&&i.splice(e,1)}}}clearHandler(e){this._handlers[e]&&delete this._handlers[e]}setHandlerFallback(e){this._handlerFb=e}reset(){if(this._active.length)for(let e=this._stack.paused?this._stack.loopPosition-1:this._active.length-1;e>=0;--e)this._active[e].unhook(!1);this._stack.paused=!1,this._active=o,this._ident=0}hook(e,t){if(this.reset(),this._ident=e,this._active=this._handlers[e]||o,this._active.length)for(let e=this._active.length-1;e>=0;e--)this._active[e].hook(t);else this._handlerFb(this._ident,"HOOK",t)}put(e,t,i){if(this._active.length)for(let s=this._active.length-1;s>=0;s--)this._active[s].put(e,t,i);else this._handlerFb(this._ident,"PUT",(0,s.utf32ToString)(e,t,i))}unhook(e,t=!0){if(this._active.length){let i=!1,s=this._active.length-1,r=!1;if(this._stack.paused&&(s=this._stack.loopPosition-1,i=t,r=this._stack.fallThrough,this._stack.paused=!1),!r&&!1===i){for(;s>=0&&(i=this._active[s].unhook(e),!0!==i);s--)if(i instanceof Promise)return this._stack.paused=!0,this._stack.loopPosition=s,this._stack.fallThrough=!1,i;s--}for(;s>=0;s--)if(i=this._active[s].unhook(!1),i instanceof Promise)return this._stack.paused=!0,this._stack.loopPosition=s,this._stack.fallThrough=!0,i}else this._handlerFb(this._ident,"UNHOOK",e);this._active=o,this._ident=0}};const a=new r.Params;a.addParam(0),t.DcsHandler=class{constructor(e){this._handler=e,this._data="",this._params=a,this._hitLimit=!1}hook(e){this._params=e.length>1||e.params[0]?e.clone():a,this._data="",this._hitLimit=!1}put(e,t,i){this._hitLimit||(this._data+=(0,s.utf32ToString)(e,t,i),this._data.length>n.PAYLOAD_LIMIT&&(this._data="",this._hitLimit=!0))}unhook(e){let t=!1;if(this._hitLimit)t=!1;else if(e&&(t=this._handler(this._data,this._params),t instanceof Promise))return t.then((e=>(this._params=a,this._data="",this._hitLimit=!1,e)));return this._params=a,this._data="",this._hitLimit=!1,t}}},2015:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.EscapeSequenceParser=t.VT500_TRANSITION_TABLE=t.TransitionTable=void 0;const s=i(844),r=i(8742),n=i(6242),o=i(6351);class a{constructor(e){this.table=new Uint8Array(e)}setDefault(e,t){this.table.fill(e<<4|t)}add(e,t,i,s){this.table[t<<8|e]=i<<4|s}addMany(e,t,i,s){for(let r=0;rt)),i=(e,i)=>t.slice(e,i),s=i(32,127),r=i(0,24);r.push(25),r.push.apply(r,i(28,32));const n=i(0,14);let o;for(o in e.setDefault(1,0),e.addMany(s,0,2,0),n)e.addMany([24,26,153,154],o,3,0),e.addMany(i(128,144),o,3,0),e.addMany(i(144,152),o,3,0),e.add(156,o,0,0),e.add(27,o,11,1),e.add(157,o,4,8),e.addMany([152,158,159],o,0,7),e.add(155,o,11,3),e.add(144,o,11,9);return e.addMany(r,0,3,0),e.addMany(r,1,3,1),e.add(127,1,0,1),e.addMany(r,8,0,8),e.addMany(r,3,3,3),e.add(127,3,0,3),e.addMany(r,4,3,4),e.add(127,4,0,4),e.addMany(r,6,3,6),e.addMany(r,5,3,5),e.add(127,5,0,5),e.addMany(r,2,3,2),e.add(127,2,0,2),e.add(93,1,4,8),e.addMany(s,8,5,8),e.add(127,8,5,8),e.addMany([156,27,24,26,7],8,6,0),e.addMany(i(28,32),8,0,8),e.addMany([88,94,95],1,0,7),e.addMany(s,7,0,7),e.addMany(r,7,0,7),e.add(156,7,0,0),e.add(127,7,0,7),e.add(91,1,11,3),e.addMany(i(64,127),3,7,0),e.addMany(i(48,60),3,8,4),e.addMany([60,61,62,63],3,9,4),e.addMany(i(48,60),4,8,4),e.addMany(i(64,127),4,7,0),e.addMany([60,61,62,63],4,0,6),e.addMany(i(32,64),6,0,6),e.add(127,6,0,6),e.addMany(i(64,127),6,0,0),e.addMany(i(32,48),3,9,5),e.addMany(i(32,48),5,9,5),e.addMany(i(48,64),5,0,6),e.addMany(i(64,127),5,7,0),e.addMany(i(32,48),4,9,5),e.addMany(i(32,48),1,9,2),e.addMany(i(32,48),2,9,2),e.addMany(i(48,127),2,10,0),e.addMany(i(48,80),1,10,0),e.addMany(i(81,88),1,10,0),e.addMany([89,90,92],1,10,0),e.addMany(i(96,127),1,10,0),e.add(80,1,11,9),e.addMany(r,9,0,9),e.add(127,9,0,9),e.addMany(i(28,32),9,0,9),e.addMany(i(32,48),9,9,12),e.addMany(i(48,60),9,8,10),e.addMany([60,61,62,63],9,9,10),e.addMany(r,11,0,11),e.addMany(i(32,128),11,0,11),e.addMany(i(28,32),11,0,11),e.addMany(r,10,0,10),e.add(127,10,0,10),e.addMany(i(28,32),10,0,10),e.addMany(i(48,60),10,8,10),e.addMany([60,61,62,63],10,0,11),e.addMany(i(32,48),10,9,12),e.addMany(r,12,0,12),e.add(127,12,0,12),e.addMany(i(28,32),12,0,12),e.addMany(i(32,48),12,9,12),e.addMany(i(48,64),12,0,11),e.addMany(i(64,127),12,12,13),e.addMany(i(64,127),10,12,13),e.addMany(i(64,127),9,12,13),e.addMany(r,13,13,13),e.addMany(s,13,13,13),e.add(127,13,0,13),e.addMany([27,156,24,26],13,14,0),e.add(h,0,2,0),e.add(h,8,5,8),e.add(h,6,0,6),e.add(h,11,0,11),e.add(h,13,13,13),e}();class c extends s.Disposable{constructor(e=t.VT500_TRANSITION_TABLE){super(),this._transitions=e,this._parseStack={state:0,handlers:[],handlerPos:0,transition:0,chunkPos:0},this.initialState=0,this.currentState=this.initialState,this._params=new r.Params,this._params.addParam(0),this._collect=0,this.precedingJoinState=0,this._printHandlerFb=(e,t,i)=>{},this._executeHandlerFb=e=>{},this._csiHandlerFb=(e,t)=>{},this._escHandlerFb=e=>{},this._errorHandlerFb=e=>e,this._printHandler=this._printHandlerFb,this._executeHandlers=Object.create(null),this._csiHandlers=Object.create(null),this._escHandlers=Object.create(null),this.register((0,s.toDisposable)((()=>{this._csiHandlers=Object.create(null),this._executeHandlers=Object.create(null),this._escHandlers=Object.create(null)}))),this._oscParser=this.register(new n.OscParser),this._dcsParser=this.register(new o.DcsParser),this._errorHandler=this._errorHandlerFb,this.registerEscHandler({final:"\\"},(()=>!0))}_identifier(e,t=[64,126]){let i=0;if(e.prefix){if(e.prefix.length>1)throw new Error("only one byte as prefix supported");if(i=e.prefix.charCodeAt(0),i&&60>i||i>63)throw new Error("prefix must be in range 0x3c .. 0x3f")}if(e.intermediates){if(e.intermediates.length>2)throw new Error("only two bytes as intermediates are supported");for(let t=0;ts||s>47)throw new Error("intermediate must be in range 0x20 .. 0x2f");i<<=8,i|=s}}if(1!==e.final.length)throw new Error("final must be a single byte");const s=e.final.charCodeAt(0);if(t[0]>s||s>t[1])throw new Error(`final must be in range ${t[0]} .. ${t[1]}`);return i<<=8,i|=s,i}identToString(e){const t=[];for(;e;)t.push(String.fromCharCode(255&e)),e>>=8;return t.reverse().join("")}setPrintHandler(e){this._printHandler=e}clearPrintHandler(){this._printHandler=this._printHandlerFb}registerEscHandler(e,t){const i=this._identifier(e,[48,126]);void 0===this._escHandlers[i]&&(this._escHandlers[i]=[]);const s=this._escHandlers[i];return s.push(t),{dispose:()=>{const e=s.indexOf(t);-1!==e&&s.splice(e,1)}}}clearEscHandler(e){this._escHandlers[this._identifier(e,[48,126])]&&delete this._escHandlers[this._identifier(e,[48,126])]}setEscHandlerFallback(e){this._escHandlerFb=e}setExecuteHandler(e,t){this._executeHandlers[e.charCodeAt(0)]=t}clearExecuteHandler(e){this._executeHandlers[e.charCodeAt(0)]&&delete this._executeHandlers[e.charCodeAt(0)]}setExecuteHandlerFallback(e){this._executeHandlerFb=e}registerCsiHandler(e,t){const i=this._identifier(e);void 0===this._csiHandlers[i]&&(this._csiHandlers[i]=[]);const s=this._csiHandlers[i];return s.push(t),{dispose:()=>{const e=s.indexOf(t);-1!==e&&s.splice(e,1)}}}clearCsiHandler(e){this._csiHandlers[this._identifier(e)]&&delete this._csiHandlers[this._identifier(e)]}setCsiHandlerFallback(e){this._csiHandlerFb=e}registerDcsHandler(e,t){return this._dcsParser.registerHandler(this._identifier(e),t)}clearDcsHandler(e){this._dcsParser.clearHandler(this._identifier(e))}setDcsHandlerFallback(e){this._dcsParser.setHandlerFallback(e)}registerOscHandler(e,t){return this._oscParser.registerHandler(e,t)}clearOscHandler(e){this._oscParser.clearHandler(e)}setOscHandlerFallback(e){this._oscParser.setHandlerFallback(e)}setErrorHandler(e){this._errorHandler=e}clearErrorHandler(){this._errorHandler=this._errorHandlerFb}reset(){this.currentState=this.initialState,this._oscParser.reset(),this._dcsParser.reset(),this._params.reset(),this._params.addParam(0),this._collect=0,this.precedingJoinState=0,0!==this._parseStack.state&&(this._parseStack.state=2,this._parseStack.handlers=[])}_preserveStack(e,t,i,s,r){this._parseStack.state=e,this._parseStack.handlers=t,this._parseStack.handlerPos=i,this._parseStack.transition=s,this._parseStack.chunkPos=r}parse(e,t,i){let s,r=0,n=0,o=0;if(this._parseStack.state)if(2===this._parseStack.state)this._parseStack.state=0,o=this._parseStack.chunkPos+1;else{if(void 0===i||1===this._parseStack.state)throw this._parseStack.state=1,new Error("improper continuation due to previous async handler, giving up parsing");const t=this._parseStack.handlers;let n=this._parseStack.handlerPos-1;switch(this._parseStack.state){case 3:if(!1===i&&n>-1)for(;n>=0&&(s=t[n](this._params),!0!==s);n--)if(s instanceof Promise)return this._parseStack.handlerPos=n,s;this._parseStack.handlers=[];break;case 4:if(!1===i&&n>-1)for(;n>=0&&(s=t[n](),!0!==s);n--)if(s instanceof Promise)return this._parseStack.handlerPos=n,s;this._parseStack.handlers=[];break;case 6:if(r=e[this._parseStack.chunkPos],s=this._dcsParser.unhook(24!==r&&26!==r,i),s)return s;27===r&&(this._parseStack.transition|=1),this._params.reset(),this._params.addParam(0),this._collect=0;break;case 5:if(r=e[this._parseStack.chunkPos],s=this._oscParser.end(24!==r&&26!==r,i),s)return s;27===r&&(this._parseStack.transition|=1),this._params.reset(),this._params.addParam(0),this._collect=0}this._parseStack.state=0,o=this._parseStack.chunkPos+1,this.precedingJoinState=0,this.currentState=15&this._parseStack.transition}for(let i=o;i>4){case 2:for(let s=i+1;;++s){if(s>=t||(r=e[s])<32||r>126&&r=t||(r=e[s])<32||r>126&&r=t||(r=e[s])<32||r>126&&r=t||(r=e[s])<32||r>126&&r=0&&(s=o[a](this._params),!0!==s);a--)if(s instanceof Promise)return this._preserveStack(3,o,a,n,i),s;a<0&&this._csiHandlerFb(this._collect<<8|r,this._params),this.precedingJoinState=0;break;case 8:do{switch(r){case 59:this._params.addParam(0);break;case 58:this._params.addSubParam(-1);break;default:this._params.addDigit(r-48)}}while(++i47&&r<60);i--;break;case 9:this._collect<<=8,this._collect|=r;break;case 10:const c=this._escHandlers[this._collect<<8|r];let l=c?c.length-1:-1;for(;l>=0&&(s=c[l](),!0!==s);l--)if(s instanceof Promise)return this._preserveStack(4,c,l,n,i),s;l<0&&this._escHandlerFb(this._collect<<8|r),this.precedingJoinState=0;break;case 11:this._params.reset(),this._params.addParam(0),this._collect=0;break;case 12:this._dcsParser.hook(this._collect<<8|r,this._params);break;case 13:for(let s=i+1;;++s)if(s>=t||24===(r=e[s])||26===r||27===r||r>127&&r=t||(r=e[s])<32||r>127&&r{Object.defineProperty(t,"__esModule",{value:!0}),t.OscHandler=t.OscParser=void 0;const s=i(5770),r=i(482),n=[];t.OscParser=class{constructor(){this._state=0,this._active=n,this._id=-1,this._handlers=Object.create(null),this._handlerFb=()=>{},this._stack={paused:!1,loopPosition:0,fallThrough:!1}}registerHandler(e,t){void 0===this._handlers[e]&&(this._handlers[e]=[]);const i=this._handlers[e];return i.push(t),{dispose:()=>{const e=i.indexOf(t);-1!==e&&i.splice(e,1)}}}clearHandler(e){this._handlers[e]&&delete this._handlers[e]}setHandlerFallback(e){this._handlerFb=e}dispose(){this._handlers=Object.create(null),this._handlerFb=()=>{},this._active=n}reset(){if(2===this._state)for(let e=this._stack.paused?this._stack.loopPosition-1:this._active.length-1;e>=0;--e)this._active[e].end(!1);this._stack.paused=!1,this._active=n,this._id=-1,this._state=0}_start(){if(this._active=this._handlers[this._id]||n,this._active.length)for(let e=this._active.length-1;e>=0;e--)this._active[e].start();else this._handlerFb(this._id,"START")}_put(e,t,i){if(this._active.length)for(let s=this._active.length-1;s>=0;s--)this._active[s].put(e,t,i);else this._handlerFb(this._id,"PUT",(0,r.utf32ToString)(e,t,i))}start(){this.reset(),this._state=1}put(e,t,i){if(3!==this._state){if(1===this._state)for(;t0&&this._put(e,t,i)}}end(e,t=!0){if(0!==this._state){if(3!==this._state)if(1===this._state&&this._start(),this._active.length){let i=!1,s=this._active.length-1,r=!1;if(this._stack.paused&&(s=this._stack.loopPosition-1,i=t,r=this._stack.fallThrough,this._stack.paused=!1),!r&&!1===i){for(;s>=0&&(i=this._active[s].end(e),!0!==i);s--)if(i instanceof Promise)return this._stack.paused=!0,this._stack.loopPosition=s,this._stack.fallThrough=!1,i;s--}for(;s>=0;s--)if(i=this._active[s].end(!1),i instanceof Promise)return this._stack.paused=!0,this._stack.loopPosition=s,this._stack.fallThrough=!0,i}else this._handlerFb(this._id,"END",e);this._active=n,this._id=-1,this._state=0}}},t.OscHandler=class{constructor(e){this._handler=e,this._data="",this._hitLimit=!1}start(){this._data="",this._hitLimit=!1}put(e,t,i){this._hitLimit||(this._data+=(0,r.utf32ToString)(e,t,i),this._data.length>s.PAYLOAD_LIMIT&&(this._data="",this._hitLimit=!0))}end(e){let t=!1;if(this._hitLimit)t=!1;else if(e&&(t=this._handler(this._data),t instanceof Promise))return t.then((e=>(this._data="",this._hitLimit=!1,e)));return this._data="",this._hitLimit=!1,t}}},8742:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.Params=void 0;const i=2147483647;class s{static fromArray(e){const t=new s;if(!e.length)return t;for(let i=Array.isArray(e[0])?1:0;i256)throw new Error("maxSubParamsLength must not be greater than 256");this.params=new Int32Array(e),this.length=0,this._subParams=new Int32Array(t),this._subParamsLength=0,this._subParamsIdx=new Uint16Array(e),this._rejectDigits=!1,this._rejectSubDigits=!1,this._digitIsSub=!1}clone(){const e=new s(this.maxLength,this.maxSubParamsLength);return e.params.set(this.params),e.length=this.length,e._subParams.set(this._subParams),e._subParamsLength=this._subParamsLength,e._subParamsIdx.set(this._subParamsIdx),e._rejectDigits=this._rejectDigits,e._rejectSubDigits=this._rejectSubDigits,e._digitIsSub=this._digitIsSub,e}toArray(){const e=[];for(let t=0;t>8,s=255&this._subParamsIdx[t];s-i>0&&e.push(Array.prototype.slice.call(this._subParams,i,s))}return e}reset(){this.length=0,this._subParamsLength=0,this._rejectDigits=!1,this._rejectSubDigits=!1,this._digitIsSub=!1}addParam(e){if(this._digitIsSub=!1,this.length>=this.maxLength)this._rejectDigits=!0;else{if(e<-1)throw new Error("values lesser than -1 are not allowed");this._subParamsIdx[this.length]=this._subParamsLength<<8|this._subParamsLength,this.params[this.length++]=e>i?i:e}}addSubParam(e){if(this._digitIsSub=!0,this.length)if(this._rejectDigits||this._subParamsLength>=this.maxSubParamsLength)this._rejectSubDigits=!0;else{if(e<-1)throw new Error("values lesser than -1 are not allowed");this._subParams[this._subParamsLength++]=e>i?i:e,this._subParamsIdx[this.length-1]++}}hasSubParams(e){return(255&this._subParamsIdx[e])-(this._subParamsIdx[e]>>8)>0}getSubParams(e){const t=this._subParamsIdx[e]>>8,i=255&this._subParamsIdx[e];return i-t>0?this._subParams.subarray(t,i):null}getSubParamsAll(){const e={};for(let t=0;t>8,s=255&this._subParamsIdx[t];s-i>0&&(e[t]=this._subParams.slice(i,s))}return e}addDigit(e){let t;if(this._rejectDigits||!(t=this._digitIsSub?this._subParamsLength:this.length)||this._digitIsSub&&this._rejectSubDigits)return;const s=this._digitIsSub?this._subParams:this.params,r=s[t-1];s[t-1]=~r?Math.min(10*r+e,i):e}}t.Params=s},5741:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.AddonManager=void 0,t.AddonManager=class{constructor(){this._addons=[]}dispose(){for(let e=this._addons.length-1;e>=0;e--)this._addons[e].instance.dispose()}loadAddon(e,t){const i={instance:t,dispose:t.dispose,isDisposed:!1};this._addons.push(i),t.dispose=()=>this._wrappedAddonDispose(i),t.activate(e)}_wrappedAddonDispose(e){if(e.isDisposed)return;let t=-1;for(let i=0;i{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferApiView=void 0;const s=i(3785),r=i(511);t.BufferApiView=class{constructor(e,t){this._buffer=e,this.type=t}init(e){return this._buffer=e,this}get cursorY(){return this._buffer.y}get cursorX(){return this._buffer.x}get viewportY(){return this._buffer.ydisp}get baseY(){return this._buffer.ybase}get length(){return this._buffer.lines.length}getLine(e){const t=this._buffer.lines.get(e);if(t)return new s.BufferLineApiView(t)}getNullCell(){return new r.CellData}}},3785:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferLineApiView=void 0;const s=i(511);t.BufferLineApiView=class{constructor(e){this._line=e}get isWrapped(){return this._line.isWrapped}get length(){return this._line.length}getCell(e,t){if(!(e<0||e>=this._line.length))return t?(this._line.loadCell(e,t),t):this._line.loadCell(e,new s.CellData)}translateToString(e,t,i){return this._line.translateToString(e,t,i)}}},8285:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.BufferNamespaceApi=void 0;const s=i(8771),r=i(8460),n=i(844);class o extends n.Disposable{constructor(e){super(),this._core=e,this._onBufferChange=this.register(new r.EventEmitter),this.onBufferChange=this._onBufferChange.event,this._normal=new s.BufferApiView(this._core.buffers.normal,"normal"),this._alternate=new s.BufferApiView(this._core.buffers.alt,"alternate"),this._core.buffers.onBufferActivate((()=>this._onBufferChange.fire(this.active)))}get active(){if(this._core.buffers.active===this._core.buffers.normal)return this.normal;if(this._core.buffers.active===this._core.buffers.alt)return this.alternate;throw new Error("Active buffer is neither normal nor alternate")}get normal(){return this._normal.init(this._core.buffers.normal)}get alternate(){return this._alternate.init(this._core.buffers.alt)}}t.BufferNamespaceApi=o},7975:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.ParserApi=void 0,t.ParserApi=class{constructor(e){this._core=e}registerCsiHandler(e,t){return this._core.registerCsiHandler(e,(e=>t(e.toArray())))}addCsiHandler(e,t){return this.registerCsiHandler(e,t)}registerDcsHandler(e,t){return this._core.registerDcsHandler(e,((e,i)=>t(e,i.toArray())))}addDcsHandler(e,t){return this.registerDcsHandler(e,t)}registerEscHandler(e,t){return this._core.registerEscHandler(e,t)}addEscHandler(e,t){return this.registerEscHandler(e,t)}registerOscHandler(e,t){return this._core.registerOscHandler(e,t)}addOscHandler(e,t){return this.registerOscHandler(e,t)}}},7090:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.UnicodeApi=void 0,t.UnicodeApi=class{constructor(e){this._core=e}register(e){this._core.unicodeService.register(e)}get versions(){return this._core.unicodeService.versions}get activeVersion(){return this._core.unicodeService.activeVersion}set activeVersion(e){this._core.unicodeService.activeVersion=e}}},744:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.BufferService=t.MINIMUM_ROWS=t.MINIMUM_COLS=void 0;const n=i(8460),o=i(844),a=i(5295),h=i(2585);t.MINIMUM_COLS=2,t.MINIMUM_ROWS=1;let c=t.BufferService=class extends o.Disposable{get buffer(){return this.buffers.active}constructor(e){super(),this.isUserScrolling=!1,this._onResize=this.register(new n.EventEmitter),this.onResize=this._onResize.event,this._onScroll=this.register(new n.EventEmitter),this.onScroll=this._onScroll.event,this.cols=Math.max(e.rawOptions.cols||0,t.MINIMUM_COLS),this.rows=Math.max(e.rawOptions.rows||0,t.MINIMUM_ROWS),this.buffers=this.register(new a.BufferSet(e,this))}resize(e,t){this.cols=e,this.rows=t,this.buffers.resize(e,t),this._onResize.fire({cols:e,rows:t})}reset(){this.buffers.reset(),this.isUserScrolling=!1}scroll(e,t=!1){const i=this.buffer;let s;s=this._cachedBlankLine,s&&s.length===this.cols&&s.getFg(0)===e.fg&&s.getBg(0)===e.bg||(s=i.getBlankLine(e,t),this._cachedBlankLine=s),s.isWrapped=t;const r=i.ybase+i.scrollTop,n=i.ybase+i.scrollBottom;if(0===i.scrollTop){const e=i.lines.isFull;n===i.lines.length-1?e?i.lines.recycle().copyFrom(s):i.lines.push(s.clone()):i.lines.splice(n+1,0,s.clone()),e?this.isUserScrolling&&(i.ydisp=Math.max(i.ydisp-1,0)):(i.ybase++,this.isUserScrolling||i.ydisp++)}else{const e=n-r+1;i.lines.shiftElements(r+1,e-1,-1),i.lines.set(n,s.clone())}this.isUserScrolling||(i.ydisp=i.ybase),this._onScroll.fire(i.ydisp)}scrollLines(e,t,i){const s=this.buffer;if(e<0){if(0===s.ydisp)return;this.isUserScrolling=!0}else e+s.ydisp>=s.ybase&&(this.isUserScrolling=!1);const r=s.ydisp;s.ydisp=Math.max(Math.min(s.ydisp+e,s.ybase),0),r!==s.ydisp&&(t||this._onScroll.fire(s.ydisp))}};t.BufferService=c=s([r(0,h.IOptionsService)],c)},7994:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.CharsetService=void 0,t.CharsetService=class{constructor(){this.glevel=0,this._charsets=[]}reset(){this.charset=void 0,this._charsets=[],this.glevel=0}setgLevel(e){this.glevel=e,this.charset=this._charsets[e]}setgCharset(e,t){this._charsets[e]=t,this.glevel===e&&(this.charset=t)}}},1753:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CoreMouseService=void 0;const n=i(2585),o=i(8460),a=i(844),h={NONE:{events:0,restrict:()=>!1},X10:{events:1,restrict:e=>4!==e.button&&1===e.action&&(e.ctrl=!1,e.alt=!1,e.shift=!1,!0)},VT200:{events:19,restrict:e=>32!==e.action},DRAG:{events:23,restrict:e=>32!==e.action||3!==e.button},ANY:{events:31,restrict:e=>!0}};function c(e,t){let i=(e.ctrl?16:0)|(e.shift?4:0)|(e.alt?8:0);return 4===e.button?(i|=64,i|=e.action):(i|=3&e.button,4&e.button&&(i|=64),8&e.button&&(i|=128),32===e.action?i|=32:0!==e.action||t||(i|=3)),i}const l=String.fromCharCode,d={DEFAULT:e=>{const t=[c(e,!1)+32,e.col+32,e.row+32];return t[0]>255||t[1]>255||t[2]>255?"":`${l(t[0])}${l(t[1])}${l(t[2])}`},SGR:e=>{const t=0===e.action&&4!==e.button?"m":"M";return`[<${c(e,!0)};${e.col};${e.row}${t}`},SGR_PIXELS:e=>{const t=0===e.action&&4!==e.button?"m":"M";return`[<${c(e,!0)};${e.x};${e.y}${t}`}};let _=t.CoreMouseService=class extends a.Disposable{constructor(e,t){super(),this._bufferService=e,this._coreService=t,this._protocols={},this._encodings={},this._activeProtocol="",this._activeEncoding="",this._lastEvent=null,this._onProtocolChange=this.register(new o.EventEmitter),this.onProtocolChange=this._onProtocolChange.event;for(const e of Object.keys(h))this.addProtocol(e,h[e]);for(const e of Object.keys(d))this.addEncoding(e,d[e]);this.reset()}addProtocol(e,t){this._protocols[e]=t}addEncoding(e,t){this._encodings[e]=t}get activeProtocol(){return this._activeProtocol}get areMouseEventsActive(){return 0!==this._protocols[this._activeProtocol].events}set activeProtocol(e){if(!this._protocols[e])throw new Error(`unknown protocol "${e}"`);this._activeProtocol=e,this._onProtocolChange.fire(this._protocols[e].events)}get activeEncoding(){return this._activeEncoding}set activeEncoding(e){if(!this._encodings[e])throw new Error(`unknown encoding "${e}"`);this._activeEncoding=e}reset(){this.activeProtocol="NONE",this.activeEncoding="DEFAULT",this._lastEvent=null}triggerMouseEvent(e){if(e.col<0||e.col>=this._bufferService.cols||e.row<0||e.row>=this._bufferService.rows)return!1;if(4===e.button&&32===e.action)return!1;if(3===e.button&&32!==e.action)return!1;if(4!==e.button&&(2===e.action||3===e.action))return!1;if(e.col++,e.row++,32===e.action&&this._lastEvent&&this._equalEvents(this._lastEvent,e,"SGR_PIXELS"===this._activeEncoding))return!1;if(!this._protocols[this._activeProtocol].restrict(e))return!1;const t=this._encodings[this._activeEncoding](e);return t&&("DEFAULT"===this._activeEncoding?this._coreService.triggerBinaryEvent(t):this._coreService.triggerDataEvent(t,!0)),this._lastEvent=e,!0}explainEvents(e){return{down:!!(1&e),up:!!(2&e),drag:!!(4&e),move:!!(8&e),wheel:!!(16&e)}}_equalEvents(e,t,i){if(i){if(e.x!==t.x)return!1;if(e.y!==t.y)return!1}else{if(e.col!==t.col)return!1;if(e.row!==t.row)return!1}return e.button===t.button&&e.action===t.action&&e.ctrl===t.ctrl&&e.alt===t.alt&&e.shift===t.shift}};t.CoreMouseService=_=s([r(0,n.IBufferService),r(1,n.ICoreService)],_)},6975:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.CoreService=void 0;const n=i(1439),o=i(8460),a=i(844),h=i(2585),c=Object.freeze({insertMode:!1}),l=Object.freeze({applicationCursorKeys:!1,applicationKeypad:!1,bracketedPasteMode:!1,origin:!1,reverseWraparound:!1,sendFocus:!1,wraparound:!0});let d=t.CoreService=class extends a.Disposable{constructor(e,t,i){super(),this._bufferService=e,this._logService=t,this._optionsService=i,this.isCursorInitialized=!1,this.isCursorHidden=!1,this._onData=this.register(new o.EventEmitter),this.onData=this._onData.event,this._onUserInput=this.register(new o.EventEmitter),this.onUserInput=this._onUserInput.event,this._onBinary=this.register(new o.EventEmitter),this.onBinary=this._onBinary.event,this._onRequestScrollToBottom=this.register(new o.EventEmitter),this.onRequestScrollToBottom=this._onRequestScrollToBottom.event,this.modes=(0,n.clone)(c),this.decPrivateModes=(0,n.clone)(l)}reset(){this.modes=(0,n.clone)(c),this.decPrivateModes=(0,n.clone)(l)}triggerDataEvent(e,t=!1){if(this._optionsService.rawOptions.disableStdin)return;const i=this._bufferService.buffer;t&&this._optionsService.rawOptions.scrollOnUserInput&&i.ybase!==i.ydisp&&this._onRequestScrollToBottom.fire(),t&&this._onUserInput.fire(),this._logService.debug(`sending data "${e}"`,(()=>e.split("").map((e=>e.charCodeAt(0))))),this._onData.fire(e)}triggerBinaryEvent(e){this._optionsService.rawOptions.disableStdin||(this._logService.debug(`sending binary "${e}"`,(()=>e.split("").map((e=>e.charCodeAt(0))))),this._onBinary.fire(e))}};t.CoreService=d=s([r(0,h.IBufferService),r(1,h.ILogService),r(2,h.IOptionsService)],d)},9074:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.DecorationService=void 0;const s=i(8055),r=i(8460),n=i(844),o=i(6106);let a=0,h=0;class c extends n.Disposable{get decorations(){return this._decorations.values()}constructor(){super(),this._decorations=new o.SortedList((e=>e?.marker.line)),this._onDecorationRegistered=this.register(new r.EventEmitter),this.onDecorationRegistered=this._onDecorationRegistered.event,this._onDecorationRemoved=this.register(new r.EventEmitter),this.onDecorationRemoved=this._onDecorationRemoved.event,this.register((0,n.toDisposable)((()=>this.reset())))}registerDecoration(e){if(e.marker.isDisposed)return;const t=new l(e);if(t){const e=t.marker.onDispose((()=>t.dispose()));t.onDispose((()=>{t&&(this._decorations.delete(t)&&this._onDecorationRemoved.fire(t),e.dispose())})),this._decorations.insert(t),this._onDecorationRegistered.fire(t)}return t}reset(){for(const e of this._decorations.values())e.dispose();this._decorations.clear()}*getDecorationsAtCell(e,t,i){let s=0,r=0;for(const n of this._decorations.getKeyIterator(t))s=n.options.x??0,r=s+(n.options.width??1),e>=s&&e{a=t.options.x??0,h=a+(t.options.width??1),e>=a&&e{Object.defineProperty(t,"__esModule",{value:!0}),t.InstantiationService=t.ServiceCollection=void 0;const s=i(2585),r=i(8343);class n{constructor(...e){this._entries=new Map;for(const[t,i]of e)this.set(t,i)}set(e,t){const i=this._entries.get(e);return this._entries.set(e,t),i}forEach(e){for(const[t,i]of this._entries.entries())e(t,i)}has(e){return this._entries.has(e)}get(e){return this._entries.get(e)}}t.ServiceCollection=n,t.InstantiationService=class{constructor(){this._services=new n,this._services.set(s.IInstantiationService,this)}setService(e,t){this._services.set(e,t)}getService(e){return this._services.get(e)}createInstance(e,...t){const i=(0,r.getServiceDependencies)(e).sort(((e,t)=>e.index-t.index)),s=[];for(const t of i){const i=this._services.get(t.id);if(!i)throw new Error(`[createInstance] ${e.name} depends on UNKNOWN service ${t.id}.`);s.push(i)}const n=i.length>0?i[0].index:t.length;if(t.length!==n)throw new Error(`[createInstance] First service dependency of ${e.name} at position ${n+1} conflicts with ${t.length} static arguments`);return new e(...[...t,...s])}}},7866:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.traceCall=t.setTraceLogger=t.LogService=void 0;const n=i(844),o=i(2585),a={trace:o.LogLevelEnum.TRACE,debug:o.LogLevelEnum.DEBUG,info:o.LogLevelEnum.INFO,warn:o.LogLevelEnum.WARN,error:o.LogLevelEnum.ERROR,off:o.LogLevelEnum.OFF};let h,c=t.LogService=class extends n.Disposable{get logLevel(){return this._logLevel}constructor(e){super(),this._optionsService=e,this._logLevel=o.LogLevelEnum.OFF,this._updateLogLevel(),this.register(this._optionsService.onSpecificOptionChange("logLevel",(()=>this._updateLogLevel()))),h=this}_updateLogLevel(){this._logLevel=a[this._optionsService.rawOptions.logLevel]}_evalLazyOptionalParams(e){for(let t=0;tJSON.stringify(e))).join(", ")})`);const t=s.apply(this,e);return h.trace(`GlyphRenderer#${s.name} return`,t),t}}},7302:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.OptionsService=t.DEFAULT_OPTIONS=void 0;const s=i(8460),r=i(844),n=i(6114);t.DEFAULT_OPTIONS={cols:80,rows:24,cursorBlink:!1,cursorStyle:"block",cursorWidth:1,cursorInactiveStyle:"outline",customGlyphs:!0,drawBoldTextInBrightColors:!0,documentOverride:null,fastScrollModifier:"alt",fastScrollSensitivity:5,fontFamily:"courier-new, courier, monospace",fontSize:15,fontWeight:"normal",fontWeightBold:"bold",ignoreBracketedPasteMode:!1,lineHeight:1,letterSpacing:0,linkHandler:null,logLevel:"info",logger:null,scrollback:1e3,scrollOnUserInput:!0,scrollSensitivity:1,screenReaderMode:!1,smoothScrollDuration:0,macOptionIsMeta:!1,macOptionClickForcesSelection:!1,minimumContrastRatio:1,disableStdin:!1,allowProposedApi:!1,allowTransparency:!1,tabStopWidth:8,theme:{},rightClickSelectsWord:n.isMac,windowOptions:{},windowsMode:!1,windowsPty:{},wordSeparator:" ()[]{}',\"`",altClickMovesCursor:!0,convertEol:!1,termName:"xterm",cancelEvents:!1,overviewRulerWidth:0};const o=["normal","bold","100","200","300","400","500","600","700","800","900"];class a extends r.Disposable{constructor(e){super(),this._onOptionChange=this.register(new s.EventEmitter),this.onOptionChange=this._onOptionChange.event;const i={...t.DEFAULT_OPTIONS};for(const t in e)if(t in i)try{const s=e[t];i[t]=this._sanitizeAndValidateOption(t,s)}catch(e){console.error(e)}this.rawOptions=i,this.options={...i},this._setupOptions(),this.register((0,r.toDisposable)((()=>{this.rawOptions.linkHandler=null,this.rawOptions.documentOverride=null})))}onSpecificOptionChange(e,t){return this.onOptionChange((i=>{i===e&&t(this.rawOptions[e])}))}onMultipleOptionChange(e,t){return this.onOptionChange((i=>{-1!==e.indexOf(i)&&t()}))}_setupOptions(){const e=e=>{if(!(e in t.DEFAULT_OPTIONS))throw new Error(`No option with key "${e}"`);return this.rawOptions[e]},i=(e,i)=>{if(!(e in t.DEFAULT_OPTIONS))throw new Error(`No option with key "${e}"`);i=this._sanitizeAndValidateOption(e,i),this.rawOptions[e]!==i&&(this.rawOptions[e]=i,this._onOptionChange.fire(e))};for(const t in this.rawOptions){const s={get:e.bind(this,t),set:i.bind(this,t)};Object.defineProperty(this.options,t,s)}}_sanitizeAndValidateOption(e,i){switch(e){case"cursorStyle":if(i||(i=t.DEFAULT_OPTIONS[e]),!function(e){return"block"===e||"underline"===e||"bar"===e}(i))throw new Error(`"${i}" is not a valid value for ${e}`);break;case"wordSeparator":i||(i=t.DEFAULT_OPTIONS[e]);break;case"fontWeight":case"fontWeightBold":if("number"==typeof i&&1<=i&&i<=1e3)break;i=o.includes(i)?i:t.DEFAULT_OPTIONS[e];break;case"cursorWidth":i=Math.floor(i);case"lineHeight":case"tabStopWidth":if(i<1)throw new Error(`${e} cannot be less than 1, value: ${i}`);break;case"minimumContrastRatio":i=Math.max(1,Math.min(21,Math.round(10*i)/10));break;case"scrollback":if((i=Math.min(i,4294967295))<0)throw new Error(`${e} cannot be less than 0, value: ${i}`);break;case"fastScrollSensitivity":case"scrollSensitivity":if(i<=0)throw new Error(`${e} cannot be less than or equal to 0, value: ${i}`);break;case"rows":case"cols":if(!i&&0!==i)throw new Error(`${e} must be numeric, value: ${i}`);break;case"windowsPty":i=i??{}}return i}}t.OptionsService=a},2660:function(e,t,i){var s=this&&this.__decorate||function(e,t,i,s){var r,n=arguments.length,o=n<3?t:null===s?s=Object.getOwnPropertyDescriptor(t,i):s;if("object"==typeof Reflect&&"function"==typeof Reflect.decorate)o=Reflect.decorate(e,t,i,s);else for(var a=e.length-1;a>=0;a--)(r=e[a])&&(o=(n<3?r(o):n>3?r(t,i,o):r(t,i))||o);return n>3&&o&&Object.defineProperty(t,i,o),o},r=this&&this.__param||function(e,t){return function(i,s){t(i,s,e)}};Object.defineProperty(t,"__esModule",{value:!0}),t.OscLinkService=void 0;const n=i(2585);let o=t.OscLinkService=class{constructor(e){this._bufferService=e,this._nextId=1,this._entriesWithId=new Map,this._dataByLinkId=new Map}registerLink(e){const t=this._bufferService.buffer;if(void 0===e.id){const i=t.addMarker(t.ybase+t.y),s={data:e,id:this._nextId++,lines:[i]};return i.onDispose((()=>this._removeMarkerFromLink(s,i))),this._dataByLinkId.set(s.id,s),s.id}const i=e,s=this._getEntryIdKey(i),r=this._entriesWithId.get(s);if(r)return this.addLineToLink(r.id,t.ybase+t.y),r.id;const n=t.addMarker(t.ybase+t.y),o={id:this._nextId++,key:this._getEntryIdKey(i),data:i,lines:[n]};return n.onDispose((()=>this._removeMarkerFromLink(o,n))),this._entriesWithId.set(o.key,o),this._dataByLinkId.set(o.id,o),o.id}addLineToLink(e,t){const i=this._dataByLinkId.get(e);if(i&&i.lines.every((e=>e.line!==t))){const e=this._bufferService.buffer.addMarker(t);i.lines.push(e),e.onDispose((()=>this._removeMarkerFromLink(i,e)))}}getLinkData(e){return this._dataByLinkId.get(e)?.data}_getEntryIdKey(e){return`${e.id};;${e.uri}`}_removeMarkerFromLink(e,t){const i=e.lines.indexOf(t);-1!==i&&(e.lines.splice(i,1),0===e.lines.length&&(void 0!==e.data.id&&this._entriesWithId.delete(e.key),this._dataByLinkId.delete(e.id)))}};t.OscLinkService=o=s([r(0,n.IBufferService)],o)},8343:(e,t)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.createDecorator=t.getServiceDependencies=t.serviceRegistry=void 0;const i="di$target",s="di$dependencies";t.serviceRegistry=new Map,t.getServiceDependencies=function(e){return e[s]||[]},t.createDecorator=function(e){if(t.serviceRegistry.has(e))return t.serviceRegistry.get(e);const r=function(e,t,n){if(3!==arguments.length)throw new Error("@IServiceName-decorator can only be used to decorate a parameter");!function(e,t,r){t[i]===t?t[s].push({id:e,index:r}):(t[s]=[{id:e,index:r}],t[i]=t)}(r,e,n)};return r.toString=()=>e,t.serviceRegistry.set(e,r),r}},2585:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.IDecorationService=t.IUnicodeService=t.IOscLinkService=t.IOptionsService=t.ILogService=t.LogLevelEnum=t.IInstantiationService=t.ICharsetService=t.ICoreService=t.ICoreMouseService=t.IBufferService=void 0;const s=i(8343);var r;t.IBufferService=(0,s.createDecorator)("BufferService"),t.ICoreMouseService=(0,s.createDecorator)("CoreMouseService"),t.ICoreService=(0,s.createDecorator)("CoreService"),t.ICharsetService=(0,s.createDecorator)("CharsetService"),t.IInstantiationService=(0,s.createDecorator)("InstantiationService"),function(e){e[e.TRACE=0]="TRACE",e[e.DEBUG=1]="DEBUG",e[e.INFO=2]="INFO",e[e.WARN=3]="WARN",e[e.ERROR=4]="ERROR",e[e.OFF=5]="OFF"}(r||(t.LogLevelEnum=r={})),t.ILogService=(0,s.createDecorator)("LogService"),t.IOptionsService=(0,s.createDecorator)("OptionsService"),t.IOscLinkService=(0,s.createDecorator)("OscLinkService"),t.IUnicodeService=(0,s.createDecorator)("UnicodeService"),t.IDecorationService=(0,s.createDecorator)("DecorationService")},1480:(e,t,i)=>{Object.defineProperty(t,"__esModule",{value:!0}),t.UnicodeService=void 0;const s=i(8460),r=i(225);class n{static extractShouldJoin(e){return 0!=(1&e)}static extractWidth(e){return e>>1&3}static extractCharKind(e){return e>>3}static createPropertyValue(e,t,i=!1){return(16777215&e)<<3|(3&t)<<1|(i?1:0)}constructor(){this._providers=Object.create(null),this._active="",this._onChange=new s.EventEmitter,this.onChange=this._onChange.event;const e=new r.UnicodeV6;this.register(e),this._active=e.version,this._activeProvider=e}dispose(){this._onChange.dispose()}get versions(){return Object.keys(this._providers)}get activeVersion(){return this._active}set activeVersion(e){if(!this._providers[e])throw new Error(`unknown Unicode version "${e}"`);this._active=e,this._activeProvider=this._providers[e],this._onChange.fire(e)}register(e){this._providers[e.version]=e}wcwidth(e){return this._activeProvider.wcwidth(e)}getStringCellWidth(e){let t=0,i=0;const s=e.length;for(let r=0;r=s)return t+this.wcwidth(o);const i=e.charCodeAt(r);56320<=i&&i<=57343?o=1024*(o-55296)+i-56320+65536:t+=this.wcwidth(i)}const a=this.charProperties(o,i);let h=n.extractWidth(a);n.extractShouldJoin(a)&&(h-=n.extractWidth(i)),t+=h,i=a}return t}charProperties(e,t){return this._activeProvider.charProperties(e,t)}}t.UnicodeService=n}},t={};function i(s){var r=t[s];if(void 0!==r)return r.exports;var n=t[s]={exports:{}};return e[s].call(n.exports,n,n.exports,i),n.exports}var s={};return(()=>{var e=s;Object.defineProperty(e,"__esModule",{value:!0}),e.Terminal=void 0;const t=i(9042),r=i(3236),n=i(844),o=i(5741),a=i(8285),h=i(7975),c=i(7090),l=["cols","rows"];class d extends n.Disposable{constructor(e){super(),this._core=this.register(new r.Terminal(e)),this._addonManager=this.register(new o.AddonManager),this._publicOptions={...this._core.options};const t=e=>this._core.options[e],i=(e,t)=>{this._checkReadonlyOptions(e),this._core.options[e]=t};for(const e in this._core.options){const s={get:t.bind(this,e),set:i.bind(this,e)};Object.defineProperty(this._publicOptions,e,s)}}_checkReadonlyOptions(e){if(l.includes(e))throw new Error(`Option "${e}" can only be set in the constructor`)}_checkProposedApi(){if(!this._core.optionsService.rawOptions.allowProposedApi)throw new Error("You must set the allowProposedApi option to true to use proposed API")}get onBell(){return this._core.onBell}get onBinary(){return this._core.onBinary}get onCursorMove(){return this._core.onCursorMove}get onData(){return this._core.onData}get onKey(){return this._core.onKey}get onLineFeed(){return this._core.onLineFeed}get onRender(){return this._core.onRender}get onResize(){return this._core.onResize}get onScroll(){return this._core.onScroll}get onSelectionChange(){return this._core.onSelectionChange}get onTitleChange(){return this._core.onTitleChange}get onWriteParsed(){return this._core.onWriteParsed}get element(){return this._core.element}get parser(){return this._parser||(this._parser=new h.ParserApi(this._core)),this._parser}get unicode(){return this._checkProposedApi(),new c.UnicodeApi(this._core)}get textarea(){return this._core.textarea}get rows(){return this._core.rows}get cols(){return this._core.cols}get buffer(){return this._buffer||(this._buffer=this.register(new a.BufferNamespaceApi(this._core))),this._buffer}get markers(){return this._checkProposedApi(),this._core.markers}get modes(){const e=this._core.coreService.decPrivateModes;let t="none";switch(this._core.coreMouseService.activeProtocol){case"X10":t="x10";break;case"VT200":t="vt200";break;case"DRAG":t="drag";break;case"ANY":t="any"}return{applicationCursorKeysMode:e.applicationCursorKeys,applicationKeypadMode:e.applicationKeypad,bracketedPasteMode:e.bracketedPasteMode,insertMode:this._core.coreService.modes.insertMode,mouseTrackingMode:t,originMode:e.origin,reverseWraparoundMode:e.reverseWraparound,sendFocusMode:e.sendFocus,wraparoundMode:e.wraparound}}get options(){return this._publicOptions}set options(e){for(const t in e)this._publicOptions[t]=e[t]}blur(){this._core.blur()}focus(){this._core.focus()}input(e,t=!0){this._core.input(e,t)}resize(e,t){this._verifyIntegers(e,t),this._core.resize(e,t)}open(e){this._core.open(e)}attachCustomKeyEventHandler(e){this._core.attachCustomKeyEventHandler(e)}attachCustomWheelEventHandler(e){this._core.attachCustomWheelEventHandler(e)}registerLinkProvider(e){return this._core.registerLinkProvider(e)}registerCharacterJoiner(e){return this._checkProposedApi(),this._core.registerCharacterJoiner(e)}deregisterCharacterJoiner(e){this._checkProposedApi(),this._core.deregisterCharacterJoiner(e)}registerMarker(e=0){return this._verifyIntegers(e),this._core.registerMarker(e)}registerDecoration(e){return this._checkProposedApi(),this._verifyPositiveIntegers(e.x??0,e.width??0,e.height??0),this._core.registerDecoration(e)}hasSelection(){return this._core.hasSelection()}select(e,t,i){this._verifyIntegers(e,t,i),this._core.select(e,t,i)}getSelection(){return this._core.getSelection()}getSelectionPosition(){return this._core.getSelectionPosition()}clearSelection(){this._core.clearSelection()}selectAll(){this._core.selectAll()}selectLines(e,t){this._verifyIntegers(e,t),this._core.selectLines(e,t)}dispose(){super.dispose()}scrollLines(e){this._verifyIntegers(e),this._core.scrollLines(e)}scrollPages(e){this._verifyIntegers(e),this._core.scrollPages(e)}scrollToTop(){this._core.scrollToTop()}scrollToBottom(){this._core.scrollToBottom()}scrollToLine(e){this._verifyIntegers(e),this._core.scrollToLine(e)}clear(){this._core.clear()}write(e,t){this._core.write(e,t)}writeln(e,t){this._core.write(e),this._core.write("\r\n",t)}paste(e){this._core.paste(e)}refresh(e,t){this._verifyIntegers(e,t),this._core.refresh(e,t)}reset(){this._core.reset()}clearTextureAtlas(){this._core.clearTextureAtlas()}loadAddon(e){this._addonManager.loadAddon(this,e)}static get strings(){return t}_verifyIntegers(...e){for(const t of e)if(t===1/0||isNaN(t)||t%1!=0)throw new Error("This API only accepts integers")}_verifyPositiveIntegers(...e){for(const t of e)if(t&&(t===1/0||isNaN(t)||t%1!=0||t<0))throw new Error("This API only accepts positive integers")}}e.Terminal=d})(),s})())); //# sourceMappingURL=xterm.js.map \ No newline at end of file diff --git a/exports.js b/exports.js index fd9c632477..df4044cf04 100644 --- a/exports.js +++ b/exports.js @@ -1,2 +1,20 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import backend from '@heyputer/backend'; export default backend; diff --git a/l_checker_config.json b/l_checker_config.json index a7bd893f9f..0572f11f13 100644 --- a/l_checker_config.json +++ b/l_checker_config.json @@ -1,5 +1,8 @@ { - "ignore": ["**/!(*.js|*.css)", "**/assets/**"], + "ignore": [ + "**/!(*.js|*.css)", "**/assets/**", "**/lib/**", + "eslint.config.js" + ], "license": "doc/license_header.txt", "licenseFormats": { "js": { diff --git a/mods/mods_available/kdmod/CustomPuterService.js b/mods/mods_available/kdmod/CustomPuterService.js index bdcc7dd814..6e6bb3f39a 100644 --- a/mods/mods_available/kdmod/CustomPuterService.js +++ b/mods/mods_available/kdmod/CustomPuterService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const path = require('path'); class CustomPuterService extends use.Service { diff --git a/mods/mods_available/kdmod/ShareTestService.js b/mods/mods_available/kdmod/ShareTestService.js index b5e36aa852..ab797f6b46 100644 --- a/mods/mods_available/kdmod/ShareTestService.js +++ b/mods/mods_available/kdmod/ShareTestService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ // TODO: accessing these imports directly from a mod is not really // the way mods are intended to work; this is temporary until // we have these things registered in "useapi". diff --git a/mods/mods_available/kdmod/data/sharetest_scenarios.js b/mods/mods_available/kdmod/data/sharetest_scenarios.js index b5c5c0c73d..c2ee1c5228 100644 --- a/mods/mods_available/kdmod/data/sharetest_scenarios.js +++ b/mods/mods_available/kdmod/data/sharetest_scenarios.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ module.exports = [ { sequence: [ diff --git a/mods/mods_available/kdmod/gui/main.js b/mods/mods_available/kdmod/gui/main.js index cc3f55b900..ddbe8bf789 100644 --- a/mods/mods_available/kdmod/gui/main.js +++ b/mods/mods_available/kdmod/gui/main.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const request_examples = [ { name: 'entity storage app read', diff --git a/mods/mods_available/kdmod/module.js b/mods/mods_available/kdmod/module.js index e6487687f4..7df281089b 100644 --- a/mods/mods_available/kdmod/module.js +++ b/mods/mods_available/kdmod/module.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ module.exports = class BillingModule extends use.Module { install (context) { const services = context.get('services'); diff --git a/package-lock.json b/package-lock.json index 73908b7721..45d091cc0a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "express": "^4.18.2", "globals": "^15.0.0", "html-entities": "^2.3.3", + "license-check-and-add": "^4.0.5", "nodemon": "^3.1.0", "uglify-js": "^3.17.4", "webpack": "^5.88.2", @@ -7865,6 +7866,15 @@ "integrity": "sha512-SyHy3T1v2NUXn29OsWdxmK6RwHD+vkj3v8en8AOBZ1wBQ/hCAQ5bAQTD02kW4W9tUp/3Qh6J8r9EvntiyCmOOw==", "license": "MIT" }, + "node_modules/gitignore-to-glob": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/gitignore-to-glob/-/gitignore-to-glob-0.3.0.tgz", + "integrity": "sha512-mk74BdnK7lIwDHnotHddx1wsjMOFIThpLY3cPNniJ/2fA/tlLzHnFxIdR+4sLOu5KGgQJdij4kjJ2RoUNnCNMA==", + "dev": true, + "engines": { + "node": ">=4.4 <5 || >=6.9" + } + }, "node_modules/glob": { "version": "8.1.0", "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz", @@ -9235,6 +9245,219 @@ "node": ">= 0.8.0" } }, + "node_modules/license-check-and-add": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/license-check-and-add/-/license-check-and-add-4.0.5.tgz", + "integrity": "sha512-FySnMi3Kf/vO5jka8tcbVF1FhDFb8PWsQ8pg5Y7U/zkQgta+fIrJGcGHO58WFjfKlgvhneG1uQ00Fpxzhau3QA==", + "dev": true, + "dependencies": { + "fs-extra": "^8.1.0", + "gitignore-to-glob": "^0.3.0", + "globby": "^10.0.1", + "ignore": "^5.1.2", + "yargs": "^13.3.0" + }, + "bin": { + "license-check-and-add": "dist/src/cli.js" + } + }, + "node_modules/license-check-and-add/node_modules/ansi-regex": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-4.1.1.tgz", + "integrity": "sha512-ILlv4k/3f6vfQ4OoP2AGvirOktlQ98ZEL1k9FaQjxa3L1abBgbuTDAdPOpvbGncC0BTVQrl+OM8xZGK6tWXt7g==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/license-check-and-add/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/license-check-and-add/node_modules/cliui": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-5.0.0.tgz", + "integrity": "sha512-PYeGSEmmHM6zvoef2w8TPzlrnNpXIjTipYK780YswmIP9vjxmd6Y2a3CB2Ks6/AU8NHjZugXvo8w3oWM2qnwXA==", + "dev": true, + "dependencies": { + "string-width": "^3.1.0", + "strip-ansi": "^5.2.0", + "wrap-ansi": "^5.1.0" + } + }, + "node_modules/license-check-and-add/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/license-check-and-add/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/license-check-and-add/node_modules/emoji-regex": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-7.0.3.tgz", + "integrity": "sha512-CwBLREIQ7LvYFB0WyRvwhq5N5qPhc6PMjD6bYggFlI5YyDgl+0vxq5VHbMOFqLg7hfWzmu8T5Z1QofhmTIhItA==", + "dev": true + }, + "node_modules/license-check-and-add/node_modules/find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "dependencies": { + "locate-path": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/license-check-and-add/node_modules/is-fullwidth-code-point": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz", + "integrity": "sha512-VHskAKYM8RfSFXwee5t5cbN5PZeq1Wrh6qd5bkyiXIf6UQcN6w/A0eXM9r6t8d+GYOh+o6ZhiEnb88LN/Y8m2w==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/license-check-and-add/node_modules/locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "dependencies": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/license-check-and-add/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/license-check-and-add/node_modules/p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "dependencies": { + "p-limit": "^2.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/license-check-and-add/node_modules/path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha512-bpC7GYwiDYQ4wYLe+FA8lhRjhQCMcQGuSgGGqDkg/QerRWw9CmGRT0iSOVRSZJ29NMLZgIzqaljJ63oaL4NIJQ==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/license-check-and-add/node_modules/string-width": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-3.1.0.tgz", + "integrity": "sha512-vafcv6KjVZKSgz06oM/H6GDBrAtz8vdhQakGjFIvNrHA6y3HCF1CInLy+QLq8dTJPQ1b+KDUqDFctkdRW44e1w==", + "dev": true, + "dependencies": { + "emoji-regex": "^7.0.1", + "is-fullwidth-code-point": "^2.0.0", + "strip-ansi": "^5.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/license-check-and-add/node_modules/strip-ansi": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-5.2.0.tgz", + "integrity": "sha512-DuRs1gKbBqsMKIZlrffwlug8MHkcnpjs5VPmL1PAh+mA30U0DTotfDZ0d2UUsXpPmPmMMJ6W773MaA3J+lbiWA==", + "dev": true, + "dependencies": { + "ansi-regex": "^4.1.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/license-check-and-add/node_modules/wrap-ansi": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-5.1.0.tgz", + "integrity": "sha512-QC1/iN/2/RPVJ5jYK8BGttj5z83LmSKmvbvrXPNCLZSEb32KKVDJDl/MOt2N01qU2H/FkzEa9PKto1BqDjtd7Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.0", + "string-width": "^3.0.0", + "strip-ansi": "^5.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/license-check-and-add/node_modules/y18n": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.3.tgz", + "integrity": "sha512-JKhqTOwSrqNA1NY5lSztJ1GrBiUodLMmIZuLiDaMRJ+itFd+ABVE8XBjOvIWL+rSqNDC74LCSFmlb/U4UZ4hJQ==", + "dev": true + }, + "node_modules/license-check-and-add/node_modules/yargs": { + "version": "13.3.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-13.3.2.tgz", + "integrity": "sha512-AX3Zw5iPruN5ie6xGRIDgqkT+ZhnRlZMLMHAs8tg7nRruy2Nb+i5o9bwghAogtM08q1dpr2LVoS8KSTMYpWXUw==", + "dev": true, + "dependencies": { + "cliui": "^5.0.0", + "find-up": "^3.0.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^3.0.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^13.1.2" + } + }, + "node_modules/license-check-and-add/node_modules/yargs-parser": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-13.1.2.tgz", + "integrity": "sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==", + "dev": true, + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, "node_modules/load-bmfont": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.1.tgz", diff --git a/package.json b/package.json index dc4be8bc8a..181da4a9e2 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "express": "^4.18.2", "globals": "^15.0.0", "html-entities": "^2.3.3", + "license-check-and-add": "^4.0.5", "nodemon": "^3.1.0", "uglify-js": "^3.17.4", "webpack": "^5.88.2", diff --git a/run-selfhosted.js b/run-selfhosted.js index bc0221cecd..a659656a1a 100644 --- a/run-selfhosted.js +++ b/run-selfhosted.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ // surrounding_box function // // It's really hard to see an error message without using diff --git a/src/backend/src/SelfHostedModule.js b/src/backend/src/SelfHostedModule.js index 9a9625a1b7..0e21c196a2 100644 --- a/src/backend/src/SelfHostedModule.js +++ b/src/backend/src/SelfHostedModule.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { AdvancedBase } = require("@heyputer/puter-js-common"); const config = require("./config"); diff --git a/src/backend/src/definitions/Library.js b/src/backend/src/definitions/Library.js index 10e16cf5d2..4be7ea1541 100644 --- a/src/backend/src/definitions/Library.js +++ b/src/backend/src/definitions/Library.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const BaseService = require("../services/BaseService"); class Library extends BaseService { diff --git a/src/backend/src/definitions/SimpleEntity.js b/src/backend/src/definitions/SimpleEntity.js index cdc64ad263..6c07305842 100644 --- a/src/backend/src/definitions/SimpleEntity.js +++ b/src/backend/src/definitions/SimpleEntity.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { Context } = require("../util/context"); module.exports = function SimpleEntity ({ name, methods, fetchers }) { diff --git a/src/backend/src/entities/Group.js b/src/backend/src/entities/Group.js index 7f8a96fa31..f6b4ce1e6f 100644 --- a/src/backend/src/entities/Group.js +++ b/src/backend/src/entities/Group.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const SimpleEntity = require("../definitions/SimpleEntity"); module.exports = SimpleEntity({ diff --git a/src/backend/src/filesystem/ll_operations/ll_listusers.js b/src/backend/src/filesystem/ll_operations/ll_listusers.js index 410f20eddb..c5b1826286 100644 --- a/src/backend/src/filesystem/ll_operations/ll_listusers.js +++ b/src/backend/src/filesystem/ll_operations/ll_listusers.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { RootNodeSelector, NodeChildSelector } = require("../node/selectors"); const { LLFilesystemOperation } = require("./definitions"); diff --git a/src/backend/src/filesystem/ll_operations/ll_readshares.js b/src/backend/src/filesystem/ll_operations/ll_readshares.js index 03fe4acec1..e8132154e4 100644 --- a/src/backend/src/filesystem/ll_operations/ll_readshares.js +++ b/src/backend/src/filesystem/ll_operations/ll_readshares.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { Context } = require("../../util/context"); const { TYPE_DIRECTORY } = require("../FSNodeContext"); const { LLFilesystemOperation } = require("./definitions"); diff --git a/src/backend/src/fun/dev-console-ui-utils.js b/src/backend/src/fun/dev-console-ui-utils.js index c30a358c82..84ac3eddb8 100644 --- a/src/backend/src/fun/dev-console-ui-utils.js +++ b/src/backend/src/fun/dev-console-ui-utils.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const config = require('../config'); const { TeePromise } = require('../util/promise'); diff --git a/src/backend/src/fun/logos.js b/src/backend/src/fun/logos.js index c5c5435b4e..139ec62b9e 100644 --- a/src/backend/src/fun/logos.js +++ b/src/backend/src/fun/logos.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ module.exports = [ { sz:40, diff --git a/src/backend/src/libraries/ArrayUtil.js b/src/backend/src/libraries/ArrayUtil.js index 950e6093ff..580be9e3af 100644 --- a/src/backend/src/libraries/ArrayUtil.js +++ b/src/backend/src/libraries/ArrayUtil.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ class ArrayUtil extends use.Library { /** * diff --git a/src/backend/src/libraries/LibTypeTagged.js b/src/backend/src/libraries/LibTypeTagged.js index fbe80c72f1..e7cb7d5956 100644 --- a/src/backend/src/libraries/LibTypeTagged.js +++ b/src/backend/src/libraries/LibTypeTagged.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { whatis } = require("../util/langutil"); class LibTypeTagged extends use.Library { diff --git a/src/backend/src/middleware/configurable_auth.js b/src/backend/src/middleware/configurable_auth.js index 2f322decb7..f564b53f97 100644 --- a/src/backend/src/middleware/configurable_auth.js +++ b/src/backend/src/middleware/configurable_auth.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const APIError = require('../api/APIError'); const config = require("../config"); const { LegacyTokenError } = require("../services/auth/AuthService"); diff --git a/src/backend/src/middleware/subdomain.js b/src/backend/src/middleware/subdomain.js index 6735b8c13a..babf286e7e 100644 --- a/src/backend/src/middleware/subdomain.js +++ b/src/backend/src/middleware/subdomain.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * This middleware checks the subdomain, and if the subdomain doesn't * match it calls `next('route')` to skip the current route. diff --git a/src/backend/src/om/entitystorage/OwnerLimitedES.js b/src/backend/src/om/entitystorage/OwnerLimitedES.js index 02909df0fa..6d5ac4fc45 100644 --- a/src/backend/src/om/entitystorage/OwnerLimitedES.js +++ b/src/backend/src/om/entitystorage/OwnerLimitedES.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { AppUnderUserActorType, UserActorType } = require("../../services/auth/Actor"); const context = require("../../util/context"); const { Context } = require("../../util/context"); diff --git a/src/backend/src/om/entitystorage/ProtectedAppES.js b/src/backend/src/om/entitystorage/ProtectedAppES.js index 8647cebc9a..7ee537ae6d 100644 --- a/src/backend/src/om/entitystorage/ProtectedAppES.js +++ b/src/backend/src/om/entitystorage/ProtectedAppES.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { AppUnderUserActorType, UserActorType } = require("../../services/auth/Actor"); const { Context } = require("../../util/context"); const { BaseES } = require("./BaseES"); diff --git a/src/backend/src/om/entitystorage/ReadOnlyES.js b/src/backend/src/om/entitystorage/ReadOnlyES.js index f506507315..2b15b2d7c8 100644 --- a/src/backend/src/om/entitystorage/ReadOnlyES.js +++ b/src/backend/src/om/entitystorage/ReadOnlyES.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const APIError = require("../../api/APIError"); const { BaseES } = require("./BaseES"); diff --git a/src/backend/src/om/mappings/notification.js b/src/backend/src/om/mappings/notification.js index 5808bbe37b..b1d976ae25 100644 --- a/src/backend/src/om/mappings/notification.js +++ b/src/backend/src/om/mappings/notification.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ module.exports = { sql: { table_name: 'notification' diff --git a/src/backend/src/routers/auth/configure-2fa.js b/src/backend/src/routers/auth/configure-2fa.js index 995e0e7a3a..5f1b444200 100644 --- a/src/backend/src/routers/auth/configure-2fa.js +++ b/src/backend/src/routers/auth/configure-2fa.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const APIError = require("../../api/APIError"); const eggspress = require("../../api/eggspress"); const { get_user } = require("../../helpers"); diff --git a/src/backend/src/routers/auth/delete-own-user.js b/src/backend/src/routers/auth/delete-own-user.js index 8235399cfd..878c4accc6 100644 --- a/src/backend/src/routers/auth/delete-own-user.js +++ b/src/backend/src/routers/auth/delete-own-user.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const eggspress = require("../../api/eggspress"); const { deleteUser, invalidate_cached_user } = require("../../helpers"); diff --git a/src/backend/src/routers/auth/grant-user-group.js b/src/backend/src/routers/auth/grant-user-group.js index a44b4e53d6..3196b2130e 100644 --- a/src/backend/src/routers/auth/grant-user-group.js +++ b/src/backend/src/routers/auth/grant-user-group.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const APIError = require("../../api/APIError"); const eggspress = require("../../api/eggspress"); const { UserActorType } = require("../../services/auth/Actor"); diff --git a/src/backend/src/routers/auth/grant-user-user.js b/src/backend/src/routers/auth/grant-user-user.js index eba591c06b..4dbbefb4bf 100644 --- a/src/backend/src/routers/auth/grant-user-user.js +++ b/src/backend/src/routers/auth/grant-user-user.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const APIError = require("../../api/APIError"); const eggspress = require("../../api/eggspress"); const { UserActorType } = require("../../services/auth/Actor"); diff --git a/src/backend/src/routers/auth/list-sessions.js b/src/backend/src/routers/auth/list-sessions.js index bdf94ca7c0..ebd0395bcb 100644 --- a/src/backend/src/routers/auth/list-sessions.js +++ b/src/backend/src/routers/auth/list-sessions.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const eggspress = require("../../api/eggspress"); const { UserActorType } = require("../../services/auth/Actor"); const { Context } = require("../../util/context"); diff --git a/src/backend/src/routers/auth/revoke-session.js b/src/backend/src/routers/auth/revoke-session.js index 5604066c4a..c5195c7214 100644 --- a/src/backend/src/routers/auth/revoke-session.js +++ b/src/backend/src/routers/auth/revoke-session.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const APIError = require("../../api/APIError"); const eggspress = require("../../api/eggspress"); const { UserActorType } = require("../../services/auth/Actor"); diff --git a/src/backend/src/routers/auth/revoke-user-group.js b/src/backend/src/routers/auth/revoke-user-group.js index f05f2cff46..82db556d82 100644 --- a/src/backend/src/routers/auth/revoke-user-group.js +++ b/src/backend/src/routers/auth/revoke-user-group.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const APIError = require("../../api/APIError"); const eggspress = require("../../api/eggspress"); const { UserActorType } = require("../../services/auth/Actor"); diff --git a/src/backend/src/routers/auth/revoke-user-user.js b/src/backend/src/routers/auth/revoke-user-user.js index a717a45899..838bfb905b 100644 --- a/src/backend/src/routers/auth/revoke-user-user.js +++ b/src/backend/src/routers/auth/revoke-user-user.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const APIError = require("../../api/APIError"); const eggspress = require("../../api/eggspress"); const { UserActorType } = require("../../services/auth/Actor"); diff --git a/src/backend/src/routers/down.js b/src/backend/src/routers/down.js index c1ee3b446c..7750691153 100644 --- a/src/backend/src/routers/down.js +++ b/src/backend/src/routers/down.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ "use strict" const express = require('express'); const router = express.Router(); diff --git a/src/backend/src/routers/user-protected/change-email.js b/src/backend/src/routers/user-protected/change-email.js index c4195712c7..bb6a2fa463 100644 --- a/src/backend/src/routers/user-protected/change-email.js +++ b/src/backend/src/routers/user-protected/change-email.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const APIError = require("../../api/APIError"); const { DB_WRITE } = require("../../services/database/consts"); const jwt = require('jsonwebtoken'); diff --git a/src/backend/src/routers/user-protected/change-password.js b/src/backend/src/routers/user-protected/change-password.js index de8bb2dee6..1ec8cf9d6d 100644 --- a/src/backend/src/routers/user-protected/change-password.js +++ b/src/backend/src/routers/user-protected/change-password.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ // TODO: DRY: This is the same function used by UIWindowChangePassword! const { invalidate_cached_user } = require("../../helpers"); diff --git a/src/backend/src/routers/user-protected/disable-2fa.js b/src/backend/src/routers/user-protected/disable-2fa.js index 5ada045137..4c2b1608c7 100644 --- a/src/backend/src/routers/user-protected/disable-2fa.js +++ b/src/backend/src/routers/user-protected/disable-2fa.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { DB_WRITE } = require("../../services/database/consts"); module.exports = { diff --git a/src/backend/src/services/AnomalyService.js b/src/backend/src/services/AnomalyService.js index a46fbb62fa..0c684e3a68 100644 --- a/src/backend/src/services/AnomalyService.js +++ b/src/backend/src/services/AnomalyService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const BaseService = require("./BaseService"); const DENY_SERVICE_INSTRUCTION = Symbol('DENY_SERVICE_INSTRUCTION'); diff --git a/src/backend/src/services/BroadcastService.js b/src/backend/src/services/BroadcastService.js index b999babffd..81266c2594 100644 --- a/src/backend/src/services/BroadcastService.js +++ b/src/backend/src/services/BroadcastService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { AdvancedBase } = require("@heyputer/puter-js-common"); const { Endpoint } = require("../util/expressutil"); const { UserActorType } = require("./auth/Actor"); diff --git a/src/backend/src/services/ComplainAboutVersionsService.js b/src/backend/src/services/ComplainAboutVersionsService.js index 64320da468..11b6b11fa6 100644 --- a/src/backend/src/services/ComplainAboutVersionsService.js +++ b/src/backend/src/services/ComplainAboutVersionsService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { BaseService } = require("../../exports"); const { surrounding_box } = require("../fun/dev-console-ui-utils"); diff --git a/src/backend/src/services/DefaultUserService.js b/src/backend/src/services/DefaultUserService.js index aa4446f9ff..556f203df3 100644 --- a/src/backend/src/services/DefaultUserService.js +++ b/src/backend/src/services/DefaultUserService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { surrounding_box } = require("../fun/dev-console-ui-utils"); const { get_user, generate_system_fsentries, invalidate_cached_user } = require("../helpers"); const { Context } = require("../util/context"); diff --git a/src/backend/src/services/DetailProviderService.js b/src/backend/src/services/DetailProviderService.js index 3d5d207444..e03dba1dfa 100644 --- a/src/backend/src/services/DetailProviderService.js +++ b/src/backend/src/services/DetailProviderService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const BaseService = require("./BaseService") /** diff --git a/src/backend/src/services/DevTODService.js b/src/backend/src/services/DevTODService.js index 400658bb23..661cf1982c 100644 --- a/src/backend/src/services/DevTODService.js +++ b/src/backend/src/services/DevTODService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { surrounding_box } = require("../fun/dev-console-ui-utils"); const BaseService = require("./BaseService"); diff --git a/src/backend/src/services/DevWatcherService.js b/src/backend/src/services/DevWatcherService.js index 71d506da8c..f980273786 100644 --- a/src/backend/src/services/DevWatcherService.js +++ b/src/backend/src/services/DevWatcherService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const BaseService = require("./BaseService"); class ProxyLogger { diff --git a/src/backend/src/services/GetUserService.js b/src/backend/src/services/GetUserService.js index ffe3d02b9d..9c3d2510e0 100644 --- a/src/backend/src/services/GetUserService.js +++ b/src/backend/src/services/GetUserService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const BaseService = require("./BaseService"); const { DB_READ } = require("./database/consts"); diff --git a/src/backend/src/services/HostDiskUsageService.js b/src/backend/src/services/HostDiskUsageService.js index 5e049aa7e0..fa2c50e88d 100644 --- a/src/backend/src/services/HostDiskUsageService.js +++ b/src/backend/src/services/HostDiskUsageService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { BaseService } = require("../../exports"); const { execSync } = require('child_process'); const config = require("../config"); diff --git a/src/backend/src/services/LockService.js b/src/backend/src/services/LockService.js index 25161ba091..f9eb78a6c9 100644 --- a/src/backend/src/services/LockService.js +++ b/src/backend/src/services/LockService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { RWLock } = require("../util/lockutil"); const BaseService = require("./BaseService"); diff --git a/src/backend/src/services/MountpointService.js b/src/backend/src/services/MountpointService.js index a8a24b5bb4..2b49426db0 100644 --- a/src/backend/src/services/MountpointService.js +++ b/src/backend/src/services/MountpointService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ // const Mountpoint = o => ({ ...o }); const BaseService = require("./BaseService"); diff --git a/src/backend/src/services/NotificationService.js b/src/backend/src/services/NotificationService.js index daf439e362..fda6b5a6c1 100644 --- a/src/backend/src/services/NotificationService.js +++ b/src/backend/src/services/NotificationService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const APIError = require("../api/APIError"); const auth2 = require("../middleware/auth2"); const { Endpoint } = require("../util/expressutil"); diff --git a/src/backend/src/services/PermissionAPIService.js b/src/backend/src/services/PermissionAPIService.js index 7404f88278..1318acab59 100644 --- a/src/backend/src/services/PermissionAPIService.js +++ b/src/backend/src/services/PermissionAPIService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { APIError } = require("openai"); const configurable_auth = require("../middleware/configurable_auth"); const { Endpoint } = require("../util/expressutil"); diff --git a/src/backend/src/services/ProtectedAppService.js b/src/backend/src/services/ProtectedAppService.js index 6628dd9e1c..17adfe67a3 100644 --- a/src/backend/src/services/ProtectedAppService.js +++ b/src/backend/src/services/ProtectedAppService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { get_app } = require("../helpers"); const { UserActorType } = require("./auth/Actor"); const { PermissionImplicator, PermissionUtil, PermissionRewriter } = require("./auth/PermissionService"); diff --git a/src/backend/src/services/PuterHomepageService.js b/src/backend/src/services/PuterHomepageService.js index 2e0a8a6dea..1e1ffbe779 100644 --- a/src/backend/src/services/PuterHomepageService.js +++ b/src/backend/src/services/PuterHomepageService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { PathBuilder } = require("../util/pathutil"); const BaseService = require("./BaseService"); diff --git a/src/backend/src/services/ScriptService.js b/src/backend/src/services/ScriptService.js index 800268b857..72aaeb1cea 100644 --- a/src/backend/src/services/ScriptService.js +++ b/src/backend/src/services/ScriptService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const BaseService = require("./BaseService"); class BackendScript { diff --git a/src/backend/src/services/SelfhostedService.js b/src/backend/src/services/SelfhostedService.js index 307c6c45f1..bfc952326b 100644 --- a/src/backend/src/services/SelfhostedService.js +++ b/src/backend/src/services/SelfhostedService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { DBKVStore } = require("../drivers/DBKVStore"); const { EntityStoreImplementation } = require("../drivers/EntityStoreImplementation"); const { HelloWorld } = require("../drivers/HelloWorld"); diff --git a/src/backend/src/services/ServeLandingService.js b/src/backend/src/services/ServeLandingService.js index f1c9cd9f85..880fa78c19 100644 --- a/src/backend/src/services/ServeLandingService.js +++ b/src/backend/src/services/ServeLandingService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * ServeLandingService is for "landing" pages, like payment success or failure. diff --git a/src/backend/src/services/ServeSingeFileService.js b/src/backend/src/services/ServeSingeFileService.js index e3d831e5da..9f47224d60 100644 --- a/src/backend/src/services/ServeSingeFileService.js +++ b/src/backend/src/services/ServeSingeFileService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const BaseService = require("./BaseService"); class ServeSingleFileService extends BaseService { diff --git a/src/backend/src/services/ServeStaticFilesService.js b/src/backend/src/services/ServeStaticFilesService.js index 3eddb8f13a..d303d45c6e 100644 --- a/src/backend/src/services/ServeStaticFilesService.js +++ b/src/backend/src/services/ServeStaticFilesService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const BaseService = require("./BaseService"); class ServeStaticFilesService extends BaseService { diff --git a/src/backend/src/services/ServicePatch.js b/src/backend/src/services/ServicePatch.js index ea70384516..f5b93b5b5b 100644 --- a/src/backend/src/services/ServicePatch.js +++ b/src/backend/src/services/ServicePatch.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { AdvancedBase } = require("@heyputer/puter-js-common"); class ServicePatch extends AdvancedBase { diff --git a/src/backend/src/services/SessionService.js b/src/backend/src/services/SessionService.js index fa8405a864..d88f93c7d9 100644 --- a/src/backend/src/services/SessionService.js +++ b/src/backend/src/services/SessionService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { invalidate_cached_user, get_user } = require("../helpers"); const { asyncSafeSetInterval } = require("../util/promise"); const { MINUTE, SECOND } = require("../util/time"); diff --git a/src/backend/src/services/ShareService.js b/src/backend/src/services/ShareService.js index bc67138abd..a2973938f8 100644 --- a/src/backend/src/services/ShareService.js +++ b/src/backend/src/services/ShareService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const APIError = require("../api/APIError"); const { get_user } = require("../helpers"); const configurable_auth = require("../middleware/configurable_auth"); diff --git a/src/backend/src/services/abuse-prevention/EdgeRateLimitService.js b/src/backend/src/services/abuse-prevention/EdgeRateLimitService.js index 01b8abe6f1..3d9963971a 100644 --- a/src/backend/src/services/abuse-prevention/EdgeRateLimitService.js +++ b/src/backend/src/services/abuse-prevention/EdgeRateLimitService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { Context } = require("../../util/context"); const { asyncSafeSetInterval } = require("../../util/promise"); const { quot } = require("../../util/strutil"); diff --git a/src/backend/src/services/auth/AntiCSRFService.js b/src/backend/src/services/auth/AntiCSRFService.js index 412f335363..5d9f436023 100644 --- a/src/backend/src/services/auth/AntiCSRFService.js +++ b/src/backend/src/services/auth/AntiCSRFService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const eggspress = require("../../api/eggspress"); const config = require("../../config"); const { subdomain } = require("../../helpers"); diff --git a/src/backend/src/services/auth/GroupService.js b/src/backend/src/services/auth/GroupService.js index 5694844fec..29d227741a 100644 --- a/src/backend/src/services/auth/GroupService.js +++ b/src/backend/src/services/auth/GroupService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const APIError = require("../../api/APIError"); const Group = require("../../entities/Group"); const { DENY_SERVICE_INSTRUCTION } = require("../AnomalyService"); diff --git a/src/backend/src/services/auth/OTPService.js b/src/backend/src/services/auth/OTPService.js index 4d14dcb4a7..205c27b1df 100644 --- a/src/backend/src/services/auth/OTPService.js +++ b/src/backend/src/services/auth/OTPService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const BaseService = require("../BaseService"); class OTPService extends BaseService { diff --git a/src/backend/src/services/auth/TokenService.js b/src/backend/src/services/auth/TokenService.js index 041e06cab1..2fe37bb280 100644 --- a/src/backend/src/services/auth/TokenService.js +++ b/src/backend/src/services/auth/TokenService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const BaseService = require("../BaseService"); const def = o => { diff --git a/src/backend/src/services/web/UserProtectedEndpointsService.js b/src/backend/src/services/web/UserProtectedEndpointsService.js index 73c401227c..16e0555642 100644 --- a/src/backend/src/services/web/UserProtectedEndpointsService.js +++ b/src/backend/src/services/web/UserProtectedEndpointsService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { get_user } = require("../../helpers"); const auth2 = require("../../middleware/auth2"); const { Context } = require("../../util/context"); diff --git a/src/backend/src/structured/sequence/check-user-permission.js b/src/backend/src/structured/sequence/check-user-permission.js index 3426b6082d..421a78ca75 100644 --- a/src/backend/src/structured/sequence/check-user-permission.js +++ b/src/backend/src/structured/sequence/check-user-permission.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { Sequence } = require("../../codex/Sequence"); const { get_user } = require("../../helpers"); const { Actor, UserActorType } = require("../../services/auth/Actor"); diff --git a/src/backend/src/structured/sequence/share.js b/src/backend/src/structured/sequence/share.js index 84aa6b7775..7c248b8d82 100644 --- a/src/backend/src/structured/sequence/share.js +++ b/src/backend/src/structured/sequence/share.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const APIError = require("../../api/APIError"); const { Sequence } = require("../../codex/Sequence"); const config = require("../../config"); diff --git a/src/backend/src/util/configutil.js b/src/backend/src/util/configutil.js index 12f707e09c..6414090303 100644 --- a/src/backend/src/util/configutil.js +++ b/src/backend/src/util/configutil.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ let memoized_common_template_vars_ = null; const get_common_template_vars = () => { const path_ = require('path'); diff --git a/src/backend/src/util/expressutil.js b/src/backend/src/util/expressutil.js index 2c9504865b..4b97e7a641 100644 --- a/src/backend/src/util/expressutil.js +++ b/src/backend/src/util/expressutil.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const eggspress = require("../api/eggspress"); const Endpoint = function Endpoint (spec) { diff --git a/src/backend/src/util/fnutil.js b/src/backend/src/util/fnutil.js index d444ca0512..ceb7620df2 100644 --- a/src/backend/src/util/fnutil.js +++ b/src/backend/src/util/fnutil.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const UtilFn = fn => { /** * A null-coalescing call diff --git a/src/backend/src/util/langutil.js b/src/backend/src/util/langutil.js index f066023487..8d39bd4144 100644 --- a/src/backend/src/util/langutil.js +++ b/src/backend/src/util/langutil.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * whatis is an alterative to typeof that reports what * the type of the value actually is for real. diff --git a/src/backend/src/util/pathutil.js b/src/backend/src/util/pathutil.js index 928db0bd7f..489827f8f5 100644 --- a/src/backend/src/util/pathutil.js +++ b/src/backend/src/util/pathutil.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { AdvancedBase } = require("@heyputer/puter-js-common"); /** diff --git a/src/backend/src/util/validutil.js b/src/backend/src/util/validutil.js index cdbdc7ac92..cb4a5f255d 100644 --- a/src/backend/src/util/validutil.js +++ b/src/backend/src/util/validutil.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const valid_file_size = v => { v = Number(v); if ( ! Number.isInteger(v) ) { diff --git a/src/backend/src/util/workutil.js b/src/backend/src/util/workutil.js index f76d1fd075..644a4b9767 100644 --- a/src/backend/src/util/workutil.js +++ b/src/backend/src/util/workutil.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ class WorkList { constructor () { this.locked_ = false; diff --git a/src/backend/tools/test.js b/src/backend/tools/test.js index c752fb6454..4eb44fc0aa 100644 --- a/src/backend/tools/test.js +++ b/src/backend/tools/test.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { AdvancedBase } = require("@heyputer/puter-js-common"); const useapi = require("useapi"); const { BaseService } = require("../exports"); diff --git a/src/contextlink/context.js b/src/contextlink/context.js index 6cbf3149aa..3c7bfe8f45 100644 --- a/src/contextlink/context.js +++ b/src/contextlink/context.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/contextlink/entry.js b/src/contextlink/entry.js index 1103462a5a..9bb711a67b 100644 --- a/src/contextlink/entry.js +++ b/src/contextlink/entry.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/contextlink/test/testcontext.js b/src/contextlink/test/testcontext.js index 040b4fd4fd..d57c4dd3dd 100644 --- a/src/contextlink/test/testcontext.js +++ b/src/contextlink/test/testcontext.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/dev-center/css/normalize.css b/src/dev-center/css/normalize.css index 192eb9ce43..bebf47bcc4 100644 --- a/src/dev-center/css/normalize.css +++ b/src/dev-center/css/normalize.css @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ /* Document diff --git a/src/dev-center/css/style.css b/src/dev-center/css/style.css index e4c7a4ba5b..62e7871cfe 100644 --- a/src/dev-center/css/style.css +++ b/src/dev-center/css/style.css @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/dev-center/js/dev-center.js b/src/dev-center/js/dev-center.js index 5a677f3f1a..0c4b8c7dfc 100644 --- a/src/dev-center/js/dev-center.js +++ b/src/dev-center/js/dev-center.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/dev-center/js/html-entities.js b/src/dev-center/js/html-entities.js index c233cb01ee..4f26dfbad3 100644 --- a/src/dev-center/js/html-entities.js +++ b/src/dev-center/js/html-entities.js @@ -1 +1,19 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ (()=>{"use strict";var r,e={563:function(r,e,a){var t=this&&this.__assign||function(){return(t=Object.assign||function(r){for(var e,a=1,t=arguments.length;a'"&]/g,nonAscii:/(?:[<>'"&\u0080-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/g,nonAsciiPrintable:/(?:[<>'"&\x01-\x08\x11-\x15\x17-\x1F\x7f-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/g,extensive:/(?:[\x01-\x0c\x0e-\x1f\x21-\x2c\x2e-\x2f\x3a-\x40\x5b-\x60\x7b-\x7d\x7f-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/g},n={mode:"specialChars",level:"all",numeric:"decimal"};e.encode=function(r,e){var a=void 0===(u=(c=void 0===e?n:e).mode)?"specialChars":u,t=void 0===(m=c.numeric)?"decimal":m,o=c.level;if(!r)return"";var c,u,p=i[a],d=s[void 0===o?"all":o].characters,g="hexadecimal"===t;if(p.lastIndex=0,c=p.exec(r)){u="";var m=0;do{m!==c.index&&(u+=r.substring(m,c.index));var f=d[o=c[0]];if(!f){var h=o.length>1?l.getCodePoint(o,0):o.charCodeAt(0);f=(g?"&#x"+h.toString(16):"&#"+h)+";"}u+=f,m=c.index+o.length}while(c=p.exec(r));m!==r.length&&(u+=r.substring(m))}else u=r;return u};var u={scope:"body",level:"all"},p=/&(?:#\d+|#[xX][\da-fA-F]+|[0-9a-zA-Z]+);/g,d=/&(?:#\d+|#[xX][\da-fA-F]+|[0-9a-zA-Z]+)[;=]?/g,g={xml:{strict:p,attribute:d,body:o.bodyRegExps.xml},html4:{strict:p,attribute:d,body:o.bodyRegExps.html4},html5:{strict:p,attribute:d,body:o.bodyRegExps.html5}},m=t(t({},g),{all:g.html5}),f=String.fromCharCode,h=f(65533),b={level:"all"};e.decodeEntity=function(r,e){var a=void 0===(t=(void 0===e?b:e).level)?"all":t;if(!r)return"";var t=r,o=(r[r.length-1],s[a].entities[r]);if(o)t=o;else if("&"===r[0]&&"#"===r[1]){var i=r[2],n="x"==i||"X"==i?parseInt(r.substr(3),16):parseInt(r.substr(2));t=n>=1114111?h:n>65535?l.fromCodePoint(n):f(c.numericUnicodeMap[n]||n)}return t},e.decode=function(r,e){var a=void 0===e?u:e,t=a.level,o=void 0===t?"all":t,i=a.scope,n=void 0===i?"xml"===o?"strict":"body":i;if(!r)return"";var p=m[o][n],d=s[o].entities,g="attribute"===n,b="strict"===n;p.lastIndex=0;var v,q=p.exec(r);if(q){v="";var y=0;do{y!==q.index&&(v+=r.substring(y,q.index));var w=q[0],x=w,A=w[w.length-1];if(g&&"="===A)x=w;else if(b&&";"!==A)x=w;else{var E=d[w];if(E)x=E;else if("&"===w[0]&&"#"===w[1]){var D=w[2],k="x"==D||"X"==D?parseInt(w.substr(3),16):parseInt(w.substr(2));x=k>=1114111?h:k>65535?l.fromCodePoint(k):f(c.numericUnicodeMap[k]||k)}}v+=x,y=q.index+w.length}while(q=p.exec(r));y!==r.length&&(v+=r.substring(y))}else v=r;return v}},81:(r,e)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.bodyRegExps={xml:/&(?:#\d+|#[xX][\da-fA-F]+|[0-9a-zA-Z]+);?/g,html4:/&(?:nbsp|iexcl|cent|pound|curren|yen|brvbar|sect|uml|copy|ordf|laquo|not|shy|reg|macr|deg|plusmn|sup2|sup3|acute|micro|para|middot|cedil|sup1|ordm|raquo|frac14|frac12|frac34|iquest|Agrave|Aacute|Acirc|Atilde|Auml|Aring|AElig|Ccedil|Egrave|Eacute|Ecirc|Euml|Igrave|Iacute|Icirc|Iuml|ETH|Ntilde|Ograve|Oacute|Ocirc|Otilde|Ouml|times|Oslash|Ugrave|Uacute|Ucirc|Uuml|Yacute|THORN|szlig|agrave|aacute|acirc|atilde|auml|aring|aelig|ccedil|egrave|eacute|ecirc|euml|igrave|iacute|icirc|iuml|eth|ntilde|ograve|oacute|ocirc|otilde|ouml|divide|oslash|ugrave|uacute|ucirc|uuml|yacute|thorn|yuml|quot|amp|lt|gt|#\d+|#[xX][\da-fA-F]+|[0-9a-zA-Z]+);?/g,html5:/&(?:AElig|AMP|Aacute|Acirc|Agrave|Aring|Atilde|Auml|COPY|Ccedil|ETH|Eacute|Ecirc|Egrave|Euml|GT|Iacute|Icirc|Igrave|Iuml|LT|Ntilde|Oacute|Ocirc|Ograve|Oslash|Otilde|Ouml|QUOT|REG|THORN|Uacute|Ucirc|Ugrave|Uuml|Yacute|aacute|acirc|acute|aelig|agrave|amp|aring|atilde|auml|brvbar|ccedil|cedil|cent|copy|curren|deg|divide|eacute|ecirc|egrave|eth|euml|frac12|frac14|frac34|gt|iacute|icirc|iexcl|igrave|iquest|iuml|laquo|lt|macr|micro|middot|nbsp|not|ntilde|oacute|ocirc|ograve|ordf|ordm|oslash|otilde|ouml|para|plusmn|pound|quot|raquo|reg|sect|shy|sup1|sup2|sup3|szlig|thorn|times|uacute|ucirc|ugrave|uml|uuml|yacute|yen|yuml|#\d+|#[xX][\da-fA-F]+|[0-9a-zA-Z]+);?/g},e.namedReferences={xml:{entities:{"<":"<",">":">",""":'"',"'":"'","&":"&"},characters:{"<":"<",">":">",'"':""","'":"'","&":"&"}},html4:{entities:{"'":"'"," ":" "," ":" ","¡":"¡","¡":"¡","¢":"¢","¢":"¢","£":"£","£":"£","¤":"¤","¤":"¤","¥":"¥","¥":"¥","¦":"¦","¦":"¦","§":"§","§":"§","¨":"¨","¨":"¨","©":"©","©":"©","ª":"ª","ª":"ª","«":"«","«":"«","¬":"¬","¬":"¬","­":"­","­":"­","®":"®","®":"®","¯":"¯","¯":"¯","°":"°","°":"°","±":"±","±":"±","²":"²","²":"²","³":"³","³":"³","´":"´","´":"´","µ":"µ","µ":"µ","¶":"¶","¶":"¶","·":"·","·":"·","¸":"¸","¸":"¸","¹":"¹","¹":"¹","º":"º","º":"º","»":"»","»":"»","¼":"¼","¼":"¼","½":"½","½":"½","¾":"¾","¾":"¾","¿":"¿","¿":"¿","À":"À","À":"À","Á":"Á","Á":"Á","Â":"Â","Â":"Â","Ã":"Ã","Ã":"Ã","Ä":"Ä","Ä":"Ä","Å":"Å","Å":"Å","Æ":"Æ","Æ":"Æ","Ç":"Ç","Ç":"Ç","È":"È","È":"È","É":"É","É":"É","Ê":"Ê","Ê":"Ê","Ë":"Ë","Ë":"Ë","Ì":"Ì","Ì":"Ì","Í":"Í","Í":"Í","Î":"Î","Î":"Î","Ï":"Ï","Ï":"Ï","Ð":"Ð","Ð":"Ð","Ñ":"Ñ","Ñ":"Ñ","Ò":"Ò","Ò":"Ò","Ó":"Ó","Ó":"Ó","Ô":"Ô","Ô":"Ô","Õ":"Õ","Õ":"Õ","Ö":"Ö","Ö":"Ö","×":"×","×":"×","Ø":"Ø","Ø":"Ø","Ù":"Ù","Ù":"Ù","Ú":"Ú","Ú":"Ú","Û":"Û","Û":"Û","Ü":"Ü","Ü":"Ü","Ý":"Ý","Ý":"Ý","Þ":"Þ","Þ":"Þ","ß":"ß","ß":"ß","à":"à","à":"à","á":"á","á":"á","â":"â","â":"â","ã":"ã","ã":"ã","ä":"ä","ä":"ä","å":"å","å":"å","æ":"æ","æ":"æ","ç":"ç","ç":"ç","è":"è","è":"è","é":"é","é":"é","ê":"ê","ê":"ê","ë":"ë","ë":"ë","ì":"ì","ì":"ì","í":"í","í":"í","î":"î","î":"î","ï":"ï","ï":"ï","ð":"ð","ð":"ð","ñ":"ñ","ñ":"ñ","ò":"ò","ò":"ò","ó":"ó","ó":"ó","ô":"ô","ô":"ô","õ":"õ","õ":"õ","ö":"ö","ö":"ö","÷":"÷","÷":"÷","ø":"ø","ø":"ø","ù":"ù","ù":"ù","ú":"ú","ú":"ú","û":"û","û":"û","ü":"ü","ü":"ü","ý":"ý","ý":"ý","þ":"þ","þ":"þ","ÿ":"ÿ","ÿ":"ÿ",""":'"',""":'"',"&":"&","&":"&","<":"<","<":"<",">":">",">":">","Œ":"Œ","œ":"œ","Š":"Š","š":"š","Ÿ":"Ÿ","ˆ":"ˆ","˜":"˜"," ":" "," ":" "," ":" ","‌":"‌","‍":"‍","‎":"‎","‏":"‏","–":"–","—":"—","‘":"‘","’":"’","‚":"‚","“":"“","”":"”","„":"„","†":"†","‡":"‡","‰":"‰","‹":"‹","›":"›","€":"€","ƒ":"ƒ","Α":"Α","Β":"Β","Γ":"Γ","Δ":"Δ","Ε":"Ε","Ζ":"Ζ","Η":"Η","Θ":"Θ","Ι":"Ι","Κ":"Κ","Λ":"Λ","Μ":"Μ","Ν":"Ν","Ξ":"Ξ","Ο":"Ο","Π":"Π","Ρ":"Ρ","Σ":"Σ","Τ":"Τ","Υ":"Υ","Φ":"Φ","Χ":"Χ","Ψ":"Ψ","Ω":"Ω","α":"α","β":"β","γ":"γ","δ":"δ","ε":"ε","ζ":"ζ","η":"η","θ":"θ","ι":"ι","κ":"κ","λ":"λ","μ":"μ","ν":"ν","ξ":"ξ","ο":"ο","π":"π","ρ":"ρ","ς":"ς","σ":"σ","τ":"τ","υ":"υ","φ":"φ","χ":"χ","ψ":"ψ","ω":"ω","ϑ":"ϑ","ϒ":"ϒ","ϖ":"ϖ","•":"•","…":"…","′":"′","″":"″","‾":"‾","⁄":"⁄","℘":"℘","ℑ":"ℑ","ℜ":"ℜ","™":"™","ℵ":"ℵ","←":"←","↑":"↑","→":"→","↓":"↓","↔":"↔","↵":"↵","⇐":"⇐","⇑":"⇑","⇒":"⇒","⇓":"⇓","⇔":"⇔","∀":"∀","∂":"∂","∃":"∃","∅":"∅","∇":"∇","∈":"∈","∉":"∉","∋":"∋","∏":"∏","∑":"∑","−":"−","∗":"∗","√":"√","∝":"∝","∞":"∞","∠":"∠","∧":"∧","∨":"∨","∩":"∩","∪":"∪","∫":"∫","∴":"∴","∼":"∼","≅":"≅","≈":"≈","≠":"≠","≡":"≡","≤":"≤","≥":"≥","⊂":"⊂","⊃":"⊃","⊄":"⊄","⊆":"⊆","⊇":"⊇","⊕":"⊕","⊗":"⊗","⊥":"⊥","⋅":"⋅","⌈":"⌈","⌉":"⌉","⌊":"⌊","⌋":"⌋","⟨":"〈","⟩":"〉","◊":"◊","♠":"♠","♣":"♣","♥":"♥","♦":"♦"},characters:{"'":"'"," ":" ","¡":"¡","¢":"¢","£":"£","¤":"¤","¥":"¥","¦":"¦","§":"§","¨":"¨","©":"©",ª:"ª","«":"«","¬":"¬","­":"­","®":"®","¯":"¯","°":"°","±":"±","²":"²","³":"³","´":"´",µ:"µ","¶":"¶","·":"·","¸":"¸","¹":"¹",º:"º","»":"»","¼":"¼","½":"½","¾":"¾","¿":"¿",À:"À",Á:"Á",Â:"Â",Ã:"Ã",Ä:"Ä",Å:"Å",Æ:"Æ",Ç:"Ç",È:"È",É:"É",Ê:"Ê",Ë:"Ë",Ì:"Ì",Í:"Í",Î:"Î",Ï:"Ï",Ð:"Ð",Ñ:"Ñ",Ò:"Ò",Ó:"Ó",Ô:"Ô",Õ:"Õ",Ö:"Ö","×":"×",Ø:"Ø",Ù:"Ù",Ú:"Ú",Û:"Û",Ü:"Ü",Ý:"Ý",Þ:"Þ",ß:"ß",à:"à",á:"á",â:"â",ã:"ã",ä:"ä",å:"å",æ:"æ",ç:"ç",è:"è",é:"é",ê:"ê",ë:"ë",ì:"ì",í:"í",î:"î",ï:"ï",ð:"ð",ñ:"ñ",ò:"ò",ó:"ó",ô:"ô",õ:"õ",ö:"ö","÷":"÷",ø:"ø",ù:"ù",ú:"ú",û:"û",ü:"ü",ý:"ý",þ:"þ",ÿ:"ÿ",'"':""","&":"&","<":"<",">":">",Œ:"Œ",œ:"œ",Š:"Š",š:"š",Ÿ:"Ÿ",ˆ:"ˆ","˜":"˜"," ":" "," ":" "," ":" ","‌":"‌","‍":"‍","‎":"‎","‏":"‏","–":"–","—":"—","‘":"‘","’":"’","‚":"‚","“":"“","”":"”","„":"„","†":"†","‡":"‡","‰":"‰","‹":"‹","›":"›","€":"€",ƒ:"ƒ",Α:"Α",Β:"Β",Γ:"Γ",Δ:"Δ",Ε:"Ε",Ζ:"Ζ",Η:"Η",Θ:"Θ",Ι:"Ι",Κ:"Κ",Λ:"Λ",Μ:"Μ",Ν:"Ν",Ξ:"Ξ",Ο:"Ο",Π:"Π",Ρ:"Ρ",Σ:"Σ",Τ:"Τ",Υ:"Υ",Φ:"Φ",Χ:"Χ",Ψ:"Ψ",Ω:"Ω",α:"α",β:"β",γ:"γ",δ:"δ",ε:"ε",ζ:"ζ",η:"η",θ:"θ",ι:"ι",κ:"κ",λ:"λ",μ:"μ",ν:"ν",ξ:"ξ",ο:"ο",π:"π",ρ:"ρ",ς:"ς",σ:"σ",τ:"τ",υ:"υ",φ:"φ",χ:"χ",ψ:"ψ",ω:"ω",ϑ:"ϑ",ϒ:"ϒ",ϖ:"ϖ","•":"•","…":"…","′":"′","″":"″","‾":"‾","⁄":"⁄",℘:"℘",ℑ:"ℑ",ℜ:"ℜ","™":"™",ℵ:"ℵ","←":"←","↑":"↑","→":"→","↓":"↓","↔":"↔","↵":"↵","⇐":"⇐","⇑":"⇑","⇒":"⇒","⇓":"⇓","⇔":"⇔","∀":"∀","∂":"∂","∃":"∃","∅":"∅","∇":"∇","∈":"∈","∉":"∉","∋":"∋","∏":"∏","∑":"∑","−":"−","∗":"∗","√":"√","∝":"∝","∞":"∞","∠":"∠","∧":"∧","∨":"∨","∩":"∩","∪":"∪","∫":"∫","∴":"∴","∼":"∼","≅":"≅","≈":"≈","≠":"≠","≡":"≡","≤":"≤","≥":"≥","⊂":"⊂","⊃":"⊃","⊄":"⊄","⊆":"⊆","⊇":"⊇","⊕":"⊕","⊗":"⊗","⊥":"⊥","⋅":"⋅","⌈":"⌈","⌉":"⌉","⌊":"⌊","⌋":"⌋","〈":"⟨","〉":"⟩","◊":"◊","♠":"♠","♣":"♣","♥":"♥","♦":"♦"}},html5:{entities:{"Æ":"Æ","Æ":"Æ","&":"&","&":"&","Á":"Á","Á":"Á","Ă":"Ă","Â":"Â","Â":"Â","А":"А","𝔄":"𝔄","À":"À","À":"À","Α":"Α","Ā":"Ā","⩓":"⩓","Ą":"Ą","𝔸":"𝔸","⁡":"⁡","Å":"Å","Å":"Å","𝒜":"𝒜","≔":"≔","Ã":"Ã","Ã":"Ã","Ä":"Ä","Ä":"Ä","∖":"∖","⫧":"⫧","⌆":"⌆","Б":"Б","∵":"∵","ℬ":"ℬ","Β":"Β","𝔅":"𝔅","𝔹":"𝔹","˘":"˘","ℬ":"ℬ","≎":"≎","Ч":"Ч","©":"©","©":"©","Ć":"Ć","⋒":"⋒","ⅅ":"ⅅ","ℭ":"ℭ","Č":"Č","Ç":"Ç","Ç":"Ç","Ĉ":"Ĉ","∰":"∰","Ċ":"Ċ","¸":"¸","·":"·","ℭ":"ℭ","Χ":"Χ","⊙":"⊙","⊖":"⊖","⊕":"⊕","⊗":"⊗","∲":"∲","”":"”","’":"’","∷":"∷","⩴":"⩴","≡":"≡","∯":"∯","∮":"∮","ℂ":"ℂ","∐":"∐","∳":"∳","⨯":"⨯","𝒞":"𝒞","⋓":"⋓","≍":"≍","ⅅ":"ⅅ","⤑":"⤑","Ђ":"Ђ","Ѕ":"Ѕ","Џ":"Џ","‡":"‡","↡":"↡","⫤":"⫤","Ď":"Ď","Д":"Д","∇":"∇","Δ":"Δ","𝔇":"𝔇","´":"´","˙":"˙","˝":"˝","`":"`","˜":"˜","⋄":"⋄","ⅆ":"ⅆ","𝔻":"𝔻","¨":"¨","⃜":"⃜","≐":"≐","∯":"∯","¨":"¨","⇓":"⇓","⇐":"⇐","⇔":"⇔","⫤":"⫤","⟸":"⟸","⟺":"⟺","⟹":"⟹","⇒":"⇒","⊨":"⊨","⇑":"⇑","⇕":"⇕","∥":"∥","↓":"↓","⤓":"⤓","⇵":"⇵","̑":"̑","⥐":"⥐","⥞":"⥞","↽":"↽","⥖":"⥖","⥟":"⥟","⇁":"⇁","⥗":"⥗","⊤":"⊤","↧":"↧","⇓":"⇓","𝒟":"𝒟","Đ":"Đ","Ŋ":"Ŋ","Ð":"Ð","Ð":"Ð","É":"É","É":"É","Ě":"Ě","Ê":"Ê","Ê":"Ê","Э":"Э","Ė":"Ė","𝔈":"𝔈","È":"È","È":"È","∈":"∈","Ē":"Ē","◻":"◻","▫":"▫","Ę":"Ę","𝔼":"𝔼","Ε":"Ε","⩵":"⩵","≂":"≂","⇌":"⇌","ℰ":"ℰ","⩳":"⩳","Η":"Η","Ë":"Ë","Ë":"Ë","∃":"∃","ⅇ":"ⅇ","Ф":"Ф","𝔉":"𝔉","◼":"◼","▪":"▪","𝔽":"𝔽","∀":"∀","ℱ":"ℱ","ℱ":"ℱ","Ѓ":"Ѓ",">":">",">":">","Γ":"Γ","Ϝ":"Ϝ","Ğ":"Ğ","Ģ":"Ģ","Ĝ":"Ĝ","Г":"Г","Ġ":"Ġ","𝔊":"𝔊","⋙":"⋙","𝔾":"𝔾","≥":"≥","⋛":"⋛","≧":"≧","⪢":"⪢","≷":"≷","⩾":"⩾","≳":"≳","𝒢":"𝒢","≫":"≫","Ъ":"Ъ","ˇ":"ˇ","^":"^","Ĥ":"Ĥ","ℌ":"ℌ","ℋ":"ℋ","ℍ":"ℍ","─":"─","ℋ":"ℋ","Ħ":"Ħ","≎":"≎","≏":"≏","Е":"Е","IJ":"IJ","Ё":"Ё","Í":"Í","Í":"Í","Î":"Î","Î":"Î","И":"И","İ":"İ","ℑ":"ℑ","Ì":"Ì","Ì":"Ì","ℑ":"ℑ","Ī":"Ī","ⅈ":"ⅈ","⇒":"⇒","∬":"∬","∫":"∫","⋂":"⋂","⁣":"⁣","⁢":"⁢","Į":"Į","𝕀":"𝕀","Ι":"Ι","ℐ":"ℐ","Ĩ":"Ĩ","І":"І","Ï":"Ï","Ï":"Ï","Ĵ":"Ĵ","Й":"Й","𝔍":"𝔍","𝕁":"𝕁","𝒥":"𝒥","Ј":"Ј","Є":"Є","Х":"Х","Ќ":"Ќ","Κ":"Κ","Ķ":"Ķ","К":"К","𝔎":"𝔎","𝕂":"𝕂","𝒦":"𝒦","Љ":"Љ","<":"<","<":"<","Ĺ":"Ĺ","Λ":"Λ","⟪":"⟪","ℒ":"ℒ","↞":"↞","Ľ":"Ľ","Ļ":"Ļ","Л":"Л","⟨":"⟨","←":"←","⇤":"⇤","⇆":"⇆","⌈":"⌈","⟦":"⟦","⥡":"⥡","⇃":"⇃","⥙":"⥙","⌊":"⌊","↔":"↔","⥎":"⥎","⊣":"⊣","↤":"↤","⥚":"⥚","⊲":"⊲","⧏":"⧏","⊴":"⊴","⥑":"⥑","⥠":"⥠","↿":"↿","⥘":"⥘","↼":"↼","⥒":"⥒","⇐":"⇐","⇔":"⇔","⋚":"⋚","≦":"≦","≶":"≶","⪡":"⪡","⩽":"⩽","≲":"≲","𝔏":"𝔏","⋘":"⋘","⇚":"⇚","Ŀ":"Ŀ","⟵":"⟵","⟷":"⟷","⟶":"⟶","⟸":"⟸","⟺":"⟺","⟹":"⟹","𝕃":"𝕃","↙":"↙","↘":"↘","ℒ":"ℒ","↰":"↰","Ł":"Ł","≪":"≪","⤅":"⤅","М":"М"," ":" ","ℳ":"ℳ","𝔐":"𝔐","∓":"∓","𝕄":"𝕄","ℳ":"ℳ","Μ":"Μ","Њ":"Њ","Ń":"Ń","Ň":"Ň","Ņ":"Ņ","Н":"Н","​":"​","​":"​","​":"​","​":"​","≫":"≫","≪":"≪"," ":"\n","𝔑":"𝔑","⁠":"⁠"," ":" ","ℕ":"ℕ","⫬":"⫬","≢":"≢","≭":"≭","∦":"∦","∉":"∉","≠":"≠","≂̸":"≂̸","∄":"∄","≯":"≯","≱":"≱","≧̸":"≧̸","≫̸":"≫̸","≹":"≹","⩾̸":"⩾̸","≵":"≵","≎̸":"≎̸","≏̸":"≏̸","⋪":"⋪","⧏̸":"⧏̸","⋬":"⋬","≮":"≮","≰":"≰","≸":"≸","≪̸":"≪̸","⩽̸":"⩽̸","≴":"≴","⪢̸":"⪢̸","⪡̸":"⪡̸","⊀":"⊀","⪯̸":"⪯̸","⋠":"⋠","∌":"∌","⋫":"⋫","⧐̸":"⧐̸","⋭":"⋭","⊏̸":"⊏̸","⋢":"⋢","⊐̸":"⊐̸","⋣":"⋣","⊂⃒":"⊂⃒","⊈":"⊈","⊁":"⊁","⪰̸":"⪰̸","⋡":"⋡","≿̸":"≿̸","⊃⃒":"⊃⃒","⊉":"⊉","≁":"≁","≄":"≄","≇":"≇","≉":"≉","∤":"∤","𝒩":"𝒩","Ñ":"Ñ","Ñ":"Ñ","Ν":"Ν","Œ":"Œ","Ó":"Ó","Ó":"Ó","Ô":"Ô","Ô":"Ô","О":"О","Ő":"Ő","𝔒":"𝔒","Ò":"Ò","Ò":"Ò","Ō":"Ō","Ω":"Ω","Ο":"Ο","𝕆":"𝕆","“":"“","‘":"‘","⩔":"⩔","𝒪":"𝒪","Ø":"Ø","Ø":"Ø","Õ":"Õ","Õ":"Õ","⨷":"⨷","Ö":"Ö","Ö":"Ö","‾":"‾","⏞":"⏞","⎴":"⎴","⏜":"⏜","∂":"∂","П":"П","𝔓":"𝔓","Φ":"Φ","Π":"Π","±":"±","ℌ":"ℌ","ℙ":"ℙ","⪻":"⪻","≺":"≺","⪯":"⪯","≼":"≼","≾":"≾","″":"″","∏":"∏","∷":"∷","∝":"∝","𝒫":"𝒫","Ψ":"Ψ",""":'"',""":'"',"𝔔":"𝔔","ℚ":"ℚ","𝒬":"𝒬","⤐":"⤐","®":"®","®":"®","Ŕ":"Ŕ","⟫":"⟫","↠":"↠","⤖":"⤖","Ř":"Ř","Ŗ":"Ŗ","Р":"Р","ℜ":"ℜ","∋":"∋","⇋":"⇋","⥯":"⥯","ℜ":"ℜ","Ρ":"Ρ","⟩":"⟩","→":"→","⇥":"⇥","⇄":"⇄","⌉":"⌉","⟧":"⟧","⥝":"⥝","⇂":"⇂","⥕":"⥕","⌋":"⌋","⊢":"⊢","↦":"↦","⥛":"⥛","⊳":"⊳","⧐":"⧐","⊵":"⊵","⥏":"⥏","⥜":"⥜","↾":"↾","⥔":"⥔","⇀":"⇀","⥓":"⥓","⇒":"⇒","ℝ":"ℝ","⥰":"⥰","⇛":"⇛","ℛ":"ℛ","↱":"↱","⧴":"⧴","Щ":"Щ","Ш":"Ш","Ь":"Ь","Ś":"Ś","⪼":"⪼","Š":"Š","Ş":"Ş","Ŝ":"Ŝ","С":"С","𝔖":"𝔖","↓":"↓","←":"←","→":"→","↑":"↑","Σ":"Σ","∘":"∘","𝕊":"𝕊","√":"√","□":"□","⊓":"⊓","⊏":"⊏","⊑":"⊑","⊐":"⊐","⊒":"⊒","⊔":"⊔","𝒮":"𝒮","⋆":"⋆","⋐":"⋐","⋐":"⋐","⊆":"⊆","≻":"≻","⪰":"⪰","≽":"≽","≿":"≿","∋":"∋","∑":"∑","⋑":"⋑","⊃":"⊃","⊇":"⊇","⋑":"⋑","Þ":"Þ","Þ":"Þ","™":"™","Ћ":"Ћ","Ц":"Ц"," ":"\t","Τ":"Τ","Ť":"Ť","Ţ":"Ţ","Т":"Т","𝔗":"𝔗","∴":"∴","Θ":"Θ","  ":"  "," ":" ","∼":"∼","≃":"≃","≅":"≅","≈":"≈","𝕋":"𝕋","⃛":"⃛","𝒯":"𝒯","Ŧ":"Ŧ","Ú":"Ú","Ú":"Ú","↟":"↟","⥉":"⥉","Ў":"Ў","Ŭ":"Ŭ","Û":"Û","Û":"Û","У":"У","Ű":"Ű","𝔘":"𝔘","Ù":"Ù","Ù":"Ù","Ū":"Ū","_":"_","⏟":"⏟","⎵":"⎵","⏝":"⏝","⋃":"⋃","⊎":"⊎","Ų":"Ų","𝕌":"𝕌","↑":"↑","⤒":"⤒","⇅":"⇅","↕":"↕","⥮":"⥮","⊥":"⊥","↥":"↥","⇑":"⇑","⇕":"⇕","↖":"↖","↗":"↗","ϒ":"ϒ","Υ":"Υ","Ů":"Ů","𝒰":"𝒰","Ũ":"Ũ","Ü":"Ü","Ü":"Ü","⊫":"⊫","⫫":"⫫","В":"В","⊩":"⊩","⫦":"⫦","⋁":"⋁","‖":"‖","‖":"‖","∣":"∣","|":"|","❘":"❘","≀":"≀"," ":" ","𝔙":"𝔙","𝕍":"𝕍","𝒱":"𝒱","⊪":"⊪","Ŵ":"Ŵ","⋀":"⋀","𝔚":"𝔚","𝕎":"𝕎","𝒲":"𝒲","𝔛":"𝔛","Ξ":"Ξ","𝕏":"𝕏","𝒳":"𝒳","Я":"Я","Ї":"Ї","Ю":"Ю","Ý":"Ý","Ý":"Ý","Ŷ":"Ŷ","Ы":"Ы","𝔜":"𝔜","𝕐":"𝕐","𝒴":"𝒴","Ÿ":"Ÿ","Ж":"Ж","Ź":"Ź","Ž":"Ž","З":"З","Ż":"Ż","​":"​","Ζ":"Ζ","ℨ":"ℨ","ℤ":"ℤ","𝒵":"𝒵","á":"á","á":"á","ă":"ă","∾":"∾","∾̳":"∾̳","∿":"∿","â":"â","â":"â","´":"´","´":"´","а":"а","æ":"æ","æ":"æ","⁡":"⁡","𝔞":"𝔞","à":"à","à":"à","ℵ":"ℵ","ℵ":"ℵ","α":"α","ā":"ā","⨿":"⨿","&":"&","&":"&","∧":"∧","⩕":"⩕","⩜":"⩜","⩘":"⩘","⩚":"⩚","∠":"∠","⦤":"⦤","∠":"∠","∡":"∡","⦨":"⦨","⦩":"⦩","⦪":"⦪","⦫":"⦫","⦬":"⦬","⦭":"⦭","⦮":"⦮","⦯":"⦯","∟":"∟","⊾":"⊾","⦝":"⦝","∢":"∢","Å":"Å","⍼":"⍼","ą":"ą","𝕒":"𝕒","≈":"≈","⩰":"⩰","⩯":"⩯","≊":"≊","≋":"≋","'":"'","≈":"≈","≊":"≊","å":"å","å":"å","𝒶":"𝒶","*":"*","≈":"≈","≍":"≍","ã":"ã","ã":"ã","ä":"ä","ä":"ä","∳":"∳","⨑":"⨑","⫭":"⫭","≌":"≌","϶":"϶","‵":"‵","∽":"∽","⋍":"⋍","⊽":"⊽","⌅":"⌅","⌅":"⌅","⎵":"⎵","⎶":"⎶","≌":"≌","б":"б","„":"„","∵":"∵","∵":"∵","⦰":"⦰","϶":"϶","ℬ":"ℬ","β":"β","ℶ":"ℶ","≬":"≬","𝔟":"𝔟","⋂":"⋂","◯":"◯","⋃":"⋃","⨀":"⨀","⨁":"⨁","⨂":"⨂","⨆":"⨆","★":"★","▽":"▽","△":"△","⨄":"⨄","⋁":"⋁","⋀":"⋀","⤍":"⤍","⧫":"⧫","▪":"▪","▴":"▴","▾":"▾","◂":"◂","▸":"▸","␣":"␣","▒":"▒","░":"░","▓":"▓","█":"█","=⃥":"=⃥","≡⃥":"≡⃥","⌐":"⌐","𝕓":"𝕓","⊥":"⊥","⊥":"⊥","⋈":"⋈","╗":"╗","╔":"╔","╖":"╖","╓":"╓","═":"═","╦":"╦","╩":"╩","╤":"╤","╧":"╧","╝":"╝","╚":"╚","╜":"╜","╙":"╙","║":"║","╬":"╬","╣":"╣","╠":"╠","╫":"╫","╢":"╢","╟":"╟","⧉":"⧉","╕":"╕","╒":"╒","┐":"┐","┌":"┌","─":"─","╥":"╥","╨":"╨","┬":"┬","┴":"┴","⊟":"⊟","⊞":"⊞","⊠":"⊠","╛":"╛","╘":"╘","┘":"┘","└":"└","│":"│","╪":"╪","╡":"╡","╞":"╞","┼":"┼","┤":"┤","├":"├","‵":"‵","˘":"˘","¦":"¦","¦":"¦","𝒷":"𝒷","⁏":"⁏","∽":"∽","⋍":"⋍","\":"\\","⧅":"⧅","⟈":"⟈","•":"•","•":"•","≎":"≎","⪮":"⪮","≏":"≏","≏":"≏","ć":"ć","∩":"∩","⩄":"⩄","⩉":"⩉","⩋":"⩋","⩇":"⩇","⩀":"⩀","∩︀":"∩︀","⁁":"⁁","ˇ":"ˇ","⩍":"⩍","č":"č","ç":"ç","ç":"ç","ĉ":"ĉ","⩌":"⩌","⩐":"⩐","ċ":"ċ","¸":"¸","¸":"¸","⦲":"⦲","¢":"¢","¢":"¢","·":"·","𝔠":"𝔠","ч":"ч","✓":"✓","✓":"✓","χ":"χ","○":"○","⧃":"⧃","ˆ":"ˆ","≗":"≗","↺":"↺","↻":"↻","®":"®","Ⓢ":"Ⓢ","⊛":"⊛","⊚":"⊚","⊝":"⊝","≗":"≗","⨐":"⨐","⫯":"⫯","⧂":"⧂","♣":"♣","♣":"♣",":":":","≔":"≔","≔":"≔",",":",","@":"@","∁":"∁","∘":"∘","∁":"∁","ℂ":"ℂ","≅":"≅","⩭":"⩭","∮":"∮","𝕔":"𝕔","∐":"∐","©":"©","©":"©","℗":"℗","↵":"↵","✗":"✗","𝒸":"𝒸","⫏":"⫏","⫑":"⫑","⫐":"⫐","⫒":"⫒","⋯":"⋯","⤸":"⤸","⤵":"⤵","⋞":"⋞","⋟":"⋟","↶":"↶","⤽":"⤽","∪":"∪","⩈":"⩈","⩆":"⩆","⩊":"⩊","⊍":"⊍","⩅":"⩅","∪︀":"∪︀","↷":"↷","⤼":"⤼","⋞":"⋞","⋟":"⋟","⋎":"⋎","⋏":"⋏","¤":"¤","¤":"¤","↶":"↶","↷":"↷","⋎":"⋎","⋏":"⋏","∲":"∲","∱":"∱","⌭":"⌭","⇓":"⇓","⥥":"⥥","†":"†","ℸ":"ℸ","↓":"↓","‐":"‐","⊣":"⊣","⤏":"⤏","˝":"˝","ď":"ď","д":"д","ⅆ":"ⅆ","‡":"‡","⇊":"⇊","⩷":"⩷","°":"°","°":"°","δ":"δ","⦱":"⦱","⥿":"⥿","𝔡":"𝔡","⇃":"⇃","⇂":"⇂","⋄":"⋄","⋄":"⋄","♦":"♦","♦":"♦","¨":"¨","ϝ":"ϝ","⋲":"⋲","÷":"÷","÷":"÷","÷":"÷","⋇":"⋇","⋇":"⋇","ђ":"ђ","⌞":"⌞","⌍":"⌍","$":"$","𝕕":"𝕕","˙":"˙","≐":"≐","≑":"≑","∸":"∸","∔":"∔","⊡":"⊡","⌆":"⌆","↓":"↓","⇊":"⇊","⇃":"⇃","⇂":"⇂","⤐":"⤐","⌟":"⌟","⌌":"⌌","𝒹":"𝒹","ѕ":"ѕ","⧶":"⧶","đ":"đ","⋱":"⋱","▿":"▿","▾":"▾","⇵":"⇵","⥯":"⥯","⦦":"⦦","џ":"џ","⟿":"⟿","⩷":"⩷","≑":"≑","é":"é","é":"é","⩮":"⩮","ě":"ě","≖":"≖","ê":"ê","ê":"ê","≕":"≕","э":"э","ė":"ė","ⅇ":"ⅇ","≒":"≒","𝔢":"𝔢","⪚":"⪚","è":"è","è":"è","⪖":"⪖","⪘":"⪘","⪙":"⪙","⏧":"⏧","ℓ":"ℓ","⪕":"⪕","⪗":"⪗","ē":"ē","∅":"∅","∅":"∅","∅":"∅"," ":" "," ":" "," ":" ","ŋ":"ŋ"," ":" ","ę":"ę","𝕖":"𝕖","⋕":"⋕","⧣":"⧣","⩱":"⩱","ε":"ε","ε":"ε","ϵ":"ϵ","≖":"≖","≕":"≕","≂":"≂","⪖":"⪖","⪕":"⪕","=":"=","≟":"≟","≡":"≡","⩸":"⩸","⧥":"⧥","≓":"≓","⥱":"⥱","ℯ":"ℯ","≐":"≐","≂":"≂","η":"η","ð":"ð","ð":"ð","ë":"ë","ë":"ë","€":"€","!":"!","∃":"∃","ℰ":"ℰ","ⅇ":"ⅇ","≒":"≒","ф":"ф","♀":"♀","ffi":"ffi","ff":"ff","ffl":"ffl","𝔣":"𝔣","fi":"fi","fj":"fj","♭":"♭","fl":"fl","▱":"▱","ƒ":"ƒ","𝕗":"𝕗","∀":"∀","⋔":"⋔","⫙":"⫙","⨍":"⨍","½":"½","½":"½","⅓":"⅓","¼":"¼","¼":"¼","⅕":"⅕","⅙":"⅙","⅛":"⅛","⅔":"⅔","⅖":"⅖","¾":"¾","¾":"¾","⅗":"⅗","⅜":"⅜","⅘":"⅘","⅚":"⅚","⅝":"⅝","⅞":"⅞","⁄":"⁄","⌢":"⌢","𝒻":"𝒻","≧":"≧","⪌":"⪌","ǵ":"ǵ","γ":"γ","ϝ":"ϝ","⪆":"⪆","ğ":"ğ","ĝ":"ĝ","г":"г","ġ":"ġ","≥":"≥","⋛":"⋛","≥":"≥","≧":"≧","⩾":"⩾","⩾":"⩾","⪩":"⪩","⪀":"⪀","⪂":"⪂","⪄":"⪄","⋛︀":"⋛︀","⪔":"⪔","𝔤":"𝔤","≫":"≫","⋙":"⋙","ℷ":"ℷ","ѓ":"ѓ","≷":"≷","⪒":"⪒","⪥":"⪥","⪤":"⪤","≩":"≩","⪊":"⪊","⪊":"⪊","⪈":"⪈","⪈":"⪈","≩":"≩","⋧":"⋧","𝕘":"𝕘","`":"`","ℊ":"ℊ","≳":"≳","⪎":"⪎","⪐":"⪐",">":">",">":">","⪧":"⪧","⩺":"⩺","⋗":"⋗","⦕":"⦕","⩼":"⩼","⪆":"⪆","⥸":"⥸","⋗":"⋗","⋛":"⋛","⪌":"⪌","≷":"≷","≳":"≳","≩︀":"≩︀","≩︀":"≩︀","⇔":"⇔"," ":" ","½":"½","ℋ":"ℋ","ъ":"ъ","↔":"↔","⥈":"⥈","↭":"↭","ℏ":"ℏ","ĥ":"ĥ","♥":"♥","♥":"♥","…":"…","⊹":"⊹","𝔥":"𝔥","⤥":"⤥","⤦":"⤦","⇿":"⇿","∻":"∻","↩":"↩","↪":"↪","𝕙":"𝕙","―":"―","𝒽":"𝒽","ℏ":"ℏ","ħ":"ħ","⁃":"⁃","‐":"‐","í":"í","í":"í","⁣":"⁣","î":"î","î":"î","и":"и","е":"е","¡":"¡","¡":"¡","⇔":"⇔","𝔦":"𝔦","ì":"ì","ì":"ì","ⅈ":"ⅈ","⨌":"⨌","∭":"∭","⧜":"⧜","℩":"℩","ij":"ij","ī":"ī","ℑ":"ℑ","ℐ":"ℐ","ℑ":"ℑ","ı":"ı","⊷":"⊷","Ƶ":"Ƶ","∈":"∈","℅":"℅","∞":"∞","⧝":"⧝","ı":"ı","∫":"∫","⊺":"⊺","ℤ":"ℤ","⊺":"⊺","⨗":"⨗","⨼":"⨼","ё":"ё","į":"į","𝕚":"𝕚","ι":"ι","⨼":"⨼","¿":"¿","¿":"¿","𝒾":"𝒾","∈":"∈","⋹":"⋹","⋵":"⋵","⋴":"⋴","⋳":"⋳","∈":"∈","⁢":"⁢","ĩ":"ĩ","і":"і","ï":"ï","ï":"ï","ĵ":"ĵ","й":"й","𝔧":"𝔧","ȷ":"ȷ","𝕛":"𝕛","𝒿":"𝒿","ј":"ј","є":"є","κ":"κ","ϰ":"ϰ","ķ":"ķ","к":"к","𝔨":"𝔨","ĸ":"ĸ","х":"х","ќ":"ќ","𝕜":"𝕜","𝓀":"𝓀","⇚":"⇚","⇐":"⇐","⤛":"⤛","⤎":"⤎","≦":"≦","⪋":"⪋","⥢":"⥢","ĺ":"ĺ","⦴":"⦴","ℒ":"ℒ","λ":"λ","⟨":"⟨","⦑":"⦑","⟨":"⟨","⪅":"⪅","«":"«","«":"«","←":"←","⇤":"⇤","⤟":"⤟","⤝":"⤝","↩":"↩","↫":"↫","⤹":"⤹","⥳":"⥳","↢":"↢","⪫":"⪫","⤙":"⤙","⪭":"⪭","⪭︀":"⪭︀","⤌":"⤌","❲":"❲","{":"{","[":"[","⦋":"⦋","⦏":"⦏","⦍":"⦍","ľ":"ľ","ļ":"ļ","⌈":"⌈","{":"{","л":"л","⤶":"⤶","“":"“","„":"„","⥧":"⥧","⥋":"⥋","↲":"↲","≤":"≤","←":"←","↢":"↢","↽":"↽","↼":"↼","⇇":"⇇","↔":"↔","⇆":"⇆","⇋":"⇋","↭":"↭","⋋":"⋋","⋚":"⋚","≤":"≤","≦":"≦","⩽":"⩽","⩽":"⩽","⪨":"⪨","⩿":"⩿","⪁":"⪁","⪃":"⪃","⋚︀":"⋚︀","⪓":"⪓","⪅":"⪅","⋖":"⋖","⋚":"⋚","⪋":"⪋","≶":"≶","≲":"≲","⥼":"⥼","⌊":"⌊","𝔩":"𝔩","≶":"≶","⪑":"⪑","↽":"↽","↼":"↼","⥪":"⥪","▄":"▄","љ":"љ","≪":"≪","⇇":"⇇","⌞":"⌞","⥫":"⥫","◺":"◺","ŀ":"ŀ","⎰":"⎰","⎰":"⎰","≨":"≨","⪉":"⪉","⪉":"⪉","⪇":"⪇","⪇":"⪇","≨":"≨","⋦":"⋦","⟬":"⟬","⇽":"⇽","⟦":"⟦","⟵":"⟵","⟷":"⟷","⟼":"⟼","⟶":"⟶","↫":"↫","↬":"↬","⦅":"⦅","𝕝":"𝕝","⨭":"⨭","⨴":"⨴","∗":"∗","_":"_","◊":"◊","◊":"◊","⧫":"⧫","(":"(","⦓":"⦓","⇆":"⇆","⌟":"⌟","⇋":"⇋","⥭":"⥭","‎":"‎","⊿":"⊿","‹":"‹","𝓁":"𝓁","↰":"↰","≲":"≲","⪍":"⪍","⪏":"⪏","[":"[","‘":"‘","‚":"‚","ł":"ł","<":"<","<":"<","⪦":"⪦","⩹":"⩹","⋖":"⋖","⋋":"⋋","⋉":"⋉","⥶":"⥶","⩻":"⩻","⦖":"⦖","◃":"◃","⊴":"⊴","◂":"◂","⥊":"⥊","⥦":"⥦","≨︀":"≨︀","≨︀":"≨︀","∺":"∺","¯":"¯","¯":"¯","♂":"♂","✠":"✠","✠":"✠","↦":"↦","↦":"↦","↧":"↧","↤":"↤","↥":"↥","▮":"▮","⨩":"⨩","м":"м","—":"—","∡":"∡","𝔪":"𝔪","℧":"℧","µ":"µ","µ":"µ","∣":"∣","*":"*","⫰":"⫰","·":"·","·":"·","−":"−","⊟":"⊟","∸":"∸","⨪":"⨪","⫛":"⫛","…":"…","∓":"∓","⊧":"⊧","𝕞":"𝕞","∓":"∓","𝓂":"𝓂","∾":"∾","μ":"μ","⊸":"⊸","⊸":"⊸","⋙̸":"⋙̸","≫⃒":"≫⃒","≫̸":"≫̸","⇍":"⇍","⇎":"⇎","⋘̸":"⋘̸","≪⃒":"≪⃒","≪̸":"≪̸","⇏":"⇏","⊯":"⊯","⊮":"⊮","∇":"∇","ń":"ń","∠⃒":"∠⃒","≉":"≉","⩰̸":"⩰̸","≋̸":"≋̸","ʼn":"ʼn","≉":"≉","♮":"♮","♮":"♮","ℕ":"ℕ"," ":" "," ":" ","≎̸":"≎̸","≏̸":"≏̸","⩃":"⩃","ň":"ň","ņ":"ņ","≇":"≇","⩭̸":"⩭̸","⩂":"⩂","н":"н","–":"–","≠":"≠","⇗":"⇗","⤤":"⤤","↗":"↗","↗":"↗","≐̸":"≐̸","≢":"≢","⤨":"⤨","≂̸":"≂̸","∄":"∄","∄":"∄","𝔫":"𝔫","≧̸":"≧̸","≱":"≱","≱":"≱","≧̸":"≧̸","⩾̸":"⩾̸","⩾̸":"⩾̸","≵":"≵","≯":"≯","≯":"≯","⇎":"⇎","↮":"↮","⫲":"⫲","∋":"∋","⋼":"⋼","⋺":"⋺","∋":"∋","њ":"њ","⇍":"⇍","≦̸":"≦̸","↚":"↚","‥":"‥","≰":"≰","↚":"↚","↮":"↮","≰":"≰","≦̸":"≦̸","⩽̸":"⩽̸","⩽̸":"⩽̸","≮":"≮","≴":"≴","≮":"≮","⋪":"⋪","⋬":"⋬","∤":"∤","𝕟":"𝕟","¬":"¬","¬":"¬","∉":"∉","⋹̸":"⋹̸","⋵̸":"⋵̸","∉":"∉","⋷":"⋷","⋶":"⋶","∌":"∌","∌":"∌","⋾":"⋾","⋽":"⋽","∦":"∦","∦":"∦","⫽⃥":"⫽⃥","∂̸":"∂̸","⨔":"⨔","⊀":"⊀","⋠":"⋠","⪯̸":"⪯̸","⊀":"⊀","⪯̸":"⪯̸","⇏":"⇏","↛":"↛","⤳̸":"⤳̸","↝̸":"↝̸","↛":"↛","⋫":"⋫","⋭":"⋭","⊁":"⊁","⋡":"⋡","⪰̸":"⪰̸","𝓃":"𝓃","∤":"∤","∦":"∦","≁":"≁","≄":"≄","≄":"≄","∤":"∤","∦":"∦","⋢":"⋢","⋣":"⋣","⊄":"⊄","⫅̸":"⫅̸","⊈":"⊈","⊂⃒":"⊂⃒","⊈":"⊈","⫅̸":"⫅̸","⊁":"⊁","⪰̸":"⪰̸","⊅":"⊅","⫆̸":"⫆̸","⊉":"⊉","⊃⃒":"⊃⃒","⊉":"⊉","⫆̸":"⫆̸","≹":"≹","ñ":"ñ","ñ":"ñ","≸":"≸","⋪":"⋪","⋬":"⋬","⋫":"⋫","⋭":"⋭","ν":"ν","#":"#","№":"№"," ":" ","⊭":"⊭","⤄":"⤄","≍⃒":"≍⃒","⊬":"⊬","≥⃒":"≥⃒",">⃒":">⃒","⧞":"⧞","⤂":"⤂","≤⃒":"≤⃒","<⃒":"<⃒","⊴⃒":"⊴⃒","⤃":"⤃","⊵⃒":"⊵⃒","∼⃒":"∼⃒","⇖":"⇖","⤣":"⤣","↖":"↖","↖":"↖","⤧":"⤧","Ⓢ":"Ⓢ","ó":"ó","ó":"ó","⊛":"⊛","⊚":"⊚","ô":"ô","ô":"ô","о":"о","⊝":"⊝","ő":"ő","⨸":"⨸","⊙":"⊙","⦼":"⦼","œ":"œ","⦿":"⦿","𝔬":"𝔬","˛":"˛","ò":"ò","ò":"ò","⧁":"⧁","⦵":"⦵","Ω":"Ω","∮":"∮","↺":"↺","⦾":"⦾","⦻":"⦻","‾":"‾","⧀":"⧀","ō":"ō","ω":"ω","ο":"ο","⦶":"⦶","⊖":"⊖","𝕠":"𝕠","⦷":"⦷","⦹":"⦹","⊕":"⊕","∨":"∨","↻":"↻","⩝":"⩝","ℴ":"ℴ","ℴ":"ℴ","ª":"ª","ª":"ª","º":"º","º":"º","⊶":"⊶","⩖":"⩖","⩗":"⩗","⩛":"⩛","ℴ":"ℴ","ø":"ø","ø":"ø","⊘":"⊘","õ":"õ","õ":"õ","⊗":"⊗","⨶":"⨶","ö":"ö","ö":"ö","⌽":"⌽","∥":"∥","¶":"¶","¶":"¶","∥":"∥","⫳":"⫳","⫽":"⫽","∂":"∂","п":"п","%":"%",".":".","‰":"‰","⊥":"⊥","‱":"‱","𝔭":"𝔭","φ":"φ","ϕ":"ϕ","ℳ":"ℳ","☎":"☎","π":"π","⋔":"⋔","ϖ":"ϖ","ℏ":"ℏ","ℎ":"ℎ","ℏ":"ℏ","+":"+","⨣":"⨣","⊞":"⊞","⨢":"⨢","∔":"∔","⨥":"⨥","⩲":"⩲","±":"±","±":"±","⨦":"⨦","⨧":"⨧","±":"±","⨕":"⨕","𝕡":"𝕡","£":"£","£":"£","≺":"≺","⪳":"⪳","⪷":"⪷","≼":"≼","⪯":"⪯","≺":"≺","⪷":"⪷","≼":"≼","⪯":"⪯","⪹":"⪹","⪵":"⪵","⋨":"⋨","≾":"≾","′":"′","ℙ":"ℙ","⪵":"⪵","⪹":"⪹","⋨":"⋨","∏":"∏","⌮":"⌮","⌒":"⌒","⌓":"⌓","∝":"∝","∝":"∝","≾":"≾","⊰":"⊰","𝓅":"𝓅","ψ":"ψ"," ":" ","𝔮":"𝔮","⨌":"⨌","𝕢":"𝕢","⁗":"⁗","𝓆":"𝓆","ℍ":"ℍ","⨖":"⨖","?":"?","≟":"≟",""":'"',""":'"',"⇛":"⇛","⇒":"⇒","⤜":"⤜","⤏":"⤏","⥤":"⥤","∽̱":"∽̱","ŕ":"ŕ","√":"√","⦳":"⦳","⟩":"⟩","⦒":"⦒","⦥":"⦥","⟩":"⟩","»":"»","»":"»","→":"→","⥵":"⥵","⇥":"⇥","⤠":"⤠","⤳":"⤳","⤞":"⤞","↪":"↪","↬":"↬","⥅":"⥅","⥴":"⥴","↣":"↣","↝":"↝","⤚":"⤚","∶":"∶","ℚ":"ℚ","⤍":"⤍","❳":"❳","}":"}","]":"]","⦌":"⦌","⦎":"⦎","⦐":"⦐","ř":"ř","ŗ":"ŗ","⌉":"⌉","}":"}","р":"р","⤷":"⤷","⥩":"⥩","”":"”","”":"”","↳":"↳","ℜ":"ℜ","ℛ":"ℛ","ℜ":"ℜ","ℝ":"ℝ","▭":"▭","®":"®","®":"®","⥽":"⥽","⌋":"⌋","𝔯":"𝔯","⇁":"⇁","⇀":"⇀","⥬":"⥬","ρ":"ρ","ϱ":"ϱ","→":"→","↣":"↣","⇁":"⇁","⇀":"⇀","⇄":"⇄","⇌":"⇌","⇉":"⇉","↝":"↝","⋌":"⋌","˚":"˚","≓":"≓","⇄":"⇄","⇌":"⇌","‏":"‏","⎱":"⎱","⎱":"⎱","⫮":"⫮","⟭":"⟭","⇾":"⇾","⟧":"⟧","⦆":"⦆","𝕣":"𝕣","⨮":"⨮","⨵":"⨵",")":")","⦔":"⦔","⨒":"⨒","⇉":"⇉","›":"›","𝓇":"𝓇","↱":"↱","]":"]","’":"’","’":"’","⋌":"⋌","⋊":"⋊","▹":"▹","⊵":"⊵","▸":"▸","⧎":"⧎","⥨":"⥨","℞":"℞","ś":"ś","‚":"‚","≻":"≻","⪴":"⪴","⪸":"⪸","š":"š","≽":"≽","⪰":"⪰","ş":"ş","ŝ":"ŝ","⪶":"⪶","⪺":"⪺","⋩":"⋩","⨓":"⨓","≿":"≿","с":"с","⋅":"⋅","⊡":"⊡","⩦":"⩦","⇘":"⇘","⤥":"⤥","↘":"↘","↘":"↘","§":"§","§":"§",";":";","⤩":"⤩","∖":"∖","∖":"∖","✶":"✶","𝔰":"𝔰","⌢":"⌢","♯":"♯","щ":"щ","ш":"ш","∣":"∣","∥":"∥","­":"­","­":"­","σ":"σ","ς":"ς","ς":"ς","∼":"∼","⩪":"⩪","≃":"≃","≃":"≃","⪞":"⪞","⪠":"⪠","⪝":"⪝","⪟":"⪟","≆":"≆","⨤":"⨤","⥲":"⥲","←":"←","∖":"∖","⨳":"⨳","⧤":"⧤","∣":"∣","⌣":"⌣","⪪":"⪪","⪬":"⪬","⪬︀":"⪬︀","ь":"ь","/":"/","⧄":"⧄","⌿":"⌿","𝕤":"𝕤","♠":"♠","♠":"♠","∥":"∥","⊓":"⊓","⊓︀":"⊓︀","⊔":"⊔","⊔︀":"⊔︀","⊏":"⊏","⊑":"⊑","⊏":"⊏","⊑":"⊑","⊐":"⊐","⊒":"⊒","⊐":"⊐","⊒":"⊒","□":"□","□":"□","▪":"▪","▪":"▪","→":"→","𝓈":"𝓈","∖":"∖","⌣":"⌣","⋆":"⋆","☆":"☆","★":"★","ϵ":"ϵ","ϕ":"ϕ","¯":"¯","⊂":"⊂","⫅":"⫅","⪽":"⪽","⊆":"⊆","⫃":"⫃","⫁":"⫁","⫋":"⫋","⊊":"⊊","⪿":"⪿","⥹":"⥹","⊂":"⊂","⊆":"⊆","⫅":"⫅","⊊":"⊊","⫋":"⫋","⫇":"⫇","⫕":"⫕","⫓":"⫓","≻":"≻","⪸":"⪸","≽":"≽","⪰":"⪰","⪺":"⪺","⪶":"⪶","⋩":"⋩","≿":"≿","∑":"∑","♪":"♪","¹":"¹","¹":"¹","²":"²","²":"²","³":"³","³":"³","⊃":"⊃","⫆":"⫆","⪾":"⪾","⫘":"⫘","⊇":"⊇","⫄":"⫄","⟉":"⟉","⫗":"⫗","⥻":"⥻","⫂":"⫂","⫌":"⫌","⊋":"⊋","⫀":"⫀","⊃":"⊃","⊇":"⊇","⫆":"⫆","⊋":"⊋","⫌":"⫌","⫈":"⫈","⫔":"⫔","⫖":"⫖","⇙":"⇙","⤦":"⤦","↙":"↙","↙":"↙","⤪":"⤪","ß":"ß","ß":"ß","⌖":"⌖","τ":"τ","⎴":"⎴","ť":"ť","ţ":"ţ","т":"т","⃛":"⃛","⌕":"⌕","𝔱":"𝔱","∴":"∴","∴":"∴","θ":"θ","ϑ":"ϑ","ϑ":"ϑ","≈":"≈","∼":"∼"," ":" ","≈":"≈","∼":"∼","þ":"þ","þ":"þ","˜":"˜","×":"×","×":"×","⊠":"⊠","⨱":"⨱","⨰":"⨰","∭":"∭","⤨":"⤨","⊤":"⊤","⌶":"⌶","⫱":"⫱","𝕥":"𝕥","⫚":"⫚","⤩":"⤩","‴":"‴","™":"™","▵":"▵","▿":"▿","◃":"◃","⊴":"⊴","≜":"≜","▹":"▹","⊵":"⊵","◬":"◬","≜":"≜","⨺":"⨺","⨹":"⨹","⧍":"⧍","⨻":"⨻","⏢":"⏢","𝓉":"𝓉","ц":"ц","ћ":"ћ","ŧ":"ŧ","≬":"≬","↞":"↞","↠":"↠","⇑":"⇑","⥣":"⥣","ú":"ú","ú":"ú","↑":"↑","ў":"ў","ŭ":"ŭ","û":"û","û":"û","у":"у","⇅":"⇅","ű":"ű","⥮":"⥮","⥾":"⥾","𝔲":"𝔲","ù":"ù","ù":"ù","↿":"↿","↾":"↾","▀":"▀","⌜":"⌜","⌜":"⌜","⌏":"⌏","◸":"◸","ū":"ū","¨":"¨","¨":"¨","ų":"ų","𝕦":"𝕦","↑":"↑","↕":"↕","↿":"↿","↾":"↾","⊎":"⊎","υ":"υ","ϒ":"ϒ","υ":"υ","⇈":"⇈","⌝":"⌝","⌝":"⌝","⌎":"⌎","ů":"ů","◹":"◹","𝓊":"𝓊","⋰":"⋰","ũ":"ũ","▵":"▵","▴":"▴","⇈":"⇈","ü":"ü","ü":"ü","⦧":"⦧","⇕":"⇕","⫨":"⫨","⫩":"⫩","⊨":"⊨","⦜":"⦜","ϵ":"ϵ","ϰ":"ϰ","∅":"∅","ϕ":"ϕ","ϖ":"ϖ","∝":"∝","↕":"↕","ϱ":"ϱ","ς":"ς","⊊︀":"⊊︀","⫋︀":"⫋︀","⊋︀":"⊋︀","⫌︀":"⫌︀","ϑ":"ϑ","⊲":"⊲","⊳":"⊳","в":"в","⊢":"⊢","∨":"∨","⊻":"⊻","≚":"≚","⋮":"⋮","|":"|","|":"|","𝔳":"𝔳","⊲":"⊲","⊂⃒":"⊂⃒","⊃⃒":"⊃⃒","𝕧":"𝕧","∝":"∝","⊳":"⊳","𝓋":"𝓋","⫋︀":"⫋︀","⊊︀":"⊊︀","⫌︀":"⫌︀","⊋︀":"⊋︀","⦚":"⦚","ŵ":"ŵ","⩟":"⩟","∧":"∧","≙":"≙","℘":"℘","𝔴":"𝔴","𝕨":"𝕨","℘":"℘","≀":"≀","≀":"≀","𝓌":"𝓌","⋂":"⋂","◯":"◯","⋃":"⋃","▽":"▽","𝔵":"𝔵","⟺":"⟺","⟷":"⟷","ξ":"ξ","⟸":"⟸","⟵":"⟵","⟼":"⟼","⋻":"⋻","⨀":"⨀","𝕩":"𝕩","⨁":"⨁","⨂":"⨂","⟹":"⟹","⟶":"⟶","𝓍":"𝓍","⨆":"⨆","⨄":"⨄","△":"△","⋁":"⋁","⋀":"⋀","ý":"ý","ý":"ý","я":"я","ŷ":"ŷ","ы":"ы","¥":"¥","¥":"¥","𝔶":"𝔶","ї":"ї","𝕪":"𝕪","𝓎":"𝓎","ю":"ю","ÿ":"ÿ","ÿ":"ÿ","ź":"ź","ž":"ž","з":"з","ż":"ż","ℨ":"ℨ","ζ":"ζ","𝔷":"𝔷","ж":"ж","⇝":"⇝","𝕫":"𝕫","𝓏":"𝓏","‍":"‍","‌":"‌"},characters:{Æ:"Æ","&":"&",Á:"Á",Ă:"Ă",Â:"Â",А:"А",𝔄:"𝔄",À:"À",Α:"Α",Ā:"Ā","⩓":"⩓",Ą:"Ą",𝔸:"𝔸","⁡":"⁡",Å:"Å",𝒜:"𝒜","≔":"≔",Ã:"Ã",Ä:"Ä","∖":"∖","⫧":"⫧","⌆":"⌆",Б:"Б","∵":"∵",ℬ:"ℬ",Β:"Β",𝔅:"𝔅",𝔹:"𝔹","˘":"˘","≎":"≎",Ч:"Ч","©":"©",Ć:"Ć","⋒":"⋒",ⅅ:"ⅅ",ℭ:"ℭ",Č:"Č",Ç:"Ç",Ĉ:"Ĉ","∰":"∰",Ċ:"Ċ","¸":"¸","·":"·",Χ:"Χ","⊙":"⊙","⊖":"⊖","⊕":"⊕","⊗":"⊗","∲":"∲","”":"”","’":"’","∷":"∷","⩴":"⩴","≡":"≡","∯":"∯","∮":"∮",ℂ:"ℂ","∐":"∐","∳":"∳","⨯":"⨯",𝒞:"𝒞","⋓":"⋓","≍":"≍","⤑":"⤑",Ђ:"Ђ",Ѕ:"Ѕ",Џ:"Џ","‡":"‡","↡":"↡","⫤":"⫤",Ď:"Ď",Д:"Д","∇":"∇",Δ:"Δ",𝔇:"𝔇","´":"´","˙":"˙","˝":"˝","`":"`","˜":"˜","⋄":"⋄",ⅆ:"ⅆ",𝔻:"𝔻","¨":"¨","⃜":"⃜","≐":"≐","⇓":"⇓","⇐":"⇐","⇔":"⇔","⟸":"⟸","⟺":"⟺","⟹":"⟹","⇒":"⇒","⊨":"⊨","⇑":"⇑","⇕":"⇕","∥":"∥","↓":"↓","⤓":"⤓","⇵":"⇵","̑":"̑","⥐":"⥐","⥞":"⥞","↽":"↽","⥖":"⥖","⥟":"⥟","⇁":"⇁","⥗":"⥗","⊤":"⊤","↧":"↧",𝒟:"𝒟",Đ:"Đ",Ŋ:"Ŋ",Ð:"Ð",É:"É",Ě:"Ě",Ê:"Ê",Э:"Э",Ė:"Ė",𝔈:"𝔈",È:"È","∈":"∈",Ē:"Ē","◻":"◻","▫":"▫",Ę:"Ę",𝔼:"𝔼",Ε:"Ε","⩵":"⩵","≂":"≂","⇌":"⇌",ℰ:"ℰ","⩳":"⩳",Η:"Η",Ë:"Ë","∃":"∃",ⅇ:"ⅇ",Ф:"Ф",𝔉:"𝔉","◼":"◼","▪":"▪",𝔽:"𝔽","∀":"∀",ℱ:"ℱ",Ѓ:"Ѓ",">":">",Γ:"Γ",Ϝ:"Ϝ",Ğ:"Ğ",Ģ:"Ģ",Ĝ:"Ĝ",Г:"Г",Ġ:"Ġ",𝔊:"𝔊","⋙":"⋙",𝔾:"𝔾","≥":"≥","⋛":"⋛","≧":"≧","⪢":"⪢","≷":"≷","⩾":"⩾","≳":"≳",𝒢:"𝒢","≫":"≫",Ъ:"Ъ",ˇ:"ˇ","^":"^",Ĥ:"Ĥ",ℌ:"ℌ",ℋ:"ℋ",ℍ:"ℍ","─":"─",Ħ:"Ħ","≏":"≏",Е:"Е",IJ:"IJ",Ё:"Ё",Í:"Í",Î:"Î",И:"И",İ:"İ",ℑ:"ℑ",Ì:"Ì",Ī:"Ī",ⅈ:"ⅈ","∬":"∬","∫":"∫","⋂":"⋂","⁣":"⁣","⁢":"⁢",Į:"Į",𝕀:"𝕀",Ι:"Ι",ℐ:"ℐ",Ĩ:"Ĩ",І:"І",Ï:"Ï",Ĵ:"Ĵ",Й:"Й",𝔍:"𝔍",𝕁:"𝕁",𝒥:"𝒥",Ј:"Ј",Є:"Є",Х:"Х",Ќ:"Ќ",Κ:"Κ",Ķ:"Ķ",К:"К",𝔎:"𝔎",𝕂:"𝕂",𝒦:"𝒦",Љ:"Љ","<":"<",Ĺ:"Ĺ",Λ:"Λ","⟪":"⟪",ℒ:"ℒ","↞":"↞",Ľ:"Ľ",Ļ:"Ļ",Л:"Л","⟨":"⟨","←":"←","⇤":"⇤","⇆":"⇆","⌈":"⌈","⟦":"⟦","⥡":"⥡","⇃":"⇃","⥙":"⥙","⌊":"⌊","↔":"↔","⥎":"⥎","⊣":"⊣","↤":"↤","⥚":"⥚","⊲":"⊲","⧏":"⧏","⊴":"⊴","⥑":"⥑","⥠":"⥠","↿":"↿","⥘":"⥘","↼":"↼","⥒":"⥒","⋚":"⋚","≦":"≦","≶":"≶","⪡":"⪡","⩽":"⩽","≲":"≲",𝔏:"𝔏","⋘":"⋘","⇚":"⇚",Ŀ:"Ŀ","⟵":"⟵","⟷":"⟷","⟶":"⟶",𝕃:"𝕃","↙":"↙","↘":"↘","↰":"↰",Ł:"Ł","≪":"≪","⤅":"⤅",М:"М"," ":" ",ℳ:"ℳ",𝔐:"𝔐","∓":"∓",𝕄:"𝕄",Μ:"Μ",Њ:"Њ",Ń:"Ń",Ň:"Ň",Ņ:"Ņ",Н:"Н","​":"​","\n":" ",𝔑:"𝔑","⁠":"⁠"," ":" ",ℕ:"ℕ","⫬":"⫬","≢":"≢","≭":"≭","∦":"∦","∉":"∉","≠":"≠","≂̸":"≂̸","∄":"∄","≯":"≯","≱":"≱","≧̸":"≧̸","≫̸":"≫̸","≹":"≹","⩾̸":"⩾̸","≵":"≵","≎̸":"≎̸","≏̸":"≏̸","⋪":"⋪","⧏̸":"⧏̸","⋬":"⋬","≮":"≮","≰":"≰","≸":"≸","≪̸":"≪̸","⩽̸":"⩽̸","≴":"≴","⪢̸":"⪢̸","⪡̸":"⪡̸","⊀":"⊀","⪯̸":"⪯̸","⋠":"⋠","∌":"∌","⋫":"⋫","⧐̸":"⧐̸","⋭":"⋭","⊏̸":"⊏̸","⋢":"⋢","⊐̸":"⊐̸","⋣":"⋣","⊂⃒":"⊂⃒","⊈":"⊈","⊁":"⊁","⪰̸":"⪰̸","⋡":"⋡","≿̸":"≿̸","⊃⃒":"⊃⃒","⊉":"⊉","≁":"≁","≄":"≄","≇":"≇","≉":"≉","∤":"∤",𝒩:"𝒩",Ñ:"Ñ",Ν:"Ν",Œ:"Œ",Ó:"Ó",Ô:"Ô",О:"О",Ő:"Ő",𝔒:"𝔒",Ò:"Ò",Ō:"Ō",Ω:"Ω",Ο:"Ο",𝕆:"𝕆","“":"“","‘":"‘","⩔":"⩔",𝒪:"𝒪",Ø:"Ø",Õ:"Õ","⨷":"⨷",Ö:"Ö","‾":"‾","⏞":"⏞","⎴":"⎴","⏜":"⏜","∂":"∂",П:"П",𝔓:"𝔓",Φ:"Φ",Π:"Π","±":"±",ℙ:"ℙ","⪻":"⪻","≺":"≺","⪯":"⪯","≼":"≼","≾":"≾","″":"″","∏":"∏","∝":"∝",𝒫:"𝒫",Ψ:"Ψ",'"':""",𝔔:"𝔔",ℚ:"ℚ",𝒬:"𝒬","⤐":"⤐","®":"®",Ŕ:"Ŕ","⟫":"⟫","↠":"↠","⤖":"⤖",Ř:"Ř",Ŗ:"Ŗ",Р:"Р",ℜ:"ℜ","∋":"∋","⇋":"⇋","⥯":"⥯",Ρ:"Ρ","⟩":"⟩","→":"→","⇥":"⇥","⇄":"⇄","⌉":"⌉","⟧":"⟧","⥝":"⥝","⇂":"⇂","⥕":"⥕","⌋":"⌋","⊢":"⊢","↦":"↦","⥛":"⥛","⊳":"⊳","⧐":"⧐","⊵":"⊵","⥏":"⥏","⥜":"⥜","↾":"↾","⥔":"⥔","⇀":"⇀","⥓":"⥓",ℝ:"ℝ","⥰":"⥰","⇛":"⇛",ℛ:"ℛ","↱":"↱","⧴":"⧴",Щ:"Щ",Ш:"Ш",Ь:"Ь",Ś:"Ś","⪼":"⪼",Š:"Š",Ş:"Ş",Ŝ:"Ŝ",С:"С",𝔖:"𝔖","↑":"↑",Σ:"Σ","∘":"∘",𝕊:"𝕊","√":"√","□":"□","⊓":"⊓","⊏":"⊏","⊑":"⊑","⊐":"⊐","⊒":"⊒","⊔":"⊔",𝒮:"𝒮","⋆":"⋆","⋐":"⋐","⊆":"⊆","≻":"≻","⪰":"⪰","≽":"≽","≿":"≿","∑":"∑","⋑":"⋑","⊃":"⊃","⊇":"⊇",Þ:"Þ","™":"™",Ћ:"Ћ",Ц:"Ц","\t":" ",Τ:"Τ",Ť:"Ť",Ţ:"Ţ",Т:"Т",𝔗:"𝔗","∴":"∴",Θ:"Θ","  ":"  "," ":" ","∼":"∼","≃":"≃","≅":"≅","≈":"≈",𝕋:"𝕋","⃛":"⃛",𝒯:"𝒯",Ŧ:"Ŧ",Ú:"Ú","↟":"↟","⥉":"⥉",Ў:"Ў",Ŭ:"Ŭ",Û:"Û",У:"У",Ű:"Ű",𝔘:"𝔘",Ù:"Ù",Ū:"Ū",_:"_","⏟":"⏟","⎵":"⎵","⏝":"⏝","⋃":"⋃","⊎":"⊎",Ų:"Ų",𝕌:"𝕌","⤒":"⤒","⇅":"⇅","↕":"↕","⥮":"⥮","⊥":"⊥","↥":"↥","↖":"↖","↗":"↗",ϒ:"ϒ",Υ:"Υ",Ů:"Ů",𝒰:"𝒰",Ũ:"Ũ",Ü:"Ü","⊫":"⊫","⫫":"⫫",В:"В","⊩":"⊩","⫦":"⫦","⋁":"⋁","‖":"‖","∣":"∣","|":"|","❘":"❘","≀":"≀"," ":" ",𝔙:"𝔙",𝕍:"𝕍",𝒱:"𝒱","⊪":"⊪",Ŵ:"Ŵ","⋀":"⋀",𝔚:"𝔚",𝕎:"𝕎",𝒲:"𝒲",𝔛:"𝔛",Ξ:"Ξ",𝕏:"𝕏",𝒳:"𝒳",Я:"Я",Ї:"Ї",Ю:"Ю",Ý:"Ý",Ŷ:"Ŷ",Ы:"Ы",𝔜:"𝔜",𝕐:"𝕐",𝒴:"𝒴",Ÿ:"Ÿ",Ж:"Ж",Ź:"Ź",Ž:"Ž",З:"З",Ż:"Ż",Ζ:"Ζ",ℨ:"ℨ",ℤ:"ℤ",𝒵:"𝒵",á:"á",ă:"ă","∾":"∾","∾̳":"∾̳","∿":"∿",â:"â",а:"а",æ:"æ",𝔞:"𝔞",à:"à",ℵ:"ℵ",α:"α",ā:"ā","⨿":"⨿","∧":"∧","⩕":"⩕","⩜":"⩜","⩘":"⩘","⩚":"⩚","∠":"∠","⦤":"⦤","∡":"∡","⦨":"⦨","⦩":"⦩","⦪":"⦪","⦫":"⦫","⦬":"⦬","⦭":"⦭","⦮":"⦮","⦯":"⦯","∟":"∟","⊾":"⊾","⦝":"⦝","∢":"∢","⍼":"⍼",ą:"ą",𝕒:"𝕒","⩰":"⩰","⩯":"⩯","≊":"≊","≋":"≋","'":"'",å:"å",𝒶:"𝒶","*":"*",ã:"ã",ä:"ä","⨑":"⨑","⫭":"⫭","≌":"≌","϶":"϶","‵":"‵","∽":"∽","⋍":"⋍","⊽":"⊽","⌅":"⌅","⎶":"⎶",б:"б","„":"„","⦰":"⦰",β:"β",ℶ:"ℶ","≬":"≬",𝔟:"𝔟","◯":"◯","⨀":"⨀","⨁":"⨁","⨂":"⨂","⨆":"⨆","★":"★","▽":"▽","△":"△","⨄":"⨄","⤍":"⤍","⧫":"⧫","▴":"▴","▾":"▾","◂":"◂","▸":"▸","␣":"␣","▒":"▒","░":"░","▓":"▓","█":"█","=⃥":"=⃥","≡⃥":"≡⃥","⌐":"⌐",𝕓:"𝕓","⋈":"⋈","╗":"╗","╔":"╔","╖":"╖","╓":"╓","═":"═","╦":"╦","╩":"╩","╤":"╤","╧":"╧","╝":"╝","╚":"╚","╜":"╜","╙":"╙","║":"║","╬":"╬","╣":"╣","╠":"╠","╫":"╫","╢":"╢","╟":"╟","⧉":"⧉","╕":"╕","╒":"╒","┐":"┐","┌":"┌","╥":"╥","╨":"╨","┬":"┬","┴":"┴","⊟":"⊟","⊞":"⊞","⊠":"⊠","╛":"╛","╘":"╘","┘":"┘","└":"└","│":"│","╪":"╪","╡":"╡","╞":"╞","┼":"┼","┤":"┤","├":"├","¦":"¦",𝒷:"𝒷","⁏":"⁏","\\":"\","⧅":"⧅","⟈":"⟈","•":"•","⪮":"⪮",ć:"ć","∩":"∩","⩄":"⩄","⩉":"⩉","⩋":"⩋","⩇":"⩇","⩀":"⩀","∩︀":"∩︀","⁁":"⁁","⩍":"⩍",č:"č",ç:"ç",ĉ:"ĉ","⩌":"⩌","⩐":"⩐",ċ:"ċ","⦲":"⦲","¢":"¢",𝔠:"𝔠",ч:"ч","✓":"✓",χ:"χ","○":"○","⧃":"⧃",ˆ:"ˆ","≗":"≗","↺":"↺","↻":"↻","Ⓢ":"Ⓢ","⊛":"⊛","⊚":"⊚","⊝":"⊝","⨐":"⨐","⫯":"⫯","⧂":"⧂","♣":"♣",":":":",",":",","@":"@","∁":"∁","⩭":"⩭",𝕔:"𝕔","℗":"℗","↵":"↵","✗":"✗",𝒸:"𝒸","⫏":"⫏","⫑":"⫑","⫐":"⫐","⫒":"⫒","⋯":"⋯","⤸":"⤸","⤵":"⤵","⋞":"⋞","⋟":"⋟","↶":"↶","⤽":"⤽","∪":"∪","⩈":"⩈","⩆":"⩆","⩊":"⩊","⊍":"⊍","⩅":"⩅","∪︀":"∪︀","↷":"↷","⤼":"⤼","⋎":"⋎","⋏":"⋏","¤":"¤","∱":"∱","⌭":"⌭","⥥":"⥥","†":"†",ℸ:"ℸ","‐":"‐","⤏":"⤏",ď:"ď",д:"д","⇊":"⇊","⩷":"⩷","°":"°",δ:"δ","⦱":"⦱","⥿":"⥿",𝔡:"𝔡","♦":"♦",ϝ:"ϝ","⋲":"⋲","÷":"÷","⋇":"⋇",ђ:"ђ","⌞":"⌞","⌍":"⌍",$:"$",𝕕:"𝕕","≑":"≑","∸":"∸","∔":"∔","⊡":"⊡","⌟":"⌟","⌌":"⌌",𝒹:"𝒹",ѕ:"ѕ","⧶":"⧶",đ:"đ","⋱":"⋱","▿":"▿","⦦":"⦦",џ:"џ","⟿":"⟿",é:"é","⩮":"⩮",ě:"ě","≖":"≖",ê:"ê","≕":"≕",э:"э",ė:"ė","≒":"≒",𝔢:"𝔢","⪚":"⪚",è:"è","⪖":"⪖","⪘":"⪘","⪙":"⪙","⏧":"⏧",ℓ:"ℓ","⪕":"⪕","⪗":"⪗",ē:"ē","∅":"∅"," ":" "," ":" "," ":" ",ŋ:"ŋ"," ":" ",ę:"ę",𝕖:"𝕖","⋕":"⋕","⧣":"⧣","⩱":"⩱",ε:"ε",ϵ:"ϵ","=":"=","≟":"≟","⩸":"⩸","⧥":"⧥","≓":"≓","⥱":"⥱",ℯ:"ℯ",η:"η",ð:"ð",ë:"ë","€":"€","!":"!",ф:"ф","♀":"♀",ffi:"ffi",ff:"ff",ffl:"ffl",𝔣:"𝔣",fi:"fi",fj:"fj","♭":"♭",fl:"fl","▱":"▱",ƒ:"ƒ",𝕗:"𝕗","⋔":"⋔","⫙":"⫙","⨍":"⨍","½":"½","⅓":"⅓","¼":"¼","⅕":"⅕","⅙":"⅙","⅛":"⅛","⅔":"⅔","⅖":"⅖","¾":"¾","⅗":"⅗","⅜":"⅜","⅘":"⅘","⅚":"⅚","⅝":"⅝","⅞":"⅞","⁄":"⁄","⌢":"⌢",𝒻:"𝒻","⪌":"⪌",ǵ:"ǵ",γ:"γ","⪆":"⪆",ğ:"ğ",ĝ:"ĝ",г:"г",ġ:"ġ","⪩":"⪩","⪀":"⪀","⪂":"⪂","⪄":"⪄","⋛︀":"⋛︀","⪔":"⪔",𝔤:"𝔤",ℷ:"ℷ",ѓ:"ѓ","⪒":"⪒","⪥":"⪥","⪤":"⪤","≩":"≩","⪊":"⪊","⪈":"⪈","⋧":"⋧",𝕘:"𝕘",ℊ:"ℊ","⪎":"⪎","⪐":"⪐","⪧":"⪧","⩺":"⩺","⋗":"⋗","⦕":"⦕","⩼":"⩼","⥸":"⥸","≩︀":"≩︀",ъ:"ъ","⥈":"⥈","↭":"↭",ℏ:"ℏ",ĥ:"ĥ","♥":"♥","…":"…","⊹":"⊹",𝔥:"𝔥","⤥":"⤥","⤦":"⤦","⇿":"⇿","∻":"∻","↩":"↩","↪":"↪",𝕙:"𝕙","―":"―",𝒽:"𝒽",ħ:"ħ","⁃":"⁃",í:"í",î:"î",и:"и",е:"е","¡":"¡",𝔦:"𝔦",ì:"ì","⨌":"⨌","∭":"∭","⧜":"⧜","℩":"℩",ij:"ij",ī:"ī",ı:"ı","⊷":"⊷",Ƶ:"Ƶ","℅":"℅","∞":"∞","⧝":"⧝","⊺":"⊺","⨗":"⨗","⨼":"⨼",ё:"ё",į:"į",𝕚:"𝕚",ι:"ι","¿":"¿",𝒾:"𝒾","⋹":"⋹","⋵":"⋵","⋴":"⋴","⋳":"⋳",ĩ:"ĩ",і:"і",ï:"ï",ĵ:"ĵ",й:"й",𝔧:"𝔧",ȷ:"ȷ",𝕛:"𝕛",𝒿:"𝒿",ј:"ј",є:"є",κ:"κ",ϰ:"ϰ",ķ:"ķ",к:"к",𝔨:"𝔨",ĸ:"ĸ",х:"х",ќ:"ќ",𝕜:"𝕜",𝓀:"𝓀","⤛":"⤛","⤎":"⤎","⪋":"⪋","⥢":"⥢",ĺ:"ĺ","⦴":"⦴",λ:"λ","⦑":"⦑","⪅":"⪅","«":"«","⤟":"⤟","⤝":"⤝","↫":"↫","⤹":"⤹","⥳":"⥳","↢":"↢","⪫":"⪫","⤙":"⤙","⪭":"⪭","⪭︀":"⪭︀","⤌":"⤌","❲":"❲","{":"{","[":"[","⦋":"⦋","⦏":"⦏","⦍":"⦍",ľ:"ľ",ļ:"ļ",л:"л","⤶":"⤶","⥧":"⥧","⥋":"⥋","↲":"↲","≤":"≤","⇇":"⇇","⋋":"⋋","⪨":"⪨","⩿":"⩿","⪁":"⪁","⪃":"⪃","⋚︀":"⋚︀","⪓":"⪓","⋖":"⋖","⥼":"⥼",𝔩:"𝔩","⪑":"⪑","⥪":"⥪","▄":"▄",љ:"љ","⥫":"⥫","◺":"◺",ŀ:"ŀ","⎰":"⎰","≨":"≨","⪉":"⪉","⪇":"⪇","⋦":"⋦","⟬":"⟬","⇽":"⇽","⟼":"⟼","↬":"↬","⦅":"⦅",𝕝:"𝕝","⨭":"⨭","⨴":"⨴","∗":"∗","◊":"◊","(":"(","⦓":"⦓","⥭":"⥭","‎":"‎","⊿":"⊿","‹":"‹",𝓁:"𝓁","⪍":"⪍","⪏":"⪏","‚":"‚",ł:"ł","⪦":"⪦","⩹":"⩹","⋉":"⋉","⥶":"⥶","⩻":"⩻","⦖":"⦖","◃":"◃","⥊":"⥊","⥦":"⥦","≨︀":"≨︀","∺":"∺","¯":"¯","♂":"♂","✠":"✠","▮":"▮","⨩":"⨩",м:"м","—":"—",𝔪:"𝔪","℧":"℧",µ:"µ","⫰":"⫰","−":"−","⨪":"⨪","⫛":"⫛","⊧":"⊧",𝕞:"𝕞",𝓂:"𝓂",μ:"μ","⊸":"⊸","⋙̸":"⋙̸","≫⃒":"≫⃒","⇍":"⇍","⇎":"⇎","⋘̸":"⋘̸","≪⃒":"≪⃒","⇏":"⇏","⊯":"⊯","⊮":"⊮",ń:"ń","∠⃒":"∠⃒","⩰̸":"⩰̸","≋̸":"≋̸",ʼn:"ʼn","♮":"♮","⩃":"⩃",ň:"ň",ņ:"ņ","⩭̸":"⩭̸","⩂":"⩂",н:"н","–":"–","⇗":"⇗","⤤":"⤤","≐̸":"≐̸","⤨":"⤨",𝔫:"𝔫","↮":"↮","⫲":"⫲","⋼":"⋼","⋺":"⋺",њ:"њ","≦̸":"≦̸","↚":"↚","‥":"‥",𝕟:"𝕟","¬":"¬","⋹̸":"⋹̸","⋵̸":"⋵̸","⋷":"⋷","⋶":"⋶","⋾":"⋾","⋽":"⋽","⫽⃥":"⫽⃥","∂̸":"∂̸","⨔":"⨔","↛":"↛","⤳̸":"⤳̸","↝̸":"↝̸",𝓃:"𝓃","⊄":"⊄","⫅̸":"⫅̸","⊅":"⊅","⫆̸":"⫆̸",ñ:"ñ",ν:"ν","#":"#","№":"№"," ":" ","⊭":"⊭","⤄":"⤄","≍⃒":"≍⃒","⊬":"⊬","≥⃒":"≥⃒",">⃒":">⃒","⧞":"⧞","⤂":"⤂","≤⃒":"≤⃒","<⃒":"<⃒","⊴⃒":"⊴⃒","⤃":"⤃","⊵⃒":"⊵⃒","∼⃒":"∼⃒","⇖":"⇖","⤣":"⤣","⤧":"⤧",ó:"ó",ô:"ô",о:"о",ő:"ő","⨸":"⨸","⦼":"⦼",œ:"œ","⦿":"⦿",𝔬:"𝔬","˛":"˛",ò:"ò","⧁":"⧁","⦵":"⦵","⦾":"⦾","⦻":"⦻","⧀":"⧀",ō:"ō",ω:"ω",ο:"ο","⦶":"⦶",𝕠:"𝕠","⦷":"⦷","⦹":"⦹","∨":"∨","⩝":"⩝",ℴ:"ℴ",ª:"ª",º:"º","⊶":"⊶","⩖":"⩖","⩗":"⩗","⩛":"⩛",ø:"ø","⊘":"⊘",õ:"õ","⨶":"⨶",ö:"ö","⌽":"⌽","¶":"¶","⫳":"⫳","⫽":"⫽",п:"п","%":"%",".":".","‰":"‰","‱":"‱",𝔭:"𝔭",φ:"φ",ϕ:"ϕ","☎":"☎",π:"π",ϖ:"ϖ",ℎ:"ℎ","+":"+","⨣":"⨣","⨢":"⨢","⨥":"⨥","⩲":"⩲","⨦":"⨦","⨧":"⨧","⨕":"⨕",𝕡:"𝕡","£":"£","⪳":"⪳","⪷":"⪷","⪹":"⪹","⪵":"⪵","⋨":"⋨","′":"′","⌮":"⌮","⌒":"⌒","⌓":"⌓","⊰":"⊰",𝓅:"𝓅",ψ:"ψ"," ":" ",𝔮:"𝔮",𝕢:"𝕢","⁗":"⁗",𝓆:"𝓆","⨖":"⨖","?":"?","⤜":"⤜","⥤":"⥤","∽̱":"∽̱",ŕ:"ŕ","⦳":"⦳","⦒":"⦒","⦥":"⦥","»":"»","⥵":"⥵","⤠":"⤠","⤳":"⤳","⤞":"⤞","⥅":"⥅","⥴":"⥴","↣":"↣","↝":"↝","⤚":"⤚","∶":"∶","❳":"❳","}":"}","]":"]","⦌":"⦌","⦎":"⦎","⦐":"⦐",ř:"ř",ŗ:"ŗ",р:"р","⤷":"⤷","⥩":"⥩","↳":"↳","▭":"▭","⥽":"⥽",𝔯:"𝔯","⥬":"⥬",ρ:"ρ",ϱ:"ϱ","⇉":"⇉","⋌":"⋌","˚":"˚","‏":"‏","⎱":"⎱","⫮":"⫮","⟭":"⟭","⇾":"⇾","⦆":"⦆",𝕣:"𝕣","⨮":"⨮","⨵":"⨵",")":")","⦔":"⦔","⨒":"⨒","›":"›",𝓇:"𝓇","⋊":"⋊","▹":"▹","⧎":"⧎","⥨":"⥨","℞":"℞",ś:"ś","⪴":"⪴","⪸":"⪸",š:"š",ş:"ş",ŝ:"ŝ","⪶":"⪶","⪺":"⪺","⋩":"⋩","⨓":"⨓",с:"с","⋅":"⋅","⩦":"⩦","⇘":"⇘","§":"§",";":";","⤩":"⤩","✶":"✶",𝔰:"𝔰","♯":"♯",щ:"щ",ш:"ш","­":"­",σ:"σ",ς:"ς","⩪":"⩪","⪞":"⪞","⪠":"⪠","⪝":"⪝","⪟":"⪟","≆":"≆","⨤":"⨤","⥲":"⥲","⨳":"⨳","⧤":"⧤","⌣":"⌣","⪪":"⪪","⪬":"⪬","⪬︀":"⪬︀",ь:"ь","/":"/","⧄":"⧄","⌿":"⌿",𝕤:"𝕤","♠":"♠","⊓︀":"⊓︀","⊔︀":"⊔︀",𝓈:"𝓈","☆":"☆","⊂":"⊂","⫅":"⫅","⪽":"⪽","⫃":"⫃","⫁":"⫁","⫋":"⫋","⊊":"⊊","⪿":"⪿","⥹":"⥹","⫇":"⫇","⫕":"⫕","⫓":"⫓","♪":"♪","¹":"¹","²":"²","³":"³","⫆":"⫆","⪾":"⪾","⫘":"⫘","⫄":"⫄","⟉":"⟉","⫗":"⫗","⥻":"⥻","⫂":"⫂","⫌":"⫌","⊋":"⊋","⫀":"⫀","⫈":"⫈","⫔":"⫔","⫖":"⫖","⇙":"⇙","⤪":"⤪",ß:"ß","⌖":"⌖",τ:"τ",ť:"ť",ţ:"ţ",т:"т","⌕":"⌕",𝔱:"𝔱",θ:"θ",ϑ:"ϑ",þ:"þ","×":"×","⨱":"⨱","⨰":"⨰","⌶":"⌶","⫱":"⫱",𝕥:"𝕥","⫚":"⫚","‴":"‴","▵":"▵","≜":"≜","◬":"◬","⨺":"⨺","⨹":"⨹","⧍":"⧍","⨻":"⨻","⏢":"⏢",𝓉:"𝓉",ц:"ц",ћ:"ћ",ŧ:"ŧ","⥣":"⥣",ú:"ú",ў:"ў",ŭ:"ŭ",û:"û",у:"у",ű:"ű","⥾":"⥾",𝔲:"𝔲",ù:"ù","▀":"▀","⌜":"⌜","⌏":"⌏","◸":"◸",ū:"ū",ų:"ų",𝕦:"𝕦",υ:"υ","⇈":"⇈","⌝":"⌝","⌎":"⌎",ů:"ů","◹":"◹",𝓊:"𝓊","⋰":"⋰",ũ:"ũ",ü:"ü","⦧":"⦧","⫨":"⫨","⫩":"⫩","⦜":"⦜","⊊︀":"⊊︀","⫋︀":"⫋︀","⊋︀":"⊋︀","⫌︀":"⫌︀",в:"в","⊻":"⊻","≚":"≚","⋮":"⋮",𝔳:"𝔳",𝕧:"𝕧",𝓋:"𝓋","⦚":"⦚",ŵ:"ŵ","⩟":"⩟","≙":"≙",℘:"℘",𝔴:"𝔴",𝕨:"𝕨",𝓌:"𝓌",𝔵:"𝔵",ξ:"ξ","⋻":"⋻",𝕩:"𝕩",𝓍:"𝓍",ý:"ý",я:"я",ŷ:"ŷ",ы:"ы","¥":"¥",𝔶:"𝔶",ї:"ї",𝕪:"𝕪",𝓎:"𝓎",ю:"ю",ÿ:"ÿ",ź:"ź",ž:"ž",з:"з",ż:"ż",ζ:"ζ",𝔷:"𝔷",ж:"ж","⇝":"⇝",𝕫:"𝕫",𝓏:"𝓏","‍":"‍","‌":"‌"}}}},687:(r,e)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.numericUnicodeMap={0:65533,128:8364,130:8218,131:402,132:8222,133:8230,134:8224,135:8225,136:710,137:8240,138:352,139:8249,140:338,142:381,145:8216,146:8217,147:8220,148:8221,149:8226,150:8211,151:8212,152:732,153:8482,154:353,155:8250,156:339,158:382,159:376}},967:(r,e)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.fromCodePoint=String.fromCodePoint||function(r){return String.fromCharCode(Math.floor((r-65536)/1024)+55296,(r-65536)%1024+56320)},e.getCodePoint=String.prototype.codePointAt?function(r,e){return r.codePointAt(e)}:function(r,e){return 1024*(r.charCodeAt(e)-55296)+r.charCodeAt(e+1)-56320+65536},e.highSurrogateFrom=55296,e.highSurrogateTo=56319}},a={};function t(r){var o=a[r];if(void 0!==o)return o.exports;var c=a[r]={exports:{}};return e[r].call(c.exports,c,c.exports,t),c.exports}t.n=r=>{var e=r&&r.__esModule?()=>r.default:()=>r;return t.d(e,{a:e}),e},t.d=(r,e)=>{for(var a in e)t.o(e,a)&&!t.o(r,a)&&Object.defineProperty(r,a,{enumerable:!0,get:e[a]})},t.o=(r,e)=>Object.prototype.hasOwnProperty.call(r,e),r=t(563),window.html_encode=r.encode,window.html_decode=r.decode})(); \ No newline at end of file diff --git a/src/dev-center/js/jquery-3.6.0.min.js b/src/dev-center/js/jquery-3.6.0.min.js index c4c6022f29..abecbc6fef 100644 --- a/src/dev-center/js/jquery-3.6.0.min.js +++ b/src/dev-center/js/jquery-3.6.0.min.js @@ -1,2 +1,20 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ !function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0. + */ // 1.0.3 /* The MIT License (MIT) diff --git a/src/dev-center/js/slugify.js b/src/dev-center/js/slugify.js index ca37320011..289b1b5fcc 100644 --- a/src/dev-center/js/slugify.js +++ b/src/dev-center/js/slugify.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ ;(function (name, root, factory) { if (typeof exports === 'object') { diff --git a/src/git/config/dev.js b/src/git/config/dev.js index c3e45185e3..9b73c08fcd 100644 --- a/src/git/config/dev.js +++ b/src/git/config/dev.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/config/release.js b/src/git/config/release.js index a3e3be6b79..2af4d14db2 100644 --- a/src/git/config/release.js +++ b/src/git/config/release.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/rollup.config.js b/src/git/rollup.config.js index 08eab6c35f..054059f7ef 100644 --- a/src/git/rollup.config.js +++ b/src/git/rollup.config.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/auth.js b/src/git/src/auth.js index eae56c5e05..caf1e6ec99 100644 --- a/src/git/src/auth.js +++ b/src/git/src/auth.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/color.js b/src/git/src/color.js index 24188b17b4..6800b08ff0 100644 --- a/src/git/src/color.js +++ b/src/git/src/color.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/diff.js b/src/git/src/diff.js index 1c804a3a91..2a1e700dac 100644 --- a/src/git/src/diff.js +++ b/src/git/src/diff.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/filesystem.js b/src/git/src/filesystem.js index 88bf74db6a..51c51b1ac2 100644 --- a/src/git/src/filesystem.js +++ b/src/git/src/filesystem.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/format.js b/src/git/src/format.js index fe9a00b7bb..437ab1b159 100644 --- a/src/git/src/format.js +++ b/src/git/src/format.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/git-command-definition.js b/src/git/src/git-command-definition.js index 08f7619617..57bbdd8f82 100644 --- a/src/git/src/git-command-definition.js +++ b/src/git/src/git-command-definition.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/git-helpers.js b/src/git/src/git-helpers.js index 46a94e6c7d..215e6b28fb 100644 --- a/src/git/src/git-helpers.js +++ b/src/git/src/git-helpers.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/help.js b/src/git/src/help.js index bd0b9c02a0..5f6b982422 100644 --- a/src/git/src/help.js +++ b/src/git/src/help.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/main.js b/src/git/src/main.js index b7753ad505..a110d22c4b 100644 --- a/src/git/src/main.js +++ b/src/git/src/main.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/refs.js b/src/git/src/refs.js index c03d125b72..f335d19960 100644 --- a/src/git/src/refs.js +++ b/src/git/src/refs.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/subcommands/__exports__.js b/src/git/src/subcommands/__exports__.js index 9bcfd7dce0..b62a22efa3 100644 --- a/src/git/src/subcommands/__exports__.js +++ b/src/git/src/subcommands/__exports__.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/subcommands/add.js b/src/git/src/subcommands/add.js index c2a2787554..dd85c54e45 100644 --- a/src/git/src/subcommands/add.js +++ b/src/git/src/subcommands/add.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/subcommands/branch.js b/src/git/src/subcommands/branch.js index 947e47f787..dec1d04bee 100644 --- a/src/git/src/subcommands/branch.js +++ b/src/git/src/subcommands/branch.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/subcommands/checkout.js b/src/git/src/subcommands/checkout.js index 2433979bb6..91d30c819b 100644 --- a/src/git/src/subcommands/checkout.js +++ b/src/git/src/subcommands/checkout.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/subcommands/cherry-pick.js b/src/git/src/subcommands/cherry-pick.js index 80dd1401d0..a8c963234a 100644 --- a/src/git/src/subcommands/cherry-pick.js +++ b/src/git/src/subcommands/cherry-pick.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/subcommands/clone.js b/src/git/src/subcommands/clone.js index 7cfa3f1464..9b61668fa6 100644 --- a/src/git/src/subcommands/clone.js +++ b/src/git/src/subcommands/clone.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/subcommands/commit.js b/src/git/src/subcommands/commit.js index c219b80aed..5070749a01 100644 --- a/src/git/src/subcommands/commit.js +++ b/src/git/src/subcommands/commit.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/subcommands/config.js b/src/git/src/subcommands/config.js index 36c5ceff27..94b41a3ead 100644 --- a/src/git/src/subcommands/config.js +++ b/src/git/src/subcommands/config.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/subcommands/diff.js b/src/git/src/subcommands/diff.js index 111554e796..bde2b4ecc9 100644 --- a/src/git/src/subcommands/diff.js +++ b/src/git/src/subcommands/diff.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/subcommands/fetch.js b/src/git/src/subcommands/fetch.js index 74418f02ce..d9ac9ff116 100644 --- a/src/git/src/subcommands/fetch.js +++ b/src/git/src/subcommands/fetch.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/subcommands/help.js b/src/git/src/subcommands/help.js index 6602fa72ac..20b8ed38a7 100644 --- a/src/git/src/subcommands/help.js +++ b/src/git/src/subcommands/help.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/subcommands/init.js b/src/git/src/subcommands/init.js index 8e33350225..7c644766a3 100644 --- a/src/git/src/subcommands/init.js +++ b/src/git/src/subcommands/init.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/subcommands/log.js b/src/git/src/subcommands/log.js index 5d449bead8..747ebcc6ef 100644 --- a/src/git/src/subcommands/log.js +++ b/src/git/src/subcommands/log.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/subcommands/pull.js b/src/git/src/subcommands/pull.js index 3fc71af758..f6748c9d10 100644 --- a/src/git/src/subcommands/pull.js +++ b/src/git/src/subcommands/pull.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/subcommands/push.js b/src/git/src/subcommands/push.js index 64e436f444..5b72d9c377 100644 --- a/src/git/src/subcommands/push.js +++ b/src/git/src/subcommands/push.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/subcommands/remote.js b/src/git/src/subcommands/remote.js index 071319cdca..18c48d861b 100644 --- a/src/git/src/subcommands/remote.js +++ b/src/git/src/subcommands/remote.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/subcommands/restore.js b/src/git/src/subcommands/restore.js index 6090ec5d26..d52ac2cf5e 100644 --- a/src/git/src/subcommands/restore.js +++ b/src/git/src/subcommands/restore.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/subcommands/show.js b/src/git/src/subcommands/show.js index bbe6e32e95..b6856dba6c 100644 --- a/src/git/src/subcommands/show.js +++ b/src/git/src/subcommands/show.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/subcommands/status.js b/src/git/src/subcommands/status.js index 249feec79a..f9f06897fe 100644 --- a/src/git/src/subcommands/status.js +++ b/src/git/src/subcommands/status.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/git/src/subcommands/version.js b/src/git/src/subcommands/version.js index c55cb29fec..0ce009d8c5 100644 --- a/src/git/src/subcommands/version.js +++ b/src/git/src/subcommands/version.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/build.js b/src/gui/build.js index e85fbfa710..bb718683e9 100644 --- a/src/gui/build.js +++ b/src/gui/build.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import { build } from "./utils.js" build(); \ No newline at end of file diff --git a/src/gui/src/IPC.js b/src/gui/src/IPC.js index 1010601b27..853af86569 100644 --- a/src/gui/src/IPC.js +++ b/src/gui/src/IPC.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Components/ActionCard.js b/src/gui/src/UI/Components/ActionCard.js index 96a79d0c2c..d53376d89e 100644 --- a/src/gui/src/UI/Components/ActionCard.js +++ b/src/gui/src/UI/Components/ActionCard.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Components/Button.js b/src/gui/src/UI/Components/Button.js index 3cb306b342..a174648998 100644 --- a/src/gui/src/UI/Components/Button.js +++ b/src/gui/src/UI/Components/Button.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Components/CodeEntryView.js b/src/gui/src/UI/Components/CodeEntryView.js index b3e718588d..90a4067758 100644 --- a/src/gui/src/UI/Components/CodeEntryView.js +++ b/src/gui/src/UI/Components/CodeEntryView.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Components/ConfirmationsView.js b/src/gui/src/UI/Components/ConfirmationsView.js index 17319b5b43..b29ad486b7 100644 --- a/src/gui/src/UI/Components/ConfirmationsView.js +++ b/src/gui/src/UI/Components/ConfirmationsView.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Components/Flexer.js b/src/gui/src/UI/Components/Flexer.js index a287213143..3e41bc6679 100644 --- a/src/gui/src/UI/Components/Flexer.js +++ b/src/gui/src/UI/Components/Flexer.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Components/Frame.js b/src/gui/src/UI/Components/Frame.js index 3b6b009889..d74eb1faad 100644 --- a/src/gui/src/UI/Components/Frame.js +++ b/src/gui/src/UI/Components/Frame.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Components/Glyph.js b/src/gui/src/UI/Components/Glyph.js index 268fdfdeac..b357093a18 100644 --- a/src/gui/src/UI/Components/Glyph.js +++ b/src/gui/src/UI/Components/Glyph.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Components/JustHTML.js b/src/gui/src/UI/Components/JustHTML.js index 8c6a57b0f1..fcf97e56d4 100644 --- a/src/gui/src/UI/Components/JustHTML.js +++ b/src/gui/src/UI/Components/JustHTML.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Components/NotifCard.js b/src/gui/src/UI/Components/NotifCard.js index fe4fdbc0ab..0db91e1778 100644 --- a/src/gui/src/UI/Components/NotifCard.js +++ b/src/gui/src/UI/Components/NotifCard.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Components/PasswordEntry.js b/src/gui/src/UI/Components/PasswordEntry.js index 02fa10e2dd..9b5adf48a5 100644 --- a/src/gui/src/UI/Components/PasswordEntry.js +++ b/src/gui/src/UI/Components/PasswordEntry.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Components/QRCode.js b/src/gui/src/UI/Components/QRCode.js index f15d83e58c..6a9f3524b0 100644 --- a/src/gui/src/UI/Components/QRCode.js +++ b/src/gui/src/UI/Components/QRCode.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Components/RecoveryCodeEntryView.js b/src/gui/src/UI/Components/RecoveryCodeEntryView.js index 2d029e4029..cb51f7d955 100644 --- a/src/gui/src/UI/Components/RecoveryCodeEntryView.js +++ b/src/gui/src/UI/Components/RecoveryCodeEntryView.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Components/RecoveryCodesView.js b/src/gui/src/UI/Components/RecoveryCodesView.js index 09fc8c506a..30dfd8237d 100644 --- a/src/gui/src/UI/Components/RecoveryCodesView.js +++ b/src/gui/src/UI/Components/RecoveryCodesView.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Components/Slider.js b/src/gui/src/UI/Components/Slider.js index 13c7754ac2..0989576254 100644 --- a/src/gui/src/UI/Components/Slider.js +++ b/src/gui/src/UI/Components/Slider.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Components/Spinner.js b/src/gui/src/UI/Components/Spinner.js index 7e00a03397..99cf804d1b 100644 --- a/src/gui/src/UI/Components/Spinner.js +++ b/src/gui/src/UI/Components/Spinner.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Components/StepHeading.js b/src/gui/src/UI/Components/StepHeading.js index 8e95380a4f..58a5c1154c 100644 --- a/src/gui/src/UI/Components/StepHeading.js +++ b/src/gui/src/UI/Components/StepHeading.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Components/StepView.js b/src/gui/src/UI/Components/StepView.js index dafa849210..2da06cc0f2 100644 --- a/src/gui/src/UI/Components/StepView.js +++ b/src/gui/src/UI/Components/StepView.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Components/StringView.js b/src/gui/src/UI/Components/StringView.js index 50fbf68eac..aee602eb1b 100644 --- a/src/gui/src/UI/Components/StringView.js +++ b/src/gui/src/UI/Components/StringView.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Components/Table.js b/src/gui/src/UI/Components/Table.js index 40b0228191..e02af517c1 100644 --- a/src/gui/src/UI/Components/Table.js +++ b/src/gui/src/UI/Components/Table.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Components/TestView.js b/src/gui/src/UI/Components/TestView.js index a412d45a6e..43baa52712 100644 --- a/src/gui/src/UI/Components/TestView.js +++ b/src/gui/src/UI/Components/TestView.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/PuterDialog.js b/src/gui/src/UI/PuterDialog.js index d2d37d61f2..456edb551b 100644 --- a/src/gui/src/UI/PuterDialog.js +++ b/src/gui/src/UI/PuterDialog.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Settings/UITabAbout.js b/src/gui/src/UI/Settings/UITabAbout.js index 9f43f38710..e4788f3f49 100644 --- a/src/gui/src/UI/Settings/UITabAbout.js +++ b/src/gui/src/UI/Settings/UITabAbout.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Settings/UITabAccount.js b/src/gui/src/UI/Settings/UITabAccount.js index 2d933ef8ea..0f2b9d8625 100644 --- a/src/gui/src/UI/Settings/UITabAccount.js +++ b/src/gui/src/UI/Settings/UITabAccount.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Settings/UITabClock.js b/src/gui/src/UI/Settings/UITabClock.js index 498aa87ebc..6e56c5c2de 100644 --- a/src/gui/src/UI/Settings/UITabClock.js +++ b/src/gui/src/UI/Settings/UITabClock.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Settings/UITabLanguage.js b/src/gui/src/UI/Settings/UITabLanguage.js index dfadec9933..4af1c22490 100644 --- a/src/gui/src/UI/Settings/UITabLanguage.js +++ b/src/gui/src/UI/Settings/UITabLanguage.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Settings/UITabPersonalization.js b/src/gui/src/UI/Settings/UITabPersonalization.js index c80e60ad65..9672ad6b80 100644 --- a/src/gui/src/UI/Settings/UITabPersonalization.js +++ b/src/gui/src/UI/Settings/UITabPersonalization.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Settings/UITabSecurity.js b/src/gui/src/UI/Settings/UITabSecurity.js index 5d6564ad62..89ef589bd0 100644 --- a/src/gui/src/UI/Settings/UITabSecurity.js +++ b/src/gui/src/UI/Settings/UITabSecurity.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import TeePromise from "../../util/TeePromise.js"; import Button from "../Components/Button.js"; import Flexer from "../Components/Flexer.js"; diff --git a/src/gui/src/UI/Settings/UITabUsage.js b/src/gui/src/UI/Settings/UITabUsage.js index e4c805b6ef..87253b1a04 100644 --- a/src/gui/src/UI/Settings/UITabUsage.js +++ b/src/gui/src/UI/Settings/UITabUsage.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Settings/UIWindowChangeEmail.js b/src/gui/src/UI/Settings/UIWindowChangeEmail.js index 787bcc893b..3a2eaf1be0 100644 --- a/src/gui/src/UI/Settings/UIWindowChangeEmail.js +++ b/src/gui/src/UI/Settings/UIWindowChangeEmail.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Settings/UIWindowConfirmUserDeletion.js b/src/gui/src/UI/Settings/UIWindowConfirmUserDeletion.js index 41b0f390e2..2404b4a1a4 100644 --- a/src/gui/src/UI/Settings/UIWindowConfirmUserDeletion.js +++ b/src/gui/src/UI/Settings/UIWindowConfirmUserDeletion.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Settings/UIWindowFinalizeUserDeletion.js b/src/gui/src/UI/Settings/UIWindowFinalizeUserDeletion.js index 6ea097bf25..3d3796f274 100644 --- a/src/gui/src/UI/Settings/UIWindowFinalizeUserDeletion.js +++ b/src/gui/src/UI/Settings/UIWindowFinalizeUserDeletion.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Settings/UIWindowSettings.js b/src/gui/src/UI/Settings/UIWindowSettings.js index e50999511c..686cd7fa6c 100644 --- a/src/gui/src/UI/Settings/UIWindowSettings.js +++ b/src/gui/src/UI/Settings/UIWindowSettings.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIAlert.js b/src/gui/src/UI/UIAlert.js index 82f2a7b0af..f19786985d 100644 --- a/src/gui/src/UI/UIAlert.js +++ b/src/gui/src/UI/UIAlert.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIComponentWindow.js b/src/gui/src/UI/UIComponentWindow.js index 3e8cf9306e..e98bd2ddf0 100644 --- a/src/gui/src/UI/UIComponentWindow.js +++ b/src/gui/src/UI/UIComponentWindow.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import UIWindow from './UIWindow.js' import Placeholder from "../util/Placeholder.js" diff --git a/src/gui/src/UI/UIContextMenu.js b/src/gui/src/UI/UIContextMenu.js index 202852c7b1..1cb9740db3 100644 --- a/src/gui/src/UI/UIContextMenu.js +++ b/src/gui/src/UI/UIContextMenu.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIDesktop.js b/src/gui/src/UI/UIDesktop.js index fcad9b24d3..71bca049c4 100644 --- a/src/gui/src/UI/UIDesktop.js +++ b/src/gui/src/UI/UIDesktop.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIItem.js b/src/gui/src/UI/UIItem.js index 5ef43227b4..3047ce2b35 100644 --- a/src/gui/src/UI/UIItem.js +++ b/src/gui/src/UI/UIItem.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UINotification.js b/src/gui/src/UI/UINotification.js index 587d0a813a..f0217b1663 100644 --- a/src/gui/src/UI/UINotification.js +++ b/src/gui/src/UI/UINotification.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIPopover.js b/src/gui/src/UI/UIPopover.js index 23f6f21bb9..950e1d17f5 100644 --- a/src/gui/src/UI/UIPopover.js +++ b/src/gui/src/UI/UIPopover.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIPrompt.js b/src/gui/src/UI/UIPrompt.js index 56b8f4ea4c..aff356a2a2 100644 --- a/src/gui/src/UI/UIPrompt.js +++ b/src/gui/src/UI/UIPrompt.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UITaskbar.js b/src/gui/src/UI/UITaskbar.js index 10cd0c0b0e..de3557ba75 100644 --- a/src/gui/src/UI/UITaskbar.js +++ b/src/gui/src/UI/UITaskbar.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UITaskbarItem.js b/src/gui/src/UI/UITaskbarItem.js index fd293cced4..c0eae73e17 100644 --- a/src/gui/src/UI/UITaskbarItem.js +++ b/src/gui/src/UI/UITaskbarItem.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindow.js b/src/gui/src/UI/UIWindow.js index 223a6d6adc..ee2937f607 100644 --- a/src/gui/src/UI/UIWindow.js +++ b/src/gui/src/UI/UIWindow.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindow2FASetup.js b/src/gui/src/UI/UIWindow2FASetup.js index d574f8d308..62aad9b9e6 100644 --- a/src/gui/src/UI/UIWindow2FASetup.js +++ b/src/gui/src/UI/UIWindow2FASetup.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* Plan: Components: OneAtATimeView < ... > diff --git a/src/gui/src/UI/UIWindowChangePassword.js b/src/gui/src/UI/UIWindowChangePassword.js index d2ff788377..4fc3e6506e 100644 --- a/src/gui/src/UI/UIWindowChangePassword.js +++ b/src/gui/src/UI/UIWindowChangePassword.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowChangeUsername.js b/src/gui/src/UI/UIWindowChangeUsername.js index e901c10c10..1ed17311ab 100644 --- a/src/gui/src/UI/UIWindowChangeUsername.js +++ b/src/gui/src/UI/UIWindowChangeUsername.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowClaimReferral.js b/src/gui/src/UI/UIWindowClaimReferral.js index 68f558e1f7..8f4a710492 100644 --- a/src/gui/src/UI/UIWindowClaimReferral.js +++ b/src/gui/src/UI/UIWindowClaimReferral.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowColorPicker.js b/src/gui/src/UI/UIWindowColorPicker.js index 70fe2b799e..ae75140fea 100644 --- a/src/gui/src/UI/UIWindowColorPicker.js +++ b/src/gui/src/UI/UIWindowColorPicker.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowDesktopBGSettings.js b/src/gui/src/UI/UIWindowDesktopBGSettings.js index 45a253f518..9c96a9e5b5 100644 --- a/src/gui/src/UI/UIWindowDesktopBGSettings.js +++ b/src/gui/src/UI/UIWindowDesktopBGSettings.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowEmailConfirmationRequired.js b/src/gui/src/UI/UIWindowEmailConfirmationRequired.js index 56dce00520..8957f09754 100644 --- a/src/gui/src/UI/UIWindowEmailConfirmationRequired.js +++ b/src/gui/src/UI/UIWindowEmailConfirmationRequired.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowFeedback.js b/src/gui/src/UI/UIWindowFeedback.js index 77aa366e64..6fe81813cf 100644 --- a/src/gui/src/UI/UIWindowFeedback.js +++ b/src/gui/src/UI/UIWindowFeedback.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowFontPicker.js b/src/gui/src/UI/UIWindowFontPicker.js index a3bcacf42f..356f05a46f 100644 --- a/src/gui/src/UI/UIWindowFontPicker.js +++ b/src/gui/src/UI/UIWindowFontPicker.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowItemProperties.js b/src/gui/src/UI/UIWindowItemProperties.js index a05d6283d8..255b8ffe31 100644 --- a/src/gui/src/UI/UIWindowItemProperties.js +++ b/src/gui/src/UI/UIWindowItemProperties.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowLogin.js b/src/gui/src/UI/UIWindowLogin.js index ba7e100294..bf05d5fe03 100644 --- a/src/gui/src/UI/UIWindowLogin.js +++ b/src/gui/src/UI/UIWindowLogin.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowLoginInProgress.js b/src/gui/src/UI/UIWindowLoginInProgress.js index ff33fe8e6a..9ebe505794 100644 --- a/src/gui/src/UI/UIWindowLoginInProgress.js +++ b/src/gui/src/UI/UIWindowLoginInProgress.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowManageSessions.js b/src/gui/src/UI/UIWindowManageSessions.js index bfa26326a0..9515c2aefb 100644 --- a/src/gui/src/UI/UIWindowManageSessions.js +++ b/src/gui/src/UI/UIWindowManageSessions.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import UIAlert from "./UIAlert.js"; import UIWindow from "./UIWindow.js"; diff --git a/src/gui/src/UI/UIWindowMyWebsites.js b/src/gui/src/UI/UIWindowMyWebsites.js index 33864ad09b..025a312145 100644 --- a/src/gui/src/UI/UIWindowMyWebsites.js +++ b/src/gui/src/UI/UIWindowMyWebsites.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowNewPassword.js b/src/gui/src/UI/UIWindowNewPassword.js index eb8c242000..3340f9d2f3 100644 --- a/src/gui/src/UI/UIWindowNewPassword.js +++ b/src/gui/src/UI/UIWindowNewPassword.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowProgress.js b/src/gui/src/UI/UIWindowProgress.js index 3f11185837..06a0d88ac3 100644 --- a/src/gui/src/UI/UIWindowProgress.js +++ b/src/gui/src/UI/UIWindowProgress.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowPublishWebsite.js b/src/gui/src/UI/UIWindowPublishWebsite.js index 619a323e2d..a45916f1c7 100644 --- a/src/gui/src/UI/UIWindowPublishWebsite.js +++ b/src/gui/src/UI/UIWindowPublishWebsite.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowQR.js b/src/gui/src/UI/UIWindowQR.js index 8976fc685e..5a4d6593d8 100644 --- a/src/gui/src/UI/UIWindowQR.js +++ b/src/gui/src/UI/UIWindowQR.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowRecoverPassword.js b/src/gui/src/UI/UIWindowRecoverPassword.js index 87e0ec2718..fbf2ccb873 100644 --- a/src/gui/src/UI/UIWindowRecoverPassword.js +++ b/src/gui/src/UI/UIWindowRecoverPassword.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowRefer.js b/src/gui/src/UI/UIWindowRefer.js index 2bc3a791b0..c5bd384099 100644 --- a/src/gui/src/UI/UIWindowRefer.js +++ b/src/gui/src/UI/UIWindowRefer.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowRequestPermission.js b/src/gui/src/UI/UIWindowRequestPermission.js index 470d949221..18f0dd7c17 100644 --- a/src/gui/src/UI/UIWindowRequestPermission.js +++ b/src/gui/src/UI/UIWindowRequestPermission.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowSaveAccount.js b/src/gui/src/UI/UIWindowSaveAccount.js index f0c7b86117..455420f72a 100644 --- a/src/gui/src/UI/UIWindowSaveAccount.js +++ b/src/gui/src/UI/UIWindowSaveAccount.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowSessionList.js b/src/gui/src/UI/UIWindowSessionList.js index 751f2e1857..dff49331fc 100644 --- a/src/gui/src/UI/UIWindowSessionList.js +++ b/src/gui/src/UI/UIWindowSessionList.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowShare.js b/src/gui/src/UI/UIWindowShare.js index cf4e7cee1f..9d0aca875a 100644 --- a/src/gui/src/UI/UIWindowShare.js +++ b/src/gui/src/UI/UIWindowShare.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import UIWindow from './UIWindow.js' async function UIWindowShare(items, recipient){ diff --git a/src/gui/src/UI/UIWindowSignup.js b/src/gui/src/UI/UIWindowSignup.js index 842672c9b7..0247b5bfca 100644 --- a/src/gui/src/UI/UIWindowSignup.js +++ b/src/gui/src/UI/UIWindowSignup.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowTaskManager.js b/src/gui/src/UI/UIWindowTaskManager.js index c92756e5c9..47c58e224a 100644 --- a/src/gui/src/UI/UIWindowTaskManager.js +++ b/src/gui/src/UI/UIWindowTaskManager.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import { END_HARD, END_SOFT } from "../definitions.js"; import UIAlert from "./UIAlert.js"; import UIContextMenu from "./UIContextMenu.js"; diff --git a/src/gui/src/UI/UIWindowThemeDialog.js b/src/gui/src/UI/UIWindowThemeDialog.js index 234bf34ffe..1226c11537 100644 --- a/src/gui/src/UI/UIWindowThemeDialog.js +++ b/src/gui/src/UI/UIWindowThemeDialog.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import UIComponentWindow from './UIComponentWindow.js'; import Button from './Components/Button.js'; import Flexer from './Components/Flexer.js'; diff --git a/src/gui/src/css/normalize.css b/src/gui/src/css/normalize.css index 192eb9ce43..bebf47bcc4 100644 --- a/src/gui/src/css/normalize.css +++ b/src/gui/src/css/normalize.css @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /*! normalize.css v8.0.1 | MIT License | github.com/necolas/normalize.css */ /* Document diff --git a/src/gui/src/css/style.css b/src/gui/src/css/style.css index e0cc475da2..2943002602 100644 --- a/src/gui/src/css/style.css +++ b/src/gui/src/css/style.css @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/css/theme.css b/src/gui/src/css/theme.css index 3438204d63..b548da5610 100644 --- a/src/gui/src/css/theme.css +++ b/src/gui/src/css/theme.css @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* used for pseudo-stylesheet */ /* diff --git a/src/gui/src/definitions.js b/src/gui/src/definitions.js index cec4261d93..9997341243 100644 --- a/src/gui/src/definitions.js +++ b/src/gui/src/definitions.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/globals.js b/src/gui/src/globals.js index 4f0c2d98a3..9f0e8441bf 100644 --- a/src/gui/src/globals.js +++ b/src/gui/src/globals.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers.js b/src/gui/src/helpers.js index 394bcc65f1..e6019dd336 100644 --- a/src/gui/src/helpers.js +++ b/src/gui/src/helpers.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/check_password_strength.js b/src/gui/src/helpers/check_password_strength.js index 4b0136e67a..429e8bffd0 100644 --- a/src/gui/src/helpers/check_password_strength.js +++ b/src/gui/src/helpers/check_password_strength.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/content_type_to_icon.js b/src/gui/src/helpers/content_type_to_icon.js index 1cec143d4d..9e32fe7b45 100644 --- a/src/gui/src/helpers/content_type_to_icon.js +++ b/src/gui/src/helpers/content_type_to_icon.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/determine_active_container_parent.js b/src/gui/src/helpers/determine_active_container_parent.js index c66d03f68d..775e89c887 100644 --- a/src/gui/src/helpers/determine_active_container_parent.js +++ b/src/gui/src/helpers/determine_active_container_parent.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/download.js b/src/gui/src/helpers/download.js index b00d9bcaa7..f973a63109 100644 --- a/src/gui/src/helpers/download.js +++ b/src/gui/src/helpers/download.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/fixedEncodeURIComponent.js b/src/gui/src/helpers/fixedEncodeURIComponent.js index d6728d811f..fb7530d13c 100644 --- a/src/gui/src/helpers/fixedEncodeURIComponent.js +++ b/src/gui/src/helpers/fixedEncodeURIComponent.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/get_html_element_from_options.js b/src/gui/src/helpers/get_html_element_from_options.js index ee464d5f22..9a725cd3b7 100644 --- a/src/gui/src/helpers/get_html_element_from_options.js +++ b/src/gui/src/helpers/get_html_element_from_options.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/globToRegExp.js b/src/gui/src/helpers/globToRegExp.js index d58be6d685..f0340f1fad 100644 --- a/src/gui/src/helpers/globToRegExp.js +++ b/src/gui/src/helpers/globToRegExp.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/item_icon.js b/src/gui/src/helpers/item_icon.js index f17ea7893b..36d5410c4e 100644 --- a/src/gui/src/helpers/item_icon.js +++ b/src/gui/src/helpers/item_icon.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/launch_app.js b/src/gui/src/helpers/launch_app.js index d6dc6553fe..565dcc2f53 100644 --- a/src/gui/src/helpers/launch_app.js +++ b/src/gui/src/helpers/launch_app.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/new_context_menu_item.js b/src/gui/src/helpers/new_context_menu_item.js index 6c2ea49e14..3a616597bb 100644 --- a/src/gui/src/helpers/new_context_menu_item.js +++ b/src/gui/src/helpers/new_context_menu_item.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/open_item.js b/src/gui/src/helpers/open_item.js index efdf3686fd..52551678eb 100644 --- a/src/gui/src/helpers/open_item.js +++ b/src/gui/src/helpers/open_item.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/refresh_item_container.js b/src/gui/src/helpers/refresh_item_container.js index 3de003295d..b64bf710f7 100644 --- a/src/gui/src/helpers/refresh_item_container.js +++ b/src/gui/src/helpers/refresh_item_container.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/socialLink.js b/src/gui/src/helpers/socialLink.js index 698ef9f1f2..efe702bc01 100644 --- a/src/gui/src/helpers/socialLink.js +++ b/src/gui/src/helpers/socialLink.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/truncate_filename.js b/src/gui/src/helpers/truncate_filename.js index 2672eb0ada..5645e381a7 100644 --- a/src/gui/src/helpers/truncate_filename.js +++ b/src/gui/src/helpers/truncate_filename.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/update_last_touch_coordinates.js b/src/gui/src/helpers/update_last_touch_coordinates.js index a814bb3a8c..3d036c8464 100644 --- a/src/gui/src/helpers/update_last_touch_coordinates.js +++ b/src/gui/src/helpers/update_last_touch_coordinates.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/update_mouse_position.js b/src/gui/src/helpers/update_mouse_position.js index 7b433180ee..01f6e4dd25 100644 --- a/src/gui/src/helpers/update_mouse_position.js +++ b/src/gui/src/helpers/update_mouse_position.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/update_title_based_on_uploads.js b/src/gui/src/helpers/update_title_based_on_uploads.js index aa0beadd74..7c55853f0d 100644 --- a/src/gui/src/helpers/update_title_based_on_uploads.js +++ b/src/gui/src/helpers/update_title_based_on_uploads.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/update_username_in_gui.js b/src/gui/src/helpers/update_username_in_gui.js index 78c2f35353..32c2806e48 100644 --- a/src/gui/src/helpers/update_username_in_gui.js +++ b/src/gui/src/helpers/update_username_in_gui.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/i18n.js b/src/gui/src/i18n/i18n.js index f0f5fd650b..64410b7ba2 100644 --- a/src/gui/src/i18n/i18n.js +++ b/src/gui/src/i18n/i18n.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/i18nChangeLanguage.js b/src/gui/src/i18n/i18nChangeLanguage.js index 44cfa33585..a5430f0cb9 100644 --- a/src/gui/src/i18n/i18nChangeLanguage.js +++ b/src/gui/src/i18n/i18nChangeLanguage.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/ar.js b/src/gui/src/i18n/translations/ar.js index 6cf2074fcc..7beec74666 100644 --- a/src/gui/src/i18n/translations/ar.js +++ b/src/gui/src/i18n/translations/ar.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index c90ebb5517..9402320935 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/br.js b/src/gui/src/i18n/translations/br.js index b9c4089350..1c8c0acf9d 100644 --- a/src/gui/src/i18n/translations/br.js +++ b/src/gui/src/i18n/translations/br.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/da.js b/src/gui/src/i18n/translations/da.js index a91d109fe3..be0934631d 100644 --- a/src/gui/src/i18n/translations/da.js +++ b/src/gui/src/i18n/translations/da.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/de.js b/src/gui/src/i18n/translations/de.js index a481060a6a..ecd95e7b35 100644 --- a/src/gui/src/i18n/translations/de.js +++ b/src/gui/src/i18n/translations/de.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/emoji.js b/src/gui/src/i18n/translations/emoji.js index 109dc7d21b..ad3017ab0b 100644 --- a/src/gui/src/i18n/translations/emoji.js +++ b/src/gui/src/i18n/translations/emoji.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/en.js b/src/gui/src/i18n/translations/en.js index e9c87c88cc..0d3a4f9567 100644 --- a/src/gui/src/i18n/translations/en.js +++ b/src/gui/src/i18n/translations/en.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/es.js b/src/gui/src/i18n/translations/es.js index 6d03e69a29..bb94e51ee1 100644 --- a/src/gui/src/i18n/translations/es.js +++ b/src/gui/src/i18n/translations/es.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/fa.js b/src/gui/src/i18n/translations/fa.js index f422759c91..9c71b0271f 100644 --- a/src/gui/src/i18n/translations/fa.js +++ b/src/gui/src/i18n/translations/fa.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/fi.js b/src/gui/src/i18n/translations/fi.js index 37a159dfa5..4aaf96a296 100644 --- a/src/gui/src/i18n/translations/fi.js +++ b/src/gui/src/i18n/translations/fi.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/fr.js b/src/gui/src/i18n/translations/fr.js index 19928c798d..5a4512b469 100644 --- a/src/gui/src/i18n/translations/fr.js +++ b/src/gui/src/i18n/translations/fr.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/hi.js b/src/gui/src/i18n/translations/hi.js index 5b8ddf7bbf..7ea9a688c6 100644 --- a/src/gui/src/i18n/translations/hi.js +++ b/src/gui/src/i18n/translations/hi.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/hy.js b/src/gui/src/i18n/translations/hy.js index 06cae2caa6..b5250cae46 100644 --- a/src/gui/src/i18n/translations/hy.js +++ b/src/gui/src/i18n/translations/hy.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/ig.js b/src/gui/src/i18n/translations/ig.js index f10d309417..e5e822e73e 100644 --- a/src/gui/src/i18n/translations/ig.js +++ b/src/gui/src/i18n/translations/ig.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/it.js b/src/gui/src/i18n/translations/it.js index 4be3baadc5..0e40485aa6 100644 --- a/src/gui/src/i18n/translations/it.js +++ b/src/gui/src/i18n/translations/it.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/ko.js b/src/gui/src/i18n/translations/ko.js index b7318a6e63..8c3e20fa8c 100644 --- a/src/gui/src/i18n/translations/ko.js +++ b/src/gui/src/i18n/translations/ko.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/nb.js b/src/gui/src/i18n/translations/nb.js index 478ef91e7b..3901711af7 100644 --- a/src/gui/src/i18n/translations/nb.js +++ b/src/gui/src/i18n/translations/nb.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/nl.js b/src/gui/src/i18n/translations/nl.js index b6b0d5af3d..f141d77213 100644 --- a/src/gui/src/i18n/translations/nl.js +++ b/src/gui/src/i18n/translations/nl.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/nn.js b/src/gui/src/i18n/translations/nn.js index ccadf63bc6..e11cf6ea19 100644 --- a/src/gui/src/i18n/translations/nn.js +++ b/src/gui/src/i18n/translations/nn.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/pl.js b/src/gui/src/i18n/translations/pl.js index b3c1ea7aaf..8c27a617ef 100644 --- a/src/gui/src/i18n/translations/pl.js +++ b/src/gui/src/i18n/translations/pl.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/pt.js b/src/gui/src/i18n/translations/pt.js index 349c906ae2..b41c1eb48c 100644 --- a/src/gui/src/i18n/translations/pt.js +++ b/src/gui/src/i18n/translations/pt.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/ro.js b/src/gui/src/i18n/translations/ro.js index 9bca3a4834..e381105705 100644 --- a/src/gui/src/i18n/translations/ro.js +++ b/src/gui/src/i18n/translations/ro.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/ru.js b/src/gui/src/i18n/translations/ru.js index f2c7680e02..678febb9f8 100644 --- a/src/gui/src/i18n/translations/ru.js +++ b/src/gui/src/i18n/translations/ru.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/sv.js b/src/gui/src/i18n/translations/sv.js index a05a5e76e0..b682a086c6 100644 --- a/src/gui/src/i18n/translations/sv.js +++ b/src/gui/src/i18n/translations/sv.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/th.js b/src/gui/src/i18n/translations/th.js index 519d871223..13521ecffb 100644 --- a/src/gui/src/i18n/translations/th.js +++ b/src/gui/src/i18n/translations/th.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/tr.js b/src/gui/src/i18n/translations/tr.js index 5b16e9cf26..ce9d1ab194 100644 --- a/src/gui/src/i18n/translations/tr.js +++ b/src/gui/src/i18n/translations/tr.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/translations.js b/src/gui/src/i18n/translations/translations.js index 4cd212972f..f64a1c5321 100644 --- a/src/gui/src/i18n/translations/translations.js +++ b/src/gui/src/i18n/translations/translations.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/ua.js b/src/gui/src/i18n/translations/ua.js index 3d59946c90..59fa3bee4c 100644 --- a/src/gui/src/i18n/translations/ua.js +++ b/src/gui/src/i18n/translations/ua.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/ur.js b/src/gui/src/i18n/translations/ur.js index 79c2690038..a9596518a2 100644 --- a/src/gui/src/i18n/translations/ur.js +++ b/src/gui/src/i18n/translations/ur.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/zh.js b/src/gui/src/i18n/translations/zh.js index e801e00d43..6928b04fb1 100644 --- a/src/gui/src/i18n/translations/zh.js +++ b/src/gui/src/i18n/translations/zh.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/i18n/translations/zhtw.js b/src/gui/src/i18n/translations/zhtw.js index 25b1a3b086..6e6c0e57cb 100644 --- a/src/gui/src/i18n/translations/zhtw.js +++ b/src/gui/src/i18n/translations/zhtw.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/index.js b/src/gui/src/index.js index cc1a58e9e7..60a3c1d991 100644 --- a/src/gui/src/index.js +++ b/src/gui/src/index.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/init_async.js b/src/gui/src/init_async.js index 31bf4a0a5c..394fb6c8e4 100644 --- a/src/gui/src/init_async.js +++ b/src/gui/src/init_async.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ // Note: this logs AFTER all imports because imports are hoisted logger.info('start -> async initialization'); diff --git a/src/gui/src/init_sync.js b/src/gui/src/init_sync.js index cea2e53478..5635e15a46 100644 --- a/src/gui/src/init_sync.js +++ b/src/gui/src/init_sync.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * @global * @function logger diff --git a/src/gui/src/initgui.js b/src/gui/src/initgui.js index 0f41366d6b..863dba03ba 100644 --- a/src/gui/src/initgui.js +++ b/src/gui/src/initgui.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/keyboard.js b/src/gui/src/keyboard.js index aa9e448708..4ee1f7544b 100644 --- a/src/gui/src/keyboard.js +++ b/src/gui/src/keyboard.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/services/BroadcastService.js b/src/gui/src/services/BroadcastService.js index e0e6a470dc..836b0c697f 100644 --- a/src/gui/src/services/BroadcastService.js +++ b/src/gui/src/services/BroadcastService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/services/ExportRegistrantService.js b/src/gui/src/services/ExportRegistrantService.js index a404d8b9c3..aefdc8af64 100644 --- a/src/gui/src/services/ExportRegistrantService.js +++ b/src/gui/src/services/ExportRegistrantService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import Spinner from "../UI/Components/Spinner"; import { Service } from "../definitions"; diff --git a/src/gui/src/services/LaunchOnInitService.js b/src/gui/src/services/LaunchOnInitService.js index 268c6be7d6..093fc7ed96 100644 --- a/src/gui/src/services/LaunchOnInitService.js +++ b/src/gui/src/services/LaunchOnInitService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import UIAlert from "../UI/UIAlert.js"; import { Service } from "../definitions.js"; diff --git a/src/gui/src/services/LocaleService.js b/src/gui/src/services/LocaleService.js index dbeeedb904..b165d07d2b 100644 --- a/src/gui/src/services/LocaleService.js +++ b/src/gui/src/services/LocaleService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import { Service } from "../definitions.js"; import i18n from "../i18n/i18n.js"; diff --git a/src/gui/src/services/ProcessService.js b/src/gui/src/services/ProcessService.js index 410217c421..08683772b4 100644 --- a/src/gui/src/services/ProcessService.js +++ b/src/gui/src/services/ProcessService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import { InitProcess, Service } from "../definitions.js"; // The NULL UUID is also the UUID for the init process. diff --git a/src/gui/src/services/SettingsService.js b/src/gui/src/services/SettingsService.js index 3470fdce83..0a74394963 100644 --- a/src/gui/src/services/SettingsService.js +++ b/src/gui/src/services/SettingsService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import { Service } from "../definitions.js"; import AboutTab from '../UI/Settings/UITabAbout.js'; diff --git a/src/gui/src/services/ThemeService.js b/src/gui/src/services/ThemeService.js index 77356eeb28..e1f6c0b5c8 100644 --- a/src/gui/src/services/ThemeService.js +++ b/src/gui/src/services/ThemeService.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/static-assets.js b/src/gui/src/static-assets.js index 1b8b0e5d58..7b07d48c30 100644 --- a/src/gui/src/static-assets.js +++ b/src/gui/src/static-assets.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/util/Component.js b/src/gui/src/util/Component.js index 813ce00b7a..7039513fc8 100644 --- a/src/gui/src/util/Component.js +++ b/src/gui/src/util/Component.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import ValueHolder from "./ValueHolder.js"; export const Component = def(class Component extends HTMLElement { diff --git a/src/gui/src/util/Placeholder.js b/src/gui/src/util/Placeholder.js index 5515a9f7b9..65af08719d 100644 --- a/src/gui/src/util/Placeholder.js +++ b/src/gui/src/util/Placeholder.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * @typedef {Object} PlaceholderReturn * @property {String} html: An html string that represents the placeholder diff --git a/src/gui/src/util/TeePromise.js b/src/gui/src/util/TeePromise.js index c53fcb6581..a98874ea3d 100644 --- a/src/gui/src/util/TeePromise.js +++ b/src/gui/src/util/TeePromise.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ export default def(class TeePromise { static ID = 'util.TeePromise'; diff --git a/src/gui/src/util/ValueHolder.js b/src/gui/src/util/ValueHolder.js index 172b76c897..662297d4ee 100644 --- a/src/gui/src/util/ValueHolder.js +++ b/src/gui/src/util/ValueHolder.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Holds an observable value. */ diff --git a/src/gui/utils.js b/src/gui/utils.js index 04cf957f4d..e0ff55a287 100644 --- a/src/gui/utils.js +++ b/src/gui/utils.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* Copyright (C) 2024 Puter Technologies Inc. diff --git a/src/parsely/exports.js b/src/parsely/exports.js index 85551cc7a2..da80f40e98 100644 --- a/src/parsely/exports.js +++ b/src/parsely/exports.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import { adapt_parser, VALUE } from './parser.js'; import { Discard, FirstMatch, Optional, Repeat, Sequence } from './parsers/combinators.js'; import { Fail, Literal, None, StringOf, StringUntil, Symbol } from './parsers/terminals.js'; diff --git a/src/parsely/parser.js b/src/parsely/parser.js index c588ccf12f..3bdcf97186 100644 --- a/src/parsely/parser.js +++ b/src/parsely/parser.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ export const adapt_parser = v => v; export const UNRECOGNIZED = Symbol('unrecognized'); diff --git a/src/parsely/parsers/combinators.js b/src/parsely/parsers/combinators.js index d65066d86d..48ca91e620 100644 --- a/src/parsely/parsers/combinators.js +++ b/src/parsely/parsers/combinators.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import { adapt_parser, INVALID, Parser, UNRECOGNIZED, VALUE } from '../parser.js'; /** diff --git a/src/parsely/parsers/terminals.js b/src/parsely/parsers/terminals.js index a7afaaa8a0..65ae419794 100644 --- a/src/parsely/parsers/terminals.js +++ b/src/parsely/parsers/terminals.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import { INVALID, Parser, UNRECOGNIZED, VALUE } from '../parser.js'; /** diff --git a/src/parsely/streams.js b/src/parsely/streams.js index 23254b624b..9e63a8aa96 100644 --- a/src/parsely/streams.js +++ b/src/parsely/streams.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Base class for input streams. * Defines which methods are expected for any stream implementations. diff --git a/src/phoenix/config/dev.js b/src/phoenix/config/dev.js index 01886c8136..fb4a27c34c 100644 --- a/src/phoenix/config/dev.js +++ b/src/phoenix/config/dev.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/config/release.js b/src/phoenix/config/release.js index 03352ff379..8e00ff05b9 100644 --- a/src/phoenix/config/release.js +++ b/src/phoenix/config/release.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/doc/stash/SymbolParserImpl.js b/src/phoenix/doc/stash/SymbolParserImpl.js index 0c6f4b2a77..5ad3c9a0e8 100644 --- a/src/phoenix/doc/stash/SymbolParserImpl.js +++ b/src/phoenix/doc/stash/SymbolParserImpl.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/rollup.config.js b/src/phoenix/rollup.config.js index 69880de09c..9b58543dbb 100644 --- a/src/phoenix/rollup.config.js +++ b/src/phoenix/rollup.config.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/ANSIContext.js b/src/phoenix/src/ansi-shell/ANSIContext.js index cc7283a1cc..5fca280122 100644 --- a/src/phoenix/src/ansi-shell/ANSIContext.js +++ b/src/phoenix/src/ansi-shell/ANSIContext.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/ANSIShell.js b/src/phoenix/src/ansi-shell/ANSIShell.js index ea83bb7fd2..f0a0baad8c 100644 --- a/src/phoenix/src/ansi-shell/ANSIShell.js +++ b/src/phoenix/src/ansi-shell/ANSIShell.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/ConcreteSyntaxError.js b/src/phoenix/src/ansi-shell/ConcreteSyntaxError.js index 7ffbfd5c6b..70bc7b33d8 100644 --- a/src/phoenix/src/ansi-shell/ConcreteSyntaxError.js +++ b/src/phoenix/src/ansi-shell/ConcreteSyntaxError.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/arg-parsers/simple-parser.js b/src/phoenix/src/ansi-shell/arg-parsers/simple-parser.js index d853d9053f..0c77fec5ec 100644 --- a/src/phoenix/src/ansi-shell/arg-parsers/simple-parser.js +++ b/src/phoenix/src/ansi-shell/arg-parsers/simple-parser.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/decorators/errors.js b/src/phoenix/src/ansi-shell/decorators/errors.js index 85eabb3e78..fb81bb6138 100644 --- a/src/phoenix/src/ansi-shell/decorators/errors.js +++ b/src/phoenix/src/ansi-shell/decorators/errors.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/ioutil/ByteWriter.js b/src/phoenix/src/ansi-shell/ioutil/ByteWriter.js index d2e0655aab..756ca4095f 100644 --- a/src/phoenix/src/ansi-shell/ioutil/ByteWriter.js +++ b/src/phoenix/src/ansi-shell/ioutil/ByteWriter.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/ioutil/MemReader.js b/src/phoenix/src/ansi-shell/ioutil/MemReader.js index 53d711aeb4..11a7c8f1ba 100644 --- a/src/phoenix/src/ansi-shell/ioutil/MemReader.js +++ b/src/phoenix/src/ansi-shell/ioutil/MemReader.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/ioutil/MemWriter.js b/src/phoenix/src/ansi-shell/ioutil/MemWriter.js index 8e091f0dc3..aa1675a492 100644 --- a/src/phoenix/src/ansi-shell/ioutil/MemWriter.js +++ b/src/phoenix/src/ansi-shell/ioutil/MemWriter.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/ioutil/MultiWriter.js b/src/phoenix/src/ansi-shell/ioutil/MultiWriter.js index 9b3be2713e..75e14f0f1a 100644 --- a/src/phoenix/src/ansi-shell/ioutil/MultiWriter.js +++ b/src/phoenix/src/ansi-shell/ioutil/MultiWriter.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/ioutil/NullifyWriter.js b/src/phoenix/src/ansi-shell/ioutil/NullifyWriter.js index 3980aeff60..f51af4d41a 100644 --- a/src/phoenix/src/ansi-shell/ioutil/NullifyWriter.js +++ b/src/phoenix/src/ansi-shell/ioutil/NullifyWriter.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/ioutil/ProxyReader.js b/src/phoenix/src/ansi-shell/ioutil/ProxyReader.js index 9b2e6bfefe..3c202dd1c3 100644 --- a/src/phoenix/src/ansi-shell/ioutil/ProxyReader.js +++ b/src/phoenix/src/ansi-shell/ioutil/ProxyReader.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/ioutil/ProxyWriter.js b/src/phoenix/src/ansi-shell/ioutil/ProxyWriter.js index cd6b4dbdc7..5ee46b0b89 100644 --- a/src/phoenix/src/ansi-shell/ioutil/ProxyWriter.js +++ b/src/phoenix/src/ansi-shell/ioutil/ProxyWriter.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/ioutil/SignalReader.js b/src/phoenix/src/ansi-shell/ioutil/SignalReader.js index 17ea234b56..66cc993014 100644 --- a/src/phoenix/src/ansi-shell/ioutil/SignalReader.js +++ b/src/phoenix/src/ansi-shell/ioutil/SignalReader.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/ioutil/SyncLinesReader.js b/src/phoenix/src/ansi-shell/ioutil/SyncLinesReader.js index be89d509f9..69fb781fd9 100644 --- a/src/phoenix/src/ansi-shell/ioutil/SyncLinesReader.js +++ b/src/phoenix/src/ansi-shell/ioutil/SyncLinesReader.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/parsing/PARSE_CONSTANTS.js b/src/phoenix/src/ansi-shell/parsing/PARSE_CONSTANTS.js index bb4769cd13..75df56c01d 100644 --- a/src/phoenix/src/ansi-shell/parsing/PARSE_CONSTANTS.js +++ b/src/phoenix/src/ansi-shell/parsing/PARSE_CONSTANTS.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/parsing/PuterShellParser.js b/src/phoenix/src/ansi-shell/parsing/PuterShellParser.js index 3c87dbf89e..297b3d8553 100644 --- a/src/phoenix/src/ansi-shell/parsing/PuterShellParser.js +++ b/src/phoenix/src/ansi-shell/parsing/PuterShellParser.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/parsing/UnquotedTokenParserImpl.js b/src/phoenix/src/ansi-shell/parsing/UnquotedTokenParserImpl.js index f6916088c2..142c017902 100644 --- a/src/phoenix/src/ansi-shell/parsing/UnquotedTokenParserImpl.js +++ b/src/phoenix/src/ansi-shell/parsing/UnquotedTokenParserImpl.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/parsing/brainstorming.js b/src/phoenix/src/ansi-shell/parsing/brainstorming.js index 0e16cdcaba..f6d760ccb1 100644 --- a/src/phoenix/src/ansi-shell/parsing/brainstorming.js +++ b/src/phoenix/src/ansi-shell/parsing/brainstorming.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/parsing/buildParserFirstHalf.js b/src/phoenix/src/ansi-shell/parsing/buildParserFirstHalf.js index 141f632f01..932c41fc1b 100644 --- a/src/phoenix/src/ansi-shell/parsing/buildParserFirstHalf.js +++ b/src/phoenix/src/ansi-shell/parsing/buildParserFirstHalf.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/parsing/buildParserSecondHalf.js b/src/phoenix/src/ansi-shell/parsing/buildParserSecondHalf.js index 1fa6e4ae0e..00cc36aa53 100644 --- a/src/phoenix/src/ansi-shell/parsing/buildParserSecondHalf.js +++ b/src/phoenix/src/ansi-shell/parsing/buildParserSecondHalf.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/pipeline/Coupler.js b/src/phoenix/src/ansi-shell/pipeline/Coupler.js index ad40b9c082..517dd405c1 100644 --- a/src/phoenix/src/ansi-shell/pipeline/Coupler.js +++ b/src/phoenix/src/ansi-shell/pipeline/Coupler.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/pipeline/Pipe.js b/src/phoenix/src/ansi-shell/pipeline/Pipe.js index 59c9c46f32..41533aabd9 100644 --- a/src/phoenix/src/ansi-shell/pipeline/Pipe.js +++ b/src/phoenix/src/ansi-shell/pipeline/Pipe.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/pipeline/Pipeline.js b/src/phoenix/src/ansi-shell/pipeline/Pipeline.js index 590d96e4b9..35dfa96fe2 100644 --- a/src/phoenix/src/ansi-shell/pipeline/Pipeline.js +++ b/src/phoenix/src/ansi-shell/pipeline/Pipeline.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/pipeline/iowrappers.js b/src/phoenix/src/ansi-shell/pipeline/iowrappers.js index fc4cf49c5c..324a59046b 100644 --- a/src/phoenix/src/ansi-shell/pipeline/iowrappers.js +++ b/src/phoenix/src/ansi-shell/pipeline/iowrappers.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/readline/history.js b/src/phoenix/src/ansi-shell/readline/history.js index f04b3a3693..ead08e74b8 100644 --- a/src/phoenix/src/ansi-shell/readline/history.js +++ b/src/phoenix/src/ansi-shell/readline/history.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/readline/readline.js b/src/phoenix/src/ansi-shell/readline/readline.js index 735ec3e997..1a99804c13 100644 --- a/src/phoenix/src/ansi-shell/readline/readline.js +++ b/src/phoenix/src/ansi-shell/readline/readline.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/readline/readtoken.js b/src/phoenix/src/ansi-shell/readline/readtoken.js index 63fbc13800..459aa0a52c 100644 --- a/src/phoenix/src/ansi-shell/readline/readtoken.js +++ b/src/phoenix/src/ansi-shell/readline/readtoken.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/readline/rl_comprehend.js b/src/phoenix/src/ansi-shell/readline/rl_comprehend.js index 12ab9a236a..30c958b52f 100644 --- a/src/phoenix/src/ansi-shell/readline/rl_comprehend.js +++ b/src/phoenix/src/ansi-shell/readline/rl_comprehend.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/readline/rl_csi_handlers.js b/src/phoenix/src/ansi-shell/readline/rl_csi_handlers.js index 1128929b5e..22470166ec 100644 --- a/src/phoenix/src/ansi-shell/readline/rl_csi_handlers.js +++ b/src/phoenix/src/ansi-shell/readline/rl_csi_handlers.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/readline/rl_words.js b/src/phoenix/src/ansi-shell/readline/rl_words.js index 1046985283..0fd1293ee1 100644 --- a/src/phoenix/src/ansi-shell/readline/rl_words.js +++ b/src/phoenix/src/ansi-shell/readline/rl_words.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/ansi-shell/signals.js b/src/phoenix/src/ansi-shell/signals.js index b81253fed6..bf060b5bee 100644 --- a/src/phoenix/src/ansi-shell/signals.js +++ b/src/phoenix/src/ansi-shell/signals.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/context/context.js b/src/phoenix/src/context/context.js index aaf3868bf4..2d6d67d305 100644 --- a/src/phoenix/src/context/context.js +++ b/src/phoenix/src/context/context.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/main_cli.js b/src/phoenix/src/main_cli.js index 1f1808eeee..093ffb2908 100644 --- a/src/phoenix/src/main_cli.js +++ b/src/phoenix/src/main_cli.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/main_puter.js b/src/phoenix/src/main_puter.js index 0411b55379..4182fad996 100644 --- a/src/phoenix/src/main_puter.js +++ b/src/phoenix/src/main_puter.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/meta/versions.js b/src/phoenix/src/meta/versions.js index cd83eacfb5..f56ebe2d96 100644 --- a/src/phoenix/src/meta/versions.js +++ b/src/phoenix/src/meta/versions.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/platform/node/env.js b/src/phoenix/src/platform/node/env.js index 58f31614a6..859692c3c4 100644 --- a/src/phoenix/src/platform/node/env.js +++ b/src/phoenix/src/platform/node/env.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import os from 'os'; export const CreateEnvProvider = () => { diff --git a/src/phoenix/src/platform/node/filesystem.js b/src/phoenix/src/platform/node/filesystem.js index 17e30710c8..c067acb2c6 100644 --- a/src/phoenix/src/platform/node/filesystem.js +++ b/src/phoenix/src/platform/node/filesystem.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/platform/node/system.js b/src/phoenix/src/platform/node/system.js index ec83ebfe6f..67564a5602 100644 --- a/src/phoenix/src/platform/node/system.js +++ b/src/phoenix/src/platform/node/system.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import process from 'node:process'; export const CreateSystemProvider = () => { diff --git a/src/phoenix/src/platform/puter/drivers.js b/src/phoenix/src/platform/puter/drivers.js index dea0d0d64b..20ab8fa386 100644 --- a/src/phoenix/src/platform/puter/drivers.js +++ b/src/phoenix/src/platform/puter/drivers.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/platform/puter/env.js b/src/phoenix/src/platform/puter/env.js index 2ef342b4a0..0c7b23896d 100644 --- a/src/phoenix/src/platform/puter/env.js +++ b/src/phoenix/src/platform/puter/env.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ export const CreateEnvProvider = ({ config }) => { return { getEnv: () => { diff --git a/src/phoenix/src/platform/puter/filesystem.js b/src/phoenix/src/platform/puter/filesystem.js index 3ce632ec07..5e028facff 100644 --- a/src/phoenix/src/platform/puter/filesystem.js +++ b/src/phoenix/src/platform/puter/filesystem.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/platform/puter/system.js b/src/phoenix/src/platform/puter/system.js index 320ec73a73..14aa7874f0 100644 --- a/src/phoenix/src/platform/puter/system.js +++ b/src/phoenix/src/platform/puter/system.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ export const CreateSystemProvider = ({ puterSDK }) => { return { exit: (code) => { diff --git a/src/phoenix/src/promise.js b/src/phoenix/src/promise.js index 5c47d2bd1d..aa75a06ef1 100644 --- a/src/phoenix/src/promise.js +++ b/src/phoenix/src/promise.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ export class TeePromise { static STATUS_PENDING = Symbol('pending'); static STATUS_RUNNING = {}; diff --git a/src/phoenix/src/pty/NodeStdioPTT.js b/src/phoenix/src/pty/NodeStdioPTT.js index 58cd947c3e..b9a35d2505 100644 --- a/src/phoenix/src/pty/NodeStdioPTT.js +++ b/src/phoenix/src/pty/NodeStdioPTT.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import { ReadableStream, WritableStream } from 'stream/web'; import { signals } from "../ansi-shell/signals.js"; diff --git a/src/phoenix/src/pty/XDocumentPTT.js b/src/phoenix/src/pty/XDocumentPTT.js index 64435d2d25..3846583d19 100644 --- a/src/phoenix/src/pty/XDocumentPTT.js +++ b/src/phoenix/src/pty/XDocumentPTT.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/completers/CommandCompleter.js b/src/phoenix/src/puter-shell/completers/CommandCompleter.js index 4f9fa2dfdf..4e9d7f6a5c 100644 --- a/src/phoenix/src/puter-shell/completers/CommandCompleter.js +++ b/src/phoenix/src/puter-shell/completers/CommandCompleter.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/completers/FileCompleter.js b/src/phoenix/src/puter-shell/completers/FileCompleter.js index 805024c614..392f19e355 100644 --- a/src/phoenix/src/puter-shell/completers/FileCompleter.js +++ b/src/phoenix/src/puter-shell/completers/FileCompleter.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/completers/OptionCompleter.js b/src/phoenix/src/puter-shell/completers/OptionCompleter.js index 922f2bad39..b9906a4a25 100644 --- a/src/phoenix/src/puter-shell/completers/OptionCompleter.js +++ b/src/phoenix/src/puter-shell/completers/OptionCompleter.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/__exports__.js b/src/phoenix/src/puter-shell/coreutils/__exports__.js index 7d35eb963e..6576a1c7c2 100644 --- a/src/phoenix/src/puter-shell/coreutils/__exports__.js +++ b/src/phoenix/src/puter-shell/coreutils/__exports__.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/ai.js b/src/phoenix/src/puter-shell/coreutils/ai.js index 23e2bbb223..c73ddf973c 100644 --- a/src/phoenix/src/puter-shell/coreutils/ai.js +++ b/src/phoenix/src/puter-shell/coreutils/ai.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/basename.js b/src/phoenix/src/puter-shell/coreutils/basename.js index f5e78602c0..e7ede73919 100644 --- a/src/phoenix/src/puter-shell/coreutils/basename.js +++ b/src/phoenix/src/puter-shell/coreutils/basename.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/cat.js b/src/phoenix/src/puter-shell/coreutils/cat.js index f1e2941f48..b555fdc1aa 100644 --- a/src/phoenix/src/puter-shell/coreutils/cat.js +++ b/src/phoenix/src/puter-shell/coreutils/cat.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/cd.js b/src/phoenix/src/puter-shell/coreutils/cd.js index 7352d39c61..0463290e4b 100644 --- a/src/phoenix/src/puter-shell/coreutils/cd.js +++ b/src/phoenix/src/puter-shell/coreutils/cd.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/changelog.js b/src/phoenix/src/puter-shell/coreutils/changelog.js index 027ec4c94c..0785df0dd2 100644 --- a/src/phoenix/src/puter-shell/coreutils/changelog.js +++ b/src/phoenix/src/puter-shell/coreutils/changelog.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/clear.js b/src/phoenix/src/puter-shell/coreutils/clear.js index 4e17963a86..e25a9184fa 100644 --- a/src/phoenix/src/puter-shell/coreutils/clear.js +++ b/src/phoenix/src/puter-shell/coreutils/clear.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/concept-parser.js b/src/phoenix/src/puter-shell/coreutils/concept-parser.js index b17ab65fc2..1ed2ebd39f 100644 --- a/src/phoenix/src/puter-shell/coreutils/concept-parser.js +++ b/src/phoenix/src/puter-shell/coreutils/concept-parser.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import { GrammarContext, standard_parsers } from '@heyputer/parsely/exports.js'; import { Parser, UNRECOGNIZED, VALUE } from '@heyputer/parsely/parser.js'; import { StringStream } from '@heyputer/parsely/streams.js'; diff --git a/src/phoenix/src/puter-shell/coreutils/coreutil_lib/echo_escapes.js b/src/phoenix/src/puter-shell/coreutils/coreutil_lib/echo_escapes.js index 8bcc0be1bd..d6c1339ce5 100644 --- a/src/phoenix/src/puter-shell/coreutils/coreutil_lib/echo_escapes.js +++ b/src/phoenix/src/puter-shell/coreutils/coreutil_lib/echo_escapes.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/coreutil_lib/exit.js b/src/phoenix/src/puter-shell/coreutils/coreutil_lib/exit.js index 1d7b419b7a..95efc7d1b9 100644 --- a/src/phoenix/src/puter-shell/coreutils/coreutil_lib/exit.js +++ b/src/phoenix/src/puter-shell/coreutils/coreutil_lib/exit.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/coreutil_lib/help.js b/src/phoenix/src/puter-shell/coreutils/coreutil_lib/help.js index fbf16f4ed8..02eb94d805 100644 --- a/src/phoenix/src/puter-shell/coreutils/coreutil_lib/help.js +++ b/src/phoenix/src/puter-shell/coreutils/coreutil_lib/help.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/coreutil_lib/validate.js b/src/phoenix/src/puter-shell/coreutils/coreutil_lib/validate.js index 807f748bc2..efbcf957a4 100644 --- a/src/phoenix/src/puter-shell/coreutils/coreutil_lib/validate.js +++ b/src/phoenix/src/puter-shell/coreutils/coreutil_lib/validate.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/cp.js b/src/phoenix/src/puter-shell/coreutils/cp.js index 032f7ecc5f..d0d173428f 100644 --- a/src/phoenix/src/puter-shell/coreutils/cp.js +++ b/src/phoenix/src/puter-shell/coreutils/cp.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/date.js b/src/phoenix/src/puter-shell/coreutils/date.js index fd3bcc685e..028dfbba90 100644 --- a/src/phoenix/src/puter-shell/coreutils/date.js +++ b/src/phoenix/src/puter-shell/coreutils/date.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/dcall.js b/src/phoenix/src/puter-shell/coreutils/dcall.js index d24d89f4c6..144a54640a 100644 --- a/src/phoenix/src/puter-shell/coreutils/dcall.js +++ b/src/phoenix/src/puter-shell/coreutils/dcall.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/dirname.js b/src/phoenix/src/puter-shell/coreutils/dirname.js index c0f52d5184..dbd595af38 100644 --- a/src/phoenix/src/puter-shell/coreutils/dirname.js +++ b/src/phoenix/src/puter-shell/coreutils/dirname.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/echo.js b/src/phoenix/src/puter-shell/coreutils/echo.js index d29509a58f..f5bda9cdca 100644 --- a/src/phoenix/src/puter-shell/coreutils/echo.js +++ b/src/phoenix/src/puter-shell/coreutils/echo.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/env.js b/src/phoenix/src/puter-shell/coreutils/env.js index 6f9eb4ab13..5cd6776bef 100644 --- a/src/phoenix/src/puter-shell/coreutils/env.js +++ b/src/phoenix/src/puter-shell/coreutils/env.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/errno.js b/src/phoenix/src/puter-shell/coreutils/errno.js index db74b2f685..34b509b398 100644 --- a/src/phoenix/src/puter-shell/coreutils/errno.js +++ b/src/phoenix/src/puter-shell/coreutils/errno.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/exit.js b/src/phoenix/src/puter-shell/coreutils/exit.js index a31649846e..b0fcd99876 100644 --- a/src/phoenix/src/puter-shell/coreutils/exit.js +++ b/src/phoenix/src/puter-shell/coreutils/exit.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/false.js b/src/phoenix/src/puter-shell/coreutils/false.js index d888e53a6a..5b31e632f9 100644 --- a/src/phoenix/src/puter-shell/coreutils/false.js +++ b/src/phoenix/src/puter-shell/coreutils/false.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/grep.js b/src/phoenix/src/puter-shell/coreutils/grep.js index eb18314446..718af4d114 100644 --- a/src/phoenix/src/puter-shell/coreutils/grep.js +++ b/src/phoenix/src/puter-shell/coreutils/grep.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/head.js b/src/phoenix/src/puter-shell/coreutils/head.js index e96d8570a3..ba6ecc55fb 100644 --- a/src/phoenix/src/puter-shell/coreutils/head.js +++ b/src/phoenix/src/puter-shell/coreutils/head.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/help.js b/src/phoenix/src/puter-shell/coreutils/help.js index 817074c0e7..5171cf735c 100644 --- a/src/phoenix/src/puter-shell/coreutils/help.js +++ b/src/phoenix/src/puter-shell/coreutils/help.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/jq.js b/src/phoenix/src/puter-shell/coreutils/jq.js index ab3a641d75..3f92f8f975 100644 --- a/src/phoenix/src/puter-shell/coreutils/jq.js +++ b/src/phoenix/src/puter-shell/coreutils/jq.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/login.js b/src/phoenix/src/puter-shell/coreutils/login.js index e5117cfa92..2ef56d43aa 100644 --- a/src/phoenix/src/puter-shell/coreutils/login.js +++ b/src/phoenix/src/puter-shell/coreutils/login.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/ls.js b/src/phoenix/src/puter-shell/coreutils/ls.js index c30d8fbe17..de6cbc8e7b 100644 --- a/src/phoenix/src/puter-shell/coreutils/ls.js +++ b/src/phoenix/src/puter-shell/coreutils/ls.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/man.js b/src/phoenix/src/puter-shell/coreutils/man.js index 2c16c1ded8..2af6ff1e0b 100644 --- a/src/phoenix/src/puter-shell/coreutils/man.js +++ b/src/phoenix/src/puter-shell/coreutils/man.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/mkdir.js b/src/phoenix/src/puter-shell/coreutils/mkdir.js index f14d32e6df..dd6deef5be 100644 --- a/src/phoenix/src/puter-shell/coreutils/mkdir.js +++ b/src/phoenix/src/puter-shell/coreutils/mkdir.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/mv.js b/src/phoenix/src/puter-shell/coreutils/mv.js index bf05b50e81..d32146d867 100644 --- a/src/phoenix/src/puter-shell/coreutils/mv.js +++ b/src/phoenix/src/puter-shell/coreutils/mv.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/neofetch.js b/src/phoenix/src/puter-shell/coreutils/neofetch.js index a7d447c555..27ceb11fdc 100644 --- a/src/phoenix/src/puter-shell/coreutils/neofetch.js +++ b/src/phoenix/src/puter-shell/coreutils/neofetch.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/printf.js b/src/phoenix/src/puter-shell/coreutils/printf.js index 0a99d87de1..51d0aa3df9 100644 --- a/src/phoenix/src/puter-shell/coreutils/printf.js +++ b/src/phoenix/src/puter-shell/coreutils/printf.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/printhist.js b/src/phoenix/src/puter-shell/coreutils/printhist.js index d740fcc64a..88efc09ff0 100644 --- a/src/phoenix/src/puter-shell/coreutils/printhist.js +++ b/src/phoenix/src/puter-shell/coreutils/printhist.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/pwd.js b/src/phoenix/src/puter-shell/coreutils/pwd.js index 1fd5907ff2..f6be908aa6 100644 --- a/src/phoenix/src/puter-shell/coreutils/pwd.js +++ b/src/phoenix/src/puter-shell/coreutils/pwd.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/rm.js b/src/phoenix/src/puter-shell/coreutils/rm.js index 358e41b59a..2e1e09f662 100644 --- a/src/phoenix/src/puter-shell/coreutils/rm.js +++ b/src/phoenix/src/puter-shell/coreutils/rm.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/rmdir.js b/src/phoenix/src/puter-shell/coreutils/rmdir.js index d03048f054..9efceb355f 100644 --- a/src/phoenix/src/puter-shell/coreutils/rmdir.js +++ b/src/phoenix/src/puter-shell/coreutils/rmdir.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/sample-data.js b/src/phoenix/src/puter-shell/coreutils/sample-data.js index 039b690076..ce3b05bf66 100644 --- a/src/phoenix/src/puter-shell/coreutils/sample-data.js +++ b/src/phoenix/src/puter-shell/coreutils/sample-data.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/sed.js b/src/phoenix/src/puter-shell/coreutils/sed.js index c9c10ede09..f4b4b5f3fd 100644 --- a/src/phoenix/src/puter-shell/coreutils/sed.js +++ b/src/phoenix/src/puter-shell/coreutils/sed.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/sed/address.js b/src/phoenix/src/puter-shell/coreutils/sed/address.js index 446466cca1..b90a0c0312 100644 --- a/src/phoenix/src/puter-shell/coreutils/sed/address.js +++ b/src/phoenix/src/puter-shell/coreutils/sed/address.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/sed/command.js b/src/phoenix/src/puter-shell/coreutils/sed/command.js index 56b8c84c30..037da01b1f 100644 --- a/src/phoenix/src/puter-shell/coreutils/sed/command.js +++ b/src/phoenix/src/puter-shell/coreutils/sed/command.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/sed/parser.js b/src/phoenix/src/puter-shell/coreutils/sed/parser.js index 3d74282236..28d0b41977 100644 --- a/src/phoenix/src/puter-shell/coreutils/sed/parser.js +++ b/src/phoenix/src/puter-shell/coreutils/sed/parser.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/sed/script.js b/src/phoenix/src/puter-shell/coreutils/sed/script.js index f77c89db68..e59a5c5ceb 100644 --- a/src/phoenix/src/puter-shell/coreutils/sed/script.js +++ b/src/phoenix/src/puter-shell/coreutils/sed/script.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/sed/utils.js b/src/phoenix/src/puter-shell/coreutils/sed/utils.js index 25da2a9c40..f3d59214f7 100644 --- a/src/phoenix/src/puter-shell/coreutils/sed/utils.js +++ b/src/phoenix/src/puter-shell/coreutils/sed/utils.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/sleep.js b/src/phoenix/src/puter-shell/coreutils/sleep.js index 9023053f39..b71b8f4313 100644 --- a/src/phoenix/src/puter-shell/coreutils/sleep.js +++ b/src/phoenix/src/puter-shell/coreutils/sleep.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/sort.js b/src/phoenix/src/puter-shell/coreutils/sort.js index 3f725a8221..4ec623a9d8 100644 --- a/src/phoenix/src/puter-shell/coreutils/sort.js +++ b/src/phoenix/src/puter-shell/coreutils/sort.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/tail.js b/src/phoenix/src/puter-shell/coreutils/tail.js index f93c5482d1..6a70bb590b 100644 --- a/src/phoenix/src/puter-shell/coreutils/tail.js +++ b/src/phoenix/src/puter-shell/coreutils/tail.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/test.js b/src/phoenix/src/puter-shell/coreutils/test.js index baf0e19b87..5c5bc2620d 100644 --- a/src/phoenix/src/puter-shell/coreutils/test.js +++ b/src/phoenix/src/puter-shell/coreutils/test.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/touch.js b/src/phoenix/src/puter-shell/coreutils/touch.js index 5b32067ad0..5757c2322f 100644 --- a/src/phoenix/src/puter-shell/coreutils/touch.js +++ b/src/phoenix/src/puter-shell/coreutils/touch.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/true.js b/src/phoenix/src/puter-shell/coreutils/true.js index fa2ddce95c..3169545201 100644 --- a/src/phoenix/src/puter-shell/coreutils/true.js +++ b/src/phoenix/src/puter-shell/coreutils/true.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/txt2img.js b/src/phoenix/src/puter-shell/coreutils/txt2img.js index bc432d241c..c4586540bf 100644 --- a/src/phoenix/src/puter-shell/coreutils/txt2img.js +++ b/src/phoenix/src/puter-shell/coreutils/txt2img.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/usages.js b/src/phoenix/src/puter-shell/coreutils/usages.js index a04c39e949..a97ec31f09 100644 --- a/src/phoenix/src/puter-shell/coreutils/usages.js +++ b/src/phoenix/src/puter-shell/coreutils/usages.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/wc.js b/src/phoenix/src/puter-shell/coreutils/wc.js index 1924a4d3f1..f3914467ba 100644 --- a/src/phoenix/src/puter-shell/coreutils/wc.js +++ b/src/phoenix/src/puter-shell/coreutils/wc.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/coreutils/which.js b/src/phoenix/src/puter-shell/coreutils/which.js index 6871acdce2..8fb3ab7810 100644 --- a/src/phoenix/src/puter-shell/coreutils/which.js +++ b/src/phoenix/src/puter-shell/coreutils/which.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/main.js b/src/phoenix/src/puter-shell/main.js index a962a27fc6..98b9dcd28e 100644 --- a/src/phoenix/src/puter-shell/main.js +++ b/src/phoenix/src/puter-shell/main.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/plugins/ChatHistoryPlugin.js b/src/phoenix/src/puter-shell/plugins/ChatHistoryPlugin.js index 8d9df329f3..103c15a897 100644 --- a/src/phoenix/src/puter-shell/plugins/ChatHistoryPlugin.js +++ b/src/phoenix/src/puter-shell/plugins/ChatHistoryPlugin.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/providers/BuiltinCommandProvider.js b/src/phoenix/src/puter-shell/providers/BuiltinCommandProvider.js index fc766dc620..680afa5f35 100644 --- a/src/phoenix/src/puter-shell/providers/BuiltinCommandProvider.js +++ b/src/phoenix/src/puter-shell/providers/BuiltinCommandProvider.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/providers/CompositeCommandProvider.js b/src/phoenix/src/puter-shell/providers/CompositeCommandProvider.js index ceffeed576..91300e7f66 100644 --- a/src/phoenix/src/puter-shell/providers/CompositeCommandProvider.js +++ b/src/phoenix/src/puter-shell/providers/CompositeCommandProvider.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/providers/PathCommandProvider.js b/src/phoenix/src/puter-shell/providers/PathCommandProvider.js index 6b55a04478..6ce2d435ae 100644 --- a/src/phoenix/src/puter-shell/providers/PathCommandProvider.js +++ b/src/phoenix/src/puter-shell/providers/PathCommandProvider.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js b/src/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js index 0de34ed2ac..13540b1509 100644 --- a/src/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js +++ b/src/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/puter-shell/providers/ScriptCommandProvider.js b/src/phoenix/src/puter-shell/providers/ScriptCommandProvider.js index f2b1edbfec..e080fa6af5 100644 --- a/src/phoenix/src/puter-shell/providers/ScriptCommandProvider.js +++ b/src/phoenix/src/puter-shell/providers/ScriptCommandProvider.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/util/bytes.js b/src/phoenix/src/util/bytes.js index cee745c959..9c785ba501 100644 --- a/src/phoenix/src/util/bytes.js +++ b/src/phoenix/src/util/bytes.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/util/file.js b/src/phoenix/src/util/file.js index a29045f286..4e1ff670a0 100644 --- a/src/phoenix/src/util/file.js +++ b/src/phoenix/src/util/file.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import { resolveRelativePath } from './path.js'; // Iterate the given file, one line at a time. diff --git a/src/phoenix/src/util/lang.js b/src/phoenix/src/util/lang.js index dea8aa0663..510f728e88 100644 --- a/src/phoenix/src/util/lang.js +++ b/src/phoenix/src/util/lang.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/util/log.js b/src/phoenix/src/util/log.js index f68f772a6a..aa55747b48 100644 --- a/src/phoenix/src/util/log.js +++ b/src/phoenix/src/util/log.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/util/path.js b/src/phoenix/src/util/path.js index bd418be06b..817de1b9fb 100644 --- a/src/phoenix/src/util/path.js +++ b/src/phoenix/src/util/path.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/util/singleton.js b/src/phoenix/src/util/singleton.js index 4bcbf85da7..6e7c2b94a5 100644 --- a/src/phoenix/src/util/singleton.js +++ b/src/phoenix/src/util/singleton.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/util/statemachine.js b/src/phoenix/src/util/statemachine.js index ca4a77ee36..459a6d0d02 100644 --- a/src/phoenix/src/util/statemachine.js +++ b/src/phoenix/src/util/statemachine.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/src/util/wrap-text.js b/src/phoenix/src/util/wrap-text.js index 86adfe840a..58c97a1fa1 100644 --- a/src/phoenix/src/util/wrap-text.js +++ b/src/phoenix/src/util/wrap-text.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/test.js b/src/phoenix/test.js index 2414e28776..dbf89ac923 100644 --- a/src/phoenix/test.js +++ b/src/phoenix/test.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/test/coreutils.test.js b/src/phoenix/test/coreutils.test.js index 004b7677c5..511ff609f3 100644 --- a/src/phoenix/test/coreutils.test.js +++ b/src/phoenix/test/coreutils.test.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/test/coreutils/basename.js b/src/phoenix/test/coreutils/basename.js index 888e1299f0..39f56a71e1 100644 --- a/src/phoenix/test/coreutils/basename.js +++ b/src/phoenix/test/coreutils/basename.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/test/coreutils/date.js b/src/phoenix/test/coreutils/date.js index efc800ea3d..c38e8af577 100644 --- a/src/phoenix/test/coreutils/date.js +++ b/src/phoenix/test/coreutils/date.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/test/coreutils/dirname.js b/src/phoenix/test/coreutils/dirname.js index a263b9d7ee..9cb8a457b7 100644 --- a/src/phoenix/test/coreutils/dirname.js +++ b/src/phoenix/test/coreutils/dirname.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/test/coreutils/echo.js b/src/phoenix/test/coreutils/echo.js index 099f762cfa..3bb7134bbf 100644 --- a/src/phoenix/test/coreutils/echo.js +++ b/src/phoenix/test/coreutils/echo.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/test/coreutils/env.js b/src/phoenix/test/coreutils/env.js index 5cb30a54ae..26855b931d 100644 --- a/src/phoenix/test/coreutils/env.js +++ b/src/phoenix/test/coreutils/env.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/test/coreutils/errno.js b/src/phoenix/test/coreutils/errno.js index 0191125bac..c09bf9d541 100644 --- a/src/phoenix/test/coreutils/errno.js +++ b/src/phoenix/test/coreutils/errno.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/test/coreutils/false.js b/src/phoenix/test/coreutils/false.js index bb88d31e8f..ef5ad3ff26 100644 --- a/src/phoenix/test/coreutils/false.js +++ b/src/phoenix/test/coreutils/false.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/test/coreutils/harness.js b/src/phoenix/test/coreutils/harness.js index 08ea91c266..344a8ebbd1 100644 --- a/src/phoenix/test/coreutils/harness.js +++ b/src/phoenix/test/coreutils/harness.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/test/coreutils/head.js b/src/phoenix/test/coreutils/head.js index fb34034fde..0c6de2769e 100644 --- a/src/phoenix/test/coreutils/head.js +++ b/src/phoenix/test/coreutils/head.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/test/coreutils/printf.js b/src/phoenix/test/coreutils/printf.js index 04c6c6a99b..60b79de030 100644 --- a/src/phoenix/test/coreutils/printf.js +++ b/src/phoenix/test/coreutils/printf.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/test/coreutils/sleep.js b/src/phoenix/test/coreutils/sleep.js index 039dbd8c90..cea93e44c8 100644 --- a/src/phoenix/test/coreutils/sleep.js +++ b/src/phoenix/test/coreutils/sleep.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/test/coreutils/sort.js b/src/phoenix/test/coreutils/sort.js index 983029355d..5f336e4c0d 100644 --- a/src/phoenix/test/coreutils/sort.js +++ b/src/phoenix/test/coreutils/sort.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/test/coreutils/tail.js b/src/phoenix/test/coreutils/tail.js index 93cd28f0ed..4f5f1dc4c6 100644 --- a/src/phoenix/test/coreutils/tail.js +++ b/src/phoenix/test/coreutils/tail.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/test/coreutils/true.js b/src/phoenix/test/coreutils/true.js index 7ef5dfe867..2e16062bb8 100644 --- a/src/phoenix/test/coreutils/true.js +++ b/src/phoenix/test/coreutils/true.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/test/coreutils/wc.js b/src/phoenix/test/coreutils/wc.js index 16fa45bb45..285f03db16 100644 --- a/src/phoenix/test/coreutils/wc.js +++ b/src/phoenix/test/coreutils/wc.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/test/readtoken.js b/src/phoenix/test/readtoken.js index 549e358969..836b969435 100644 --- a/src/phoenix/test/readtoken.js +++ b/src/phoenix/test/readtoken.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/test/test-bytes.js b/src/phoenix/test/test-bytes.js index ba58376219..5ef27bab44 100644 --- a/src/phoenix/test/test-bytes.js +++ b/src/phoenix/test/test-bytes.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/test/test-stateful-processor.js b/src/phoenix/test/test-stateful-processor.js index 8e6ecd5a51..5264ede115 100644 --- a/src/phoenix/test/test-stateful-processor.js +++ b/src/phoenix/test/test-stateful-processor.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/test/wrap-text.js b/src/phoenix/test/wrap-text.js index 3ee7a7bd8e..5d6ba3a5c9 100644 --- a/src/phoenix/test/wrap-text.js +++ b/src/phoenix/test/wrap-text.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/phoenix/tools/gen.js b/src/phoenix/tools/gen.js index 031d6932f7..713b2c1c05 100644 --- a/src/phoenix/tools/gen.js +++ b/src/phoenix/tools/gen.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/pty/exports.js b/src/pty/exports.js index 1e36b76853..6dd6cad435 100644 --- a/src/pty/exports.js +++ b/src/pty/exports.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/puter-js-common/index.js b/src/puter-js-common/index.js index 384cdc8f2c..ce7be26ae1 100644 --- a/src/puter-js-common/index.js +++ b/src/puter-js-common/index.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { AdvancedBase } = require('./src/AdvancedBase'); module.exports = { diff --git a/src/puter-js-common/src/AdvancedBase.js b/src/puter-js-common/src/AdvancedBase.js index e0ca8ab454..069e474aff 100644 --- a/src/puter-js-common/src/AdvancedBase.js +++ b/src/puter-js-common/src/AdvancedBase.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ // This doesn't go in ./bases because it logically depends on // both ./bases and ./traits, and ./traits depends on ./bases. diff --git a/src/puter-js-common/src/PosixError.js b/src/puter-js-common/src/PosixError.js index 06159998d2..6d177f600e 100644 --- a/src/puter-js-common/src/PosixError.js +++ b/src/puter-js-common/src/PosixError.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/puter-js-common/src/bases/BasicBase.js b/src/puter-js-common/src/bases/BasicBase.js index a01a0f00d2..78d121f980 100644 --- a/src/puter-js-common/src/bases/BasicBase.js +++ b/src/puter-js-common/src/bases/BasicBase.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ class BasicBase { _get_inheritance_chain () { const chain = []; diff --git a/src/puter-js-common/src/bases/TraitBase.js b/src/puter-js-common/src/bases/TraitBase.js index 3cec906ab0..62d3cc1e9f 100644 --- a/src/puter-js-common/src/bases/TraitBase.js +++ b/src/puter-js-common/src/bases/TraitBase.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { BasicBase } = require("./BasicBase"); class TraitBase extends BasicBase { diff --git a/src/puter-js-common/src/traits/NodeModuleDITrait.js b/src/puter-js-common/src/traits/NodeModuleDITrait.js index 1e011de641..d7952704c0 100644 --- a/src/puter-js-common/src/traits/NodeModuleDITrait.js +++ b/src/puter-js-common/src/traits/NodeModuleDITrait.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * This trait allows dependency injection of node modules. * This is incredibly useful for passing mock implementations diff --git a/src/puter-js-common/src/traits/PropertiesTrait.js b/src/puter-js-common/src/traits/PropertiesTrait.js index 7e35a9f3f5..9e2c4b72ba 100644 --- a/src/puter-js-common/src/traits/PropertiesTrait.js +++ b/src/puter-js-common/src/traits/PropertiesTrait.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ module.exports = { install_in_instance: (instance) => { const properties = instance._get_merged_static_object('PROPERTIES'); diff --git a/src/puter-js-common/test/test.js b/src/puter-js-common/test/test.js index ef08e5b462..34a36f4d7e 100644 --- a/src/puter-js-common/test/test.js +++ b/src/puter-js-common/test/test.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const { expect } = require('chai'); const { BasicBase } = require('../src/bases/BasicBase'); const { AdvancedBase } = require('../src/AdvancedBase'); diff --git a/src/puter-js/src/index.js b/src/puter-js/src/index.js index 425fb06a02..0ccb016e4b 100644 --- a/src/puter-js/src/index.js +++ b/src/puter-js/src/index.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import OS from './modules/OS.js'; import FileSystem from './modules/FileSystem/index.js'; import Hosting from './modules/Hosting.js'; diff --git a/src/puter-js/src/modules/AI.js b/src/puter-js/src/modules/AI.js index edf9abb4a3..9a8b47c4ef 100644 --- a/src/puter-js/src/modules/AI.js +++ b/src/puter-js/src/modules/AI.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import * as utils from '../lib/utils.js' class AI{ diff --git a/src/puter-js/src/modules/Apps.js b/src/puter-js/src/modules/Apps.js index 4307e29b53..0ab7145751 100644 --- a/src/puter-js/src/modules/Apps.js +++ b/src/puter-js/src/modules/Apps.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import * as utils from '../lib/utils.js' class Apps{ diff --git a/src/puter-js/src/modules/Auth.js b/src/puter-js/src/modules/Auth.js index 7c877bbe2c..9858c15cd5 100644 --- a/src/puter-js/src/modules/Auth.js +++ b/src/puter-js/src/modules/Auth.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import * as utils from '../lib/utils.js' class Auth{ diff --git a/src/puter-js/src/modules/Email.js b/src/puter-js/src/modules/Email.js index 4f754d3351..c134051652 100644 --- a/src/puter-js/src/modules/Email.js +++ b/src/puter-js/src/modules/Email.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import * as utils from '../lib/utils.js' class Email{ diff --git a/src/puter-js/src/modules/FSItem.js b/src/puter-js/src/modules/FSItem.js index 0df2ec5f3c..52ac52b6a1 100644 --- a/src/puter-js/src/modules/FSItem.js +++ b/src/puter-js/src/modules/FSItem.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import path from "../lib/path.js" class FSItem{ diff --git a/src/puter-js/src/modules/FileSystem/index.js b/src/puter-js/src/modules/FileSystem/index.js index 0e6b2679d2..e3de175070 100644 --- a/src/puter-js/src/modules/FileSystem/index.js +++ b/src/puter-js/src/modules/FileSystem/index.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import io from '../../lib/socket.io/socket.io.esm.min.js'; // Operations diff --git a/src/puter-js/src/modules/FileSystem/operations/copy.js b/src/puter-js/src/modules/FileSystem/operations/copy.js index 4e33162a0c..30b32a8aab 100644 --- a/src/puter-js/src/modules/FileSystem/operations/copy.js +++ b/src/puter-js/src/modules/FileSystem/operations/copy.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import * as utils from '../../../lib/utils.js'; import getAbsolutePathForApp from '../utils/getAbsolutePathForApp.js'; diff --git a/src/puter-js/src/modules/FileSystem/operations/deleteFSEntry.js b/src/puter-js/src/modules/FileSystem/operations/deleteFSEntry.js index 0b8644b65a..616e202fa9 100644 --- a/src/puter-js/src/modules/FileSystem/operations/deleteFSEntry.js +++ b/src/puter-js/src/modules/FileSystem/operations/deleteFSEntry.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import * as utils from '../../../lib/utils.js'; import getAbsolutePathForApp from '../utils/getAbsolutePathForApp.js'; diff --git a/src/puter-js/src/modules/FileSystem/operations/mkdir.js b/src/puter-js/src/modules/FileSystem/operations/mkdir.js index c256ab6547..d48474b725 100644 --- a/src/puter-js/src/modules/FileSystem/operations/mkdir.js +++ b/src/puter-js/src/modules/FileSystem/operations/mkdir.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import * as utils from '../../../lib/utils.js'; import getAbsolutePathForApp from '../utils/getAbsolutePathForApp.js'; import path from "../../../lib/path.js" diff --git a/src/puter-js/src/modules/FileSystem/operations/move.js b/src/puter-js/src/modules/FileSystem/operations/move.js index eb87c245b8..ca338cd1ac 100644 --- a/src/puter-js/src/modules/FileSystem/operations/move.js +++ b/src/puter-js/src/modules/FileSystem/operations/move.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import * as utils from '../../../lib/utils.js'; import getAbsolutePathForApp from '../utils/getAbsolutePathForApp.js'; diff --git a/src/puter-js/src/modules/FileSystem/operations/read.js b/src/puter-js/src/modules/FileSystem/operations/read.js index 971bc59d83..0d35b868f2 100644 --- a/src/puter-js/src/modules/FileSystem/operations/read.js +++ b/src/puter-js/src/modules/FileSystem/operations/read.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import * as utils from '../../../lib/utils.js'; import getAbsolutePathForApp from '../utils/getAbsolutePathForApp.js'; diff --git a/src/puter-js/src/modules/FileSystem/operations/readdir.js b/src/puter-js/src/modules/FileSystem/operations/readdir.js index fe2f2e1456..1bbbe001fd 100644 --- a/src/puter-js/src/modules/FileSystem/operations/readdir.js +++ b/src/puter-js/src/modules/FileSystem/operations/readdir.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import * as utils from '../../../lib/utils.js'; import getAbsolutePathForApp from '../utils/getAbsolutePathForApp.js'; diff --git a/src/puter-js/src/modules/FileSystem/operations/rename.js b/src/puter-js/src/modules/FileSystem/operations/rename.js index c670e482aa..0c8e1ad2e5 100644 --- a/src/puter-js/src/modules/FileSystem/operations/rename.js +++ b/src/puter-js/src/modules/FileSystem/operations/rename.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import * as utils from '../../../lib/utils.js'; import getAbsolutePathForApp from '../utils/getAbsolutePathForApp.js'; diff --git a/src/puter-js/src/modules/FileSystem/operations/sign.js b/src/puter-js/src/modules/FileSystem/operations/sign.js index c2d5efb503..20fe871372 100644 --- a/src/puter-js/src/modules/FileSystem/operations/sign.js +++ b/src/puter-js/src/modules/FileSystem/operations/sign.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import * as utils from '../../../lib/utils.js'; diff --git a/src/puter-js/src/modules/FileSystem/operations/space.js b/src/puter-js/src/modules/FileSystem/operations/space.js index 9c2e787fae..6592936d05 100644 --- a/src/puter-js/src/modules/FileSystem/operations/space.js +++ b/src/puter-js/src/modules/FileSystem/operations/space.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import * as utils from '../../../lib/utils.js'; const space = function (...args) { diff --git a/src/puter-js/src/modules/FileSystem/operations/stat.js b/src/puter-js/src/modules/FileSystem/operations/stat.js index 28f9d64981..856f51eb54 100644 --- a/src/puter-js/src/modules/FileSystem/operations/stat.js +++ b/src/puter-js/src/modules/FileSystem/operations/stat.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import * as utils from '../../../lib/utils.js'; import getAbsolutePathForApp from '../utils/getAbsolutePathForApp.js'; diff --git a/src/puter-js/src/modules/FileSystem/operations/upload.js b/src/puter-js/src/modules/FileSystem/operations/upload.js index ab8778ea9b..3744d19076 100644 --- a/src/puter-js/src/modules/FileSystem/operations/upload.js +++ b/src/puter-js/src/modules/FileSystem/operations/upload.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import * as utils from '../../../lib/utils.js'; import getAbsolutePathForApp from '../utils/getAbsolutePathForApp.js'; import path from "../../../lib/path.js" diff --git a/src/puter-js/src/modules/FileSystem/operations/write.js b/src/puter-js/src/modules/FileSystem/operations/write.js index c1319ad4b6..dd16047844 100644 --- a/src/puter-js/src/modules/FileSystem/operations/write.js +++ b/src/puter-js/src/modules/FileSystem/operations/write.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import path from "../../../lib/path.js" import getAbsolutePathForApp from '../utils/getAbsolutePathForApp.js'; diff --git a/src/puter-js/src/modules/FileSystem/utils/getAbsolutePathForApp.js b/src/puter-js/src/modules/FileSystem/utils/getAbsolutePathForApp.js index 186b94dcfd..48a6669511 100644 --- a/src/puter-js/src/modules/FileSystem/utils/getAbsolutePathForApp.js +++ b/src/puter-js/src/modules/FileSystem/utils/getAbsolutePathForApp.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import path from "../../../lib/path.js" const getAbsolutePathForApp = (relativePath)=>{ diff --git a/src/puter-js/src/modules/Hosting.js b/src/puter-js/src/modules/Hosting.js index fa2234164d..bca46b3d7c 100644 --- a/src/puter-js/src/modules/Hosting.js +++ b/src/puter-js/src/modules/Hosting.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import * as utils from '../lib/utils.js'; import getAbsolutePathForApp from './FileSystem/utils/getAbsolutePathForApp.js'; diff --git a/src/puter-js/src/modules/KV.js b/src/puter-js/src/modules/KV.js index c040560658..0341d17939 100644 --- a/src/puter-js/src/modules/KV.js +++ b/src/puter-js/src/modules/KV.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import * as utils from '../lib/utils.js' class KV{ diff --git a/src/puter-js/src/modules/OS.js b/src/puter-js/src/modules/OS.js index a436e58a3b..cf2f43d4ed 100644 --- a/src/puter-js/src/modules/OS.js +++ b/src/puter-js/src/modules/OS.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import * as utils from '../lib/utils.js' class OS{ diff --git a/src/puter-js/src/modules/PuterDialog.js b/src/puter-js/src/modules/PuterDialog.js index 8be194176c..1d77c076a6 100644 --- a/src/puter-js/src/modules/PuterDialog.js +++ b/src/puter-js/src/modules/PuterDialog.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ class PuterDialog extends HTMLElement { constructor(resolve, reject) { super(); diff --git a/src/puter-js/src/modules/UI.js b/src/puter-js/src/modules/UI.js index 8a3fe496aa..221cb9ae64 100644 --- a/src/puter-js/src/modules/UI.js +++ b/src/puter-js/src/modules/UI.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import FSItem from './FSItem.js'; import PuterDialog from './PuterDialog.js'; import EventListener from '../lib/EventListener.js'; diff --git a/src/puter-js/src/modules/Util.js b/src/puter-js/src/modules/Util.js index 16dbe14771..2d8fc119e6 100644 --- a/src/puter-js/src/modules/Util.js +++ b/src/puter-js/src/modules/Util.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import { CallbackManager, Dehydrator, Hydrator } from "../lib/xdrpc"; /** diff --git a/src/puter-js/test/fs.test.js b/src/puter-js/test/fs.test.js index c194ef3818..dcbd071596 100644 --- a/src/puter-js/test/fs.test.js +++ b/src/puter-js/test/fs.test.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* eslint-disable */ // TODO: Make these more compatible with eslint naughtyStrings = [ diff --git a/src/puter-js/test/kv.test.js b/src/puter-js/test/kv.test.js index 16de6ab37e..0a91ab2b89 100644 --- a/src/puter-js/test/kv.test.js +++ b/src/puter-js/test/kv.test.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* eslint-disable */ // TODO: Make these more compatible with eslint window.kvTests = [ diff --git a/src/strataparse/dsl/ParserBuilder.js b/src/strataparse/dsl/ParserBuilder.js index 0936f9730e..1a218b28f9 100644 --- a/src/strataparse/dsl/ParserBuilder.js +++ b/src/strataparse/dsl/ParserBuilder.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/strataparse/dsl/ParserRegistry.js b/src/strataparse/dsl/ParserRegistry.js index 87e5f7b4c8..9ef5104e0d 100644 --- a/src/strataparse/dsl/ParserRegistry.js +++ b/src/strataparse/dsl/ParserRegistry.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/strataparse/exports.js b/src/strataparse/exports.js index 928f29021e..daa579d29f 100644 --- a/src/strataparse/exports.js +++ b/src/strataparse/exports.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/strataparse/parse.js b/src/strataparse/parse.js index 14663335c9..fd5e675f48 100644 --- a/src/strataparse/parse.js +++ b/src/strataparse/parse.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/strataparse/parse_impls/StrUntilParserImpl.js b/src/strataparse/parse_impls/StrUntilParserImpl.js index 9f627faf11..a80e4baa3c 100644 --- a/src/strataparse/parse_impls/StrUntilParserImpl.js +++ b/src/strataparse/parse_impls/StrUntilParserImpl.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/strataparse/parse_impls/combinators.js b/src/strataparse/parse_impls/combinators.js index 6d6b569773..2f68a8c3b7 100644 --- a/src/strataparse/parse_impls/combinators.js +++ b/src/strataparse/parse_impls/combinators.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/strataparse/parse_impls/literal.js b/src/strataparse/parse_impls/literal.js index 4b6319cf2e..b5af905e6c 100644 --- a/src/strataparse/parse_impls/literal.js +++ b/src/strataparse/parse_impls/literal.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/strataparse/parse_impls/whitespace.js b/src/strataparse/parse_impls/whitespace.js index 82bcb1cb9f..baba772ca6 100644 --- a/src/strataparse/parse_impls/whitespace.js +++ b/src/strataparse/parse_impls/whitespace.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/strataparse/strata.js b/src/strataparse/strata.js index 73dc7055d5..e3faafa863 100644 --- a/src/strataparse/strata.js +++ b/src/strataparse/strata.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/strataparse/strata_impls/ContextSwitchingPStratumImpl.js b/src/strataparse/strata_impls/ContextSwitchingPStratumImpl.js index de8190728f..a3014ad888 100644 --- a/src/strataparse/strata_impls/ContextSwitchingPStratumImpl.js +++ b/src/strataparse/strata_impls/ContextSwitchingPStratumImpl.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/strataparse/strata_impls/FirstRecognizedPStratumImpl.js b/src/strataparse/strata_impls/FirstRecognizedPStratumImpl.js index cc3c645cbb..2455d3f866 100644 --- a/src/strataparse/strata_impls/FirstRecognizedPStratumImpl.js +++ b/src/strataparse/strata_impls/FirstRecognizedPStratumImpl.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/strataparse/strata_impls/MergeWhitespacePStratumImpl.js b/src/strataparse/strata_impls/MergeWhitespacePStratumImpl.js index f699557b83..f5b7d9273a 100644 --- a/src/strataparse/strata_impls/MergeWhitespacePStratumImpl.js +++ b/src/strataparse/strata_impls/MergeWhitespacePStratumImpl.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/strataparse/strata_impls/terminals.js b/src/strataparse/strata_impls/terminals.js index eb3445c68a..405a3e0363 100644 --- a/src/strataparse/strata_impls/terminals.js +++ b/src/strataparse/strata_impls/terminals.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/terminal/config/dev.js b/src/terminal/config/dev.js index 129f905574..f3a709c697 100644 --- a/src/terminal/config/dev.js +++ b/src/terminal/config/dev.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/terminal/config/release.js b/src/terminal/config/release.js index a919ca1fd2..dad116d296 100644 --- a/src/terminal/config/release.js +++ b/src/terminal/config/release.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/terminal/rollup.config.js b/src/terminal/rollup.config.js index 7c0920b6df..ae756766b1 100644 --- a/src/terminal/rollup.config.js +++ b/src/terminal/rollup.config.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/terminal/src/main.js b/src/terminal/src/main.js index d27f557fc8..f1254e704a 100644 --- a/src/terminal/src/main.js +++ b/src/terminal/src/main.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/terminal/src/pty/PTT.js b/src/terminal/src/pty/PTT.js index c39d083966..a3d75a0775 100644 --- a/src/terminal/src/pty/PTT.js +++ b/src/terminal/src/pty/PTT.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/terminal/src/pty/PTY.js b/src/terminal/src/pty/PTY.js index 476e4d6e8f..a053e84140 100644 --- a/src/terminal/src/pty/PTY.js +++ b/src/terminal/src/pty/PTY.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/terminal/src/pty/XDocumentANSIShell.js b/src/terminal/src/pty/XDocumentANSIShell.js index 8863834115..880b7d0659 100644 --- a/src/terminal/src/pty/XDocumentANSIShell.js +++ b/src/terminal/src/pty/XDocumentANSIShell.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /* * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/useapi/main.js b/src/useapi/main.js index 9a6c1e1383..c45fb9e1f6 100644 --- a/src/useapi/main.js +++ b/src/useapi/main.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const globalwith = (vars, fn) => { const original_values = {}; const keys = Object.keys(vars); diff --git a/tools/check-translations.js b/tools/check-translations.js index eaf7e98a5b..d593277082 100644 --- a/tools/check-translations.js +++ b/tools/check-translations.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/tools/file-walker/test.js b/tools/file-walker/test.js index 515ad1b3a3..784e7e282f 100644 --- a/tools/file-walker/test.js +++ b/tools/file-walker/test.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ const fs = require('fs'); const fsp = fs.promises; const path_ = require('path'); diff --git a/tools/gen-release-notes.js b/tools/gen-release-notes.js index 49987cd19f..ed82b94baa 100644 --- a/tools/gen-release-notes.js +++ b/tools/gen-release-notes.js @@ -1,3 +1,21 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ import { simpleGit } from 'simple-git'; const REPO_URL = 'https://github.com/HeyPuter/puter'; From 3a7221dba5825078dd35ad7f9fd623046a296afd Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 9 Jul 2024 04:18:55 -0400 Subject: [PATCH 0480/2119] chore: cleanup root directory --- package.json | 2 +- src/gui/dev-server.js | 77 +++++++++++++++++++ .../l_checker_config.json | 0 run-selfhosted.js => tools/run-selfhosted.js | 0 4 files changed, 78 insertions(+), 1 deletion(-) create mode 100644 src/gui/dev-server.js rename l_checker_config.json => tools/l_checker_config.json (100%) rename run-selfhosted.js => tools/run-selfhosted.js (100%) diff --git a/package.json b/package.json index 181da4a9e2..4bca22575a 100644 --- a/package.json +++ b/package.json @@ -28,7 +28,7 @@ "scripts": { "test": "mocha ./src/phoenix/test ./src/phoenix/packages/contextlink/test", "start=gui": "nodemon --exec \"node dev-server.js\" ", - "start": "node run-selfhosted.js", + "start": "node ./tools/run-selfhosted.js", "build": "cd src/gui; node ./build.js", "check-translations": "node tools/check-translations.js" }, diff --git a/src/gui/dev-server.js b/src/gui/dev-server.js new file mode 100644 index 0000000000..d506eff7ba --- /dev/null +++ b/src/gui/dev-server.js @@ -0,0 +1,77 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ +import express from "express"; +import { generateDevHtml, build } from "./utils.js"; +import { argv } from 'node:process'; +import chalk from 'chalk'; +import dotenv from 'dotenv'; +import path_ from 'path'; +dotenv.config(); + +const app = express(); +let port = process.env.PORT ?? 4000; // Starting port +const maxAttempts = 10; // Maximum number of ports to try +const env = argv[2] ?? "dev"; + +const startServer = (attempt, useAnyFreePort = false) => { + if (attempt > maxAttempts) { + useAnyFreePort = true; // Use any port that is free + } + + const server = app.listen(useAnyFreePort ? 0 : port, () => { + console.log("\n-----------------------------------------------------------\n"); + console.log(`Puter is now live at: `, chalk.underline.blue(`http://localhost:${server.address().port}`)); + console.log("\n-----------------------------------------------------------\n"); + }).on('error', (err) => { + if (err.code === 'EADDRINUSE') { // Check if the error is because the port is already in use + console.error(chalk.red(`ERROR: Port ${port} is already in use. Trying next port...`)); + port++; // Increment the port number + startServer(attempt + 1); // Try the next port + } + }); +}; + +// Start the server with the first attempt +startServer(1); + +// build the GUI +build(); + +app.get(["/", "/app/*", "/action/*"], (req, res) => { + res.send(generateDevHtml({ + env: env, + api_origin: "https://api.puter.com", + title: "Puter", + max_item_name_length: 150, + require_email_verification_to_publish_website: false, + short_description: `Puter is a privacy-first personal cloud that houses all your files, apps, and games in one private and secure place, accessible from anywhere at any time.`, + })); +}) +app.use(express.static('./')); + +if(env === "prod"){ + // make sure to serve the ./dist/ folder maps to the root of the website + app.use(express.static('./src/gui/dist/')); +} + +if(env === "dev"){ + app.use(express.static('./src/gui/src/')); +} + +export { app }; diff --git a/l_checker_config.json b/tools/l_checker_config.json similarity index 100% rename from l_checker_config.json rename to tools/l_checker_config.json diff --git a/run-selfhosted.js b/tools/run-selfhosted.js similarity index 100% rename from run-selfhosted.js rename to tools/run-selfhosted.js From 78a0acea6980b6d491da4874edbd98e17c0d9577 Mon Sep 17 00:00:00 2001 From: stronkexe Date: Tue, 9 Jul 2024 09:35:07 +0100 Subject: [PATCH 0481/2119] Completing Arabic translation based on English file --- src/gui/src/i18n/translations/ar.js | 363 +++++++++++++++++++++------- 1 file changed, 273 insertions(+), 90 deletions(-) diff --git a/src/gui/src/i18n/translations/ar.js b/src/gui/src/i18n/translations/ar.js index c429fd4858..97b622c241 100644 --- a/src/gui/src/i18n/translations/ar.js +++ b/src/gui/src/i18n/translations/ar.js @@ -16,153 +16,336 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const ar = { name: "العربية", english_name: "Arabic", code: "ar", dictionary: { + about: "حول", + account: "حساب", + account_password: "التحقق من كلمة مرور الحساب", access_granted_to: "دخول مسموح به", add_existing_account: "إضافة حساب موجود", - all_fields_required: 'يجب ملء كل الفراغات', - apply: "تطبيق ", - ascending: 'تصاعدي ', + all_fields_required: "يجب ملء كل الفراغات", + allow: "سماح", + apply: "تطبيق", + ascending: "تصاعدي", + associated_websites: "المواقع المرتبطة", + auto_arrange: "ترتيب تلقائي", background: "خلفية", browse: "إبحث", - cancel: 'إلغاء', - center: 'وسط', - change_desktop_background: 'تغيير خلفية المكتب', + cancel: "إلغاء", + center: "وسط", + change_desktop_background: "تغيير خلفية المكتب", + change_email: "تغيير البريد الإلكتروني", change_language: "تغيير اللغة", change_password: "تغيير كلمة السر", + change_ui_colors: "تغيير ألوان واجهة المستخدم", change_username: "تغيير إسم المستخدم", + close: "غلق", close_all_windows: "غلق كل النوافذ", - color: 'اللون', - confirm_account_for_free_referral_storage_c2a: 'تأكيد الحساب لتخزين الإحالة المجانية ', + close_all_windows_confirm: "هل أنت متأكد أنك تريد إغلاق كافة النوافذ؟", + close_all_windows_and_log_out: "أغلق جميع النوافذ وقم بتسجيل الخروج", + change_always_open_with: "هل تريد دائمًا فتح هذا النوع من الملفات باستخدام", + color: "اللون", + confirm: "تأكيد", + confirm_2fa_setup: "لقد أضفت الرمز إلى تطبيق المصادقة الخاص بي", + confirm_2fa_recovery: "لقد قمت بحفظ رموز الاسترداد الخاصة بي في مكان آمن", + confirm_account_for_free_referral_storage_c2a: "تأكيد الحساب لتخزين الإحالة المجانية", + confirm_code_generic_incorrect: "رمز غير صحيح", + confirm_code_generic_too_many_requests: "طلبات كثيرة جدا. يرجى الانتظار بضع دقائق", + confirm_code_generic_submit: "إرسال الرمز", + confirm_code_generic_try_again: "حاول ثانية", + confirm_code_generic_title: "أدخل رمز التأكيد", + confirm_code_2fa_instruction: "أدخل الرمز المكون من 6 أرقام من تطبيق المصادقة الخاص بك", + confirm_code_2fa_submit_btn: "إرسال", + confirm_code_2fa_title: "أدخل رمز المصادقة الثنائية", + confirm_delete_multiple_items: "هل أنت متأكد أنك تريد حذف هذه العناصر نهائيًا؟", + confirm_delete_single_item: "هل تريد حذف هذا العنصر نهائيًا؟", + confirm_open_apps_log_out: "لديك تطبيقات مفتوحة. هل أنت متأكد أنك تريد تسجيل الخروج؟", confirm_new_password: "تأكيد كلمة السر الجديدة", + confirm_delete_user: "هل انت متأكد انك تريد حذف حسابك؟ سيتم حذف جميع ملفاتك وبياناتك نهائيًا. لا يمكن التراجع عن هذا الإجراء", + confirm_delete_user_title: "حذف الحساب؟", + confirm_session_revoke: "هل أنت متأكد أنك تريد إلغاء هذه الجلسة؟", + confirm_your_email_address: "قم بتأكيد عنوان بريدك الإلكتروني", contact_us: "اتصل بنا", - contain: 'إملء', + contact_us_verification_required: "يجب أن يكون لديك عنوان بريد إلكتروني تم التحقق منه لاستخدام هذا", + contain: "يحتوي", continue: "أكمل", copy: 'أنسخ', copy_link: "أنسخ الرابط", copying: "ينسخ", - cover: 'غطاء', + copying_file: "%% ينسخ", + cover: "غلاف", create_account: "إنشاء حساب", create_free_account: "إنشاء حساب مجاني", - create_shortcut: "تم تصميم المنتج", + create_shortcut: "انشاء اختصار", + credits: "الاعتمادات", current_password: "كلمة السر الحالية", - cut: 'إقطع', - date_modified: 'تغيير الوقت', - delete: 'حذف', - delete_permanently: "حذف دائم", - deploy_as_app: 'نشر كتطبيق', - descending: 'تنازلي', + cut: "قطع", + clock: "ساعة", + clock_visible_hide: "إخفاء - مخفي دائمًا", + clock_visible_show: "إظهار - مرئي دائمًا", + clock_visible_auto: "تلقائي - افتراضي، مرئي فقط في وضع ملء الشاشة", + close_all: "إغلاق الكل", + created: "تم إنشاؤه", + date_modified: "تم تغيير الوقت", + default: "افتراضي", + delete: "حذف", + delete_account: "حذف الحساب", + delete_permanently: "حذف بشكل نهائي", + deleting_file: "%% حذف", + deploy_as_app: "نشر كتطبيق", + descending: "تنازلي", + desktop: "سطح المكتب", desktop_background_fit: "خلفية سطح المكتب مناسبة", + developers: "المطورين", dir_published_as_website: `:تم نشر الدليل كموقع ويب`, - disassociate_dir: "فصل الدليل", - download: 'تحميل ', - downloading: "جارى التحميل ", + disable_2fa: "تعطيل المصادقة الثنائية", + disable_2fa_confirm: "هل أنت متأكد أنك تريد تعطيل المصادقة الثنائية؟", + disable_2fa_instructions: "أدخل كلمة المرور الخاصة بك لتعطيل المصادقة الثنائية", + disassociate_dir: "فصل المجلد", + documents: "المستندات", + dont_allow: "عدم السماح", + download: "تحميل", + download_file: "تحميل ملف", + downloading: "جارى التحميل", email: "بريد إلكتروني", - email_or_username: "البريد الإلكتروني أو اسم المستخدم ", - empty_trash: 'سلة مهملات فارغة', - empty_trash_confirmation:'تأكيد إفراغ سلة المهملات ', - emptying_trash: 'إفراغ القمامة', - feedback: "تعليق ", - feedback_c2a: "تعليق ", - feedback_sent_confirmation: "أرسلت ردود الفعل التكوين ", + email_change_confirmation_sent: "تم إرسال رسالة تأكيد بالبريد الإلكتروني إلى عنوان بريدك الإلكتروني الجديد. يرجى التحقق من صندوق الوارد الخاص بك واتباع التعليمات لإكمال العملية", + email_invalid: "البريد الإلكتروني غير صالح", + email_or_username: "البريد الإلكتروني أو اسم المستخدم", + email_required: "يجب إدخال البريد الإلكتروني", + empty_trash: "قم بإفراغ سلة المهملات", + empty_trash_confirmation: "تأكيد إفراغ سلة المهملات", + emptying_trash: "...إفراغ القمامة", + enable_2fa: "تمكين المصادقة الثنائية", + end_hard: "نهاية بالقوة", + end_process_force_confirm: "هل أنت متأكد أنك تريد فرض إنهاء هذه العملية؟", + end_soft: "نهاية لينة", + enlarged_qr_code: "رمز الاستجابة السريعة الموسع", + enter_password_to_confirm_delete_user: "أدخل كلمة المرور الخاصة بك لتأكيد حذف الحساب", + error_message_is_missing: "خطأ الرسالة مفقودة", + error_unknown_cause: "حدث خطأ غير معروف", + error_uploading_files: "فشل تحميل الملفات", + favorites: "المفضلة", + feedback: "تعليق", + feedback_c2a: "يرجى استخدام النموذج أدناه لإرسال تعليقاتك وتعليقاتك وتقارير الأخطاء إلينا", + feedback_sent_confirmation: "أشكركم على الاتصال بنا. إذا كان لديك بريد إلكتروني مرتبط بحسابك، فسوف تتلقى ردًا منا في أقرب وقت ممكن", + fit: "ملائم", + folder: "مجلد", + force_quit: "الخروج بالقوة", forgot_pass_c2a: "هل نسيت كلمة السر؟", from: "من", general: "عام ", get_a_copy_of_on_puter: `الحصول على نسخة على جهاز الكمبيوتر`, - get_copy_link: 'الحصول على رابط النسخ', + get_copy_link: "الحصول على رابط النسخ", hide_all_windows: "إخفاء كافة النوافذ ", - html_document: 'وثيقة أتش تي أم أل', - image: 'صورة', + home: "الرئيسة", + html_document: "وثيقة أتش تي أم أل", + hue: "مسحة", + image: "صورة", + incorrect_password: "كلمة سر خاطئة", invite_link: "رابط الدعوة", - items_in_trash_cannot_be_renamed: `لا يمكن إعادة تسمية العناصر الموجودة في سلة المهملات `, - jpeg_image: 'صورة j p e g', - keep_in_taskbar: 'احتفظ بها في شريط المهام ', + item: "عنصر", + items_in_trash_cannot_be_renamed: "لا يمكن إعادة تسمية هذا العنصر لأنه موجود في سلة المهملات. لإعادة تسمية هذا العنصر، اسحبه أولاً خارج سلة المهملات", + jpeg_image: "صورة jpeg", + keep_in_taskbar: "احتفظ بها في شريط المهام", + language: "لغة", + license: "رخصة", + lightness: "خفة", + link_copied: "تم نسخ الرابط", + loading: "تحميل", log_in: "تسجيل الدخول", - log_out: 'تسجيل خروج', - move: 'يتحرك', - moving_file: "متحرك %%", - my_websites: "مواقعي الإلكترونية ", + log_into_another_account_anyway: "قم بتسجيل الدخول إلى حساب آخر على أي حال", + log_out: "تسجيل خروج", + looks_good: "تبدو جيدة!", + manage_sessions: "إدارة الجلسات", + menubar_style: "نمط شريط القوائم", + menubar_style_desktop: "سطح المكتب", + menubar_style_system: "نظام", + menubar_style_window: "نافذة", + modified: "معدل", + move: "نقل", + moving_file: "نقل %%", + my_websites: "مواقعي الإلكترونية", name: 'اسم', name_cannot_be_empty: 'لا يمكن أن يكون الاسم فارغًا', name_cannot_contain_double_period: "لا يمكن أن يحتوي الاسم على نقطة مزدوجة ", - name_cannot_contain_period: "لا يمكن أن يحتوي الاسم على فترة", - name_cannot_contain_slash: "لا يمكن أن يحتوي الاسم على شرطة مائلة", + name_cannot_contain_period: "' ' لا يمكن أن يحتوي الاسم على", + name_cannot_contain_slash: "'/' لا يمكن أن يحتوي الاسم على", name_must_be_string: "يجب أن يكون الاسم سلسلة", - name_too_long: `الاسم طويل جدًا`, - new: 'جديد', - new_folder: 'ملف جديد ', + name_too_long: "الاسم طويل جدًا", + new: "جديد", + new_email: "بريد إلكتروني جديد", + new_folder: "ملف جديد", new_password: "كلمة المرور الجديدة ", - new_username: "اسم مستخدم جديد ", + new_username: "اسم مستخدم جديد", + no: "لا", no_dir_associated_with_site: 'لا يوجد دليل مرتبط بالموقع', no_websites_published: "لم يتم نشر أي مواقع", ok: 'نعم', - open: "يفتح", + open: "فتح", open_in_new_tab: "فتح في علامة تبويب جديدة", - open_in_new_window: "افتح في نافذة جديدة ", - open_with: "مفتوحة مع ", - password: "كلمة المرور ", - password_changed: "تم تغيير كلمة السر ", - passwords_do_not_match: 'كلمة المرور غير مطابقة', - paste: 'لصق', + open_in_new_window: "افتح في نافذة جديدة", + open_with: "افتح ب", + original_name: "الاسم الاصلي", + original_path: "المسار الأصلي", + oss_code_and_content: "البرامج والمحتوى مفتوح المصدر", + password: "كلمة المرور", + password_changed: "تم تغيير كلمة السر", + password_recovery_rate_limit: "لقد وصلت إلى الحد الأقصى؛ يرجى الانتظار بضع دقائق. ولمنع حدوث ذلك في المستقبل، تجنب إعادة تحميل الصفحة عدة مرات", + password_recovery_token_invalid: "استعادة كلمة المرور لم تعد صالحة", + password_recovery_unknown_error: "حدث خطأ غير معروف. الرجاء معاودة المحاولة في وقت لاحق", + password_required: "كلمة المرور مطلوبة", + password_strength_error: "يجب أن تتكون كلمة المرور من 8 أحرف على الأقل وتحتوي على حرف كبير واحد وحرف صغير واحد ورقم واحد وحرف خاص واحد على الأقل", + passwords_do_not_match: "كلمة المرور غير مطابقة", + paste: "لصق", paste_into_folder: "الصق داخل الملف", - pick_name_for_website: "اختيار اسم لموقع الويب ", - picture: "صورة ", + path: "مسار", + personalization: "الطابع الشخصي", + pick_name_for_website: "اختيار اسم لموقع الويب", + picture: "صورة", + pictures: "صور", + plural_suffix: "س", powered_by_puter_js: `مشغل بواسطة{{link=docs}}Puter.js{{/link}}`, - preparing: "إعداده", - preparing_for_upload: "التحضير للتحميل ", - properties: "ملكيات ", + preparing: "إعداد", + preparing_for_upload: "التحضير للتحميل", + print: "طبع", + privacy: "خصوصية", + proceed_to_login: "انتقل إلى تسجيل الدخول", + proceed_with_account_deletion: "تابع عملية حذف الحساب", + process_status_initializing: "تهيئة", + process_status_running: "تشغيل", + process_type_app: "برنامج", + process_type_init: "أولي", + process_type_ui: "واجهة المستخدم", + properties: "ملكيات", + public: "عام", publish: "ينشر", - publish_as_website: 'نشر كموقع على شبكة الإنترنت ', + publish_as_website: "نشر كموقع على شبكة الإنترنت", + puter_description: "Puter عبارة عن سحابة شخصية تعطي الأولوية للخصوصية للاحتفاظ بجميع ملفاتك وتطبيقاتك وألعابك في مكان واحد آمن، ويمكن الوصول إليها من أي مكان وفي أي وقت.", + reading_file: "قراءة %%", recent: "مؤخرًا", - recover_password: "إستعادة كلمة المرور ", - refer_friends_c2a: "احصل على 1 جيجابايت لكل صديق يقوم بإنشاء حساب والتحقق منه مع Puter. صديقك يحصل على 1 غيغابايت أيضًا!", - refer_friends_social_media_c2a: `احصل على 1 غيغابايت من مساحة التخزين المجانية على موقع Puter.com!`, - refresh: 'ينعش ', - release_address_confirmation: `تأكيد عنوان الإصدار `, - remove_from_taskbar:'إزالة من شريط المهام ', - rename: 'إعادة تسمية', - repeat: 'تكرار', + recommended: "موصى به", + recover_password: "إستعادة كلمة المرور", + refer_friends_c2a: "احصل على 1 جيجابايت لكل صديق يقوم بإنشاء حساب على Outer وتأكيده. سيحصل صديقك أيضًا على 1 غيغابايت!", + refer_friends_social_media_c2a: "احصل على 1 غيغابايت من مساحة التخزين المجانية على موقع Puter.com!", + refresh: "أنعش", + release_address_confirmation: "هل أنت متأكد أنك تريد تحرير هذا العنوان؟", + remove_from_taskbar: "إزالة من شريط المهام", + rename: "إعادة تسمية", + repeat: "تكرار", + replace: "إستبدال", + replace_all: "استبدال الكل", resend_confirmation_code: "إعادة إرسال رمز التأكيد", + reset_colors: "إعادة تعيين الألوان", + restart_puter_confirm: "هل أنت متأكد أنك تريد إعادة تشغيل Puter؟", restore: "استرجاع", - save_account_to_get_copy_link: "حفظ الحساب للحصول على نسخة الرابط", - save_account_to_publish: 'حفظ الحساب للنشر', - save_session_c2a: 'حفظ جلسة ', - scan_qr_c2a: 'قم بمسح الرمز أدناه لتسجيل الدخول إلى هذه الجلسة من الأجهزة الأخرى', + save: "حفظ", + saturation: "تشبع", + save_account: "حفظ الحساب", + save_account_to_get_copy_link: "يرجى إنشاء حساب للمتابعة", + save_account_to_publish: "يرجى إنشاء حساب للمتابعة", + save_session: "حفظ جلسة", + save_session_c2a: "قم بإنشاء حساب لحفظ جلستك الحالية وتجنب فقدان عملك", + scan_qr_c2a: "قم بمسح الرمز أدناه لتسجيل الدخول إلى هذه الجلسة من الأجهزة الأخرى", + scan_qr_2fa: "امسح رمز الاستجابة السريعة ضوئيًا باستخدام تطبيق المصادقة الخاص بك", + scan_qr_generic: "قم بمسح رمز الاستجابة السريعة هذا باستخدام هاتفك أو جهاز آخر", + search: "Search", + seconds: "ثواني", + security: "حماية", select: "إختار", - select_color: 'إختر لون ', + selected: "المحدد", + select_color: "إختر لون", + sessions: "الجلسات", send: "أرسل", send_password_recovery_email: "إرسال بريد إلكتروني لاستعادة كلمة المرور", - session_saved: "تم حفظ الجلسة ", - set_new_password: "تعيين كلمة مرور جديدة ", - share_to: " شارك إلى", - show_all_windows: "إظهار كافة النوافذ ", - show_hidden: 'أظهر المخفي ', + session_saved: "تم حفظ الجلسة", + settings: "إعدادات", + set_new_password: "تعيين كلمة مرور جديدة", + share: "مشاركة", + share_to: "شارك إلى", + share_with: "شارك مع:", + shortcut_to: "اختصار ل", + show_all_windows: "إظهار كافة النوافذ", + show_hidden: "أظهر المخفي", sign_in_with_puter: "سجل الدخول ب Puter", sign_up: "إشترك", signing_in: "تسجيل الدخول", - size: 'الحجم', - sort_by: 'ترتيب حسب', - start: 'إبدأ ', - taking_longer_than_usual: 'يستغرق وقتا أطول من المعتاد ', - text_document: 'وثيقة نصية', + size: "الحجم", + skip: "تخطي", + something_went_wrong: "لقد حدث خطأ ما", + sort_by: "ترتيب حسب", + start: "بدأ", + status: "حالة", + storage_usage: "استخدام التخزين", + storage_puter_used: "يستخدمه بوتر", + taking_longer_than_usual: "يستغرق وقتا أطول قليلا من المعتاد. انتظر من فضلك...", + task_manager: "مدير المهام", + taskmgr_header_name: "اسم", + taskmgr_header_status: "حالة", + taskmgr_header_type: "نوع", + terms: "شروط", + text_document: "وثيقة نصية", tos_fineprint: `بالنقر على "إنشاء حساب مجاني"، فإنك توافق على {{link=terms}}شروط الاستخدام{{/link}} و {{link=privacy}}حماية البيانات{{/link}}`, - trash: 'نفاية', - type: 'اكتب', - undo: 'الغاء التحميل', + transparency: "شفافية", + trash: "نفايات", + two_factor: "المصادقة الثنائية", + two_factor_disabled: "المصادقة الثنائية معطل", + two_factor_enabled: "المصادقة الثنائية ممكّن", + type: "اكتب", + type_confirm_to_delete_account: "اكتب 'تأكيد' لحذف حسابك", + ui_colors: "ألوان واجهة المستخدم", + ui_manage_sessions: "مدير الجلسة", + ui_revoke: "إبطال", + undo: "الغاء", + unlimited: "غير محدود", unzip: "فك الضغط", - upload: 'رفع ', - upload_here: 'ارفع هنا', - username: "اسم المستخدم ", - username_changed: 'تم تغيير اسم المستخدم', - versions: "الإصدارات ", - yes_release_it: 'نعم أطلقه', + upload: "رفع", + upload_here: "ارفع هنا", + usage: "الاستخدام", + username: "اسم المستخدم", + username_changed: "تم تغيير اسم المستخدم", + username_required: "اسم المستخدم مطلوب", + versions: "الإصدارات", + videos: "فيديوهات", + visibility: "رؤية", + yes: "نعم", + yes_release_it: "نعم أطلقه", you_have_been_referred_to_puter_by_a_friend: "لقد تمت إحالتك إلى Puter بواسطة صديق!", zip: "ملف مضغوط", + zipping_file: "ضغط %%", + + // === إعداد المصادقة الثنائية === + setup2fa_1_step_heading: "افتح تطبيق المصادقة الخاص بك", + setup2fa_1_instructions: ` + مكنك استخدام أي تطبيق مصادقة يدعم بروتوكول كلمة المرور المستندة إلى الوقت (TOTP). + هناك الكثير للاختيار من بينها، ولكن إذا لم تكن متأكدًا + Authy + يعد خيارًا قويًا لنظامي التشغيل Android وiOS. + `, + setup2fa_2_step_heading: "مسح رمز الاستجابة السريعة", + setup2fa_3_step_heading: "أدخل الرمز المكون من 6 أرقام", + setup2fa_4_step_heading: "انسخ رموز الاسترداد الخاصة بك", + setup2fa_4_instructions: ` + تعد رموز الاسترداد هذه هي الطريقة الوحيدة للوصول إلى حسابك إذا فقدت هاتفك أو لم تتمكن من استخدام تطبيق المصادقة الخاص بك. + تأكد من تخزينها في مكان آمن. + `, + setup2fa_5_step_heading: "تأكيد إعداد المصادقة الثنائية", + setup2fa_5_confirmation_1: "لقد قمت بحفظ رموز الاسترداد الخاصة بي في مكان آمن", + setup2fa_5_confirmation_2: "أنا مستعد لتمكين المصادقة الثنائية", + setup2fa_5_button: "تمكين المصادقة الثنائية", + + // === تسجيل دخول المصادقة الثنائية === + login2fa_otp_title: "دخل رمز المصادقة الثنائية", + login2fa_otp_instructions: "أدخل الرمز المكون من 6 أرقام من تطبيق المصادقة الخاص بك", + login2fa_recovery_title: "أدخل رمز الاسترداد", + login2fa_recovery_instructions: "أدخل أحد رموز الاسترداد الخاصة بك للوصول إلى حسابك", + login2fa_use_recovery_code: "استخدم رمز الاسترداد", + login2fa_recovery_back: "عودة", + login2fa_recovery_placeholder: "XXXXXXXX", } }; -export default ar; - +export default ar; \ No newline at end of file From 1f4297f7469f143f80c3bc12d5a46dc41a8d9da0 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 9 Jul 2024 07:48:35 -0700 Subject: [PATCH 0482/2119] Remove extra license header from ar.js --- src/gui/src/i18n/translations/ar.js | 18 ------------------ 1 file changed, 18 deletions(-) diff --git a/src/gui/src/i18n/translations/ar.js b/src/gui/src/i18n/translations/ar.js index 7beec74666..6cf2074fcc 100644 --- a/src/gui/src/i18n/translations/ar.js +++ b/src/gui/src/i18n/translations/ar.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * From a96abb5793528d0dc56d75f95d771e1dcf5960d1 Mon Sep 17 00:00:00 2001 From: micheledinelli Date: Tue, 9 Jul 2024 16:49:19 +0200 Subject: [PATCH 0483/2119] Completing Italian translation based on English file. --- src/gui/src/i18n/translations/it.js | 188 +++++++++++++++++++++++++++- 1 file changed, 186 insertions(+), 2 deletions(-) diff --git a/src/gui/src/i18n/translations/it.js b/src/gui/src/i18n/translations/it.js index 0e40485aa6..0c45b0e598 100644 --- a/src/gui/src/i18n/translations/it.js +++ b/src/gui/src/i18n/translations/it.js @@ -34,72 +34,156 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const it = { name: "Italiano", english_name: "Italian", code: "it", dictionary: { + about: "About", + account: "Account", + account_password: "Verifica Account Password", access_granted_to: "Accesso garantito a", add_existing_account: "Aggiungi un account esistente", - all_fields_required: 'Tutte le caselle sono richieste.', + all_fields_required: "Tutte i campi sono richiesti.", + allow: "Consenti", apply: "Applica", ascending: 'Ascendente', + associated_websites: "Siti associati", + auto_arrange: 'Organizzazione automatica', background: "Sfondo", browse: "Sfoglia", cancel: 'Annulla', center: 'Centra ', change_desktop_background: 'Modifica sfondo…', + change_email: "Modifica Email", change_language: "Cambia lingua", change_password: "Modifica password", + change_ui_colors: "Cambia i colori dell'interfaccia", change_username: "Modifica Nome Utente", + close: "Chiudi", close_all_windows: "Chiudi tutte le finestre", + close_all_windows_confirm: "Sei sicuro di voler chiudere tutte le finestre?", + close_all_windows_and_log_out: "Chiudi tutte le finestre e disconnettiti", + change_always_open_with: "Vuoi sempre aprire questo tipo di file con", color: 'Colore', + confirm: "Conferma", + confirm_2fa_setup: "Ho aggiunto il codice alla mia app di autenticazione", + confirm_2fa_recovery: "Ho salvato il codice di recupero in un posto sicuro", confirm_account_for_free_referral_storage_c2a: 'Crea un account e conferma la tua email per ricevere 1 GB di spazio di archiviazione gratuito. Anche il tuo amico riceverà dello spazio extra!', + confirm_code_generic_incorrect: "Codice errato.", + confirm_code_generic_too_many_requests: "Troppe richieste. Attendi qualche minuto.", + confirm_code_generic_submit: "Invia Codice", + confirm_code_generic_try_again: "Riprova", + confirm_code_generic_title: "Inserisci Codice di Conferma", + confirm_code_2fa_instruction: "Inserisci il codice a 6 cifre dalla tua app di autenticazione.", + confirm_code_2fa_submit_btn: "Invia", + confirm_code_2fa_title: "Inserisci il Codice 2FA", + confirm_delete_multiple_items: 'Sei sicuro di voler eliminare definitivamente questi elementi?', + confirm_delete_single_item: 'Vuoi eliminare definitivamente questo elemento?', + confirm_open_apps_log_out: 'Ci sono delle applicazioni aperte. Sei sicuro di voler effettuare il log out?', confirm_new_password: "Conferma la nuova Password", + confirm_delete_user: "Sei sicuro di voler cancellare il tuo account? tutti i tuoi file e dati saranno definitivamente cancellati. Quest'azione non è reversibile.", + confirm_delete_user_title: "Cancellare l'Account?", + confirm_session_revoke: "Sei sicuro di voler revocare questa sessione?", + confirm_your_email_address: "Conferma il tuo indirizzo email", contact_us: "Contattaci", + contact_us_verification_required: "Devi verificare il tuo indirizzo email per utilizzare questa funzione.", contain: 'Contiene', continue: "Continua", copy: 'Copia', copy_link: "Copia il link", copying: "Copia in corso", + copying_file: "Copiando %%", cover: 'Cover', create_account: "Crea Account", create_free_account: "Crea un account gratis", create_shortcut: "Crea Scorciatoia", + credits: "Credits", current_password: "Password corrente", cut: 'Taglia', + clock: "Orologio", + clock_visible_hide: 'Nascondi - Sempre nascosto', + clock_visible_show: 'Mostra - Sempre visibile', + clock_visible_auto: 'Auto - Default, visibile solo in modalità schermo intero', + close_all: 'Close All', + created: 'Created', date_modified: 'Data ultima modifica', + default: 'Default', delete: 'Elimina', + delete_account: "Elimina Account", delete_permanently: "Elimina permanentemente", + deleting_file: "Eliminando %%", deploy_as_app: 'Distribuisci come Applicazione', descending: 'Discendente', + desktop: 'Desktop', desktop_background_fit: "Adatta", + developers: "Sviluppatori", dir_published_as_website: `%strong% è stato pubblicato su:`, + disable_2fa: 'Disabilita 2FA', + disable_2fa_confirm: "Sei sicuro di voler disabilitare 2FA?", + disable_2fa_instructions: "Inserisci la tua password per disabilitare 2FA.", disassociate_dir: "Dissocia la Directory", + documents: 'Documenti', + dont_allow: 'Non consentire', download: 'Scarica', + download_file: 'Scarica file', downloading: "Download in corso", email: "Email", + email_change_confirmation_sent: "Ti abbiamo inviato un'email di conferma. Controlla la tua casella di posta e segui le istruzioni per completare il processo.", + email_invalid: 'Email non valida.', email_or_username: "Email o Nome Utente", + email_required: "Email richiesta.", empty_trash: 'Svuota Cestino', empty_trash_confirmation: `Sei sicuro di voler svuotare il cestino?`, emptying_trash: 'Il cestino si sta svuotando…', + enable_2fa: 'Abilita 2FA', + end_hard: "Forza la chiusura", + end_process_force_confirm: "Sei sicuro di voler forzare la chiusura di questo processo?", + end_soft: "Chiudi", + enlarged_qr_code: "QR Code ingrandito", + enter_password_to_confirm_delete_user: "Inserisci la tua password per confermare l'eliminazione del tuo account.", + error_message_is_missing: "Messaggio di errore mancante.", + error_unknown_cause: "Errore sconosciuto.", + error_uploading_files: "Errore durante l'upload dei file.", + favorites: "Preferiti", feedback: "Feedback", feedback_c2a: "Usa il form qua sotto per inviarci feedback, commenti, e segnalarci dei bug.", feedback_sent_confirmation: "Grazie per averci contattato. Se hai un indirizzo email associato al tuo account, ti ricontatteremo il prima possibile.", + fit: 'Adatta', + folder: 'Cartella', + force_quit: 'Forza la chiusura', forgot_pass_c2a: "Password dimenticata?", from: "Da", general: "Generale", get_a_copy_of_on_puter: `Ottieni una copia di '%%' su Puter.com!`, get_copy_link: 'Ottieni link di copia', hide_all_windows: "Nascondi tutte le finestre", + home: 'Home', html_document: 'Documento HTML', + hue: 'Tonalità', image: 'Immagine', + incorrect_password: 'Password errata', invite_link: "Link d’invito", + item: 'elemento', items_in_trash_cannot_be_renamed: `Impossibile rinominare un elemento nel Cestino. Per rinominarlo, è necessario ripristinarlo.`, jpeg_image: 'Immagine JPEG', keep_in_taskbar: 'Blocca nella barra delle applicazioni', + language: "Lingua", + license: "Licenza", + lightness: 'Luminosità', + link_copied: "Link copiato", + loading: 'Caricamento', log_in: "Accedi", + log_into_another_account_anyway: 'Accedi comunque con un altro account', log_out: 'Disconnettiti', + looks_good: "Sembra buono!", + manage_sessions: "Gestisci le sessioni", + menubar_style: "Stile della barra dei menu", + menubar_style_desktop: "Desktop", + menubar_style_system: "System", + menubar_style_window: "Window", + modified: 'Modificato', move: 'Sposta', moving_file: "Spostamento in corso %%", my_websites: "I miei siti web", @@ -111,9 +195,11 @@ const it = { name_must_be_string: "Il nome può contenere una sola linea.", name_too_long: `Il nome non può essere più lungo di %% caratteri.`, new: 'Nuovo', + new_email: "Nuova Email", new_folder: 'Nuova Cartella', new_password: "Nuova Password", new_username: "Nuovo Nome Utente", + no: 'No', no_dir_associated_with_site: 'Nessuna directory è stata associata all’indirizzo.', no_websites_published: "Non hai pubblicato nessun sito web.", ok: 'OK', @@ -121,20 +207,45 @@ const it = { open_in_new_tab: "Apri in una nuova scheda", open_in_new_window: "Apri in una nuova finestra", open_with: "Apri con", + original_name: 'Nome originale', + original_path: 'Percorso originale', + oss_code_and_content: "Contenuto e software Open Source", password: "Password", password_changed: "Password modificata.", + password_recovery_rate_limit: "Hai raggiunto il limite di richieste; per favore attendi qualche minuto. Per evitarlo in futuro evita di ricaricare la pagina troppe volte.", + password_recovery_token_invalid: "Questo token per il recupero della password non è valido.", + password_recovery_unknown_error: "Errore sconosciuto. Per favore riprova più tardi.", + password_required: 'Password richiesta.', + password_strength_error: "La password deve essere lunga almeno 8 caratteri e contenete almeno una maiuscola, una minuscola, un numero e un carattere speciale.", passwords_do_not_match: 'Le caselle `Nuova Password` and `Conferma Nuova Password` non corrispondono.', paste: 'Incolla', paste_into_folder: "Incolla nella cartella", + path: 'Percorso', + personalization: "Personalizzazione", pick_name_for_website: "Scegli un nome per il tuo sito web:", picture: "Immagine", + pictures: 'Immagini', + plural_suffix: 'i', powered_by_puter_js: `Powered by {{link=docs}}Puter.js{{/link}}`, preparing: "Preparazione in corso...", preparing_for_upload: "Preparazione per l’upload...", + print: 'Stampa', + privacy: "Privacy", + proceed_to_login: 'Procedi con il login', + proceed_with_account_deletion: "Continua con l'eliminazione dell'account", + process_status_initializing: "Inizializzando", + process_status_running: "In esecuzione", + process_type_app: 'App', + process_type_init: 'Init', + process_type_ui: 'UI', properties: "Proprietà", + public: "Pubblico", publish: "Pubblica", publish_as_website: 'Pubblica come sito web', + puter_description: `Puter è un cloud personale che mette la privacy al primo posto, per conservare tutti i tuoi file, app e giochi in un unico luogo sicuro, accessibile da qualsiasi luogo e in qualsiasi momento.`, + reading_file: "Leggendo %strong%", recent: "Recenti", + recommended: "Consigliati", recover_password: "Ripristina la Password", refer_friends_c2a: "Ottieni 1 GB di spazio di archiviazione per ogni amico che crea un account e conferma l’email su Puter. Anche il tuo amico riceverà dello spazio extra!", refer_friends_social_media_c2a: `Ottieni 1GB di spazio di spazio di archiviazione gratuito su Puter.com!`, @@ -143,43 +254,116 @@ const it = { remove_from_taskbar:'Sblocca dalla barra delle applicazioni', rename: 'Rinomina', repeat: 'Ripeti', + replace: 'Sostituisci', + replace_all: 'Sostituisci tutto', resend_confirmation_code: "Invia di nuovo il codice di conferma", + reset_colors: "Ripristina i colori", + restart_puter_confirm: "Sei sicuro di voler resettare Puter?", restore: "Ripristina", + save: "Salva", + saturation: "Saturazione", + save_account: 'Salva Account', save_account_to_get_copy_link: "È necessario creare un account per procedere.", save_account_to_publish: 'È necessario creare un account per procedere.', + save_session: "Salva sessione", save_session_c2a: 'Crea un account per salvare la tua sessione e non perdere i tuoi dati.', scan_qr_c2a: 'Scansiona il codice qua sotto per utilizzare questa sessione da altri dispositivi', + scan_qr_2fa: 'Scansiona il codice QR con la tua app di autenticazione', + scan_qr_generic: 'Scansiona il codice QR usando il tuo sma', + search: 'Search', + seconds: 'seconds', + security: "Security", select: "Seleziona", + selected: 'Selezionato', select_color: 'Seleziona un colore…', + sessions: "Sessioni", send: "Invia", send_password_recovery_email: "Invia Email per il ripristino della password", session_saved: "Grazie per aver creato un account. La sessione è stata salvata", + settings: "Impostazioni", set_new_password: "Imposta una nuova Password", + share: "Condividi", share_to: "Condividi con", + share_with: "Condividi con", + shortcut_to: "Scorciatoia per", show_all_windows: "Mostra tutte le finestre", show_hidden: 'Mostra nascosti', sign_in_with_puter: "Accedi con Puter", sign_up: "Registrati", signing_in: "Accesso in corso…", size: 'Dimensione', + skip: "Salta", + something_went_wrong: "Qualcosa è andato storto.", sort_by: 'Ordina per', start: 'Start', + status: 'Stato', + storage_usage: "Utilizzo dello spazio", + storage_puter_used: 'utilizzato da Puter', taking_longer_than_usual: 'Il processo in corso ci sta mettendo più del solito. Attendere prego...', + task_manager: "Task Manager", + taskmgr_header_name: "Nome", + taskmgr_header_status: "Stato", + taskmgr_header_type: "Tipo", + terms: "Termini", text_document: 'Documento di testo', tos_fineprint: `Cliccando su 'Crea un account gratis' accetti i {{link=terms}}Termini di Servizio{{/link}} e l'{{link=privacy}}Informativa sulla Privacy{{/link}} di Puter.`, + transparency: "Trasparenza", trash: 'Cestino', + two_factor: 'Autenticazione a due fattori', + two_factor_disabled: '2FA Disabilitata', + two_factor_enabled: '2FA Abilitata', type: 'Tipo', + type_confirm_to_delete_account: "Scrivi 'conferma' per eliminare il tuo account.", + ui_colors: "Colori dell'interfaccia", + ui_manage_sessions: "Session Manager", + ui_revoke: "Revoca", undo: 'Annulla', + unlimited: 'Illimitato', unzip: "Unzip", upload: 'Carica', upload_here: 'Carica qui', + usage: 'Utilizzo', username: "Nome Utente", username_changed: 'Nome utente aggiornato con successo.', + username_required: 'Il nome utente è richiesto.', versions: "Versioni", + videos: "Video", + visibility: "Visibilità", + yes: 'Sì', yes_release_it: 'Si, rilascialo', you_have_been_referred_to_puter_by_a_friend: "Sei stato invitato su Puter da un amico!", zip: "Zip", + zipping_file: "Zipping %strong%", + + // === 2FA Setup === + setup2fa_1_step_heading: 'Apri la tua app di autenticazione', + setup2fa_1_instructions: ` + Puoi utilizzare qualsiasi app di autenticazione che supporti il protocollo TOTP (Time-based One-Time Password). + Ci sono molte opzioni tra cui scegliere, ma se non sei sicuro, + Authy + è una scelta valida sia per Android che per iOS. + `, + setup2fa_2_step_heading: 'Scansiona il codice QR', + setup2fa_3_step_heading: 'Inserisci il codice a 6 cifre', + setup2fa_4_step_heading: 'Copia i tuoi codici di recupero', + setup2fa_4_instructions: ` + Questi codici di recupero sono l'unico modo per accedere al tuo account se perdi il telefono o non puoi utilizzare la tua app di autenticazione. + Assicurati di conservarli in un luogo sicuro. + `, + setup2fa_5_step_heading: 'Conferma la configurazione del 2FA', + setup2fa_5_confirmation_1: 'Ho salvato i miei codici di recupero in un luogo sicuro', + setup2fa_5_confirmation_2: 'Sono pronto per abilitare il 2FA', + setup2fa_5_button: 'Abilita 2FA', + + // === 2FA Login === + login2fa_otp_title: 'Inserisci il codice 2FA', + login2fa_otp_instructions: 'Inserisci il codice a 6 cifre dalla tua app di autenticazione.', + login2fa_recovery_title: 'Inserisci un codice di recupero', + login2fa_recovery_instructions: 'Inserisci uno dei tuoi codici di recupero per accedere al tuo account.', + login2fa_use_recovery_code: 'Usa un codice di recupero', + login2fa_recovery_back: 'Indietro', + login2fa_recovery_placeholder: 'XXXXXXXX', } -} +}; export default it; \ No newline at end of file From 7fa2dd535ffae2892908b1db673f12eb63e648ae Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 9 Jul 2024 07:51:54 -0700 Subject: [PATCH 0484/2119] remove all duplicated license headers --- src/gui/src/UI/Components/ActionCard.js | 19 +------------------ src/gui/src/UI/Components/Button.js | 19 +------------------ src/gui/src/UI/Components/CodeEntryView.js | 19 +------------------ .../src/UI/Components/ConfirmationsView.js | 19 +------------------ src/gui/src/UI/Components/Flexer.js | 19 +------------------ src/gui/src/UI/Components/Frame.js | 19 +------------------ src/gui/src/UI/Components/Glyph.js | 19 +------------------ src/gui/src/UI/Components/JustHTML.js | 19 +------------------ src/gui/src/UI/Components/NotifCard.js | 19 +------------------ src/gui/src/UI/Components/PasswordEntry.js | 19 +------------------ src/gui/src/UI/Components/QRCode.js | 19 +------------------ .../UI/Components/RecoveryCodeEntryView.js | 19 +------------------ .../src/UI/Components/RecoveryCodesView.js | 19 +------------------ src/gui/src/UI/Components/Slider.js | 19 +------------------ src/gui/src/UI/Components/Spinner.js | 19 +------------------ src/gui/src/UI/Components/StepHeading.js | 19 +------------------ src/gui/src/UI/Components/StepView.js | 19 +------------------ src/gui/src/UI/Components/StringView.js | 19 +------------------ src/gui/src/UI/Components/Table.js | 19 +------------------ src/gui/src/UI/Components/TestView.js | 19 +------------------ src/gui/src/UI/Settings/UITabAccount.js | 19 +------------------ src/gui/src/UI/Settings/UITabClock.js | 19 +------------------ src/gui/src/UI/Settings/UITabLanguage.js | 19 +------------------ .../src/UI/Settings/UITabPersonalization.js | 19 +------------------ src/gui/src/definitions.js | 19 +------------------ src/gui/src/helpers/truncate_filename.js | 19 +------------------ src/gui/src/i18n/i18n.js | 19 +------------------ src/gui/src/i18n/i18nChangeLanguage.js | 19 +------------------ src/gui/src/i18n/translations/bn.js | 19 +------------------ src/gui/src/i18n/translations/br.js | 19 +------------------ src/gui/src/i18n/translations/da.js | 19 +------------------ src/gui/src/i18n/translations/de.js | 19 +------------------ src/gui/src/i18n/translations/emoji.js | 19 +------------------ src/gui/src/i18n/translations/en.js | 19 +------------------ src/gui/src/i18n/translations/es.js | 19 +------------------ src/gui/src/i18n/translations/fa.js | 19 +------------------ src/gui/src/i18n/translations/fi.js | 19 +------------------ src/gui/src/i18n/translations/fr.js | 19 +------------------ src/gui/src/i18n/translations/hi.js | 19 +------------------ src/gui/src/i18n/translations/hy.js | 19 +------------------ src/gui/src/i18n/translations/ig.js | 19 +------------------ src/gui/src/i18n/translations/it.js | 19 +------------------ src/gui/src/i18n/translations/ko.js | 19 +------------------ src/gui/src/i18n/translations/nb.js | 19 +------------------ src/gui/src/i18n/translations/nl.js | 19 +------------------ src/gui/src/i18n/translations/nn.js | 19 +------------------ src/gui/src/i18n/translations/pl.js | 19 +------------------ src/gui/src/i18n/translations/pt.js | 19 +------------------ src/gui/src/i18n/translations/ro.js | 19 +------------------ src/gui/src/i18n/translations/ru.js | 19 +------------------ src/gui/src/i18n/translations/sv.js | 19 +------------------ src/gui/src/i18n/translations/th.js | 19 +------------------ src/gui/src/i18n/translations/tr.js | 19 +------------------ src/gui/src/i18n/translations/translations.js | 19 +------------------ src/gui/src/i18n/translations/ua.js | 19 +------------------ src/gui/src/i18n/translations/ur.js | 19 +------------------ src/gui/src/i18n/translations/zh.js | 19 +------------------ src/gui/src/i18n/translations/zhtw.js | 19 +------------------ src/gui/src/index.js | 19 +------------------ src/gui/src/initgui.js | 19 +------------------ src/gui/src/services/BroadcastService.js | 19 +------------------ src/gui/src/services/ThemeService.js | 19 +------------------ 62 files changed, 62 insertions(+), 1116 deletions(-) diff --git a/src/gui/src/UI/Components/ActionCard.js b/src/gui/src/UI/Components/ActionCard.js index d53376d89e..dc115b2a0a 100644 --- a/src/gui/src/UI/Components/ActionCard.js +++ b/src/gui/src/UI/Components/ActionCard.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const Component = use('util.Component'); export default def(class ActionCard extends Component { diff --git a/src/gui/src/UI/Components/Button.js b/src/gui/src/UI/Components/Button.js index a174648998..bd72d05e2d 100644 --- a/src/gui/src/UI/Components/Button.js +++ b/src/gui/src/UI/Components/Button.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const Component = use('util.Component'); export default def(class Button extends Component { diff --git a/src/gui/src/UI/Components/CodeEntryView.js b/src/gui/src/UI/Components/CodeEntryView.js index 90a4067758..534296077d 100644 --- a/src/gui/src/UI/Components/CodeEntryView.js +++ b/src/gui/src/UI/Components/CodeEntryView.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const Component = use('util.Component'); export default def(class CodeEntryView extends Component { diff --git a/src/gui/src/UI/Components/ConfirmationsView.js b/src/gui/src/UI/Components/ConfirmationsView.js index b29ad486b7..b94a1fd23e 100644 --- a/src/gui/src/UI/Components/ConfirmationsView.js +++ b/src/gui/src/UI/Components/ConfirmationsView.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const Component = use('util.Component'); /** diff --git a/src/gui/src/UI/Components/Flexer.js b/src/gui/src/UI/Components/Flexer.js index 3e41bc6679..c3404b2b17 100644 --- a/src/gui/src/UI/Components/Flexer.js +++ b/src/gui/src/UI/Components/Flexer.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const Component = use('util.Component'); /** diff --git a/src/gui/src/UI/Components/Frame.js b/src/gui/src/UI/Components/Frame.js index d74eb1faad..581481f3a1 100644 --- a/src/gui/src/UI/Components/Frame.js +++ b/src/gui/src/UI/Components/Frame.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const Component = use('util.Component'); export default def(class Frame extends Component { diff --git a/src/gui/src/UI/Components/Glyph.js b/src/gui/src/UI/Components/Glyph.js index b357093a18..39f6c1455e 100644 --- a/src/gui/src/UI/Components/Glyph.js +++ b/src/gui/src/UI/Components/Glyph.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + import { Component } from "../../util/Component.js"; export default def(class Glyph extends Component { diff --git a/src/gui/src/UI/Components/JustHTML.js b/src/gui/src/UI/Components/JustHTML.js index fcf97e56d4..5fe51a129a 100644 --- a/src/gui/src/UI/Components/JustHTML.js +++ b/src/gui/src/UI/Components/JustHTML.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const Component = use('util.Component'); /** diff --git a/src/gui/src/UI/Components/NotifCard.js b/src/gui/src/UI/Components/NotifCard.js index 0db91e1778..9f71a8b4b2 100644 --- a/src/gui/src/UI/Components/NotifCard.js +++ b/src/gui/src/UI/Components/NotifCard.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const Component = use('util.Component'); export default def(class NotifCard extends Component { diff --git a/src/gui/src/UI/Components/PasswordEntry.js b/src/gui/src/UI/Components/PasswordEntry.js index 9b5adf48a5..82e59fc558 100644 --- a/src/gui/src/UI/Components/PasswordEntry.js +++ b/src/gui/src/UI/Components/PasswordEntry.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const Component = use('util.Component'); export default def(class PasswordEntry extends Component { diff --git a/src/gui/src/UI/Components/QRCode.js b/src/gui/src/UI/Components/QRCode.js index 6a9f3524b0..e724690bdc 100644 --- a/src/gui/src/UI/Components/QRCode.js +++ b/src/gui/src/UI/Components/QRCode.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const Component = use('util.Component'); import UIComponentWindow from "../UIComponentWindow.js"; diff --git a/src/gui/src/UI/Components/RecoveryCodeEntryView.js b/src/gui/src/UI/Components/RecoveryCodeEntryView.js index cb51f7d955..e8b21182df 100644 --- a/src/gui/src/UI/Components/RecoveryCodeEntryView.js +++ b/src/gui/src/UI/Components/RecoveryCodeEntryView.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const Component = use('util.Component'); export default def(class RecoveryCodeEntryView extends Component { diff --git a/src/gui/src/UI/Components/RecoveryCodesView.js b/src/gui/src/UI/Components/RecoveryCodesView.js index 30dfd8237d..9e57c8a183 100644 --- a/src/gui/src/UI/Components/RecoveryCodesView.js +++ b/src/gui/src/UI/Components/RecoveryCodesView.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const Component = use('util.Component'); export default def(class RecoveryCodesView extends Component { diff --git a/src/gui/src/UI/Components/Slider.js b/src/gui/src/UI/Components/Slider.js index 0989576254..112bfd94ad 100644 --- a/src/gui/src/UI/Components/Slider.js +++ b/src/gui/src/UI/Components/Slider.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const Component = use('util.Component'); /** diff --git a/src/gui/src/UI/Components/Spinner.js b/src/gui/src/UI/Components/Spinner.js index 99cf804d1b..89d8a27035 100644 --- a/src/gui/src/UI/Components/Spinner.js +++ b/src/gui/src/UI/Components/Spinner.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const Component = use('util.Component'); export default def(class Spinner extends Component { diff --git a/src/gui/src/UI/Components/StepHeading.js b/src/gui/src/UI/Components/StepHeading.js index 58a5c1154c..6aa1f2a0dd 100644 --- a/src/gui/src/UI/Components/StepHeading.js +++ b/src/gui/src/UI/Components/StepHeading.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const Component = use('util.Component'); /** diff --git a/src/gui/src/UI/Components/StepView.js b/src/gui/src/UI/Components/StepView.js index 2da06cc0f2..cc26373eea 100644 --- a/src/gui/src/UI/Components/StepView.js +++ b/src/gui/src/UI/Components/StepView.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const Component = use('util.Component'); export default def(class StepView extends Component { diff --git a/src/gui/src/UI/Components/StringView.js b/src/gui/src/UI/Components/StringView.js index aee602eb1b..82849d46fc 100644 --- a/src/gui/src/UI/Components/StringView.js +++ b/src/gui/src/UI/Components/StringView.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const Component = use('util.Component'); /** diff --git a/src/gui/src/UI/Components/Table.js b/src/gui/src/UI/Components/Table.js index e02af517c1..f34d060f8d 100644 --- a/src/gui/src/UI/Components/Table.js +++ b/src/gui/src/UI/Components/Table.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const Component = use('util.Component'); /** diff --git a/src/gui/src/UI/Components/TestView.js b/src/gui/src/UI/Components/TestView.js index 43baa52712..f92eacb2c4 100644 --- a/src/gui/src/UI/Components/TestView.js +++ b/src/gui/src/UI/Components/TestView.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const Component = use('util.Component'); /** diff --git a/src/gui/src/UI/Settings/UITabAccount.js b/src/gui/src/UI/Settings/UITabAccount.js index 0f2b9d8625..47a027d7c6 100644 --- a/src/gui/src/UI/Settings/UITabAccount.js +++ b/src/gui/src/UI/Settings/UITabAccount.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + import UIWindowChangePassword from '../UIWindowChangePassword.js'; import UIWindowChangeEmail from './UIWindowChangeEmail.js'; import UIWindowChangeUsername from '../UIWindowChangeUsername.js'; diff --git a/src/gui/src/UI/Settings/UITabClock.js b/src/gui/src/UI/Settings/UITabClock.js index 6e56c5c2de..e49530ee6a 100644 --- a/src/gui/src/UI/Settings/UITabClock.js +++ b/src/gui/src/UI/Settings/UITabClock.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + // About export default { id: 'clock', diff --git a/src/gui/src/UI/Settings/UITabLanguage.js b/src/gui/src/UI/Settings/UITabLanguage.js index 4af1c22490..fbea62a279 100644 --- a/src/gui/src/UI/Settings/UITabLanguage.js +++ b/src/gui/src/UI/Settings/UITabLanguage.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + import changeLanguage from '../../i18n/i18nChangeLanguage.js'; // About diff --git a/src/gui/src/UI/Settings/UITabPersonalization.js b/src/gui/src/UI/Settings/UITabPersonalization.js index 9672ad6b80..0c50464f7d 100644 --- a/src/gui/src/UI/Settings/UITabPersonalization.js +++ b/src/gui/src/UI/Settings/UITabPersonalization.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + import UIWindowThemeDialog from '../UIWindowThemeDialog.js'; import UIWindowDesktopBGSettings from '../UIWindowDesktopBGSettings.js'; diff --git a/src/gui/src/definitions.js b/src/gui/src/definitions.js index 9997341243..d738066b24 100644 --- a/src/gui/src/definitions.js +++ b/src/gui/src/definitions.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + export class Service { construct (o) { this.$puter = {}; diff --git a/src/gui/src/helpers/truncate_filename.js b/src/gui/src/helpers/truncate_filename.js index 5645e381a7..c8d51636e9 100644 --- a/src/gui/src/helpers/truncate_filename.js +++ b/src/gui/src/helpers/truncate_filename.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + import path from '../lib/path.js'; export const DEFAULT_TRUNCATE_LENGTH = 20; diff --git a/src/gui/src/i18n/i18n.js b/src/gui/src/i18n/i18n.js index 64410b7ba2..7b4f55cb48 100644 --- a/src/gui/src/i18n/i18n.js +++ b/src/gui/src/i18n/i18n.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + import translations from './translations/translations.js'; window.listSupportedLanguages = () => Object.keys(translations).map(lang => translations[lang]); diff --git a/src/gui/src/i18n/i18nChangeLanguage.js b/src/gui/src/i18n/i18nChangeLanguage.js index a5430f0cb9..9a10ab0a18 100644 --- a/src/gui/src/i18n/i18nChangeLanguage.js +++ b/src/gui/src/i18n/i18nChangeLanguage.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + function changeLanguage(lang) { window.locale = lang; window.mutate_user_preferences({ diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 9402320935..f21028ac7b 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const bn = { name: "বাংলা", english_name: "Bengali", diff --git a/src/gui/src/i18n/translations/br.js b/src/gui/src/i18n/translations/br.js index 1c8c0acf9d..e46761a821 100644 --- a/src/gui/src/i18n/translations/br.js +++ b/src/gui/src/i18n/translations/br.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const br = { name: "Português (Brasil)", english_name: "Portuguese (Brazil)", diff --git a/src/gui/src/i18n/translations/da.js b/src/gui/src/i18n/translations/da.js index be0934631d..bbba3ca423 100644 --- a/src/gui/src/i18n/translations/da.js +++ b/src/gui/src/i18n/translations/da.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const da = { name: "Dansk", english_name: "Danish", diff --git a/src/gui/src/i18n/translations/de.js b/src/gui/src/i18n/translations/de.js index ecd95e7b35..7b77e09b9b 100644 --- a/src/gui/src/i18n/translations/de.js +++ b/src/gui/src/i18n/translations/de.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const de = { name: "Deutsch", english_name: "German", diff --git a/src/gui/src/i18n/translations/emoji.js b/src/gui/src/i18n/translations/emoji.js index ad3017ab0b..04ac847ad7 100644 --- a/src/gui/src/i18n/translations/emoji.js +++ b/src/gui/src/i18n/translations/emoji.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const emoji = { name: "🌍", english_name: "Emoji", diff --git a/src/gui/src/i18n/translations/en.js b/src/gui/src/i18n/translations/en.js index 0d3a4f9567..f867e6aaa1 100644 --- a/src/gui/src/i18n/translations/en.js +++ b/src/gui/src/i18n/translations/en.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const en = { name: "English", english_name: "English", diff --git a/src/gui/src/i18n/translations/es.js b/src/gui/src/i18n/translations/es.js index bb94e51ee1..8ff49e19f4 100644 --- a/src/gui/src/i18n/translations/es.js +++ b/src/gui/src/i18n/translations/es.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const es = { name: "Español", english_name: "Spanish", diff --git a/src/gui/src/i18n/translations/fa.js b/src/gui/src/i18n/translations/fa.js index 9c71b0271f..dd8947451f 100644 --- a/src/gui/src/i18n/translations/fa.js +++ b/src/gui/src/i18n/translations/fa.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const fa = { name: "فارسی", english_name: "Farsi", diff --git a/src/gui/src/i18n/translations/fi.js b/src/gui/src/i18n/translations/fi.js index 4aaf96a296..887566193a 100644 --- a/src/gui/src/i18n/translations/fi.js +++ b/src/gui/src/i18n/translations/fi.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const fi = { name: "Suomi", english_name: "Finnish", diff --git a/src/gui/src/i18n/translations/fr.js b/src/gui/src/i18n/translations/fr.js index 5a4512b469..7cc30be810 100644 --- a/src/gui/src/i18n/translations/fr.js +++ b/src/gui/src/i18n/translations/fr.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const fr = { name: "Français", english_name: "French", diff --git a/src/gui/src/i18n/translations/hi.js b/src/gui/src/i18n/translations/hi.js index 7ea9a688c6..bfdaf7e91f 100644 --- a/src/gui/src/i18n/translations/hi.js +++ b/src/gui/src/i18n/translations/hi.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const hi = { name: "हिंदी", english_name: "hindi", diff --git a/src/gui/src/i18n/translations/hy.js b/src/gui/src/i18n/translations/hy.js index b5250cae46..e340f9cca3 100644 --- a/src/gui/src/i18n/translations/hy.js +++ b/src/gui/src/i18n/translations/hy.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const hy = { name: "Հայերեն", english_name: "Armenian", diff --git a/src/gui/src/i18n/translations/ig.js b/src/gui/src/i18n/translations/ig.js index e5e822e73e..7bc7e88c79 100644 --- a/src/gui/src/i18n/translations/ig.js +++ b/src/gui/src/i18n/translations/ig.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const ig = { name: "Igbo", english_name: "Igbo", diff --git a/src/gui/src/i18n/translations/it.js b/src/gui/src/i18n/translations/it.js index 0e40485aa6..a0c7fead13 100644 --- a/src/gui/src/i18n/translations/it.js +++ b/src/gui/src/i18n/translations/it.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const it = { name: "Italiano", english_name: "Italian", diff --git a/src/gui/src/i18n/translations/ko.js b/src/gui/src/i18n/translations/ko.js index 8c3e20fa8c..c9659f622f 100644 --- a/src/gui/src/i18n/translations/ko.js +++ b/src/gui/src/i18n/translations/ko.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const ko = { name: "한국어", english_name: "Korean", diff --git a/src/gui/src/i18n/translations/nb.js b/src/gui/src/i18n/translations/nb.js index 3901711af7..191e0bef5a 100644 --- a/src/gui/src/i18n/translations/nb.js +++ b/src/gui/src/i18n/translations/nb.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const nb = { name: "Norsk Bokmål", english_name: "Norwegian Bokmål", diff --git a/src/gui/src/i18n/translations/nl.js b/src/gui/src/i18n/translations/nl.js index f141d77213..d02da55d23 100644 --- a/src/gui/src/i18n/translations/nl.js +++ b/src/gui/src/i18n/translations/nl.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const nl = { name: "Nederlands", english_name: "Dutch", diff --git a/src/gui/src/i18n/translations/nn.js b/src/gui/src/i18n/translations/nn.js index e11cf6ea19..1f323609dc 100644 --- a/src/gui/src/i18n/translations/nn.js +++ b/src/gui/src/i18n/translations/nn.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const nn = { name: "Norsk Nynorsk", english_name: "Norwegian Nynorsk", diff --git a/src/gui/src/i18n/translations/pl.js b/src/gui/src/i18n/translations/pl.js index 8c27a617ef..631dafc553 100644 --- a/src/gui/src/i18n/translations/pl.js +++ b/src/gui/src/i18n/translations/pl.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const pl = { name: "Polski", english_name: "Polish", diff --git a/src/gui/src/i18n/translations/pt.js b/src/gui/src/i18n/translations/pt.js index b41c1eb48c..32ebbbf586 100644 --- a/src/gui/src/i18n/translations/pt.js +++ b/src/gui/src/i18n/translations/pt.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const pt = { name: "Português", english_name: "Portuguese", diff --git a/src/gui/src/i18n/translations/ro.js b/src/gui/src/i18n/translations/ro.js index e381105705..7cd7c9361a 100644 --- a/src/gui/src/i18n/translations/ro.js +++ b/src/gui/src/i18n/translations/ro.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const ro = { name: "Română", english_name: "Romanian", diff --git a/src/gui/src/i18n/translations/ru.js b/src/gui/src/i18n/translations/ru.js index 678febb9f8..34802e926d 100644 --- a/src/gui/src/i18n/translations/ru.js +++ b/src/gui/src/i18n/translations/ru.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const ru = { name: "Русский", english_name: "Russian", diff --git a/src/gui/src/i18n/translations/sv.js b/src/gui/src/i18n/translations/sv.js index b682a086c6..ea88c573b7 100644 --- a/src/gui/src/i18n/translations/sv.js +++ b/src/gui/src/i18n/translations/sv.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const sv = { name: "Svenska", english_name: "Swedish", diff --git a/src/gui/src/i18n/translations/th.js b/src/gui/src/i18n/translations/th.js index 13521ecffb..4d391ba393 100644 --- a/src/gui/src/i18n/translations/th.js +++ b/src/gui/src/i18n/translations/th.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const th = { name: "ไทย", english_name: "Thai", diff --git a/src/gui/src/i18n/translations/tr.js b/src/gui/src/i18n/translations/tr.js index ce9d1ab194..0e1a29f689 100644 --- a/src/gui/src/i18n/translations/tr.js +++ b/src/gui/src/i18n/translations/tr.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const tr = { name: "Türkçe", english_name: "Turkish", diff --git a/src/gui/src/i18n/translations/translations.js b/src/gui/src/i18n/translations/translations.js index f64a1c5321..1abbd95a90 100644 --- a/src/gui/src/i18n/translations/translations.js +++ b/src/gui/src/i18n/translations/translations.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + import ar from './ar.js'; import bn from './bn.js'; import br from './br.js'; diff --git a/src/gui/src/i18n/translations/ua.js b/src/gui/src/i18n/translations/ua.js index 59fa3bee4c..ee521f5663 100644 --- a/src/gui/src/i18n/translations/ua.js +++ b/src/gui/src/i18n/translations/ua.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const ua = { name: "Українська", english_name: "Ukrainian", diff --git a/src/gui/src/i18n/translations/ur.js b/src/gui/src/i18n/translations/ur.js index a9596518a2..8b48be53bb 100644 --- a/src/gui/src/i18n/translations/ur.js +++ b/src/gui/src/i18n/translations/ur.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const ur = { name: "اردو", english_name: "Urdu", diff --git a/src/gui/src/i18n/translations/zh.js b/src/gui/src/i18n/translations/zh.js index 6928b04fb1..7c5646d309 100644 --- a/src/gui/src/i18n/translations/zh.js +++ b/src/gui/src/i18n/translations/zh.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + const zh = { name: "中文", english_name: "Chinese", diff --git a/src/gui/src/i18n/translations/zhtw.js b/src/gui/src/i18n/translations/zhtw.js index 6e6c0e57cb..276284d440 100644 --- a/src/gui/src/i18n/translations/zhtw.js +++ b/src/gui/src/i18n/translations/zhtw.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + const zhtw = { name: "繁體中文", english_name: "Traditional Chinese", diff --git a/src/gui/src/index.js b/src/gui/src/index.js index 60a3c1d991..450cff7982 100644 --- a/src/gui/src/index.js +++ b/src/gui/src/index.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + window.puter_gui_enabled = true; /** diff --git a/src/gui/src/initgui.js b/src/gui/src/initgui.js index 863dba03ba..a4ed477b86 100644 --- a/src/gui/src/initgui.js +++ b/src/gui/src/initgui.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -35,6 +17,7 @@ * along with this program. If not, see . */ + import UIDesktop from './UI/UIDesktop.js' import UIWindow from './UI/UIWindow.js' import UIAlert from './UI/UIAlert.js' diff --git a/src/gui/src/services/BroadcastService.js b/src/gui/src/services/BroadcastService.js index 836b0c697f..21bb9dfeb6 100644 --- a/src/gui/src/services/BroadcastService.js +++ b/src/gui/src/services/BroadcastService.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + import { Service } from "../definitions.js"; export class BroadcastService extends Service { diff --git a/src/gui/src/services/ThemeService.js b/src/gui/src/services/ThemeService.js index e1f6c0b5c8..b49d41e684 100644 --- a/src/gui/src/services/ThemeService.js +++ b/src/gui/src/services/ThemeService.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * @@ -34,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ + import UIAlert from "../UI/UIAlert.js"; import { Service } from "../definitions.js"; From f5a8ee1c6ab950d62c90b6257791f026a508b4e4 Mon Sep 17 00:00:00 2001 From: micheledinelli Date: Tue, 9 Jul 2024 16:55:45 +0200 Subject: [PATCH 0485/2119] Completing Italian translation based on English file --- src/gui/src/i18n/translations/it.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/it.js b/src/gui/src/i18n/translations/it.js index 0c45b0e598..183c5abf0b 100644 --- a/src/gui/src/i18n/translations/it.js +++ b/src/gui/src/i18n/translations/it.js @@ -45,7 +45,7 @@ const it = { account_password: "Verifica Account Password", access_granted_to: "Accesso garantito a", add_existing_account: "Aggiungi un account esistente", - all_fields_required: "Tutte i campi sono richiesti.", + all_fields_required: "Tutti i campi sono richiesti.", allow: "Consenti", apply: "Applica", ascending: 'Ascendente', From 1d52a559ffadafacbd1c14373012f2dc3958bf43 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 9 Jul 2024 08:14:33 -0700 Subject: [PATCH 0486/2119] Remove more duplicate license headers --- src/dev-center/css/style.css | 18 ------------------ src/dev-center/js/dev-center.js | 18 ------------------ src/dev-center/js/html-entities.js | 18 ------------------ src/dev-center/js/jquery-3.6.0.min.js | 18 ------------------ src/dev-center/js/jquery.dragster.js | 18 ------------------ src/dev-center/js/slugify.js | 19 ------------------- src/gui/src/IPC.js | 18 ------------------ src/gui/src/UI/PuterDialog.js | 18 ------------------ src/gui/src/UI/Settings/UITabAbout.js | 18 ------------------ src/gui/src/UI/Settings/UITabUsage.js | 18 ------------------ .../src/UI/Settings/UIWindowChangeEmail.js | 18 ------------------ .../Settings/UIWindowConfirmUserDeletion.js | 18 ------------------ .../Settings/UIWindowFinalizeUserDeletion.js | 18 ------------------ src/gui/src/UI/Settings/UIWindowSettings.js | 18 ------------------ src/gui/src/UI/UIAlert.js | 18 ------------------ src/gui/src/UI/UIContextMenu.js | 18 ------------------ src/gui/src/UI/UIDesktop.js | 18 ------------------ src/gui/src/UI/UIItem.js | 18 ------------------ src/gui/src/UI/UINotification.js | 18 ------------------ src/gui/src/UI/UIPopover.js | 18 ------------------ src/gui/src/UI/UIPrompt.js | 18 ------------------ src/gui/src/UI/UITaskbar.js | 18 ------------------ src/gui/src/UI/UITaskbarItem.js | 18 ------------------ src/gui/src/UI/UIWindow.js | 18 ------------------ src/gui/src/UI/UIWindowChangePassword.js | 18 ------------------ src/gui/src/UI/UIWindowChangeUsername.js | 18 ------------------ src/gui/src/UI/UIWindowClaimReferral.js | 18 ------------------ src/gui/src/UI/UIWindowColorPicker.js | 18 ------------------ src/gui/src/UI/UIWindowDesktopBGSettings.js | 18 ------------------ .../UI/UIWindowEmailConfirmationRequired.js | 18 ------------------ src/gui/src/UI/UIWindowFeedback.js | 18 ------------------ src/gui/src/UI/UIWindowFontPicker.js | 18 ------------------ src/gui/src/UI/UIWindowItemProperties.js | 18 ------------------ src/gui/src/UI/UIWindowLogin.js | 18 ------------------ src/gui/src/UI/UIWindowLoginInProgress.js | 18 ------------------ src/gui/src/UI/UIWindowMyWebsites.js | 18 ------------------ src/gui/src/UI/UIWindowNewPassword.js | 18 ------------------ src/gui/src/UI/UIWindowProgress.js | 18 ------------------ src/gui/src/UI/UIWindowPublishWebsite.js | 18 ------------------ src/gui/src/UI/UIWindowQR.js | 18 ------------------ src/gui/src/UI/UIWindowRecoverPassword.js | 18 ------------------ src/gui/src/UI/UIWindowRefer.js | 18 ------------------ src/gui/src/UI/UIWindowRequestPermission.js | 18 ------------------ src/gui/src/UI/UIWindowSaveAccount.js | 18 ------------------ src/gui/src/UI/UIWindowSessionList.js | 18 ------------------ src/gui/src/UI/UIWindowSignup.js | 18 ------------------ src/gui/src/css/style.css | 18 ------------------ src/gui/src/globals.js | 18 ------------------ src/gui/src/helpers.js | 18 ------------------ .../src/helpers/check_password_strength.js | 18 ------------------ src/gui/src/helpers/content_type_to_icon.js | 18 ------------------ .../determine_active_container_parent.js | 18 ------------------ src/gui/src/helpers/download.js | 18 ------------------ .../src/helpers/fixedEncodeURIComponent.js | 18 ------------------ .../helpers/get_html_element_from_options.js | 18 ------------------ src/gui/src/helpers/globToRegExp.js | 18 ------------------ src/gui/src/helpers/item_icon.js | 18 ------------------ src/gui/src/helpers/launch_app.js | 18 ------------------ src/gui/src/helpers/new_context_menu_item.js | 18 ------------------ src/gui/src/helpers/open_item.js | 18 ------------------ src/gui/src/helpers/refresh_item_container.js | 18 ------------------ src/gui/src/helpers/socialLink.js | 18 ------------------ .../helpers/update_last_touch_coordinates.js | 18 ------------------ src/gui/src/helpers/update_mouse_position.js | 18 ------------------ .../helpers/update_title_based_on_uploads.js | 18 ------------------ src/gui/src/helpers/update_username_in_gui.js | 18 ------------------ src/gui/src/keyboard.js | 18 ------------------ src/gui/src/static-assets.js | 18 ------------------ 68 files changed, 1225 deletions(-) diff --git a/src/dev-center/css/style.css b/src/dev-center/css/style.css index 62e7871cfe..e4c7a4ba5b 100644 --- a/src/dev-center/css/style.css +++ b/src/dev-center/css/style.css @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/dev-center/js/dev-center.js b/src/dev-center/js/dev-center.js index 0c4b8c7dfc..5a677f3f1a 100644 --- a/src/dev-center/js/dev-center.js +++ b/src/dev-center/js/dev-center.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/dev-center/js/html-entities.js b/src/dev-center/js/html-entities.js index 4f26dfbad3..c233cb01ee 100644 --- a/src/dev-center/js/html-entities.js +++ b/src/dev-center/js/html-entities.js @@ -1,19 +1 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ (()=>{"use strict";var r,e={563:function(r,e,a){var t=this&&this.__assign||function(){return(t=Object.assign||function(r){for(var e,a=1,t=arguments.length;a'"&]/g,nonAscii:/(?:[<>'"&\u0080-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/g,nonAsciiPrintable:/(?:[<>'"&\x01-\x08\x11-\x15\x17-\x1F\x7f-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/g,extensive:/(?:[\x01-\x0c\x0e-\x1f\x21-\x2c\x2e-\x2f\x3a-\x40\x5b-\x60\x7b-\x7d\x7f-\uD7FF\uE000-\uFFFF]|[\uD800-\uDBFF][\uDC00-\uDFFF]|[\uD800-\uDBFF](?![\uDC00-\uDFFF])|(?:[^\uD800-\uDBFF]|^)[\uDC00-\uDFFF])/g},n={mode:"specialChars",level:"all",numeric:"decimal"};e.encode=function(r,e){var a=void 0===(u=(c=void 0===e?n:e).mode)?"specialChars":u,t=void 0===(m=c.numeric)?"decimal":m,o=c.level;if(!r)return"";var c,u,p=i[a],d=s[void 0===o?"all":o].characters,g="hexadecimal"===t;if(p.lastIndex=0,c=p.exec(r)){u="";var m=0;do{m!==c.index&&(u+=r.substring(m,c.index));var f=d[o=c[0]];if(!f){var h=o.length>1?l.getCodePoint(o,0):o.charCodeAt(0);f=(g?"&#x"+h.toString(16):"&#"+h)+";"}u+=f,m=c.index+o.length}while(c=p.exec(r));m!==r.length&&(u+=r.substring(m))}else u=r;return u};var u={scope:"body",level:"all"},p=/&(?:#\d+|#[xX][\da-fA-F]+|[0-9a-zA-Z]+);/g,d=/&(?:#\d+|#[xX][\da-fA-F]+|[0-9a-zA-Z]+)[;=]?/g,g={xml:{strict:p,attribute:d,body:o.bodyRegExps.xml},html4:{strict:p,attribute:d,body:o.bodyRegExps.html4},html5:{strict:p,attribute:d,body:o.bodyRegExps.html5}},m=t(t({},g),{all:g.html5}),f=String.fromCharCode,h=f(65533),b={level:"all"};e.decodeEntity=function(r,e){var a=void 0===(t=(void 0===e?b:e).level)?"all":t;if(!r)return"";var t=r,o=(r[r.length-1],s[a].entities[r]);if(o)t=o;else if("&"===r[0]&&"#"===r[1]){var i=r[2],n="x"==i||"X"==i?parseInt(r.substr(3),16):parseInt(r.substr(2));t=n>=1114111?h:n>65535?l.fromCodePoint(n):f(c.numericUnicodeMap[n]||n)}return t},e.decode=function(r,e){var a=void 0===e?u:e,t=a.level,o=void 0===t?"all":t,i=a.scope,n=void 0===i?"xml"===o?"strict":"body":i;if(!r)return"";var p=m[o][n],d=s[o].entities,g="attribute"===n,b="strict"===n;p.lastIndex=0;var v,q=p.exec(r);if(q){v="";var y=0;do{y!==q.index&&(v+=r.substring(y,q.index));var w=q[0],x=w,A=w[w.length-1];if(g&&"="===A)x=w;else if(b&&";"!==A)x=w;else{var E=d[w];if(E)x=E;else if("&"===w[0]&&"#"===w[1]){var D=w[2],k="x"==D||"X"==D?parseInt(w.substr(3),16):parseInt(w.substr(2));x=k>=1114111?h:k>65535?l.fromCodePoint(k):f(c.numericUnicodeMap[k]||k)}}v+=x,y=q.index+w.length}while(q=p.exec(r));y!==r.length&&(v+=r.substring(y))}else v=r;return v}},81:(r,e)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.bodyRegExps={xml:/&(?:#\d+|#[xX][\da-fA-F]+|[0-9a-zA-Z]+);?/g,html4:/&(?:nbsp|iexcl|cent|pound|curren|yen|brvbar|sect|uml|copy|ordf|laquo|not|shy|reg|macr|deg|plusmn|sup2|sup3|acute|micro|para|middot|cedil|sup1|ordm|raquo|frac14|frac12|frac34|iquest|Agrave|Aacute|Acirc|Atilde|Auml|Aring|AElig|Ccedil|Egrave|Eacute|Ecirc|Euml|Igrave|Iacute|Icirc|Iuml|ETH|Ntilde|Ograve|Oacute|Ocirc|Otilde|Ouml|times|Oslash|Ugrave|Uacute|Ucirc|Uuml|Yacute|THORN|szlig|agrave|aacute|acirc|atilde|auml|aring|aelig|ccedil|egrave|eacute|ecirc|euml|igrave|iacute|icirc|iuml|eth|ntilde|ograve|oacute|ocirc|otilde|ouml|divide|oslash|ugrave|uacute|ucirc|uuml|yacute|thorn|yuml|quot|amp|lt|gt|#\d+|#[xX][\da-fA-F]+|[0-9a-zA-Z]+);?/g,html5:/&(?:AElig|AMP|Aacute|Acirc|Agrave|Aring|Atilde|Auml|COPY|Ccedil|ETH|Eacute|Ecirc|Egrave|Euml|GT|Iacute|Icirc|Igrave|Iuml|LT|Ntilde|Oacute|Ocirc|Ograve|Oslash|Otilde|Ouml|QUOT|REG|THORN|Uacute|Ucirc|Ugrave|Uuml|Yacute|aacute|acirc|acute|aelig|agrave|amp|aring|atilde|auml|brvbar|ccedil|cedil|cent|copy|curren|deg|divide|eacute|ecirc|egrave|eth|euml|frac12|frac14|frac34|gt|iacute|icirc|iexcl|igrave|iquest|iuml|laquo|lt|macr|micro|middot|nbsp|not|ntilde|oacute|ocirc|ograve|ordf|ordm|oslash|otilde|ouml|para|plusmn|pound|quot|raquo|reg|sect|shy|sup1|sup2|sup3|szlig|thorn|times|uacute|ucirc|ugrave|uml|uuml|yacute|yen|yuml|#\d+|#[xX][\da-fA-F]+|[0-9a-zA-Z]+);?/g},e.namedReferences={xml:{entities:{"<":"<",">":">",""":'"',"'":"'","&":"&"},characters:{"<":"<",">":">",'"':""","'":"'","&":"&"}},html4:{entities:{"'":"'"," ":" "," ":" ","¡":"¡","¡":"¡","¢":"¢","¢":"¢","£":"£","£":"£","¤":"¤","¤":"¤","¥":"¥","¥":"¥","¦":"¦","¦":"¦","§":"§","§":"§","¨":"¨","¨":"¨","©":"©","©":"©","ª":"ª","ª":"ª","«":"«","«":"«","¬":"¬","¬":"¬","­":"­","­":"­","®":"®","®":"®","¯":"¯","¯":"¯","°":"°","°":"°","±":"±","±":"±","²":"²","²":"²","³":"³","³":"³","´":"´","´":"´","µ":"µ","µ":"µ","¶":"¶","¶":"¶","·":"·","·":"·","¸":"¸","¸":"¸","¹":"¹","¹":"¹","º":"º","º":"º","»":"»","»":"»","¼":"¼","¼":"¼","½":"½","½":"½","¾":"¾","¾":"¾","¿":"¿","¿":"¿","À":"À","À":"À","Á":"Á","Á":"Á","Â":"Â","Â":"Â","Ã":"Ã","Ã":"Ã","Ä":"Ä","Ä":"Ä","Å":"Å","Å":"Å","Æ":"Æ","Æ":"Æ","Ç":"Ç","Ç":"Ç","È":"È","È":"È","É":"É","É":"É","Ê":"Ê","Ê":"Ê","Ë":"Ë","Ë":"Ë","Ì":"Ì","Ì":"Ì","Í":"Í","Í":"Í","Î":"Î","Î":"Î","Ï":"Ï","Ï":"Ï","Ð":"Ð","Ð":"Ð","Ñ":"Ñ","Ñ":"Ñ","Ò":"Ò","Ò":"Ò","Ó":"Ó","Ó":"Ó","Ô":"Ô","Ô":"Ô","Õ":"Õ","Õ":"Õ","Ö":"Ö","Ö":"Ö","×":"×","×":"×","Ø":"Ø","Ø":"Ø","Ù":"Ù","Ù":"Ù","Ú":"Ú","Ú":"Ú","Û":"Û","Û":"Û","Ü":"Ü","Ü":"Ü","Ý":"Ý","Ý":"Ý","Þ":"Þ","Þ":"Þ","ß":"ß","ß":"ß","à":"à","à":"à","á":"á","á":"á","â":"â","â":"â","ã":"ã","ã":"ã","ä":"ä","ä":"ä","å":"å","å":"å","æ":"æ","æ":"æ","ç":"ç","ç":"ç","è":"è","è":"è","é":"é","é":"é","ê":"ê","ê":"ê","ë":"ë","ë":"ë","ì":"ì","ì":"ì","í":"í","í":"í","î":"î","î":"î","ï":"ï","ï":"ï","ð":"ð","ð":"ð","ñ":"ñ","ñ":"ñ","ò":"ò","ò":"ò","ó":"ó","ó":"ó","ô":"ô","ô":"ô","õ":"õ","õ":"õ","ö":"ö","ö":"ö","÷":"÷","÷":"÷","ø":"ø","ø":"ø","ù":"ù","ù":"ù","ú":"ú","ú":"ú","û":"û","û":"û","ü":"ü","ü":"ü","ý":"ý","ý":"ý","þ":"þ","þ":"þ","ÿ":"ÿ","ÿ":"ÿ",""":'"',""":'"',"&":"&","&":"&","<":"<","<":"<",">":">",">":">","Œ":"Œ","œ":"œ","Š":"Š","š":"š","Ÿ":"Ÿ","ˆ":"ˆ","˜":"˜"," ":" "," ":" "," ":" ","‌":"‌","‍":"‍","‎":"‎","‏":"‏","–":"–","—":"—","‘":"‘","’":"’","‚":"‚","“":"“","”":"”","„":"„","†":"†","‡":"‡","‰":"‰","‹":"‹","›":"›","€":"€","ƒ":"ƒ","Α":"Α","Β":"Β","Γ":"Γ","Δ":"Δ","Ε":"Ε","Ζ":"Ζ","Η":"Η","Θ":"Θ","Ι":"Ι","Κ":"Κ","Λ":"Λ","Μ":"Μ","Ν":"Ν","Ξ":"Ξ","Ο":"Ο","Π":"Π","Ρ":"Ρ","Σ":"Σ","Τ":"Τ","Υ":"Υ","Φ":"Φ","Χ":"Χ","Ψ":"Ψ","Ω":"Ω","α":"α","β":"β","γ":"γ","δ":"δ","ε":"ε","ζ":"ζ","η":"η","θ":"θ","ι":"ι","κ":"κ","λ":"λ","μ":"μ","ν":"ν","ξ":"ξ","ο":"ο","π":"π","ρ":"ρ","ς":"ς","σ":"σ","τ":"τ","υ":"υ","φ":"φ","χ":"χ","ψ":"ψ","ω":"ω","ϑ":"ϑ","ϒ":"ϒ","ϖ":"ϖ","•":"•","…":"…","′":"′","″":"″","‾":"‾","⁄":"⁄","℘":"℘","ℑ":"ℑ","ℜ":"ℜ","™":"™","ℵ":"ℵ","←":"←","↑":"↑","→":"→","↓":"↓","↔":"↔","↵":"↵","⇐":"⇐","⇑":"⇑","⇒":"⇒","⇓":"⇓","⇔":"⇔","∀":"∀","∂":"∂","∃":"∃","∅":"∅","∇":"∇","∈":"∈","∉":"∉","∋":"∋","∏":"∏","∑":"∑","−":"−","∗":"∗","√":"√","∝":"∝","∞":"∞","∠":"∠","∧":"∧","∨":"∨","∩":"∩","∪":"∪","∫":"∫","∴":"∴","∼":"∼","≅":"≅","≈":"≈","≠":"≠","≡":"≡","≤":"≤","≥":"≥","⊂":"⊂","⊃":"⊃","⊄":"⊄","⊆":"⊆","⊇":"⊇","⊕":"⊕","⊗":"⊗","⊥":"⊥","⋅":"⋅","⌈":"⌈","⌉":"⌉","⌊":"⌊","⌋":"⌋","⟨":"〈","⟩":"〉","◊":"◊","♠":"♠","♣":"♣","♥":"♥","♦":"♦"},characters:{"'":"'"," ":" ","¡":"¡","¢":"¢","£":"£","¤":"¤","¥":"¥","¦":"¦","§":"§","¨":"¨","©":"©",ª:"ª","«":"«","¬":"¬","­":"­","®":"®","¯":"¯","°":"°","±":"±","²":"²","³":"³","´":"´",µ:"µ","¶":"¶","·":"·","¸":"¸","¹":"¹",º:"º","»":"»","¼":"¼","½":"½","¾":"¾","¿":"¿",À:"À",Á:"Á",Â:"Â",Ã:"Ã",Ä:"Ä",Å:"Å",Æ:"Æ",Ç:"Ç",È:"È",É:"É",Ê:"Ê",Ë:"Ë",Ì:"Ì",Í:"Í",Î:"Î",Ï:"Ï",Ð:"Ð",Ñ:"Ñ",Ò:"Ò",Ó:"Ó",Ô:"Ô",Õ:"Õ",Ö:"Ö","×":"×",Ø:"Ø",Ù:"Ù",Ú:"Ú",Û:"Û",Ü:"Ü",Ý:"Ý",Þ:"Þ",ß:"ß",à:"à",á:"á",â:"â",ã:"ã",ä:"ä",å:"å",æ:"æ",ç:"ç",è:"è",é:"é",ê:"ê",ë:"ë",ì:"ì",í:"í",î:"î",ï:"ï",ð:"ð",ñ:"ñ",ò:"ò",ó:"ó",ô:"ô",õ:"õ",ö:"ö","÷":"÷",ø:"ø",ù:"ù",ú:"ú",û:"û",ü:"ü",ý:"ý",þ:"þ",ÿ:"ÿ",'"':""","&":"&","<":"<",">":">",Œ:"Œ",œ:"œ",Š:"Š",š:"š",Ÿ:"Ÿ",ˆ:"ˆ","˜":"˜"," ":" "," ":" "," ":" ","‌":"‌","‍":"‍","‎":"‎","‏":"‏","–":"–","—":"—","‘":"‘","’":"’","‚":"‚","“":"“","”":"”","„":"„","†":"†","‡":"‡","‰":"‰","‹":"‹","›":"›","€":"€",ƒ:"ƒ",Α:"Α",Β:"Β",Γ:"Γ",Δ:"Δ",Ε:"Ε",Ζ:"Ζ",Η:"Η",Θ:"Θ",Ι:"Ι",Κ:"Κ",Λ:"Λ",Μ:"Μ",Ν:"Ν",Ξ:"Ξ",Ο:"Ο",Π:"Π",Ρ:"Ρ",Σ:"Σ",Τ:"Τ",Υ:"Υ",Φ:"Φ",Χ:"Χ",Ψ:"Ψ",Ω:"Ω",α:"α",β:"β",γ:"γ",δ:"δ",ε:"ε",ζ:"ζ",η:"η",θ:"θ",ι:"ι",κ:"κ",λ:"λ",μ:"μ",ν:"ν",ξ:"ξ",ο:"ο",π:"π",ρ:"ρ",ς:"ς",σ:"σ",τ:"τ",υ:"υ",φ:"φ",χ:"χ",ψ:"ψ",ω:"ω",ϑ:"ϑ",ϒ:"ϒ",ϖ:"ϖ","•":"•","…":"…","′":"′","″":"″","‾":"‾","⁄":"⁄",℘:"℘",ℑ:"ℑ",ℜ:"ℜ","™":"™",ℵ:"ℵ","←":"←","↑":"↑","→":"→","↓":"↓","↔":"↔","↵":"↵","⇐":"⇐","⇑":"⇑","⇒":"⇒","⇓":"⇓","⇔":"⇔","∀":"∀","∂":"∂","∃":"∃","∅":"∅","∇":"∇","∈":"∈","∉":"∉","∋":"∋","∏":"∏","∑":"∑","−":"−","∗":"∗","√":"√","∝":"∝","∞":"∞","∠":"∠","∧":"∧","∨":"∨","∩":"∩","∪":"∪","∫":"∫","∴":"∴","∼":"∼","≅":"≅","≈":"≈","≠":"≠","≡":"≡","≤":"≤","≥":"≥","⊂":"⊂","⊃":"⊃","⊄":"⊄","⊆":"⊆","⊇":"⊇","⊕":"⊕","⊗":"⊗","⊥":"⊥","⋅":"⋅","⌈":"⌈","⌉":"⌉","⌊":"⌊","⌋":"⌋","〈":"⟨","〉":"⟩","◊":"◊","♠":"♠","♣":"♣","♥":"♥","♦":"♦"}},html5:{entities:{"Æ":"Æ","Æ":"Æ","&":"&","&":"&","Á":"Á","Á":"Á","Ă":"Ă","Â":"Â","Â":"Â","А":"А","𝔄":"𝔄","À":"À","À":"À","Α":"Α","Ā":"Ā","⩓":"⩓","Ą":"Ą","𝔸":"𝔸","⁡":"⁡","Å":"Å","Å":"Å","𝒜":"𝒜","≔":"≔","Ã":"Ã","Ã":"Ã","Ä":"Ä","Ä":"Ä","∖":"∖","⫧":"⫧","⌆":"⌆","Б":"Б","∵":"∵","ℬ":"ℬ","Β":"Β","𝔅":"𝔅","𝔹":"𝔹","˘":"˘","ℬ":"ℬ","≎":"≎","Ч":"Ч","©":"©","©":"©","Ć":"Ć","⋒":"⋒","ⅅ":"ⅅ","ℭ":"ℭ","Č":"Č","Ç":"Ç","Ç":"Ç","Ĉ":"Ĉ","∰":"∰","Ċ":"Ċ","¸":"¸","·":"·","ℭ":"ℭ","Χ":"Χ","⊙":"⊙","⊖":"⊖","⊕":"⊕","⊗":"⊗","∲":"∲","”":"”","’":"’","∷":"∷","⩴":"⩴","≡":"≡","∯":"∯","∮":"∮","ℂ":"ℂ","∐":"∐","∳":"∳","⨯":"⨯","𝒞":"𝒞","⋓":"⋓","≍":"≍","ⅅ":"ⅅ","⤑":"⤑","Ђ":"Ђ","Ѕ":"Ѕ","Џ":"Џ","‡":"‡","↡":"↡","⫤":"⫤","Ď":"Ď","Д":"Д","∇":"∇","Δ":"Δ","𝔇":"𝔇","´":"´","˙":"˙","˝":"˝","`":"`","˜":"˜","⋄":"⋄","ⅆ":"ⅆ","𝔻":"𝔻","¨":"¨","⃜":"⃜","≐":"≐","∯":"∯","¨":"¨","⇓":"⇓","⇐":"⇐","⇔":"⇔","⫤":"⫤","⟸":"⟸","⟺":"⟺","⟹":"⟹","⇒":"⇒","⊨":"⊨","⇑":"⇑","⇕":"⇕","∥":"∥","↓":"↓","⤓":"⤓","⇵":"⇵","̑":"̑","⥐":"⥐","⥞":"⥞","↽":"↽","⥖":"⥖","⥟":"⥟","⇁":"⇁","⥗":"⥗","⊤":"⊤","↧":"↧","⇓":"⇓","𝒟":"𝒟","Đ":"Đ","Ŋ":"Ŋ","Ð":"Ð","Ð":"Ð","É":"É","É":"É","Ě":"Ě","Ê":"Ê","Ê":"Ê","Э":"Э","Ė":"Ė","𝔈":"𝔈","È":"È","È":"È","∈":"∈","Ē":"Ē","◻":"◻","▫":"▫","Ę":"Ę","𝔼":"𝔼","Ε":"Ε","⩵":"⩵","≂":"≂","⇌":"⇌","ℰ":"ℰ","⩳":"⩳","Η":"Η","Ë":"Ë","Ë":"Ë","∃":"∃","ⅇ":"ⅇ","Ф":"Ф","𝔉":"𝔉","◼":"◼","▪":"▪","𝔽":"𝔽","∀":"∀","ℱ":"ℱ","ℱ":"ℱ","Ѓ":"Ѓ",">":">",">":">","Γ":"Γ","Ϝ":"Ϝ","Ğ":"Ğ","Ģ":"Ģ","Ĝ":"Ĝ","Г":"Г","Ġ":"Ġ","𝔊":"𝔊","⋙":"⋙","𝔾":"𝔾","≥":"≥","⋛":"⋛","≧":"≧","⪢":"⪢","≷":"≷","⩾":"⩾","≳":"≳","𝒢":"𝒢","≫":"≫","Ъ":"Ъ","ˇ":"ˇ","^":"^","Ĥ":"Ĥ","ℌ":"ℌ","ℋ":"ℋ","ℍ":"ℍ","─":"─","ℋ":"ℋ","Ħ":"Ħ","≎":"≎","≏":"≏","Е":"Е","IJ":"IJ","Ё":"Ё","Í":"Í","Í":"Í","Î":"Î","Î":"Î","И":"И","İ":"İ","ℑ":"ℑ","Ì":"Ì","Ì":"Ì","ℑ":"ℑ","Ī":"Ī","ⅈ":"ⅈ","⇒":"⇒","∬":"∬","∫":"∫","⋂":"⋂","⁣":"⁣","⁢":"⁢","Į":"Į","𝕀":"𝕀","Ι":"Ι","ℐ":"ℐ","Ĩ":"Ĩ","І":"І","Ï":"Ï","Ï":"Ï","Ĵ":"Ĵ","Й":"Й","𝔍":"𝔍","𝕁":"𝕁","𝒥":"𝒥","Ј":"Ј","Є":"Є","Х":"Х","Ќ":"Ќ","Κ":"Κ","Ķ":"Ķ","К":"К","𝔎":"𝔎","𝕂":"𝕂","𝒦":"𝒦","Љ":"Љ","<":"<","<":"<","Ĺ":"Ĺ","Λ":"Λ","⟪":"⟪","ℒ":"ℒ","↞":"↞","Ľ":"Ľ","Ļ":"Ļ","Л":"Л","⟨":"⟨","←":"←","⇤":"⇤","⇆":"⇆","⌈":"⌈","⟦":"⟦","⥡":"⥡","⇃":"⇃","⥙":"⥙","⌊":"⌊","↔":"↔","⥎":"⥎","⊣":"⊣","↤":"↤","⥚":"⥚","⊲":"⊲","⧏":"⧏","⊴":"⊴","⥑":"⥑","⥠":"⥠","↿":"↿","⥘":"⥘","↼":"↼","⥒":"⥒","⇐":"⇐","⇔":"⇔","⋚":"⋚","≦":"≦","≶":"≶","⪡":"⪡","⩽":"⩽","≲":"≲","𝔏":"𝔏","⋘":"⋘","⇚":"⇚","Ŀ":"Ŀ","⟵":"⟵","⟷":"⟷","⟶":"⟶","⟸":"⟸","⟺":"⟺","⟹":"⟹","𝕃":"𝕃","↙":"↙","↘":"↘","ℒ":"ℒ","↰":"↰","Ł":"Ł","≪":"≪","⤅":"⤅","М":"М"," ":" ","ℳ":"ℳ","𝔐":"𝔐","∓":"∓","𝕄":"𝕄","ℳ":"ℳ","Μ":"Μ","Њ":"Њ","Ń":"Ń","Ň":"Ň","Ņ":"Ņ","Н":"Н","​":"​","​":"​","​":"​","​":"​","≫":"≫","≪":"≪"," ":"\n","𝔑":"𝔑","⁠":"⁠"," ":" ","ℕ":"ℕ","⫬":"⫬","≢":"≢","≭":"≭","∦":"∦","∉":"∉","≠":"≠","≂̸":"≂̸","∄":"∄","≯":"≯","≱":"≱","≧̸":"≧̸","≫̸":"≫̸","≹":"≹","⩾̸":"⩾̸","≵":"≵","≎̸":"≎̸","≏̸":"≏̸","⋪":"⋪","⧏̸":"⧏̸","⋬":"⋬","≮":"≮","≰":"≰","≸":"≸","≪̸":"≪̸","⩽̸":"⩽̸","≴":"≴","⪢̸":"⪢̸","⪡̸":"⪡̸","⊀":"⊀","⪯̸":"⪯̸","⋠":"⋠","∌":"∌","⋫":"⋫","⧐̸":"⧐̸","⋭":"⋭","⊏̸":"⊏̸","⋢":"⋢","⊐̸":"⊐̸","⋣":"⋣","⊂⃒":"⊂⃒","⊈":"⊈","⊁":"⊁","⪰̸":"⪰̸","⋡":"⋡","≿̸":"≿̸","⊃⃒":"⊃⃒","⊉":"⊉","≁":"≁","≄":"≄","≇":"≇","≉":"≉","∤":"∤","𝒩":"𝒩","Ñ":"Ñ","Ñ":"Ñ","Ν":"Ν","Œ":"Œ","Ó":"Ó","Ó":"Ó","Ô":"Ô","Ô":"Ô","О":"О","Ő":"Ő","𝔒":"𝔒","Ò":"Ò","Ò":"Ò","Ō":"Ō","Ω":"Ω","Ο":"Ο","𝕆":"𝕆","“":"“","‘":"‘","⩔":"⩔","𝒪":"𝒪","Ø":"Ø","Ø":"Ø","Õ":"Õ","Õ":"Õ","⨷":"⨷","Ö":"Ö","Ö":"Ö","‾":"‾","⏞":"⏞","⎴":"⎴","⏜":"⏜","∂":"∂","П":"П","𝔓":"𝔓","Φ":"Φ","Π":"Π","±":"±","ℌ":"ℌ","ℙ":"ℙ","⪻":"⪻","≺":"≺","⪯":"⪯","≼":"≼","≾":"≾","″":"″","∏":"∏","∷":"∷","∝":"∝","𝒫":"𝒫","Ψ":"Ψ",""":'"',""":'"',"𝔔":"𝔔","ℚ":"ℚ","𝒬":"𝒬","⤐":"⤐","®":"®","®":"®","Ŕ":"Ŕ","⟫":"⟫","↠":"↠","⤖":"⤖","Ř":"Ř","Ŗ":"Ŗ","Р":"Р","ℜ":"ℜ","∋":"∋","⇋":"⇋","⥯":"⥯","ℜ":"ℜ","Ρ":"Ρ","⟩":"⟩","→":"→","⇥":"⇥","⇄":"⇄","⌉":"⌉","⟧":"⟧","⥝":"⥝","⇂":"⇂","⥕":"⥕","⌋":"⌋","⊢":"⊢","↦":"↦","⥛":"⥛","⊳":"⊳","⧐":"⧐","⊵":"⊵","⥏":"⥏","⥜":"⥜","↾":"↾","⥔":"⥔","⇀":"⇀","⥓":"⥓","⇒":"⇒","ℝ":"ℝ","⥰":"⥰","⇛":"⇛","ℛ":"ℛ","↱":"↱","⧴":"⧴","Щ":"Щ","Ш":"Ш","Ь":"Ь","Ś":"Ś","⪼":"⪼","Š":"Š","Ş":"Ş","Ŝ":"Ŝ","С":"С","𝔖":"𝔖","↓":"↓","←":"←","→":"→","↑":"↑","Σ":"Σ","∘":"∘","𝕊":"𝕊","√":"√","□":"□","⊓":"⊓","⊏":"⊏","⊑":"⊑","⊐":"⊐","⊒":"⊒","⊔":"⊔","𝒮":"𝒮","⋆":"⋆","⋐":"⋐","⋐":"⋐","⊆":"⊆","≻":"≻","⪰":"⪰","≽":"≽","≿":"≿","∋":"∋","∑":"∑","⋑":"⋑","⊃":"⊃","⊇":"⊇","⋑":"⋑","Þ":"Þ","Þ":"Þ","™":"™","Ћ":"Ћ","Ц":"Ц"," ":"\t","Τ":"Τ","Ť":"Ť","Ţ":"Ţ","Т":"Т","𝔗":"𝔗","∴":"∴","Θ":"Θ","  ":"  "," ":" ","∼":"∼","≃":"≃","≅":"≅","≈":"≈","𝕋":"𝕋","⃛":"⃛","𝒯":"𝒯","Ŧ":"Ŧ","Ú":"Ú","Ú":"Ú","↟":"↟","⥉":"⥉","Ў":"Ў","Ŭ":"Ŭ","Û":"Û","Û":"Û","У":"У","Ű":"Ű","𝔘":"𝔘","Ù":"Ù","Ù":"Ù","Ū":"Ū","_":"_","⏟":"⏟","⎵":"⎵","⏝":"⏝","⋃":"⋃","⊎":"⊎","Ų":"Ų","𝕌":"𝕌","↑":"↑","⤒":"⤒","⇅":"⇅","↕":"↕","⥮":"⥮","⊥":"⊥","↥":"↥","⇑":"⇑","⇕":"⇕","↖":"↖","↗":"↗","ϒ":"ϒ","Υ":"Υ","Ů":"Ů","𝒰":"𝒰","Ũ":"Ũ","Ü":"Ü","Ü":"Ü","⊫":"⊫","⫫":"⫫","В":"В","⊩":"⊩","⫦":"⫦","⋁":"⋁","‖":"‖","‖":"‖","∣":"∣","|":"|","❘":"❘","≀":"≀"," ":" ","𝔙":"𝔙","𝕍":"𝕍","𝒱":"𝒱","⊪":"⊪","Ŵ":"Ŵ","⋀":"⋀","𝔚":"𝔚","𝕎":"𝕎","𝒲":"𝒲","𝔛":"𝔛","Ξ":"Ξ","𝕏":"𝕏","𝒳":"𝒳","Я":"Я","Ї":"Ї","Ю":"Ю","Ý":"Ý","Ý":"Ý","Ŷ":"Ŷ","Ы":"Ы","𝔜":"𝔜","𝕐":"𝕐","𝒴":"𝒴","Ÿ":"Ÿ","Ж":"Ж","Ź":"Ź","Ž":"Ž","З":"З","Ż":"Ż","​":"​","Ζ":"Ζ","ℨ":"ℨ","ℤ":"ℤ","𝒵":"𝒵","á":"á","á":"á","ă":"ă","∾":"∾","∾̳":"∾̳","∿":"∿","â":"â","â":"â","´":"´","´":"´","а":"а","æ":"æ","æ":"æ","⁡":"⁡","𝔞":"𝔞","à":"à","à":"à","ℵ":"ℵ","ℵ":"ℵ","α":"α","ā":"ā","⨿":"⨿","&":"&","&":"&","∧":"∧","⩕":"⩕","⩜":"⩜","⩘":"⩘","⩚":"⩚","∠":"∠","⦤":"⦤","∠":"∠","∡":"∡","⦨":"⦨","⦩":"⦩","⦪":"⦪","⦫":"⦫","⦬":"⦬","⦭":"⦭","⦮":"⦮","⦯":"⦯","∟":"∟","⊾":"⊾","⦝":"⦝","∢":"∢","Å":"Å","⍼":"⍼","ą":"ą","𝕒":"𝕒","≈":"≈","⩰":"⩰","⩯":"⩯","≊":"≊","≋":"≋","'":"'","≈":"≈","≊":"≊","å":"å","å":"å","𝒶":"𝒶","*":"*","≈":"≈","≍":"≍","ã":"ã","ã":"ã","ä":"ä","ä":"ä","∳":"∳","⨑":"⨑","⫭":"⫭","≌":"≌","϶":"϶","‵":"‵","∽":"∽","⋍":"⋍","⊽":"⊽","⌅":"⌅","⌅":"⌅","⎵":"⎵","⎶":"⎶","≌":"≌","б":"б","„":"„","∵":"∵","∵":"∵","⦰":"⦰","϶":"϶","ℬ":"ℬ","β":"β","ℶ":"ℶ","≬":"≬","𝔟":"𝔟","⋂":"⋂","◯":"◯","⋃":"⋃","⨀":"⨀","⨁":"⨁","⨂":"⨂","⨆":"⨆","★":"★","▽":"▽","△":"△","⨄":"⨄","⋁":"⋁","⋀":"⋀","⤍":"⤍","⧫":"⧫","▪":"▪","▴":"▴","▾":"▾","◂":"◂","▸":"▸","␣":"␣","▒":"▒","░":"░","▓":"▓","█":"█","=⃥":"=⃥","≡⃥":"≡⃥","⌐":"⌐","𝕓":"𝕓","⊥":"⊥","⊥":"⊥","⋈":"⋈","╗":"╗","╔":"╔","╖":"╖","╓":"╓","═":"═","╦":"╦","╩":"╩","╤":"╤","╧":"╧","╝":"╝","╚":"╚","╜":"╜","╙":"╙","║":"║","╬":"╬","╣":"╣","╠":"╠","╫":"╫","╢":"╢","╟":"╟","⧉":"⧉","╕":"╕","╒":"╒","┐":"┐","┌":"┌","─":"─","╥":"╥","╨":"╨","┬":"┬","┴":"┴","⊟":"⊟","⊞":"⊞","⊠":"⊠","╛":"╛","╘":"╘","┘":"┘","└":"└","│":"│","╪":"╪","╡":"╡","╞":"╞","┼":"┼","┤":"┤","├":"├","‵":"‵","˘":"˘","¦":"¦","¦":"¦","𝒷":"𝒷","⁏":"⁏","∽":"∽","⋍":"⋍","\":"\\","⧅":"⧅","⟈":"⟈","•":"•","•":"•","≎":"≎","⪮":"⪮","≏":"≏","≏":"≏","ć":"ć","∩":"∩","⩄":"⩄","⩉":"⩉","⩋":"⩋","⩇":"⩇","⩀":"⩀","∩︀":"∩︀","⁁":"⁁","ˇ":"ˇ","⩍":"⩍","č":"č","ç":"ç","ç":"ç","ĉ":"ĉ","⩌":"⩌","⩐":"⩐","ċ":"ċ","¸":"¸","¸":"¸","⦲":"⦲","¢":"¢","¢":"¢","·":"·","𝔠":"𝔠","ч":"ч","✓":"✓","✓":"✓","χ":"χ","○":"○","⧃":"⧃","ˆ":"ˆ","≗":"≗","↺":"↺","↻":"↻","®":"®","Ⓢ":"Ⓢ","⊛":"⊛","⊚":"⊚","⊝":"⊝","≗":"≗","⨐":"⨐","⫯":"⫯","⧂":"⧂","♣":"♣","♣":"♣",":":":","≔":"≔","≔":"≔",",":",","@":"@","∁":"∁","∘":"∘","∁":"∁","ℂ":"ℂ","≅":"≅","⩭":"⩭","∮":"∮","𝕔":"𝕔","∐":"∐","©":"©","©":"©","℗":"℗","↵":"↵","✗":"✗","𝒸":"𝒸","⫏":"⫏","⫑":"⫑","⫐":"⫐","⫒":"⫒","⋯":"⋯","⤸":"⤸","⤵":"⤵","⋞":"⋞","⋟":"⋟","↶":"↶","⤽":"⤽","∪":"∪","⩈":"⩈","⩆":"⩆","⩊":"⩊","⊍":"⊍","⩅":"⩅","∪︀":"∪︀","↷":"↷","⤼":"⤼","⋞":"⋞","⋟":"⋟","⋎":"⋎","⋏":"⋏","¤":"¤","¤":"¤","↶":"↶","↷":"↷","⋎":"⋎","⋏":"⋏","∲":"∲","∱":"∱","⌭":"⌭","⇓":"⇓","⥥":"⥥","†":"†","ℸ":"ℸ","↓":"↓","‐":"‐","⊣":"⊣","⤏":"⤏","˝":"˝","ď":"ď","д":"д","ⅆ":"ⅆ","‡":"‡","⇊":"⇊","⩷":"⩷","°":"°","°":"°","δ":"δ","⦱":"⦱","⥿":"⥿","𝔡":"𝔡","⇃":"⇃","⇂":"⇂","⋄":"⋄","⋄":"⋄","♦":"♦","♦":"♦","¨":"¨","ϝ":"ϝ","⋲":"⋲","÷":"÷","÷":"÷","÷":"÷","⋇":"⋇","⋇":"⋇","ђ":"ђ","⌞":"⌞","⌍":"⌍","$":"$","𝕕":"𝕕","˙":"˙","≐":"≐","≑":"≑","∸":"∸","∔":"∔","⊡":"⊡","⌆":"⌆","↓":"↓","⇊":"⇊","⇃":"⇃","⇂":"⇂","⤐":"⤐","⌟":"⌟","⌌":"⌌","𝒹":"𝒹","ѕ":"ѕ","⧶":"⧶","đ":"đ","⋱":"⋱","▿":"▿","▾":"▾","⇵":"⇵","⥯":"⥯","⦦":"⦦","џ":"џ","⟿":"⟿","⩷":"⩷","≑":"≑","é":"é","é":"é","⩮":"⩮","ě":"ě","≖":"≖","ê":"ê","ê":"ê","≕":"≕","э":"э","ė":"ė","ⅇ":"ⅇ","≒":"≒","𝔢":"𝔢","⪚":"⪚","è":"è","è":"è","⪖":"⪖","⪘":"⪘","⪙":"⪙","⏧":"⏧","ℓ":"ℓ","⪕":"⪕","⪗":"⪗","ē":"ē","∅":"∅","∅":"∅","∅":"∅"," ":" "," ":" "," ":" ","ŋ":"ŋ"," ":" ","ę":"ę","𝕖":"𝕖","⋕":"⋕","⧣":"⧣","⩱":"⩱","ε":"ε","ε":"ε","ϵ":"ϵ","≖":"≖","≕":"≕","≂":"≂","⪖":"⪖","⪕":"⪕","=":"=","≟":"≟","≡":"≡","⩸":"⩸","⧥":"⧥","≓":"≓","⥱":"⥱","ℯ":"ℯ","≐":"≐","≂":"≂","η":"η","ð":"ð","ð":"ð","ë":"ë","ë":"ë","€":"€","!":"!","∃":"∃","ℰ":"ℰ","ⅇ":"ⅇ","≒":"≒","ф":"ф","♀":"♀","ffi":"ffi","ff":"ff","ffl":"ffl","𝔣":"𝔣","fi":"fi","fj":"fj","♭":"♭","fl":"fl","▱":"▱","ƒ":"ƒ","𝕗":"𝕗","∀":"∀","⋔":"⋔","⫙":"⫙","⨍":"⨍","½":"½","½":"½","⅓":"⅓","¼":"¼","¼":"¼","⅕":"⅕","⅙":"⅙","⅛":"⅛","⅔":"⅔","⅖":"⅖","¾":"¾","¾":"¾","⅗":"⅗","⅜":"⅜","⅘":"⅘","⅚":"⅚","⅝":"⅝","⅞":"⅞","⁄":"⁄","⌢":"⌢","𝒻":"𝒻","≧":"≧","⪌":"⪌","ǵ":"ǵ","γ":"γ","ϝ":"ϝ","⪆":"⪆","ğ":"ğ","ĝ":"ĝ","г":"г","ġ":"ġ","≥":"≥","⋛":"⋛","≥":"≥","≧":"≧","⩾":"⩾","⩾":"⩾","⪩":"⪩","⪀":"⪀","⪂":"⪂","⪄":"⪄","⋛︀":"⋛︀","⪔":"⪔","𝔤":"𝔤","≫":"≫","⋙":"⋙","ℷ":"ℷ","ѓ":"ѓ","≷":"≷","⪒":"⪒","⪥":"⪥","⪤":"⪤","≩":"≩","⪊":"⪊","⪊":"⪊","⪈":"⪈","⪈":"⪈","≩":"≩","⋧":"⋧","𝕘":"𝕘","`":"`","ℊ":"ℊ","≳":"≳","⪎":"⪎","⪐":"⪐",">":">",">":">","⪧":"⪧","⩺":"⩺","⋗":"⋗","⦕":"⦕","⩼":"⩼","⪆":"⪆","⥸":"⥸","⋗":"⋗","⋛":"⋛","⪌":"⪌","≷":"≷","≳":"≳","≩︀":"≩︀","≩︀":"≩︀","⇔":"⇔"," ":" ","½":"½","ℋ":"ℋ","ъ":"ъ","↔":"↔","⥈":"⥈","↭":"↭","ℏ":"ℏ","ĥ":"ĥ","♥":"♥","♥":"♥","…":"…","⊹":"⊹","𝔥":"𝔥","⤥":"⤥","⤦":"⤦","⇿":"⇿","∻":"∻","↩":"↩","↪":"↪","𝕙":"𝕙","―":"―","𝒽":"𝒽","ℏ":"ℏ","ħ":"ħ","⁃":"⁃","‐":"‐","í":"í","í":"í","⁣":"⁣","î":"î","î":"î","и":"и","е":"е","¡":"¡","¡":"¡","⇔":"⇔","𝔦":"𝔦","ì":"ì","ì":"ì","ⅈ":"ⅈ","⨌":"⨌","∭":"∭","⧜":"⧜","℩":"℩","ij":"ij","ī":"ī","ℑ":"ℑ","ℐ":"ℐ","ℑ":"ℑ","ı":"ı","⊷":"⊷","Ƶ":"Ƶ","∈":"∈","℅":"℅","∞":"∞","⧝":"⧝","ı":"ı","∫":"∫","⊺":"⊺","ℤ":"ℤ","⊺":"⊺","⨗":"⨗","⨼":"⨼","ё":"ё","į":"į","𝕚":"𝕚","ι":"ι","⨼":"⨼","¿":"¿","¿":"¿","𝒾":"𝒾","∈":"∈","⋹":"⋹","⋵":"⋵","⋴":"⋴","⋳":"⋳","∈":"∈","⁢":"⁢","ĩ":"ĩ","і":"і","ï":"ï","ï":"ï","ĵ":"ĵ","й":"й","𝔧":"𝔧","ȷ":"ȷ","𝕛":"𝕛","𝒿":"𝒿","ј":"ј","є":"є","κ":"κ","ϰ":"ϰ","ķ":"ķ","к":"к","𝔨":"𝔨","ĸ":"ĸ","х":"х","ќ":"ќ","𝕜":"𝕜","𝓀":"𝓀","⇚":"⇚","⇐":"⇐","⤛":"⤛","⤎":"⤎","≦":"≦","⪋":"⪋","⥢":"⥢","ĺ":"ĺ","⦴":"⦴","ℒ":"ℒ","λ":"λ","⟨":"⟨","⦑":"⦑","⟨":"⟨","⪅":"⪅","«":"«","«":"«","←":"←","⇤":"⇤","⤟":"⤟","⤝":"⤝","↩":"↩","↫":"↫","⤹":"⤹","⥳":"⥳","↢":"↢","⪫":"⪫","⤙":"⤙","⪭":"⪭","⪭︀":"⪭︀","⤌":"⤌","❲":"❲","{":"{","[":"[","⦋":"⦋","⦏":"⦏","⦍":"⦍","ľ":"ľ","ļ":"ļ","⌈":"⌈","{":"{","л":"л","⤶":"⤶","“":"“","„":"„","⥧":"⥧","⥋":"⥋","↲":"↲","≤":"≤","←":"←","↢":"↢","↽":"↽","↼":"↼","⇇":"⇇","↔":"↔","⇆":"⇆","⇋":"⇋","↭":"↭","⋋":"⋋","⋚":"⋚","≤":"≤","≦":"≦","⩽":"⩽","⩽":"⩽","⪨":"⪨","⩿":"⩿","⪁":"⪁","⪃":"⪃","⋚︀":"⋚︀","⪓":"⪓","⪅":"⪅","⋖":"⋖","⋚":"⋚","⪋":"⪋","≶":"≶","≲":"≲","⥼":"⥼","⌊":"⌊","𝔩":"𝔩","≶":"≶","⪑":"⪑","↽":"↽","↼":"↼","⥪":"⥪","▄":"▄","љ":"љ","≪":"≪","⇇":"⇇","⌞":"⌞","⥫":"⥫","◺":"◺","ŀ":"ŀ","⎰":"⎰","⎰":"⎰","≨":"≨","⪉":"⪉","⪉":"⪉","⪇":"⪇","⪇":"⪇","≨":"≨","⋦":"⋦","⟬":"⟬","⇽":"⇽","⟦":"⟦","⟵":"⟵","⟷":"⟷","⟼":"⟼","⟶":"⟶","↫":"↫","↬":"↬","⦅":"⦅","𝕝":"𝕝","⨭":"⨭","⨴":"⨴","∗":"∗","_":"_","◊":"◊","◊":"◊","⧫":"⧫","(":"(","⦓":"⦓","⇆":"⇆","⌟":"⌟","⇋":"⇋","⥭":"⥭","‎":"‎","⊿":"⊿","‹":"‹","𝓁":"𝓁","↰":"↰","≲":"≲","⪍":"⪍","⪏":"⪏","[":"[","‘":"‘","‚":"‚","ł":"ł","<":"<","<":"<","⪦":"⪦","⩹":"⩹","⋖":"⋖","⋋":"⋋","⋉":"⋉","⥶":"⥶","⩻":"⩻","⦖":"⦖","◃":"◃","⊴":"⊴","◂":"◂","⥊":"⥊","⥦":"⥦","≨︀":"≨︀","≨︀":"≨︀","∺":"∺","¯":"¯","¯":"¯","♂":"♂","✠":"✠","✠":"✠","↦":"↦","↦":"↦","↧":"↧","↤":"↤","↥":"↥","▮":"▮","⨩":"⨩","м":"м","—":"—","∡":"∡","𝔪":"𝔪","℧":"℧","µ":"µ","µ":"µ","∣":"∣","*":"*","⫰":"⫰","·":"·","·":"·","−":"−","⊟":"⊟","∸":"∸","⨪":"⨪","⫛":"⫛","…":"…","∓":"∓","⊧":"⊧","𝕞":"𝕞","∓":"∓","𝓂":"𝓂","∾":"∾","μ":"μ","⊸":"⊸","⊸":"⊸","⋙̸":"⋙̸","≫⃒":"≫⃒","≫̸":"≫̸","⇍":"⇍","⇎":"⇎","⋘̸":"⋘̸","≪⃒":"≪⃒","≪̸":"≪̸","⇏":"⇏","⊯":"⊯","⊮":"⊮","∇":"∇","ń":"ń","∠⃒":"∠⃒","≉":"≉","⩰̸":"⩰̸","≋̸":"≋̸","ʼn":"ʼn","≉":"≉","♮":"♮","♮":"♮","ℕ":"ℕ"," ":" "," ":" ","≎̸":"≎̸","≏̸":"≏̸","⩃":"⩃","ň":"ň","ņ":"ņ","≇":"≇","⩭̸":"⩭̸","⩂":"⩂","н":"н","–":"–","≠":"≠","⇗":"⇗","⤤":"⤤","↗":"↗","↗":"↗","≐̸":"≐̸","≢":"≢","⤨":"⤨","≂̸":"≂̸","∄":"∄","∄":"∄","𝔫":"𝔫","≧̸":"≧̸","≱":"≱","≱":"≱","≧̸":"≧̸","⩾̸":"⩾̸","⩾̸":"⩾̸","≵":"≵","≯":"≯","≯":"≯","⇎":"⇎","↮":"↮","⫲":"⫲","∋":"∋","⋼":"⋼","⋺":"⋺","∋":"∋","њ":"њ","⇍":"⇍","≦̸":"≦̸","↚":"↚","‥":"‥","≰":"≰","↚":"↚","↮":"↮","≰":"≰","≦̸":"≦̸","⩽̸":"⩽̸","⩽̸":"⩽̸","≮":"≮","≴":"≴","≮":"≮","⋪":"⋪","⋬":"⋬","∤":"∤","𝕟":"𝕟","¬":"¬","¬":"¬","∉":"∉","⋹̸":"⋹̸","⋵̸":"⋵̸","∉":"∉","⋷":"⋷","⋶":"⋶","∌":"∌","∌":"∌","⋾":"⋾","⋽":"⋽","∦":"∦","∦":"∦","⫽⃥":"⫽⃥","∂̸":"∂̸","⨔":"⨔","⊀":"⊀","⋠":"⋠","⪯̸":"⪯̸","⊀":"⊀","⪯̸":"⪯̸","⇏":"⇏","↛":"↛","⤳̸":"⤳̸","↝̸":"↝̸","↛":"↛","⋫":"⋫","⋭":"⋭","⊁":"⊁","⋡":"⋡","⪰̸":"⪰̸","𝓃":"𝓃","∤":"∤","∦":"∦","≁":"≁","≄":"≄","≄":"≄","∤":"∤","∦":"∦","⋢":"⋢","⋣":"⋣","⊄":"⊄","⫅̸":"⫅̸","⊈":"⊈","⊂⃒":"⊂⃒","⊈":"⊈","⫅̸":"⫅̸","⊁":"⊁","⪰̸":"⪰̸","⊅":"⊅","⫆̸":"⫆̸","⊉":"⊉","⊃⃒":"⊃⃒","⊉":"⊉","⫆̸":"⫆̸","≹":"≹","ñ":"ñ","ñ":"ñ","≸":"≸","⋪":"⋪","⋬":"⋬","⋫":"⋫","⋭":"⋭","ν":"ν","#":"#","№":"№"," ":" ","⊭":"⊭","⤄":"⤄","≍⃒":"≍⃒","⊬":"⊬","≥⃒":"≥⃒",">⃒":">⃒","⧞":"⧞","⤂":"⤂","≤⃒":"≤⃒","<⃒":"<⃒","⊴⃒":"⊴⃒","⤃":"⤃","⊵⃒":"⊵⃒","∼⃒":"∼⃒","⇖":"⇖","⤣":"⤣","↖":"↖","↖":"↖","⤧":"⤧","Ⓢ":"Ⓢ","ó":"ó","ó":"ó","⊛":"⊛","⊚":"⊚","ô":"ô","ô":"ô","о":"о","⊝":"⊝","ő":"ő","⨸":"⨸","⊙":"⊙","⦼":"⦼","œ":"œ","⦿":"⦿","𝔬":"𝔬","˛":"˛","ò":"ò","ò":"ò","⧁":"⧁","⦵":"⦵","Ω":"Ω","∮":"∮","↺":"↺","⦾":"⦾","⦻":"⦻","‾":"‾","⧀":"⧀","ō":"ō","ω":"ω","ο":"ο","⦶":"⦶","⊖":"⊖","𝕠":"𝕠","⦷":"⦷","⦹":"⦹","⊕":"⊕","∨":"∨","↻":"↻","⩝":"⩝","ℴ":"ℴ","ℴ":"ℴ","ª":"ª","ª":"ª","º":"º","º":"º","⊶":"⊶","⩖":"⩖","⩗":"⩗","⩛":"⩛","ℴ":"ℴ","ø":"ø","ø":"ø","⊘":"⊘","õ":"õ","õ":"õ","⊗":"⊗","⨶":"⨶","ö":"ö","ö":"ö","⌽":"⌽","∥":"∥","¶":"¶","¶":"¶","∥":"∥","⫳":"⫳","⫽":"⫽","∂":"∂","п":"п","%":"%",".":".","‰":"‰","⊥":"⊥","‱":"‱","𝔭":"𝔭","φ":"φ","ϕ":"ϕ","ℳ":"ℳ","☎":"☎","π":"π","⋔":"⋔","ϖ":"ϖ","ℏ":"ℏ","ℎ":"ℎ","ℏ":"ℏ","+":"+","⨣":"⨣","⊞":"⊞","⨢":"⨢","∔":"∔","⨥":"⨥","⩲":"⩲","±":"±","±":"±","⨦":"⨦","⨧":"⨧","±":"±","⨕":"⨕","𝕡":"𝕡","£":"£","£":"£","≺":"≺","⪳":"⪳","⪷":"⪷","≼":"≼","⪯":"⪯","≺":"≺","⪷":"⪷","≼":"≼","⪯":"⪯","⪹":"⪹","⪵":"⪵","⋨":"⋨","≾":"≾","′":"′","ℙ":"ℙ","⪵":"⪵","⪹":"⪹","⋨":"⋨","∏":"∏","⌮":"⌮","⌒":"⌒","⌓":"⌓","∝":"∝","∝":"∝","≾":"≾","⊰":"⊰","𝓅":"𝓅","ψ":"ψ"," ":" ","𝔮":"𝔮","⨌":"⨌","𝕢":"𝕢","⁗":"⁗","𝓆":"𝓆","ℍ":"ℍ","⨖":"⨖","?":"?","≟":"≟",""":'"',""":'"',"⇛":"⇛","⇒":"⇒","⤜":"⤜","⤏":"⤏","⥤":"⥤","∽̱":"∽̱","ŕ":"ŕ","√":"√","⦳":"⦳","⟩":"⟩","⦒":"⦒","⦥":"⦥","⟩":"⟩","»":"»","»":"»","→":"→","⥵":"⥵","⇥":"⇥","⤠":"⤠","⤳":"⤳","⤞":"⤞","↪":"↪","↬":"↬","⥅":"⥅","⥴":"⥴","↣":"↣","↝":"↝","⤚":"⤚","∶":"∶","ℚ":"ℚ","⤍":"⤍","❳":"❳","}":"}","]":"]","⦌":"⦌","⦎":"⦎","⦐":"⦐","ř":"ř","ŗ":"ŗ","⌉":"⌉","}":"}","р":"р","⤷":"⤷","⥩":"⥩","”":"”","”":"”","↳":"↳","ℜ":"ℜ","ℛ":"ℛ","ℜ":"ℜ","ℝ":"ℝ","▭":"▭","®":"®","®":"®","⥽":"⥽","⌋":"⌋","𝔯":"𝔯","⇁":"⇁","⇀":"⇀","⥬":"⥬","ρ":"ρ","ϱ":"ϱ","→":"→","↣":"↣","⇁":"⇁","⇀":"⇀","⇄":"⇄","⇌":"⇌","⇉":"⇉","↝":"↝","⋌":"⋌","˚":"˚","≓":"≓","⇄":"⇄","⇌":"⇌","‏":"‏","⎱":"⎱","⎱":"⎱","⫮":"⫮","⟭":"⟭","⇾":"⇾","⟧":"⟧","⦆":"⦆","𝕣":"𝕣","⨮":"⨮","⨵":"⨵",")":")","⦔":"⦔","⨒":"⨒","⇉":"⇉","›":"›","𝓇":"𝓇","↱":"↱","]":"]","’":"’","’":"’","⋌":"⋌","⋊":"⋊","▹":"▹","⊵":"⊵","▸":"▸","⧎":"⧎","⥨":"⥨","℞":"℞","ś":"ś","‚":"‚","≻":"≻","⪴":"⪴","⪸":"⪸","š":"š","≽":"≽","⪰":"⪰","ş":"ş","ŝ":"ŝ","⪶":"⪶","⪺":"⪺","⋩":"⋩","⨓":"⨓","≿":"≿","с":"с","⋅":"⋅","⊡":"⊡","⩦":"⩦","⇘":"⇘","⤥":"⤥","↘":"↘","↘":"↘","§":"§","§":"§",";":";","⤩":"⤩","∖":"∖","∖":"∖","✶":"✶","𝔰":"𝔰","⌢":"⌢","♯":"♯","щ":"щ","ш":"ш","∣":"∣","∥":"∥","­":"­","­":"­","σ":"σ","ς":"ς","ς":"ς","∼":"∼","⩪":"⩪","≃":"≃","≃":"≃","⪞":"⪞","⪠":"⪠","⪝":"⪝","⪟":"⪟","≆":"≆","⨤":"⨤","⥲":"⥲","←":"←","∖":"∖","⨳":"⨳","⧤":"⧤","∣":"∣","⌣":"⌣","⪪":"⪪","⪬":"⪬","⪬︀":"⪬︀","ь":"ь","/":"/","⧄":"⧄","⌿":"⌿","𝕤":"𝕤","♠":"♠","♠":"♠","∥":"∥","⊓":"⊓","⊓︀":"⊓︀","⊔":"⊔","⊔︀":"⊔︀","⊏":"⊏","⊑":"⊑","⊏":"⊏","⊑":"⊑","⊐":"⊐","⊒":"⊒","⊐":"⊐","⊒":"⊒","□":"□","□":"□","▪":"▪","▪":"▪","→":"→","𝓈":"𝓈","∖":"∖","⌣":"⌣","⋆":"⋆","☆":"☆","★":"★","ϵ":"ϵ","ϕ":"ϕ","¯":"¯","⊂":"⊂","⫅":"⫅","⪽":"⪽","⊆":"⊆","⫃":"⫃","⫁":"⫁","⫋":"⫋","⊊":"⊊","⪿":"⪿","⥹":"⥹","⊂":"⊂","⊆":"⊆","⫅":"⫅","⊊":"⊊","⫋":"⫋","⫇":"⫇","⫕":"⫕","⫓":"⫓","≻":"≻","⪸":"⪸","≽":"≽","⪰":"⪰","⪺":"⪺","⪶":"⪶","⋩":"⋩","≿":"≿","∑":"∑","♪":"♪","¹":"¹","¹":"¹","²":"²","²":"²","³":"³","³":"³","⊃":"⊃","⫆":"⫆","⪾":"⪾","⫘":"⫘","⊇":"⊇","⫄":"⫄","⟉":"⟉","⫗":"⫗","⥻":"⥻","⫂":"⫂","⫌":"⫌","⊋":"⊋","⫀":"⫀","⊃":"⊃","⊇":"⊇","⫆":"⫆","⊋":"⊋","⫌":"⫌","⫈":"⫈","⫔":"⫔","⫖":"⫖","⇙":"⇙","⤦":"⤦","↙":"↙","↙":"↙","⤪":"⤪","ß":"ß","ß":"ß","⌖":"⌖","τ":"τ","⎴":"⎴","ť":"ť","ţ":"ţ","т":"т","⃛":"⃛","⌕":"⌕","𝔱":"𝔱","∴":"∴","∴":"∴","θ":"θ","ϑ":"ϑ","ϑ":"ϑ","≈":"≈","∼":"∼"," ":" ","≈":"≈","∼":"∼","þ":"þ","þ":"þ","˜":"˜","×":"×","×":"×","⊠":"⊠","⨱":"⨱","⨰":"⨰","∭":"∭","⤨":"⤨","⊤":"⊤","⌶":"⌶","⫱":"⫱","𝕥":"𝕥","⫚":"⫚","⤩":"⤩","‴":"‴","™":"™","▵":"▵","▿":"▿","◃":"◃","⊴":"⊴","≜":"≜","▹":"▹","⊵":"⊵","◬":"◬","≜":"≜","⨺":"⨺","⨹":"⨹","⧍":"⧍","⨻":"⨻","⏢":"⏢","𝓉":"𝓉","ц":"ц","ћ":"ћ","ŧ":"ŧ","≬":"≬","↞":"↞","↠":"↠","⇑":"⇑","⥣":"⥣","ú":"ú","ú":"ú","↑":"↑","ў":"ў","ŭ":"ŭ","û":"û","û":"û","у":"у","⇅":"⇅","ű":"ű","⥮":"⥮","⥾":"⥾","𝔲":"𝔲","ù":"ù","ù":"ù","↿":"↿","↾":"↾","▀":"▀","⌜":"⌜","⌜":"⌜","⌏":"⌏","◸":"◸","ū":"ū","¨":"¨","¨":"¨","ų":"ų","𝕦":"𝕦","↑":"↑","↕":"↕","↿":"↿","↾":"↾","⊎":"⊎","υ":"υ","ϒ":"ϒ","υ":"υ","⇈":"⇈","⌝":"⌝","⌝":"⌝","⌎":"⌎","ů":"ů","◹":"◹","𝓊":"𝓊","⋰":"⋰","ũ":"ũ","▵":"▵","▴":"▴","⇈":"⇈","ü":"ü","ü":"ü","⦧":"⦧","⇕":"⇕","⫨":"⫨","⫩":"⫩","⊨":"⊨","⦜":"⦜","ϵ":"ϵ","ϰ":"ϰ","∅":"∅","ϕ":"ϕ","ϖ":"ϖ","∝":"∝","↕":"↕","ϱ":"ϱ","ς":"ς","⊊︀":"⊊︀","⫋︀":"⫋︀","⊋︀":"⊋︀","⫌︀":"⫌︀","ϑ":"ϑ","⊲":"⊲","⊳":"⊳","в":"в","⊢":"⊢","∨":"∨","⊻":"⊻","≚":"≚","⋮":"⋮","|":"|","|":"|","𝔳":"𝔳","⊲":"⊲","⊂⃒":"⊂⃒","⊃⃒":"⊃⃒","𝕧":"𝕧","∝":"∝","⊳":"⊳","𝓋":"𝓋","⫋︀":"⫋︀","⊊︀":"⊊︀","⫌︀":"⫌︀","⊋︀":"⊋︀","⦚":"⦚","ŵ":"ŵ","⩟":"⩟","∧":"∧","≙":"≙","℘":"℘","𝔴":"𝔴","𝕨":"𝕨","℘":"℘","≀":"≀","≀":"≀","𝓌":"𝓌","⋂":"⋂","◯":"◯","⋃":"⋃","▽":"▽","𝔵":"𝔵","⟺":"⟺","⟷":"⟷","ξ":"ξ","⟸":"⟸","⟵":"⟵","⟼":"⟼","⋻":"⋻","⨀":"⨀","𝕩":"𝕩","⨁":"⨁","⨂":"⨂","⟹":"⟹","⟶":"⟶","𝓍":"𝓍","⨆":"⨆","⨄":"⨄","△":"△","⋁":"⋁","⋀":"⋀","ý":"ý","ý":"ý","я":"я","ŷ":"ŷ","ы":"ы","¥":"¥","¥":"¥","𝔶":"𝔶","ї":"ї","𝕪":"𝕪","𝓎":"𝓎","ю":"ю","ÿ":"ÿ","ÿ":"ÿ","ź":"ź","ž":"ž","з":"з","ż":"ż","ℨ":"ℨ","ζ":"ζ","𝔷":"𝔷","ж":"ж","⇝":"⇝","𝕫":"𝕫","𝓏":"𝓏","‍":"‍","‌":"‌"},characters:{Æ:"Æ","&":"&",Á:"Á",Ă:"Ă",Â:"Â",А:"А",𝔄:"𝔄",À:"À",Α:"Α",Ā:"Ā","⩓":"⩓",Ą:"Ą",𝔸:"𝔸","⁡":"⁡",Å:"Å",𝒜:"𝒜","≔":"≔",Ã:"Ã",Ä:"Ä","∖":"∖","⫧":"⫧","⌆":"⌆",Б:"Б","∵":"∵",ℬ:"ℬ",Β:"Β",𝔅:"𝔅",𝔹:"𝔹","˘":"˘","≎":"≎",Ч:"Ч","©":"©",Ć:"Ć","⋒":"⋒",ⅅ:"ⅅ",ℭ:"ℭ",Č:"Č",Ç:"Ç",Ĉ:"Ĉ","∰":"∰",Ċ:"Ċ","¸":"¸","·":"·",Χ:"Χ","⊙":"⊙","⊖":"⊖","⊕":"⊕","⊗":"⊗","∲":"∲","”":"”","’":"’","∷":"∷","⩴":"⩴","≡":"≡","∯":"∯","∮":"∮",ℂ:"ℂ","∐":"∐","∳":"∳","⨯":"⨯",𝒞:"𝒞","⋓":"⋓","≍":"≍","⤑":"⤑",Ђ:"Ђ",Ѕ:"Ѕ",Џ:"Џ","‡":"‡","↡":"↡","⫤":"⫤",Ď:"Ď",Д:"Д","∇":"∇",Δ:"Δ",𝔇:"𝔇","´":"´","˙":"˙","˝":"˝","`":"`","˜":"˜","⋄":"⋄",ⅆ:"ⅆ",𝔻:"𝔻","¨":"¨","⃜":"⃜","≐":"≐","⇓":"⇓","⇐":"⇐","⇔":"⇔","⟸":"⟸","⟺":"⟺","⟹":"⟹","⇒":"⇒","⊨":"⊨","⇑":"⇑","⇕":"⇕","∥":"∥","↓":"↓","⤓":"⤓","⇵":"⇵","̑":"̑","⥐":"⥐","⥞":"⥞","↽":"↽","⥖":"⥖","⥟":"⥟","⇁":"⇁","⥗":"⥗","⊤":"⊤","↧":"↧",𝒟:"𝒟",Đ:"Đ",Ŋ:"Ŋ",Ð:"Ð",É:"É",Ě:"Ě",Ê:"Ê",Э:"Э",Ė:"Ė",𝔈:"𝔈",È:"È","∈":"∈",Ē:"Ē","◻":"◻","▫":"▫",Ę:"Ę",𝔼:"𝔼",Ε:"Ε","⩵":"⩵","≂":"≂","⇌":"⇌",ℰ:"ℰ","⩳":"⩳",Η:"Η",Ë:"Ë","∃":"∃",ⅇ:"ⅇ",Ф:"Ф",𝔉:"𝔉","◼":"◼","▪":"▪",𝔽:"𝔽","∀":"∀",ℱ:"ℱ",Ѓ:"Ѓ",">":">",Γ:"Γ",Ϝ:"Ϝ",Ğ:"Ğ",Ģ:"Ģ",Ĝ:"Ĝ",Г:"Г",Ġ:"Ġ",𝔊:"𝔊","⋙":"⋙",𝔾:"𝔾","≥":"≥","⋛":"⋛","≧":"≧","⪢":"⪢","≷":"≷","⩾":"⩾","≳":"≳",𝒢:"𝒢","≫":"≫",Ъ:"Ъ",ˇ:"ˇ","^":"^",Ĥ:"Ĥ",ℌ:"ℌ",ℋ:"ℋ",ℍ:"ℍ","─":"─",Ħ:"Ħ","≏":"≏",Е:"Е",IJ:"IJ",Ё:"Ё",Í:"Í",Î:"Î",И:"И",İ:"İ",ℑ:"ℑ",Ì:"Ì",Ī:"Ī",ⅈ:"ⅈ","∬":"∬","∫":"∫","⋂":"⋂","⁣":"⁣","⁢":"⁢",Į:"Į",𝕀:"𝕀",Ι:"Ι",ℐ:"ℐ",Ĩ:"Ĩ",І:"І",Ï:"Ï",Ĵ:"Ĵ",Й:"Й",𝔍:"𝔍",𝕁:"𝕁",𝒥:"𝒥",Ј:"Ј",Є:"Є",Х:"Х",Ќ:"Ќ",Κ:"Κ",Ķ:"Ķ",К:"К",𝔎:"𝔎",𝕂:"𝕂",𝒦:"𝒦",Љ:"Љ","<":"<",Ĺ:"Ĺ",Λ:"Λ","⟪":"⟪",ℒ:"ℒ","↞":"↞",Ľ:"Ľ",Ļ:"Ļ",Л:"Л","⟨":"⟨","←":"←","⇤":"⇤","⇆":"⇆","⌈":"⌈","⟦":"⟦","⥡":"⥡","⇃":"⇃","⥙":"⥙","⌊":"⌊","↔":"↔","⥎":"⥎","⊣":"⊣","↤":"↤","⥚":"⥚","⊲":"⊲","⧏":"⧏","⊴":"⊴","⥑":"⥑","⥠":"⥠","↿":"↿","⥘":"⥘","↼":"↼","⥒":"⥒","⋚":"⋚","≦":"≦","≶":"≶","⪡":"⪡","⩽":"⩽","≲":"≲",𝔏:"𝔏","⋘":"⋘","⇚":"⇚",Ŀ:"Ŀ","⟵":"⟵","⟷":"⟷","⟶":"⟶",𝕃:"𝕃","↙":"↙","↘":"↘","↰":"↰",Ł:"Ł","≪":"≪","⤅":"⤅",М:"М"," ":" ",ℳ:"ℳ",𝔐:"𝔐","∓":"∓",𝕄:"𝕄",Μ:"Μ",Њ:"Њ",Ń:"Ń",Ň:"Ň",Ņ:"Ņ",Н:"Н","​":"​","\n":" ",𝔑:"𝔑","⁠":"⁠"," ":" ",ℕ:"ℕ","⫬":"⫬","≢":"≢","≭":"≭","∦":"∦","∉":"∉","≠":"≠","≂̸":"≂̸","∄":"∄","≯":"≯","≱":"≱","≧̸":"≧̸","≫̸":"≫̸","≹":"≹","⩾̸":"⩾̸","≵":"≵","≎̸":"≎̸","≏̸":"≏̸","⋪":"⋪","⧏̸":"⧏̸","⋬":"⋬","≮":"≮","≰":"≰","≸":"≸","≪̸":"≪̸","⩽̸":"⩽̸","≴":"≴","⪢̸":"⪢̸","⪡̸":"⪡̸","⊀":"⊀","⪯̸":"⪯̸","⋠":"⋠","∌":"∌","⋫":"⋫","⧐̸":"⧐̸","⋭":"⋭","⊏̸":"⊏̸","⋢":"⋢","⊐̸":"⊐̸","⋣":"⋣","⊂⃒":"⊂⃒","⊈":"⊈","⊁":"⊁","⪰̸":"⪰̸","⋡":"⋡","≿̸":"≿̸","⊃⃒":"⊃⃒","⊉":"⊉","≁":"≁","≄":"≄","≇":"≇","≉":"≉","∤":"∤",𝒩:"𝒩",Ñ:"Ñ",Ν:"Ν",Œ:"Œ",Ó:"Ó",Ô:"Ô",О:"О",Ő:"Ő",𝔒:"𝔒",Ò:"Ò",Ō:"Ō",Ω:"Ω",Ο:"Ο",𝕆:"𝕆","“":"“","‘":"‘","⩔":"⩔",𝒪:"𝒪",Ø:"Ø",Õ:"Õ","⨷":"⨷",Ö:"Ö","‾":"‾","⏞":"⏞","⎴":"⎴","⏜":"⏜","∂":"∂",П:"П",𝔓:"𝔓",Φ:"Φ",Π:"Π","±":"±",ℙ:"ℙ","⪻":"⪻","≺":"≺","⪯":"⪯","≼":"≼","≾":"≾","″":"″","∏":"∏","∝":"∝",𝒫:"𝒫",Ψ:"Ψ",'"':""",𝔔:"𝔔",ℚ:"ℚ",𝒬:"𝒬","⤐":"⤐","®":"®",Ŕ:"Ŕ","⟫":"⟫","↠":"↠","⤖":"⤖",Ř:"Ř",Ŗ:"Ŗ",Р:"Р",ℜ:"ℜ","∋":"∋","⇋":"⇋","⥯":"⥯",Ρ:"Ρ","⟩":"⟩","→":"→","⇥":"⇥","⇄":"⇄","⌉":"⌉","⟧":"⟧","⥝":"⥝","⇂":"⇂","⥕":"⥕","⌋":"⌋","⊢":"⊢","↦":"↦","⥛":"⥛","⊳":"⊳","⧐":"⧐","⊵":"⊵","⥏":"⥏","⥜":"⥜","↾":"↾","⥔":"⥔","⇀":"⇀","⥓":"⥓",ℝ:"ℝ","⥰":"⥰","⇛":"⇛",ℛ:"ℛ","↱":"↱","⧴":"⧴",Щ:"Щ",Ш:"Ш",Ь:"Ь",Ś:"Ś","⪼":"⪼",Š:"Š",Ş:"Ş",Ŝ:"Ŝ",С:"С",𝔖:"𝔖","↑":"↑",Σ:"Σ","∘":"∘",𝕊:"𝕊","√":"√","□":"□","⊓":"⊓","⊏":"⊏","⊑":"⊑","⊐":"⊐","⊒":"⊒","⊔":"⊔",𝒮:"𝒮","⋆":"⋆","⋐":"⋐","⊆":"⊆","≻":"≻","⪰":"⪰","≽":"≽","≿":"≿","∑":"∑","⋑":"⋑","⊃":"⊃","⊇":"⊇",Þ:"Þ","™":"™",Ћ:"Ћ",Ц:"Ц","\t":" ",Τ:"Τ",Ť:"Ť",Ţ:"Ţ",Т:"Т",𝔗:"𝔗","∴":"∴",Θ:"Θ","  ":"  "," ":" ","∼":"∼","≃":"≃","≅":"≅","≈":"≈",𝕋:"𝕋","⃛":"⃛",𝒯:"𝒯",Ŧ:"Ŧ",Ú:"Ú","↟":"↟","⥉":"⥉",Ў:"Ў",Ŭ:"Ŭ",Û:"Û",У:"У",Ű:"Ű",𝔘:"𝔘",Ù:"Ù",Ū:"Ū",_:"_","⏟":"⏟","⎵":"⎵","⏝":"⏝","⋃":"⋃","⊎":"⊎",Ų:"Ų",𝕌:"𝕌","⤒":"⤒","⇅":"⇅","↕":"↕","⥮":"⥮","⊥":"⊥","↥":"↥","↖":"↖","↗":"↗",ϒ:"ϒ",Υ:"Υ",Ů:"Ů",𝒰:"𝒰",Ũ:"Ũ",Ü:"Ü","⊫":"⊫","⫫":"⫫",В:"В","⊩":"⊩","⫦":"⫦","⋁":"⋁","‖":"‖","∣":"∣","|":"|","❘":"❘","≀":"≀"," ":" ",𝔙:"𝔙",𝕍:"𝕍",𝒱:"𝒱","⊪":"⊪",Ŵ:"Ŵ","⋀":"⋀",𝔚:"𝔚",𝕎:"𝕎",𝒲:"𝒲",𝔛:"𝔛",Ξ:"Ξ",𝕏:"𝕏",𝒳:"𝒳",Я:"Я",Ї:"Ї",Ю:"Ю",Ý:"Ý",Ŷ:"Ŷ",Ы:"Ы",𝔜:"𝔜",𝕐:"𝕐",𝒴:"𝒴",Ÿ:"Ÿ",Ж:"Ж",Ź:"Ź",Ž:"Ž",З:"З",Ż:"Ż",Ζ:"Ζ",ℨ:"ℨ",ℤ:"ℤ",𝒵:"𝒵",á:"á",ă:"ă","∾":"∾","∾̳":"∾̳","∿":"∿",â:"â",а:"а",æ:"æ",𝔞:"𝔞",à:"à",ℵ:"ℵ",α:"α",ā:"ā","⨿":"⨿","∧":"∧","⩕":"⩕","⩜":"⩜","⩘":"⩘","⩚":"⩚","∠":"∠","⦤":"⦤","∡":"∡","⦨":"⦨","⦩":"⦩","⦪":"⦪","⦫":"⦫","⦬":"⦬","⦭":"⦭","⦮":"⦮","⦯":"⦯","∟":"∟","⊾":"⊾","⦝":"⦝","∢":"∢","⍼":"⍼",ą:"ą",𝕒:"𝕒","⩰":"⩰","⩯":"⩯","≊":"≊","≋":"≋","'":"'",å:"å",𝒶:"𝒶","*":"*",ã:"ã",ä:"ä","⨑":"⨑","⫭":"⫭","≌":"≌","϶":"϶","‵":"‵","∽":"∽","⋍":"⋍","⊽":"⊽","⌅":"⌅","⎶":"⎶",б:"б","„":"„","⦰":"⦰",β:"β",ℶ:"ℶ","≬":"≬",𝔟:"𝔟","◯":"◯","⨀":"⨀","⨁":"⨁","⨂":"⨂","⨆":"⨆","★":"★","▽":"▽","△":"△","⨄":"⨄","⤍":"⤍","⧫":"⧫","▴":"▴","▾":"▾","◂":"◂","▸":"▸","␣":"␣","▒":"▒","░":"░","▓":"▓","█":"█","=⃥":"=⃥","≡⃥":"≡⃥","⌐":"⌐",𝕓:"𝕓","⋈":"⋈","╗":"╗","╔":"╔","╖":"╖","╓":"╓","═":"═","╦":"╦","╩":"╩","╤":"╤","╧":"╧","╝":"╝","╚":"╚","╜":"╜","╙":"╙","║":"║","╬":"╬","╣":"╣","╠":"╠","╫":"╫","╢":"╢","╟":"╟","⧉":"⧉","╕":"╕","╒":"╒","┐":"┐","┌":"┌","╥":"╥","╨":"╨","┬":"┬","┴":"┴","⊟":"⊟","⊞":"⊞","⊠":"⊠","╛":"╛","╘":"╘","┘":"┘","└":"└","│":"│","╪":"╪","╡":"╡","╞":"╞","┼":"┼","┤":"┤","├":"├","¦":"¦",𝒷:"𝒷","⁏":"⁏","\\":"\","⧅":"⧅","⟈":"⟈","•":"•","⪮":"⪮",ć:"ć","∩":"∩","⩄":"⩄","⩉":"⩉","⩋":"⩋","⩇":"⩇","⩀":"⩀","∩︀":"∩︀","⁁":"⁁","⩍":"⩍",č:"č",ç:"ç",ĉ:"ĉ","⩌":"⩌","⩐":"⩐",ċ:"ċ","⦲":"⦲","¢":"¢",𝔠:"𝔠",ч:"ч","✓":"✓",χ:"χ","○":"○","⧃":"⧃",ˆ:"ˆ","≗":"≗","↺":"↺","↻":"↻","Ⓢ":"Ⓢ","⊛":"⊛","⊚":"⊚","⊝":"⊝","⨐":"⨐","⫯":"⫯","⧂":"⧂","♣":"♣",":":":",",":",","@":"@","∁":"∁","⩭":"⩭",𝕔:"𝕔","℗":"℗","↵":"↵","✗":"✗",𝒸:"𝒸","⫏":"⫏","⫑":"⫑","⫐":"⫐","⫒":"⫒","⋯":"⋯","⤸":"⤸","⤵":"⤵","⋞":"⋞","⋟":"⋟","↶":"↶","⤽":"⤽","∪":"∪","⩈":"⩈","⩆":"⩆","⩊":"⩊","⊍":"⊍","⩅":"⩅","∪︀":"∪︀","↷":"↷","⤼":"⤼","⋎":"⋎","⋏":"⋏","¤":"¤","∱":"∱","⌭":"⌭","⥥":"⥥","†":"†",ℸ:"ℸ","‐":"‐","⤏":"⤏",ď:"ď",д:"д","⇊":"⇊","⩷":"⩷","°":"°",δ:"δ","⦱":"⦱","⥿":"⥿",𝔡:"𝔡","♦":"♦",ϝ:"ϝ","⋲":"⋲","÷":"÷","⋇":"⋇",ђ:"ђ","⌞":"⌞","⌍":"⌍",$:"$",𝕕:"𝕕","≑":"≑","∸":"∸","∔":"∔","⊡":"⊡","⌟":"⌟","⌌":"⌌",𝒹:"𝒹",ѕ:"ѕ","⧶":"⧶",đ:"đ","⋱":"⋱","▿":"▿","⦦":"⦦",џ:"џ","⟿":"⟿",é:"é","⩮":"⩮",ě:"ě","≖":"≖",ê:"ê","≕":"≕",э:"э",ė:"ė","≒":"≒",𝔢:"𝔢","⪚":"⪚",è:"è","⪖":"⪖","⪘":"⪘","⪙":"⪙","⏧":"⏧",ℓ:"ℓ","⪕":"⪕","⪗":"⪗",ē:"ē","∅":"∅"," ":" "," ":" "," ":" ",ŋ:"ŋ"," ":" ",ę:"ę",𝕖:"𝕖","⋕":"⋕","⧣":"⧣","⩱":"⩱",ε:"ε",ϵ:"ϵ","=":"=","≟":"≟","⩸":"⩸","⧥":"⧥","≓":"≓","⥱":"⥱",ℯ:"ℯ",η:"η",ð:"ð",ë:"ë","€":"€","!":"!",ф:"ф","♀":"♀",ffi:"ffi",ff:"ff",ffl:"ffl",𝔣:"𝔣",fi:"fi",fj:"fj","♭":"♭",fl:"fl","▱":"▱",ƒ:"ƒ",𝕗:"𝕗","⋔":"⋔","⫙":"⫙","⨍":"⨍","½":"½","⅓":"⅓","¼":"¼","⅕":"⅕","⅙":"⅙","⅛":"⅛","⅔":"⅔","⅖":"⅖","¾":"¾","⅗":"⅗","⅜":"⅜","⅘":"⅘","⅚":"⅚","⅝":"⅝","⅞":"⅞","⁄":"⁄","⌢":"⌢",𝒻:"𝒻","⪌":"⪌",ǵ:"ǵ",γ:"γ","⪆":"⪆",ğ:"ğ",ĝ:"ĝ",г:"г",ġ:"ġ","⪩":"⪩","⪀":"⪀","⪂":"⪂","⪄":"⪄","⋛︀":"⋛︀","⪔":"⪔",𝔤:"𝔤",ℷ:"ℷ",ѓ:"ѓ","⪒":"⪒","⪥":"⪥","⪤":"⪤","≩":"≩","⪊":"⪊","⪈":"⪈","⋧":"⋧",𝕘:"𝕘",ℊ:"ℊ","⪎":"⪎","⪐":"⪐","⪧":"⪧","⩺":"⩺","⋗":"⋗","⦕":"⦕","⩼":"⩼","⥸":"⥸","≩︀":"≩︀",ъ:"ъ","⥈":"⥈","↭":"↭",ℏ:"ℏ",ĥ:"ĥ","♥":"♥","…":"…","⊹":"⊹",𝔥:"𝔥","⤥":"⤥","⤦":"⤦","⇿":"⇿","∻":"∻","↩":"↩","↪":"↪",𝕙:"𝕙","―":"―",𝒽:"𝒽",ħ:"ħ","⁃":"⁃",í:"í",î:"î",и:"и",е:"е","¡":"¡",𝔦:"𝔦",ì:"ì","⨌":"⨌","∭":"∭","⧜":"⧜","℩":"℩",ij:"ij",ī:"ī",ı:"ı","⊷":"⊷",Ƶ:"Ƶ","℅":"℅","∞":"∞","⧝":"⧝","⊺":"⊺","⨗":"⨗","⨼":"⨼",ё:"ё",į:"į",𝕚:"𝕚",ι:"ι","¿":"¿",𝒾:"𝒾","⋹":"⋹","⋵":"⋵","⋴":"⋴","⋳":"⋳",ĩ:"ĩ",і:"і",ï:"ï",ĵ:"ĵ",й:"й",𝔧:"𝔧",ȷ:"ȷ",𝕛:"𝕛",𝒿:"𝒿",ј:"ј",є:"є",κ:"κ",ϰ:"ϰ",ķ:"ķ",к:"к",𝔨:"𝔨",ĸ:"ĸ",х:"х",ќ:"ќ",𝕜:"𝕜",𝓀:"𝓀","⤛":"⤛","⤎":"⤎","⪋":"⪋","⥢":"⥢",ĺ:"ĺ","⦴":"⦴",λ:"λ","⦑":"⦑","⪅":"⪅","«":"«","⤟":"⤟","⤝":"⤝","↫":"↫","⤹":"⤹","⥳":"⥳","↢":"↢","⪫":"⪫","⤙":"⤙","⪭":"⪭","⪭︀":"⪭︀","⤌":"⤌","❲":"❲","{":"{","[":"[","⦋":"⦋","⦏":"⦏","⦍":"⦍",ľ:"ľ",ļ:"ļ",л:"л","⤶":"⤶","⥧":"⥧","⥋":"⥋","↲":"↲","≤":"≤","⇇":"⇇","⋋":"⋋","⪨":"⪨","⩿":"⩿","⪁":"⪁","⪃":"⪃","⋚︀":"⋚︀","⪓":"⪓","⋖":"⋖","⥼":"⥼",𝔩:"𝔩","⪑":"⪑","⥪":"⥪","▄":"▄",љ:"љ","⥫":"⥫","◺":"◺",ŀ:"ŀ","⎰":"⎰","≨":"≨","⪉":"⪉","⪇":"⪇","⋦":"⋦","⟬":"⟬","⇽":"⇽","⟼":"⟼","↬":"↬","⦅":"⦅",𝕝:"𝕝","⨭":"⨭","⨴":"⨴","∗":"∗","◊":"◊","(":"(","⦓":"⦓","⥭":"⥭","‎":"‎","⊿":"⊿","‹":"‹",𝓁:"𝓁","⪍":"⪍","⪏":"⪏","‚":"‚",ł:"ł","⪦":"⪦","⩹":"⩹","⋉":"⋉","⥶":"⥶","⩻":"⩻","⦖":"⦖","◃":"◃","⥊":"⥊","⥦":"⥦","≨︀":"≨︀","∺":"∺","¯":"¯","♂":"♂","✠":"✠","▮":"▮","⨩":"⨩",м:"м","—":"—",𝔪:"𝔪","℧":"℧",µ:"µ","⫰":"⫰","−":"−","⨪":"⨪","⫛":"⫛","⊧":"⊧",𝕞:"𝕞",𝓂:"𝓂",μ:"μ","⊸":"⊸","⋙̸":"⋙̸","≫⃒":"≫⃒","⇍":"⇍","⇎":"⇎","⋘̸":"⋘̸","≪⃒":"≪⃒","⇏":"⇏","⊯":"⊯","⊮":"⊮",ń:"ń","∠⃒":"∠⃒","⩰̸":"⩰̸","≋̸":"≋̸",ʼn:"ʼn","♮":"♮","⩃":"⩃",ň:"ň",ņ:"ņ","⩭̸":"⩭̸","⩂":"⩂",н:"н","–":"–","⇗":"⇗","⤤":"⤤","≐̸":"≐̸","⤨":"⤨",𝔫:"𝔫","↮":"↮","⫲":"⫲","⋼":"⋼","⋺":"⋺",њ:"њ","≦̸":"≦̸","↚":"↚","‥":"‥",𝕟:"𝕟","¬":"¬","⋹̸":"⋹̸","⋵̸":"⋵̸","⋷":"⋷","⋶":"⋶","⋾":"⋾","⋽":"⋽","⫽⃥":"⫽⃥","∂̸":"∂̸","⨔":"⨔","↛":"↛","⤳̸":"⤳̸","↝̸":"↝̸",𝓃:"𝓃","⊄":"⊄","⫅̸":"⫅̸","⊅":"⊅","⫆̸":"⫆̸",ñ:"ñ",ν:"ν","#":"#","№":"№"," ":" ","⊭":"⊭","⤄":"⤄","≍⃒":"≍⃒","⊬":"⊬","≥⃒":"≥⃒",">⃒":">⃒","⧞":"⧞","⤂":"⤂","≤⃒":"≤⃒","<⃒":"<⃒","⊴⃒":"⊴⃒","⤃":"⤃","⊵⃒":"⊵⃒","∼⃒":"∼⃒","⇖":"⇖","⤣":"⤣","⤧":"⤧",ó:"ó",ô:"ô",о:"о",ő:"ő","⨸":"⨸","⦼":"⦼",œ:"œ","⦿":"⦿",𝔬:"𝔬","˛":"˛",ò:"ò","⧁":"⧁","⦵":"⦵","⦾":"⦾","⦻":"⦻","⧀":"⧀",ō:"ō",ω:"ω",ο:"ο","⦶":"⦶",𝕠:"𝕠","⦷":"⦷","⦹":"⦹","∨":"∨","⩝":"⩝",ℴ:"ℴ",ª:"ª",º:"º","⊶":"⊶","⩖":"⩖","⩗":"⩗","⩛":"⩛",ø:"ø","⊘":"⊘",õ:"õ","⨶":"⨶",ö:"ö","⌽":"⌽","¶":"¶","⫳":"⫳","⫽":"⫽",п:"п","%":"%",".":".","‰":"‰","‱":"‱",𝔭:"𝔭",φ:"φ",ϕ:"ϕ","☎":"☎",π:"π",ϖ:"ϖ",ℎ:"ℎ","+":"+","⨣":"⨣","⨢":"⨢","⨥":"⨥","⩲":"⩲","⨦":"⨦","⨧":"⨧","⨕":"⨕",𝕡:"𝕡","£":"£","⪳":"⪳","⪷":"⪷","⪹":"⪹","⪵":"⪵","⋨":"⋨","′":"′","⌮":"⌮","⌒":"⌒","⌓":"⌓","⊰":"⊰",𝓅:"𝓅",ψ:"ψ"," ":" ",𝔮:"𝔮",𝕢:"𝕢","⁗":"⁗",𝓆:"𝓆","⨖":"⨖","?":"?","⤜":"⤜","⥤":"⥤","∽̱":"∽̱",ŕ:"ŕ","⦳":"⦳","⦒":"⦒","⦥":"⦥","»":"»","⥵":"⥵","⤠":"⤠","⤳":"⤳","⤞":"⤞","⥅":"⥅","⥴":"⥴","↣":"↣","↝":"↝","⤚":"⤚","∶":"∶","❳":"❳","}":"}","]":"]","⦌":"⦌","⦎":"⦎","⦐":"⦐",ř:"ř",ŗ:"ŗ",р:"р","⤷":"⤷","⥩":"⥩","↳":"↳","▭":"▭","⥽":"⥽",𝔯:"𝔯","⥬":"⥬",ρ:"ρ",ϱ:"ϱ","⇉":"⇉","⋌":"⋌","˚":"˚","‏":"‏","⎱":"⎱","⫮":"⫮","⟭":"⟭","⇾":"⇾","⦆":"⦆",𝕣:"𝕣","⨮":"⨮","⨵":"⨵",")":")","⦔":"⦔","⨒":"⨒","›":"›",𝓇:"𝓇","⋊":"⋊","▹":"▹","⧎":"⧎","⥨":"⥨","℞":"℞",ś:"ś","⪴":"⪴","⪸":"⪸",š:"š",ş:"ş",ŝ:"ŝ","⪶":"⪶","⪺":"⪺","⋩":"⋩","⨓":"⨓",с:"с","⋅":"⋅","⩦":"⩦","⇘":"⇘","§":"§",";":";","⤩":"⤩","✶":"✶",𝔰:"𝔰","♯":"♯",щ:"щ",ш:"ш","­":"­",σ:"σ",ς:"ς","⩪":"⩪","⪞":"⪞","⪠":"⪠","⪝":"⪝","⪟":"⪟","≆":"≆","⨤":"⨤","⥲":"⥲","⨳":"⨳","⧤":"⧤","⌣":"⌣","⪪":"⪪","⪬":"⪬","⪬︀":"⪬︀",ь:"ь","/":"/","⧄":"⧄","⌿":"⌿",𝕤:"𝕤","♠":"♠","⊓︀":"⊓︀","⊔︀":"⊔︀",𝓈:"𝓈","☆":"☆","⊂":"⊂","⫅":"⫅","⪽":"⪽","⫃":"⫃","⫁":"⫁","⫋":"⫋","⊊":"⊊","⪿":"⪿","⥹":"⥹","⫇":"⫇","⫕":"⫕","⫓":"⫓","♪":"♪","¹":"¹","²":"²","³":"³","⫆":"⫆","⪾":"⪾","⫘":"⫘","⫄":"⫄","⟉":"⟉","⫗":"⫗","⥻":"⥻","⫂":"⫂","⫌":"⫌","⊋":"⊋","⫀":"⫀","⫈":"⫈","⫔":"⫔","⫖":"⫖","⇙":"⇙","⤪":"⤪",ß:"ß","⌖":"⌖",τ:"τ",ť:"ť",ţ:"ţ",т:"т","⌕":"⌕",𝔱:"𝔱",θ:"θ",ϑ:"ϑ",þ:"þ","×":"×","⨱":"⨱","⨰":"⨰","⌶":"⌶","⫱":"⫱",𝕥:"𝕥","⫚":"⫚","‴":"‴","▵":"▵","≜":"≜","◬":"◬","⨺":"⨺","⨹":"⨹","⧍":"⧍","⨻":"⨻","⏢":"⏢",𝓉:"𝓉",ц:"ц",ћ:"ћ",ŧ:"ŧ","⥣":"⥣",ú:"ú",ў:"ў",ŭ:"ŭ",û:"û",у:"у",ű:"ű","⥾":"⥾",𝔲:"𝔲",ù:"ù","▀":"▀","⌜":"⌜","⌏":"⌏","◸":"◸",ū:"ū",ų:"ų",𝕦:"𝕦",υ:"υ","⇈":"⇈","⌝":"⌝","⌎":"⌎",ů:"ů","◹":"◹",𝓊:"𝓊","⋰":"⋰",ũ:"ũ",ü:"ü","⦧":"⦧","⫨":"⫨","⫩":"⫩","⦜":"⦜","⊊︀":"⊊︀","⫋︀":"⫋︀","⊋︀":"⊋︀","⫌︀":"⫌︀",в:"в","⊻":"⊻","≚":"≚","⋮":"⋮",𝔳:"𝔳",𝕧:"𝕧",𝓋:"𝓋","⦚":"⦚",ŵ:"ŵ","⩟":"⩟","≙":"≙",℘:"℘",𝔴:"𝔴",𝕨:"𝕨",𝓌:"𝓌",𝔵:"𝔵",ξ:"ξ","⋻":"⋻",𝕩:"𝕩",𝓍:"𝓍",ý:"ý",я:"я",ŷ:"ŷ",ы:"ы","¥":"¥",𝔶:"𝔶",ї:"ї",𝕪:"𝕪",𝓎:"𝓎",ю:"ю",ÿ:"ÿ",ź:"ź",ž:"ž",з:"з",ż:"ż",ζ:"ζ",𝔷:"𝔷",ж:"ж","⇝":"⇝",𝕫:"𝕫",𝓏:"𝓏","‍":"‍","‌":"‌"}}}},687:(r,e)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.numericUnicodeMap={0:65533,128:8364,130:8218,131:402,132:8222,133:8230,134:8224,135:8225,136:710,137:8240,138:352,139:8249,140:338,142:381,145:8216,146:8217,147:8220,148:8221,149:8226,150:8211,151:8212,152:732,153:8482,154:353,155:8250,156:339,158:382,159:376}},967:(r,e)=>{Object.defineProperty(e,"__esModule",{value:!0}),e.fromCodePoint=String.fromCodePoint||function(r){return String.fromCharCode(Math.floor((r-65536)/1024)+55296,(r-65536)%1024+56320)},e.getCodePoint=String.prototype.codePointAt?function(r,e){return r.codePointAt(e)}:function(r,e){return 1024*(r.charCodeAt(e)-55296)+r.charCodeAt(e+1)-56320+65536},e.highSurrogateFrom=55296,e.highSurrogateTo=56319}},a={};function t(r){var o=a[r];if(void 0!==o)return o.exports;var c=a[r]={exports:{}};return e[r].call(c.exports,c,c.exports,t),c.exports}t.n=r=>{var e=r&&r.__esModule?()=>r.default:()=>r;return t.d(e,{a:e}),e},t.d=(r,e)=>{for(var a in e)t.o(e,a)&&!t.o(r,a)&&Object.defineProperty(r,a,{enumerable:!0,get:e[a]})},t.o=(r,e)=>Object.prototype.hasOwnProperty.call(r,e),r=t(563),window.html_encode=r.encode,window.html_decode=r.decode})(); \ No newline at end of file diff --git a/src/dev-center/js/jquery-3.6.0.min.js b/src/dev-center/js/jquery-3.6.0.min.js index abecbc6fef..c4c6022f29 100644 --- a/src/dev-center/js/jquery-3.6.0.min.js +++ b/src/dev-center/js/jquery-3.6.0.min.js @@ -1,20 +1,2 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /*! jQuery v3.6.0 | (c) OpenJS Foundation and other contributors | jquery.org/license */ !function(e,t){"use strict";"object"==typeof module&&"object"==typeof module.exports?module.exports=e.document?t(e,!0):function(e){if(!e.document)throw new Error("jQuery requires a window with a document");return t(e)}:t(e)}("undefined"!=typeof window?window:this,function(C,e){"use strict";var t=[],r=Object.getPrototypeOf,s=t.slice,g=t.flat?function(e){return t.flat.call(e)}:function(e){return t.concat.apply([],e)},u=t.push,i=t.indexOf,n={},o=n.toString,v=n.hasOwnProperty,a=v.toString,l=a.call(Object),y={},m=function(e){return"function"==typeof e&&"number"!=typeof e.nodeType&&"function"!=typeof e.item},x=function(e){return null!=e&&e===e.window},E=C.document,c={type:!0,src:!0,nonce:!0,noModule:!0};function b(e,t,n){var r,i,o=(n=n||E).createElement("script");if(o.text=e,t)for(r in c)(i=t[r]||t.getAttribute&&t.getAttribute(r))&&o.setAttribute(r,i);n.head.appendChild(o).parentNode.removeChild(o)}function w(e){return null==e?e+"":"object"==typeof e||"function"==typeof e?n[o.call(e)]||"object":typeof e}var f="3.6.0",S=function(e,t){return new S.fn.init(e,t)};function p(e){var t=!!e&&"length"in e&&e.length,n=w(e);return!m(e)&&!x(e)&&("array"===n||0===t||"number"==typeof t&&0+~]|"+M+")"+M+"*"),U=new RegExp(M+"|>"),X=new RegExp(F),V=new RegExp("^"+I+"$"),G={ID:new RegExp("^#("+I+")"),CLASS:new RegExp("^\\.("+I+")"),TAG:new RegExp("^("+I+"|[*])"),ATTR:new RegExp("^"+W),PSEUDO:new RegExp("^"+F),CHILD:new RegExp("^:(only|first|last|nth|nth-last)-(child|of-type)(?:\\("+M+"*(even|odd|(([+-]|)(\\d*)n|)"+M+"*(?:([+-]|)"+M+"*(\\d+)|))"+M+"*\\)|)","i"),bool:new RegExp("^(?:"+R+")$","i"),needsContext:new RegExp("^"+M+"*[>+~]|:(even|odd|eq|gt|lt|nth|first|last)(?:\\("+M+"*((?:-\\d)?\\d*)"+M+"*\\)|)(?=[^-]|$)","i")},Y=/HTML$/i,Q=/^(?:input|select|textarea|button)$/i,J=/^h\d$/i,K=/^[^{]+\{\s*\[native \w/,Z=/^(?:#([\w-]+)|(\w+)|\.([\w-]+))$/,ee=/[+~]/,te=new RegExp("\\\\[\\da-fA-F]{1,6}"+M+"?|\\\\([^\\r\\n\\f])","g"),ne=function(e,t){var n="0x"+e.slice(1)-65536;return t||(n<0?String.fromCharCode(n+65536):String.fromCharCode(n>>10|55296,1023&n|56320))},re=/([\0-\x1f\x7f]|^-?\d)|^-$|[^\0-\x1f\x7f-\uFFFF\w-]/g,ie=function(e,t){return t?"\0"===e?"\ufffd":e.slice(0,-1)+"\\"+e.charCodeAt(e.length-1).toString(16)+" ":"\\"+e},oe=function(){T()},ae=be(function(e){return!0===e.disabled&&"fieldset"===e.nodeName.toLowerCase()},{dir:"parentNode",next:"legend"});try{H.apply(t=O.call(p.childNodes),p.childNodes),t[p.childNodes.length].nodeType}catch(e){H={apply:t.length?function(e,t){L.apply(e,O.call(t))}:function(e,t){var n=e.length,r=0;while(e[n++]=t[r++]);e.length=n-1}}}function se(t,e,n,r){var i,o,a,s,u,l,c,f=e&&e.ownerDocument,p=e?e.nodeType:9;if(n=n||[],"string"!=typeof t||!t||1!==p&&9!==p&&11!==p)return n;if(!r&&(T(e),e=e||C,E)){if(11!==p&&(u=Z.exec(t)))if(i=u[1]){if(9===p){if(!(a=e.getElementById(i)))return n;if(a.id===i)return n.push(a),n}else if(f&&(a=f.getElementById(i))&&y(e,a)&&a.id===i)return n.push(a),n}else{if(u[2])return H.apply(n,e.getElementsByTagName(t)),n;if((i=u[3])&&d.getElementsByClassName&&e.getElementsByClassName)return H.apply(n,e.getElementsByClassName(i)),n}if(d.qsa&&!N[t+" "]&&(!v||!v.test(t))&&(1!==p||"object"!==e.nodeName.toLowerCase())){if(c=t,f=e,1===p&&(U.test(t)||z.test(t))){(f=ee.test(t)&&ye(e.parentNode)||e)===e&&d.scope||((s=e.getAttribute("id"))?s=s.replace(re,ie):e.setAttribute("id",s=S)),o=(l=h(t)).length;while(o--)l[o]=(s?"#"+s:":scope")+" "+xe(l[o]);c=l.join(",")}try{return H.apply(n,f.querySelectorAll(c)),n}catch(e){N(t,!0)}finally{s===S&&e.removeAttribute("id")}}}return g(t.replace($,"$1"),e,n,r)}function ue(){var r=[];return function e(t,n){return r.push(t+" ")>b.cacheLength&&delete e[r.shift()],e[t+" "]=n}}function le(e){return e[S]=!0,e}function ce(e){var t=C.createElement("fieldset");try{return!!e(t)}catch(e){return!1}finally{t.parentNode&&t.parentNode.removeChild(t),t=null}}function fe(e,t){var n=e.split("|"),r=n.length;while(r--)b.attrHandle[n[r]]=t}function pe(e,t){var n=t&&e,r=n&&1===e.nodeType&&1===t.nodeType&&e.sourceIndex-t.sourceIndex;if(r)return r;if(n)while(n=n.nextSibling)if(n===t)return-1;return e?1:-1}function de(t){return function(e){return"input"===e.nodeName.toLowerCase()&&e.type===t}}function he(n){return function(e){var t=e.nodeName.toLowerCase();return("input"===t||"button"===t)&&e.type===n}}function ge(t){return function(e){return"form"in e?e.parentNode&&!1===e.disabled?"label"in e?"label"in e.parentNode?e.parentNode.disabled===t:e.disabled===t:e.isDisabled===t||e.isDisabled!==!t&&ae(e)===t:e.disabled===t:"label"in e&&e.disabled===t}}function ve(a){return le(function(o){return o=+o,le(function(e,t){var n,r=a([],e.length,o),i=r.length;while(i--)e[n=r[i]]&&(e[n]=!(t[n]=e[n]))})})}function ye(e){return e&&"undefined"!=typeof e.getElementsByTagName&&e}for(e in d=se.support={},i=se.isXML=function(e){var t=e&&e.namespaceURI,n=e&&(e.ownerDocument||e).documentElement;return!Y.test(t||n&&n.nodeName||"HTML")},T=se.setDocument=function(e){var t,n,r=e?e.ownerDocument||e:p;return r!=C&&9===r.nodeType&&r.documentElement&&(a=(C=r).documentElement,E=!i(C),p!=C&&(n=C.defaultView)&&n.top!==n&&(n.addEventListener?n.addEventListener("unload",oe,!1):n.attachEvent&&n.attachEvent("onunload",oe)),d.scope=ce(function(e){return a.appendChild(e).appendChild(C.createElement("div")),"undefined"!=typeof e.querySelectorAll&&!e.querySelectorAll(":scope fieldset div").length}),d.attributes=ce(function(e){return e.className="i",!e.getAttribute("className")}),d.getElementsByTagName=ce(function(e){return e.appendChild(C.createComment("")),!e.getElementsByTagName("*").length}),d.getElementsByClassName=K.test(C.getElementsByClassName),d.getById=ce(function(e){return a.appendChild(e).id=S,!C.getElementsByName||!C.getElementsByName(S).length}),d.getById?(b.filter.ID=function(e){var t=e.replace(te,ne);return function(e){return e.getAttribute("id")===t}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n=t.getElementById(e);return n?[n]:[]}}):(b.filter.ID=function(e){var n=e.replace(te,ne);return function(e){var t="undefined"!=typeof e.getAttributeNode&&e.getAttributeNode("id");return t&&t.value===n}},b.find.ID=function(e,t){if("undefined"!=typeof t.getElementById&&E){var n,r,i,o=t.getElementById(e);if(o){if((n=o.getAttributeNode("id"))&&n.value===e)return[o];i=t.getElementsByName(e),r=0;while(o=i[r++])if((n=o.getAttributeNode("id"))&&n.value===e)return[o]}return[]}}),b.find.TAG=d.getElementsByTagName?function(e,t){return"undefined"!=typeof t.getElementsByTagName?t.getElementsByTagName(e):d.qsa?t.querySelectorAll(e):void 0}:function(e,t){var n,r=[],i=0,o=t.getElementsByTagName(e);if("*"===e){while(n=o[i++])1===n.nodeType&&r.push(n);return r}return o},b.find.CLASS=d.getElementsByClassName&&function(e,t){if("undefined"!=typeof t.getElementsByClassName&&E)return t.getElementsByClassName(e)},s=[],v=[],(d.qsa=K.test(C.querySelectorAll))&&(ce(function(e){var t;a.appendChild(e).innerHTML="",e.querySelectorAll("[msallowcapture^='']").length&&v.push("[*^$]="+M+"*(?:''|\"\")"),e.querySelectorAll("[selected]").length||v.push("\\["+M+"*(?:value|"+R+")"),e.querySelectorAll("[id~="+S+"-]").length||v.push("~="),(t=C.createElement("input")).setAttribute("name",""),e.appendChild(t),e.querySelectorAll("[name='']").length||v.push("\\["+M+"*name"+M+"*="+M+"*(?:''|\"\")"),e.querySelectorAll(":checked").length||v.push(":checked"),e.querySelectorAll("a#"+S+"+*").length||v.push(".#.+[+~]"),e.querySelectorAll("\\\f"),v.push("[\\r\\n\\f]")}),ce(function(e){e.innerHTML="";var t=C.createElement("input");t.setAttribute("type","hidden"),e.appendChild(t).setAttribute("name","D"),e.querySelectorAll("[name=d]").length&&v.push("name"+M+"*[*^$|!~]?="),2!==e.querySelectorAll(":enabled").length&&v.push(":enabled",":disabled"),a.appendChild(e).disabled=!0,2!==e.querySelectorAll(":disabled").length&&v.push(":enabled",":disabled"),e.querySelectorAll("*,:x"),v.push(",.*:")})),(d.matchesSelector=K.test(c=a.matches||a.webkitMatchesSelector||a.mozMatchesSelector||a.oMatchesSelector||a.msMatchesSelector))&&ce(function(e){d.disconnectedMatch=c.call(e,"*"),c.call(e,"[s!='']:x"),s.push("!=",F)}),v=v.length&&new RegExp(v.join("|")),s=s.length&&new RegExp(s.join("|")),t=K.test(a.compareDocumentPosition),y=t||K.test(a.contains)?function(e,t){var n=9===e.nodeType?e.documentElement:e,r=t&&t.parentNode;return e===r||!(!r||1!==r.nodeType||!(n.contains?n.contains(r):e.compareDocumentPosition&&16&e.compareDocumentPosition(r)))}:function(e,t){if(t)while(t=t.parentNode)if(t===e)return!0;return!1},j=t?function(e,t){if(e===t)return l=!0,0;var n=!e.compareDocumentPosition-!t.compareDocumentPosition;return n||(1&(n=(e.ownerDocument||e)==(t.ownerDocument||t)?e.compareDocumentPosition(t):1)||!d.sortDetached&&t.compareDocumentPosition(e)===n?e==C||e.ownerDocument==p&&y(p,e)?-1:t==C||t.ownerDocument==p&&y(p,t)?1:u?P(u,e)-P(u,t):0:4&n?-1:1)}:function(e,t){if(e===t)return l=!0,0;var n,r=0,i=e.parentNode,o=t.parentNode,a=[e],s=[t];if(!i||!o)return e==C?-1:t==C?1:i?-1:o?1:u?P(u,e)-P(u,t):0;if(i===o)return pe(e,t);n=e;while(n=n.parentNode)a.unshift(n);n=t;while(n=n.parentNode)s.unshift(n);while(a[r]===s[r])r++;return r?pe(a[r],s[r]):a[r]==p?-1:s[r]==p?1:0}),C},se.matches=function(e,t){return se(e,null,null,t)},se.matchesSelector=function(e,t){if(T(e),d.matchesSelector&&E&&!N[t+" "]&&(!s||!s.test(t))&&(!v||!v.test(t)))try{var n=c.call(e,t);if(n||d.disconnectedMatch||e.document&&11!==e.document.nodeType)return n}catch(e){N(t,!0)}return 0":{dir:"parentNode",first:!0}," ":{dir:"parentNode"},"+":{dir:"previousSibling",first:!0},"~":{dir:"previousSibling"}},preFilter:{ATTR:function(e){return e[1]=e[1].replace(te,ne),e[3]=(e[3]||e[4]||e[5]||"").replace(te,ne),"~="===e[2]&&(e[3]=" "+e[3]+" "),e.slice(0,4)},CHILD:function(e){return e[1]=e[1].toLowerCase(),"nth"===e[1].slice(0,3)?(e[3]||se.error(e[0]),e[4]=+(e[4]?e[5]+(e[6]||1):2*("even"===e[3]||"odd"===e[3])),e[5]=+(e[7]+e[8]||"odd"===e[3])):e[3]&&se.error(e[0]),e},PSEUDO:function(e){var t,n=!e[6]&&e[2];return G.CHILD.test(e[0])?null:(e[3]?e[2]=e[4]||e[5]||"":n&&X.test(n)&&(t=h(n,!0))&&(t=n.indexOf(")",n.length-t)-n.length)&&(e[0]=e[0].slice(0,t),e[2]=n.slice(0,t)),e.slice(0,3))}},filter:{TAG:function(e){var t=e.replace(te,ne).toLowerCase();return"*"===e?function(){return!0}:function(e){return e.nodeName&&e.nodeName.toLowerCase()===t}},CLASS:function(e){var t=m[e+" "];return t||(t=new RegExp("(^|"+M+")"+e+"("+M+"|$)"))&&m(e,function(e){return t.test("string"==typeof e.className&&e.className||"undefined"!=typeof e.getAttribute&&e.getAttribute("class")||"")})},ATTR:function(n,r,i){return function(e){var t=se.attr(e,n);return null==t?"!="===r:!r||(t+="","="===r?t===i:"!="===r?t!==i:"^="===r?i&&0===t.indexOf(i):"*="===r?i&&-1:\x20\t\r\n\f]*)[\x20\t\r\n\f]*\/?>(?:<\/\1>|)$/i;function j(e,n,r){return m(n)?S.grep(e,function(e,t){return!!n.call(e,t,e)!==r}):n.nodeType?S.grep(e,function(e){return e===n!==r}):"string"!=typeof n?S.grep(e,function(e){return-1)[^>]*|#([\w-]+))$/;(S.fn.init=function(e,t,n){var r,i;if(!e)return this;if(n=n||D,"string"==typeof e){if(!(r="<"===e[0]&&">"===e[e.length-1]&&3<=e.length?[null,e,null]:q.exec(e))||!r[1]&&t)return!t||t.jquery?(t||n).find(e):this.constructor(t).find(e);if(r[1]){if(t=t instanceof S?t[0]:t,S.merge(this,S.parseHTML(r[1],t&&t.nodeType?t.ownerDocument||t:E,!0)),N.test(r[1])&&S.isPlainObject(t))for(r in t)m(this[r])?this[r](t[r]):this.attr(r,t[r]);return this}return(i=E.getElementById(r[2]))&&(this[0]=i,this.length=1),this}return e.nodeType?(this[0]=e,this.length=1,this):m(e)?void 0!==n.ready?n.ready(e):e(S):S.makeArray(e,this)}).prototype=S.fn,D=S(E);var L=/^(?:parents|prev(?:Until|All))/,H={children:!0,contents:!0,next:!0,prev:!0};function O(e,t){while((e=e[t])&&1!==e.nodeType);return e}S.fn.extend({has:function(e){var t=S(e,this),n=t.length;return this.filter(function(){for(var e=0;e\x20\t\r\n\f]*)/i,he=/^$|^module$|\/(?:java|ecma)script/i;ce=E.createDocumentFragment().appendChild(E.createElement("div")),(fe=E.createElement("input")).setAttribute("type","radio"),fe.setAttribute("checked","checked"),fe.setAttribute("name","t"),ce.appendChild(fe),y.checkClone=ce.cloneNode(!0).cloneNode(!0).lastChild.checked,ce.innerHTML="",y.noCloneChecked=!!ce.cloneNode(!0).lastChild.defaultValue,ce.innerHTML="",y.option=!!ce.lastChild;var ge={thead:[1,"","
"],col:[2,"","
"],tr:[2,"","
"],td:[3,"","
"],_default:[0,"",""]};function ve(e,t){var n;return n="undefined"!=typeof e.getElementsByTagName?e.getElementsByTagName(t||"*"):"undefined"!=typeof e.querySelectorAll?e.querySelectorAll(t||"*"):[],void 0===t||t&&A(e,t)?S.merge([e],n):n}function ye(e,t){for(var n=0,r=e.length;n",""]);var me=/<|&#?\w+;/;function xe(e,t,n,r,i){for(var o,a,s,u,l,c,f=t.createDocumentFragment(),p=[],d=0,h=e.length;d\s*$/g;function je(e,t){return A(e,"table")&&A(11!==t.nodeType?t:t.firstChild,"tr")&&S(e).children("tbody")[0]||e}function De(e){return e.type=(null!==e.getAttribute("type"))+"/"+e.type,e}function qe(e){return"true/"===(e.type||"").slice(0,5)?e.type=e.type.slice(5):e.removeAttribute("type"),e}function Le(e,t){var n,r,i,o,a,s;if(1===t.nodeType){if(Y.hasData(e)&&(s=Y.get(e).events))for(i in Y.remove(t,"handle events"),s)for(n=0,r=s[i].length;n").attr(n.scriptAttrs||{}).prop({charset:n.scriptCharset,src:n.url}).on("load error",i=function(e){r.remove(),i=null,e&&t("error"===e.type?404:200,e.type)}),E.head.appendChild(r[0])},abort:function(){i&&i()}}});var _t,zt=[],Ut=/(=)\?(?=&|$)|\?\?/;S.ajaxSetup({jsonp:"callback",jsonpCallback:function(){var e=zt.pop()||S.expando+"_"+wt.guid++;return this[e]=!0,e}}),S.ajaxPrefilter("json jsonp",function(e,t,n){var r,i,o,a=!1!==e.jsonp&&(Ut.test(e.url)?"url":"string"==typeof e.data&&0===(e.contentType||"").indexOf("application/x-www-form-urlencoded")&&Ut.test(e.data)&&"data");if(a||"jsonp"===e.dataTypes[0])return r=e.jsonpCallback=m(e.jsonpCallback)?e.jsonpCallback():e.jsonpCallback,a?e[a]=e[a].replace(Ut,"$1"+r):!1!==e.jsonp&&(e.url+=(Tt.test(e.url)?"&":"?")+e.jsonp+"="+r),e.converters["script json"]=function(){return o||S.error(r+" was not called"),o[0]},e.dataTypes[0]="json",i=C[r],C[r]=function(){o=arguments},n.always(function(){void 0===i?S(C).removeProp(r):C[r]=i,e[r]&&(e.jsonpCallback=t.jsonpCallback,zt.push(r)),o&&m(i)&&i(o[0]),o=i=void 0}),"script"}),y.createHTMLDocument=((_t=E.implementation.createHTMLDocument("").body).innerHTML="
",2===_t.childNodes.length),S.parseHTML=function(e,t,n){return"string"!=typeof e?[]:("boolean"==typeof t&&(n=t,t=!1),t||(y.createHTMLDocument?((r=(t=E.implementation.createHTMLDocument("")).createElement("base")).href=E.location.href,t.head.appendChild(r)):t=E),o=!n&&[],(i=N.exec(e))?[t.createElement(i[1])]:(i=xe([e],t,o),o&&o.length&&S(o).remove(),S.merge([],i.childNodes)));var r,i,o},S.fn.load=function(e,t,n){var r,i,o,a=this,s=e.indexOf(" ");return-1").append(S.parseHTML(e)).find(r):e)}).always(n&&function(e,t){a.each(function(){n.apply(this,o||[e.responseText,t,e])})}),this},S.expr.pseudos.animated=function(t){return S.grep(S.timers,function(e){return t===e.elem}).length},S.offset={setOffset:function(e,t,n){var r,i,o,a,s,u,l=S.css(e,"position"),c=S(e),f={};"static"===l&&(e.style.position="relative"),s=c.offset(),o=S.css(e,"top"),u=S.css(e,"left"),("absolute"===l||"fixed"===l)&&-1<(o+u).indexOf("auto")?(a=(r=c.position()).top,i=r.left):(a=parseFloat(o)||0,i=parseFloat(u)||0),m(t)&&(t=t.call(e,n,S.extend({},s))),null!=t.top&&(f.top=t.top-s.top+a),null!=t.left&&(f.left=t.left-s.left+i),"using"in t?t.using.call(e,f):c.css(f)}},S.fn.extend({offset:function(t){if(arguments.length)return void 0===t?this:this.each(function(e){S.offset.setOffset(this,t,e)});var e,n,r=this[0];return r?r.getClientRects().length?(e=r.getBoundingClientRect(),n=r.ownerDocument.defaultView,{top:e.top+n.pageYOffset,left:e.left+n.pageXOffset}):{top:0,left:0}:void 0},position:function(){if(this[0]){var e,t,n,r=this[0],i={top:0,left:0};if("fixed"===S.css(r,"position"))t=r.getBoundingClientRect();else{t=this.offset(),n=r.ownerDocument,e=r.offsetParent||n.documentElement;while(e&&(e===n.body||e===n.documentElement)&&"static"===S.css(e,"position"))e=e.parentNode;e&&e!==r&&1===e.nodeType&&((i=S(e).offset()).top+=S.css(e,"borderTopWidth",!0),i.left+=S.css(e,"borderLeftWidth",!0))}return{top:t.top-i.top-S.css(r,"marginTop",!0),left:t.left-i.left-S.css(r,"marginLeft",!0)}}},offsetParent:function(){return this.map(function(){var e=this.offsetParent;while(e&&"static"===S.css(e,"position"))e=e.offsetParent;return e||re})}}),S.each({scrollLeft:"pageXOffset",scrollTop:"pageYOffset"},function(t,i){var o="pageYOffset"===i;S.fn[t]=function(e){return $(this,function(e,t,n){var r;if(x(e)?r=e:9===e.nodeType&&(r=e.defaultView),void 0===n)return r?r[i]:e[t];r?r.scrollTo(o?r.pageXOffset:n,o?n:r.pageYOffset):e[t]=n},t,e,arguments.length)}}),S.each(["top","left"],function(e,n){S.cssHooks[n]=Fe(y.pixelPosition,function(e,t){if(t)return t=We(e,n),Pe.test(t)?S(e).position()[n]+"px":t})}),S.each({Height:"height",Width:"width"},function(a,s){S.each({padding:"inner"+a,content:s,"":"outer"+a},function(r,o){S.fn[o]=function(e,t){var n=arguments.length&&(r||"boolean"!=typeof e),i=r||(!0===e||!0===t?"margin":"border");return $(this,function(e,t,n){var r;return x(e)?0===o.indexOf("outer")?e["inner"+a]:e.document.documentElement["client"+a]:9===e.nodeType?(r=e.documentElement,Math.max(e.body["scroll"+a],r["scroll"+a],e.body["offset"+a],r["offset"+a],r["client"+a])):void 0===n?S.css(e,t,i):S.style(e,t,n,i)},s,n?e:void 0,n)}})}),S.each(["ajaxStart","ajaxStop","ajaxComplete","ajaxError","ajaxSuccess","ajaxSend"],function(e,t){S.fn[t]=function(e){return this.on(t,e)}}),S.fn.extend({bind:function(e,t,n){return this.on(e,null,t,n)},unbind:function(e,t){return this.off(e,null,t)},delegate:function(e,t,n,r){return this.on(t,e,n,r)},undelegate:function(e,t,n){return 1===arguments.length?this.off(e,"**"):this.off(t,e||"**",n)},hover:function(e,t){return this.mouseenter(e).mouseleave(t||e)}}),S.each("blur focus focusin focusout resize scroll click dblclick mousedown mouseup mousemove mouseover mouseout mouseenter mouseleave change select submit keydown keypress keyup contextmenu".split(" "),function(e,n){S.fn[n]=function(e,t){return 0. - */ // 1.0.3 /* The MIT License (MIT) diff --git a/src/dev-center/js/slugify.js b/src/dev-center/js/slugify.js index 289b1b5fcc..3970cb124d 100644 --- a/src/dev-center/js/slugify.js +++ b/src/dev-center/js/slugify.js @@ -1,22 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ - ;(function (name, root, factory) { if (typeof exports === 'object') { module.exports = factory() diff --git a/src/gui/src/IPC.js b/src/gui/src/IPC.js index 853af86569..1010601b27 100644 --- a/src/gui/src/IPC.js +++ b/src/gui/src/IPC.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/PuterDialog.js b/src/gui/src/UI/PuterDialog.js index 456edb551b..d2d37d61f2 100644 --- a/src/gui/src/UI/PuterDialog.js +++ b/src/gui/src/UI/PuterDialog.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Settings/UITabAbout.js b/src/gui/src/UI/Settings/UITabAbout.js index e4788f3f49..9f43f38710 100644 --- a/src/gui/src/UI/Settings/UITabAbout.js +++ b/src/gui/src/UI/Settings/UITabAbout.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Settings/UITabUsage.js b/src/gui/src/UI/Settings/UITabUsage.js index 87253b1a04..e4c805b6ef 100644 --- a/src/gui/src/UI/Settings/UITabUsage.js +++ b/src/gui/src/UI/Settings/UITabUsage.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Settings/UIWindowChangeEmail.js b/src/gui/src/UI/Settings/UIWindowChangeEmail.js index 3a2eaf1be0..787bcc893b 100644 --- a/src/gui/src/UI/Settings/UIWindowChangeEmail.js +++ b/src/gui/src/UI/Settings/UIWindowChangeEmail.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Settings/UIWindowConfirmUserDeletion.js b/src/gui/src/UI/Settings/UIWindowConfirmUserDeletion.js index 2404b4a1a4..41b0f390e2 100644 --- a/src/gui/src/UI/Settings/UIWindowConfirmUserDeletion.js +++ b/src/gui/src/UI/Settings/UIWindowConfirmUserDeletion.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Settings/UIWindowFinalizeUserDeletion.js b/src/gui/src/UI/Settings/UIWindowFinalizeUserDeletion.js index 3d3796f274..6ea097bf25 100644 --- a/src/gui/src/UI/Settings/UIWindowFinalizeUserDeletion.js +++ b/src/gui/src/UI/Settings/UIWindowFinalizeUserDeletion.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/Settings/UIWindowSettings.js b/src/gui/src/UI/Settings/UIWindowSettings.js index 686cd7fa6c..e50999511c 100644 --- a/src/gui/src/UI/Settings/UIWindowSettings.js +++ b/src/gui/src/UI/Settings/UIWindowSettings.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIAlert.js b/src/gui/src/UI/UIAlert.js index f19786985d..82f2a7b0af 100644 --- a/src/gui/src/UI/UIAlert.js +++ b/src/gui/src/UI/UIAlert.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIContextMenu.js b/src/gui/src/UI/UIContextMenu.js index 1cb9740db3..202852c7b1 100644 --- a/src/gui/src/UI/UIContextMenu.js +++ b/src/gui/src/UI/UIContextMenu.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIDesktop.js b/src/gui/src/UI/UIDesktop.js index 71bca049c4..fcad9b24d3 100644 --- a/src/gui/src/UI/UIDesktop.js +++ b/src/gui/src/UI/UIDesktop.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIItem.js b/src/gui/src/UI/UIItem.js index 3047ce2b35..5ef43227b4 100644 --- a/src/gui/src/UI/UIItem.js +++ b/src/gui/src/UI/UIItem.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UINotification.js b/src/gui/src/UI/UINotification.js index f0217b1663..587d0a813a 100644 --- a/src/gui/src/UI/UINotification.js +++ b/src/gui/src/UI/UINotification.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIPopover.js b/src/gui/src/UI/UIPopover.js index 950e1d17f5..23f6f21bb9 100644 --- a/src/gui/src/UI/UIPopover.js +++ b/src/gui/src/UI/UIPopover.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIPrompt.js b/src/gui/src/UI/UIPrompt.js index aff356a2a2..56b8f4ea4c 100644 --- a/src/gui/src/UI/UIPrompt.js +++ b/src/gui/src/UI/UIPrompt.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UITaskbar.js b/src/gui/src/UI/UITaskbar.js index de3557ba75..10cd0c0b0e 100644 --- a/src/gui/src/UI/UITaskbar.js +++ b/src/gui/src/UI/UITaskbar.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UITaskbarItem.js b/src/gui/src/UI/UITaskbarItem.js index c0eae73e17..fd293cced4 100644 --- a/src/gui/src/UI/UITaskbarItem.js +++ b/src/gui/src/UI/UITaskbarItem.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindow.js b/src/gui/src/UI/UIWindow.js index ee2937f607..223a6d6adc 100644 --- a/src/gui/src/UI/UIWindow.js +++ b/src/gui/src/UI/UIWindow.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowChangePassword.js b/src/gui/src/UI/UIWindowChangePassword.js index 4fc3e6506e..d2ff788377 100644 --- a/src/gui/src/UI/UIWindowChangePassword.js +++ b/src/gui/src/UI/UIWindowChangePassword.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowChangeUsername.js b/src/gui/src/UI/UIWindowChangeUsername.js index 1ed17311ab..e901c10c10 100644 --- a/src/gui/src/UI/UIWindowChangeUsername.js +++ b/src/gui/src/UI/UIWindowChangeUsername.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowClaimReferral.js b/src/gui/src/UI/UIWindowClaimReferral.js index 8f4a710492..68f558e1f7 100644 --- a/src/gui/src/UI/UIWindowClaimReferral.js +++ b/src/gui/src/UI/UIWindowClaimReferral.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowColorPicker.js b/src/gui/src/UI/UIWindowColorPicker.js index ae75140fea..70fe2b799e 100644 --- a/src/gui/src/UI/UIWindowColorPicker.js +++ b/src/gui/src/UI/UIWindowColorPicker.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowDesktopBGSettings.js b/src/gui/src/UI/UIWindowDesktopBGSettings.js index 9c96a9e5b5..45a253f518 100644 --- a/src/gui/src/UI/UIWindowDesktopBGSettings.js +++ b/src/gui/src/UI/UIWindowDesktopBGSettings.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowEmailConfirmationRequired.js b/src/gui/src/UI/UIWindowEmailConfirmationRequired.js index 8957f09754..56dce00520 100644 --- a/src/gui/src/UI/UIWindowEmailConfirmationRequired.js +++ b/src/gui/src/UI/UIWindowEmailConfirmationRequired.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowFeedback.js b/src/gui/src/UI/UIWindowFeedback.js index 6fe81813cf..77aa366e64 100644 --- a/src/gui/src/UI/UIWindowFeedback.js +++ b/src/gui/src/UI/UIWindowFeedback.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowFontPicker.js b/src/gui/src/UI/UIWindowFontPicker.js index 356f05a46f..a3bcacf42f 100644 --- a/src/gui/src/UI/UIWindowFontPicker.js +++ b/src/gui/src/UI/UIWindowFontPicker.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowItemProperties.js b/src/gui/src/UI/UIWindowItemProperties.js index 255b8ffe31..a05d6283d8 100644 --- a/src/gui/src/UI/UIWindowItemProperties.js +++ b/src/gui/src/UI/UIWindowItemProperties.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowLogin.js b/src/gui/src/UI/UIWindowLogin.js index bf05d5fe03..ba7e100294 100644 --- a/src/gui/src/UI/UIWindowLogin.js +++ b/src/gui/src/UI/UIWindowLogin.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowLoginInProgress.js b/src/gui/src/UI/UIWindowLoginInProgress.js index 9ebe505794..ff33fe8e6a 100644 --- a/src/gui/src/UI/UIWindowLoginInProgress.js +++ b/src/gui/src/UI/UIWindowLoginInProgress.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowMyWebsites.js b/src/gui/src/UI/UIWindowMyWebsites.js index 025a312145..33864ad09b 100644 --- a/src/gui/src/UI/UIWindowMyWebsites.js +++ b/src/gui/src/UI/UIWindowMyWebsites.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowNewPassword.js b/src/gui/src/UI/UIWindowNewPassword.js index 3340f9d2f3..eb8c242000 100644 --- a/src/gui/src/UI/UIWindowNewPassword.js +++ b/src/gui/src/UI/UIWindowNewPassword.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowProgress.js b/src/gui/src/UI/UIWindowProgress.js index 06a0d88ac3..3f11185837 100644 --- a/src/gui/src/UI/UIWindowProgress.js +++ b/src/gui/src/UI/UIWindowProgress.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowPublishWebsite.js b/src/gui/src/UI/UIWindowPublishWebsite.js index a45916f1c7..619a323e2d 100644 --- a/src/gui/src/UI/UIWindowPublishWebsite.js +++ b/src/gui/src/UI/UIWindowPublishWebsite.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowQR.js b/src/gui/src/UI/UIWindowQR.js index 5a4d6593d8..8976fc685e 100644 --- a/src/gui/src/UI/UIWindowQR.js +++ b/src/gui/src/UI/UIWindowQR.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowRecoverPassword.js b/src/gui/src/UI/UIWindowRecoverPassword.js index fbf2ccb873..87e0ec2718 100644 --- a/src/gui/src/UI/UIWindowRecoverPassword.js +++ b/src/gui/src/UI/UIWindowRecoverPassword.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowRefer.js b/src/gui/src/UI/UIWindowRefer.js index c5bd384099..2bc3a791b0 100644 --- a/src/gui/src/UI/UIWindowRefer.js +++ b/src/gui/src/UI/UIWindowRefer.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowRequestPermission.js b/src/gui/src/UI/UIWindowRequestPermission.js index 18f0dd7c17..470d949221 100644 --- a/src/gui/src/UI/UIWindowRequestPermission.js +++ b/src/gui/src/UI/UIWindowRequestPermission.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowSaveAccount.js b/src/gui/src/UI/UIWindowSaveAccount.js index 455420f72a..f0c7b86117 100644 --- a/src/gui/src/UI/UIWindowSaveAccount.js +++ b/src/gui/src/UI/UIWindowSaveAccount.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowSessionList.js b/src/gui/src/UI/UIWindowSessionList.js index dff49331fc..751f2e1857 100644 --- a/src/gui/src/UI/UIWindowSessionList.js +++ b/src/gui/src/UI/UIWindowSessionList.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/UI/UIWindowSignup.js b/src/gui/src/UI/UIWindowSignup.js index 0247b5bfca..842672c9b7 100644 --- a/src/gui/src/UI/UIWindowSignup.js +++ b/src/gui/src/UI/UIWindowSignup.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/css/style.css b/src/gui/src/css/style.css index 2943002602..e0cc475da2 100644 --- a/src/gui/src/css/style.css +++ b/src/gui/src/css/style.css @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/globals.js b/src/gui/src/globals.js index 9f0e8441bf..4f0c2d98a3 100644 --- a/src/gui/src/globals.js +++ b/src/gui/src/globals.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers.js b/src/gui/src/helpers.js index e6019dd336..394bcc65f1 100644 --- a/src/gui/src/helpers.js +++ b/src/gui/src/helpers.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/check_password_strength.js b/src/gui/src/helpers/check_password_strength.js index 429e8bffd0..4b0136e67a 100644 --- a/src/gui/src/helpers/check_password_strength.js +++ b/src/gui/src/helpers/check_password_strength.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/content_type_to_icon.js b/src/gui/src/helpers/content_type_to_icon.js index 9e32fe7b45..1cec143d4d 100644 --- a/src/gui/src/helpers/content_type_to_icon.js +++ b/src/gui/src/helpers/content_type_to_icon.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/determine_active_container_parent.js b/src/gui/src/helpers/determine_active_container_parent.js index 775e89c887..c66d03f68d 100644 --- a/src/gui/src/helpers/determine_active_container_parent.js +++ b/src/gui/src/helpers/determine_active_container_parent.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/download.js b/src/gui/src/helpers/download.js index f973a63109..b00d9bcaa7 100644 --- a/src/gui/src/helpers/download.js +++ b/src/gui/src/helpers/download.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/fixedEncodeURIComponent.js b/src/gui/src/helpers/fixedEncodeURIComponent.js index fb7530d13c..d6728d811f 100644 --- a/src/gui/src/helpers/fixedEncodeURIComponent.js +++ b/src/gui/src/helpers/fixedEncodeURIComponent.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/get_html_element_from_options.js b/src/gui/src/helpers/get_html_element_from_options.js index 9a725cd3b7..ee464d5f22 100644 --- a/src/gui/src/helpers/get_html_element_from_options.js +++ b/src/gui/src/helpers/get_html_element_from_options.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/globToRegExp.js b/src/gui/src/helpers/globToRegExp.js index f0340f1fad..d58be6d685 100644 --- a/src/gui/src/helpers/globToRegExp.js +++ b/src/gui/src/helpers/globToRegExp.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/item_icon.js b/src/gui/src/helpers/item_icon.js index 36d5410c4e..f17ea7893b 100644 --- a/src/gui/src/helpers/item_icon.js +++ b/src/gui/src/helpers/item_icon.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/launch_app.js b/src/gui/src/helpers/launch_app.js index 565dcc2f53..d6dc6553fe 100644 --- a/src/gui/src/helpers/launch_app.js +++ b/src/gui/src/helpers/launch_app.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/new_context_menu_item.js b/src/gui/src/helpers/new_context_menu_item.js index 3a616597bb..6c2ea49e14 100644 --- a/src/gui/src/helpers/new_context_menu_item.js +++ b/src/gui/src/helpers/new_context_menu_item.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/open_item.js b/src/gui/src/helpers/open_item.js index 52551678eb..efdf3686fd 100644 --- a/src/gui/src/helpers/open_item.js +++ b/src/gui/src/helpers/open_item.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/refresh_item_container.js b/src/gui/src/helpers/refresh_item_container.js index b64bf710f7..3de003295d 100644 --- a/src/gui/src/helpers/refresh_item_container.js +++ b/src/gui/src/helpers/refresh_item_container.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/socialLink.js b/src/gui/src/helpers/socialLink.js index efe702bc01..698ef9f1f2 100644 --- a/src/gui/src/helpers/socialLink.js +++ b/src/gui/src/helpers/socialLink.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/update_last_touch_coordinates.js b/src/gui/src/helpers/update_last_touch_coordinates.js index 3d036c8464..a814bb3a8c 100644 --- a/src/gui/src/helpers/update_last_touch_coordinates.js +++ b/src/gui/src/helpers/update_last_touch_coordinates.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/update_mouse_position.js b/src/gui/src/helpers/update_mouse_position.js index 01f6e4dd25..7b433180ee 100644 --- a/src/gui/src/helpers/update_mouse_position.js +++ b/src/gui/src/helpers/update_mouse_position.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/update_title_based_on_uploads.js b/src/gui/src/helpers/update_title_based_on_uploads.js index 7c55853f0d..aa0beadd74 100644 --- a/src/gui/src/helpers/update_title_based_on_uploads.js +++ b/src/gui/src/helpers/update_title_based_on_uploads.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/helpers/update_username_in_gui.js b/src/gui/src/helpers/update_username_in_gui.js index 32c2806e48..78c2f35353 100644 --- a/src/gui/src/helpers/update_username_in_gui.js +++ b/src/gui/src/helpers/update_username_in_gui.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/keyboard.js b/src/gui/src/keyboard.js index 4ee1f7544b..aa9e448708 100644 --- a/src/gui/src/keyboard.js +++ b/src/gui/src/keyboard.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * diff --git a/src/gui/src/static-assets.js b/src/gui/src/static-assets.js index 7b07d48c30..1b8b0e5d58 100644 --- a/src/gui/src/static-assets.js +++ b/src/gui/src/static-assets.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /** * Copyright (C) 2024 Puter Technologies Inc. * From 00eabd7b10903101cfffc298453fe46c663ac925 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 9 Jul 2024 13:50:20 -0700 Subject: [PATCH 0487/2119] remove duplicate and/or incorrect license headers --- src/contextlink/context.js | 18 ------------------ src/contextlink/entry.js | 18 ------------------ src/contextlink/test/testcontext.js | 18 ------------------ src/git/config/dev.js | 18 ------------------ src/git/config/release.js | 18 ------------------ src/git/rollup.config.js | 18 ------------------ src/git/src/auth.js | 2 +- src/git/src/color.js | 2 +- src/git/src/diff.js | 2 +- src/git/src/filesystem.js | 2 +- src/git/src/format.js | 2 +- src/git/src/git-command-definition.js | 2 +- src/git/src/git-helpers.js | 2 +- src/git/src/help.js | 2 +- src/git/src/main.js | 2 +- src/git/src/refs.js | 2 +- src/git/src/subcommands/__exports__.js | 18 ------------------ src/git/src/subcommands/add.js | 2 +- src/git/src/subcommands/branch.js | 2 +- src/git/src/subcommands/checkout.js | 2 +- src/git/src/subcommands/cherry-pick.js | 2 +- src/git/src/subcommands/clone.js | 2 +- src/git/src/subcommands/commit.js | 2 +- src/git/src/subcommands/config.js | 2 +- src/git/src/subcommands/diff.js | 2 +- src/git/src/subcommands/fetch.js | 2 +- src/git/src/subcommands/help.js | 2 +- src/git/src/subcommands/init.js | 2 +- src/git/src/subcommands/log.js | 2 +- src/git/src/subcommands/pull.js | 2 +- src/git/src/subcommands/push.js | 2 +- src/git/src/subcommands/remote.js | 2 +- src/git/src/subcommands/restore.js | 2 +- src/git/src/subcommands/show.js | 2 +- src/git/src/subcommands/status.js | 2 +- src/git/src/subcommands/version.js | 2 +- src/gui/utils.js | 2 +- src/phoenix/config/dev.js | 18 ------------------ src/phoenix/config/release.js | 18 ------------------ src/phoenix/doc/license_header.txt | 2 +- src/phoenix/doc/stash/SymbolParserImpl.js | 18 ------------------ src/phoenix/rollup.config.js | 18 ------------------ src/phoenix/src/ansi-shell/ANSIContext.js | 18 ------------------ src/phoenix/src/ansi-shell/ANSIShell.js | 18 ------------------ .../src/ansi-shell/ConcreteSyntaxError.js | 18 ------------------ .../ansi-shell/arg-parsers/simple-parser.js | 18 ------------------ .../src/ansi-shell/decorators/errors.js | 18 ------------------ .../src/ansi-shell/ioutil/ByteWriter.js | 18 ------------------ .../src/ansi-shell/ioutil/MemReader.js | 18 ------------------ .../src/ansi-shell/ioutil/MemWriter.js | 18 ------------------ .../src/ansi-shell/ioutil/MultiWriter.js | 18 ------------------ .../src/ansi-shell/ioutil/NullifyWriter.js | 18 ------------------ .../src/ansi-shell/ioutil/ProxyReader.js | 18 ------------------ .../src/ansi-shell/ioutil/ProxyWriter.js | 18 ------------------ .../src/ansi-shell/ioutil/SignalReader.js | 18 ------------------ .../src/ansi-shell/ioutil/SyncLinesReader.js | 18 ------------------ .../src/ansi-shell/parsing/PARSE_CONSTANTS.js | 18 ------------------ .../ansi-shell/parsing/PuterShellParser.js | 18 ------------------ .../parsing/UnquotedTokenParserImpl.js | 18 ------------------ .../src/ansi-shell/parsing/brainstorming.js | 18 ------------------ .../parsing/buildParserFirstHalf.js | 18 ------------------ .../parsing/buildParserSecondHalf.js | 18 ------------------ .../src/ansi-shell/pipeline/Coupler.js | 18 ------------------ src/phoenix/src/ansi-shell/pipeline/Pipe.js | 18 ------------------ .../src/ansi-shell/pipeline/Pipeline.js | 18 ------------------ .../src/ansi-shell/pipeline/iowrappers.js | 18 ------------------ .../src/ansi-shell/readline/history.js | 18 ------------------ .../src/ansi-shell/readline/readline.js | 18 ------------------ .../src/ansi-shell/readline/readtoken.js | 18 ------------------ .../src/ansi-shell/readline/rl_comprehend.js | 18 ------------------ .../ansi-shell/readline/rl_csi_handlers.js | 18 ------------------ .../src/ansi-shell/readline/rl_words.js | 18 ------------------ src/phoenix/src/ansi-shell/signals.js | 18 ------------------ src/phoenix/src/context/context.js | 18 ------------------ src/phoenix/src/main_cli.js | 18 ------------------ src/phoenix/src/main_puter.js | 18 ------------------ src/phoenix/src/meta/versions.js | 18 ------------------ src/phoenix/src/platform/node/filesystem.js | 18 ------------------ src/phoenix/src/platform/puter/drivers.js | 18 ------------------ src/phoenix/src/platform/puter/filesystem.js | 18 ------------------ src/phoenix/src/pty/XDocumentPTT.js | 18 ------------------ .../completers/CommandCompleter.js | 18 ------------------ .../puter-shell/completers/FileCompleter.js | 18 ------------------ .../puter-shell/completers/OptionCompleter.js | 18 ------------------ .../src/puter-shell/coreutils/__exports__.js | 18 ------------------ src/phoenix/src/puter-shell/coreutils/ai.js | 18 ------------------ .../src/puter-shell/coreutils/basename.js | 18 ------------------ src/phoenix/src/puter-shell/coreutils/cat.js | 18 ------------------ src/phoenix/src/puter-shell/coreutils/cd.js | 18 ------------------ .../src/puter-shell/coreutils/changelog.js | 18 ------------------ .../src/puter-shell/coreutils/clear.js | 18 ------------------ .../coreutils/coreutil_lib/echo_escapes.js | 18 ------------------ .../coreutils/coreutil_lib/exit.js | 18 ------------------ .../coreutils/coreutil_lib/help.js | 18 ------------------ .../coreutils/coreutil_lib/validate.js | 18 ------------------ src/phoenix/src/puter-shell/coreutils/cp.js | 18 ------------------ src/phoenix/src/puter-shell/coreutils/date.js | 18 ------------------ .../src/puter-shell/coreutils/dcall.js | 18 ------------------ .../src/puter-shell/coreutils/dirname.js | 18 ------------------ src/phoenix/src/puter-shell/coreutils/echo.js | 18 ------------------ src/phoenix/src/puter-shell/coreutils/env.js | 18 ------------------ .../src/puter-shell/coreutils/errno.js | 18 ------------------ src/phoenix/src/puter-shell/coreutils/exit.js | 18 ------------------ .../src/puter-shell/coreutils/false.js | 18 ------------------ src/phoenix/src/puter-shell/coreutils/grep.js | 18 ------------------ src/phoenix/src/puter-shell/coreutils/head.js | 18 ------------------ src/phoenix/src/puter-shell/coreutils/help.js | 18 ------------------ src/phoenix/src/puter-shell/coreutils/jq.js | 18 ------------------ .../src/puter-shell/coreutils/login.js | 18 ------------------ src/phoenix/src/puter-shell/coreutils/ls.js | 18 ------------------ src/phoenix/src/puter-shell/coreutils/man.js | 18 ------------------ .../src/puter-shell/coreutils/mkdir.js | 18 ------------------ src/phoenix/src/puter-shell/coreutils/mv.js | 18 ------------------ .../src/puter-shell/coreutils/neofetch.js | 18 ------------------ .../src/puter-shell/coreutils/printf.js | 18 ------------------ .../src/puter-shell/coreutils/printhist.js | 18 ------------------ src/phoenix/src/puter-shell/coreutils/pwd.js | 18 ------------------ src/phoenix/src/puter-shell/coreutils/rm.js | 18 ------------------ .../src/puter-shell/coreutils/rmdir.js | 18 ------------------ .../src/puter-shell/coreutils/sample-data.js | 18 ------------------ src/phoenix/src/puter-shell/coreutils/sed.js | 18 ------------------ .../src/puter-shell/coreutils/sed/address.js | 18 ------------------ .../src/puter-shell/coreutils/sed/command.js | 18 ------------------ .../src/puter-shell/coreutils/sed/parser.js | 18 ------------------ .../src/puter-shell/coreutils/sed/script.js | 18 ------------------ .../src/puter-shell/coreutils/sed/utils.js | 18 ------------------ .../src/puter-shell/coreutils/sleep.js | 18 ------------------ src/phoenix/src/puter-shell/coreutils/sort.js | 18 ------------------ src/phoenix/src/puter-shell/coreutils/tail.js | 18 ------------------ src/phoenix/src/puter-shell/coreutils/test.js | 18 ------------------ .../src/puter-shell/coreutils/touch.js | 18 ------------------ src/phoenix/src/puter-shell/coreutils/true.js | 18 ------------------ .../src/puter-shell/coreutils/txt2img.js | 18 ------------------ .../src/puter-shell/coreutils/usages.js | 18 ------------------ src/phoenix/src/puter-shell/coreutils/wc.js | 18 ------------------ .../src/puter-shell/coreutils/which.js | 18 ------------------ src/phoenix/src/puter-shell/main.js | 18 ------------------ .../puter-shell/plugins/ChatHistoryPlugin.js | 18 ------------------ .../providers/BuiltinCommandProvider.js | 18 ------------------ .../providers/CompositeCommandProvider.js | 18 ------------------ .../providers/PathCommandProvider.js | 18 ------------------ .../providers/PuterAppCommandProvider.js | 18 ------------------ .../providers/ScriptCommandProvider.js | 18 ------------------ src/phoenix/src/util/bytes.js | 18 ------------------ src/phoenix/src/util/lang.js | 18 ------------------ src/phoenix/src/util/log.js | 18 ------------------ src/phoenix/src/util/path.js | 18 ------------------ src/phoenix/src/util/singleton.js | 18 ------------------ src/phoenix/src/util/statemachine.js | 18 ------------------ src/phoenix/src/util/wrap-text.js | 18 ------------------ src/phoenix/test.js | 18 ------------------ src/phoenix/test/coreutils.test.js | 18 ------------------ src/phoenix/test/coreutils/basename.js | 18 ------------------ src/phoenix/test/coreutils/date.js | 18 ------------------ src/phoenix/test/coreutils/dirname.js | 18 ------------------ src/phoenix/test/coreutils/echo.js | 18 ------------------ src/phoenix/test/coreutils/env.js | 18 ------------------ src/phoenix/test/coreutils/errno.js | 18 ------------------ src/phoenix/test/coreutils/false.js | 18 ------------------ src/phoenix/test/coreutils/harness.js | 18 ------------------ src/phoenix/test/coreutils/head.js | 18 ------------------ src/phoenix/test/coreutils/printf.js | 18 ------------------ src/phoenix/test/coreutils/sleep.js | 18 ------------------ src/phoenix/test/coreutils/sort.js | 18 ------------------ src/phoenix/test/coreutils/tail.js | 18 ------------------ src/phoenix/test/coreutils/true.js | 18 ------------------ src/phoenix/test/coreutils/wc.js | 18 ------------------ src/phoenix/test/readtoken.js | 18 ------------------ src/phoenix/test/test-bytes.js | 18 ------------------ src/phoenix/test/test-stateful-processor.js | 18 ------------------ src/phoenix/test/wrap-text.js | 18 ------------------ src/phoenix/tools/gen.js | 18 ------------------ src/pty/exports.js | 18 ------------------ src/puter-js-common/src/PosixError.js | 19 +------------------ src/puter-js/src/index.js | 18 ------------------ src/puter-js/src/modules/AI.js | 18 ------------------ src/puter-js/src/modules/Apps.js | 18 ------------------ src/puter-js/src/modules/Auth.js | 18 ------------------ src/puter-js/src/modules/Email.js | 18 ------------------ src/puter-js/src/modules/FSItem.js | 18 ------------------ src/puter-js/src/modules/FileSystem/index.js | 18 ------------------ .../src/modules/FileSystem/operations/copy.js | 18 ------------------ .../FileSystem/operations/deleteFSEntry.js | 18 ------------------ .../modules/FileSystem/operations/mkdir.js | 18 ------------------ .../src/modules/FileSystem/operations/move.js | 18 ------------------ .../src/modules/FileSystem/operations/read.js | 18 ------------------ .../modules/FileSystem/operations/readdir.js | 18 ------------------ .../modules/FileSystem/operations/rename.js | 18 ------------------ .../src/modules/FileSystem/operations/sign.js | 18 ------------------ .../modules/FileSystem/operations/space.js | 18 ------------------ .../src/modules/FileSystem/operations/stat.js | 18 ------------------ .../modules/FileSystem/operations/upload.js | 18 ------------------ .../modules/FileSystem/operations/write.js | 18 ------------------ .../FileSystem/utils/getAbsolutePathForApp.js | 18 ------------------ src/puter-js/src/modules/Hosting.js | 18 ------------------ src/puter-js/src/modules/KV.js | 18 ------------------ src/puter-js/src/modules/OS.js | 18 ------------------ src/puter-js/src/modules/PuterDialog.js | 18 ------------------ src/puter-js/src/modules/UI.js | 18 ------------------ src/puter-js/src/modules/Util.js | 18 ------------------ src/puter-js/test/fs.test.js | 18 ------------------ src/puter-js/test/kv.test.js | 18 ------------------ src/strataparse/dsl/ParserBuilder.js | 18 ------------------ src/strataparse/dsl/ParserRegistry.js | 18 ------------------ src/strataparse/exports.js | 18 ------------------ src/strataparse/parse.js | 18 ------------------ .../parse_impls/StrUntilParserImpl.js | 18 ------------------ src/strataparse/parse_impls/combinators.js | 18 ------------------ src/strataparse/parse_impls/literal.js | 18 ------------------ src/strataparse/parse_impls/whitespace.js | 18 ------------------ src/strataparse/strata.js | 18 ------------------ .../ContextSwitchingPStratumImpl.js | 18 ------------------ .../FirstRecognizedPStratumImpl.js | 18 ------------------ .../MergeWhitespacePStratumImpl.js | 18 ------------------ src/strataparse/strata_impls/terminals.js | 18 ------------------ src/terminal/assets/normalize.css | 2 +- src/terminal/assets/style.css | 2 +- src/terminal/config/dev.js | 2 +- src/terminal/config/release.js | 2 +- src/terminal/doc/license_header.txt | 2 +- src/terminal/rollup.config.js | 2 +- src/terminal/src/main.js | 2 +- src/terminal/src/pty/PTT.js | 2 +- src/terminal/src/pty/PTY.js | 2 +- src/terminal/src/pty/XDocumentANSIShell.js | 2 +- 225 files changed, 42 insertions(+), 3353 deletions(-) diff --git a/src/contextlink/context.js b/src/contextlink/context.js index 3c7bfe8f45..123445264c 100644 --- a/src/contextlink/context.js +++ b/src/contextlink/context.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export class Context { constructor (values) { for ( const k in values ) this[k] = values[k]; diff --git a/src/contextlink/entry.js b/src/contextlink/entry.js index 9bb711a67b..3583855c5f 100644 --- a/src/contextlink/entry.js +++ b/src/contextlink/entry.js @@ -16,22 +16,4 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export { Context } from "./context.js"; diff --git a/src/contextlink/test/testcontext.js b/src/contextlink/test/testcontext.js index d57c4dd3dd..9f50368dbb 100644 --- a/src/contextlink/test/testcontext.js +++ b/src/contextlink/test/testcontext.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import assert from 'assert'; import { Context } from "../context.js"; diff --git a/src/git/config/dev.js b/src/git/config/dev.js index 9b73c08fcd..4bc464f7d5 100644 --- a/src/git/config/dev.js +++ b/src/git/config/dev.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ globalThis.__CONFIG__ = { sdk_url: 'http://puter.localhost:4100/sdk/puter.js', proxy_url: 'https://cors.isomorphic-git.org', diff --git a/src/git/config/release.js b/src/git/config/release.js index 2af4d14db2..dc287e06e1 100644 --- a/src/git/config/release.js +++ b/src/git/config/release.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ globalThis.__CONFIG__ = { sdk_url: 'https://puter.com/puter.js/v2', // TODO: Host a proxy ourselves, so we're not relying on (and maybe overloading) theirs. diff --git a/src/git/rollup.config.js b/src/git/rollup.config.js index 054059f7ef..0097eaef58 100644 --- a/src/git/rollup.config.js +++ b/src/git/rollup.config.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { nodeResolve } from '@rollup/plugin-node-resolve' import commonjs from '@rollup/plugin-commonjs'; import copy from 'rollup-plugin-copy'; diff --git a/src/git/src/auth.js b/src/git/src/auth.js index caf1e6ec99..54828f1545 100644 --- a/src/git/src/auth.js +++ b/src/git/src/auth.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/color.js b/src/git/src/color.js index 6800b08ff0..48d46cab82 100644 --- a/src/git/src/color.js +++ b/src/git/src/color.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/diff.js b/src/git/src/diff.js index 2a1e700dac..86da0ed2aa 100644 --- a/src/git/src/diff.js +++ b/src/git/src/diff.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/filesystem.js b/src/git/src/filesystem.js index 51c51b1ac2..2378bd0aad 100644 --- a/src/git/src/filesystem.js +++ b/src/git/src/filesystem.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/format.js b/src/git/src/format.js index 437ab1b159..3c721d95d6 100644 --- a/src/git/src/format.js +++ b/src/git/src/format.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/git-command-definition.js b/src/git/src/git-command-definition.js index 57bbdd8f82..a710df3102 100644 --- a/src/git/src/git-command-definition.js +++ b/src/git/src/git-command-definition.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/git-helpers.js b/src/git/src/git-helpers.js index 215e6b28fb..22c3531dbe 100644 --- a/src/git/src/git-helpers.js +++ b/src/git/src/git-helpers.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/help.js b/src/git/src/help.js index 5f6b982422..6b703e7463 100644 --- a/src/git/src/help.js +++ b/src/git/src/help.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/main.js b/src/git/src/main.js index a110d22c4b..86e060a005 100644 --- a/src/git/src/main.js +++ b/src/git/src/main.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/refs.js b/src/git/src/refs.js index f335d19960..eaae68782e 100644 --- a/src/git/src/refs.js +++ b/src/git/src/refs.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/subcommands/__exports__.js b/src/git/src/subcommands/__exports__.js index b62a22efa3..cbd354c57f 100644 --- a/src/git/src/subcommands/__exports__.js +++ b/src/git/src/subcommands/__exports__.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ // Generated by /tools/gen.js import module_add from './add.js' import module_branch from './branch.js' diff --git a/src/git/src/subcommands/add.js b/src/git/src/subcommands/add.js index dd85c54e45..8233fcbadc 100644 --- a/src/git/src/subcommands/add.js +++ b/src/git/src/subcommands/add.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/subcommands/branch.js b/src/git/src/subcommands/branch.js index dec1d04bee..1866e046cf 100644 --- a/src/git/src/subcommands/branch.js +++ b/src/git/src/subcommands/branch.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/subcommands/checkout.js b/src/git/src/subcommands/checkout.js index 91d30c819b..ddd848b4f6 100644 --- a/src/git/src/subcommands/checkout.js +++ b/src/git/src/subcommands/checkout.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/subcommands/cherry-pick.js b/src/git/src/subcommands/cherry-pick.js index a8c963234a..377e7334d5 100644 --- a/src/git/src/subcommands/cherry-pick.js +++ b/src/git/src/subcommands/cherry-pick.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/subcommands/clone.js b/src/git/src/subcommands/clone.js index 9b61668fa6..c93da28b3f 100644 --- a/src/git/src/subcommands/clone.js +++ b/src/git/src/subcommands/clone.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/subcommands/commit.js b/src/git/src/subcommands/commit.js index 5070749a01..0af26fcb4f 100644 --- a/src/git/src/subcommands/commit.js +++ b/src/git/src/subcommands/commit.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/subcommands/config.js b/src/git/src/subcommands/config.js index 94b41a3ead..2b604e55cc 100644 --- a/src/git/src/subcommands/config.js +++ b/src/git/src/subcommands/config.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/subcommands/diff.js b/src/git/src/subcommands/diff.js index bde2b4ecc9..a46b7f1e23 100644 --- a/src/git/src/subcommands/diff.js +++ b/src/git/src/subcommands/diff.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/subcommands/fetch.js b/src/git/src/subcommands/fetch.js index d9ac9ff116..d65e0772cb 100644 --- a/src/git/src/subcommands/fetch.js +++ b/src/git/src/subcommands/fetch.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/subcommands/help.js b/src/git/src/subcommands/help.js index 20b8ed38a7..af48792d40 100644 --- a/src/git/src/subcommands/help.js +++ b/src/git/src/subcommands/help.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/subcommands/init.js b/src/git/src/subcommands/init.js index 7c644766a3..df7e3ddf63 100644 --- a/src/git/src/subcommands/init.js +++ b/src/git/src/subcommands/init.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/subcommands/log.js b/src/git/src/subcommands/log.js index 747ebcc6ef..2741df3978 100644 --- a/src/git/src/subcommands/log.js +++ b/src/git/src/subcommands/log.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/subcommands/pull.js b/src/git/src/subcommands/pull.js index f6748c9d10..daff7c713d 100644 --- a/src/git/src/subcommands/pull.js +++ b/src/git/src/subcommands/pull.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/subcommands/push.js b/src/git/src/subcommands/push.js index 5b72d9c377..4d87887608 100644 --- a/src/git/src/subcommands/push.js +++ b/src/git/src/subcommands/push.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/subcommands/remote.js b/src/git/src/subcommands/remote.js index 18c48d861b..f3fd32b562 100644 --- a/src/git/src/subcommands/remote.js +++ b/src/git/src/subcommands/remote.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/subcommands/restore.js b/src/git/src/subcommands/restore.js index d52ac2cf5e..d49f64f7b4 100644 --- a/src/git/src/subcommands/restore.js +++ b/src/git/src/subcommands/restore.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/subcommands/show.js b/src/git/src/subcommands/show.js index b6856dba6c..77cf6f5b4c 100644 --- a/src/git/src/subcommands/show.js +++ b/src/git/src/subcommands/show.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/subcommands/status.js b/src/git/src/subcommands/status.js index f9f06897fe..c4c053bd6f 100644 --- a/src/git/src/subcommands/status.js +++ b/src/git/src/subcommands/status.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/git/src/subcommands/version.js b/src/git/src/subcommands/version.js index 0ce009d8c5..6bf82f3b0b 100644 --- a/src/git/src/subcommands/version.js +++ b/src/git/src/subcommands/version.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Git client. * diff --git a/src/gui/utils.js b/src/gui/utils.js index e0ff55a287..d5b1d21a35 100644 --- a/src/gui/utils.js +++ b/src/gui/utils.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* -Copyright (C) 2024 Puter Technologies Inc. +Copyright (C) 2024 Puter Technologies Inc. This file is part of Puter.com. diff --git a/src/phoenix/config/dev.js b/src/phoenix/config/dev.js index fb4a27c34c..78843bd89d 100644 --- a/src/phoenix/config/dev.js +++ b/src/phoenix/config/dev.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ globalThis.__CONFIG__ = { "origin": "https://puter.local:8080", "shell.href": "https://puter.local:8081", diff --git a/src/phoenix/config/release.js b/src/phoenix/config/release.js index 8e00ff05b9..8a11c77dfb 100644 --- a/src/phoenix/config/release.js +++ b/src/phoenix/config/release.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ globalThis.__CONFIG__ = { origin: "https://xd.puter.sh", sdk_url: 'https://puter.com/puter.js/v2', diff --git a/src/phoenix/doc/license_header.txt b/src/phoenix/doc/license_header.txt index ec7fa58466..282276a28c 100644 --- a/src/phoenix/doc/license_header.txt +++ b/src/phoenix/doc/license_header.txt @@ -1,4 +1,4 @@ -Copyright (C) 2024 Puter Technologies Inc. +Copyright (C) 2024 Puter Technologies Inc. This file is part of Phoenix Shell. diff --git a/src/phoenix/doc/stash/SymbolParserImpl.js b/src/phoenix/doc/stash/SymbolParserImpl.js index 5ad3c9a0e8..0623eb844f 100644 --- a/src/phoenix/doc/stash/SymbolParserImpl.js +++ b/src/phoenix/doc/stash/SymbolParserImpl.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ // Here for safe-keeping - wasn't correct for shell tokens but // it will be needed later for variable assignments diff --git a/src/phoenix/rollup.config.js b/src/phoenix/rollup.config.js index 9b58543dbb..ae7dfb13c3 100644 --- a/src/phoenix/rollup.config.js +++ b/src/phoenix/rollup.config.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { nodeResolve } from '@rollup/plugin-node-resolve' import commonjs from '@rollup/plugin-commonjs'; import copy from 'rollup-plugin-copy'; diff --git a/src/phoenix/src/ansi-shell/ANSIContext.js b/src/phoenix/src/ansi-shell/ANSIContext.js index 5fca280122..612c9b3acd 100644 --- a/src/phoenix/src/ansi-shell/ANSIContext.js +++ b/src/phoenix/src/ansi-shell/ANSIContext.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { Context } from "../context/context.js"; const modifiers = ['shift', 'alt', 'ctrl', 'meta']; diff --git a/src/phoenix/src/ansi-shell/ANSIShell.js b/src/phoenix/src/ansi-shell/ANSIShell.js index f0a0baad8c..93df6c31af 100644 --- a/src/phoenix/src/ansi-shell/ANSIShell.js +++ b/src/phoenix/src/ansi-shell/ANSIShell.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { ConcreteSyntaxError } from "./ConcreteSyntaxError.js"; import { MultiWriter } from "./ioutil/MultiWriter.js"; import { Coupler } from "./pipeline/Coupler.js"; diff --git a/src/phoenix/src/ansi-shell/ConcreteSyntaxError.js b/src/phoenix/src/ansi-shell/ConcreteSyntaxError.js index 70bc7b33d8..9ea38d4ddc 100644 --- a/src/phoenix/src/ansi-shell/ConcreteSyntaxError.js +++ b/src/phoenix/src/ansi-shell/ConcreteSyntaxError.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ /** * An error for which the location it occurred within the input is known. */ diff --git a/src/phoenix/src/ansi-shell/arg-parsers/simple-parser.js b/src/phoenix/src/ansi-shell/arg-parsers/simple-parser.js index 0c77fec5ec..44b47a27f4 100644 --- a/src/phoenix/src/ansi-shell/arg-parsers/simple-parser.js +++ b/src/phoenix/src/ansi-shell/arg-parsers/simple-parser.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { parseArgs } from '@pkgjs/parseargs'; import { DEFAULT_OPTIONS } from '../../puter-shell/coreutils/coreutil_lib/help.js'; diff --git a/src/phoenix/src/ansi-shell/decorators/errors.js b/src/phoenix/src/ansi-shell/decorators/errors.js index fb81bb6138..199a6262d2 100644 --- a/src/phoenix/src/ansi-shell/decorators/errors.js +++ b/src/phoenix/src/ansi-shell/decorators/errors.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export default { name: 'errors', decorate (fn, { command, ctx }) { diff --git a/src/phoenix/src/ansi-shell/ioutil/ByteWriter.js b/src/phoenix/src/ansi-shell/ioutil/ByteWriter.js index 756ca4095f..d29fb46f7f 100644 --- a/src/phoenix/src/ansi-shell/ioutil/ByteWriter.js +++ b/src/phoenix/src/ansi-shell/ioutil/ByteWriter.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { ProxyWriter } from "./ProxyWriter.js"; const encoder = new TextEncoder(); diff --git a/src/phoenix/src/ansi-shell/ioutil/MemReader.js b/src/phoenix/src/ansi-shell/ioutil/MemReader.js index 11a7c8f1ba..b412c7de0a 100644 --- a/src/phoenix/src/ansi-shell/ioutil/MemReader.js +++ b/src/phoenix/src/ansi-shell/ioutil/MemReader.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export class MemReader { constructor (data) { this.data = data; diff --git a/src/phoenix/src/ansi-shell/ioutil/MemWriter.js b/src/phoenix/src/ansi-shell/ioutil/MemWriter.js index aa1675a492..8c59a6ff28 100644 --- a/src/phoenix/src/ansi-shell/ioutil/MemWriter.js +++ b/src/phoenix/src/ansi-shell/ioutil/MemWriter.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ const encoder = new TextEncoder(); export class MemWriter { diff --git a/src/phoenix/src/ansi-shell/ioutil/MultiWriter.js b/src/phoenix/src/ansi-shell/ioutil/MultiWriter.js index 75e14f0f1a..939b3e7d26 100644 --- a/src/phoenix/src/ansi-shell/ioutil/MultiWriter.js +++ b/src/phoenix/src/ansi-shell/ioutil/MultiWriter.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export class MultiWriter { constructor ({ delegates }) { this.delegates = delegates; diff --git a/src/phoenix/src/ansi-shell/ioutil/NullifyWriter.js b/src/phoenix/src/ansi-shell/ioutil/NullifyWriter.js index f51af4d41a..0773467af5 100644 --- a/src/phoenix/src/ansi-shell/ioutil/NullifyWriter.js +++ b/src/phoenix/src/ansi-shell/ioutil/NullifyWriter.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { ProxyWriter } from "./ProxyWriter.js"; export class NullifyWriter extends ProxyWriter { diff --git a/src/phoenix/src/ansi-shell/ioutil/ProxyReader.js b/src/phoenix/src/ansi-shell/ioutil/ProxyReader.js index 3c202dd1c3..9e76ac9e87 100644 --- a/src/phoenix/src/ansi-shell/ioutil/ProxyReader.js +++ b/src/phoenix/src/ansi-shell/ioutil/ProxyReader.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export class ProxyReader { constructor ({ delegate }) { this.delegate = delegate; diff --git a/src/phoenix/src/ansi-shell/ioutil/ProxyWriter.js b/src/phoenix/src/ansi-shell/ioutil/ProxyWriter.js index 5ee46b0b89..9cdc17489f 100644 --- a/src/phoenix/src/ansi-shell/ioutil/ProxyWriter.js +++ b/src/phoenix/src/ansi-shell/ioutil/ProxyWriter.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export class ProxyWriter { constructor ({ delegate }) { this.delegate = delegate; diff --git a/src/phoenix/src/ansi-shell/ioutil/SignalReader.js b/src/phoenix/src/ansi-shell/ioutil/SignalReader.js index 66cc993014..a4d587f61d 100644 --- a/src/phoenix/src/ansi-shell/ioutil/SignalReader.js +++ b/src/phoenix/src/ansi-shell/ioutil/SignalReader.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { ANSIContext } from "../ANSIContext.js"; import { signals } from "../signals.js"; import { ProxyReader } from "./ProxyReader.js"; diff --git a/src/phoenix/src/ansi-shell/ioutil/SyncLinesReader.js b/src/phoenix/src/ansi-shell/ioutil/SyncLinesReader.js index 69fb781fd9..a6ea91e5a3 100644 --- a/src/phoenix/src/ansi-shell/ioutil/SyncLinesReader.js +++ b/src/phoenix/src/ansi-shell/ioutil/SyncLinesReader.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { ProxyReader } from "./ProxyReader.js"; const decoder = new TextDecoder(); diff --git a/src/phoenix/src/ansi-shell/parsing/PARSE_CONSTANTS.js b/src/phoenix/src/ansi-shell/parsing/PARSE_CONSTANTS.js index 75df56c01d..b8168c1de3 100644 --- a/src/phoenix/src/ansi-shell/parsing/PARSE_CONSTANTS.js +++ b/src/phoenix/src/ansi-shell/parsing/PARSE_CONSTANTS.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export const PARSE_CONSTANTS = { list_ws: [' ', '\n', '\t'], list_quot: [`"`, `'`], diff --git a/src/phoenix/src/ansi-shell/parsing/PuterShellParser.js b/src/phoenix/src/ansi-shell/parsing/PuterShellParser.js index 297b3d8553..50eba17830 100644 --- a/src/phoenix/src/ansi-shell/parsing/PuterShellParser.js +++ b/src/phoenix/src/ansi-shell/parsing/PuterShellParser.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { StrataParser, StringPStratumImpl } from "strataparse"; import { buildParserFirstHalf } from "./buildParserFirstHalf.js"; import { buildParserSecondHalf } from "./buildParserSecondHalf.js"; diff --git a/src/phoenix/src/ansi-shell/parsing/UnquotedTokenParserImpl.js b/src/phoenix/src/ansi-shell/parsing/UnquotedTokenParserImpl.js index 142c017902..71d028b92e 100644 --- a/src/phoenix/src/ansi-shell/parsing/UnquotedTokenParserImpl.js +++ b/src/phoenix/src/ansi-shell/parsing/UnquotedTokenParserImpl.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ const list_ws = [' ', '\n', '\t']; const list_quot = [`"`, `'`]; const list_stoptoken = [ diff --git a/src/phoenix/src/ansi-shell/parsing/brainstorming.js b/src/phoenix/src/ansi-shell/parsing/brainstorming.js index f6d760ccb1..189e9c4dc1 100644 --- a/src/phoenix/src/ansi-shell/parsing/brainstorming.js +++ b/src/phoenix/src/ansi-shell/parsing/brainstorming.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ const seq = [ { $: 'symbol', text: 'command' }, { $: 'string.dquote' }, diff --git a/src/phoenix/src/ansi-shell/parsing/buildParserFirstHalf.js b/src/phoenix/src/ansi-shell/parsing/buildParserFirstHalf.js index 932c41fc1b..7666be3a90 100644 --- a/src/phoenix/src/ansi-shell/parsing/buildParserFirstHalf.js +++ b/src/phoenix/src/ansi-shell/parsing/buildParserFirstHalf.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { FirstRecognizedPStratumImpl, ParserBuilder, ParserFactory, StrUntilParserImpl, StrataParseFacade, WhitespaceParserImpl } from "strataparse"; import { UnquotedTokenParserImpl } from "./UnquotedTokenParserImpl.js"; import { PARSE_CONSTANTS } from "./PARSE_CONSTANTS.js"; diff --git a/src/phoenix/src/ansi-shell/parsing/buildParserSecondHalf.js b/src/phoenix/src/ansi-shell/parsing/buildParserSecondHalf.js index 00cc36aa53..0215048515 100644 --- a/src/phoenix/src/ansi-shell/parsing/buildParserSecondHalf.js +++ b/src/phoenix/src/ansi-shell/parsing/buildParserSecondHalf.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { ParserBuilder, ParserFactory, StrataParseFacade } from "strataparse" import { PARSE_CONSTANTS } from "./PARSE_CONSTANTS.js"; diff --git a/src/phoenix/src/ansi-shell/pipeline/Coupler.js b/src/phoenix/src/ansi-shell/pipeline/Coupler.js index 517dd405c1..90893e584f 100644 --- a/src/phoenix/src/ansi-shell/pipeline/Coupler.js +++ b/src/phoenix/src/ansi-shell/pipeline/Coupler.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { TeePromise, raceCase } from "../../promise.js"; export class Coupler { diff --git a/src/phoenix/src/ansi-shell/pipeline/Pipe.js b/src/phoenix/src/ansi-shell/pipeline/Pipe.js index 41533aabd9..b3d262af36 100644 --- a/src/phoenix/src/ansi-shell/pipeline/Pipe.js +++ b/src/phoenix/src/ansi-shell/pipeline/Pipe.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export class Pipe { constructor () { this.readableStream = new ReadableStream({ diff --git a/src/phoenix/src/ansi-shell/pipeline/Pipeline.js b/src/phoenix/src/ansi-shell/pipeline/Pipeline.js index 35dfa96fe2..46cada8e64 100644 --- a/src/phoenix/src/ansi-shell/pipeline/Pipeline.js +++ b/src/phoenix/src/ansi-shell/pipeline/Pipeline.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { SyncLinesReader } from "../ioutil/SyncLinesReader.js"; import { TOKENS } from "../readline/readtoken.js"; import { ByteWriter } from "../ioutil/ByteWriter.js"; diff --git a/src/phoenix/src/ansi-shell/pipeline/iowrappers.js b/src/phoenix/src/ansi-shell/pipeline/iowrappers.js index 324a59046b..8cadfc2d49 100644 --- a/src/phoenix/src/ansi-shell/pipeline/iowrappers.js +++ b/src/phoenix/src/ansi-shell/pipeline/iowrappers.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export class CommandStdinDecorator { constructor (rs) { this.rs = rs; diff --git a/src/phoenix/src/ansi-shell/readline/history.js b/src/phoenix/src/ansi-shell/readline/history.js index ead08e74b8..7457eb1e43 100644 --- a/src/phoenix/src/ansi-shell/readline/history.js +++ b/src/phoenix/src/ansi-shell/readline/history.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export class HistoryManager { constructor({ enableLogging = false } = {}) { this.items = []; diff --git a/src/phoenix/src/ansi-shell/readline/readline.js b/src/phoenix/src/ansi-shell/readline/readline.js index 1a99804c13..64c068e3ea 100644 --- a/src/phoenix/src/ansi-shell/readline/readline.js +++ b/src/phoenix/src/ansi-shell/readline/readline.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { Context } from '../../context/context.js'; import { CommandCompleter } from '../../puter-shell/completers/CommandCompleter.js'; import { FileCompleter } from '../../puter-shell/completers/FileCompleter.js'; diff --git a/src/phoenix/src/ansi-shell/readline/readtoken.js b/src/phoenix/src/ansi-shell/readline/readtoken.js index 459aa0a52c..84f51c02a4 100644 --- a/src/phoenix/src/ansi-shell/readline/readtoken.js +++ b/src/phoenix/src/ansi-shell/readline/readtoken.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ // [reference impl](https://github.com/brgl/busybox/blob/master/shell/ash.c) const list_ws = [' ', '\n', '\t']; diff --git a/src/phoenix/src/ansi-shell/readline/rl_comprehend.js b/src/phoenix/src/ansi-shell/readline/rl_comprehend.js index 30c958b52f..c921a5ada6 100644 --- a/src/phoenix/src/ansi-shell/readline/rl_comprehend.js +++ b/src/phoenix/src/ansi-shell/readline/rl_comprehend.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ // This function comprehends the readline input and returns something // called a "readline input state" - this includes any information needed diff --git a/src/phoenix/src/ansi-shell/readline/rl_csi_handlers.js b/src/phoenix/src/ansi-shell/readline/rl_csi_handlers.js index 22470166ec..fa59193a28 100644 --- a/src/phoenix/src/ansi-shell/readline/rl_csi_handlers.js +++ b/src/phoenix/src/ansi-shell/readline/rl_csi_handlers.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ /* ## this source file - maps: CSI (Control Sequence Introducer) sequences diff --git a/src/phoenix/src/ansi-shell/readline/rl_words.js b/src/phoenix/src/ansi-shell/readline/rl_words.js index 0fd1293ee1..3d0a031b6d 100644 --- a/src/phoenix/src/ansi-shell/readline/rl_words.js +++ b/src/phoenix/src/ansi-shell/readline/rl_words.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export const findNextWord = (str, from, reverse) => { let stage = 0; let incr = reverse ? -1 : 1; diff --git a/src/phoenix/src/ansi-shell/signals.js b/src/phoenix/src/ansi-shell/signals.js index bf060b5bee..585d3a82bc 100644 --- a/src/phoenix/src/ansi-shell/signals.js +++ b/src/phoenix/src/ansi-shell/signals.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export const signals = Object.freeze({ SIGINT: 2, SIGQUIT: 3, diff --git a/src/phoenix/src/context/context.js b/src/phoenix/src/context/context.js index 2d6d67d305..1df63940af 100644 --- a/src/phoenix/src/context/context.js +++ b/src/phoenix/src/context/context.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export class AbstractContext { get constants () { return this.instance_.constants; diff --git a/src/phoenix/src/main_cli.js b/src/phoenix/src/main_cli.js index 093ffb2908..6bf740553e 100644 --- a/src/phoenix/src/main_cli.js +++ b/src/phoenix/src/main_cli.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { Context } from 'contextlink'; import { launchPuterShell } from './puter-shell/main.js'; import { NodeStdioPTT } from './pty/NodeStdioPTT.js'; diff --git a/src/phoenix/src/main_puter.js b/src/phoenix/src/main_puter.js index 4182fad996..85dc0af028 100644 --- a/src/phoenix/src/main_puter.js +++ b/src/phoenix/src/main_puter.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { Context } from 'contextlink'; import { launchPuterShell } from './puter-shell/main.js'; import { CreateFilesystemProvider } from './platform/puter/filesystem.js'; diff --git a/src/phoenix/src/meta/versions.js b/src/phoenix/src/meta/versions.js index f56ebe2d96..ea5034821e 100644 --- a/src/phoenix/src/meta/versions.js +++ b/src/phoenix/src/meta/versions.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export const SHELL_VERSIONS = [ { v: '0.2.4', diff --git a/src/phoenix/src/platform/node/filesystem.js b/src/phoenix/src/platform/node/filesystem.js index c067acb2c6..7ca9930953 100644 --- a/src/phoenix/src/platform/node/filesystem.js +++ b/src/phoenix/src/platform/node/filesystem.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import fs from 'fs'; import path_ from 'path'; diff --git a/src/phoenix/src/platform/puter/drivers.js b/src/phoenix/src/platform/puter/drivers.js index 20ab8fa386..c7cb7761be 100644 --- a/src/phoenix/src/platform/puter/drivers.js +++ b/src/phoenix/src/platform/puter/drivers.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export const CreateDriversProvider = ({ puterSDK }) => { diff --git a/src/phoenix/src/platform/puter/filesystem.js b/src/phoenix/src/platform/puter/filesystem.js index 5e028facff..49bc878fe1 100644 --- a/src/phoenix/src/platform/puter/filesystem.js +++ b/src/phoenix/src/platform/puter/filesystem.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { ErrorCodes, PosixError } from '@heyputer/puter-js-common/src/PosixError.js'; // DRY: Almost the same as node/filesystem.js diff --git a/src/phoenix/src/pty/XDocumentPTT.js b/src/phoenix/src/pty/XDocumentPTT.js index 3846583d19..e9afbb6fec 100644 --- a/src/phoenix/src/pty/XDocumentPTT.js +++ b/src/phoenix/src/pty/XDocumentPTT.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { BetterReader } from "dev-pty"; const encoder = new TextEncoder(); diff --git a/src/phoenix/src/puter-shell/completers/CommandCompleter.js b/src/phoenix/src/puter-shell/completers/CommandCompleter.js index 4e9d7f6a5c..4e6e093644 100644 --- a/src/phoenix/src/puter-shell/completers/CommandCompleter.js +++ b/src/phoenix/src/puter-shell/completers/CommandCompleter.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export class CommandCompleter { async getCompletions (ctx, inputState) { const { builtins } = ctx.registries; diff --git a/src/phoenix/src/puter-shell/completers/FileCompleter.js b/src/phoenix/src/puter-shell/completers/FileCompleter.js index 392f19e355..36465362c0 100644 --- a/src/phoenix/src/puter-shell/completers/FileCompleter.js +++ b/src/phoenix/src/puter-shell/completers/FileCompleter.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import path_ from "path-browserify"; import { resolveRelativePath } from '../../util/path.js'; diff --git a/src/phoenix/src/puter-shell/completers/OptionCompleter.js b/src/phoenix/src/puter-shell/completers/OptionCompleter.js index b9906a4a25..3b40ac1f77 100644 --- a/src/phoenix/src/puter-shell/completers/OptionCompleter.js +++ b/src/phoenix/src/puter-shell/completers/OptionCompleter.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { DEFAULT_OPTIONS } from '../coreutils/coreutil_lib/help.js'; export class OptionCompleter { diff --git a/src/phoenix/src/puter-shell/coreutils/__exports__.js b/src/phoenix/src/puter-shell/coreutils/__exports__.js index 6576a1c7c2..cedc87c9e8 100644 --- a/src/phoenix/src/puter-shell/coreutils/__exports__.js +++ b/src/phoenix/src/puter-shell/coreutils/__exports__.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ // Generated by /tools/gen.js import module_ai from './ai.js' import module_basename from './basename.js' diff --git a/src/phoenix/src/puter-shell/coreutils/ai.js b/src/phoenix/src/puter-shell/coreutils/ai.js index c73ddf973c..b05e3c7806 100644 --- a/src/phoenix/src/puter-shell/coreutils/ai.js +++ b/src/phoenix/src/puter-shell/coreutils/ai.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { Exit } from './coreutil_lib/exit.js'; export default { diff --git a/src/phoenix/src/puter-shell/coreutils/basename.js b/src/phoenix/src/puter-shell/coreutils/basename.js index e7ede73919..d1434e21e5 100644 --- a/src/phoenix/src/puter-shell/coreutils/basename.js +++ b/src/phoenix/src/puter-shell/coreutils/basename.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { Exit } from './coreutil_lib/exit.js'; export default { diff --git a/src/phoenix/src/puter-shell/coreutils/cat.js b/src/phoenix/src/puter-shell/coreutils/cat.js index b555fdc1aa..32e639ed01 100644 --- a/src/phoenix/src/puter-shell/coreutils/cat.js +++ b/src/phoenix/src/puter-shell/coreutils/cat.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { resolveRelativePath } from '../../util/path.js'; export default { diff --git a/src/phoenix/src/puter-shell/coreutils/cd.js b/src/phoenix/src/puter-shell/coreutils/cd.js index 0463290e4b..74829d1193 100644 --- a/src/phoenix/src/puter-shell/coreutils/cd.js +++ b/src/phoenix/src/puter-shell/coreutils/cd.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { Exit } from './coreutil_lib/exit.js'; import { resolveRelativePath } from '../../util/path.js'; diff --git a/src/phoenix/src/puter-shell/coreutils/changelog.js b/src/phoenix/src/puter-shell/coreutils/changelog.js index 0785df0dd2..13d02d4f30 100644 --- a/src/phoenix/src/puter-shell/coreutils/changelog.js +++ b/src/phoenix/src/puter-shell/coreutils/changelog.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { SHELL_VERSIONS } from "../../meta/versions.js"; async function printVersion(ctx, version) { diff --git a/src/phoenix/src/puter-shell/coreutils/clear.js b/src/phoenix/src/puter-shell/coreutils/clear.js index e25a9184fa..8b6c7d72b2 100644 --- a/src/phoenix/src/puter-shell/coreutils/clear.js +++ b/src/phoenix/src/puter-shell/coreutils/clear.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export default { name: 'clear', usage: 'clear', diff --git a/src/phoenix/src/puter-shell/coreutils/coreutil_lib/echo_escapes.js b/src/phoenix/src/puter-shell/coreutils/coreutil_lib/echo_escapes.js index d6c1339ce5..05a9626601 100644 --- a/src/phoenix/src/puter-shell/coreutils/coreutil_lib/echo_escapes.js +++ b/src/phoenix/src/puter-shell/coreutils/coreutil_lib/echo_escapes.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ /* Echo Escapes Implementations ---------------------------- diff --git a/src/phoenix/src/puter-shell/coreutils/coreutil_lib/exit.js b/src/phoenix/src/puter-shell/coreutils/coreutil_lib/exit.js index 95efc7d1b9..dd3af6de24 100644 --- a/src/phoenix/src/puter-shell/coreutils/coreutil_lib/exit.js +++ b/src/phoenix/src/puter-shell/coreutils/coreutil_lib/exit.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export class Exit extends Error { constructor (code) { super(`exit ${code}`); diff --git a/src/phoenix/src/puter-shell/coreutils/coreutil_lib/help.js b/src/phoenix/src/puter-shell/coreutils/coreutil_lib/help.js index 02eb94d805..3d2b62ba1a 100644 --- a/src/phoenix/src/puter-shell/coreutils/coreutil_lib/help.js +++ b/src/phoenix/src/puter-shell/coreutils/coreutil_lib/help.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { wrapText } from '../../../util/wrap-text.js'; const TAB_SIZE = 8; diff --git a/src/phoenix/src/puter-shell/coreutils/coreutil_lib/validate.js b/src/phoenix/src/puter-shell/coreutils/coreutil_lib/validate.js index efbcf957a4..f5184bb585 100644 --- a/src/phoenix/src/puter-shell/coreutils/coreutil_lib/validate.js +++ b/src/phoenix/src/puter-shell/coreutils/coreutil_lib/validate.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export const validate_string = (str, meta) => { if ( str === undefined ) { if ( ! meta.allow_empty ) { diff --git a/src/phoenix/src/puter-shell/coreutils/cp.js b/src/phoenix/src/puter-shell/coreutils/cp.js index d0d173428f..5edbe63a77 100644 --- a/src/phoenix/src/puter-shell/coreutils/cp.js +++ b/src/phoenix/src/puter-shell/coreutils/cp.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { Exit } from "./coreutil_lib/exit.js"; import { resolveRelativePath } from '../../util/path.js'; diff --git a/src/phoenix/src/puter-shell/coreutils/date.js b/src/phoenix/src/puter-shell/coreutils/date.js index 028dfbba90..c15433ccdf 100644 --- a/src/phoenix/src/puter-shell/coreutils/date.js +++ b/src/phoenix/src/puter-shell/coreutils/date.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { Exit } from './coreutil_lib/exit.js'; // "When no formatting operand is specified, the output in the POSIX locale shall be equivalent to specifying:" diff --git a/src/phoenix/src/puter-shell/coreutils/dcall.js b/src/phoenix/src/puter-shell/coreutils/dcall.js index 144a54640a..378802f5b5 100644 --- a/src/phoenix/src/puter-shell/coreutils/dcall.js +++ b/src/phoenix/src/puter-shell/coreutils/dcall.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ function highlight(text) { return `\x1B[92m${text}\x1B[0m`; } diff --git a/src/phoenix/src/puter-shell/coreutils/dirname.js b/src/phoenix/src/puter-shell/coreutils/dirname.js index dbd595af38..36f7948446 100644 --- a/src/phoenix/src/puter-shell/coreutils/dirname.js +++ b/src/phoenix/src/puter-shell/coreutils/dirname.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { Exit } from './coreutil_lib/exit.js'; export default { diff --git a/src/phoenix/src/puter-shell/coreutils/echo.js b/src/phoenix/src/puter-shell/coreutils/echo.js index f5bda9cdca..b0673c3489 100644 --- a/src/phoenix/src/puter-shell/coreutils/echo.js +++ b/src/phoenix/src/puter-shell/coreutils/echo.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { processEscapes } from "./coreutil_lib/echo_escapes.js"; export default { diff --git a/src/phoenix/src/puter-shell/coreutils/env.js b/src/phoenix/src/puter-shell/coreutils/env.js index 5cd6776bef..1d2beedcf7 100644 --- a/src/phoenix/src/puter-shell/coreutils/env.js +++ b/src/phoenix/src/puter-shell/coreutils/env.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export default { name: 'env', usage: 'env', diff --git a/src/phoenix/src/puter-shell/coreutils/errno.js b/src/phoenix/src/puter-shell/coreutils/errno.js index 34b509b398..8ea010c1df 100644 --- a/src/phoenix/src/puter-shell/coreutils/errno.js +++ b/src/phoenix/src/puter-shell/coreutils/errno.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { ErrorCodes, ErrorMetadata, errorFromIntegerCode } from '@heyputer/puter-js-common/src/PosixError.js'; import { Exit } from './coreutil_lib/exit.js'; diff --git a/src/phoenix/src/puter-shell/coreutils/exit.js b/src/phoenix/src/puter-shell/coreutils/exit.js index b0fcd99876..d93158fe92 100644 --- a/src/phoenix/src/puter-shell/coreutils/exit.js +++ b/src/phoenix/src/puter-shell/coreutils/exit.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { Exit } from './coreutil_lib/exit.js'; export default { diff --git a/src/phoenix/src/puter-shell/coreutils/false.js b/src/phoenix/src/puter-shell/coreutils/false.js index 5b31e632f9..3066a476c9 100644 --- a/src/phoenix/src/puter-shell/coreutils/false.js +++ b/src/phoenix/src/puter-shell/coreutils/false.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { Exit } from './coreutil_lib/exit.js'; export default { diff --git a/src/phoenix/src/puter-shell/coreutils/grep.js b/src/phoenix/src/puter-shell/coreutils/grep.js index 718af4d114..d89b9f5439 100644 --- a/src/phoenix/src/puter-shell/coreutils/grep.js +++ b/src/phoenix/src/puter-shell/coreutils/grep.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { resolveRelativePath } from '../../util/path.js'; const lxor = (a, b) => a ? !b : b; diff --git a/src/phoenix/src/puter-shell/coreutils/head.js b/src/phoenix/src/puter-shell/coreutils/head.js index ba6ecc55fb..48c853e6a0 100644 --- a/src/phoenix/src/puter-shell/coreutils/head.js +++ b/src/phoenix/src/puter-shell/coreutils/head.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { Exit } from './coreutil_lib/exit.js'; import { fileLines } from '../../util/file.js'; diff --git a/src/phoenix/src/puter-shell/coreutils/help.js b/src/phoenix/src/puter-shell/coreutils/help.js index 5171cf735c..45c5fbd175 100644 --- a/src/phoenix/src/puter-shell/coreutils/help.js +++ b/src/phoenix/src/puter-shell/coreutils/help.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ // TODO: fetch help information from command registry import { printUsage } from "./coreutil_lib/help.js"; diff --git a/src/phoenix/src/puter-shell/coreutils/jq.js b/src/phoenix/src/puter-shell/coreutils/jq.js index 3f92f8f975..bfd934d058 100644 --- a/src/phoenix/src/puter-shell/coreutils/jq.js +++ b/src/phoenix/src/puter-shell/coreutils/jq.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import jsonQuery from 'json-query'; import { signals } from '../../ansi-shell/signals.js'; import { Exit } from './coreutil_lib/exit.js'; diff --git a/src/phoenix/src/puter-shell/coreutils/login.js b/src/phoenix/src/puter-shell/coreutils/login.js index 2ef56d43aa..8f86c759a8 100644 --- a/src/phoenix/src/puter-shell/coreutils/login.js +++ b/src/phoenix/src/puter-shell/coreutils/login.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { Exit } from './coreutil_lib/exit.js'; export default { diff --git a/src/phoenix/src/puter-shell/coreutils/ls.js b/src/phoenix/src/puter-shell/coreutils/ls.js index de6cbc8e7b..351d190959 100644 --- a/src/phoenix/src/puter-shell/coreutils/ls.js +++ b/src/phoenix/src/puter-shell/coreutils/ls.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import columnify from "columnify"; import cli_columns from "cli-columns"; import { resolveRelativePath } from '../../util/path.js'; diff --git a/src/phoenix/src/puter-shell/coreutils/man.js b/src/phoenix/src/puter-shell/coreutils/man.js index 2af6ff1e0b..5884fa173f 100644 --- a/src/phoenix/src/puter-shell/coreutils/man.js +++ b/src/phoenix/src/puter-shell/coreutils/man.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export default { name: 'man', usage: 'man', diff --git a/src/phoenix/src/puter-shell/coreutils/mkdir.js b/src/phoenix/src/puter-shell/coreutils/mkdir.js index dd6deef5be..955f78101e 100644 --- a/src/phoenix/src/puter-shell/coreutils/mkdir.js +++ b/src/phoenix/src/puter-shell/coreutils/mkdir.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { validate_string } from "./coreutil_lib/validate.js"; import { EMPTY } from "../../util/singleton.js"; import { Exit } from './coreutil_lib/exit.js'; diff --git a/src/phoenix/src/puter-shell/coreutils/mv.js b/src/phoenix/src/puter-shell/coreutils/mv.js index d32146d867..62b2b39510 100644 --- a/src/phoenix/src/puter-shell/coreutils/mv.js +++ b/src/phoenix/src/puter-shell/coreutils/mv.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { Exit } from './coreutil_lib/exit.js'; import { resolveRelativePath } from '../../util/path.js'; diff --git a/src/phoenix/src/puter-shell/coreutils/neofetch.js b/src/phoenix/src/puter-shell/coreutils/neofetch.js index 27ceb11fdc..65943acda2 100644 --- a/src/phoenix/src/puter-shell/coreutils/neofetch.js +++ b/src/phoenix/src/puter-shell/coreutils/neofetch.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { SHELL_VERSIONS } from "../../meta/versions.js"; const logo = ` diff --git a/src/phoenix/src/puter-shell/coreutils/printf.js b/src/phoenix/src/puter-shell/coreutils/printf.js index 51d0aa3df9..3dc8bdacc1 100644 --- a/src/phoenix/src/puter-shell/coreutils/printf.js +++ b/src/phoenix/src/puter-shell/coreutils/printf.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { Exit } from './coreutil_lib/exit.js'; // TODO: get these values from a common place diff --git a/src/phoenix/src/puter-shell/coreutils/printhist.js b/src/phoenix/src/puter-shell/coreutils/printhist.js index 88efc09ff0..5784e237cf 100644 --- a/src/phoenix/src/puter-shell/coreutils/printhist.js +++ b/src/phoenix/src/puter-shell/coreutils/printhist.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export default { name: 'printhist', usage: 'printhist', diff --git a/src/phoenix/src/puter-shell/coreutils/pwd.js b/src/phoenix/src/puter-shell/coreutils/pwd.js index f6be908aa6..cdd75600dc 100644 --- a/src/phoenix/src/puter-shell/coreutils/pwd.js +++ b/src/phoenix/src/puter-shell/coreutils/pwd.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export default { name: 'pwd', diff --git a/src/phoenix/src/puter-shell/coreutils/rm.js b/src/phoenix/src/puter-shell/coreutils/rm.js index 2e1e09f662..15899160da 100644 --- a/src/phoenix/src/puter-shell/coreutils/rm.js +++ b/src/phoenix/src/puter-shell/coreutils/rm.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { resolveRelativePath } from '../../util/path.js'; // TODO: add logic to check if directory is empty diff --git a/src/phoenix/src/puter-shell/coreutils/rmdir.js b/src/phoenix/src/puter-shell/coreutils/rmdir.js index 9efceb355f..0d3a24a0b7 100644 --- a/src/phoenix/src/puter-shell/coreutils/rmdir.js +++ b/src/phoenix/src/puter-shell/coreutils/rmdir.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { resolveRelativePath } from '../../util/path.js'; // TODO: add logic to check if directory is empty diff --git a/src/phoenix/src/puter-shell/coreutils/sample-data.js b/src/phoenix/src/puter-shell/coreutils/sample-data.js index ce3b05bf66..df6e6a8711 100644 --- a/src/phoenix/src/puter-shell/coreutils/sample-data.js +++ b/src/phoenix/src/puter-shell/coreutils/sample-data.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export default { name: 'sample-data', args: { diff --git a/src/phoenix/src/puter-shell/coreutils/sed.js b/src/phoenix/src/puter-shell/coreutils/sed.js index f4b4b5f3fd..517c8f2679 100644 --- a/src/phoenix/src/puter-shell/coreutils/sed.js +++ b/src/phoenix/src/puter-shell/coreutils/sed.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { Exit } from './coreutil_lib/exit.js'; import { fileLines } from '../../util/file.js'; import { parseScript } from './sed/parser.js'; diff --git a/src/phoenix/src/puter-shell/coreutils/sed/address.js b/src/phoenix/src/puter-shell/coreutils/sed/address.js index b90a0c0312..fbc943289b 100644 --- a/src/phoenix/src/puter-shell/coreutils/sed/address.js +++ b/src/phoenix/src/puter-shell/coreutils/sed/address.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { makeIndent } from './utils.js'; // Either a line number or a regex diff --git a/src/phoenix/src/puter-shell/coreutils/sed/command.js b/src/phoenix/src/puter-shell/coreutils/sed/command.js index 037da01b1f..3b258ba56b 100644 --- a/src/phoenix/src/puter-shell/coreutils/sed/command.js +++ b/src/phoenix/src/puter-shell/coreutils/sed/command.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { AddressRange } from './address.js'; import { makeIndent } from './utils.js'; diff --git a/src/phoenix/src/puter-shell/coreutils/sed/parser.js b/src/phoenix/src/puter-shell/coreutils/sed/parser.js index 28d0b41977..68805cf525 100644 --- a/src/phoenix/src/puter-shell/coreutils/sed/parser.js +++ b/src/phoenix/src/puter-shell/coreutils/sed/parser.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { Address, AddressRange } from './address.js'; import { AppendTextCommand, diff --git a/src/phoenix/src/puter-shell/coreutils/sed/script.js b/src/phoenix/src/puter-shell/coreutils/sed/script.js index e59a5c5ceb..db2f10d389 100644 --- a/src/phoenix/src/puter-shell/coreutils/sed/script.js +++ b/src/phoenix/src/puter-shell/coreutils/sed/script.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { JumpLocation, LabelCommand, GroupEndCommand } from './command.js'; import { fileLines } from '../../../util/file.js'; diff --git a/src/phoenix/src/puter-shell/coreutils/sed/utils.js b/src/phoenix/src/puter-shell/coreutils/sed/utils.js index f3d59214f7..bb068f8df6 100644 --- a/src/phoenix/src/puter-shell/coreutils/sed/utils.js +++ b/src/phoenix/src/puter-shell/coreutils/sed/utils.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export function makeIndent(size) { return ' '.repeat(size); } diff --git a/src/phoenix/src/puter-shell/coreutils/sleep.js b/src/phoenix/src/puter-shell/coreutils/sleep.js index b71b8f4313..7aecc0fa24 100644 --- a/src/phoenix/src/puter-shell/coreutils/sleep.js +++ b/src/phoenix/src/puter-shell/coreutils/sleep.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { Exit } from './coreutil_lib/exit.js'; export default { diff --git a/src/phoenix/src/puter-shell/coreutils/sort.js b/src/phoenix/src/puter-shell/coreutils/sort.js index 4ec623a9d8..e618ee66ef 100644 --- a/src/phoenix/src/puter-shell/coreutils/sort.js +++ b/src/phoenix/src/puter-shell/coreutils/sort.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { resolveRelativePath } from '../../util/path.js'; export default { diff --git a/src/phoenix/src/puter-shell/coreutils/tail.js b/src/phoenix/src/puter-shell/coreutils/tail.js index 6a70bb590b..9e7990835a 100644 --- a/src/phoenix/src/puter-shell/coreutils/tail.js +++ b/src/phoenix/src/puter-shell/coreutils/tail.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { Exit } from './coreutil_lib/exit.js'; import { fileLines } from '../../util/file.js'; diff --git a/src/phoenix/src/puter-shell/coreutils/test.js b/src/phoenix/src/puter-shell/coreutils/test.js index 5c5bc2620d..b8d22f869e 100644 --- a/src/phoenix/src/puter-shell/coreutils/test.js +++ b/src/phoenix/src/puter-shell/coreutils/test.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export default { name: 'test', args: { diff --git a/src/phoenix/src/puter-shell/coreutils/touch.js b/src/phoenix/src/puter-shell/coreutils/touch.js index 5757c2322f..d77b09d3d6 100644 --- a/src/phoenix/src/puter-shell/coreutils/touch.js +++ b/src/phoenix/src/puter-shell/coreutils/touch.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { Exit } from './coreutil_lib/exit.js'; import { resolveRelativePath } from '../../util/path.js'; import { ErrorCodes } from '@heyputer/puter-js-common/src/PosixError.js'; diff --git a/src/phoenix/src/puter-shell/coreutils/true.js b/src/phoenix/src/puter-shell/coreutils/true.js index 3169545201..21ba47ca79 100644 --- a/src/phoenix/src/puter-shell/coreutils/true.js +++ b/src/phoenix/src/puter-shell/coreutils/true.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export default { name: 'true', usage: 'true', diff --git a/src/phoenix/src/puter-shell/coreutils/txt2img.js b/src/phoenix/src/puter-shell/coreutils/txt2img.js index c4586540bf..9de5e78078 100644 --- a/src/phoenix/src/puter-shell/coreutils/txt2img.js +++ b/src/phoenix/src/puter-shell/coreutils/txt2img.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { Exit } from './coreutil_lib/exit.js'; export default { diff --git a/src/phoenix/src/puter-shell/coreutils/usages.js b/src/phoenix/src/puter-shell/coreutils/usages.js index a97ec31f09..182731bde9 100644 --- a/src/phoenix/src/puter-shell/coreutils/usages.js +++ b/src/phoenix/src/puter-shell/coreutils/usages.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export default { name: 'usages', usage: 'usages', diff --git a/src/phoenix/src/puter-shell/coreutils/wc.js b/src/phoenix/src/puter-shell/coreutils/wc.js index f3914467ba..71376c9a57 100644 --- a/src/phoenix/src/puter-shell/coreutils/wc.js +++ b/src/phoenix/src/puter-shell/coreutils/wc.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { resolveRelativePath } from '../../util/path.js'; import { fileLines } from '../../util/file.js'; diff --git a/src/phoenix/src/puter-shell/coreutils/which.js b/src/phoenix/src/puter-shell/coreutils/which.js index 8fb3ab7810..c468bd7c50 100644 --- a/src/phoenix/src/puter-shell/coreutils/which.js +++ b/src/phoenix/src/puter-shell/coreutils/which.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { Exit } from './coreutil_lib/exit.js'; export default { diff --git a/src/phoenix/src/puter-shell/main.js b/src/phoenix/src/puter-shell/main.js index 98b9dcd28e..8c200a9224 100644 --- a/src/phoenix/src/puter-shell/main.js +++ b/src/phoenix/src/puter-shell/main.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import builtins from './coreutils/__exports__.js'; import ReadlineLib from "../ansi-shell/readline/readline.js"; diff --git a/src/phoenix/src/puter-shell/plugins/ChatHistoryPlugin.js b/src/phoenix/src/puter-shell/plugins/ChatHistoryPlugin.js index 103c15a897..2bf8b8024b 100644 --- a/src/phoenix/src/puter-shell/plugins/ChatHistoryPlugin.js +++ b/src/phoenix/src/puter-shell/plugins/ChatHistoryPlugin.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export const CreateChatHistoryPlugin = ctx => { const messages = [ { diff --git a/src/phoenix/src/puter-shell/providers/BuiltinCommandProvider.js b/src/phoenix/src/puter-shell/providers/BuiltinCommandProvider.js index 680afa5f35..cf71fc0c69 100644 --- a/src/phoenix/src/puter-shell/providers/BuiltinCommandProvider.js +++ b/src/phoenix/src/puter-shell/providers/BuiltinCommandProvider.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import builtins from '../coreutils/__exports__.js'; export class BuiltinCommandProvider { diff --git a/src/phoenix/src/puter-shell/providers/CompositeCommandProvider.js b/src/phoenix/src/puter-shell/providers/CompositeCommandProvider.js index 91300e7f66..0dd03adade 100644 --- a/src/phoenix/src/puter-shell/providers/CompositeCommandProvider.js +++ b/src/phoenix/src/puter-shell/providers/CompositeCommandProvider.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export class CompositeCommandProvider { constructor (providers) { this.providers = providers; diff --git a/src/phoenix/src/puter-shell/providers/PathCommandProvider.js b/src/phoenix/src/puter-shell/providers/PathCommandProvider.js index 6ce2d435ae..b6293e3e04 100644 --- a/src/phoenix/src/puter-shell/providers/PathCommandProvider.js +++ b/src/phoenix/src/puter-shell/providers/PathCommandProvider.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import path_ from "node:path"; import child_process from "node:child_process"; import stream from "node:stream"; diff --git a/src/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js b/src/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js index 13540b1509..c25892449d 100644 --- a/src/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js +++ b/src/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { Exit } from '../coreutils/coreutil_lib/exit.js'; import { signals } from '../../ansi-shell/signals.js'; diff --git a/src/phoenix/src/puter-shell/providers/ScriptCommandProvider.js b/src/phoenix/src/puter-shell/providers/ScriptCommandProvider.js index e080fa6af5..2d994096bd 100644 --- a/src/phoenix/src/puter-shell/providers/ScriptCommandProvider.js +++ b/src/phoenix/src/puter-shell/providers/ScriptCommandProvider.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import path_ from "path-browserify"; import { Pipeline } from "../../ansi-shell/pipeline/Pipeline.js"; import { resolveRelativePath } from '../../util/path.js'; diff --git a/src/phoenix/src/util/bytes.js b/src/phoenix/src/util/bytes.js index 9c785ba501..15410da99a 100644 --- a/src/phoenix/src/util/bytes.js +++ b/src/phoenix/src/util/bytes.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export class Uint8List { constructor (initialSize) { initialSize = initialSize || 2; diff --git a/src/phoenix/src/util/lang.js b/src/phoenix/src/util/lang.js index 510f728e88..2b17477847 100644 --- a/src/phoenix/src/util/lang.js +++ b/src/phoenix/src/util/lang.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export const disallowAccessToUndefined = (obj) => { return new Proxy(obj, { get (target, prop, receiver) { diff --git a/src/phoenix/src/util/log.js b/src/phoenix/src/util/log.js index aa55747b48..cd11ea743e 100644 --- a/src/phoenix/src/util/log.js +++ b/src/phoenix/src/util/log.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export class Log { static log (...items) { items = items.map(this.toString); diff --git a/src/phoenix/src/util/path.js b/src/phoenix/src/util/path.js index 817de1b9fb..d21338e67f 100644 --- a/src/phoenix/src/util/path.js +++ b/src/phoenix/src/util/path.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import path_ from "path-browserify"; export const resolveRelativePath = (vars, relativePath) => { diff --git a/src/phoenix/src/util/singleton.js b/src/phoenix/src/util/singleton.js index 6e7c2b94a5..bad0521edc 100644 --- a/src/phoenix/src/util/singleton.js +++ b/src/phoenix/src/util/singleton.js @@ -16,22 +16,4 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export const EMPTY = Object.freeze({}); diff --git a/src/phoenix/src/util/statemachine.js b/src/phoenix/src/util/statemachine.js index 459a6d0d02..ce0d6c1176 100644 --- a/src/phoenix/src/util/statemachine.js +++ b/src/phoenix/src/util/statemachine.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { disallowAccessToUndefined } from "./lang.js"; import { Context } from "contextlink"; diff --git a/src/phoenix/src/util/wrap-text.js b/src/phoenix/src/util/wrap-text.js index 58c97a1fa1..bae9a72650 100644 --- a/src/phoenix/src/util/wrap-text.js +++ b/src/phoenix/src/util/wrap-text.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ /* eslint-disable no-control-regex */ export function lengthIgnoringEscapes(text) { diff --git a/src/phoenix/test.js b/src/phoenix/test.js index dbf89ac923..6c5fded778 100644 --- a/src/phoenix/test.js +++ b/src/phoenix/test.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { StringPStratumImpl, StrataParser, diff --git a/src/phoenix/test/coreutils.test.js b/src/phoenix/test/coreutils.test.js index 511ff609f3..affd1d4d66 100644 --- a/src/phoenix/test/coreutils.test.js +++ b/src/phoenix/test/coreutils.test.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { runBasenameTests } from "./coreutils/basename.js"; import { runDateTests } from "./coreutils/date.js"; import { runDirnameTests } from "./coreutils/dirname.js"; diff --git a/src/phoenix/test/coreutils/basename.js b/src/phoenix/test/coreutils/basename.js index 39f56a71e1..0c08e2af1c 100644 --- a/src/phoenix/test/coreutils/basename.js +++ b/src/phoenix/test/coreutils/basename.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import assert from 'assert'; import { MakeTestContext } from './harness.js' import builtins from '../../src/puter-shell/coreutils/__exports__.js'; diff --git a/src/phoenix/test/coreutils/date.js b/src/phoenix/test/coreutils/date.js index c38e8af577..407e9896b8 100644 --- a/src/phoenix/test/coreutils/date.js +++ b/src/phoenix/test/coreutils/date.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import assert from 'assert'; import * as ck from 'chronokinesis'; import { MakeTestContext } from './harness.js' diff --git a/src/phoenix/test/coreutils/dirname.js b/src/phoenix/test/coreutils/dirname.js index 9cb8a457b7..35e0c74ddc 100644 --- a/src/phoenix/test/coreutils/dirname.js +++ b/src/phoenix/test/coreutils/dirname.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import assert from 'assert'; import { MakeTestContext } from './harness.js' import builtins from '../../src/puter-shell/coreutils/__exports__.js'; diff --git a/src/phoenix/test/coreutils/echo.js b/src/phoenix/test/coreutils/echo.js index 3bb7134bbf..fd0819ed6e 100644 --- a/src/phoenix/test/coreutils/echo.js +++ b/src/phoenix/test/coreutils/echo.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import assert from 'assert'; import { MakeTestContext } from './harness.js' import builtins from '../../src/puter-shell/coreutils/__exports__.js'; diff --git a/src/phoenix/test/coreutils/env.js b/src/phoenix/test/coreutils/env.js index 26855b931d..e65358998e 100644 --- a/src/phoenix/test/coreutils/env.js +++ b/src/phoenix/test/coreutils/env.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import assert from 'assert'; import { MakeTestContext } from './harness.js' import builtins from '../../src/puter-shell/coreutils/__exports__.js'; diff --git a/src/phoenix/test/coreutils/errno.js b/src/phoenix/test/coreutils/errno.js index c09bf9d541..b749de46f9 100644 --- a/src/phoenix/test/coreutils/errno.js +++ b/src/phoenix/test/coreutils/errno.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import assert from 'assert'; import { MakeTestContext } from './harness.js' import builtins from '../../src/puter-shell/coreutils/__exports__.js'; diff --git a/src/phoenix/test/coreutils/false.js b/src/phoenix/test/coreutils/false.js index ef5ad3ff26..c1adfabc46 100644 --- a/src/phoenix/test/coreutils/false.js +++ b/src/phoenix/test/coreutils/false.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import assert from 'assert'; import { MakeTestContext } from './harness.js' import builtins from '../../src/puter-shell/coreutils/__exports__.js'; diff --git a/src/phoenix/test/coreutils/harness.js b/src/phoenix/test/coreutils/harness.js index 344a8ebbd1..5bfc2cdbd5 100644 --- a/src/phoenix/test/coreutils/harness.js +++ b/src/phoenix/test/coreutils/harness.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { Context } from "contextlink"; import { SyncLinesReader } from '../../src/ansi-shell/ioutil/SyncLinesReader.js'; import { CommandStdinDecorator } from '../../src/ansi-shell/pipeline/iowrappers.js'; diff --git a/src/phoenix/test/coreutils/head.js b/src/phoenix/test/coreutils/head.js index 0c6de2769e..bc8f0c8add 100644 --- a/src/phoenix/test/coreutils/head.js +++ b/src/phoenix/test/coreutils/head.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import assert from 'assert'; import { MakeTestContext } from './harness.js' import builtins from '../../src/puter-shell/coreutils/__exports__.js'; diff --git a/src/phoenix/test/coreutils/printf.js b/src/phoenix/test/coreutils/printf.js index 60b79de030..b5008bbc78 100644 --- a/src/phoenix/test/coreutils/printf.js +++ b/src/phoenix/test/coreutils/printf.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import assert from 'assert'; import { MakeTestContext } from './harness.js' import builtins from '../../src/puter-shell/coreutils/__exports__.js'; diff --git a/src/phoenix/test/coreutils/sleep.js b/src/phoenix/test/coreutils/sleep.js index cea93e44c8..afb9150bca 100644 --- a/src/phoenix/test/coreutils/sleep.js +++ b/src/phoenix/test/coreutils/sleep.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import assert from 'assert'; import sinon from 'sinon'; import { MakeTestContext } from './harness.js'; diff --git a/src/phoenix/test/coreutils/sort.js b/src/phoenix/test/coreutils/sort.js index 5f336e4c0d..02aa6076a6 100644 --- a/src/phoenix/test/coreutils/sort.js +++ b/src/phoenix/test/coreutils/sort.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import assert from 'assert'; import { MakeTestContext } from './harness.js' import builtins from '../../src/puter-shell/coreutils/__exports__.js'; diff --git a/src/phoenix/test/coreutils/tail.js b/src/phoenix/test/coreutils/tail.js index 4f5f1dc4c6..7e4f07fe20 100644 --- a/src/phoenix/test/coreutils/tail.js +++ b/src/phoenix/test/coreutils/tail.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import assert from 'assert'; import { MakeTestContext } from './harness.js' import builtins from '../../src/puter-shell/coreutils/__exports__.js'; diff --git a/src/phoenix/test/coreutils/true.js b/src/phoenix/test/coreutils/true.js index 2e16062bb8..ab87352f41 100644 --- a/src/phoenix/test/coreutils/true.js +++ b/src/phoenix/test/coreutils/true.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import assert from 'assert'; import { MakeTestContext } from './harness.js' import builtins from '../../src/puter-shell/coreutils/__exports__.js'; diff --git a/src/phoenix/test/coreutils/wc.js b/src/phoenix/test/coreutils/wc.js index 285f03db16..f2e9553f34 100644 --- a/src/phoenix/test/coreutils/wc.js +++ b/src/phoenix/test/coreutils/wc.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import assert from 'assert'; import { MakeTestContext } from './harness.js' import builtins from '../../src/puter-shell/coreutils/__exports__.js'; diff --git a/src/phoenix/test/readtoken.js b/src/phoenix/test/readtoken.js index 836b969435..33ca677a1a 100644 --- a/src/phoenix/test/readtoken.js +++ b/src/phoenix/test/readtoken.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import assert from 'assert'; import { readtoken, TOKENS } from '../src/ansi-shell/readline/readtoken.js'; diff --git a/src/phoenix/test/test-bytes.js b/src/phoenix/test/test-bytes.js index 5ef27bab44..735442ce2f 100644 --- a/src/phoenix/test/test-bytes.js +++ b/src/phoenix/test/test-bytes.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import assert from 'assert'; import { Uint8List } from '../src/util/bytes.js'; diff --git a/src/phoenix/test/test-stateful-processor.js b/src/phoenix/test/test-stateful-processor.js index 5264ede115..d77de833da 100644 --- a/src/phoenix/test/test-stateful-processor.js +++ b/src/phoenix/test/test-stateful-processor.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import assert from 'assert'; import { StatefulProcessorBuilder } from '../src/util/statemachine.js'; diff --git a/src/phoenix/test/wrap-text.js b/src/phoenix/test/wrap-text.js index 5d6ba3a5c9..8a17dca8a1 100644 --- a/src/phoenix/test/wrap-text.js +++ b/src/phoenix/test/wrap-text.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import assert from 'assert'; import { lengthIgnoringEscapes, wrapText } from '../src/util/wrap-text.js'; diff --git a/src/phoenix/tools/gen.js b/src/phoenix/tools/gen.js index 713b2c1c05..20a29787e5 100644 --- a/src/phoenix/tools/gen.js +++ b/src/phoenix/tools/gen.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ // Script that generates some of the javascript files import fs from 'fs'; import path from 'path'; diff --git a/src/pty/exports.js b/src/pty/exports.js index 6dd6cad435..997fb79701 100644 --- a/src/pty/exports.js +++ b/src/pty/exports.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { libs } from '@heyputer/puter-js-common'; const { TeePromise, raceCase } = libs.promise; diff --git a/src/puter-js-common/src/PosixError.js b/src/puter-js-common/src/PosixError.js index 6d177f600e..dd6fd2fcb4 100644 --- a/src/puter-js-common/src/PosixError.js +++ b/src/puter-js-common/src/PosixError.js @@ -16,24 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ + const ErrorCodes = { EACCES: Symbol.for('EACCES'), EADDRINUSE: Symbol.for('EADDRINUSE'), diff --git a/src/puter-js/src/index.js b/src/puter-js/src/index.js index 0ccb016e4b..425fb06a02 100644 --- a/src/puter-js/src/index.js +++ b/src/puter-js/src/index.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import OS from './modules/OS.js'; import FileSystem from './modules/FileSystem/index.js'; import Hosting from './modules/Hosting.js'; diff --git a/src/puter-js/src/modules/AI.js b/src/puter-js/src/modules/AI.js index 9a8b47c4ef..edf9abb4a3 100644 --- a/src/puter-js/src/modules/AI.js +++ b/src/puter-js/src/modules/AI.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import * as utils from '../lib/utils.js' class AI{ diff --git a/src/puter-js/src/modules/Apps.js b/src/puter-js/src/modules/Apps.js index 0ab7145751..4307e29b53 100644 --- a/src/puter-js/src/modules/Apps.js +++ b/src/puter-js/src/modules/Apps.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import * as utils from '../lib/utils.js' class Apps{ diff --git a/src/puter-js/src/modules/Auth.js b/src/puter-js/src/modules/Auth.js index 9858c15cd5..7c877bbe2c 100644 --- a/src/puter-js/src/modules/Auth.js +++ b/src/puter-js/src/modules/Auth.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import * as utils from '../lib/utils.js' class Auth{ diff --git a/src/puter-js/src/modules/Email.js b/src/puter-js/src/modules/Email.js index c134051652..4f754d3351 100644 --- a/src/puter-js/src/modules/Email.js +++ b/src/puter-js/src/modules/Email.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import * as utils from '../lib/utils.js' class Email{ diff --git a/src/puter-js/src/modules/FSItem.js b/src/puter-js/src/modules/FSItem.js index 52ac52b6a1..0df2ec5f3c 100644 --- a/src/puter-js/src/modules/FSItem.js +++ b/src/puter-js/src/modules/FSItem.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import path from "../lib/path.js" class FSItem{ diff --git a/src/puter-js/src/modules/FileSystem/index.js b/src/puter-js/src/modules/FileSystem/index.js index e3de175070..0e6b2679d2 100644 --- a/src/puter-js/src/modules/FileSystem/index.js +++ b/src/puter-js/src/modules/FileSystem/index.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import io from '../../lib/socket.io/socket.io.esm.min.js'; // Operations diff --git a/src/puter-js/src/modules/FileSystem/operations/copy.js b/src/puter-js/src/modules/FileSystem/operations/copy.js index 30b32a8aab..4e33162a0c 100644 --- a/src/puter-js/src/modules/FileSystem/operations/copy.js +++ b/src/puter-js/src/modules/FileSystem/operations/copy.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import * as utils from '../../../lib/utils.js'; import getAbsolutePathForApp from '../utils/getAbsolutePathForApp.js'; diff --git a/src/puter-js/src/modules/FileSystem/operations/deleteFSEntry.js b/src/puter-js/src/modules/FileSystem/operations/deleteFSEntry.js index 616e202fa9..0b8644b65a 100644 --- a/src/puter-js/src/modules/FileSystem/operations/deleteFSEntry.js +++ b/src/puter-js/src/modules/FileSystem/operations/deleteFSEntry.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import * as utils from '../../../lib/utils.js'; import getAbsolutePathForApp from '../utils/getAbsolutePathForApp.js'; diff --git a/src/puter-js/src/modules/FileSystem/operations/mkdir.js b/src/puter-js/src/modules/FileSystem/operations/mkdir.js index d48474b725..c256ab6547 100644 --- a/src/puter-js/src/modules/FileSystem/operations/mkdir.js +++ b/src/puter-js/src/modules/FileSystem/operations/mkdir.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import * as utils from '../../../lib/utils.js'; import getAbsolutePathForApp from '../utils/getAbsolutePathForApp.js'; import path from "../../../lib/path.js" diff --git a/src/puter-js/src/modules/FileSystem/operations/move.js b/src/puter-js/src/modules/FileSystem/operations/move.js index ca338cd1ac..eb87c245b8 100644 --- a/src/puter-js/src/modules/FileSystem/operations/move.js +++ b/src/puter-js/src/modules/FileSystem/operations/move.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import * as utils from '../../../lib/utils.js'; import getAbsolutePathForApp from '../utils/getAbsolutePathForApp.js'; diff --git a/src/puter-js/src/modules/FileSystem/operations/read.js b/src/puter-js/src/modules/FileSystem/operations/read.js index 0d35b868f2..971bc59d83 100644 --- a/src/puter-js/src/modules/FileSystem/operations/read.js +++ b/src/puter-js/src/modules/FileSystem/operations/read.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import * as utils from '../../../lib/utils.js'; import getAbsolutePathForApp from '../utils/getAbsolutePathForApp.js'; diff --git a/src/puter-js/src/modules/FileSystem/operations/readdir.js b/src/puter-js/src/modules/FileSystem/operations/readdir.js index 1bbbe001fd..fe2f2e1456 100644 --- a/src/puter-js/src/modules/FileSystem/operations/readdir.js +++ b/src/puter-js/src/modules/FileSystem/operations/readdir.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import * as utils from '../../../lib/utils.js'; import getAbsolutePathForApp from '../utils/getAbsolutePathForApp.js'; diff --git a/src/puter-js/src/modules/FileSystem/operations/rename.js b/src/puter-js/src/modules/FileSystem/operations/rename.js index 0c8e1ad2e5..c670e482aa 100644 --- a/src/puter-js/src/modules/FileSystem/operations/rename.js +++ b/src/puter-js/src/modules/FileSystem/operations/rename.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import * as utils from '../../../lib/utils.js'; import getAbsolutePathForApp from '../utils/getAbsolutePathForApp.js'; diff --git a/src/puter-js/src/modules/FileSystem/operations/sign.js b/src/puter-js/src/modules/FileSystem/operations/sign.js index 20fe871372..c2d5efb503 100644 --- a/src/puter-js/src/modules/FileSystem/operations/sign.js +++ b/src/puter-js/src/modules/FileSystem/operations/sign.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import * as utils from '../../../lib/utils.js'; diff --git a/src/puter-js/src/modules/FileSystem/operations/space.js b/src/puter-js/src/modules/FileSystem/operations/space.js index 6592936d05..9c2e787fae 100644 --- a/src/puter-js/src/modules/FileSystem/operations/space.js +++ b/src/puter-js/src/modules/FileSystem/operations/space.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import * as utils from '../../../lib/utils.js'; const space = function (...args) { diff --git a/src/puter-js/src/modules/FileSystem/operations/stat.js b/src/puter-js/src/modules/FileSystem/operations/stat.js index 856f51eb54..28f9d64981 100644 --- a/src/puter-js/src/modules/FileSystem/operations/stat.js +++ b/src/puter-js/src/modules/FileSystem/operations/stat.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import * as utils from '../../../lib/utils.js'; import getAbsolutePathForApp from '../utils/getAbsolutePathForApp.js'; diff --git a/src/puter-js/src/modules/FileSystem/operations/upload.js b/src/puter-js/src/modules/FileSystem/operations/upload.js index 3744d19076..ab8778ea9b 100644 --- a/src/puter-js/src/modules/FileSystem/operations/upload.js +++ b/src/puter-js/src/modules/FileSystem/operations/upload.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import * as utils from '../../../lib/utils.js'; import getAbsolutePathForApp from '../utils/getAbsolutePathForApp.js'; import path from "../../../lib/path.js" diff --git a/src/puter-js/src/modules/FileSystem/operations/write.js b/src/puter-js/src/modules/FileSystem/operations/write.js index dd16047844..c1319ad4b6 100644 --- a/src/puter-js/src/modules/FileSystem/operations/write.js +++ b/src/puter-js/src/modules/FileSystem/operations/write.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import path from "../../../lib/path.js" import getAbsolutePathForApp from '../utils/getAbsolutePathForApp.js'; diff --git a/src/puter-js/src/modules/FileSystem/utils/getAbsolutePathForApp.js b/src/puter-js/src/modules/FileSystem/utils/getAbsolutePathForApp.js index 48a6669511..186b94dcfd 100644 --- a/src/puter-js/src/modules/FileSystem/utils/getAbsolutePathForApp.js +++ b/src/puter-js/src/modules/FileSystem/utils/getAbsolutePathForApp.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import path from "../../../lib/path.js" const getAbsolutePathForApp = (relativePath)=>{ diff --git a/src/puter-js/src/modules/Hosting.js b/src/puter-js/src/modules/Hosting.js index bca46b3d7c..fa2234164d 100644 --- a/src/puter-js/src/modules/Hosting.js +++ b/src/puter-js/src/modules/Hosting.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import * as utils from '../lib/utils.js'; import getAbsolutePathForApp from './FileSystem/utils/getAbsolutePathForApp.js'; diff --git a/src/puter-js/src/modules/KV.js b/src/puter-js/src/modules/KV.js index 0341d17939..c040560658 100644 --- a/src/puter-js/src/modules/KV.js +++ b/src/puter-js/src/modules/KV.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import * as utils from '../lib/utils.js' class KV{ diff --git a/src/puter-js/src/modules/OS.js b/src/puter-js/src/modules/OS.js index cf2f43d4ed..a436e58a3b 100644 --- a/src/puter-js/src/modules/OS.js +++ b/src/puter-js/src/modules/OS.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import * as utils from '../lib/utils.js' class OS{ diff --git a/src/puter-js/src/modules/PuterDialog.js b/src/puter-js/src/modules/PuterDialog.js index 1d77c076a6..8be194176c 100644 --- a/src/puter-js/src/modules/PuterDialog.js +++ b/src/puter-js/src/modules/PuterDialog.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ class PuterDialog extends HTMLElement { constructor(resolve, reject) { super(); diff --git a/src/puter-js/src/modules/UI.js b/src/puter-js/src/modules/UI.js index 221cb9ae64..8a3fe496aa 100644 --- a/src/puter-js/src/modules/UI.js +++ b/src/puter-js/src/modules/UI.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import FSItem from './FSItem.js'; import PuterDialog from './PuterDialog.js'; import EventListener from '../lib/EventListener.js'; diff --git a/src/puter-js/src/modules/Util.js b/src/puter-js/src/modules/Util.js index 2d8fc119e6..16dbe14771 100644 --- a/src/puter-js/src/modules/Util.js +++ b/src/puter-js/src/modules/Util.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import { CallbackManager, Dehydrator, Hydrator } from "../lib/xdrpc"; /** diff --git a/src/puter-js/test/fs.test.js b/src/puter-js/test/fs.test.js index dcbd071596..c194ef3818 100644 --- a/src/puter-js/test/fs.test.js +++ b/src/puter-js/test/fs.test.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /* eslint-disable */ // TODO: Make these more compatible with eslint naughtyStrings = [ diff --git a/src/puter-js/test/kv.test.js b/src/puter-js/test/kv.test.js index 0a91ab2b89..16de6ab37e 100644 --- a/src/puter-js/test/kv.test.js +++ b/src/puter-js/test/kv.test.js @@ -1,21 +1,3 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ /* eslint-disable */ // TODO: Make these more compatible with eslint window.kvTests = [ diff --git a/src/strataparse/dsl/ParserBuilder.js b/src/strataparse/dsl/ParserBuilder.js index 1a218b28f9..c6f3ba19be 100644 --- a/src/strataparse/dsl/ParserBuilder.js +++ b/src/strataparse/dsl/ParserBuilder.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { SingleParserFactory } from "../parse.js"; export class ParserConfigDSL extends SingleParserFactory { diff --git a/src/strataparse/dsl/ParserRegistry.js b/src/strataparse/dsl/ParserRegistry.js index 9ef5104e0d..b5126ba89f 100644 --- a/src/strataparse/dsl/ParserRegistry.js +++ b/src/strataparse/dsl/ParserRegistry.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export class ParserRegistry { constructor () { this.parsers_ = {}; diff --git a/src/strataparse/exports.js b/src/strataparse/exports.js index daa579d29f..42c46f02bc 100644 --- a/src/strataparse/exports.js +++ b/src/strataparse/exports.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { ParserRegistry } from './dsl/ParserRegistry.js'; import { PStratum } from './strata.js'; diff --git a/src/strataparse/parse.js b/src/strataparse/parse.js index fd5e675f48..f999c30864 100644 --- a/src/strataparse/parse.js +++ b/src/strataparse/parse.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export class Parser { constructor ({ impl, diff --git a/src/strataparse/parse_impls/StrUntilParserImpl.js b/src/strataparse/parse_impls/StrUntilParserImpl.js index a80e4baa3c..ed0e871682 100644 --- a/src/strataparse/parse_impls/StrUntilParserImpl.js +++ b/src/strataparse/parse_impls/StrUntilParserImpl.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export default class StrUntilParserImpl { constructor ({ stopChars }) { this.stopChars = stopChars; diff --git a/src/strataparse/parse_impls/combinators.js b/src/strataparse/parse_impls/combinators.js index 2f68a8c3b7..6d26c3c9b0 100644 --- a/src/strataparse/parse_impls/combinators.js +++ b/src/strataparse/parse_impls/combinators.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { ParserConfigDSL } from "../dsl/ParserBuilder.js"; import { AcceptParserUtil, Parser, ParseResult } from "../parse.js"; diff --git a/src/strataparse/parse_impls/literal.js b/src/strataparse/parse_impls/literal.js index b5af905e6c..7cf64d4147 100644 --- a/src/strataparse/parse_impls/literal.js +++ b/src/strataparse/parse_impls/literal.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { ParserConfigDSL } from "../dsl/ParserBuilder.js"; const encoder = new TextEncoder(); diff --git a/src/strataparse/parse_impls/whitespace.js b/src/strataparse/parse_impls/whitespace.js index baba772ca6..fac313dea6 100644 --- a/src/strataparse/parse_impls/whitespace.js +++ b/src/strataparse/parse_impls/whitespace.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export default class WhitespaceParserImpl { static meta = { inputs: 'bytes', diff --git a/src/strataparse/strata.js b/src/strataparse/strata.js index e3faafa863..1822545532 100644 --- a/src/strataparse/strata.js +++ b/src/strataparse/strata.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ export class DelegatingPStratumImplAPI { constructor (facade) { this.facade = facade; diff --git a/src/strataparse/strata_impls/ContextSwitchingPStratumImpl.js b/src/strataparse/strata_impls/ContextSwitchingPStratumImpl.js index a3014ad888..cb351104d4 100644 --- a/src/strataparse/strata_impls/ContextSwitchingPStratumImpl.js +++ b/src/strataparse/strata_impls/ContextSwitchingPStratumImpl.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { AcceptParserUtil, ParseResult, Parser } from "../parse.js"; export default class ContextSwitchingPStratumImpl { diff --git a/src/strataparse/strata_impls/FirstRecognizedPStratumImpl.js b/src/strataparse/strata_impls/FirstRecognizedPStratumImpl.js index 2455d3f866..305d1ded0b 100644 --- a/src/strataparse/strata_impls/FirstRecognizedPStratumImpl.js +++ b/src/strataparse/strata_impls/FirstRecognizedPStratumImpl.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { AcceptParserUtil, ParseResult, Parser } from "../parse.js"; export default class FirstRecognizedPStratumImpl { diff --git a/src/strataparse/strata_impls/MergeWhitespacePStratumImpl.js b/src/strataparse/strata_impls/MergeWhitespacePStratumImpl.js index f5b7d9273a..2867bb7b2d 100644 --- a/src/strataparse/strata_impls/MergeWhitespacePStratumImpl.js +++ b/src/strataparse/strata_impls/MergeWhitespacePStratumImpl.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ const decoder = new TextDecoder(); export class MergeWhitespacePStratumImpl { diff --git a/src/strataparse/strata_impls/terminals.js b/src/strataparse/strata_impls/terminals.js index 405a3e0363..56fa1e68db 100644 --- a/src/strataparse/strata_impls/terminals.js +++ b/src/strataparse/strata_impls/terminals.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Phoenix Shell. - * - * Phoenix Shell 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 . - */ import { TerminalPStratumImplType } from "../strata.js"; export class BytesPStratumImpl { diff --git a/src/terminal/assets/normalize.css b/src/terminal/assets/normalize.css index ea251ae7a5..69dca4e375 100644 --- a/src/terminal/assets/normalize.css +++ b/src/terminal/assets/normalize.css @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Terminal. * diff --git a/src/terminal/assets/style.css b/src/terminal/assets/style.css index f8681392a6..5aa3c1ed6f 100644 --- a/src/terminal/assets/style.css +++ b/src/terminal/assets/style.css @@ -1,5 +1,5 @@ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Terminal. * diff --git a/src/terminal/config/dev.js b/src/terminal/config/dev.js index f3a709c697..9323fe988c 100644 --- a/src/terminal/config/dev.js +++ b/src/terminal/config/dev.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Terminal. * diff --git a/src/terminal/config/release.js b/src/terminal/config/release.js index dad116d296..6560428302 100644 --- a/src/terminal/config/release.js +++ b/src/terminal/config/release.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Terminal. * diff --git a/src/terminal/doc/license_header.txt b/src/terminal/doc/license_header.txt index e8d3b6525e..1daf37e6a1 100644 --- a/src/terminal/doc/license_header.txt +++ b/src/terminal/doc/license_header.txt @@ -1,4 +1,4 @@ -Copyright (C) 2024 Puter Technologies Inc. +Copyright (C) 2024 Puter Technologies Inc. This file is part of Puter's Terminal. diff --git a/src/terminal/rollup.config.js b/src/terminal/rollup.config.js index ae756766b1..85f3ac7a94 100644 --- a/src/terminal/rollup.config.js +++ b/src/terminal/rollup.config.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Terminal. * diff --git a/src/terminal/src/main.js b/src/terminal/src/main.js index f1254e704a..ab3e8f2fd7 100644 --- a/src/terminal/src/main.js +++ b/src/terminal/src/main.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Terminal. * diff --git a/src/terminal/src/pty/PTT.js b/src/terminal/src/pty/PTT.js index a3d75a0775..7261a7553f 100644 --- a/src/terminal/src/pty/PTT.js +++ b/src/terminal/src/pty/PTT.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Terminal. * diff --git a/src/terminal/src/pty/PTY.js b/src/terminal/src/pty/PTY.js index a053e84140..736724a4ee 100644 --- a/src/terminal/src/pty/PTY.js +++ b/src/terminal/src/pty/PTY.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Terminal. * diff --git a/src/terminal/src/pty/XDocumentANSIShell.js b/src/terminal/src/pty/XDocumentANSIShell.js index 880b7d0659..24bd65d20a 100644 --- a/src/terminal/src/pty/XDocumentANSIShell.js +++ b/src/terminal/src/pty/XDocumentANSIShell.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ /* - * Copyright (C) 2024 Puter Technologies Inc. + * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter's Terminal. * From 6c4c73a9e85ff8eb5e7663dcce11f4d1f824032b Mon Sep 17 00:00:00 2001 From: micheledinelli Date: Tue, 9 Jul 2024 23:32:46 +0200 Subject: [PATCH 0488/2119] Add documentation instructions to get started with My Websites --- doc/prod.md | 12 ++++++++++++ src/gui/src/i18n/translations/en.js | 2 +- src/gui/src/i18n/translations/it.js | 2 +- 3 files changed, 14 insertions(+), 2 deletions(-) diff --git a/doc/prod.md b/doc/prod.md index 5d04898f97..c56c02da4d 100644 --- a/doc/prod.md +++ b/doc/prod.md @@ -124,6 +124,18 @@ The GUI is a single page application (SPA) and as best practice any route under In other words, consider the routes above as "reserved" for Puter. +### Publish My Website + +Right-click anywhere on the desktop to display options +From the options menu, select "New". +Then, choose "Folder". +Give the folder a name according to your preference. + +After creating the folder: + +Right-click on the folder. +Select the option "Publish as Website". + ### Best Practices - The `title` tags and meta tags (``, ` Date: Tue, 9 Jul 2024 15:12:19 -0700 Subject: [PATCH 0489/2119] retry npm 3 times to account for the flakiness of the process --- Dockerfile | 11 +++++++++-- src/puter-js/app-migration-guide.txt | 12 ------------ 2 files changed, 9 insertions(+), 14 deletions(-) delete mode 100644 src/puter-js/app-migration-guide.txt diff --git a/Dockerfile b/Dockerfile index 8a6f8c489d..5e41d7a000 100644 --- a/Dockerfile +++ b/Dockerfile @@ -24,8 +24,15 @@ COPY package*.json ./ COPY . . # Install node modules -RUN npm cache clean --force \ - && npm ci +RUN npm cache clean --force && \ + for i in 1 2 3; do \ + npm ci && break || \ + if [ $i -lt 3 ]; then \ + sleep 15; \ + else \ + exit 1; \ + fi; \ + done # Run the build command if necessary RUN cd src/gui && npm run build && cd - diff --git a/src/puter-js/app-migration-guide.txt b/src/puter-js/app-migration-guide.txt deleted file mode 100644 index f1f530ab22..0000000000 --- a/src/puter-js/app-migration-guide.txt +++ /dev/null @@ -1,12 +0,0 @@ -all UI function calls from puter should be in the form `puter.ui.` - e.g. `puter.showOpenFilePicker` becomes `puter.ui.showOpenFilePicker` - -puter.FileSystem. -> puter.fs. -puter.Router. -> puter.router. -puter.Apps. -> puter.apps. - -puter.setItem -> puter.kv.set -puter.getItem -> puter.kv.get -puter.removeItem -> puter.kv.del -puter.createCloudItem(...) -> new puter.CloudItem(...) -puter.router.* -> puter.hosting.* \ No newline at end of file From eebf3792057506d1259c75680f3ab400c6e7f553 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 9 Jul 2024 15:58:55 -0700 Subject: [PATCH 0490/2119] Move `.commit` to `/tools` --- .commit => tools/.commit | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .commit => tools/.commit (100%) diff --git a/.commit b/tools/.commit similarity index 100% rename from .commit rename to tools/.commit From fafa36c73f8a255ef49fcbcdc4d50497073686e2 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 9 Jul 2024 19:01:28 -0400 Subject: [PATCH 0491/2119] move: move dev-server.js back to gui I'm not sure why it was here, I thought I moved it already. --- dev-server.js | 76 ------------------------------------------- src/gui/dev-server.js | 5 ++- 2 files changed, 2 insertions(+), 79 deletions(-) delete mode 100644 dev-server.js diff --git a/dev-server.js b/dev-server.js deleted file mode 100644 index 9ba6367ec9..0000000000 --- a/dev-server.js +++ /dev/null @@ -1,76 +0,0 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ -import express from "express"; -import { generateDevHtml, build } from "./utils.js"; -import { argv } from 'node:process'; -import chalk from 'chalk'; -import dotenv from 'dotenv'; -dotenv.config(); - -const app = express(); -let port = process.env.PORT ?? 4000; // Starting port -const maxAttempts = 10; // Maximum number of ports to try -const env = argv[2] ?? "dev"; - -const startServer = (attempt, useAnyFreePort = false) => { - if (attempt > maxAttempts) { - useAnyFreePort = true; // Use any port that is free - } - - const server = app.listen(useAnyFreePort ? 0 : port, () => { - console.log("\n-----------------------------------------------------------\n"); - console.log(`Puter is now live at: `, chalk.underline.blue(`http://localhost:${server.address().port}`)); - console.log("\n-----------------------------------------------------------\n"); - }).on('error', (err) => { - if (err.code === 'EADDRINUSE') { // Check if the error is because the port is already in use - console.error(chalk.red(`ERROR: Port ${port} is already in use. Trying next port...`)); - port++; // Increment the port number - startServer(attempt + 1); // Try the next port - } - }); -}; - -// Start the server with the first attempt -startServer(1); - -// build the GUI -build(); - -app.get(["/", "/app/*", "/action/*"], (req, res) => { - res.send(generateDevHtml({ - env: env, - api_origin: "https://api.puter.com", - title: "Puter", - max_item_name_length: 150, - require_email_verification_to_publish_website: false, - short_description: `Puter is a privacy-first personal cloud that houses all your files, apps, and games in one private and secure place, accessible from anywhere at any time.`, - })); -}) -app.use(express.static('./')); - -if(env === "prod"){ - // make sure to serve the ./dist/ folder maps to the root of the website - app.use(express.static('./dist/')); -} - -if(env === "dev"){ - app.use(express.static('./src/')); -} - -export { app }; \ No newline at end of file diff --git a/src/gui/dev-server.js b/src/gui/dev-server.js index d506eff7ba..689b198dff 100644 --- a/src/gui/dev-server.js +++ b/src/gui/dev-server.js @@ -21,7 +21,6 @@ import { generateDevHtml, build } from "./utils.js"; import { argv } from 'node:process'; import chalk from 'chalk'; import dotenv from 'dotenv'; -import path_ from 'path'; dotenv.config(); const app = express(); @@ -67,11 +66,11 @@ app.use(express.static('./')); if(env === "prod"){ // make sure to serve the ./dist/ folder maps to the root of the website - app.use(express.static('./src/gui/dist/')); + app.use(express.static('./dist/')); } if(env === "dev"){ - app.use(express.static('./src/gui/src/')); + app.use(express.static('./src/')); } export { app }; From 831b2e259e2644c641eddaaf87ad513774eb09a3 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 9 Jul 2024 16:54:54 -0700 Subject: [PATCH 0492/2119] Add ladybird to #DIRP and move the license section to the bottom --- README.md | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index 55f828ad76..41c88e7f41 100644 --- a/README.md +++ b/README.md @@ -78,14 +78,6 @@ Puter is available as a hosted service at [**puter.com**](https://puter.com).
- - -## License - -This repository is licensed under AGPL-3.0; However, our SDK (puter.js) is also available under Apache 2.0, as indicated by the license file in that section (packages/puter-js) of this repository. - -
- ## #DoesItRunPuter - [Minecraft](https://twitter.com/HeyPuter/status/1771957571496092036) | [video](https://www.youtube.com/watch?v=GIowZUXkg5g) @@ -99,3 +91,12 @@ This repository is licensed under AGPL-3.0; However, our SDK (puter.js) is also - [Tesla Model Y](https://twitter.com/HeyPuter/status/1772858333751636310) - [Nintendo Switch](https://twitter.com/HeyPuter/status/1780645795240538518) - [Steam Deck](https://twitter.com/everythingSung/status/1782162352403828793) +- [Ladybird Browser](https://x.com/HeyPuter/status/1810783504503800035) + +
+ +## License + +This repository, including all its contents, sub-projects, modules, and components, is licensed under [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) unless explicitly stated otherwise. Third-party libraries included in this repository may be subject to their own licenses. + +
From e745f67273de47129c4fb7605daf204ff9cffa16 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 9 Jul 2024 19:04:09 -0700 Subject: [PATCH 0493/2119] Add 'Support' section to README.md --- README.md | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/README.md b/README.md index 41c88e7f41..6829c6334c 100644 --- a/README.md +++ b/README.md @@ -76,6 +76,19 @@ docker compose up Puter is available as a hosted service at [**puter.com**](https://puter.com). +
+ +## Support + +You can reach out to us and the community in several ways: + +- Bug report or feature request? Please [open an issue](https://github.com/HeyPuter/puter/issues/new/choose). +- Discord: [https://discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- X (Twitter): [https://x.com/HeyPuter](https://x.com/HeyPuter) +- Reddit: [https://www.reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- Email maintainers at [hi@puter.com](mailto:hi@puter.com) + +
## #DoesItRunPuter From e5243ec5602699cfca746809fb96f830d2d96ac6 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 9 Jul 2024 19:05:04 -0700 Subject: [PATCH 0494/2119] Delete .github/ISSUE_TEMPLATE/driver-request.md --- .github/ISSUE_TEMPLATE/driver-request.md | 10 ---------- 1 file changed, 10 deletions(-) delete mode 100644 .github/ISSUE_TEMPLATE/driver-request.md diff --git a/.github/ISSUE_TEMPLATE/driver-request.md b/.github/ISSUE_TEMPLATE/driver-request.md deleted file mode 100644 index 8d7f3be689..0000000000 --- a/.github/ISSUE_TEMPLATE/driver-request.md +++ /dev/null @@ -1,10 +0,0 @@ ---- -name: Driver Request -about: Request a driver on Puter -title: '' -labels: '' -assignees: '' - ---- - -> Drivers are services that apps on Puter can use. For example, drivers support many of the features in the [Puter SDK](https://docs.puter.com/). If you're not sure if what you're suggesting is a driver, you should use the "Feature Request" template instead. From 3bd3be7deed087fecd4db2a662b878bcd6528f01 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 9 Jul 2024 19:15:50 -0700 Subject: [PATCH 0495/2119] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 6829c6334c..678cc4a2c4 100644 --- a/README.md +++ b/README.md @@ -88,6 +88,7 @@ You can reach out to us and the community in several ways: - Reddit: [https://www.reddit.com/r/puter/](https://www.reddit.com/r/puter/) - Email maintainers at [hi@puter.com](mailto:hi@puter.com) +We are always happy to help you with any questions you may have. Don't hesitate to ask!
From 5e4582dda65235006669f5e03e90b065bf81a2f7 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 9 Jul 2024 19:18:14 -0700 Subject: [PATCH 0496/2119] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 678cc4a2c4..5538eb74e2 100644 --- a/README.md +++ b/README.md @@ -80,7 +80,7 @@ Puter is available as a hosted service at [**puter.com**](https://puter.com). ## Support -You can reach out to us and the community in several ways: +Connect with the maintainers and community through these channels: - Bug report or feature request? Please [open an issue](https://github.com/HeyPuter/puter/issues/new/choose). - Discord: [https://discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) From 47ec74f0aa6adb3952e6460909029a4acb0c3039 Mon Sep 17 00:00:00 2001 From: askdkc Date: Wed, 10 Jul 2024 11:20:29 +0900 Subject: [PATCH 0497/2119] Add Japanese Translation --- src/gui/src/i18n/translations/translations.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/src/i18n/translations/translations.js b/src/gui/src/i18n/translations/translations.js index 1abbd95a90..36d55e2644 100644 --- a/src/gui/src/i18n/translations/translations.js +++ b/src/gui/src/i18n/translations/translations.js @@ -31,6 +31,7 @@ import hi from './hi.js'; import hy from './hy.js'; import it from './it.js'; import ig from './ig.js'; +import ja from './ja.js'; import ko from './ko.js'; import nb from './nb.js'; import nl from './nl.js'; @@ -65,6 +66,7 @@ export default { hy, it, ig, + ja, ko, nb, nl, From 31748506b79ff5644bdf1f02d798cfb01b91c825 Mon Sep 17 00:00:00 2001 From: askdkc Date: Wed, 10 Jul 2024 11:22:16 +0900 Subject: [PATCH 0498/2119] Create ja.js for Japanese Translation --- src/gui/src/i18n/translations/ja.js | 353 ++++++++++++++++++++++++++++ 1 file changed, 353 insertions(+) create mode 100644 src/gui/src/i18n/translations/ja.js diff --git a/src/gui/src/i18n/translations/ja.js b/src/gui/src/i18n/translations/ja.js new file mode 100644 index 0000000000..d6409e8e6f --- /dev/null +++ b/src/gui/src/i18n/translations/ja.js @@ -0,0 +1,353 @@ +/** + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ + + +const ja = { + name: "日本語", + english_name: "Japanese", + code: "ja", + dictionary: { + about: "概要", + account: "アカウント", + account_password: "アカウントのパスワードを確認", + access_granted_to: "アクセスを承認するアカウント", + add_existing_account: "既存のアカウントを追加", + all_fields_required: '全ての項目が必須です。', + allow: '許可', + apply: "適用", + ascending: '昇順', + associated_websites: "関連ウェブサイト", + auto_arrange: '自動配置', + background: "背景", + browse: "ブラウズ", + cancel: 'キャンセル', + center: '中央', + change_desktop_background: 'デスクトップの背景を変更…', + change_email: "メールアドレスを変更", + change_language: "言語を変更", + change_password: "パスワードを変更", + change_ui_colors: "UIの色を変更", + change_username: "ユーザー名を変更", + close: '閉じる', + close_all_windows: "すべてのウィンドウを閉じる", + close_all_windows_confirm: "すべてのウィンドウを閉じてよろしいですか?", + close_all_windows_and_log_out: 'ウィンドウを閉じてログアウト', + change_always_open_with: "この種類のファイルを常にこのアプリで開きますか?", + color: '色', + confirm: '確認', + confirm_2fa_setup: '認証アプリにコードを追加しました', + confirm_2fa_recovery: 'リカバリーコードを安全な場所に保存しました', + confirm_account_for_free_referral_storage_c2a: 'アカウントを作成してメールアドレスを確認すると、1GBの無料ストレージを獲得できます。友人も1GBの無料ストレージを獲得します。', + confirm_code_generic_incorrect: "コードが間違っています。", + confirm_code_generic_too_many_requests: "リクエストが多すぎます。数分待ってください。", + confirm_code_generic_submit: "コードを送信", + confirm_code_generic_try_again: "もう一度試す", + confirm_code_generic_title: "確認コードを入力", + confirm_code_2fa_instruction: "認証アプリから6桁のコードを入力してください。", + confirm_code_2fa_submit_btn: "送信", + confirm_code_2fa_title: "2FAコードを入力", + confirm_delete_multiple_items: 'これらの項目を完全に削除してよろしいですか?', + confirm_delete_single_item: 'この項目を完全に削除してよろしいですか?', + confirm_open_apps_log_out: 'アプリが開いています。ログアウトしてもよろしいですか?', + confirm_new_password: "新しいパスワードを確認", + confirm_delete_user: "アカウントを削除してよろしいですか?すべてのファイルとデータが完全に削除されます。この操作は元に戻せません。", + confirm_delete_user_title: "アカウントを削除しますか?", + confirm_session_revoke: "このセッションを取り消してもよろしいですか?", + confirm_your_email_address: "メールアドレスを確認", + contact_us: "お問い合わせ", + contact_us_verification_required: "この機能を使用するには、確認済みのメールアドレスが必要です。", + contain: '合わせる', + continue: "続行", + copy: 'コピー', + copy_link: "リンクをコピー", + copying: "コピー中", + copying_file: "%% コピー中", + cover: '全体に表示', + create_account: "アカウントを作成", + create_free_account: "無料アカウントを作成", + create_shortcut: "ショートカットを作成", + credits: "クレジット", + current_password: "現在のパスワード", + cut: 'カット', + clock: "時計", + clock_visible_hide: '非表示 - 常に非表示', + clock_visible_show: '表示 - 常に表示', + clock_visible_auto: '自動 - デフォルト、フルスクリーンモードでのみ表示', + close_all: 'すべて閉じる', + created: '作成日', + date_modified: '更新日', + default: 'デフォルト', + delete: '削除', + delete_account: "アカウントを削除", + delete_permanently: "完全に削除", + deleting_file: "削除中 %%", + deploy_as_app: 'アプリとしてデプロイ', + descending: '降順', + desktop: 'デスクトップ', + desktop_background_fit: "画面背景をフィット", + developers: "開発者", + dir_published_as_website: `%strong% が公開されました:`, + disable_2fa: '2FAを無効にする', + disable_2fa_confirm: "2FAを無効にしてよろしいですか?", + disable_2fa_instructions: "パスワードを入力して2FAを無効にします。", + disassociate_dir: "ディレクトリの関連付けを解除", + documents: 'ドキュメント', + dont_allow: '許可しない', + download: 'ダウンロード', + download_file: 'ファイルをダウンロード', + downloading: "ダウンロード中", + email: "メール", + email_change_confirmation_sent: "確認メールが新しいメールアドレスに送信されました。受信トレイを確認し、指示に従って手続きを完了してください。", + email_invalid: 'メールアドレスが無効です。', + email_or_username: "メールアドレスまたはユーザー名", + email_required: 'メールアドレスは必須です。', + empty_trash: 'ゴミ箱を空にする', + empty_trash_confirmation: 'ゴミ箱の中のアイテムを完全に削除してもよろしいですか?', + emptying_trash: 'ゴミ箱を空にしています…', + enable_2fa: '2FAを有効にする', + end_hard: "ハード終了", + end_process_force_confirm: "このプロセスを強制終了してもよろしいですか?", + end_soft: "ソフト終了", + enlarged_qr_code: "拡大QRコード", + enter_password_to_confirm_delete_user: "アカウント削除を確認するためにパスワードを入力してください", + error_message_is_missing: "エラーメッセージがありません。", + error_unknown_cause: "不明なエラーが発生しました。", + error_uploading_files: "ファイルのアップロードに失敗しました", + favorites: "お気に入り", + feedback: "フィードバック", + feedback_c2a: "以下のフォームを使用して、フィードバック、コメント、およびバグ報告をお送りください。", + feedback_sent_confirmation: "お問い合わせいただきありがとうございます。アカウントに関連付けられたメールがある場合は、できるだけ早く返信いたします。", + fit: "フィット", + folder: 'フォルダー', + force_quit: '強制終了', + forgot_pass_c2a: "パスワードを忘れましたか?", + from: "送信者", + general: "一般", + get_a_copy_of_on_puter: `Puter.comで '%%' のコピーを取得!`, + get_copy_link: 'コピーリンクを取得', + hide_all_windows: "すべてのウィンドウを隠す", + home: 'ホーム', + html_document: 'HTML文書', + hue: '色合い', + image: '画像', + incorrect_password: "パスワードが間違っています", + invite_link: "招待リンク", + item: 'アイテム', + items_in_trash_cannot_be_renamed: 'このアイテムはゴミ箱にあるため、名前を変更できません。このアイテムの名前を変更するには、まずゴミ箱からドラッグしてください。', + jpeg_image: 'JPEG画像', + keep_in_taskbar: 'タスクバーに保持', + language: "言語", + license: "ライセンス", + lightness: '明るさ', + link_copied: "リンクがコピーされました", + loading: '読み込み中', + log_in: "ログイン", + log_into_another_account_anyway: '別のアカウントにログインする', + log_out: 'ログアウト', + looks_good: "ナイス!", + manage_sessions: "セッションを管理", + menubar_style: "メニューバースタイル", + menubar_style_desktop: "デスクトップ", + menubar_style_system: "システム", + menubar_style_window: "ウィンドウ", + modified: '変更日時', + move: '移動', + moving_file: "移動中 %%", + my_websites: "私のウェブサイト", + name: '名前', + name_cannot_be_empty: '名前は空にできません。', + name_cannot_contain_double_period: "名前には '..' 文字を含めることはできません。", + name_cannot_contain_period: "名前には '.' 文字を含めることはできません。", + name_cannot_contain_slash: "名前には '/' 文字を含めることはできません。", + name_must_be_string: "名前は文字列のみ可能です。", + name_too_long: `名前は %% 文字を超えてはなりません。`, + new: '新規', + new_email: '新しいメールアドレス', + new_folder: '新しいフォルダー', + new_password: "新しいパスワード", + new_username: "新しいユーザー名", + no: 'いいえ', + no_dir_associated_with_site: 'このアドレスには関連付けられたディレクトリがありません。', + no_websites_published: "まだウェブサイトを公開していません。開始するにはフォルダーを右クリックしてください。", + ok: 'OK', + open: "開く", + open_in_new_tab: "新しいタブで開く", + open_in_new_window: "新しいウィンドウで開く", + open_with: "アプリケーションで開く", + original_name: '元の名前', + original_path: '元のパス', + oss_code_and_content: "オープンソースソフトウェアとコンテンツ", + password: "パスワード", + password_changed: "パスワードが変更されました。", + password_recovery_rate_limit: "レート制限に達しました。数分待ってください。将来これを防ぐために、ページを何度もリロードしないでください。", + password_recovery_token_invalid: "このパスワードリカバリトークンは無効です。", + password_recovery_unknown_error: "不明なエラーが発生しました。後でもう一度試してください。", + password_required: 'パスワードは必須です。', + password_strength_error: "パスワードは8文字以上で、少なくとも1つの大文字、小文字、数字、および特殊文字を含む必要があります。", + passwords_do_not_match: '`新しいパスワード`と`新しいパスワードを確認`が一致しません。', + paste: '貼り付け', + paste_into_folder: "フォルダーに貼り付け", + path: 'パス', + personalization: "パーソナライズ", + pick_name_for_website: "ウェブサイトの名前を選んでください:", + picture: "写真", + pictures: '写真', + plural_suffix: '', + powered_by_puter_js: `{{link=docs}}Puter.js{{/link}} によって提供されています`, + preparing: "準備中...", + preparing_for_upload: "アップロードの準備中...", + print: '印刷', + privacy: "プライバシー", + proceed_to_login: 'ログインに進む', + proceed_with_account_deletion: "アカウントの削除を続行", + process_status_initializing: "初期化中", + process_status_running: "実行中", + process_type_app: 'アプリ', + process_type_init: '初期化', + process_type_ui: 'UI', + properties: "プロパティ", + public: '公開', + publish: "公開", + publish_as_website: 'ウェブサイトとして公開', + puter_description: `Puterは、すべてのファイル、アプリ、およびゲームを一か所に安全に保管し、いつでもどこからでもアクセスできるプライバシー重視の個人用クラウドです。`, + reading_file: "読み込み中 %strong%", + recent: "最近", + recommended: "おすすめ", + recover_password: "パスワードを回復", + refer_friends_c2a: "友達がPuterでアカウントを作成して確認すると、1GBを獲得できます。友達も1GBを獲得できます!", + refer_friends_social_media_c2a: `Puter.comで1GBの無料ストレージを手に入れよう!`, + refresh: '更新', + release_address_confirmation: `このアドレスを解放してもよろしいですか?`, + remove_from_taskbar: 'タスクバーから削除', + rename: '名前を変更', + repeat: '繰り返す', + replace: '置換', + replace_all: 'すべて置換', + resend_confirmation_code: "確認コードを再送信", + reset_colors: "色をリセット", + restart_puter_confirm: "Puterを再起動してもよろしいですか?", + restore: "復元", + save: '保存', + saturation: '彩度', + save_account: 'アカウントを保存', + save_account_to_get_copy_link: "続行するにはアカウントを作成してください。", + save_account_to_publish: '続行するにはアカウントを作成してください。', + save_session: 'セッションを保存', + save_session_c2a: '現在のセッションを保存して、作業を失わないようにするにはアカウントを作成してください。', + scan_qr_c2a: '以下のコードをスキャンすると、他のデバイスからこのセッションにログインできます', + scan_qr_2fa: '認証アプリでQRコードをスキャンしてください', + scan_qr_generic: 'スマートフォンまたは他のデバイスでこのQRコードをスキャンしてください', + search: '検索', + seconds: '秒', + security: "セキュリティ", + select: "選択", + selected: '選択済み', + select_color: '色を選択…', + sessions: "セッション", + send: "送信", + send_password_recovery_email: "パスワード回復メールを送信", + session_saved: "アカウントを作成していただきありがとうございます。このセッションは保存されました。", + settings: "設定", + set_new_password: "新しいパスワードを設定", + share: "共有", + share_to: "共有先", + share_with: "共有相手:", + shortcut_to: "ショートカット先", + show_all_windows: "すべてのウィンドウを表示", + show_hidden: '隠しファイルを表示', + sign_in_with_puter: "Puterでサインイン", + sign_up: "サインアップ", + signing_in: "サインイン中…", + size: 'サイズ', + skip: 'スキップ', + something_went_wrong: "問題が発生しました。", + sort_by: '並べ替え', + start: '開始', + status: "ステータス", + storage_usage: "ストレージ使用量", + storage_puter_used: 'Puterで使用中', + taking_longer_than_usual: 'いつもより少し時間がかかっています。お待ちください...', + task_manager: "タスクマネージャー", + taskmgr_header_name: "名前", + taskmgr_header_status: "ステータス", + taskmgr_header_type: "タイプ", + terms: "利用規約", + text_document: 'テキスト文書', + tos_fineprint: `「無料アカウントを作成」をクリックすることで、Puterの{{link=terms}}利用規約{{/link}}および{{link=privacy}}プライバシーポリシー{{/link}}に同意するものとします。`, + transparency: "透明度", + trash: 'ゴミ箱', + two_factor: '二要素認証', + two_factor_disabled: '2FA無効', + two_factor_enabled: '2FA有効', + type: 'タイプ', + type_confirm_to_delete_account: "アカウントを削除するには「confirm」と入力してください。", + ui_colors: "UIカラー", + ui_manage_sessions: "セッションマネージャー", + ui_revoke: "取り消し", + undo: '元に戻す', + unlimited: '無制限', + unzip: "解凍", + upload: 'アップロード', + upload_here: 'ここにアップロード', + usage: '使用量', + username: "ユーザー名", + username_changed: 'ユーザー名が正常に更新されました。', + username_required: 'ユーザー名は必須です。', + versions: "バージョン", + videos: '動画', + visibility: '見え方', + yes: 'はい', + yes_release_it: 'はい、解放します', + you_have_been_referred_to_puter_by_a_friend: "友達からPuterに紹介されました!", + zip: "圧縮", + zipping_file: "圧縮中 %strong%", + + // === 2FA Setup === + setup2fa_1_step_heading: '認証アプリを開く', + setup2fa_1_instructions: ` + Time-based One-Time Password (TOTP) プロトコルをサポートする任意の認証アプリを使用できます。 + 多くの選択肢がありますが、迷った場合は + Authy + がAndroidとiOSのおすすめの選択肢です。 + `, + setup2fa_2_step_heading: 'QRコードをスキャンする', + setup2fa_3_step_heading: '6桁のコードを入力', + setup2fa_4_step_heading: '回復コードをコピーする', + setup2fa_4_instructions: ` + これらの回復コードは、電話を紛失したり認証アプリを使用できない場合にアカウントにアクセスする唯一の方法です。 + 安全な場所に保管してください。 + `, + setup2fa_5_step_heading: '2FA設定を確認', + setup2fa_5_confirmation_1: '回復コードを安全な場所に保存しました', + setup2fa_5_confirmation_2: '2FAを有効にする準備ができました', + setup2fa_5_button: '2FAを有効にする', + + // === 2FA Login === + login2fa_otp_title: '2FAコードを入力', + login2fa_otp_instructions: '認証アプリから6桁のコードを入力してください。', + login2fa_recovery_title: '回復コードを入力', + login2fa_recovery_instructions: 'アカウントにアクセスするために、回復コードの1つを入力してください。', + login2fa_use_recovery_code: '回復コードを使用', + login2fa_recovery_back: '戻る', + + login2fa_recovery_placeholder: 'XXXXXXXX', + } +}; + +export default ja; \ No newline at end of file From 67139ef91b8ee2a177ea50255467f16ba36d7b82 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 10 Jul 2024 00:40:37 -0400 Subject: [PATCH 0499/2119] dev(tools): add license header adder thingy --- addlicense.yml | 1 + package-lock.json | 455 ++++++++++++++++++++++++++++- tools/comment-parser/main.js | 345 ++++++++++++++++++++++ tools/comment-parser/package.json | 15 + tools/comment-parser/test/test.js | 127 ++++++++ tools/file-walker/test.js | 44 +-- tools/license-headers/main.js | 356 ++++++++++++++++++++++ tools/license-headers/package.json | 19 ++ 8 files changed, 1334 insertions(+), 28 deletions(-) create mode 100644 addlicense.yml create mode 100644 tools/comment-parser/main.js create mode 100644 tools/comment-parser/package.json create mode 100644 tools/comment-parser/test/test.js create mode 100644 tools/license-headers/main.js create mode 100644 tools/license-headers/package.json diff --git a/addlicense.yml b/addlicense.yml new file mode 100644 index 0000000000..c826c8da38 --- /dev/null +++ b/addlicense.yml @@ -0,0 +1 @@ +header: doc/license_header.txt diff --git a/package-lock.json b/package-lock.json index 45d091cc0a..89380bb756 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1024,6 +1024,102 @@ "url": "https://github.com/sponsors/nzakas" } }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "license": "ISC", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "license": "MIT", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", + "license": "MIT" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "license": "MIT", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -6021,6 +6117,10 @@ "node": ">=14" } }, + "node_modules/comment-parser": { + "resolved": "tools/comment-parser", + "link": true + }, "node_modules/commondir": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", @@ -6183,6 +6283,15 @@ "integrity": "sha512-ty/fTekppD2fIwRvnZAVdeOiGd1c7YXEixbgJTNzqcxJWKQnjJ/V1bNEEE6hygpM3WjwHFUVK6HTjWSzV4a8sQ==", "license": "ISC" }, + "node_modules/console-table-printer": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/console-table-printer/-/console-table-printer-2.12.1.tgz", + "integrity": "sha512-wKGOQRRvdnd89pCeH96e2Fn4wkbenSP6LMHfjfyNLMbGuHEFbMqQNuxXqd0oXG9caIOQ1FTvc5Uijp9/4jujnQ==", + "license": "MIT", + "dependencies": { + "simple-wcswidth": "^1.0.1" + } + }, "node_modules/content-disposition": { "version": "0.5.4", "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", @@ -6327,7 +6436,6 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", - "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -6617,6 +6725,12 @@ "node": ">=0.3.1" } }, + "node_modules/diff-match-patch": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/diff-match-patch/-/diff-match-patch-1.0.5.tgz", + "integrity": "sha512-IayShXAgj/QMXgB0IWmKx+rOPuGMhqm5w6jvFxmVenXKIzRqTAAsbBPT3kWQeGANj3jGgvcvv4yK6SxqYmikgw==", + "license": "Apache-2.0" + }, "node_modules/diff3": { "version": "0.0.3", "resolved": "https://registry.npmjs.org/diff3/-/diff3-0.0.3.tgz", @@ -6707,6 +6821,12 @@ "url": "https://dotenvx.com" } }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", + "license": "MIT" + }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -8001,6 +8121,10 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/google-license": { + "resolved": "tools/google-license", + "link": true + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -8682,8 +8806,7 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", - "dev": true + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" }, "node_modules/isobject": { "version": "3.0.1", @@ -8889,6 +9012,24 @@ "node": ">=8" } }, + "node_modules/jackspeak": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.1.tgz", + "integrity": "sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==", + "license": "BlueOak-1.0.0", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, "node_modules/jest-worker": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", @@ -8973,6 +9114,15 @@ "integrity": "sha512-WZzeDOEtTOBK4Mdsar0IqEU5sMr3vSV2RqkAIzUEV2BHnUfKGyswWFPFwK5EeDo93K3FohSHbLAjj0s1Wzd+dg==", "license": "BSD-3-Clause" }, + "node_modules/js-levenshtein": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/js-levenshtein/-/js-levenshtein-1.1.6.tgz", + "integrity": "sha512-X2BB11YZtrRqY4EnQcLX5Rh373zbK4alC1FW7D7MBhL2gtcC17cTnr6DmfHZeS0s2rTHjUTMMHfG7gO8SSdw+g==", + "license": "MIT", + "engines": { + "node": ">=0.10.0" + } + }, "node_modules/js-parse-and-output": { "resolved": "experiments/js-parse-and-output", "link": true @@ -9458,6 +9608,10 @@ "decamelize": "^1.2.0" } }, + "node_modules/license-headers": { + "resolved": "tools/license-headers", + "link": true + }, "node_modules/load-bmfont": { "version": "1.4.1", "resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.1.tgz", @@ -10760,6 +10914,12 @@ "node": ">=8" } }, + "node_modules/package-json-from-dist": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", + "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", + "license": "BlueOak-1.0.0" + }, "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -10855,7 +11015,6 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", - "dev": true, "engines": { "node": ">=8" } @@ -10865,6 +11024,40 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, + "node_modules/path-scurry": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", + "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", + "license": "BlueOak-1.0.0", + "dependencies": { + "lru-cache": "^11.0.0", + "minipass": "^7.1.2" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.0.tgz", + "integrity": "sha512-Qv32eSV1RSCfhY3fpPE2GNZ8jgM9X7rdAfemLWqTUxwiyIC4jJ6Sy0fZ8H+oLWevO6i4/bizg7c8d8i6bxrzbA==", + "license": "ISC", + "engines": { + "node": "20 || >=22" + } + }, + "node_modules/path-scurry/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -11965,7 +12158,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", - "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -11977,7 +12169,6 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", - "dev": true, "engines": { "node": ">=8" } @@ -12116,6 +12307,12 @@ "node": ">=10" } }, + "node_modules/simple-wcswidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-wcswidth/-/simple-wcswidth-1.0.1.tgz", + "integrity": "sha512-xMO/8eNREtaROt7tJvWJqHBDTMFN4eiQ5I4JRMuilwfnFcV5W9u7RUkueNkdw0jPqGMX36iCywelS5yilTuOxg==", + "license": "MIT" + }, "node_modules/sinon": { "version": "15.2.0", "resolved": "https://registry.npmjs.org/sinon/-/sinon-15.2.0.tgz", @@ -12435,6 +12632,21 @@ "node": ">=8" } }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "license": "MIT", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -12446,6 +12658,19 @@ "node": ">=8" } }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "license": "MIT", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", @@ -13383,7 +13608,6 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", - "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -13525,6 +13749,24 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "license": "MIT", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -13638,6 +13880,18 @@ "dev": true, "license": "ISC" }, + "node_modules/yaml": { + "version": "2.4.5", + "resolved": "https://registry.npmjs.org/yaml/-/yaml-2.4.5.tgz", + "integrity": "sha512-aBx2bnqDzVOyNKfsysjA2ms5ZlnjSAW2eG3/L5G/CSujfjLJTJsEw1bGw8kCf04KodQWk1pxlGnZ56CRxiawmg==", + "license": "ISC", + "bin": { + "yaml": "bin.mjs" + }, + "engines": { + "node": ">= 14" + } + }, "node_modules/yargs": { "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", @@ -14213,9 +14467,196 @@ "version": "1.0.0", "license": "AGPL-3.0-only" }, + "tools/comment-parser": { + "version": "1.0.0", + "license": "AGPL-3.0-only", + "devDependencies": { + "chai": "^5.1.1" + } + }, + "tools/comment-parser/node_modules/assertion-error": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-2.0.1.tgz", + "integrity": "sha512-Izi8RQcffqCeNVgFigKli1ssklIbpHnCYc6AknXGYoB6grJqyeby7jv12JUQgmTAnIDnbck1uxksT4dzN3PWBA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=12" + } + }, + "tools/comment-parser/node_modules/chai": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/chai/-/chai-5.1.1.tgz", + "integrity": "sha512-pT1ZgP8rPNqUgieVaEY+ryQr6Q4HXNg8Ei9UnLUrjN4IA7dvQC5JB+/kxVcPNDHyBcc/26CXPkbNzq3qwrOEKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "assertion-error": "^2.0.1", + "check-error": "^2.1.1", + "deep-eql": "^5.0.1", + "loupe": "^3.1.0", + "pathval": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "tools/comment-parser/node_modules/check-error": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-2.1.1.tgz", + "integrity": "sha512-OAlb+T7V4Op9OwdkjmguYRqncdlx5JiofwOAUkmTF+jNdHwzTaTs4sRAGpzLF3oOz5xAyDGrPgeIDFQmDOTiJw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 16" + } + }, + "tools/comment-parser/node_modules/deep-eql": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-5.0.2.tgz", + "integrity": "sha512-h5k/5U50IJJFpzfL6nO9jaaumfjO/f2NjK/oYB2Djzm4p9L+3T9qWpZqZ2hAbLPuuYq9wrU08WQyBTL5GbPk5Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "tools/comment-parser/node_modules/loupe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-3.1.1.tgz", + "integrity": "sha512-edNu/8D5MKVfGVFRhFf8aAxiTM6Wumfz5XsaatSxlD3w4R1d/WEKUTydCdPGbl9K7QG/Ca3GnDV2sIKIpXRQcw==", + "dev": true, + "license": "MIT", + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "tools/comment-parser/node_modules/pathval": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-2.0.0.tgz", + "integrity": "sha512-vE7JKRyES09KiunauX7nd2Q9/L7lhok4smP9RZTDeD4MVs72Dp2qNFVz39Nz5a0FVEW0BJR6C0DYrq6unoziZA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 14.16" + } + }, "tools/file-walker": { "version": "1.0.0", "license": "AGPL-3.0-only" + }, + "tools/google-license": { + "version": "1.0.0", + "license": "ISC", + "dependencies": { + "commander": "^12.1.0", + "glob": "^11.0.0", + "handlebars": "^4.7.8" + } + }, + "tools/google-license/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "tools/google-license/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "tools/google-license/node_modules/foreground-child": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", + "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", + "license": "ISC", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "tools/google-license/node_modules/glob": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz", + "integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==", + "license": "ISC", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^4.0.1", + "minimatch": "^10.0.0", + "minipass": "^7.1.2", + "package-json-from-dist": "^1.0.0", + "path-scurry": "^2.0.0" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "tools/google-license/node_modules/minimatch": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", + "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": "20 || >=22" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "tools/google-license/node_modules/minipass": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", + "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", + "license": "ISC", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "tools/google-license/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "license": "ISC", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "tools/license-headers": { + "version": "1.0.0", + "license": "AGPL-3.0-only", + "dependencies": { + "console-table-printer": "^2.12.1", + "dedent": "^1.5.3", + "diff-match-patch": "^1.0.5", + "js-levenshtein": "^1.1.6", + "yaml": "^2.4.5" + } } } } diff --git a/tools/comment-parser/main.js b/tools/comment-parser/main.js new file mode 100644 index 0000000000..0441291578 --- /dev/null +++ b/tools/comment-parser/main.js @@ -0,0 +1,345 @@ +const lib = {}; +lib.dedent_lines = lines => { + // If any lines are just spaces, remove the spaces + for ( let i=0 ; i < lines.length ; i++ ) { + if ( /^\s+$/.test(lines[i]) ) lines[i] = ''; + } + + // Remove leading and trailing blanks + while ( lines[0] === '' ) lines.shift(); + while ( lines[lines.length-1] === '' ) lines.pop(); + + let min_indent = Number.MAX_SAFE_INTEGER; + for ( let i=0 ; i < lines.length ; i++ ) { + if ( lines[i] === '' ) continue; + let n_spaces = 0; + for ( let j=0 ; j < lines[i].length ; j++ ) { + if ( lines[i][j] === ' ' ) n_spaces++; + else break; + } + if ( n_spaces < min_indent ) min_indent = n_spaces; + } + for ( let i=0 ; i < lines.length ; i++ ) { + if ( lines[i] === '' ) continue; + lines[i] = lines[i].slice(min_indent); + } +}; + +const StringStream = (str, { state_ } = {}) => { + const state = state_ ?? { pos: 0 }; + return { + skip_whitespace () { + while ( /^\s/.test(str[state.pos]) ) state.pos++; + }, + // INCOMPLETE: only handles single chars + skip_matching (items) { + while ( items.some(item => { + return str[state.pos] === item; + }) ) state.pos++; + }, + fwd (amount) { + state.pos += amount ?? 1; + }, + fork () { + return StringStream(str, { state_: { pos: state.pos } }); + }, + async get_pos () { + return state.pos; + }, + async get_char () { + return str[state.pos]; + }, + async matches (re_or_lit) { + if ( re_or_lit instanceof RegExp ) { + const re = re_or_lit; + return re.test(str.slice(state.pos)); + } + + const lit = re_or_lit; + return lit === str.slice(state.pos, state.pos + lit.length); + }, + async get_until (re_or_lit) { + let index; + if ( re_or_lit instanceof RegExp ) { + const re = re_or_lit; + const result = re.exec(str.slice(state.pos)); + if ( ! result ) return; + index = state.pos + result.index; + } else { + const lit = re_or_lit; + const ind = str.slice(state.pos).indexOf(lit); + // TODO: parser warnings? + if ( ind === -1 ) return; + index = state.pos + ind; + } + const start_pos = state.pos; + state.pos = index; + return str.slice(start_pos, index); + }, + async debug () { + const l1 = str.length; + const l2 = str.length - state.pos; + const clean = s => s.replace(/\n/, '{LF}'); + return `[stream : "${ + clean(str.slice(0, Math.min(6, l1))) + }"... |${state.pos}| ..."${ + clean(str.slice(state.pos, state.pos + Math.min(6, l2))) + }"]` + } + }; +}; + +const LinesCommentParser = ({ + prefix +}) => { + return { + parse: async (stream) => { + stream.skip_whitespace(); + const lines = []; + while ( await stream.matches(prefix) ) { + const line = await stream.get_until('\n'); + if ( ! line ) return; + lines.push(line); + stream.fwd(); + stream.skip_matching([' ', '\t']); + if ( await stream.get_char() === '\n' ){ + stream.fwd(); + break; + } + stream.skip_whitespace(); + } + if ( lines.length === 0 ) return; + for ( let i=0 ; i < lines.length ; i++ ) { + lines[i] = lines[i].slice(prefix.length); + } + lib.dedent_lines(lines); + return { + lines, + }; + } + }; +}; + +const BlockCommentParser = ({ + start, + end, + ignore_line_prefix, +}) => { + return { + parse: async (stream) => { + stream.skip_whitespace(); + stream.debug('starting at', await stream.debug()) + if ( ! stream.matches(start) ) return; + stream.fwd(start.length); + const contents = await stream.get_until(end); + if ( ! contents ) return; + stream.fwd(end.length); + // console.log('ending at', await stream.debug()) + const lines = contents.split('\n'); + + // === Formatting Time! === // + + // Special case: remove the last '*' after '/**' + if ( lines[0].trim() === ignore_line_prefix ) { + lines.shift(); + } + + // First dedent pass + lib.dedent_lines(lines); + + // If all the lines start with asterisks, remove + let allofem = true; + for ( let i=0 ; i < lines.length ; i++ ) { + if ( lines[i] === '' ) continue; + if ( ! lines[i].startsWith(ignore_line_prefix) ) { + allofem = false; + break + } + } + + if ( allofem ) { + for ( let i=0 ; i < lines.length ; i++ ) { + if ( lines[i] === '' ) continue; + lines[i] = lines[i].slice(ignore_line_prefix.length); + } + + // Second dedent pass + lib.dedent_lines(lines); + } + + return { lines }; + } + }; +}; + +const LinesCommentWriter = ({ prefix }) => { + return { + write: (lines) => { + lib.dedent_lines(lines); + for ( let i=0 ; i < lines.length ; i++ ) { + lines[i] = prefix + lines[i]; + } + return lines.join('\n') + '\n'; + } + }; +}; + +const BlockCommentWriter = ({ start, end, prefix }) => { + return { + write: (lines) => { + lib.dedent_lines(lines); + for ( let i=0 ; i < lines.length ; i++ ) { + lines[i] = prefix + lines[i]; + } + let s = start + '\n'; + s += lines.join('\n') + '\n'; + s += end + '\n'; + return s; + } + }; +}; + +const CommentParser = () => { + const registry_ = { + object: { + parsers: { + lines: LinesCommentParser, + block: BlockCommentParser, + }, + writers: { + lines: LinesCommentWriter, + block: BlockCommentWriter, + }, + }, + data: { + extensions: { + js: 'javascript', + cjs: 'javascript', + mjs: 'javascript', + }, + languages: { + javascript: { + parsers: [ + ['lines', { + prefix: '// ', + }], + ['block', { + start: '/*', + end: '*/', + ignore_line_prefix: '*', + }], + ], + writers: { + lines: ['lines', { + prefix: '//' + }], + block: ['block', { + start: '/*', + end: '*/', + prefix: ' * ', + }] + }, + } + }, + } + + }; + + const get_language_by_filename = ({ filename }) => { + const { language } = (({ filename }) => { + const { language_id } = (({ filename }) => { + const { extension } = (({ filename }) => { + const components = ('' + filename).split('.'); + const extension = components[components.length - 1]; + return { extension }; + })({ filename }); + + const language_id = registry_.data.extensions[extension]; + + if ( ! language_id ) { + throw new Error(`unrecognized language id: ` + + language_id); + } + return { language_id }; + })({ filename }); + + const language = registry_.data.languages[language_id]; + return { language }; + })({ filename }); + + if ( ! language ) { + // TODO: use strutil quot here + throw new Error(`unrecognized language: ${language}`) + } + + return { language }; + } + + const supports = ({ filename }) => { + try { + get_language_by_filename({ filename }); + } catch (e) { + return false; + } + return true; + }; + + const extract_top_comments = async ({ filename, source }) => { + const { language } = get_language_by_filename({ filename }); + + // TODO: registry has `data` and `object`... + // ... maybe add `virt` (virtual), which will + // behave in the way the above code is written. + + const inst_ = spec => registry_.object.parsers[spec[0]](spec[1]); + + let ss = StringStream(source); + const results = []; + for (;;) { + let comment; + for ( let parser of language.parsers ) { + const parser_name = parser[0]; + parser = inst_(parser); + + const ss_ = ss.fork(); + const start_pos = await ss_.get_pos(); + comment = await parser.parse(ss_); + const end_pos = await ss_.get_pos(); + if ( comment ) { + ss = ss_; + comment.type = parser_name; + comment.range = [start_pos, end_pos]; + break; + } + } + if ( ! comment ) break; + results.push(comment); + } + + return results; + } + + const output_comment = ({ filename, style, text }) => { + const { language } = get_language_by_filename({ filename }); + + const inst_ = spec => registry_.object.writers[spec[0]](spec[1]); + let writer = language.writers[style]; + writer = inst_(writer); + const lines = text.split('\n'); + const s = writer.write(lines); + return s; + } + + return { + supports, + extract_top_comments, + output_comment, + }; +}; + +module.exports = { + StringStream, + LinesCommentParser, + BlockCommentParser, + CommentParser, +}; diff --git a/tools/comment-parser/package.json b/tools/comment-parser/package.json new file mode 100644 index 0000000000..4f4aa82f0e --- /dev/null +++ b/tools/comment-parser/package.json @@ -0,0 +1,15 @@ +{ + "name": "comment-parser", + "version": "1.0.0", + "main": "main.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "AGPL-3.0-only", + "description": "", + "devDependencies": { + "chai": "^5.1.1" + } +} diff --git a/tools/comment-parser/test/test.js b/tools/comment-parser/test/test.js new file mode 100644 index 0000000000..67ef095cf1 --- /dev/null +++ b/tools/comment-parser/test/test.js @@ -0,0 +1,127 @@ +const { + StringStream, + LinesCommentParser, + BlockCommentParser, + CommentParser +} = require('../main'); + +const assert = async (label, fn) => { + if ( ! await fn() ) { + // TODO: strutil quot + throw new Error(`assert: '${label}' failed`) + } +}; + +describe('parsers', () => { + describe('lines-comment-parser', () => { + it ('basic test', async () => { + const parser = LinesCommentParser({ prefix: '//' }); + let lines; + const ss = StringStream(` + // first line of first block + // second line of first block + + // first line of second block + + function () {} + `); + const results = []; + for (;;) { + comment = await parser.parse(ss); + if ( ! comment ) break; + results.push(comment.lines); + } + console.log('results?', results); + }) + }) + describe('block-comment-parser', () => { + it ('basic test', async () => { + const parser = BlockCommentParser({ + start: '/*', + end: '*/', + ignore_line_prefix: '*', + }); + let lines; + const ss = StringStream(` + /* + First block + comment + */ + /* + * second block + * comment + */ + + /** + * third block + * comment + */ + function () {} + `); + const results = []; + for (;;) { + comment = await parser.parse(ss); + if ( ! comment ) break; + results.push(comment.lines); + } + console.log('results?', results); + }) + it ('doesn\'t return anything for line comments', async () => { + const parser = BlockCommentParser({ + start: '/*', + end: '*/', + ignore_line_prefix: '*', + }); + let lines; + const ss = StringStream(` + // this comment should not be parsed + // by the block comment parser + function () {} + `); + const results = []; + for (;;) { + comment = await parser.parse(ss); + if ( ! comment ) break; + results.push(comment.lines); + } + console.log('results?', results); + }) + }) + describe('extract_top_comments', () => { + it ('basic test', async () => { + const parser = CommentParser(); + + const filename = 'test.js'; + const source = ` + // First lines comment + // second line of lines comment + + /* + First block comment + second line of block comment + */ + `; + + const results = await parser.extract_top_comments({ + filename, + source, + }); + console.log('results?', results); + }) + }) + describe('StringStream', () => { + describe('fork', () => { + it('works', async () => { + const ss = StringStream('asdf'); + const ss_ = ss.fork(); + ss_.fwd(); + await assert('fwd worked', async () => { + return await ss_.get_char() === 's'; + }); + await assert('upstream state is same', async () => { + return await ss.get_char() === 'a'; + }); + }) + }) + }) +}); diff --git a/tools/file-walker/test.js b/tools/file-walker/test.js index 784e7e282f..603dd4bb75 100644 --- a/tools/file-walker/test.js +++ b/tools/file-walker/test.js @@ -20,6 +20,19 @@ const fs = require('fs'); const fsp = fs.promises; const path_ = require('path'); +const EXCLUDE_LISTS = { + NOT_SOURCE: [ + /^\.git/, + /^volatile\//, + /^node_modules\//, + /\/node_modules$/, + /^node_modules$/, + /package-lock\.json/, + /src\/backend\/src\/public\/assets/, + /^src\/gui\/src\/lib/ + ] +}; + const hl_readdir = async path => { const names = await fs.promises.readdir(path); const entries = []; @@ -130,15 +143,7 @@ const blame = async (path) => { const walk_test = async () => { // console.log(await hl_readdir('.')); for await ( const value of walk({ - excludes: [ - /^\.git/, - /^volatile\//, - /^node_modules\//, - /\/node_modules$/, - /^node_modules$/, - /package-lock\.json/, - /^src\/gui\/dist/, - ] + excludes: EXCLUDE_LISTS.NOT_SOURCE, }, '.') ) { if ( ! value.is_dir ) continue; console.log('value', value.path); @@ -170,16 +175,7 @@ git blame parsing. const walk_and_blame = async () => { // console.log(await hl_readdir('.')); for await ( const value of walk({ - excludes: [ - /^\.git/, - /^volatile\//, - /^node_modules\//, - /\/node_modules$/, - /^node_modules$/, - /package-lock\.json/, - /src\/backend\/src\/public\/assets/, - /^src\/gui\/src\/lib/ - ] + excludes: EXCLUDE_LISTS.NOT_SOURCE, }, '.') ) { if ( value.is_dir ) continue; console.log('value', value.path); @@ -194,6 +190,12 @@ const walk_and_blame = async () => { console.log('AUTHORS', authors); } -const main = walk_and_blame; +if ( require.main === module ) { + const main = walk_and_blame; + main(); +} -main(); +module.exports = { + walk, + EXCLUDE_LISTS, +}; diff --git a/tools/license-headers/main.js b/tools/license-headers/main.js new file mode 100644 index 0000000000..8c4a6bbe06 --- /dev/null +++ b/tools/license-headers/main.js @@ -0,0 +1,356 @@ +const levenshtein = require('js-levenshtein'); +const DiffMatchPatch = require('diff-match-patch'); +const dmp = new DiffMatchPatch(); +const dedent = require('dedent'); + +const { walk, EXCLUDE_LISTS } = require('file-walker'); +const { CommentParser } = require('../comment-parser/main'); + +const fs = require('fs'); +const path_ = require('path'); + +const CompareFn = ({ header1, header2, distance_only = false }) => { + + // Calculate Levenshtein distance + const distance = levenshtein(header1, header2); + // console.log(`Levenshtein distance: ${distance}`); + + if ( distance_only ) return { distance }; + + // Generate diffs using diff-match-patch + const diffs = dmp.diff_main(header1, header2); + dmp.diff_cleanupSemantic(diffs); + + let term_diff = ''; + + // Manually format diffs for terminal display + diffs.forEach(([type, text]) => { + switch (type) { + case DiffMatchPatch.DIFF_INSERT: + term_diff += `\x1b[32m${text}\x1b[0m`; // Green for insertions + break; + case DiffMatchPatch.DIFF_DELETE: + term_diff += `\x1b[31m${text}\x1b[0m`; // Red for deletions + break; + case DiffMatchPatch.DIFF_EQUAL: + term_diff += text; // No color for equal parts + break; + } + }); + + return { + distance, + term_diff, + }; +} + +const LicenseChecker = ({ + comment_parser, + desired_header, +}) => { + const supports = ({ filename }) => { + return comment_parser.supports({ filename }); + }; + const compare = async ({ filename, source }) => { + const headers = await comment_parser.extract_top_comments( + { filename, source }); + const headers_lines = headers.map(h => h.lines); + + if ( headers.length < 1 ) { + return { + has_header: false, + }; + } + + // console.log('headers', headers); + + let top = 0; + let bottom = 0; + let current_distance = Number.MAX_SAFE_INTEGER; + + // "wah" + for ( let i=1 ; i <= headers.length ; i++ ) { + const combined = headers_lines.slice(top, i).flat(); + const combined_txt = combined.join('\n'); + const { distance } = + CompareFn({ + header1: desired_header, + header2: combined_txt, + distance_only: true, + }); + if ( distance < current_distance ) { + current_distance = distance; + bottom = i; + } else { + break; + } + } + // "woop" + for ( let i=1 ; i < headers.length ; i++ ) { + const combined = headers_lines.slice(i, bottom).flat(); + const combined_txt = combined.join('\n'); + const { distance } = + CompareFn({ + header1: desired_header, + header2: combined_txt, + distance_only: true, + }); + if ( distance < current_distance ) { + current_distance = distance; + top = i; + } else { + break; + } + } + + const combined = headers_lines.slice(top, bottom).flat(); + const combined_txt = combined.join('\n'); + + const diff_info = CompareFn({ + header1: desired_header, + header2: combined_txt, + }) + + diff_info.range = [ + headers[top].range[0], + headers[bottom-1].range[1], + ]; + + diff_info.has_header = true; + + return diff_info; + }; + return { + compare, + supports, + }; +}; + +const license_check_test = async ({ options }) => { + const comment_parser = CommentParser(); + const license_checker = LicenseChecker({ + comment_parser, + desired_header: fs.readFileSync( + path_.join(__dirname, '../../doc/license_header.txt'), + 'utf-8', + ), + }); + + const walk_iterator = walk({ + excludes: EXCLUDE_LISTS.NOT_SOURCE, + }, path_.join(__dirname, '../..')); + for await ( const value of walk_iterator ) { + if ( value.is_dir ) continue; + if ( value.name !== 'dev-console-ui-utils.js' ) continue; + console.log(value.path); + const source = fs.readFileSync(value.path, 'utf-8'); + const diff_info = await license_checker.compare({ + filename: value.name, + source, + }) + if ( diff_info ) { + process.stdout.write('\x1B[36;1m=======\x1B[0m\n'); + process.stdout.write(diff_info.term_diff); + process.stdout.write('\n\x1B[36;1m=======\x1B[0m\n'); + // console.log('headers', headers); + } else { + console.log('NO COMMENT'); + } + + console.log('RANGE', diff_info.range) + + const new_comment = comment_parser.output_comment({ + filename: value.name, + style: 'block', + text: 'some text\nto display' + }); + + console.log('NEW COMMENT?', new_comment); + } +}; + +const cmd_check_fn = async () => { + const comment_parser = CommentParser(); + const license_checker = LicenseChecker({ + comment_parser, + desired_header: fs.readFileSync( + path_.join(__dirname, '../../doc/license_header.txt'), + 'utf-8', + ), + }); + + const counts = { + ok: 0, + missing: 0, + conflict: 0, + error: 0, + unsupported: 0, + }; + + const walk_iterator = walk({ + excludes: EXCLUDE_LISTS.NOT_SOURCE, + }, path_.join(__dirname, '../..')); + for await ( const value of walk_iterator ) { + if ( value.is_dir ) continue; + + process.stdout.write(value.path + ' ... '); + + if ( ! license_checker.supports({ filename: value.name }) ) { + process.stdout.write(`\x1B[37;1mUNSUPPORTED\x1B[0m\n`); + counts.unsupported++; + continue; + } + + const source = fs.readFileSync(value.path, 'utf-8'); + const diff_info = await license_checker.compare({ + filename: value.name, + source, + }) + if ( ! diff_info ) { + counts.error++; + continue; + } + if ( ! diff_info.has_header ) { + counts.missing++; + process.stdout.write(`\x1B[33;1mMISSING\x1B[0m\n`); + continue; + } + if ( diff_info ) { + if ( diff_info.distance !== 0 ) { + counts.conflict++; + process.stdout.write(`\x1B[31;1mCONFLICT\x1B[0m\n`); + } else { + counts.ok++; + process.stdout.write(`\x1B[32;1mOK\x1B[0m\n`); + } + } else { + console.log('NO COMMENT'); + } + } + + const { Table } = require('console-table-printer'); + const t = new Table({ + columns: [ + { + title: 'License Header', + name: 'situation', alignment: 'left', color: 'white_bold' }, + { + title: 'Number of Files', + name: 'count', alignment: 'right' }, + ], + colorMap: { + green: '\x1B[32;1m', + yellow: '\x1B[33;1m', + red: '\x1B[31;1m', + } + }); + + console.log(''); + + if ( counts.error > 0 ) { + console.log(`\x1B[31;1mTHERE WERE SOME ERRORS!\x1B[0m`); + console.log('check the log above for the stack trace'); + console.log(''); + t.addRow({ situation: 'error', count: counts.error }, + { color: 'red' }); + } + + console.log(dedent(` + \x1B[31;1mAny text below is mostly lies!\x1B[0m + This tool is still being developed and most of what's + described is "the plan" rather than a thing that will + actually happen. + \x1B[31;1m^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\x1B[0m + `)); + + if ( counts.conflict ) { + console.log(dedent(` + \x1B[37;1mIt looks like you have some conflicts!\x1B[0m + Run the following command to update license headers: + + \x1B[36;1maddlicense sync\x1B[0m + + This will begin an interactive license update. + Any time the license doesn't quite match you will + be given the option to replace it or skip the file. + \x1B[90mSee \`addlicense help sync\` for other options.\x1B[0m + + You will also be able to choose + "remember for headers matching this one" + if you know the same issue will come up later. + `)); + } else if ( counts.missing ) { + console.log(dedent(` + \x1B[37;1mSome missing license headers!\x1B[0m + Run the following command to add the missing license headers: + + \x1B[36;1maddlicense sync\x1B[0m + `)); + } else { + console.log(dedent(` + \x1B[37;1mNo action to perform!\x1B[0m + Run the following command to do absolutely nothing: + + \x1B[36;1maddlicense sync\x1B[0m + `)); + } + + console.log(''); + + t.addRow({ situation: 'ok', count: counts.ok }, + { color: 'green' }); + t.addRow({ situation: 'missing', count: counts.missing }, + { color: 'yellow' }); + t.addRow({ situation: 'conflict', count: counts.conflict }, + { color: 'red' }); + t.addRow({ situation: 'unsupported', count: counts.unsupported }); + t.printTable(); +}; + +const main = async () => { + const { program } = require('commander'); + const helptext = dedent(` + Usage: usage text + `); + + const run_command = async ({ cmd, cmd_fn }) => { + const options = { + program: program.opts(), + command: cmd.opts(), + }; + console.log('options', options); + + if ( ! fs.existsSync(options.program.config) ) { + // TODO: configuration wizard + fs.writeFileSync(options.program.config, ''); + } + + await cmd_fn({ options }); + }; + + program + .name('addlicense') + .option('-c, --config', 'configuration file', 'addlicense.yml') + .addHelpText('before', helptext) + ; + const cmd_check = program.command('check') + .description('check license headers') + .option('-n, --non-interactive', 'disable prompting') + .action(() => { + run_command({ cmd: cmd_check, cmd_fn: cmd_check_fn }); + }) + const cmd_sync = program.command('sync') + .description('synchronize files with license header rules') + .option('-n, --non-interactive', 'disable prompting') + .action(() => { + console.log('called sync'); + console.log(program.opts()); + console.log(cmd_sync.opts()); + }) + program.parse(process.argv); + +}; + +if ( require.main === module ) { + main(); +} \ No newline at end of file diff --git a/tools/license-headers/package.json b/tools/license-headers/package.json new file mode 100644 index 0000000000..05ced1f180 --- /dev/null +++ b/tools/license-headers/package.json @@ -0,0 +1,19 @@ +{ + "name": "license-headers", + "version": "1.0.0", + "main": "main.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "AGPL-3.0-only", + "description": "", + "dependencies": { + "console-table-printer": "^2.12.1", + "dedent": "^1.5.3", + "diff-match-patch": "^1.0.5", + "js-levenshtein": "^1.1.6", + "yaml": "^2.4.5" + } +} From 473b6512c697854e3f3badae1eb7b87742954da5 Mon Sep 17 00:00:00 2001 From: Slendi Date: Wed, 10 Jul 2024 11:37:06 +0300 Subject: [PATCH 0500/2119] Add 2FA Romanian translations Signed-off-by: Slendi --- src/gui/src/i18n/translations/ro.js | 31 ++++++++++++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/ro.js b/src/gui/src/i18n/translations/ro.js index 7cd7c9361a..4fc681dc60 100644 --- a/src/gui/src/i18n/translations/ro.js +++ b/src/gui/src/i18n/translations/ro.js @@ -161,7 +161,36 @@ const ro = { yes_release_it: 'Da, eliberează-l', you_have_been_referred_to_puter_by_a_friend: "Ai fost invitat pe Puter de către un prieten!", zip: "Zip", + + // === 2FA Setup === + setup2fa_1_step_heading: 'Deschideți aplicația dvs. de autentificare', + setup2fa_1_instructions: ` + Puteți folosi orice aplicație de autentificare care suportă protocolul TOTP. + Sunt multe valabile, dar daca nu sunteți sigur(ă), + Authy + este o alegere solidă pentru Android și iOS. + `, + setup2fa_2_step_heading: 'Scanați codul QR', + setup2fa_3_step_heading: 'Introduceți codul de 6 cifre', + setup2fa_4_step_heading: 'Copiați codurile de recuperare', + setup2fa_4_instructions: ` + Aceste coduri de recuperare sunt singura metoră de acces al contului dvs. dacă vă pierdeți telefonul sau nu mai puteți folosi aplicația de autentificare. + Fiți sigur(ă) să le păstrați într-un loc sigur. + `, + setup2fa_5_step_heading: 'Confirmați configurarea 2FA', + setup2fa_5_confirmation_1: 'Mi-am salvat codurile de recuperare într-o locație sigură.', + setup2fa_5_confirmation_2: 'Sunt pregătit(ă) să activez 2FA', + setup2fa_5_button: 'Activare 2FA', + + // === 2FA Login === + login2fa_otp_title: 'Introduceți codul 2FA', + login2fa_otp_instructions: 'Introduceți codul de 6 cifre din aplicația dvs. de autentificare.', + login2fa_recovery_title: 'Introduceți codul de recuperare', + login2fa_recovery_instructions: 'Introduceți una din codurile de recuperare ale dvs. pentru a vă acesa contul.', + login2fa_use_recovery_code: 'Utilizați un cod de recuperare', + login2fa_recovery_back: 'Înapoi', + login2fa_recovery_placeholder: 'XXXXXXXX', } } -export default ro; \ No newline at end of file +export default ro; From 8440f566b91c9eb4f01addcb850061e3fbe3afc7 Mon Sep 17 00:00:00 2001 From: Sergiu Bondor Date: Wed, 10 Jul 2024 19:49:45 +0300 Subject: [PATCH 0501/2119] Added missing Romanian translations. --- src/gui/src/i18n/translations/ro.js | 243 ++++++++++++++++++++++------ 1 file changed, 198 insertions(+), 45 deletions(-) diff --git a/src/gui/src/i18n/translations/ro.js b/src/gui/src/i18n/translations/ro.js index 4fc681dc60..e6ef5553a7 100644 --- a/src/gui/src/i18n/translations/ro.js +++ b/src/gui/src/i18n/translations/ro.js @@ -22,66 +22,151 @@ const ro = { english_name: "Romanian", code: "ro", dictionary: { + about: "Despre Puter", + account: "Cont", + account_password: "Verifică parola contului", access_granted_to: "Acces acordat pentru", add_existing_account: "Adaugă cont existent", all_fields_required: 'Toate câmpurile sunt necesare.', + allow: "Permite", apply: "Aplică", ascending: 'Ascendent', + associated_websites: "Site-uri partenere", + auto_arrange: "Aranjare automată", background: "Background", browse: "Caută", cancel: 'Anulează', - center: 'Center', + center: 'Centru', change_desktop_background: 'Schimbă imaginea de fundal…', + change_email: "Schimbă e-mailul", + change_language: "Schimbă Limba", change_password: "Schimbă Parola", - change_username: "Schimbă Numele", - close_all_windows: "Inchide toate ferestrele", + change_ui_colors: "Schimbă Culorile Interfeței", + change_username: "Schimbă User-ul", + close: "Închide", + close_all_windows: "Închide toate ferestrele", + close_all_windows_confirm: "Sunteți sigur(ă) că doriți să închideți toate ferestrele?", + close_all_windows_and_log_out: "Închide toate ferestrele și delogheză-mă", + change_always_open_with: "Doriți să deschideți acest tip de fișiere cu ", color: 'Culoare', - confirm_account_for_free_referral_storage_c2a: 'Creați un cont și confirmați adresa de e-mail pentru a primi 1 GB de spațiu de stocare gratuit. Și prietenul tău va primi 1 GB de spațiu de stocare gratuit.', + confirm: "Confirmă", + confirm_2fa_setup: "Am adăgat codul la aplicația de autentificare", + confirm_2fa_recovery: "Am salvat codurile de recuperare într-o locație sigură", + + confirm_account_for_free_referral_storage_c2a: 'Creați un cont și confirmați adresa de e-mail pentru a primi 1 GB de spațiu de stocare gratuit. Deasemenea, un prieten de-al tău va primi 1 GB de spațiu de stocare gratuit.', + confirm_code_generic_incorrect: "Cod incorect", + confirm_code_generic_too_many_requests: "Prea multe solicitări. Vă rugăm așteptați câteva minute.", + confirm_code_generic_submit: "Trimite cod", + confirm_code_generic_try_again: "Încercați din nou", + confirm_code_generic_title: "Introduceți codul de confirmare", + confirm_code_2fa_instruction: "Introduceți codul de 6 cifre generat de aplicația de autentificare", + confirm_code_2fa_submit_btn: "Trimite", + confirm_code_2fa_title: "Introduceți codul 2FA", + confirm_delete_multiple_items: "Sunteți sigur(ă) că doriți să ștergeți aceste obiecte permanent", + confirm_delete_single_item: "Doriți să ștergeți acest obiect permanent?", + confirm_open_apps_log_out: "Aveți aplicații care rulează. Sunteți sigur(ă) că doriți să vă delogați?", confirm_new_password: "Confirmă Parola Nouă", + confirm_delete_user: "Sunteți sigur(ă) că doriți să ștergeți acest cont? Toate fișierele dumneavoastră și toate datele vor fi șterse permanent. Această operație nu poate fi anulată.", + confirm_delete_user_title: "Ștergeți contul?", + confirm_session_revoke: "Sunteți sigur(ă) că doriți să revocați sesiunea curentă?", + confirm_your_email_address: "Confirmați adresa dumneavoastră de e-mail", contact_us: "Contactează-ne", - contain: 'Contain', + contact_us_verification_required: "Aveți nevoie de o adresă de e-mail confirmată.", + contain: 'Conțină', continue: "Continuă", copy: 'Copiază', copy_link: "Copiază link", copying: "Se copiază", - cover: 'Cover', + copying_file: "Se copiază %%", + cover: 'Copertă', create_account: "Crează un cont", create_free_account: "Crează un cont gratuit", - create_shortcut: "Crează o scurtătură", + create_shortcut: "Crează o comandă rapidă", + credits: "Credite", current_password: "Parola Curentă", - cut: 'Taie', - date_modified: 'Dată modificată', + cut: 'Decupează', + clock: "Ora", + clock_visible_hide: "Ascunde - Întotdeauna ascuns", + clock_visible_show: "Afișează - Întotdeauna vizibil", + clock_visible_auto: "Automat - Mod implicit, vizibil doar în modul ecran complet.", + close_all: "Închide toate", + created: "Creat", + date_modified: 'Dată modificare', + default: "Implicit", delete: 'Șterge', + delete_account: "Șterge cont", delete_permanently: "Șterge Permanent", - deploy_as_app: 'Implementează ca aplicație', - descending: 'Descending', + deleting_file: "Se șterge %%", + deploy_as_app: 'Publică ca aplicație', + descending: 'Coborând', + desktop: 'Desktop', desktop_background_fit: "Potrivește fundalul", + developers: "Programatori", dir_published_as_website: `%strong% a fost publicat către:`, + disable_2fa: "Dezactivați 2FA", + disable_2fa_confirm: "Sunteți sigur(ă) că doriți să dezactivați 2FA?", + disable_2fa_instructions: "Introduceți parola dumneavoastră pentru a dezactiva 2FA.", disassociate_dir: "Dezasociaza folderul", + documents: "Documente", + dont_allow: "Nu permiteți", download: 'Descarcă', + download_file: "Descarcă fișier", downloading: "Se descarcă", - email: "Mail", - email_or_username: "Mail sau Nume de Utilizator", + email: "E-mail", + email_change_confirmation_sent: "Un e-mail de confirmare a fost trimis către noua dumneavoastră adresă de e-mail. Vă rugăm să verificați ©ăsuța și să urmați intrucțiunile pentru a finaliza procesul.", + email_invalid: "E-mailul este invalid.", + email_or_username: "E-mail sau Nume de Utilizator", + email_required: "E-mailul este necesar.", empty_trash: 'Golește Coșul de gunoi', empty_trash_confirmation: `Ești sigur că vrei să ștergi permanent conținutul Coșului de gunoi?`, emptying_trash: 'Coșul de gunoi se golește…', - feedback: "Feedback", + enable_2fa: "Activați 2FA", + end_hard: "Terminați brutal", + end_process_force_confirm: "Sunteți sigur(ă) că doriți să forțați terminarea acestui proces", + end_soft: "Terminați Aplicația", + enlarged_qr_code: "Măriți Codul QR", + enter_password_to_confirm_delete_user: "Introduceți parola pentru a confirma începerea ștergerii contului", + error_message_is_missing: "Mesajul de eroare lipsește.", + error_unknown_cause: "A apărut o erorare necunoscută.", + error_uploading_files: "Încărcarea fișierelor a eșuat", + favorites: "Preferate", + feedback: "Evaluare", feedback_c2a: "Vă rugăm să folosiți formularul de mai jos pentru a ne trimite feedback, comentarii și rapoarte de erori.", feedback_sent_confirmation: "Mulțumim că ne-ți contactat. Dacă aveți un e-mail asociat contului dvs, veți primi un răspuns de la noi cât mai curând posibil.", - forgot_pass_c2a: "Ai uitat parola?", + fit: "Potrivit", + folder: "Folder", + force_quit: "Forțează ieșirea", + forgot_pass_c2a: "Ați uitat parola?", from: "De la", general: "General", get_a_copy_of_on_puter: `Obțineți o copie a '%%' pe Puter.com!`, get_copy_link: 'Obțineți link-ul copiei', hide_all_windows: "Ascunde toate ferestrele", + home: "Acasă", html_document: 'Document HTML', + hue: "Hue", image: 'Imagine', + incorrect_password: "Parolă incorectă", invite_link: "Link de invitație", - items_in_trash_cannot_be_renamed: `Acest articol nu poate fi redenumit deoarece este în coșul de gunoi. Pentru a redenumi acest element, mai întâi scoateți-l din Coșul de gunoi.`, + item: "Obiect", + items_in_trash_cannot_be_renamed: `Acest obiect nu poate fi redenumit deoarece este în coșul de gunoi. Pentru a redenumi acest obiect, mai întâi scoateți-l din Coșul de gunoi.`, jpeg_image: 'Imagine JPEG', keep_in_taskbar: 'Păstrează în bara de activități', + language: "Limbă", + license: "Licență", + lightness: "Luminozitate", + link_copied: "Link copiat", + loading: "Încarcă", log_in: "Loghează-te", + log_into_another_account_anyway: "Logați-vă oricum într-un alt cont", log_out: 'Deconectează-te', + looks_good: "Arată bine!", + manage_sessions: "Administrează sesiuni", + menubar_style: "Stil bară de meniu", + menubar_style_desktop: "Desktop", + menubar_style_system: "Sistem", + menubar_style_window: "Fereastră", + modified: "Modificat", move: 'Mută', moving_file: "Se mută %%", my_websites: "Site-urile mele", @@ -93,9 +178,11 @@ const ro = { name_must_be_string: "Numele poate fi doar un șir.", name_too_long: `Numele nu poate fi mai lung de %% caractere.`, new: 'Nou', + new_email: "E-mail nou", new_folder: 'Folder nou', new_password: "Parolă nouă", new_username: "Nume de Utilizator nou", + no: "Nu", no_dir_associated_with_site: 'Niciun director asociat cu această adresă.', no_websites_published: "Nu ați publicat încă niciun site web.", ok: 'OK', @@ -103,20 +190,45 @@ const ro = { open_in_new_tab: "Deschide in alt tab", open_in_new_window: "Deschide in fereastră nouă", open_with: "Deschide cu", + original_name: "Numele original", + original_path: "Calea originală", + oss_code_and_content: "Software și conținut Open Source", password: "Parolă", password_changed: "Parolă schimbată.", + password_recovery_rate_limit: "Ați ajuns la frecvența limită; vă rugăm așteptați câteva minute. Pentru a nu se mai repeta pe viitor, evitați să reîncărcați pagina de prea multe ori.", + password_recovery_token_invalid: "Acest cod de recuperare nu mai este valabil.", + password_recovery_unknown_error: "A apărut o eroare necunoscută. Vă rugăm încercați din nou mai târziu.", + password_required: "Parola este necesară", + password_strength_error: "Parola trebuie să aibe cel puțin 8 caractere și să conțină cel puțin o literă mare, o litera mică, o cifră și un caracter special.", passwords_do_not_match: '`Parola nouă` și `Confirmă Parola nouă` nu sunt la fel.', paste: 'Inserează', paste_into_folder: "Inserează in folder", + path: "Cale", + personalization: "Personalizare", pick_name_for_website: "Alegeți un nume pentru site-ul dvs:", - picture: "Poza", + picture: "Imagine", + pictures: "Imagini", + plural_suffix: "e", powered_by_puter_js: `Creat de {{link=docs}}Puter.js{{/link}}`, preparing: "Preparare...", preparing_for_upload: "Preparare pentru încărcare...", + print: "Tipărește", + privacy: "Confidențialitate", + proceed_to_login: "Mergeți mai departe pentru logare", + proceed_with_account_deletion: "Mergeți mai departe cu ștergerea contului", + process_status_initializing: "Se inițializează", + process_status_running: "Procesează", + process_type_app: "App", + process_type_init: "Inițializare", + process_type_ui: "Interfață grafică", properties: "Proprietăți", + public: "Public", publish: "Publică", publish_as_website: 'Publică, ca site web', + puter_description: "Puter este un cloud personal care pune pe primul loc confidențialitatea pentru păstrarea tuturor fișierelor dumneavoastră, a app-urilor, a jocurilor într-un loc sigur și accesibil de oriunde oricând.", + reading_file: "Citind %strong%", recent: "Recente", + recommended: "Recomandat", recover_password: "Recuperare Parolă", refer_friends_c2a: "Obțineți 1 GB pentru fiecare prieten care creează și confirmă un cont pe Puter. și prietenul tău va primi 1 GB!", refer_friends_social_media_c2a: `Obțineți 1 GB de spațiu de stocare gratuit pe Puter.com!`, @@ -125,71 +237,112 @@ const ro = { remove_from_taskbar:'Eliminați din bara de activități', rename: 'Redenumește', repeat: 'Repetă', + replace: "Înlocuiește", + replace_all: "Înlocuiește toate", resend_confirmation_code: "Re-trimite cod de confirmare", + reset_colors: "Resetează culori", + restart_puter_confirm: "Sunteți sigur(ă) că doriți să reporniți Puter?", restore: "Restaurare", + save: "Salvare", + saturation: "Saturație", + save_account: "Salvați contul", save_account_to_get_copy_link: "Vă rugăm să creați un cont pentru a copia un link.", save_account_to_publish: 'Vă rugăm să creați un cont pentru a publica.', + save_session: "Salvați sesiunea", save_session_c2a: 'Creați un cont pentru a vă salva sesiunea curentă și pentru a evita pierderea muncii.', scan_qr_c2a: 'Scanați codul de mai jos pentru a vă conecta la această sesiune de pe alte dispozitive', + scan_qr_2fa: "Scanati codul QR cu aplicația de autentificare", + scan_qr_generic: "Scanați acest cod QR folsindu-vă telefonul personal sau un alt dispozitiv", + search: "Caută", + seconds: "Secunde", + security: "Securitate", select: "Selectează", + selected: "Selectat", select_color: 'Selectează culoare…', + sessions: "Sesiuni", send: "Trimite", send_password_recovery_email: "Trimite mail de recuperare parolă", session_saved: "Vă mulțumim pentru crearea unui cont. Această sesiune a fost salvată.", + settings: "Setări", set_new_password: "Setează o parolă Nouă", + share: "Distribuie", share_to: "Distribuie către", + share_with: "Distribuie cu", + shortcut_to: "Comandă rapidă ©ătre", show_all_windows: "Afișați toate ferestrele", show_hidden: 'Arată ascuns', sign_in_with_puter: "Conectați-vă cu Puter", sign_up: "Inscrie-te", signing_in: "Se conectează…", size: 'Mărime', + skip: "Ignoră", + something_went_wrong: "Ceva nu a funcționat.", sort_by: 'Sortează dupa', start: 'Start', + status: "Stare", + storage_usage: "Utilizare spațiu", + storage_puter_used: "folosit de Puter", taking_longer_than_usual: 'Durează puțin mai mult decât de obicei. Vă rugăm așteptați...', + task_manager: "Administrator aplicații", + taskmgr_header_name: "Nume", + taskmgr_header_status: "Stare", + taskmgr_header_type: "Tip", + terms: "Termeni", text_document: 'Document Text', tos_fineprint: `Făcând clic pe „Creați un cont gratuit”, sunteți de acord cu {{link=terms}}Termenii si conditiile{{/link}} si {{link=privacy}}Politia de Confidentialitate Puter.com{{/link}}.`, + transparency: "Transparență", trash: 'Coș de gunoi', + two_factor: "Autentificare Two Factor", + two_factor_disabled: "2FA Dezactivat", + two_factor_enabled: "2FA Activat", type: 'Type', + type_confirm_to_delete_account: "Tastați 'confirm' pentru a șterge contul dumneavoastră.", + ui_colors: "Culori Interfața", + ui_manage_sessions: "Administrator Sesiuni", + ui_revoke: "Revocă", undo: 'Undo', + unlimited: "Nelimitat", unzip: "Unzip", upload: 'Incarcă', upload_here: 'Incarcă aici', + usage: "Grad de utilizare", username: "Nume de Utilizator", username_changed: 'Nume de Utilizator actualizat cu succes.', + username_required: "Utilizatorul este necesar", versions: "Versiuni", - yes_release_it: 'Da, eliberează-l', + videos: "Video-uri", + visibility: "Vizibilitate", + yes: "Da", + yes_release_it: 'Da, publică', you_have_been_referred_to_puter_by_a_friend: "Ai fost invitat pe Puter de către un prieten!", zip: "Zip", - - // === 2FA Setup === - setup2fa_1_step_heading: 'Deschideți aplicația dvs. de autentificare', + zipping_file: 'Se arhivează %strong%', + + setup2fa_1_step_heading: "Deschideți aplicația de autentificare", setup2fa_1_instructions: ` - Puteți folosi orice aplicație de autentificare care suportă protocolul TOTP. - Sunt multe valabile, dar daca nu sunteți sigur(ă), - Authy - este o alegere solidă pentru Android și iOS. - `, - setup2fa_2_step_heading: 'Scanați codul QR', - setup2fa_3_step_heading: 'Introduceți codul de 6 cifre', - setup2fa_4_step_heading: 'Copiați codurile de recuperare', + Puteți folosi orice aplicație de autentificare care folosește protocolul Time-based One-Time Password (TOTP). + Sunt multe astfel de aplicații, dar dacă sunteți nesiguri + Authy + este o opțiune serioasă pentru Android si iOS. + `, + setup2fa_2_step_heading: "Scanați codul QR", + setup2fa_3_step_heading: "Introduceți codul de 6 cifre", + setup2fa_4_step_heading: "Copiați codurile dumneavoastră de restaurare", setup2fa_4_instructions: ` - Aceste coduri de recuperare sunt singura metoră de acces al contului dvs. dacă vă pierdeți telefonul sau nu mai puteți folosi aplicația de autentificare. - Fiți sigur(ă) să le păstrați într-un loc sigur. - `, - setup2fa_5_step_heading: 'Confirmați configurarea 2FA', - setup2fa_5_confirmation_1: 'Mi-am salvat codurile de recuperare într-o locație sigură.', - setup2fa_5_confirmation_2: 'Sunt pregătit(ă) să activez 2FA', - setup2fa_5_button: 'Activare 2FA', - - // === 2FA Login === - login2fa_otp_title: 'Introduceți codul 2FA', - login2fa_otp_instructions: 'Introduceți codul de 6 cifre din aplicația dvs. de autentificare.', - login2fa_recovery_title: 'Introduceți codul de recuperare', - login2fa_recovery_instructions: 'Introduceți una din codurile de recuperare ale dvs. pentru a vă acesa contul.', - login2fa_use_recovery_code: 'Utilizați un cod de recuperare', - login2fa_recovery_back: 'Înapoi', - login2fa_recovery_placeholder: 'XXXXXXXX', + Aceste coduri de restaurare sunt singurul mod în care vă puteți accesa contul dacă vă pierdeți telefonul sau nu puteți folosi aplicația de autentificare. + Asigurați-vă că le scrie-ți într-un loc sigur.`, + setup2fa_5_step_heading: "Confirmați configurația 2FA", + setup2fa_5_confirmation_1: "Mi-am salvat codurile de restaurare într-un loc sigur", + setup2fa_5_confirmation_2: "Sunt gata să activez 2FA", + setup2fa_5_button: "Activează 2FA", + + login2fa_otp_title: "Introduceți codul 2FA", + login2fa_otp_instructions: "Introduceți codul de 6 cifre din aplicația de autentificare.", + login2fa_recovery_title: "Introduceți un cod de restaurare", + login2fa_recovery_instructions: "Introduceți unul dintre codurile de restaurare pentru a vă accesa contul.", + login2fa_use_recovery_code: "Folosiți un cod de restaurare", + login2fa_recovery_back: "Înapoi", + login2fa_recovery_placeholder: "XXXXXXXX", } } From fac08c41520efa068822ddbca1c2a5a74545e765 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 10 Jul 2024 13:52:20 -0400 Subject: [PATCH 0502/2119] doc: remove extra log in doc snippet --- src/backend/doc/contributors/modules.md | 1 - 1 file changed, 1 deletion(-) diff --git a/src/backend/doc/contributors/modules.md b/src/backend/doc/contributors/modules.md index 5d00e4aa7a..188c7031f2 100644 --- a/src/backend/doc/contributors/modules.md +++ b/src/backend/doc/contributors/modules.md @@ -18,7 +18,6 @@ const { SelfHostedModule } = (await import('@heyputer/backend')).default; -console.log('kerne', Kernel); const k = new Kernel(); k.add_module(new CoreModule()); k.add_module(new DatabaseModule()); From 713b1f5889c2e4055e054f4815b74f934451e520 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 10 Jul 2024 14:01:28 -0400 Subject: [PATCH 0503/2119] dev(tools): add missing header adding to license-headers --- tools/comment-parser/main.js | 2 +- tools/file-walker/test.js | 4 +- tools/license-headers/main.js | 170 +++++++++++++++++++++++++++++++++- 3 files changed, 171 insertions(+), 5 deletions(-) diff --git a/tools/comment-parser/main.js b/tools/comment-parser/main.js index 0441291578..a6ddb8e752 100644 --- a/tools/comment-parser/main.js +++ b/tools/comment-parser/main.js @@ -235,7 +235,7 @@ const CommentParser = () => { }], block: ['block', { start: '/*', - end: '*/', + end: ' */', prefix: ' * ', }] }, diff --git a/tools/file-walker/test.js b/tools/file-walker/test.js index 603dd4bb75..eec352f963 100644 --- a/tools/file-walker/test.js +++ b/tools/file-walker/test.js @@ -28,8 +28,10 @@ const EXCLUDE_LISTS = { /\/node_modules$/, /^node_modules$/, /package-lock\.json/, + /^src\/dev-center\/js/, /src\/backend\/src\/public\/assets/, - /^src\/gui\/src\/lib/ + /^src\/gui\/src\/lib/, + /^src\/puter\.js/, ] }; diff --git a/tools/license-headers/main.js b/tools/license-headers/main.js index 8c4a6bbe06..97c6414e60 100644 --- a/tools/license-headers/main.js +++ b/tools/license-headers/main.js @@ -1,3 +1,22 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ + const levenshtein = require('js-levenshtein'); const DiffMatchPatch = require('diff-match-patch'); const dmp = new DiffMatchPatch(); @@ -307,6 +326,153 @@ const cmd_check_fn = async () => { t.printTable(); }; +const cmd_sync_fn = async () => { + const comment_parser = CommentParser(); + const desired_header = fs.readFileSync( + path_.join(__dirname, '../../doc/license_header.txt'), + 'utf-8', + ); + const license_checker = LicenseChecker({ + comment_parser, + desired_header, + }); + + const counts = { + ok: 0, + missing: 0, + conflict: 0, + error: 0, + unsupported: 0, + }; + + const walk_iterator = walk({ + excludes: EXCLUDE_LISTS.NOT_SOURCE, + }, '.'); + for await ( const value of walk_iterator ) { + if ( value.is_dir ) continue; + + process.stdout.write(value.path + ' ... '); + + if ( ! license_checker.supports({ filename: value.name }) ) { + process.stdout.write(`\x1B[37;1mUNSUPPORTED\x1B[0m\n`); + counts.unsupported++; + continue; + } + + const source = fs.readFileSync(value.path, 'utf-8'); + const diff_info = await license_checker.compare({ + filename: value.name, + source, + }) + if ( ! diff_info ) { + counts.error++; + continue; + } + if ( ! diff_info.has_header ) { + if ( false ) fs.writeFileSync( + value.path, + comment_parser.output_comment({ + style: 'block', + filename: value.name, + text: desired_header, + }) + + '\n' + + source + ); + continue; + } + if ( diff_info ) { + if ( diff_info.distance !== 0 ) { + counts.conflict++; + process.stdout.write(`\x1B[31;1mCONFLICT\x1B[0m\n`); + } else { + counts.ok++; + process.stdout.write(`\x1B[32;1mOK\x1B[0m\n`); + } + } else { + console.log('NO COMMENT'); + } + } + + const { Table } = require('console-table-printer'); + const t = new Table({ + columns: [ + { + title: 'License Header', + name: 'situation', alignment: 'left', color: 'white_bold' }, + { + title: 'Number of Files', + name: 'count', alignment: 'right' }, + ], + colorMap: { + green: '\x1B[32;1m', + yellow: '\x1B[33;1m', + red: '\x1B[31;1m', + } + }); + + console.log(''); + + if ( counts.error > 0 ) { + console.log(`\x1B[31;1mTHERE WERE SOME ERRORS!\x1B[0m`); + console.log('check the log above for the stack trace'); + console.log(''); + t.addRow({ situation: 'error', count: counts.error }, + { color: 'red' }); + } + + console.log(dedent(` + \x1B[31;1mAny text below is mostly lies!\x1B[0m + This tool is still being developed and most of what's + described is "the plan" rather than a thing that will + actually happen. + \x1B[31;1m^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\x1B[0m + `)); + + if ( counts.conflict ) { + console.log(dedent(` + \x1B[37;1mIt looks like you have some conflicts!\x1B[0m + Run the following command to update license headers: + + \x1B[36;1maddlicense sync\x1B[0m + + This will begin an interactive license update. + Any time the license doesn't quite match you will + be given the option to replace it or skip the file. + \x1B[90mSee \`addlicense help sync\` for other options.\x1B[0m + + You will also be able to choose + "remember for headers matching this one" + if you know the same issue will come up later. + `)); + } else if ( counts.missing ) { + console.log(dedent(` + \x1B[37;1mSome missing license headers!\x1B[0m + Run the following command to add the missing license headers: + + \x1B[36;1maddlicense sync\x1B[0m + `)); + } else { + console.log(dedent(` + \x1B[37;1mNo action to perform!\x1B[0m + Run the following command to do absolutely nothing: + + \x1B[36;1maddlicense sync\x1B[0m + `)); + } + + console.log(''); + + t.addRow({ situation: 'ok', count: counts.ok }, + { color: 'green' }); + t.addRow({ situation: 'missing', count: counts.missing }, + { color: 'yellow' }); + t.addRow({ situation: 'conflict', count: counts.conflict }, + { color: 'red' }); + t.addRow({ situation: 'unsupported', count: counts.unsupported }); + t.printTable(); +}; + const main = async () => { const { program } = require('commander'); const helptext = dedent(` @@ -343,9 +509,7 @@ const main = async () => { .description('synchronize files with license header rules') .option('-n, --non-interactive', 'disable prompting') .action(() => { - console.log('called sync'); - console.log(program.opts()); - console.log(cmd_sync.opts()); + run_command({ cmd: cmd_sync, cmd_fn: cmd_sync_fn }) }) program.parse(process.argv); From 2378f1a833f40a40d5ed31693d372da76552ca28 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 10 Jul 2024 11:30:15 -0700 Subject: [PATCH 0504/2119] Delete `.vscode` directory --- .vscode/settings.json | 7 ------- 1 file changed, 7 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index 58f080f42e..0000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,7 +0,0 @@ -{ - "cSpell.words": [ - "dnsmasq", - "heyputer", - "Puter" - ] -} From e96bba850f89d3b3fcf663c09483520426ad9cbe Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 10 Jul 2024 11:38:03 -0700 Subject: [PATCH 0505/2119] move `#DoesItRunPuter` from `README.md` to `./awesome` --- README.md | 16 ---------------- awesome/doesitrunputer.md | 14 ++++++++++++++ 2 files changed, 14 insertions(+), 16 deletions(-) create mode 100644 awesome/doesitrunputer.md diff --git a/README.md b/README.md index 5538eb74e2..d73d7a57eb 100644 --- a/README.md +++ b/README.md @@ -92,22 +92,6 @@ We are always happy to help you with any questions you may have. Don't hesitate
-## #DoesItRunPuter - -- [Minecraft](https://twitter.com/HeyPuter/status/1771957571496092036) | [video](https://www.youtube.com/watch?v=GIowZUXkg5g) -- [Samsung Watch](https://twitter.com/CharmunkDev/status/1781501714543030554) -- [PlayStation 4](https://twitter.com/HeyPuter/status/1767978053014270059) -- [Skyworth TV](https://twitter.com/ericalexdube/status/1767983049277411564) -- [A Fridge!](https://twitter.com/HeyPuter/status/1778890003797745842) -- [Oculus Quest 2](https://twitter.com/HeyPuter/status/1768664081756754012) -- [Tesla Model 3](https://twitter.com/EricLighthall/status/1781479732997214501) -- [Tesla Model S](https://twitter.com/HeyPuter/status/1767971178864587057) -- [Tesla Model Y](https://twitter.com/HeyPuter/status/1772858333751636310) -- [Nintendo Switch](https://twitter.com/HeyPuter/status/1780645795240538518) -- [Steam Deck](https://twitter.com/everythingSung/status/1782162352403828793) -- [Ladybird Browser](https://x.com/HeyPuter/status/1810783504503800035) - -
## License diff --git a/awesome/doesitrunputer.md b/awesome/doesitrunputer.md new file mode 100644 index 0000000000..c1fc16d5e2 --- /dev/null +++ b/awesome/doesitrunputer.md @@ -0,0 +1,14 @@ +# #DoesItRunPuter + +- [Minecraft](https://twitter.com/HeyPuter/status/1771957571496092036) | [video](https://www.youtube.com/watch?v=GIowZUXkg5g) +- [Samsung Watch](https://twitter.com/CharmunkDev/status/1781501714543030554) +- [PlayStation 4](https://twitter.com/HeyPuter/status/1767978053014270059) +- [Skyworth TV](https://twitter.com/ericalexdube/status/1767983049277411564) +- [A Fridge!](https://twitter.com/HeyPuter/status/1778890003797745842) +- [Oculus Quest 2](https://twitter.com/HeyPuter/status/1768664081756754012) +- [Tesla Model 3](https://twitter.com/EricLighthall/status/1781479732997214501) +- [Tesla Model S](https://twitter.com/HeyPuter/status/1767971178864587057) +- [Tesla Model Y](https://twitter.com/HeyPuter/status/1772858333751636310) +- [Nintendo Switch](https://twitter.com/HeyPuter/status/1780645795240538518) +- [Steam Deck](https://twitter.com/everythingSung/status/1782162352403828793) +- [Ladybird Browser](https://x.com/HeyPuter/status/1810783504503800035) \ No newline at end of file From 435e1786a3350fcf1ed9c035d0439b6949852dd3 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 10 Jul 2024 11:38:56 -0700 Subject: [PATCH 0506/2119] Rename doesitrunputer.md to DoesItRunPuter.md --- awesome/{doesitrunputer.md => DoesItRunPuter.md} | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename awesome/{doesitrunputer.md => DoesItRunPuter.md} (99%) diff --git a/awesome/doesitrunputer.md b/awesome/DoesItRunPuter.md similarity index 99% rename from awesome/doesitrunputer.md rename to awesome/DoesItRunPuter.md index c1fc16d5e2..af047ed222 100644 --- a/awesome/doesitrunputer.md +++ b/awesome/DoesItRunPuter.md @@ -11,4 +11,4 @@ - [Tesla Model Y](https://twitter.com/HeyPuter/status/1772858333751636310) - [Nintendo Switch](https://twitter.com/HeyPuter/status/1780645795240538518) - [Steam Deck](https://twitter.com/everythingSung/status/1782162352403828793) -- [Ladybird Browser](https://x.com/HeyPuter/status/1810783504503800035) \ No newline at end of file +- [Ladybird Browser](https://x.com/HeyPuter/status/1810783504503800035) From 6013466bcb8b1c0770665e4ad0281dad2fe4fce3 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 10 Jul 2024 11:52:34 -0700 Subject: [PATCH 0507/2119] Rename DoesItRunPuter.md to #DoesItRunPuter?.md --- awesome/{DoesItRunPuter.md => #DoesItRunPuter?.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename awesome/{DoesItRunPuter.md => #DoesItRunPuter?.md} (100%) diff --git a/awesome/DoesItRunPuter.md b/awesome/#DoesItRunPuter?.md similarity index 100% rename from awesome/DoesItRunPuter.md rename to awesome/#DoesItRunPuter?.md From f006c9ed2667806a6ffd7afddd80c8dddf809b9c Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 10 Jul 2024 11:53:11 -0700 Subject: [PATCH 0508/2119] Rename #DoesItRunPuter?.md to #DoesItRunPuter.md --- awesome/{#DoesItRunPuter?.md => #DoesItRunPuter.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename awesome/{#DoesItRunPuter?.md => #DoesItRunPuter.md} (100%) diff --git a/awesome/#DoesItRunPuter?.md b/awesome/#DoesItRunPuter.md similarity index 100% rename from awesome/#DoesItRunPuter?.md rename to awesome/#DoesItRunPuter.md From d0a5a57c884e111f4ff9198cd66aa8bd2f8709a5 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 10 Jul 2024 14:57:20 -0400 Subject: [PATCH 0509/2119] dev(tools): add conflict prompt to license-headers --- package-lock.json | 15 ++++++++++++++- tools/comment-parser/main.js | 8 ++++---- tools/license-headers/main.js | 21 +++++++++++++++++++++ tools/license-headers/package.json | 1 + 4 files changed, 40 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 89380bb756..fedf9fff0d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5033,7 +5033,6 @@ "version": "4.1.3", "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", - "dev": true, "license": "MIT", "engines": { "node": ">=6" @@ -6932,6 +6931,19 @@ "node": ">=10.13.0" } }, + "node_modules/enquirer": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.4.1.tgz", + "integrity": "sha512-rRqJg/6gd538VHvR3PSrdRBb/1Vy2YfzHqzvbhGIQpDRKIa4FgV/54b5Q1xYSxOOwKvjXweS26E0Q+nAMwp2pQ==", + "license": "MIT", + "dependencies": { + "ansi-colors": "^4.1.1", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -14654,6 +14666,7 @@ "console-table-printer": "^2.12.1", "dedent": "^1.5.3", "diff-match-patch": "^1.0.5", + "enquirer": "^2.4.1", "js-levenshtein": "^1.1.6", "yaml": "^2.4.5" } diff --git a/tools/comment-parser/main.js b/tools/comment-parser/main.js index a6ddb8e752..68e64245ae 100644 --- a/tools/comment-parser/main.js +++ b/tools/comment-parser/main.js @@ -128,8 +128,7 @@ const BlockCommentParser = ({ return { parse: async (stream) => { stream.skip_whitespace(); - stream.debug('starting at', await stream.debug()) - if ( ! stream.matches(start) ) return; + if ( ! await stream.matches(start) ) return; stream.fwd(start.length); const contents = await stream.get_until(end); if ( ! contents ) return; @@ -221,7 +220,7 @@ const CommentParser = () => { javascript: { parsers: [ ['lines', { - prefix: '// ', + prefix: '//', }], ['block', { start: '/*', @@ -231,7 +230,7 @@ const CommentParser = () => { ], writers: { lines: ['lines', { - prefix: '//' + prefix: '// ' }], block: ['block', { start: '/*', @@ -312,6 +311,7 @@ const CommentParser = () => { break; } } + console.log('comment?', comment); if ( ! comment ) break; results.push(comment); } diff --git a/tools/license-headers/main.js b/tools/license-headers/main.js index 97c6414e60..0716031a10 100644 --- a/tools/license-headers/main.js +++ b/tools/license-headers/main.js @@ -19,6 +19,7 @@ const levenshtein = require('js-levenshtein'); const DiffMatchPatch = require('diff-match-patch'); +const enq = require('enquirer'); const dmp = new DiffMatchPatch(); const dedent = require('dedent'); @@ -121,6 +122,8 @@ const LicenseChecker = ({ break; } } + + console.log('headers', headers); const combined = headers_lines.slice(top, bottom).flat(); const combined_txt = combined.join('\n'); @@ -130,6 +133,12 @@ const LicenseChecker = ({ header2: combined_txt, }) + if ( diff_info.distance > 0.7*desired_header.length ) { + return { + has_header: false, + }; + } + diff_info.range = [ headers[top].range[0], headers[bottom-1].range[1], @@ -385,6 +394,18 @@ const cmd_sync_fn = async () => { if ( diff_info.distance !== 0 ) { counts.conflict++; process.stdout.write(`\x1B[31;1mCONFLICT\x1B[0m\n`); + process.stdout.write('\x1B[36;1m=======\x1B[0m\n'); + process.stdout.write(diff_info.term_diff); + process.stdout.write('\n\x1B[36;1m=======\x1B[0m\n'); + const prompt = new enq.Select({ + message: 'Select Action', + choices: [ + { name: 'skip', message: 'Skip' }, + { name: 'replace', message: 'Replace' }, + ] + }) + const action = await prompt.run(); + console.log('action', action); } else { counts.ok++; process.stdout.write(`\x1B[32;1mOK\x1B[0m\n`); diff --git a/tools/license-headers/package.json b/tools/license-headers/package.json index 05ced1f180..0bf0b49e3d 100644 --- a/tools/license-headers/package.json +++ b/tools/license-headers/package.json @@ -13,6 +13,7 @@ "console-table-printer": "^2.12.1", "dedent": "^1.5.3", "diff-match-patch": "^1.0.5", + "enquirer": "^2.4.1", "js-levenshtein": "^1.1.6", "yaml": "^2.4.5" } From 2bf9f60bb08fc2a0cc5c582d54e16aaa315dc193 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 10 Jul 2024 16:12:09 -0400 Subject: [PATCH 0510/2119] dev(license-headers): implement skip and replace --- experiments/js-parse-and-output/test.js | 10 ++++++---- tools/license-headers/main.js | 12 +++++++++++- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/experiments/js-parse-and-output/test.js b/experiments/js-parse-and-output/test.js index 50dac4c74b..496114b665 100644 --- a/experiments/js-parse-and-output/test.js +++ b/experiments/js-parse-and-output/test.js @@ -1,21 +1,23 @@ /* * Copyright (C) 2024 Puter Technologies Inc. - * + * * This file is part of Puter. - * + * * Puter 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 . */ + + const babelParser = require('@babel/parser'); const generate = (require('@babel/generator')).default; const fs = require('fs'); diff --git a/tools/license-headers/main.js b/tools/license-headers/main.js index 0716031a10..57c1c985ab 100644 --- a/tools/license-headers/main.js +++ b/tools/license-headers/main.js @@ -405,7 +405,17 @@ const cmd_sync_fn = async () => { ] }) const action = await prompt.run(); - console.log('action', action); + if ( action === 'skip' ) continue; + const before = source.slice(0, diff_info.range[0]); + const after = source.slice(diff_info.range[1]); + const new_source = before + + comment_parser.output_comment({ + style: 'block', + filename: value.name, + text: desired_header, + }) + + after; + fs.writeFileSync(value.path, new_source); } else { counts.ok++; process.stdout.write(`\x1B[32;1mOK\x1B[0m\n`); From 6728dd2571fce5147c3a0b719253c81711ecff69 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 10 Jul 2024 16:25:03 -0400 Subject: [PATCH 0511/2119] dev(license-headers): fix excludes list --- experiments/x86emu/www/js/Instance.mjs | 19 +++++++++++++++++ experiments/x86emu/www/js/InstanceManager.mjs | 19 +++++++++++++++++ experiments/x86emu/www/js/V86Wrapper.mjs | 19 +++++++++++++++++ experiments/x86emu/www/main.js | 19 +++++++++++++++++ src/backend/src/services/ParameterService.js | 19 +++++++++++++++++ .../information/InformationService.js | 19 +++++++++++++++++ tools/comment-parser/main.js | 21 ++++++++++++++++++- tools/comment-parser/test/test.js | 19 +++++++++++++++++ tools/file-walker/test.js | 7 ++++++- tools/license-headers/main.js | 10 ++++----- 10 files changed, 164 insertions(+), 7 deletions(-) diff --git a/experiments/x86emu/www/js/Instance.mjs b/experiments/x86emu/www/js/Instance.mjs index e64dd40455..54df570e00 100644 --- a/experiments/x86emu/www/js/Instance.mjs +++ b/experiments/x86emu/www/js/Instance.mjs @@ -1,3 +1,22 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ + import { V86 } from "./V86Wrapper.mjs"; /** * Class representing an Instance of an emulator machine. diff --git a/experiments/x86emu/www/js/InstanceManager.mjs b/experiments/x86emu/www/js/InstanceManager.mjs index 6e8ebce644..04a5813402 100644 --- a/experiments/x86emu/www/js/InstanceManager.mjs +++ b/experiments/x86emu/www/js/InstanceManager.mjs @@ -1,3 +1,22 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ + import Instance from "./Instance.mjs" /** diff --git a/experiments/x86emu/www/js/V86Wrapper.mjs b/experiments/x86emu/www/js/V86Wrapper.mjs index 5417bc6867..f81510e440 100644 --- a/experiments/x86emu/www/js/V86Wrapper.mjs +++ b/experiments/x86emu/www/js/V86Wrapper.mjs @@ -1,3 +1,22 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ + let V86; if (typeof window !== 'undefined') { diff --git a/experiments/x86emu/www/main.js b/experiments/x86emu/www/main.js index 23e207f936..69df0af813 100755 --- a/experiments/x86emu/www/main.js +++ b/experiments/x86emu/www/main.js @@ -1,3 +1,22 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ + #!/usr/bin/env node /* * Copyright (C) 2024 Puter Technologies Inc. diff --git a/src/backend/src/services/ParameterService.js b/src/backend/src/services/ParameterService.js index ed08bae4b5..8ff72367df 100644 --- a/src/backend/src/services/ParameterService.js +++ b/src/backend/src/services/ParameterService.js @@ -1,3 +1,22 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ + const BaseService = require("./BaseService"); /* diff --git a/src/backend/src/services/information/InformationService.js b/src/backend/src/services/information/InformationService.js index 7e508cae28..2e371d7937 100644 --- a/src/backend/src/services/information/InformationService.js +++ b/src/backend/src/services/information/InformationService.js @@ -1,3 +1,22 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ + const BaseService = require("../BaseService"); /* diff --git a/tools/comment-parser/main.js b/tools/comment-parser/main.js index 68e64245ae..185cab0936 100644 --- a/tools/comment-parser/main.js +++ b/tools/comment-parser/main.js @@ -1,3 +1,22 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ + const lib = {}; lib.dedent_lines = lines => { // If any lines are just spaces, remove the spaces @@ -311,7 +330,7 @@ const CommentParser = () => { break; } } - console.log('comment?', comment); + // console.log('comment?', comment); if ( ! comment ) break; results.push(comment); } diff --git a/tools/comment-parser/test/test.js b/tools/comment-parser/test/test.js index 67ef095cf1..f0518ef3cc 100644 --- a/tools/comment-parser/test/test.js +++ b/tools/comment-parser/test/test.js @@ -1,3 +1,22 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ + const { StringStream, LinesCommentParser, diff --git a/tools/file-walker/test.js b/tools/file-walker/test.js index eec352f963..d0bc26f595 100644 --- a/tools/file-walker/test.js +++ b/tools/file-walker/test.js @@ -31,10 +31,15 @@ const EXCLUDE_LISTS = { /^src\/dev-center\/js/, /src\/backend\/src\/public\/assets/, /^src\/gui\/src\/lib/, - /^src\/puter\.js/, + /^eslint\.config\.js$/, ] }; +EXCLUDE_LISTS.NOT_AGPL = [ + ...EXCLUDE_LISTS.NOT_SOURCE, + /^src\/puter-js/, +]; + const hl_readdir = async path => { const names = await fs.promises.readdir(path); const entries = []; diff --git a/tools/license-headers/main.js b/tools/license-headers/main.js index 57c1c985ab..9b4596e5ac 100644 --- a/tools/license-headers/main.js +++ b/tools/license-headers/main.js @@ -123,7 +123,7 @@ const LicenseChecker = ({ } } - console.log('headers', headers); + // console.log('headers', headers); const combined = headers_lines.slice(top, bottom).flat(); const combined_txt = combined.join('\n'); @@ -165,7 +165,7 @@ const license_check_test = async ({ options }) => { }); const walk_iterator = walk({ - excludes: EXCLUDE_LISTS.NOT_SOURCE, + excludes: EXCLUDE_LISTS.NOT_AGPL, }, path_.join(__dirname, '../..')); for await ( const value of walk_iterator ) { if ( value.is_dir ) continue; @@ -216,7 +216,7 @@ const cmd_check_fn = async () => { }; const walk_iterator = walk({ - excludes: EXCLUDE_LISTS.NOT_SOURCE, + excludes: EXCLUDE_LISTS.NOT_AGPL, }, path_.join(__dirname, '../..')); for await ( const value of walk_iterator ) { if ( value.is_dir ) continue; @@ -355,7 +355,7 @@ const cmd_sync_fn = async () => { }; const walk_iterator = walk({ - excludes: EXCLUDE_LISTS.NOT_SOURCE, + excludes: EXCLUDE_LISTS.NOT_AGPL, }, '.'); for await ( const value of walk_iterator ) { if ( value.is_dir ) continue; @@ -378,7 +378,7 @@ const cmd_sync_fn = async () => { continue; } if ( ! diff_info.has_header ) { - if ( false ) fs.writeFileSync( + fs.writeFileSync( value.path, comment_parser.output_comment({ style: 'block', From e6e92dc7b21f01f59d0fd4b10fb9f7543259f29a Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 10 Jul 2024 16:50:41 -0400 Subject: [PATCH 0512/2119] dev(license-headers): add dupe detector --- tools/license-headers/main.js | 43 +++++++++++++++++++++++++++++++++++ 1 file changed, 43 insertions(+) diff --git a/tools/license-headers/main.js b/tools/license-headers/main.js index 9b4596e5ac..12632cfdb7 100644 --- a/tools/license-headers/main.js +++ b/tools/license-headers/main.js @@ -417,6 +417,49 @@ const cmd_sync_fn = async () => { after; fs.writeFileSync(value.path, new_source); } else { + let cut_diff_info = diff_info; + let cut_source = source; + const cut_header = async () => { + cut_source = cut_source.slice(cut_diff_info.range[1]); + cut_diff_info = await license_checker.compare({ + filename: value.name, + source: cut_source, + }); + }; + await cut_header(); + const cut_range = [ + diff_info.range[1], + diff_info.range[1], + ]; + const cut_diff_infos = []; + while ( cut_diff_info.has_header ) { + cut_diff_infos.push(cut_diff_info); + cut_range[1] = cut_diff_info.range[1]; + await cut_header(); + } + if ( cut_range[0] !== cut_range[1] ) { + process.stdout.write(`\x1B[31;1mDUPLICATE\x1B[0m\n`); + process.stdout.write('\x1B[36;1m==== KEEP ====\x1B[0m\n'); + process.stdout.write(diff_info.term_diff + '\n'); + process.stdout.write('\x1B[36;1m==== REMOVE ====\x1B[0m\n'); + for ( const diff_info of cut_diff_infos ) { + process.stdout.write(diff_info.term_diff); + } + process.stdout.write('\n\x1B[36;1m=======\x1B[0m\n'); + const prompt = new enq.Select({ + message: 'Select Action', + choices: [ + { name: 'skip', message: 'Skip' }, + { name: 'remove', message: 'Remove' }, + ] + }) + const action = await prompt.run(); + if ( action === 'skip' ) continue; + const new_source = + source.slice(0, cut_range[0]) + + source.slice(cut_range[1]); + fs.writeFileSync(value.path, new_source); + } counts.ok++; process.stdout.write(`\x1B[32;1mOK\x1B[0m\n`); } From 5b1924f3122b107c1938edf91dd42acec351a801 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 10 Jul 2024 16:53:54 -0400 Subject: [PATCH 0513/2119] chore: remove duplicate headers --- src/git/src/auth.js | 18 ------------------ src/git/src/color.js | 18 ------------------ src/git/src/diff.js | 18 ------------------ src/git/src/filesystem.js | 18 ------------------ src/git/src/format.js | 18 ------------------ src/git/src/git-command-definition.js | 18 ------------------ src/git/src/git-helpers.js | 18 ------------------ src/git/src/help.js | 18 ------------------ src/git/src/main.js | 18 ------------------ src/git/src/refs.js | 18 ------------------ src/git/src/subcommands/add.js | 18 ------------------ src/git/src/subcommands/branch.js | 18 ------------------ src/git/src/subcommands/checkout.js | 18 ------------------ src/git/src/subcommands/cherry-pick.js | 18 ------------------ src/git/src/subcommands/clone.js | 18 ------------------ src/git/src/subcommands/commit.js | 18 ------------------ src/git/src/subcommands/config.js | 18 ------------------ src/git/src/subcommands/diff.js | 18 ------------------ src/git/src/subcommands/fetch.js | 18 ------------------ src/git/src/subcommands/help.js | 18 ------------------ src/git/src/subcommands/init.js | 18 ------------------ src/git/src/subcommands/log.js | 18 ------------------ src/git/src/subcommands/pull.js | 18 ------------------ src/git/src/subcommands/push.js | 18 ------------------ src/git/src/subcommands/remote.js | 18 ------------------ src/git/src/subcommands/restore.js | 18 ------------------ src/git/src/subcommands/show.js | 18 ------------------ src/git/src/subcommands/status.js | 18 ------------------ src/git/src/subcommands/version.js | 18 ------------------ src/gui/utils.js | 18 ------------------ src/terminal/config/dev.js | 18 ------------------ src/terminal/config/release.js | 18 ------------------ src/terminal/rollup.config.js | 18 ------------------ src/terminal/src/main.js | 18 ------------------ src/terminal/src/pty/PTT.js | 18 ------------------ src/terminal/src/pty/PTY.js | 18 ------------------ src/terminal/src/pty/XDocumentANSIShell.js | 18 ------------------ tools/check-translations.js | 18 ------------------ tools/license-headers/main.js | 2 +- 39 files changed, 1 insertion(+), 685 deletions(-) diff --git a/src/git/src/auth.js b/src/git/src/auth.js index 54828f1545..29fbec8d2e 100644 --- a/src/git/src/auth.js +++ b/src/git/src/auth.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ /** * Authentication manager * Eventually this will want to retrieve stored credentials from somewhere, but for now diff --git a/src/git/src/color.js b/src/git/src/color.js index 48d46cab82..096199d61a 100644 --- a/src/git/src/color.js +++ b/src/git/src/color.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ import chalk from 'chalk'; export const color_options = { diff --git a/src/git/src/diff.js b/src/git/src/diff.js index 86da0ed2aa..726f9d3996 100644 --- a/src/git/src/diff.js +++ b/src/git/src/diff.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ import * as Diff from 'diff'; import git from 'isomorphic-git'; import path from 'path-browserify'; diff --git a/src/git/src/filesystem.js b/src/git/src/filesystem.js index 2378bd0aad..8ad0cbce55 100644 --- a/src/git/src/filesystem.js +++ b/src/git/src/filesystem.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ import { PosixError } from '@heyputer/puter-js-common/src/PosixError.js'; import path_ from 'path-browserify'; diff --git a/src/git/src/format.js b/src/git/src/format.js index 3c721d95d6..cfd2ad9947 100644 --- a/src/git/src/format.js +++ b/src/git/src/format.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ import { shorten_hash } from './git-helpers.js'; import chalk from 'chalk'; import { get_matching_refs } from './refs.js'; diff --git a/src/git/src/git-command-definition.js b/src/git/src/git-command-definition.js index a710df3102..4961e2d18b 100644 --- a/src/git/src/git-command-definition.js +++ b/src/git/src/git-command-definition.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ /** * The command definition for `git` itself, in the same format as subcommands. diff --git a/src/git/src/git-helpers.js b/src/git/src/git-helpers.js index 22c3531dbe..a68a1b51ca 100644 --- a/src/git/src/git-helpers.js +++ b/src/git/src/git-helpers.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ import path from 'path-browserify'; import git from 'isomorphic-git'; import { GrammarContext, standard_parsers } from '@heyputer/parsely/exports.js'; diff --git a/src/git/src/help.js b/src/git/src/help.js index 6b703e7463..f83cbc7251 100644 --- a/src/git/src/help.js +++ b/src/git/src/help.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ /** * Throw this from a subcommand's execute() in order to print its usage text to stderr. diff --git a/src/git/src/main.js b/src/git/src/main.js index 86e060a005..ef26fd7b35 100644 --- a/src/git/src/main.js +++ b/src/git/src/main.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ import { parseArgs } from '@pkgjs/parseargs'; import subcommands from './subcommands/__exports__.js'; import git_command from './git-command-definition.js'; diff --git a/src/git/src/refs.js b/src/git/src/refs.js index eaae68782e..3b37a695c4 100644 --- a/src/git/src/refs.js +++ b/src/git/src/refs.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ // Map of hash -> array of full reference names import git from 'isomorphic-git'; diff --git a/src/git/src/subcommands/add.js b/src/git/src/subcommands/add.js index 8233fcbadc..11a414b68b 100644 --- a/src/git/src/subcommands/add.js +++ b/src/git/src/subcommands/add.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ import git from 'isomorphic-git'; import { find_repo_root } from '../git-helpers.js'; diff --git a/src/git/src/subcommands/branch.js b/src/git/src/subcommands/branch.js index 1866e046cf..479ef97b19 100644 --- a/src/git/src/subcommands/branch.js +++ b/src/git/src/subcommands/branch.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ import git from 'isomorphic-git'; import { find_repo_root, shorten_hash } from '../git-helpers.js'; import { SHOW_USAGE } from '../help.js'; diff --git a/src/git/src/subcommands/checkout.js b/src/git/src/subcommands/checkout.js index ddd848b4f6..fe58083fd2 100644 --- a/src/git/src/subcommands/checkout.js +++ b/src/git/src/subcommands/checkout.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ import git from 'isomorphic-git'; import { find_repo_root, resolve_to_commit, shorten_hash } from '../git-helpers.js'; import { SHOW_USAGE } from '../help.js'; diff --git a/src/git/src/subcommands/cherry-pick.js b/src/git/src/subcommands/cherry-pick.js index 377e7334d5..a094886d9a 100644 --- a/src/git/src/subcommands/cherry-pick.js +++ b/src/git/src/subcommands/cherry-pick.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ import git, { TREE } from 'isomorphic-git'; import { find_repo_root, has_staged_changes, resolve_to_commit, shorten_hash } from '../git-helpers.js'; import { SHOW_USAGE } from '../help.js'; diff --git a/src/git/src/subcommands/clone.js b/src/git/src/subcommands/clone.js index c93da28b3f..f34b761066 100644 --- a/src/git/src/subcommands/clone.js +++ b/src/git/src/subcommands/clone.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ import git from 'isomorphic-git'; import http from 'isomorphic-git/http/web'; import { SHOW_USAGE } from '../help.js'; diff --git a/src/git/src/subcommands/commit.js b/src/git/src/subcommands/commit.js index 0af26fcb4f..a835a0cd04 100644 --- a/src/git/src/subcommands/commit.js +++ b/src/git/src/subcommands/commit.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ import git from 'isomorphic-git'; import { find_repo_root, shorten_hash } from '../git-helpers.js'; diff --git a/src/git/src/subcommands/config.js b/src/git/src/subcommands/config.js index 2b604e55cc..fa2e36422b 100644 --- a/src/git/src/subcommands/config.js +++ b/src/git/src/subcommands/config.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ import git from 'isomorphic-git'; import { find_repo_root } from '../git-helpers.js'; import { SHOW_USAGE } from '../help.js'; diff --git a/src/git/src/subcommands/diff.js b/src/git/src/subcommands/diff.js index a46b7f1e23..53b6f43c63 100644 --- a/src/git/src/subcommands/diff.js +++ b/src/git/src/subcommands/diff.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ import git, { STAGE, TREE, WORKDIR } from 'isomorphic-git'; import { find_repo_root, group_positional_arguments, resolve_to_commit, resolve_to_oid } from '../git-helpers.js'; import { SHOW_USAGE } from '../help.js'; diff --git a/src/git/src/subcommands/fetch.js b/src/git/src/subcommands/fetch.js index d65e0772cb..dc844d0dea 100644 --- a/src/git/src/subcommands/fetch.js +++ b/src/git/src/subcommands/fetch.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ import git from 'isomorphic-git'; import http from 'isomorphic-git/http/web'; import { determine_fetch_remote, find_repo_root } from '../git-helpers.js'; diff --git a/src/git/src/subcommands/help.js b/src/git/src/subcommands/help.js index af48792d40..9e78d6e1cd 100644 --- a/src/git/src/subcommands/help.js +++ b/src/git/src/subcommands/help.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ import subcommands from './__exports__.js'; import git_command from '../git-command-definition.js'; import { produce_help_string } from '../help.js'; diff --git a/src/git/src/subcommands/init.js b/src/git/src/subcommands/init.js index df7e3ddf63..59d989e284 100644 --- a/src/git/src/subcommands/init.js +++ b/src/git/src/subcommands/init.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ import git from 'isomorphic-git'; import path from 'path-browserify'; diff --git a/src/git/src/subcommands/log.js b/src/git/src/subcommands/log.js index 2741df3978..b616dc92a3 100644 --- a/src/git/src/subcommands/log.js +++ b/src/git/src/subcommands/log.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ import git, { TREE } from 'isomorphic-git'; import { find_repo_root, group_positional_arguments } from '../git-helpers.js'; import { diff --git a/src/git/src/subcommands/pull.js b/src/git/src/subcommands/pull.js index daff7c713d..fa15b00e79 100644 --- a/src/git/src/subcommands/pull.js +++ b/src/git/src/subcommands/pull.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ import git from 'isomorphic-git'; import http from 'isomorphic-git/http/web'; import { determine_fetch_remote, find_repo_root } from '../git-helpers.js'; diff --git a/src/git/src/subcommands/push.js b/src/git/src/subcommands/push.js index 4d87887608..f631aa28b3 100644 --- a/src/git/src/subcommands/push.js +++ b/src/git/src/subcommands/push.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ import git from 'isomorphic-git'; import http from 'isomorphic-git/http/web'; import { determine_fetch_remote, find_repo_root, resolve_to_oid, shorten_hash } from '../git-helpers.js'; diff --git a/src/git/src/subcommands/remote.js b/src/git/src/subcommands/remote.js index f3fd32b562..24c6bfdba5 100644 --- a/src/git/src/subcommands/remote.js +++ b/src/git/src/subcommands/remote.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ import git from 'isomorphic-git'; import { find_repo_root } from '../git-helpers.js'; diff --git a/src/git/src/subcommands/restore.js b/src/git/src/subcommands/restore.js index d49f64f7b4..b1b0ee8eb9 100644 --- a/src/git/src/subcommands/restore.js +++ b/src/git/src/subcommands/restore.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ import git, { STAGE, TREE, WORKDIR } from 'isomorphic-git'; import { find_repo_root } from '../git-helpers.js'; import path from 'path-browserify'; diff --git a/src/git/src/subcommands/show.js b/src/git/src/subcommands/show.js index 77cf6f5b4c..dd321c5f6a 100644 --- a/src/git/src/subcommands/show.js +++ b/src/git/src/subcommands/show.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ import git, { TREE } from 'isomorphic-git'; import { find_repo_root, resolve_to_oid } from '../git-helpers.js'; import { diff --git a/src/git/src/subcommands/status.js b/src/git/src/subcommands/status.js index c4c053bd6f..e28cf6d13d 100644 --- a/src/git/src/subcommands/status.js +++ b/src/git/src/subcommands/status.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ import git from 'isomorphic-git'; import path from 'path-browserify'; import { find_repo_root, shorten_hash } from '../git-helpers.js'; diff --git a/src/git/src/subcommands/version.js b/src/git/src/subcommands/version.js index 6bf82f3b0b..713fa7d645 100644 --- a/src/git/src/subcommands/version.js +++ b/src/git/src/subcommands/version.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Git client. - * - * Puter's Git client 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 . - */ import git from 'isomorphic-git'; const VERSION = '1.0.0'; diff --git a/src/gui/utils.js b/src/gui/utils.js index d5b1d21a35..b3394f8822 100644 --- a/src/gui/utils.js +++ b/src/gui/utils.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* -Copyright (C) 2024 Puter Technologies Inc. - -This file is part of Puter.com. - -Puter.com 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 . -*/ import { encode } from 'html-entities'; import fs from 'fs'; import path from 'path'; diff --git a/src/terminal/config/dev.js b/src/terminal/config/dev.js index 9323fe988c..b8c70bbca0 100644 --- a/src/terminal/config/dev.js +++ b/src/terminal/config/dev.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Terminal. - * - * Puter's Terminal 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 . - */ globalThis.__CONFIG__ = { "origin": "http://127.0.0.1:8082", "sdk_url": "http://puter.localhost:4100/sdk/puter.js", diff --git a/src/terminal/config/release.js b/src/terminal/config/release.js index 6560428302..f795ca1395 100644 --- a/src/terminal/config/release.js +++ b/src/terminal/config/release.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Terminal. - * - * Puter's Terminal 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 . - */ globalThis.__CONFIG__ = { "origin": "https://puter.sh", "sdk_url": "https://puter.com/puter.js/v2", diff --git a/src/terminal/rollup.config.js b/src/terminal/rollup.config.js index 85f3ac7a94..5d3864a154 100644 --- a/src/terminal/rollup.config.js +++ b/src/terminal/rollup.config.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Terminal. - * - * Puter's Terminal 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 . - */ import { nodeResolve } from '@rollup/plugin-node-resolve' import commonjs from '@rollup/plugin-commonjs'; import copy from 'rollup-plugin-copy'; diff --git a/src/terminal/src/main.js b/src/terminal/src/main.js index ab3e8f2fd7..cf7347f1de 100644 --- a/src/terminal/src/main.js +++ b/src/terminal/src/main.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Terminal. - * - * Puter's Terminal 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 . - */ import { Terminal } from '@xterm/xterm'; import { FitAddon } from '@xterm/addon-fit'; import { PTY } from './pty/PTY'; diff --git a/src/terminal/src/pty/PTT.js b/src/terminal/src/pty/PTT.js index 7261a7553f..b38bff8c84 100644 --- a/src/terminal/src/pty/PTT.js +++ b/src/terminal/src/pty/PTT.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Terminal. - * - * Puter's Terminal 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 . - */ /** * PTT: pseudo-terminal target; called "slave" in POSIX */ diff --git a/src/terminal/src/pty/PTY.js b/src/terminal/src/pty/PTY.js index 736724a4ee..716ddd4ff5 100644 --- a/src/terminal/src/pty/PTY.js +++ b/src/terminal/src/pty/PTY.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Terminal. - * - * Puter's Terminal 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 . - */ import { PTT } from "./PTT"; const encoder = new TextEncoder(); diff --git a/src/terminal/src/pty/XDocumentANSIShell.js b/src/terminal/src/pty/XDocumentANSIShell.js index 24bd65d20a..953659ec2b 100644 --- a/src/terminal/src/pty/XDocumentANSIShell.js +++ b/src/terminal/src/pty/XDocumentANSIShell.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter's Terminal. - * - * Puter's Terminal 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 . - */ export class XDocumentANSIShell { constructor (params) { this.internal_ = {}; diff --git a/tools/check-translations.js b/tools/check-translations.js index d593277082..17e5361e86 100644 --- a/tools/check-translations.js +++ b/tools/check-translations.js @@ -16,24 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -/** - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ import translations from '../src/gui/src/i18n/translations/translations.js'; import fs from 'fs'; diff --git a/tools/license-headers/main.js b/tools/license-headers/main.js index 12632cfdb7..2a6a734edc 100644 --- a/tools/license-headers/main.js +++ b/tools/license-headers/main.js @@ -434,7 +434,7 @@ const cmd_sync_fn = async () => { const cut_diff_infos = []; while ( cut_diff_info.has_header ) { cut_diff_infos.push(cut_diff_info); - cut_range[1] = cut_diff_info.range[1]; + cut_range[1] += cut_diff_info.range[1]; await cut_header(); } if ( cut_range[0] !== cut_range[1] ) { From 7aadae58ce1a51f925bf64c3d65ac1fa6971b164 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 10 Jul 2024 17:18:33 -0400 Subject: [PATCH 0514/2119] fix: remove flag that breaks puter-js webpack --- src/puter-js/package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/puter-js/package.json b/src/puter-js/package.json index 7c0eccfb28..2e63edab48 100644 --- a/src/puter-js/package.json +++ b/src/puter-js/package.json @@ -5,9 +5,9 @@ "main": "index.js", "scripts": { "start-server": "npx http-server --cors -c-1", - "start-webpack": "export NODE_OPTIONS=--openssl-legacy-provider && webpack ./src/index.js --output-filename puter.js && webpack ./src/index.js --output-filename puter.dev.js --watch --devtool source-map", + "start-webpack": "webpack ./src/index.js --output-filename puter.js && webpack ./src/index.js --output-filename puter.dev.js --watch --devtool source-map", "start": "concurrently \"npm run start-server\" \"npm run start-webpack\"", - "build": "export NODE_OPTIONS=--openssl-legacy-provider && webpack ./src/index.js --output-filename puter.js && { echo \"// Copyright 2024 Puter Technologies Inc. All rights reserved.\"; echo \"// Generated on $(date '+%Y-%m-%d %H:%M')\n\"; cat ./dist/puter.js; } > temp && mv temp ./dist/puter.js" + "build": "webpack ./src/index.js --output-filename puter.js && { echo \"// Copyright 2024 Puter Technologies Inc. All rights reserved.\"; echo \"// Generated on $(date '+%Y-%m-%d %H:%M')\n\"; cat ./dist/puter.js; } > temp && mv temp ./dist/puter.js" }, "keywords": [], "author": "", From 92abc9947f811f94f17a5ee5a4b73ee2b210900a Mon Sep 17 00:00:00 2001 From: Waheed Uddin Ahmed Date: Thu, 11 Jul 2024 06:42:52 +0600 Subject: [PATCH 0515/2119] Issue#530 - Update bengali translations --- src/gui/src/i18n/translations/bn.js | 482 +++++++++++++++++++--------- 1 file changed, 336 insertions(+), 146 deletions(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index f21028ac7b..6d81199daf 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -18,150 +18,340 @@ */ const bn = { - name: "বাংলা", - english_name: "Bengali", - code: "bn", - dictionary: { - access_granted_to: "অ্যাক্সেস মঞ্জুর করা হয়েছে", - add_existing_account: "আগে থাকা একাউন্ট অ্যাড করুন", - all_fields_required: 'সমস্ত ক্ষেত্র প্রয়োজন.', - apply: "আবেদন করুন", - ascending: 'উদীয়মান', - background: "পটভূমি", - browse: "ব্রাউজ করুন", - cancel: 'বাতিল করুন', - center: 'কেন্দ্র', - change_desktop_background: 'ডেস্কটপ পটভূমি পরিবর্তন করুন...', - change_password: "পাসওয়ার্ড পরিবর্তন করুন", - change_username: "ব্যবহারকারীর নাম পরিবর্তন করুন", - close_all_windows: "সমস্ত উইন্ডোজ বন্ধ করুন", - color: 'রঙ', - confirm_account_for_free_referral_storage_c2a: 'একটি অ্যাকাউন্ট তৈরি করুন এবং 1 GB বিনামূল্যে সঞ্চয়স্থান পেতে আপনার ইমেল ঠিকানা নিশ্চিত করুন৷ আপনার বন্ধুও 1 জিবি ফ্রি স্টোরেজ পাবে।', - confirm_new_password: "নিশ্চিত কর নতুন পাসওয়ার্ড", - contact_us: "আমাদের সাথে যোগাযোগ করুন", - contain: 'ধারণ করে', - continue: "চালিয়ে যান", - copy: 'কপি', - copy_link: "লিংক কপি করুন", - copying: "কপি করা হচ্ছে", - cover: 'আবরণ', - create_account: "একাউন্ট তৈরি করুন", - create_free_account: "ফ্রি একাউন্ট তৈরি করুন", - create_shortcut: "শর্টকাট তৈরি করুন", - current_password: "বর্তমান পাসওয়ার্ড", - cut: 'কাট', - date_modified: 'তারিখ পরিবর্তন করা হয়েছে', - delete: 'মুছে ফেলা', - delete_permanently: "চিরতরে মুছে দাও", - deploy_as_app: 'অ্যাপ হিসাবে স্থাপন করুন', - descending: 'অধোগামী', - desktop_background_fit: "ফিট", - dir_published_as_website: `%strong% এতে প্রকাশিত হয়েছে:`, - disassociate_dir: "ডিসঅ্যাসোসিয়েট ডিরেক্টরি", - download: 'ডাউনলোড করুন', - downloading: "ডাউনলোড হচ্ছে", - email: "ইমেইল", - email_or_username: "ইমেল বা ব্যবহারকারীর নাম", - empty_trash: 'ট্র্যাশ খালি', - empty_trash_confirmation: `আপনি কি ট্র্যাশে থাকা আইটেমগুলিকে স্থায়ীভাবে মুছে দেওয়ার বিষয়ে নিশ্চিত?`, - emptying_trash: 'ট্র্যাশ খালি করা হচ্ছে...', - feedback: "প্রতিক্রিয়া", - feedback_c2a: "আমাদের আপনার প্রতিক্রিয়া, মন্তব্য, এবং বাগ রিপোর্ট পাঠাতে নীচের ফর্ম ব্যবহার করুন.", - feedback_sent_confirmation: "আমাদের সাথে যোগাযোগ করার জন্য আপনাকে ধন্যবাদ। আপনার অ্যাকাউন্টের সাথে যুক্ত কোনো ইমেল থাকলে, আপনি যত তাড়াতাড়ি সম্ভব আমাদের কাছ থেকে ফিরে পাবেন।", - forgot_pass_c2a: "পাসওয়ার্ড ভুলে গেছেন?", - from: "থেকে", - general: "সাধারণ", - get_a_copy_of_on_puter: `এর একটি কপি পান '%%' on Puter.com!`, - get_copy_link: 'অনুলিপি লিঙ্ক পান', - hide_all_windows: "সমস্ত উইন্ডোজ লুকান", - html_document: 'HTML নথি', - image: 'ছবি', - invite_link: "আমন্ত্রণ লিঙ্ক", - items_in_trash_cannot_be_renamed: `এই আইটেমটির নাম পরিবর্তন করা যাবে না কারণ এটি ট্র্যাশে রয়েছে৷ এই আইটেমটির নাম পরিবর্তন করতে, প্রথমে এটিকে ট্র্যাশ থেকে টেনে আনুন৷`, - jpeg_image: 'JPEG ছবি', - keep_in_taskbar: 'টাস্কবারে রাখুন', - log_in: "প্রবেশ করুন", - log_out: 'প্রস্থান', - move: 'সরান', - moving_file: "চলন্ত %%", - my_websites: "আমার ওয়েবসাইট", - name: 'নাম', - name_cannot_be_empty: 'নাম খালি রাখা যাবে না।', - name_cannot_contain_double_period: "নাম '..' অক্ষর হতে পারে না।", - name_cannot_contain_period: "নাম হতে পারে না '.' চরিত্র", - name_cannot_contain_slash: "নামে '/' অক্ষর থাকতে পারে না।", - name_must_be_string: "নাম শুধুমাত্র একটি স্ট্রিং হতে পারে.", - name_too_long: `নাম %% অক্ষরের বেশি হতে পারে না।`, - new: 'নতুন', - new_folder: 'নতুন ফোল্ডার', - new_password: "নতুন পাসওয়ার্ড", - new_username: "নতুন ব্যবহারকারীর নাম", - no_dir_associated_with_site: 'এই ঠিকানার সাথে সম্পর্কিত কোন ডিরেক্টরি নেই।', - no_websites_published: "আপনি এখনও কোনো ওয়েবসাইট প্রকাশ করেননি.", - ok: 'ঠিক আছে', - open: "খোলা", - open_in_new_tab: "নতুন ট্যাবে খুলুন", - open_in_new_window: "নতুন উইন্ডোতে খুলুন", - open_with: "সঙ্গে খোলা", - password: "পাসওয়ার্ড", - password_changed: "পাসওয়ার্ড পরিবর্তন.", - passwords_do_not_match: '`নতুন পাসওয়ার্ড` এবং `নিউ পাসওয়ার্ড নিশ্চিত করুন` মিলছে না।', - paste: 'পেস্ট করুন', - paste_into_folder: "ফোল্ডার আয়ে পেস্ট করুন", - pick_name_for_website: "আপনার ওয়েবসাইটের জন্য একটি নাম পছন্দ করুন:", - picture: "ছবি", - powered_by_puter_js: `দ্বারা চালিত {{link=docs}}Puter.js{{/link}}`, - preparing: "প্রস্তুত হচ্ছে...", - preparing_for_upload: "আপলোডের জন্য প্রস্তুত হচ্ছে...", - properties: "বৈশিষ্ট্য", - publish: "প্রকাশ করুন", - publish_as_website: 'ওয়েবসাইট হিসাবে প্রকাশ করুন', - recent: "সাম্প্রতিক", - recover_password: "পাসওয়ার্ড রিকভার করুন", - refer_friends_c2a: "Puter-এ অ্যাকাউন্ট তৈরি এবং নিশ্চিত করা প্রত্যেক বন্ধুর জন্য 1 GB পান। আপনার বন্ধুও পাবেন 1 জিবি!", - refer_friends_social_media_c2a: `1 GB বিনামূল্যে সঞ্চয়স্থান পান Puter.com এ!`, - refresh: 'রিফ্রেশ', - release_address_confirmation: `আপনি কি এই ঠিকানাটি প্রকাশ করার বিষয়ে নিশ্চিত?`, - remove_from_taskbar:'টাস্কবার থেকে সরান', - rename: 'নাম পরিবর্তন করুন', - repeat: 'রিপিট করুন', - resend_confirmation_code: "কনফার্মেশন কোড আবার পাঠান", - restore: "পুনরুদ্ধার করুন", - save_account_to_get_copy_link: "এগিয়ে যেতে একটি অ্যাকাউন্ট তৈরি করুন.", - save_account_to_publish: 'এগিয়ে যেতে একটি অ্যাকাউন্ট তৈরি করুন.', - save_session_c2a: 'আপনার বর্তমান সেশন সংরক্ষণ করতে এবং আপনার কাজ হারানো এড়াতে একটি অ্যাকাউন্ট তৈরি করুন।', - scan_qr_c2a: 'অন্যান্য ডিভাইস থেকে এই সেশনে লগ ইন করতে নিচের কোডটি স্ক্যান করুন', - select: "নির্বাচন করুন", - select_color: 'রঙ নির্বাচন করুন...', - send: "পাঠান", - send_password_recovery_email: "পাসওয়ার্ড পুনরুদ্ধার ইমেল পাঠান", - session_saved: "একটি অ্যাকাউন্ট তৈরি করার জন্য আপনাকে ধন্যবাদ. এই অধিবেশন সংরক্ষণ করা হয়েছে.", - set_new_password: "নতুন পাসওয়ার্ড সেট করুন", - share_to: "শেয়ার করুন", - show_all_windows: "সমস্ত উইন্ডোজ দেখান", - show_hidden: 'লুকোনো জিনিষ দেখাও', - sign_in_with_puter: "Puter দিয়ে সাইন ইন করুন", - sign_up: "নিবন্ধন করুন", - signing_in: "সাইন ইন…", - size: 'আকার', - sort_by: 'ক্রমানুসার', - start: 'শুরু করুন', - taking_longer_than_usual: 'স্বাভাবিকের চেয়ে একটু বেশি সময় নিচ্ছে। অনুগ্রহপূর্বক অপেক্ষা করুন...', - text_document: 'পাঠ্য নথি', - tos_fineprint: `'ফ্রি অ্যাকাউন্ট তৈরি করুন'-এ ক্লিক করার মাধ্যমে আপনি Puter-এর {{link=terms}}পরিষেবার শর্তাবলী{{/link}} এবং {{link=privacy}}গোপনীয়তা নীতি{{/link}}।`, - trash: 'আবর্জনা', - type: 'টাইপ', - undo: 'পূর্বাবস্থায় ফেরান', - unzip: "আনজিপ করুন", - upload: 'আপলোড করুন', - upload_here: 'এখানে আপলোড করুন', - username: "ব্যবহারকারীর নাম", - username_changed: 'ব্যবহারকারীর নাম সফলভাবে আপডেট করা হয়েছে।', - versions: "সংস্করণ", - yes_release_it: 'হ্যাঁ, এটা ছেড়ে দিন', - you_have_been_referred_to_puter_by_a_friend: "আপনি একজন বন্ধু দ্বারা Puter উল্লেখ করা হয়েছে!", - zip: "জিপ" - } -} + name: "বাংলা", + english_name: "Bengali", + code: "bn", + dictionary: { + about: "সম্পর্কে", + account: "অ্যাকাউন্ট", + account_password: "অ্যাকাউন্ট পাসওয়ার্ড যাচাই করুন", + access_granted_to: "অ্যাক্সেস দেওয়া হয়েছে", + add_existing_account: "বিদ্যমান অ্যাকাউন্ট যোগ করুন", + all_fields_required: "সমস্ত ফিল্ড প্রয়োজন.", + allow: "অনুমতি দিন", + apply: "প্রয়োগ করুন", + ascending: "উত্তরাধিকার", + associated_websites: "সংযুক্ত ওয়েবসাইটগুলি", + auto_arrange: "অটো বিন্যাস", + background: "পেছনের অংশ", + browse: "ব্রাউজ", + cancel: "বাতিল করুন", + center: "কেন্দ্র", + change_desktop_background: "ডেস্কটপ পৃষ্ঠভূমি পরিবর্তন করুন…", + change_email: "ইমেল পরিবর্তন করুন", + change_language: "ভাষা পরিবর্তন করুন", + change_password: "পাসওয়ার্ড পরিবর্তন করুন", + change_ui_colors: "ইউআই রঙ পরিবর্তন করুন", + change_username: "ইউজারনেম পরিবর্তন করুন", + close: "বন্ধ করুন", + close_all_windows: "সমস্ত উইন্ডো বন্ধ করুন", + close_all_windows_confirm: "আপনি কি সমস্ত উইন্ডো বন্ধ করতে চান?", + close_all_windows_and_log_out: "উইন্ডো বন্ধ এবং লগ আউট করুন", + change_always_open_with: "আপনি কি এই ধরনের ফাইলটি সবসময় এই সাথে খোলার জন্য চান", + color: "রঙ", + confirm: "অনুমোদন", + confirm_2fa_setup: "আমি আমার অথেন্টিকেশন অ্যাপ্লিকেশনে কোডটি যোগ করেছি", + confirm_2fa_recovery: "আমি আমার পুনরুদ্ধার কোডগুলি একটি নিরাপদ স্থানে সংরক্ষণ করেছি", + confirm_account_for_free_referral_storage_c2a: "একটি অ্যাকাউন্ট তৈরি করুন এবং আপনার ইমেল ঠিকানা নিশ্চিত করুন যাতে ফ্রি 1 জিবি স্টোরেজ পান। আপনার বন্ধুও 1 জিবি ফ্রি স্টোরেজ পাবেন।", + confirm_code_generic_incorrect: "ভুল কোড।", + confirm_code_generic_too_many_requests: "অনেক অনুরোধ। দয়া করে কয়েক মিনিট অপেক্ষা করুন।", + confirm_code_generic_submit: "কোড জমা দিন", + confirm_code_generic_try_again: "আবার চেষ্টা করুন", + confirm_code_generic_title: "অনুমোদন কোড প্রবেশ করুন", + confirm_code_2fa_instruction: "আপনার অথেন্টিকেশন অ্যাপ্লিকেশন থেকে 6-ডিজিট কোডটি প্রবেশ করুন।", + confirm_code_2fa_submit_btn: "জমা দিন", + confirm_code_2fa_title: "2FA কোড প্রবেশ করুন", + confirm_delete_multiple_items: "আপনি কি নিশ্চিত যে আপনি এই আইটেমগুলি স্থায়ীভাবে মুছতে চান?", + confirm_delete_single_item: "আপনি কি এই আইটেমটি স্থায়ীভাবে মুছতে চান?", + confirm_open_apps_log_out: "আপনার খোলা অ্যাপ আছে। আপনি কি নিশ্চিত যে আপনি লগ আউট করতে চান?", + confirm_new_password: "নতুন পাসওয়ার্ড নিশ্চিত করুন", + confirm_delete_user: "আপনি কি নিশ্চিত যে আপনি আপনার অ্যাকাউন্টটি মুছতে চান? সমস্ত আপনার ফাইল এবং ডেটা স্থায়ীভাবে মুছে ফেলা হবে। এই ক্রিয়াটি ফিরে পাওয়া যাবে না।", + confirm_delete_user_title: "অ্যাকাউন্ট মুছে ফেলুন?", + confirm_session_revoke: "আপনি কি নিশ্চিত যে আপনি এই সেশনটি প্রত্যাহার করতে চান?", + confirm_your_email_address: "আপনার ইমেল ঠিকানা নিশ্চিত করুন", + contact_us: "যোগাযোগ করুন", + contact_us_verification_required: "এটি ব্যবহার করতে আপনার যাচাইযোগ্য ইমেল ঠিকানা থাকতে হবে।", + contain: "অন্তর্ভুক্ত করুন", + continue: "চালিয়ে যান", + copy: "কপি", + copy_link: "লিংক কপি করুন", + copying: "কপি হচ্ছে", + copying_file: "ফাইল কপি করা হচ্ছে %%", + cover: "কভার", + create_account: "অ্যাকাউন্ট তৈরি করুন", + create_free_account: "ফ্রি অ্যাকাউন্ট তৈরি করুন", + create_shortcut: "শর্টকাট তৈরি করুন", + credits: "ক্রেডিট", + current_password: "বর্তমান পাসওয়ার্ড", + cut: "কাটুন", + clock: "ঘড়ি", + clock_visible_hide: "লুকান - সর্বদা লুকিয়ে রাখা", + clock_visible_show: "দেখান - সর্বদা দৃশ্যমান", + clock_visible_auto: "অটো - ডিফল্ট, মুখ্যম্বর মোডে শুধুমাত্র দৃশ্যমান।", + close_all: "সমস্ত বন্ধ করুন", + created: "তৈরি করা হয়েছে", + date_modified: "তারিখ পরিবর্তন", + default: "ডিফল্ট", + delete: "মুছে ফেলুন", + delete_account: "অ্যাকাউন্ট মুছে ফেলুন", + delete_permanently: "চিরকালের জন্য মুছুন", + deleting_file: "ফাইল মুছে ফেলা হচ্ছে %%", + deploy_as_app: "অ্যাপ্লিকেশন হিসেবে ডিপ্লয়", + descending: "অবতলভাবে", + desktop: "ডেস্কটপ", + desktop_background_fit: "ফিট", + developers: "ডেভেলপারগণ", + dir_published_as_website: `%strong% প্রকাশিত হয়েছে:`, + disable_2fa: "2FA অক্ষম করুন", + disable_2fa_confirm: "আপনি কি নিশ্চিত যে আপনি 2FA অক্ষম করতে চান?", + disable_2fa_instructions: "2FA অক্ষম করতে আপনার পাসওয়ার্ড লিখুন।", + disassociate_dir: "ডিরেক্টরি আনসোসিএট করুন", + documents: "ডকুমেন্টস", + dont_allow: "অনুমতি দিন না", + download: "ডাউনলোড", + download_file: "ফাইল ডাউনলোড করুন", + downloading: "ডাউনলোড হচ্ছে", + email: "ইমেল", + email_change_confirmation_sent: "নতুন ইমেল ঠিকানা নিশ্চিতকরণের জন্য একটি নিশ্চিতকরণ ইমেল পাঠানো হয়েছে। আপনার ইনবক্স পরীক্ষা করুন এবং নির্দেশানুযায়ী প্রক্রিয়াটি সম্পন্ন করতে।", + email_invalid: "ইমেল অবৈধ।", + email_or_username: "ইমেল বা ইউজারনেম", + email_required: "ইমেল প্রয়োজন।", + empty_trash: "খালি ট্র্যাশ", + empty_trash_confirmation: `আপনি কি নিশ্চিত যে আপনি ট্র্যাশে আইটেমগুলি স্থায়ীভাবে মুছতে চান?`, + emptying_trash: "ট্র্যাশ খালি করা হচ্ছে…", + enable_2fa: "2FA চালু করুন", + end_hard: "হার্ড শেষ", + end_process_force_confirm: "আপনি কি নিশ্চিত যে আপনি এই প্রক্রিয়াটি ফোর্স-কুইট করতে চান?", + end_soft: "সফট শেষ", + enlarged_qr_code: "বড় QR কোড", + enter_password_to_confirm_delete_user: "অ্যাকাউন্ট মুছতে নিশ্চিত করতে আপনার পাসওয়ার্ড লিখুন", + error_message_is_missing: "ত্রুটি বার্তাটি অনুপস্থিত।", + error_unknown_cause: "অজানা কারণে একটি অজানা ত্রুটি ঘটেছে।", + error_uploading_files: "ফাইল আপলোড করতে ব্যর্থ", + favorites: "প্রিয়", + feedback: "প্রতিক্রিয়া", + feedback_c2a: "নীচের ফর্মটি ব্যবহার করে আপনার মতামত, মন্তব্য এবং বাগ রিপোর্ট প্রেরণ করুন।", + feedback_sent_confirmation: "আমাদের সাথে যোগাযোগ করার জন্য ধন্যবাদ। আপনার একাউন্টে ইমেল সংযোজন থাকলে আমরা যত তাড়াতাড়ি সম্ভব তাদের থেকে ফিরে পাবেন।", + fit: "ফিট", + folder: "ফোল্ডার", + force_quit: "প্রবল বন্ধ", + forgot_pass_c2a: "পাসওয়ার্ড ভুলে গেছেন?", + from: "থেকে", + general: "সাধারণ", + get_a_copy_of_on_puter: `পিউটার ডটকমে '%%' এর একটি অনুলিপি পান!`, + get_copy_link: "কপি লিংক নিন", + hide_all_windows: "সমস্ত উইন্ডো লুকান", + home: "হোম", + html_document: "এইচটিএমএল ডকুমেন্ট", + hue: "হিউ", + image: "ছবি", + incorrect_password: "ভুল পাসওয়ার্ড", + invite_link: "আমন্ত্রণ লিংক", + item: "আইটেম", + items_in_trash_cannot_be_renamed: `এই আইটেমটি নাম পরিবর্তন করা যাবে না কারণ এটি ট্র্যাশে রয়েছে। এই আইটেমটির নাম পরিবর্তন করতে, প্রথমে এটি ট্র্যাশ থেকে তুলে নিন।`, + jpeg_image: "জেপিইজি ইমেজ", + keep_in_taskbar: "টাস্কবারে রাখুন", + language: "ভাষা", + license: "লাইসেন্স", + lightness: "হালকালোত্ব", + link_copied: "লিংক কপি করা হয়েছে", + loading: "লোড হচ্ছে", + log_in: "লগ ইন করুন", + log_into_another_account_anyway: "অন্য অ্যাকাউন্টে লগ ইন করুন", + log_out: "লগ আউট", + looks_good: "ভাল দেখা যাচ্ছে!", + manage_sessions: "সেশন পরিচালনা করুন", + menubar_style: "মেনুবার স্টাইল", + menubar_style_desktop: "ডেস্কটপ", + menubar_style_system: "সিস্টেম", + menubar_style_window: "উইন্ডো", + modified: "পরিবর্তিত", + move: "চলুন", + moving_file: "ফাইল চলার পথে %%", + my_websites: "আমার ওয়েবসাইটগুলি", + name: "নাম", + name_cannot_be_empty: "নাম ফাঁকা রাখা যাবে না।", + name_cannot_contain_double_period: "নাম অবশ্যই '..' অক্ষর হতে পারে না।", + name_cannot_contain_period: "নাম অবশ্যই '.' অক্ষর হতে পারে না।", + name_cannot_contain_slash: "নাম '/' অক্ষর ধারণ করতে পারে না।", + name_must_be_string: "নামটি শুধুমাত্র একটি স্ট্রিং হতে পারে।", + name_too_long: `নাম %% অক্ষরের চেয়ে বেশি হতে পারে না।`, + new: "নতুন", + new_email: "নতুন ইমেল", + new_folder: "নতুন ফোল্ডার", + new_password: "নতুন পাসওয়ার্ড", + new_username: "নতুন ব্যবহারকারীর নাম", + no: "না", + no_dir_associated_with_site: "এই ঠিকানা সম্পর্কিত কোনও ডিরেক্টরি নেই।", + no_websites_published: + "আপনি এখনও কোনও ওয়েবসাইট প্রকাশ করেননি। শুরু করতে একটি ফোল্ডারে ক্লিক করুন।", + ok: "ঠিক আছে", + open: "খোলা", + open_in_new_tab: "নতুন ট্যাবে খুলুন", + open_in_new_window: "নতুন উইন্ডোয়ে খুলুন", + open_with: "দিয়ে খোলুন", + original_name: "মৌলিক নাম", + original_path: "মূল পথ", + oss_code_and_content: "ওপেন সোর্স সফটওয়্যার এবং কন্টেন্ট", + password: "পাসওয়ার্ড", + password_changed: "পাসওয়ার্ড পরিবর্তন করা হয়েছে।", + password_recovery_rate_limit: "আপনি আমাদের রেকভারি সিস্টেমে প্রতি দিনে অধিকতর পাঁচবার ব্যবহার করতে পারবেন না। দয়া করে কয়েক ঘণ্টা অপেক্ষা করুন এবং পুনরায় চেষ্টা করুন।", + password_recovery_sent: "আপনার পাসওয়ার্ড পুনরুদ্ধারের জন্য নির্দেশানুযায়ী একটি ইমেল পাঠানো হয়েছে।", + password_requirements: "পাসওয়ার্ড অবশ্যই অবশ্যই ৮ অক্ষরের বৃহত্তর হতে হবে।", + password_reset: "পাসওয়ার্ড রিসেট করুন", + password_reset_confirmation: "পাসওয়ার্ড সেট করতে নীচের ফর্মটি পূরণ করুন।", + password_reset_request_expired: "আপনার পাসওয়ার্ড রিসেট রিকোয়েস্টের মেয়াদ শেষ হয়ে গেছে। দয়া করে পুনরায় চেষ্টা করুন।", + password_reset_sent: "পাসওয়ার্ড রিসেট রিকোয়েস্ট সফলভাবে প্রেরিত হয়েছে। আপনার ইনবক্স পরীক্ষা করুন এবং নির্দেশানুযায়ী প্রক্রিয়াটি সম্পন্ন করতে।", + password_update_success: "পাসওয়ার্ড সফলভাবে আপডেট হয়েছে!", + passwords_do_not_match: "পাসওয়ার্ড মিলে না", + paste: "পেস্ট", + paste_into_folder: "ফোল্ডারে পেস্ট করুন", + path: "পথ", + personalization: "ব্যক্তিগতীকরণ", + pick_name_for_website: "আপনার ওয়েবসাইটের জন্য নাম নির্বাচন করুন:", + picture: "ছবি", + pictures: "চিত্র", + plural_suffix: "গুলি", + powered_by_puter_js: `{{link=docs}}Puter.js{{/link}} দ্বারা প্রচালিত`, + preparing: "প্রস্তুতি চলছে...", + preparing_for_upload: "আপলোডের জন্য প্রস্তুতি চলছে...", + print: "প্রিন্ট", + privacy: "গোপনীয়তা", + proceed_to_login: "লগইনে অগ্রসর হোন", + proceed_with_account_deletion: "অ্যাকাউন্ট মোছার সাথে অগ্রসর হন", + process_status_initializing: "আসন্নকরণ চলছে", + process_status_running: "চলছে", + process_type_app: "অ্যাপ", + process_type_init: "প্রাথমিকতা", + process_type_ui: "ইউআই", + properties: "বৈশিষ্ট্য", + public: "পাবলিক", + publish: "প্রকাশ করুন", + publish_as_website: "ওয়েবসাইট হিসাবে প্রকাশ করুন", + puter_description: `Puter হল একটি গোপনীয়তা-প্রথম ব্যক্তিগত ক্লাউড, যেখানে আপনার সমস্ত ফাইল, অ্যাপ্লিকেশন এবং গেম একটি নিরাপদ জায়গায় রাখা হয়, যেখান থেকে সর্বক্ষণে অ্যাক্সেস করা যায়।`, + reading_file: "%strong% পড়া হচ্ছে", + recent: "সাম্প্রতিক", + recommended: "অনুমোদিত", + recover_password: "পাসওয়ার্ড পুনরুদ্ধার করুন", + refer_friends_c2a: "Puter তে অ্যাকাউন্ট তৈরি এবং নিশ্চিতকরণ করে একটি বন্ধুর প্রতি 1 জিবি পান। আপনার বন্ধুও 1 জিবি পাবে!", + refer_friends_social_media_c2a: `Puter.com এ 1 GB বিনামূল্যের সংরক্ষণ পান!`, + refresh: "রিফ্রেশ", + release_address_confirmation: `আপনি কি নিশ্চিত যে আপনি এই ঠিকানা রিলিজ করতে চান?`, + remove_from_taskbar: "টাস্কবার থেকে সরান", + rename: "পুনঃনামকরণ", + repeat: "পুনরাবৃত্তি", + replace: "প্রতিস্থাপন", + replace_all: "সমস্ত প্রতিস্থাপন", + resend_confirmation_code: "পুনরায় নিশ্চিতকরণ কোড প্রেরণ করুন", + reset_colors: "রঙ পুনঃনির্ধারণ করুন", + restart_puter_confirm: "আপনি কি নিশ্চিত যে Puter পুনরায় চালু করতে চান?", + restore: "পুনরুদ্ধার", + save: "সংরক্ষণ করুন", + saturation: "সম্পৃক্তি", + save_account: "অ্যাকাউন্ট সংরক্ষণ করুন", + save_account_to_get_copy_link: "অগ্রসর হতে অ্যাকাউন্ট তৈরি করুন।", + save_account_to_publish: "অগ্রসর হতে অ্যাকাউন্ট তৈরি করুন।", + save_session: "সেশন সংরক্ষণ করুন", + save_session_c2a: "আপনার বর্তমান সেশনটি সংরক্ষণ করতে একটি অ্যাকাউন্ট তৈরি করুন এবং আপনার কাজ হারাতে হবেনা।", + scan_qr_c2a: "অন্যান্য ডিভাইস থেকে এই সেশনে লগইন করতে নীচের কোডটি স্ক্যান করুন", + scan_qr_2fa: "আপনার প্রামাণিকতা অ্যাপ্লিকেশন দিয়ে QR কোডটি স্ক্যান করুন", + scan_qr_generic: "আপনার ফোন বা অন্য ডিভাইস ব্যবহার করে এই QR কোড স্ক্যান করুন", + search: "অনুসন্ধান", + seconds: "সেকেন্ড", + security: "নিরাপত্তা", + select: "নির্বাচন করুন", + selected: "নির্বাচিত", + select_color: "রঙ নির্বাচন করুন…", + sessions: "সেশনগুলি", + send: "প্রেরণ করুন", + send_password_recovery_email: "পাসওয়ার্ড পুনরুদ্ধারের ইমেল প্রেরণ করুন", + session_saved: "অ্যাকাউন্ট তৈরি করার জন্য ধন্যবাদ। এই সেশনটি সংরক্ষিত হয়েছে।", + settings: "সেটিংস", + set_new_password: "নতুন পাসওয়ার্ড সেট করুন", + share: "ভাগাভাগি করুন", + share_to: "শেয়ার করুন", + share_with: "সঙ্গে ভাগাভাগি করুন:", + shortcut_to: "শর্টকাট", + show_all_windows: "সমস্ত উইন্ডো দেখান", + show_hidden: "লুকানো দেখান", + sign_in_with_puter: "Puter দিয়ে সাইন ইন করুন", + sign_up: "নিবন্ধন করুন", + signing_in: "সাইন ইন হচ্ছে...", + size: "আকার", + skip: "পার যান", + something_went_wrong: "কিছু সমস্যা হয়েছে।", + sort_by: "অনুযায়ী সাজান", + start: "শুরু", + status: "অবস্থা", + storage_usage: "স্টোরেজ ব্যবহার", + storage_puter_used: "Puter দ্বারা ব্যবহৃত", + taking_longer_than_usual: "স্বাভাবিক চেয়ে বেশি সময় নিচ্ছে। অনুগ্রহ করে অপেক্ষা করুন...", + task_manager: "টাস্ক ম্যানেজার", + taskmgr_header_name: "নাম", + taskmgr_header_status: "অবস্থা", + taskmgr_header_type: "ধরণ", + terms: "শর্তাবলী", + text_document: "পাঠ্য নথি", + tos_fineprint: `‘ফ্রি অ্যাকাউন্ট তৈরি করুন’ ক্লিক করে আপনি Puter-এর {{link=terms}}সেবা শর্ত{{/link}} এবং {{link=privacy}}গোপনীয়তা নীতি{{/link}} এর সাথে সম্মত হন।`, + transparency: "স্বচ্ছতা", + trash: "আবর্জনা", + two_factor: "দুটি ফ্যাক্টর প্রমাণীকরণ", + two_factor_disabled: "2FA অক্ষম", + two_factor_enabled: "2FA সক্ষম", + type: "ধরণ", + type_confirm_to_delete_account: "অ্যাকাউন্ট মোছার জন্য 'অনুমোদন' টাইপ করুন।", + ui_colors: "ইউআই রঙ", + ui_manage_sessions: "সেশন ম্যানেজার", + ui_revoke: "প্রত্যাহার করুন", + undo: "আনডো", + unlimited: "অসীম", + unzip: "আনজিপ", + upload: "আপলোড", + upload_here: "এখানে আপলোড করুন", + usage: "ব্যবহার", + username: "ব্যবহারকারীর নাম", + username_changed: "ব্যবহারকারীর নাম সফলভাবে আপডেট হয়েছে।", + username_required: "ব্যবহারকারীর নাম প্রয়োজন।", + versions: "সংস্করণ", + videos: "ভিডিও", + visibility: "দৃশ্যমানতা", + yes: "হ্যাঁ", + yes_release_it: "হ্যাঁ, এটি রিলিজ করুন", + you_have_been_referred_to_puter_by_a_friend: "আপনাকে একটি বন্ধু দ্বারা Puter এ উল্লিখিত করা হয়েছে!", + zip: "জিপ", + zipping_file: "%strong% জিপিং হচ্ছে", -export default bn; \ No newline at end of file + // === 2FA Setup === + setup2fa_1_step_heading: "আপনার প্রামাণিকতা অ্যাপ খুলুন", + setup2fa_1_instructions: ` + আপনি যেকোনো প্রামাণিকতা অ্যাপ ব্যবহার করতে পারেন যা Time-based One-Time Password (TOTP) প্রোটোকল সমর্থন করে। + অনেক বিকল্প রয়েছে, তবে যদি আপনি নিশ্চিত না হন + Authy + একটি ভালো পছন্দ Android এবং iOS এর জন্য। + `, + setup2fa_2_step_heading: "QR কোড স্ক্যান করুন", + setup2fa_3_step_heading: "6-টি অংকের কোড লিখুন", + setup2fa_4_step_heading: "আপনার পুনরুদ্ধার কোড কপি করুন", + setup2fa_4_instructions: ` + এই পুনরুদ্ধার কোডগুলি আপনার অ্যাকাউন্টে অ্যাক্সেস পাওয়ার একমাত্র উপায় যদি আপনি আপনার ফোন হারান বা আপনার প্রামাণিকতা অ্যাপ ব্যবহার করতে না পারেন। + নিশ্চিত করুন যে আপনি তাদের একটি নিরাপদ জায়গায় সংরক্ষণ করেছেন। + `, + setup2fa_5_step_heading: "2FA সেটআপ নিশ্চিত করুন", + setup2fa_5_confirmation_1: + "আমি আমার পুনরুদ্ধার কোডগুলি একটি নিরাপদ অবস্থানে সংরক্ষণ করেছি", + setup2fa_5_confirmation_2: "আমি 2FA সক্ষম করার জন্য প্রস্তুত", + setup2fa_5_button: "2FA সক্ষম করুন", + + login2fa_otp_title: "2FA কোড লিখুন", + login2fa_otp_instructions: + "আপনার প্রামাণিকতা অ্যাপ থেকে 6-টি অংকের কোড লিখুন।", + login2fa_recovery_title: "একটি পুনরুদ্ধার কোড লিখুন", + login2fa_recovery_instructions: + "আপনার অ্যাকাউন্টে অ্যাক্সেস পাওয়ার জন্য আপনার পুনরুদ্ধার কোডগুলির মধ্য থেকে একটি লিখুন।", + login2fa_use_recovery_code: "একটি পুনরুদ্ধার কোড ব্যবহার করুন", + login2fa_recovery_back: "পিছনে", + login2fa_recovery_placeholder: "XXXXXXXX", + }, +}; + +export default bn; From cff488f4f4378ca6c7568a585a665f2a3b87b89c Mon Sep 17 00:00:00 2001 From: Waheed Uddin Ahmed Date: Thu, 11 Jul 2024 06:46:34 +0600 Subject: [PATCH 0516/2119] Update bn.js file formatting --- src/gui/src/i18n/translations/bn.js | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 6d81199daf..eb9a79a73a 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -183,8 +183,7 @@ const bn = { new_username: "নতুন ব্যবহারকারীর নাম", no: "না", no_dir_associated_with_site: "এই ঠিকানা সম্পর্কিত কোনও ডিরেক্টরি নেই।", - no_websites_published: - "আপনি এখনও কোনও ওয়েবসাইট প্রকাশ করেননি। শুরু করতে একটি ফোল্ডারে ক্লিক করুন।", + no_websites_published: "আপনি এখনও কোনও ওয়েবসাইট প্রকাশ করেননি। শুরু করতে একটি ফোল্ডারে ক্লিক করুন।", ok: "ঠিক আছে", open: "খোলা", open_in_new_tab: "নতুন ট্যাবে খুলুন", @@ -337,17 +336,15 @@ const bn = { নিশ্চিত করুন যে আপনি তাদের একটি নিরাপদ জায়গায় সংরক্ষণ করেছেন। `, setup2fa_5_step_heading: "2FA সেটআপ নিশ্চিত করুন", - setup2fa_5_confirmation_1: - "আমি আমার পুনরুদ্ধার কোডগুলি একটি নিরাপদ অবস্থানে সংরক্ষণ করেছি", + setup2fa_5_confirmation_1: "আমি আমার পুনরুদ্ধার কোডগুলি একটি নিরাপদ অবস্থানে সংরক্ষণ করেছি", setup2fa_5_confirmation_2: "আমি 2FA সক্ষম করার জন্য প্রস্তুত", setup2fa_5_button: "2FA সক্ষম করুন", + // === 2FA Login === login2fa_otp_title: "2FA কোড লিখুন", - login2fa_otp_instructions: - "আপনার প্রামাণিকতা অ্যাপ থেকে 6-টি অংকের কোড লিখুন।", + login2fa_otp_instructions: "আপনার প্রামাণিকতা অ্যাপ থেকে 6-টি অংকের কোড লিখুন।", login2fa_recovery_title: "একটি পুনরুদ্ধার কোড লিখুন", - login2fa_recovery_instructions: - "আপনার অ্যাকাউন্টে অ্যাক্সেস পাওয়ার জন্য আপনার পুনরুদ্ধার কোডগুলির মধ্য থেকে একটি লিখুন।", + login2fa_recovery_instructions: "আপনার অ্যাকাউন্টে অ্যাক্সেস পাওয়ার জন্য আপনার পুনরুদ্ধার কোডগুলির মধ্য থেকে একটি লিখুন।", login2fa_use_recovery_code: "একটি পুনরুদ্ধার কোড ব্যবহার করুন", login2fa_recovery_back: "পিছনে", login2fa_recovery_placeholder: "XXXXXXXX", From f7d15bae41f338def6c4a32f29240db654a9c661 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 11 Jul 2024 16:50:09 -0400 Subject: [PATCH 0517/2119] refactor(backend): rename traits to features --- src/backend/src/filesystem/batch/commands.js | 6 +++--- .../src/filesystem/hl_operations/hl_mkdir.js | 8 ++++---- .../src/filesystem/hl_operations/hl_write.js | 6 +++--- .../filesystem/storage/DatabaseFSEntryService.js | 6 +++--- src/backend/src/om/IdentifierUtil.js | 6 +++--- src/backend/src/om/definitions/Mapping.js | 6 +++--- src/backend/src/om/definitions/PropType.js | 6 +++--- src/backend/src/om/definitions/Property.js | 6 +++--- src/backend/src/om/entitystorage/BaseES.js | 6 +++--- src/backend/src/om/entitystorage/Entity.js | 6 +++--- src/backend/src/om/entitystorage/SQLES.js | 6 +++--- src/backend/src/om/query/query.js | 6 +++--- src/backend/src/services/EntityStoreService.js | 2 +- src/backend/src/services/OperationTraceService.js | 14 +++++++------- src/backend/src/services/auth/PermissionService.js | 2 +- src/backend/src/services/sla/RateLimitService.js | 6 +++--- ...MethodsTrait.js => AssignableMethodsFeature.js} | 4 ++-- ...yncProviderTrait.js => AsyncProviderFeature.js} | 14 +++++++------- ...ContextAwareTrait.js => ContextAwareFeature.js} | 4 ++-- .../src/traits/{OtelTrait.js => OtelFeature.js} | 6 +++--- .../src/traits/{SyncTrait.js => SyncFeature.js} | 4 ++-- ...nstructorTrait.js => WeakConstructorFeature.js} | 4 ++-- src/puter-js-common/src/AdvancedBase.js | 10 +++++----- .../src/bases/{TraitBase.js => FeatureBase.js} | 12 ++++++------ .../NodeModuleDIFeature.js} | 2 +- .../PropertiesFeature.js} | 0 26 files changed, 79 insertions(+), 79 deletions(-) rename src/backend/src/traits/{AssignableMethodsTrait.js => AssignableMethodsFeature.js} (94%) rename src/backend/src/traits/{AsyncProviderTrait.js => AsyncProviderFeature.js} (88%) rename src/backend/src/traits/{ContextAwareTrait.js => ContextAwareFeature.js} (94%) rename src/backend/src/traits/{OtelTrait.js => OtelFeature.js} (97%) rename src/backend/src/traits/{SyncTrait.js => SyncFeature.js} (97%) rename src/backend/src/traits/{WeakConstructorTrait.js => WeakConstructorFeature.js} (94%) rename src/puter-js-common/src/bases/{TraitBase.js => FeatureBase.js} (82%) rename src/puter-js-common/src/{traits/NodeModuleDITrait.js => features/NodeModuleDIFeature.js} (99%) rename src/puter-js-common/src/{traits/PropertiesTrait.js => features/PropertiesFeature.js} (100%) diff --git a/src/backend/src/filesystem/batch/commands.js b/src/backend/src/filesystem/batch/commands.js index ba282449cd..0385076a4e 100644 --- a/src/backend/src/filesystem/batch/commands.js +++ b/src/backend/src/filesystem/batch/commands.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ const { AdvancedBase } = require("@heyputer/puter-js-common"); -const { AsyncProviderTrait } = require("../../traits/AsyncProviderTrait"); +const { AsyncProviderFeature } = require("../../traits/AsyncProviderFeature"); const { HLMkdir, QuickMkdir } = require("../hl_operations/hl_mkdir"); const { Context } = require("../../util/context"); const { HLWrite } = require("../hl_operations/hl_write"); @@ -32,8 +32,8 @@ const { HLRemove } = require("../hl_operations/hl_remove"); class BatchCommand extends AdvancedBase { - static TRAITS = [ - new AsyncProviderTrait(), + static FEATURES = [ + new AsyncProviderFeature(), ] static async run (executor, parameters) { const instance = new this(); diff --git a/src/backend/src/filesystem/hl_operations/hl_mkdir.js b/src/backend/src/filesystem/hl_operations/hl_mkdir.js index 7a36924435..a4cbdb480e 100644 --- a/src/backend/src/filesystem/hl_operations/hl_mkdir.js +++ b/src/backend/src/filesystem/hl_operations/hl_mkdir.js @@ -26,8 +26,8 @@ const StringParam = require('../../api/filesystem/StringParam'); const FlagParam = require("../../api/filesystem/FlagParam"); const UserParam = require('../../api/filesystem/UserParam'); const FSNodeContext = require('../FSNodeContext'); -const { ContextAwareTrait } = require('../../traits/ContextAwareTrait'); -const { OtelTrait } = require('../../traits/OtelTrait'); +const { ContextAwareFeature } = require('../../traits/ContextAwareFeature'); +const { OtelFeature } = require('../../traits/OtelFeature'); const { HLFilesystemOperation } = require('./definitions'); const { is_valid_path } = require('../validation'); const { HLRemove } = require('./hl_remove'); @@ -249,8 +249,8 @@ class HLMkdir extends HLFilesystemOperation { parent_directories_created: () => [], } - static TRAITS = [ - new OtelTrait([ + static FEATURES = [ + new OtelFeature([ '_get_existing_parent', '_create_parents', ]), diff --git a/src/backend/src/filesystem/hl_operations/hl_write.js b/src/backend/src/filesystem/hl_operations/hl_write.js index dfccef46dd..b6b439ac55 100644 --- a/src/backend/src/filesystem/hl_operations/hl_write.js +++ b/src/backend/src/filesystem/hl_operations/hl_write.js @@ -33,7 +33,7 @@ const { HLFilesystemOperation } = require("./definitions"); const { MkTree } = require("./hl_mkdir"); const { Actor } = require("../../services/auth/Actor"); -class WriteCommonTrait { +class WriteCommonFeature { install_in_instance (instance) { instance._verify_size = async function () { if ( @@ -84,8 +84,8 @@ class HLWrite extends HLFilesystemOperation { - create shortcuts ` - static TRAITS = [ - new WriteCommonTrait(), + static FEATURES = [ + new WriteCommonFeature(), ] static PARAMETERS = { diff --git a/src/backend/src/filesystem/storage/DatabaseFSEntryService.js b/src/backend/src/filesystem/storage/DatabaseFSEntryService.js index b997ba2be9..df84e69d73 100644 --- a/src/backend/src/filesystem/storage/DatabaseFSEntryService.js +++ b/src/backend/src/filesystem/storage/DatabaseFSEntryService.js @@ -21,7 +21,7 @@ const { id2path } = require("../../helpers"); const { PuterPath } = require("../lib/PuterPath"); const { NodeUIDSelector } = require("../node/selectors"); -const { OtelTrait } = require("../../traits/OtelTrait"); +const { OtelFeature } = require("../../traits/OtelFeature"); const { Context } = require("../../util/context"); const { DB_WRITE } = require("../../services/database/consts"); @@ -195,8 +195,8 @@ class DatabaseFSEntryService extends AdvancedBase { static STATUS_READY = {}; static STATUS_RUNNING_JOB = {}; - static TRAITS = [ - new OtelTrait([ + static FEATURES = [ + new OtelFeature([ 'insert', 'update', 'delete', diff --git a/src/backend/src/om/IdentifierUtil.js b/src/backend/src/om/IdentifierUtil.js index 31376f91c6..f70245d1dc 100644 --- a/src/backend/src/om/IdentifierUtil.js +++ b/src/backend/src/om/IdentifierUtil.js @@ -17,13 +17,13 @@ * along with this program. If not, see . */ const { AdvancedBase } = require("@heyputer/puter-js-common"); -const { WeakConstructorTrait } = require("../traits/WeakConstructorTrait"); +const { WeakConstructorFeature } = require("../traits/WeakConstructorFeature"); const { Eq, And } = require("./query/query"); const { Entity } = require("./entitystorage/Entity"); class IdentifierUtil extends AdvancedBase { - static TRAITS = [ - new WeakConstructorTrait(), + static FEATURES = [ + new WeakConstructorFeature(), ] async detect_identifier (object) { diff --git a/src/backend/src/om/definitions/Mapping.js b/src/backend/src/om/definitions/Mapping.js index d066c69cbe..1f6bc89910 100644 --- a/src/backend/src/om/definitions/Mapping.js +++ b/src/backend/src/om/definitions/Mapping.js @@ -18,7 +18,7 @@ */ const { AdvancedBase } = require("@heyputer/puter-js-common"); const { instance_ } = require("../../monitor/PerformanceMonitor"); -const { WeakConstructorTrait } = require("../../traits/WeakConstructorTrait"); +const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature"); const { Property } = require("./Property"); const { Entity } = require("../entitystorage/Entity"); const FSNodeContext = require("../../filesystem/FSNodeContext"); @@ -29,13 +29,13 @@ const FSNodeContext = require("../../filesystem/FSNodeContext"); * Both wrapping and registering are done by RegistrantService. */ class Mapping extends AdvancedBase { - static TRAITS = [ + static FEATURES = [ // Whenever you can override something, it's reasonable to want // to pull the desired implementation from somewhere else to // avoid repeating yourself. Class constructors are one of a few // examples where this is typically not possible. // However, javascript is magic, and we do what we want. - new WeakConstructorTrait(), + new WeakConstructorFeature(), ] static create (context, data) { diff --git a/src/backend/src/om/definitions/PropType.js b/src/backend/src/om/definitions/PropType.js index 94f9fed5d4..b4a964fd7a 100644 --- a/src/backend/src/om/definitions/PropType.js +++ b/src/backend/src/om/definitions/PropType.js @@ -17,11 +17,11 @@ * along with this program. If not, see . */ const { AdvancedBase } = require("@heyputer/puter-js-common"); -const { WeakConstructorTrait } = require("../../traits/WeakConstructorTrait"); +const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature"); class PropType extends AdvancedBase { - static TRAITS = [ - new WeakConstructorTrait(), + static FEATURES = [ + new WeakConstructorFeature(), ] static create (context, data, k) { diff --git a/src/backend/src/om/definitions/Property.js b/src/backend/src/om/definitions/Property.js index 85e972168e..76c11ea21b 100644 --- a/src/backend/src/om/definitions/Property.js +++ b/src/backend/src/om/definitions/Property.js @@ -17,11 +17,11 @@ * along with this program. If not, see . */ const { AdvancedBase } = require("@heyputer/puter-js-common"); -const { WeakConstructorTrait } = require("../../traits/WeakConstructorTrait"); +const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature"); class Property extends AdvancedBase { - static TRAITS = [ - new WeakConstructorTrait(), + static FEATURES = [ + new WeakConstructorFeature(), ] static create (context, name, descriptor) { diff --git a/src/backend/src/om/entitystorage/BaseES.js b/src/backend/src/om/entitystorage/BaseES.js index 416386526e..a91d4e90db 100644 --- a/src/backend/src/om/entitystorage/BaseES.js +++ b/src/backend/src/om/entitystorage/BaseES.js @@ -17,15 +17,15 @@ * along with this program. If not, see . */ const { AdvancedBase } = require("@heyputer/puter-js-common"); -const { WeakConstructorTrait } = require("../../traits/WeakConstructorTrait"); +const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature"); const { Context } = require("../../util/context"); /** * BaseES is a base class for Entity Store classes. */ class BaseES extends AdvancedBase { - static TRAITS = [ - new WeakConstructorTrait(), + static FEATURES = [ + new WeakConstructorFeature(), ] // Default implementations diff --git a/src/backend/src/om/entitystorage/Entity.js b/src/backend/src/om/entitystorage/Entity.js index 57d245b587..f02bba8c1e 100644 --- a/src/backend/src/om/entitystorage/Entity.js +++ b/src/backend/src/om/entitystorage/Entity.js @@ -17,11 +17,11 @@ * along with this program. If not, see . */ const { AdvancedBase } = require("@heyputer/puter-js-common"); -const { WeakConstructorTrait } = require("../../traits/WeakConstructorTrait"); +const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature"); class Entity extends AdvancedBase { - static TRAITS = [ - new WeakConstructorTrait(), + static FEATURES = [ + new WeakConstructorFeature(), ] constructor (args) { diff --git a/src/backend/src/om/entitystorage/SQLES.js b/src/backend/src/om/entitystorage/SQLES.js index b7f58d1aa5..0a87f5e6c0 100644 --- a/src/backend/src/om/entitystorage/SQLES.js +++ b/src/backend/src/om/entitystorage/SQLES.js @@ -21,14 +21,14 @@ const { BaseES } = require("./BaseES"); const APIError = require("../../api/APIError"); const { Entity } = require("./Entity"); -const { WeakConstructorTrait } = require("../../traits/WeakConstructorTrait"); +const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature"); const { And, Or, Eq, Like, Null, Predicate, PredicateUtil, IsNotNull } = require("../query/query"); const { DB_WRITE } = require("../../services/database/consts"); class RawCondition extends AdvancedBase { // properties: sql:string, values:any[] - static TRAITS = [ - new WeakConstructorTrait(), + static FEATURES = [ + new WeakConstructorFeature(), ] } diff --git a/src/backend/src/om/query/query.js b/src/backend/src/om/query/query.js index 7cf6265959..80d81b384d 100644 --- a/src/backend/src/om/query/query.js +++ b/src/backend/src/om/query/query.js @@ -17,11 +17,11 @@ * along with this program. If not, see . */ const { AdvancedBase } = require("@heyputer/puter-js-common"); -const { WeakConstructorTrait } = require("../../traits/WeakConstructorTrait"); +const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature"); class Predicate extends AdvancedBase { - static TRAITS = [ - new WeakConstructorTrait(), + static FEATURES = [ + new WeakConstructorFeature(), ] } diff --git a/src/backend/src/services/EntityStoreService.js b/src/backend/src/services/EntityStoreService.js index e546262cc9..8addef7934 100644 --- a/src/backend/src/services/EntityStoreService.js +++ b/src/backend/src/services/EntityStoreService.js @@ -40,7 +40,7 @@ class EntityStoreService extends BaseService { }); } - // TODO: can replace these with MethodProxyTrait + // TODO: can replace these with MethodProxyFeature async create (entity) { return await this.upstream.upsert(entity, { old_entity: null }); } diff --git a/src/backend/src/services/OperationTraceService.js b/src/backend/src/services/OperationTraceService.js index d038f7f80e..fd86c8f41f 100644 --- a/src/backend/src/services/OperationTraceService.js +++ b/src/backend/src/services/OperationTraceService.js @@ -18,10 +18,10 @@ */ const { AdvancedBase } = require("@heyputer/puter-js-common"); const { Context } = require("../util/context"); -const { ContextAwareTrait } = require("../traits/ContextAwareTrait"); -const { OtelTrait } = require("../traits/OtelTrait"); +const { ContextAwareFeature } = require("../traits/ContextAwareFeature"); +const { OtelFeature } = require("../traits/OtelFeature"); const APIError = require("../api/APIError"); -const { AssignableMethodsTrait } = require("../traits/AssignableMethodsTrait"); +const { AssignableMethodsFeature } = require("../traits/AssignableMethodsFeature"); const CONTEXT_KEY = Context.make_context_key('operation-trace'); @@ -220,10 +220,10 @@ class OperationTraceService { } class BaseOperation extends AdvancedBase { - static TRAITS = [ - new ContextAwareTrait(), - new OtelTrait(['run']), - new AssignableMethodsTrait(), + static FEATURES = [ + new ContextAwareFeature(), + new OtelFeature(['run']), + new AssignableMethodsFeature(), ] async run (values) { diff --git a/src/backend/src/services/auth/PermissionService.js b/src/backend/src/services/auth/PermissionService.js index 694ceff3b1..b18d1a2a50 100644 --- a/src/backend/src/services/auth/PermissionService.js +++ b/src/backend/src/services/auth/PermissionService.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ const { get_user, get_app } = require("../../helpers"); -const { AssignableMethodsTrait } = require("../../traits/AssignableMethodsTrait"); +const { AssignableMethodsFeature } = require("../../traits/AssignableMethodsFeature"); const { Context } = require("../../util/context"); const BaseService = require("../BaseService"); const { DB_WRITE } = require("../database/consts"); diff --git a/src/backend/src/services/sla/RateLimitService.js b/src/backend/src/services/sla/RateLimitService.js index 632877f301..ecaf7a30f7 100644 --- a/src/backend/src/services/sla/RateLimitService.js +++ b/src/backend/src/services/sla/RateLimitService.js @@ -20,7 +20,7 @@ const { AdvancedBase } = require("@heyputer/puter-js-common"); const APIError = require("../../api/APIError"); const { Context } = require("../../util/context"); const BaseService = require("../BaseService"); -const { SyncTrait } = require("../../traits/SyncTrait"); +const { SyncFeature } = require("../../traits/SyncFeature"); const { DB_WRITE } = require("../database/consts"); const ts_to_sql = (ts) => Math.floor(ts / 1000); @@ -31,8 +31,8 @@ class RateLimitService extends BaseService { kv: globalThis.kv, } - static TRAITS = [ - new SyncTrait([ + static FEATURES = [ + new SyncFeature([ 'check_and_increment', ]), ] diff --git a/src/backend/src/traits/AssignableMethodsTrait.js b/src/backend/src/traits/AssignableMethodsFeature.js similarity index 94% rename from src/backend/src/traits/AssignableMethodsTrait.js rename to src/backend/src/traits/AssignableMethodsFeature.js index 0730be46fa..39801851a1 100644 --- a/src/backend/src/traits/AssignableMethodsTrait.js +++ b/src/backend/src/traits/AssignableMethodsFeature.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -class AssignableMethodsTrait { +class AssignableMethodsFeature { install_in_instance (instance) { const methods = instance._get_merged_static_object('METHODS'); @@ -27,5 +27,5 @@ class AssignableMethodsTrait { } module.exports = { - AssignableMethodsTrait + AssignableMethodsFeature }; diff --git a/src/backend/src/traits/AsyncProviderTrait.js b/src/backend/src/traits/AsyncProviderFeature.js similarity index 88% rename from src/backend/src/traits/AsyncProviderTrait.js rename to src/backend/src/traits/AsyncProviderFeature.js index 280ac6cab6..28304320f9 100644 --- a/src/backend/src/traits/AsyncProviderTrait.js +++ b/src/backend/src/traits/AsyncProviderFeature.js @@ -16,18 +16,18 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -class AsyncProviderTrait { +class AsyncProviderFeature { install_in_instance (instance) { instance.valueListeners_ = {}; instance.valueFactories_ = {}; instance.values_ = {}; instance.rejections_ = {}; - instance.provideValue = AsyncProviderTrait.prototype.provideValue; - instance.rejectValue = AsyncProviderTrait.prototype.rejectValue; - instance.awaitValue = AsyncProviderTrait.prototype.awaitValue; - instance.onValue = AsyncProviderTrait.prototype.onValue; - instance.setFactory = AsyncProviderTrait.prototype.setFactory; + instance.provideValue = AsyncProviderFeature.prototype.provideValue; + instance.rejectValue = AsyncProviderFeature.prototype.rejectValue; + instance.awaitValue = AsyncProviderFeature.prototype.awaitValue; + instance.onValue = AsyncProviderFeature.prototype.onValue; + instance.setFactory = AsyncProviderFeature.prototype.setFactory; } provideValue (key, value) { @@ -116,5 +116,5 @@ class AsyncProviderTrait { } module.exports = { - AsyncProviderTrait + AsyncProviderFeature }; \ No newline at end of file diff --git a/src/backend/src/traits/ContextAwareTrait.js b/src/backend/src/traits/ContextAwareFeature.js similarity index 94% rename from src/backend/src/traits/ContextAwareTrait.js rename to src/backend/src/traits/ContextAwareFeature.js index e95cfc6e1a..ce5383f728 100644 --- a/src/backend/src/traits/ContextAwareTrait.js +++ b/src/backend/src/traits/ContextAwareFeature.js @@ -18,7 +18,7 @@ */ const { Context } = require("../util/context"); -class ContextAwareTrait { +class ContextAwareFeature { install_in_instance (instance) { instance.context = Context.get(); instance.x = instance.context; @@ -26,5 +26,5 @@ class ContextAwareTrait { } module.exports = { - ContextAwareTrait, + ContextAwareFeature, }; diff --git a/src/backend/src/traits/OtelTrait.js b/src/backend/src/traits/OtelFeature.js similarity index 97% rename from src/backend/src/traits/OtelTrait.js rename to src/backend/src/traits/OtelFeature.js index 422281e2b2..ecebb908d0 100644 --- a/src/backend/src/traits/OtelTrait.js +++ b/src/backend/src/traits/OtelFeature.js @@ -18,7 +18,7 @@ */ const { Context } = require("../util/context"); -class OtelTrait { +class OtelFeature { constructor (method_include_list) { this.method_include_list = method_include_list; } @@ -44,7 +44,7 @@ class OtelTrait { } } -class SyncOtelTrait { +class SyncOtelFeature { constructor (method_include_list) { this.method_include_list = method_include_list; } @@ -72,5 +72,5 @@ class SyncOtelTrait { } module.exports = { - OtelTrait + OtelFeature }; diff --git a/src/backend/src/traits/SyncTrait.js b/src/backend/src/traits/SyncFeature.js similarity index 97% rename from src/backend/src/traits/SyncTrait.js rename to src/backend/src/traits/SyncFeature.js index 7257ef5533..b88c5ca43c 100644 --- a/src/backend/src/traits/SyncTrait.js +++ b/src/backend/src/traits/SyncFeature.js @@ -18,7 +18,7 @@ */ const { Lock } = require("../util/promise"); -class SyncTrait { +class SyncFeature { constructor (method_include_list) { this.method_include_list = method_include_list; } @@ -37,5 +37,5 @@ class SyncTrait { } module.exports = { - SyncTrait, + SyncFeature, }; diff --git a/src/backend/src/traits/WeakConstructorTrait.js b/src/backend/src/traits/WeakConstructorFeature.js similarity index 94% rename from src/backend/src/traits/WeakConstructorTrait.js rename to src/backend/src/traits/WeakConstructorFeature.js index 8b3b653d2a..6e2d4eb974 100644 --- a/src/backend/src/traits/WeakConstructorTrait.js +++ b/src/backend/src/traits/WeakConstructorFeature.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -class WeakConstructorTrait { +class WeakConstructorFeature { install_in_instance(instance, { parameters }) { for ( const key in parameters ) { instance[key] = parameters[key]; @@ -25,5 +25,5 @@ class WeakConstructorTrait { } module.exports = { - WeakConstructorTrait, + WeakConstructorFeature, }; diff --git a/src/puter-js-common/src/AdvancedBase.js b/src/puter-js-common/src/AdvancedBase.js index 069e474aff..4732410ab4 100644 --- a/src/puter-js-common/src/AdvancedBase.js +++ b/src/puter-js-common/src/AdvancedBase.js @@ -19,12 +19,12 @@ // This doesn't go in ./bases because it logically depends on // both ./bases and ./traits, and ./traits depends on ./bases. -const { TraitBase } = require("./bases/TraitBase"); +const { FeatureBase } = require("./bases/FeatureBase"); -class AdvancedBase extends TraitBase { - static TRAITS = [ - require('./traits/NodeModuleDITrait'), - require('./traits/PropertiesTrait'), +class AdvancedBase extends FeatureBase { + static FEATURES = [ + require('./features/NodeModuleDIFeature'), + require('./features/PropertiesFeature'), ] } diff --git a/src/puter-js-common/src/bases/TraitBase.js b/src/puter-js-common/src/bases/FeatureBase.js similarity index 82% rename from src/puter-js-common/src/bases/TraitBase.js rename to src/puter-js-common/src/bases/FeatureBase.js index 62d3cc1e9f..ab7f4fb3ac 100644 --- a/src/puter-js-common/src/bases/TraitBase.js +++ b/src/puter-js-common/src/bases/FeatureBase.js @@ -18,11 +18,11 @@ */ const { BasicBase } = require("./BasicBase"); -class TraitBase extends BasicBase { +class FeatureBase extends BasicBase { constructor (parameters, ...a) { super(parameters, ...a); - for ( const trait of this.traits ) { - trait.install_in_instance( + for ( const feature of this.features ) { + feature.install_in_instance( this, { parameters: parameters || {}, @@ -31,11 +31,11 @@ class TraitBase extends BasicBase { } } - get traits () { - return this._get_merged_static_array('TRAITS'); + get features () { + return this._get_merged_static_array('FEATURES'); } } module.exports = { - TraitBase, + FeatureBase, }; diff --git a/src/puter-js-common/src/traits/NodeModuleDITrait.js b/src/puter-js-common/src/features/NodeModuleDIFeature.js similarity index 99% rename from src/puter-js-common/src/traits/NodeModuleDITrait.js rename to src/puter-js-common/src/features/NodeModuleDIFeature.js index d7952704c0..1888da774d 100644 --- a/src/puter-js-common/src/traits/NodeModuleDITrait.js +++ b/src/puter-js-common/src/features/NodeModuleDIFeature.js @@ -45,7 +45,7 @@ module.exports = { } instance.modules = modules; - + // This "require" function can shadow the real one so // that editor tools are aware of the modules that // are being used. diff --git a/src/puter-js-common/src/traits/PropertiesTrait.js b/src/puter-js-common/src/features/PropertiesFeature.js similarity index 100% rename from src/puter-js-common/src/traits/PropertiesTrait.js rename to src/puter-js-common/src/features/PropertiesFeature.js From ab74f1ee8daab3fe3f869b2e016f30ce865411e2 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 11 Jul 2024 17:13:49 -0400 Subject: [PATCH 0518/2119] release: v2.4.1 --- CHANGELOG.md | 32 +++++++++++++++++++++ package.json | 2 +- tools/gen-release-notes.js | 59 +++++++++++++++++++++++++++++++++----- 3 files changed, 85 insertions(+), 8 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 95e49d11f8..2eb896735c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,37 @@ # Changelog +## v2.4.1 (2024-07-11) + +### Puter + + +#### Features + +- update BR translation ([42a6b39](https://github.com/HeyPuter/puter/commit/42a6b3938a588b8b4d1bd976c37e9c6e58408c75)) +- JSON support for kv driver ([3ed7916](https://github.com/HeyPuter/puter/commit/3ed7916856f03eafbe0891f2ab39c34d20d2bd24)) + +#### Translations + +- Update bn.js file formatting ([cff488f](https://github.com/HeyPuter/puter/commit/cff488f4f4378ca6c7568a585a665f2a3b87b89c)) +- Issue#530 - Update bengali translations ([92abc99](https://github.com/HeyPuter/puter/commit/92abc9947f811f94f17a5ee5a4b73ee2b210900a)) +- Added missing Romanian translations. ([8440f56](https://github.com/HeyPuter/puter/commit/8440f566b91c9eb4f01addcb850061e3fbe3afc7)) +- Add 2FA Romanian translations ([473b651](https://github.com/HeyPuter/puter/commit/473b6512c697854e3f3badae1eb7b87742954da5)) +- Add Japanese Translation ([47ec74f](https://github.com/HeyPuter/puter/commit/47ec74f0aa6adb3952e6460909029a4acb0c3039)) +- Completing Italian translation based on English file ([f5a8ee1](https://github.com/HeyPuter/puter/commit/f5a8ee1c6ab950d62c90b6257791f026a508b4e4)) +- Completing Italian translation based on English file. ([a96abb5](https://github.com/HeyPuter/puter/commit/a96abb5793528d0dc56d75f95d771e1dcf5960d1)) +- Completing Arabic translation based on English file ([78a0ace](https://github.com/HeyPuter/puter/commit/78a0acea6980b6d491da4874edbd98e17c0d9577)) +- Update Arabic translations in src/gui/src/i18n/translations/ar.js to match English version in src/gui/src/i18n/translations/en.js ([fe5be7f](https://github.com/HeyPuter/puter/commit/fe5be7f3cf7f336730137293ba86a637e8d8591d)) +- Update Arabic translations in src/gui/src/i18n/translations/ar.js to match English version in src/gui/src/i18n/translations/en.js ([bffa192](https://github.com/HeyPuter/puter/commit/bffa192805216fc17045cd8d629f34784dca7f3f)) +- Ukrainian updated ([e61039f](https://github.com/HeyPuter/puter/commit/e61039faf409b0ad85c7513b0123f3f2e92ebe32)) +- Update ru.js issue #547 ([17145d0](https://github.com/HeyPuter/puter/commit/17145d0be6a9a1445947cc0c4bec8f16a475144c)) +- Russian translation fixed ([8836011](https://github.com/HeyPuter/puter/commit/883601142873f10d69c84874499065a7d29af054)) + +#### Bug Fixes + +- remove flag that breaks puter-js webpack ([7aadae5](https://github.com/HeyPuter/puter/commit/7aadae58ce1a51f925bf64c3d65ac1fa6971b164)) +- Improve `getMimeType` to remove trailing dot in the extension if preset ([535475b](https://github.com/HeyPuter/puter/commit/535475b3c36a37e3319ed067a24fb671790dcda3)) + + ## 2.4.0 (2024-07-08) diff --git a/package.json b/package.json index 4bca22575a..4ffb10390b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "puter.com", - "version": "1.0.0", + "version": "2.4.1", "author": "Puter Technologies Inc.", "license": "AGPL-3.0-only", "description": "Desktop environment in the browser!", diff --git a/tools/gen-release-notes.js b/tools/gen-release-notes.js index ed82b94baa..5f9b519714 100644 --- a/tools/gen-release-notes.js +++ b/tools/gen-release-notes.js @@ -21,17 +21,17 @@ import { simpleGit } from 'simple-git'; const REPO_URL = 'https://github.com/HeyPuter/puter'; const params = { - from: 'v2.3.0', + from: 'v2.4.0', // from: 'v2.4.0', - to: 'v2.5.0', - date: '2024-07-08', + to: 'v2.4.1', + date: '2024-07-11', }; const git = simpleGit(); const log = await git.log({ from: params.from }); const commits = log.all; -const CC_REGEX = /^([a-z]+)(\([a-z]+\))?:\s(.*)/; +const CC_REGEX = /^([a-z0-9]+)(\([a-z0-9]+\))?:\s(.*)/; const parse_conventional_commit = message => { const parts = CC_REGEX.exec(message); if ( ! parts ) return null; @@ -45,9 +45,12 @@ const types = { feat: { label: 'Features' }, + i18n: { + label: 'Translations' + }, fix: { label: 'Bug Fixes' - } + }, }; const scopes = { @@ -66,6 +69,9 @@ const scopes = { gui: { label: 'GUI' }, + tools: { + ignore: true, + }, }; const scope_aliases = { @@ -74,6 +80,40 @@ const scope_aliases = { parsely: 'phoenix', }; +const retro_prefixes_0 = { + i18n: [ + '883601142873f10d69c84874499065a7d29af054', + '17145d0be6a9a1445947cc0c4bec8f16a475144c', + 'e61039faf409b0ad85c7513b0123f3f2e92ebe32', + 'bffa192805216fc17045cd8d629f34784dca7f3f', + 'fe5be7f3cf7f336730137293ba86a637e8d8591d', + '78a0acea6980b6d491da4874edbd98e17c0d9577', + 'a96abb5793528d0dc56d75f95d771e1dcf5960d1', + 'f5a8ee1c6ab950d62c90b6257791f026a508b4e4', + '47ec74f0aa6adb3952e6460909029a4acb0c3039', + '473b6512c697854e3f3badae1eb7b87742954da5', + '8440f566b91c9eb4f01addcb850061e3fbe3afc7', + '92abc9947f811f94f17a5ee5a4b73ee2b210900a', + 'cff488f4f4378ca6c7568a585a665f2a3b87b89c', + + ], + fix: [ + '535475b3c36a37e3319ed067a24fb671790dcda3', + ], + doc: [ + '338004474f078a00608af1d0ebf8a7f9534bad28', + '6c4c73a9e85ff8eb5e7663dcce11f4d1f824032b', + ], +}; + +const retro_prefixes = {}; +for ( const prefix in retro_prefixes_0 ) { + for ( const commit_hash of retro_prefixes_0[prefix] ) { + console.log('PREFIX', commit_hash, prefix); + retro_prefixes[commit_hash] = prefix; + } +} + const data = {}; const ensure_scope = name => { if ( data[name] ) return; @@ -82,17 +122,22 @@ const ensure_scope = name => { }; for ( const commit of commits ) { + if ( retro_prefixes.hasOwnProperty(commit.hash) ) { + commit.message = retro_prefixes[commit.hash] + ': ' + + commit.message; + } const meta = parse_conventional_commit(commit.message); if ( ! meta ) continue; let scope = meta.scope ?? 'puter'; while ( scope in scope_aliases ) { scope = scope_aliases[scope]; } - ensure_scope(scope); if ( ! scopes[scope] ) { console.log(commit); throw new Error(`missing scope: ${scope}`); } + if ( scopes[scope].ignore ) continue; + ensure_scope(scope); if ( types.hasOwnProperty(meta.type) ) { data[scope][meta.type].push({ meta, commit }); @@ -108,7 +153,7 @@ for ( const scope_name in data ) { const type = types[type_name]; const items = scope[type_name]; if ( items.length == 0 ) continue; - s += `#### ${type.label}\n\n`; + s += `\n#### ${type.label}\n\n`; for ( const { meta, commit } of items ) { const shorthash = commit.hash.slice(0,7) s += `- ${meta.summary} ([${shorthash}](${REPO_URL}/commit/${commit.hash}))\n`; From 6a2fbc1925952ecceed741afe138270d1eeda7b7 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 11 Jul 2024 20:09:39 -0400 Subject: [PATCH 0519/2119] fix(security): hoist acl check in ll_read --- .../src/filesystem/ll_operations/ll_read.js | 35 +++++++++++-------- 1 file changed, 20 insertions(+), 15 deletions(-) diff --git a/src/backend/src/filesystem/ll_operations/ll_read.js b/src/backend/src/filesystem/ll_operations/ll_read.js index a133c74b35..e19782ddbd 100644 --- a/src/backend/src/filesystem/ll_operations/ll_read.js +++ b/src/backend/src/filesystem/ll_operations/ll_read.js @@ -26,6 +26,24 @@ const { buffer_to_stream } = require("../../util/streamutil"); const { TYPE_SYMLINK, TYPE_DIRECTORY } = require("../FSNodeContext"); const { LLFilesystemOperation } = require("./definitions"); +const dry_checks = [ + async function check_ACL_for_read (a) { + if ( a.get('no_acl') ) return; + const context = a.iget('context'); + const svc_acl = context.get('services').get('acl'); + const { fsNode, actor } = a.values(); + if ( ! await svc_acl.check(actor, fsNode, 'read') ) { + throw await svc_acl.get_safe_acl_error(actor, fsNode, 'read'); + } + }, + async function type_check_for_read (a) { + const fsNode = a.get('fsNode'); + if ( await fsNode.get('type') === TYPE_DIRECTORY ) { + throw APIError.create('cannot_read_a_directory'); + } + }, +]; + class LLRead extends LLFilesystemOperation { static METHODS = { _run: new Sequence({ @@ -39,12 +57,7 @@ class LLRead extends LLFilesystemOperation { throw APIError.create('subject_does_not_exist'); } }, - async function type_check_for_read (a) { - const fsNode = a.get('fsNode'); - if ( await fsNode.get('type') === TYPE_DIRECTORY ) { - throw APIError.create('cannot_read_a_directory'); - } - }, + ...dry_checks, async function resolve_symlink (a) { let fsNode = a.get('fsNode'); let type = await fsNode.get('type'); @@ -54,15 +67,7 @@ class LLRead extends LLFilesystemOperation { } a.set('fsNode', fsNode); }, - async function check_ACL_for_read (a) { - if ( a.get('no_acl') ) return; - const context = a.iget('context'); - const svc_acl = context.get('services').get('acl'); - const { fsNode, actor } = a.values(); - if ( ! await svc_acl.check(actor, fsNode, 'read') ) { - throw await svc_acl.get_safe_acl_error(actor, fsNode, 'read'); - } - }, + ...dry_checks, async function calculate_has_range (a) { const { offset, length } = a.values(); const fsNode = a.get('fsNode'); From 7b4e95139f2991f848685dc1f20f6ae389ce8e42 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 11 Jul 2024 17:24:57 -0700 Subject: [PATCH 0520/2119] Shorten Reddit link --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index d73d7a57eb..a59bc97215 100644 --- a/README.md +++ b/README.md @@ -85,7 +85,7 @@ Connect with the maintainers and community through these channels: - Bug report or feature request? Please [open an issue](https://github.com/HeyPuter/puter/issues/new/choose). - Discord: [https://discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) - X (Twitter): [https://x.com/HeyPuter](https://x.com/HeyPuter) -- Reddit: [https://www.reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- Reddit: [https://reddit.com/r/puter/](https://www.reddit.com/r/puter/) - Email maintainers at [hi@puter.com](mailto:hi@puter.com) We are always happy to help you with any questions you may have. Don't hesitate to ask! From e8f4c328bff5c36b95fe460b80803e12e619f8ee Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 11 Jul 2024 21:00:14 -0400 Subject: [PATCH 0521/2119] fix: read_only fields in ES --- src/backend/src/om/entitystorage/ValidationES.js | 5 ++++- src/backend/src/om/mappings/app.js | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/backend/src/om/entitystorage/ValidationES.js b/src/backend/src/om/entitystorage/ValidationES.js index affe7e4468..52cd2f9a9b 100644 --- a/src/backend/src/om/entitystorage/ValidationES.js +++ b/src/backend/src/om/entitystorage/ValidationES.js @@ -41,7 +41,10 @@ class ValidationES extends BaseES { console.log('OLD ENT', extra.old_entity); for ( const prop of Object.values(this.om.properties) ) { - if ( prop.descriptor.protected ) { + if ( + prop.descriptor.protected || + prop.descriptor.read_only + ) { await entity.del(prop.name); } } diff --git a/src/backend/src/om/mappings/app.js b/src/backend/src/om/mappings/app.js index ed9a0ab416..c9f9dc2c79 100644 --- a/src/backend/src/om/mappings/app.js +++ b/src/backend/src/om/mappings/app.js @@ -142,7 +142,7 @@ module.exports = { // SYSTEM godmode: { type: 'flag', - protected: true, + read_only: true, }, } } From ae04a09c9005bc0206c9960d6b8e4e52a2ed5555 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 11 Jul 2024 18:07:09 -0700 Subject: [PATCH 0522/2119] Take into account that `godmode` might be either integer or boolean --- src/gui/src/helpers/launch_app.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/helpers/launch_app.js b/src/gui/src/helpers/launch_app.js index d6dc6553fe..40a33d96a0 100644 --- a/src/gui/src/helpers/launch_app.js +++ b/src/gui/src/helpers/launch_app.js @@ -197,7 +197,7 @@ const launch_app = async (options)=>{ // In godmode, we add the super token to the iframe URL // so that the app can access everything. - if (app_info.godmode && app_info.godmode === 1){ + if (app_info.godmode && (app_info.godmode === true || app_info.godmode === 1)){ iframe_url.searchParams.append('puter.auth.token', window.auth_token); iframe_url.searchParams.append('puter.auth.username', window.user.username); } From 9afb1b78b81aab70ec80880f551b71792be3c32b Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 11 Jul 2024 18:36:29 -0700 Subject: [PATCH 0523/2119] Fix blackfortresslabs.com URL --- SECURITY-ACKNOWLEDGEMENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SECURITY-ACKNOWLEDGEMENTS.md b/SECURITY-ACKNOWLEDGEMENTS.md index 4ad8908df5..5702f03b47 100644 --- a/SECURITY-ACKNOWLEDGEMENTS.md +++ b/SECURITY-ACKNOWLEDGEMENTS.md @@ -3,5 +3,5 @@ We would like to thank the following security researchers for their responsible # 2024 -- Tim Suess: [GitHub](https://github.com/blackfortresslabs) | [Email](tim@blackfortresslabs.com) | [Website](blackfortresslabs.com) +- Tim Suess: [GitHub](https://github.com/blackfortresslabs) | [Email](tim@blackfortresslabs.com) | [Website](https://www.blackfortresslabs.com) - xyzeva: [Github](https://github.com/xyzeva) | [Email](mailto:xyzeva@riseup.net) | [Website](https://kibty.town/) From 3b8af7cc5c1be8ed67be827360bbfe0f0b5027e9 Mon Sep 17 00:00:00 2001 From: Narek Date: Sun, 14 Jul 2024 00:11:15 +0400 Subject: [PATCH 0524/2119] Update Armenian translation file --- src/gui/src/i18n/translations/hy.js | 267 +++++++++++++++++++++++----- 1 file changed, 225 insertions(+), 42 deletions(-) diff --git a/src/gui/src/i18n/translations/hy.js b/src/gui/src/i18n/translations/hy.js index e340f9cca3..cc5e0eab41 100644 --- a/src/gui/src/i18n/translations/hy.js +++ b/src/gui/src/i18n/translations/hy.js @@ -22,147 +22,330 @@ const hy = { english_name: "Armenian", code: "hy", dictionary: { + about: "Մեր մասին", + account: "Հաշիվ", + account_password: "Հաստատել հաշվի գաղտնաբառը", access_granted_to: "Մուտքը տրված է՝", add_existing_account: "Ավելացնել առկա հաշիվ", - all_fields_required: "Բոլոր դաշտերը պահանջվում են", + all_fields_required: "Բոլոր դաշտերը պարտադիր են", + allow: "Թույլատրել", apply: "Կիրառել", - ascending: "Աճման կարգով", + ascending: "Աճող", + associated_websites: "Կապված կայքեր", + auto_arrange: "Ավտոմատ դասավորել", background: "Ֆոն", browse: "Թերթել", cancel: "Չեղարկել", center: "Կենտրոն", - change_desktop_background: "Փոխել աշխատասեղանի ֆոնը", + change_desktop_background: "Փոխել աշխատասեղանի ֆոնը…", + change_email: "Փոխել էլ. փոստը", change_language: "Փոխել լեզուն", change_password: "Փոխել գաղտնաբառը", + change_ui_colors: "Փոխել UI գույները", change_username: "Փոխել օգտանունը", + close: "Փակել", close_all_windows: "Փակել բոլոր պատուհանները", + close_all_windows_confirm: "Վստա՞հ եք, որ ցանկանում եք փակել բոլոր պատուհանները:", + close_all_windows_and_log_out: "Փակել պատուհաններն ու դուրս գալ", + change_always_open_with: "Ցանկանու՞մ եք այս տեսակի ֆայլը միշտ բացել", color: "Գույն", - confirm_account_for_free_referral_storage_c2a: "Ստեղծեք հաշիվ և հաստատեք ձեր էլ․ հասցեն 1 ԳԲ անվճար պահեստ ստանալու համար: Ձեր ընկերը նույնպես կստանա 1 ԳԲ անվճար պահեստ:", + confirm: "Հաստատել", + confirm_2fa_setup: "Ես ավելացրել եմ կոդը իմ իսկորոշիչ հավելվածում", + confirm_2fa_recovery: "Ես պահել եմ վերականգնման կոդերը ապահով վայրում", + confirm_account_for_free_referral_storage_c2a: "Ստեղծեք հաշիվ և հաստատեք ձեր էլ. հասցեն 1 ԳԲ անվճար պահեստ ստանալու համար: Ձեր ընկերը նույնպես կստանա 1 ԳԲ անվճար պահեստ:", + confirm_code_generic_incorrect: "Սխալ կոդ:", + confirm_code_generic_too_many_requests: "Չափազանց շատ հարցումներ: Խնդրում ենք սպասել մի քանի րոպե:", + confirm_code_generic_submit: "Հաստատել կոդը", + confirm_code_generic_try_again: "Կրկին փորձեք", + confirm_code_generic_title: "Մուտքագրեք հաստատման կոդը", + confirm_code_2fa_instruction: "Մուտքագրեք 6 նիշանոց կոդը ձեր իսկորոշիչ հավելվածից:", + confirm_code_2fa_submit_btn: "Հաստատել", + confirm_code_2fa_title: "Մուտքագրեք 2FA կոդը", + confirm_delete_multiple_items: "Վստա՞հ եք, որ ցանկանում եք ընդմիշտ ջնջել այս տարրերը:", + confirm_delete_single_item: "Ցանկանու՞մ եք ընդմիշտ ջնջել այս տարրը:", + confirm_open_apps_log_out: "Դուք ունեք բաց հավելվածներ: Վստա՞հ եք, որ ցանկանում եք դուրս գալ:", confirm_new_password: "Հաստատել նոր գաղտնաբառը", + confirm_delete_user: "Վստա՞հ եք, որ ցանկանում եք ջնջել ձեր հաշիվը: Ձեր բոլոր ֆայլերը և տվյալները ընդմիշտ կջնջվեն: Այս գործողությունը հնարավոր չէ հետարկել:", + confirm_delete_user_title: "Ջնջել հաշիվը?", + confirm_session_revoke: "Վստա՞հ եք, որ ցանկանում եք չեղարկել այս սեսիան:", + confirm_your_email_address: "Հաստատեք ձեր էլ. փոստի հասցեն", contact_us: "Հետադարձ կապ", + contact_us_verification_required: "Սա օգտագործելու համար դուք պետք է ունենաք հաստատված էլ․ հասցե։:", contain: "Պարունակել", continue: "Շարունակել", copy: "Պատճենել", copy_link: "Պատճենել հղումը", copying: "Պատճենվում է", - cover: "Ծածկել", + copying_file: "Պատճենվում է %%", + cover: "Ծածկոց", create_account: "Ստեղծել հաշիվ", create_free_account: "Ստեղծել անվճար հաշիվ", create_shortcut: "Ստեղծել դյուրանցում", - current_password: "Ներկայիս գաղտնաբառ", + credits: "Կրեդիտներ", + current_password: "Ընթացիկ գաղտնաբառ", cut: "Կտրել", - date_modified: "Փոփոխման ամսապիվ", + clock: "Ժամացույց", + clock_visible_hide: "Թաքցնել - Միշտ թաքնված", + clock_visible_show: "Ցուցադրել - Միշտ տեսանելի", + clock_visible_auto: "Ավտոմատ - լռելյայն, տեսանելի միայն ամբողջական էկրանային ռեժիմում:", + close_all: "Փակել բոլորը", + created: "Ստեղծված", + date_modified: "Փոփոխման ամսաթիվ", + default: "Լռելյայն", delete: "Ջնջել", + delete_account: "Ջնջել հաշիվը", delete_permanently: "Ընդմիշտ ջնջել", + deleting_file: "Ջնջվում է %%", deploy_as_app: "Տեղադրել որպես հավելված", - descending: "Նվազման կարգով", + descending: "Նվազող", + desktop: "Աշխատասեղան", desktop_background_fit: "Հարմարեցնել", + developers: "Ծրագրավորողներ", dir_published_as_website: "%strong% հրապարակվել է", + disable_2fa: "Անջատել 2FA", + disable_2fa_confirm: "Վստա՞հ եք, որ ցանկանում եք անջատել 2FA-ն:", + disable_2fa_instructions: "Մուտքագրեք ձեր գաղտնաբառը՝ 2FA-ն անջատելու համար:", disassociate_dir: "Անջատել պանակը", + documents: "Փաստաթղթեր", + dont_allow: "Թույլ չտալ", download: "Ներբեռնել", - downloading: "Ներբեռնում է", + download_file: "Ներբեռնել ֆայլը", + downloading: "Ներբեռնվում է", email: "Էլեկտրոնային հասցե", + email_change_confirmation_sent: "Հաստատման նամակը ուղարկվել է ձեր նոր էլ. հասցեին։ Խնդրում ենք ստուգեք ձեր փոստարկղը և հետևեք ցուցումներին՝ գործընթացը ավարտելու համար:", + email_invalid: "Էլ. հասցեն անվավեր է:", email_or_username: "Էլ․ հասցե կամ օգտանուն", - empty_trash: "Դատարկել աղբամանը", + email_required: "Էլ. հասցեն պարտադիր է:", + empty_trash: "Դատարկել աղբարկղը", empty_trash_confirmation: "Իսկապե՞ս ուզում եք ընդմիշտ ջնջել աղբարկղում գտնվող տարրերը:", - emptying_trash: "Աղբամանը դատարկվում է…", + emptying_trash: "Աղբարկղը դատարկվում է…", + enable_2fa: "Միացնել 2FA", + end_hard: "Ավարտել խիստ", + end_process_force_confirm: "Վստա՞հ եք, որ ցանկանում եք հարկադրաբար կանգնեցնել այս գործընթացը:", + end_soft: "Ավարտել մեղմ", + enlarged_qr_code: "Մեծացված QR-կոդ", + enter_password_to_confirm_delete_user: "Մուտքագրեք ձեր գաղտնաբառը՝ հաշվի ջնջումը հաստատելու համար", + error_message_is_missing: "Սխալի մասին հաղորդագրությունը բացակայում է:", + error_unknown_cause: "Անհայտ սխալ է տեղի ունեցել:", + error_uploading_files: "Չհաջողվեց վերբեռնել ֆայլերը", + favorites: "Նախընտրածներ", feedback: "Հետադարձ կապ", - feedback_c2a: "Խնդրում ենք օգտագործել ստորև բերված ձևը ձեր կարծիքի, մեկնաբանությունների և վրիպակների մասին զեկուցելու համար:", - feedback_sent_confirmation: "Շնորհակալություն մեզ հետ կապնվելու համար: Եթե ​​ձեր հաշվի հետ կապված էլ. հասցե ունեք, հնարավորինս շուտ կպատասխանեք ձեզ:", + feedback_c2a: "Խնդրում ենք օգտագործել ստորև բերված ձևը՝ մեզ ուղարկելու ձեր կարծիքը, մեկնաբանությունները և վրիպակների հաղորդումները:", + feedback_sent_confirmation: "Շնորհակալություն մեզ հետ կապվելու համար: Եթե ձեր հաշվի հետ կապված էլ. հասցե ունեք, հնարավորինս շուտ կպատասխանենք ձեզ:", + fit: "Հարմարեցնել", + folder: "Պանակ", + force_quit: "Հարկադրված ելք", forgot_pass_c2a: "Մոռացե՞լ եք գաղտնաբառը", from: "Ումից՝", general: "Ընդհանուր", - get_a_copy_of_on_puter: "Ստանալ '%%'-ի պատճենը Puter.com-ում:", + get_a_copy_of_on_puter: "Ստանալ '%%'-ի պատճենը Puter.com-ում!", get_copy_link: "Ստանալ պատճենված հղումը", hide_all_windows: "Թաքցնել բոլոր պատուհանները", - html_document: "HTML նիշք", + home: "Գլխավոր", + html_document: "HTML փաստաթուղթ", + hue: "Երանգ", image: "Պատկեր", + incorrect_password: "Սխալ գաղտնաբառ", invite_link: "Հրավերի հղում", + item: "տարր", items_in_trash_cannot_be_renamed: "Այս տարրը չի կարող վերանվանվել, քանի որ այն աղբարկղում է: Այս տարրը վերանվանելու համար նախ տեղափոխեք այն աղբարկղից:", - jpeg_image: "JPEG նիշք", + jpeg_image: "JPEG պատկեր", keep_in_taskbar: "Պահպանել խնդրագոտում", + language: "Լեզու", + license: "Լիցենզիա", + lightness: "Լուսավորություն", + link_copied: "Հղումը պատճենվել է", + loading: "Բեռնում", log_in: "Մուտք գործել", + log_into_another_account_anyway: "Այնուամենայնիվ, մուտք գործեք մեկ այլ հաշիվ", log_out: "Դուրս գալ", + looks_good: "Լավ է նայվում!", + manage_sessions: "Սեսիաների կառավարում", + menubar_style: "Մենյուբարի ոճը", + menubar_style_desktop: "Աշխատասեղան", + menubar_style_system: "Համակարգ", + menubar_style_window: "Պատուհան", + modified: "Փոփոխված", move: "Տեղափոխել", moving_file: "Տեղափոխվում է %%", my_websites: "Իմ կայքերը", name: "Անուն", - name_cannot_be_empty: "Անվան դաշտը չի կառող լինել դատարկ։", - name_cannot_contain_double_period: "Անունը չի կարող լինել '..' նիշը։", - name_cannot_contain_period: "Անունը չի կարող պարունակել '.' նիշը։", - name_cannot_contain_slash: "Անունը չի կարող պարունակել '/' նիշը։", + name_cannot_be_empty: "Անվան դաշտը չի կարող լինել դատարկ:", + name_cannot_contain_double_period: "Անունը չի կարող լինել '..' նիշը:", + name_cannot_contain_period: "Անունը չի կարող լինել '.' նիշը:", + name_cannot_contain_slash: "Անունը չի կարող պարունակել '/' նիշը:", name_must_be_string: "Անունը կարող է լինել միայն տող:", name_too_long: "Անունը չի կարող լինել ավելի քան %% նիշ:", new: "Նոր", + new_email: "Նոր էլ. հասցե", new_folder: "Նոր պանակ", new_password: "Նոր գաղտնաբառ", new_username: "Նոր օգտանուն", + no: "Ոչ", no_dir_associated_with_site: "Այս հասցեի հետ կապված պանակ չկա:", - no_websites_published: "Դուք դեռ ոչ մի կայք չեք հրապարակել։", + no_websites_published: "Դուք դեռ ոչ մի կայք չեք հրապարակել։ Սկսելու համար թղթապանակի վրա սեղմեք աջ", ok: "Լավ", open: "Բացել", open_in_new_tab: "Բացել նոր ներդիրով", open_in_new_window: "Բացել նոր պատուհանում", open_with: "Բացել հավելվածով", + original_name: "սկզբնական անուն", + original_path: "սկզբնական ուղի", + oss_code_and_content: "Բաց կոդով ծրագրակազմ և բովանդակություն", password: "Գաղտնաբառ", password_changed: "Գաղտնաբառը փոփոխված է", - passwords_do_not_match: "«Նոր գաղտնաբառ» և «Հաստատել նոր գաղտնաբառը» դաշտերը չեն համընկնում:", - paste: "Կպցնել", + password_recovery_rate_limit: "Դուք հասել եք մեր արագության սահմանաչափին. խնդրում ենք սպասել մի քանի րոպե: Ապագայում սա կանխելու համար խուսափեք էջը շատ անգամներ վերաբեռնելուց:", + password_recovery_token_invalid: "Այս գաղտնաբառի վերականգնման տոկենը այլևս վավեր չէ:", + password_recovery_unknown_error: "Անհայտ սխալ է տեղի ունեցել: Խնդրում ենք փորձել ավելի ուշ:", + password_required: "Գաղտնաբառը պարտադիր է:", + password_strength_error: "Գաղտնաբառը պետք է լինի առնվազն 8 նիշ երկարությամբ և պարունակի առնվազն մեկ մեծատառ, մեկ փոքրատառ, մեկ թիվ և մեկ հատուկ նիշ:", + passwords_do_not_match: "«Նոր գաղտնաբառ» և «Հաստատել նոր գաղտնաբառը» չեն համընկնում:", + paste: "Տեղադրել", paste_into_folder: "Տեղադրել պանակում", - pick_name_for_website: "Ընտրել անուն ձեր կայքի համար", + path: "Ուղի", + personalization: "Անհատականացում", + pick_name_for_website: "Ընտրեք անուն ձեր կայքի համար", picture: "Նկար", - powered_by_puter_js: `Աջակցվում է {{link=docs}}Puter.js{{/link}}-ի կողմից`, + pictures: "Նկարներ", + plural_suffix: "ներ", + powered_by_puter_js: "Աջակցվում է {{link=docs}}Puter.js{{/link}}-ի կողմից", preparing: "Պատրաստվում է...", preparing_for_upload: "Պատրաստվում է վերբեռնել...", + print: "Տպել", + privacy: "Գաղտնիություն", + proceed_to_login: "Շարունակել մուտք գործելը", + proceed_with_account_deletion: "Շարունակել հաշվի ջնջումը", + process_status_initializing: "Սկսում է", + process_status_running: "Աշխատում է", + process_type_app: "Հավելված", + process_type_init: "Սկսում", + process_type_ui: "UI", properties: "Հատկություններ", + public: "Հանրային", publish: "Հրապարակել", publish_as_website: "Հրապարակել որպես կայք", + puter_description: "Փութերը գաղտնիության առաջնահերթություն ունեցող անձնական ամպ է՝ ձեր բոլոր ֆայլերը, հավելվածները և խաղերը մեկ անվտանգ տեղում պահելու համար, որը հասանելի է ցանկացած վայրից ցանկացած ժամանակ:", + reading_file: "Ընթերցում է %strong%", recent: "Վերջին", + recommended: "Խորհուրդ է տրվում", recover_password: "Վերականգնել գաղտնաբառը", - refer_friends_c2a: "Ստացեք 1 ԳԲ Փութերում յուրաքանչյուր հաշիվ ստեղծող և այն հաստատող ընկերոջ համար: Ձեր ընկերը նույնպես կստանա 1 ԳԲ պահեստ:", - refer_friends_social_media_c2a: "Ստացեք 1 ԳԲ անվճար պահեստ Puter.com-ում:", + refer_friends_c2a: "Ստացեք 1 ԳԲ յուրաքանչյուր ընկերոջ համար, ով ստեղծում և հաստատում է հաշիվ Փութերում: Ձեր ընկերը նույնպես կստանա 1 ԳԲ!", + refer_friends_social_media_c2a: "Ստացեք 1 ԳԲ անվճար պահեստ Puter.com-ում!", refresh: "Թարմացնել", - release_address_confirmation: "Իսկապե՞ս ուզում եք ջնջել այս հասցեն:", + release_address_confirmation: "Իսկապե՞ս ուզում եք թողարկել այս հասցեն:", remove_from_taskbar: "Հանել խնդրագոտուց", rename: "Վերանվանել", repeat: "Կրկնել", + replace: "Փոխարինել", + replace_all: "Փոխարինել բոլորը", resend_confirmation_code: "Նորից ուղարկել հաստատման կոդը", + reset_colors: "Վերականգնել գույները", + restart_puter_confirm: "Վստա՞հ եք, որ ցանկանում եք վերագործարկել Փութերը:", restore: "Վերականգնել", + save: "Պահպանել", + saturation: "Հագեցվածություն", + save_account: "Պահպանել հաշիվը", save_account_to_get_copy_link: "Շարունակելու համար խնդրում ենք ստեղծել հաշիվ:", save_account_to_publish: "Շարունակելու համար խնդրում ենք ստեղծել հաշիվ:", - save_session_c2a: "Ստեղծեք հաշիվ՝ ձեր ընթացիկ աշխատաշրջանը պահպանելու և աշխատանքը չկորցնելու համար:", - scan_qr_c2a: "Սկանավորեք ստորև նշված կոդը՝ այլ սարքերից այս աշխատաշրջան մուտք գործելու համար", + save_session: "Պահպանել սեսիան", + save_session_c2a: "Ստեղծեք հաշիվ՝ ձեր ընթացիկ սեսիան պահպանելու և աշխատանքը չկորցնելու համար:", + scan_qr_c2a: "Սկանավորեք ստորև նշված կոդը՝\nայլ սարքերից այս սեսիա մուտք գործելու համար", + scan_qr_2fa: "Սկանավորեք QR-կոդը ձեր իսկորոշիչ հավելվածով", + scan_qr_generic: "Սկանավորեք այս QR-կոդը ձեր հեռախոսով կամ այլ սարքով", + search: "Որոնել", + seconds: "վայրկյաններ", + security: "Անվտանգություն", select: "Ընտրել", - select_color: "Ընտրել գույն…", + selected: "ընտրված", + select_color: "Ընտրել գույնը…", + sessions: "Սեսիաներ", send: "Ուղարկել", send_password_recovery_email: "Ուղարկել գաղտնաբառի վերականգնման էլ․փոստի նամակ", - session_saved: "Շնորհակալություն հաշիվ ստեղծելու համար: Այս աշխատաշրջանը պահպանվել է:", + session_saved: "Շնորհակալություն հաշիվ ստեղծելու համար: Այս սեսիան պահպանվել է:", + settings: "Կարգավորումներ", set_new_password: "Սահմանել նոր գաղտնաբառ", - share_to: "Տարածել", + share: "Տարածել", + share_to: "Տարածել դեպի", + share_with: "Տարածել հետ՝", + shortcut_to: "Դյուրանցում դեպի", show_all_windows: "Ցույց տալ բոլոր պատուհանները", show_hidden: "Ցույց տալ թաքնված տարրերը", sign_in_with_puter: "Մուտք գործել Փութերի միջոցով", sign_up: "Գրանցվել", - signing_in: "Մուտք է գործում", + signing_in: "Մուտք է գործում…", size: "Չափ", + skip: "Բաց թողնել", + something_went_wrong: "Ինչ-որ բան սխալ գնաց:", sort_by: "Տեսակավորել ըստ՝", start: "Սկսել", + status: "Կարգավիճակ", + storage_usage: "Պահեստի օգտագործում", + storage_puter_used: "օգտագործվում է Փութերի կողմից", taking_longer_than_usual: "Սովորականից մի փոքր ավելի երկար է տևում: Խնդրում ենք սպասել...", - text_document: "Text նիշք", - tos_fineprint: `Սեղմելով «Ստեղծել անվճար հաշիվ»՝ դուք համաձայնում եք Փութերի {{link=terms}}ծառայությունների պայմաններին{{/link}} և {{link=privacy}}գաղտնիության քաղաքականությանը{{/link}}:`, - trash: "Աղբաման", + task_manager: "Առաջադրանքների կառավարիչ", + taskmgr_header_name: "Անուն", + taskmgr_header_status: "Կարգավիճակ", + taskmgr_header_type: "Տեսակ", + terms: "Պայմաններ", + text_document: "Տեքստային փաստաթուղթ", + tos_fineprint: "Սեղմելով «Ստեղծել անվճար հաշիվ»՝ դուք համաձայնում եք Փութերի {{link=terms}}ծառայությունների պայմաններին{{/link}} և {{link=privacy}}գաղտնիության քաղաքականությանը{{/link}}:", + transparency: "Թափանցիկություն", + trash: "Աղբարկղ", + two_factor: "Երկու գործոնով նույնականացում", + two_factor_disabled: "2FA-ն անջատված է", + two_factor_enabled: "2FA-ն միացված է", type: "Տեսակ", + type_confirm_to_delete_account: "Հաշիվը ջնջելու համար գրեք 'confirm':", + ui_colors: "UI գույներ", + ui_manage_sessions: "Սեսիայի կառավարիչ", + ui_revoke: "Հետ կանչել", undo: "Հետարկել", - unzip: "Դուրս բերել", + unlimited: "Անսահմանափակ", + unzip: "Արխիվից հանել", upload: "Վերբեռնել", upload_here: "Վերբեռնել այստեղ", + usage: "Օգտագործում", username: "Օգտանուն", username_changed: "Օգտանունը հաջողությամբ թարմացվել է:", + username_required: "Օգտանունը պարտադիր է:", versions: "Տարբերակներ", - yes_release_it: "Այո, ջնջել", - you_have_been_referred_to_puter_by_a_friend: "Դուք ուղղորդվել եք Փութեր ձեր ընկերոջ կողմից:", - zip: "Սեղմել ZIP նիշքի", - }, + videos: "Տեսանյութեր", + visibility: "Տեսանելիություն", + yes: "Այո", + yes_release_it: "Այո, թողարկեք այն", + you_have_been_referred_to_puter_by_a_friend: "Դուք ուղղորդվել եք Փութեր ձեր ընկերոջ կողմից!", + zip: "Ավելացնել արխիվում", + zipping_file: "Ավելացվում է արխիվում %strong%-ը", + + // === 2FA Setup === + setup2fa_1_step_heading: "Բացեք ձեր իսկորոշիչ հավելվածը", + setup2fa_1_instructions: ` + Դուք կարող եք օգտագործել ցանկացած իսկորոշիչ հավելված, որն աջակցում է ժամանակի վրա հիմնված միանգամյա գաղտնաբառ (TOTP) պրոտոկոլը: + Կան բազմաթիվ տարբերակներ, բայց եթե վստահ չեք, + Authy + լավ ընտրություն է Android-ի և iOS-ի համար: + `, + setup2fa_2_step_heading: "Սկանավորեք QR-կոդը", + setup2fa_3_step_heading: "Մուտքագրեք 6 նիշանոց կոդը", + setup2fa_4_step_heading: "Պատճենեք ձեր վերականգնման կոդերը", + setup2fa_4_instructions: ` + Այս վերականգնման կոդերը միակ միջոցն են մուտք գործելու ձեր հաշիվ, եթե կորցնեք ձեր հեռախոսը կամ չկարողանաք օգտագործել ձեր իսկորոշիչ հավելվածը: + Պարտադիր դրանք պահեք ապահով վայրում: + `, + setup2fa_5_step_heading: "Հաստատեք 2FA կարգավորումը", + setup2fa_5_confirmation_1: "Ես իմ վերականգնման կոդերը պահել եմ ապահով վայրում", + setup2fa_5_confirmation_2: "Ես պատրաստ եմ միացնել 2FA", + setup2fa_5_button: "Միացնել 2FA", + + // === 2FA Login === + login2fa_otp_title: "Մուտքագրեք 2FA կոդը", + login2fa_otp_instructions: "Մուտքագրեք 6 նիշանոց կոդը ձեր իսկորոշիչ հավելվածից:", + login2fa_recovery_title: "Մուտքագրեք վերականգնման կոդը", + login2fa_recovery_instructions: "Մուտքագրեք ձեր վերականգնման կոդերից մեկը ձեր հաշիվ մուտք գործելու համար:", + login2fa_use_recovery_code: "Օգտագործել վերականգնման կոդը", + login2fa_recovery_back: "Հետ", + login2fa_recovery_placeholder: "XXXXXXXX", + } }; export default hy; From 84e31eff2f58584d8fab7dd10606f2f6ced933a2 Mon Sep 17 00:00:00 2001 From: LNLenost Date: Sun, 14 Jul 2024 19:34:09 +0200 Subject: [PATCH 0525/2119] Update it.js --- src/gui/src/i18n/translations/it.js | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/gui/src/i18n/translations/it.js b/src/gui/src/i18n/translations/it.js index e73e29cf1f..9fb87cedd7 100644 --- a/src/gui/src/i18n/translations/it.js +++ b/src/gui/src/i18n/translations/it.js @@ -103,8 +103,8 @@ const it = { developers: "Sviluppatori", dir_published_as_website: `%strong% è stato pubblicato su:`, disable_2fa: 'Disabilita 2FA', - disable_2fa_confirm: "Sei sicuro di voler disabilitare 2FA?", - disable_2fa_instructions: "Inserisci la tua password per disabilitare 2FA.", + disable_2fa_confirm: "Sei sicuro di voler disabilitare la 2FA?", + disable_2fa_instructions: "Inserisci la tua password per disabilitare la 2FA.", disassociate_dir: "Dissocia la Directory", documents: 'Documenti', dont_allow: 'Non consentire', @@ -113,13 +113,13 @@ const it = { downloading: "Download in corso", email: "Email", email_change_confirmation_sent: "Ti abbiamo inviato un'email di conferma. Controlla la tua casella di posta e segui le istruzioni per completare il processo.", - email_invalid: 'Email non valida.', + email_invalid: 'Email invalida.', email_or_username: "Email o Nome Utente", email_required: "Email richiesta.", empty_trash: 'Svuota Cestino', empty_trash_confirmation: `Sei sicuro di voler svuotare il cestino?`, emptying_trash: 'Il cestino si sta svuotando…', - enable_2fa: 'Abilita 2FA', + enable_2fa: 'Abilita la 2FA', end_hard: "Forza la chiusura", end_process_force_confirm: "Sei sicuro di voler forzare la chiusura di questo processo?", end_soft: "Chiudi", @@ -240,7 +240,7 @@ const it = { replace_all: 'Sostituisci tutto', resend_confirmation_code: "Invia di nuovo il codice di conferma", reset_colors: "Ripristina i colori", - restart_puter_confirm: "Sei sicuro di voler resettare Puter?", + restart_puter_confirm: "Sei sicuro di voler riavviare Puter?", restore: "Ripristina", save: "Salva", saturation: "Saturazione", @@ -251,7 +251,7 @@ const it = { save_session_c2a: 'Crea un account per salvare la tua sessione e non perdere i tuoi dati.', scan_qr_c2a: 'Scansiona il codice qua sotto per utilizzare questa sessione da altri dispositivi', scan_qr_2fa: 'Scansiona il codice QR con la tua app di autenticazione', - scan_qr_generic: 'Scansiona il codice QR usando il tuo sma', + scan_qr_generic: 'Scansiona il codice QR usando il tuo smartphone', search: 'Search', seconds: 'seconds', security: "Security", @@ -260,7 +260,7 @@ const it = { select_color: 'Seleziona un colore…', sessions: "Sessioni", send: "Invia", - send_password_recovery_email: "Invia Email per il ripristino della password", + send_password_recovery_email: "Invia email per il ripristino della password", session_saved: "Grazie per aver creato un account. La sessione è stata salvata", settings: "Impostazioni", set_new_password: "Imposta una nuova Password", @@ -282,7 +282,7 @@ const it = { storage_usage: "Utilizzo dello spazio", storage_puter_used: 'utilizzato da Puter', taking_longer_than_usual: 'Il processo in corso ci sta mettendo più del solito. Attendere prego...', - task_manager: "Task Manager", + task_manager: "Gestione attività", taskmgr_header_name: "Nome", taskmgr_header_status: "Stato", taskmgr_header_type: "Tipo", @@ -301,7 +301,7 @@ const it = { ui_revoke: "Revoca", undo: 'Annulla', unlimited: 'Illimitato', - unzip: "Unzip", + unzip: "Estrai", upload: 'Carica', upload_here: 'Carica qui', usage: 'Utilizzo', @@ -334,8 +334,8 @@ const it = { `, setup2fa_5_step_heading: 'Conferma la configurazione del 2FA', setup2fa_5_confirmation_1: 'Ho salvato i miei codici di recupero in un luogo sicuro', - setup2fa_5_confirmation_2: 'Sono pronto per abilitare il 2FA', - setup2fa_5_button: 'Abilita 2FA', + setup2fa_5_confirmation_2: 'Sono pronto per abilitare la 2FA', + setup2fa_5_button: 'Abilita la 2FA', // === 2FA Login === login2fa_otp_title: 'Inserisci il codice 2FA', @@ -348,4 +348,4 @@ const it = { } }; -export default it; \ No newline at end of file +export default it; From 93f4e52983d3e262dfadf3870e07a7a6bbbd1982 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sun, 14 Jul 2024 16:43:56 -0700 Subject: [PATCH 0526/2119] Update README.md to add Mastodon link --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index a59bc97215..60b7973bf0 100644 --- a/README.md +++ b/README.md @@ -82,10 +82,11 @@ Puter is available as a hosted service at [**puter.com**](https://puter.com). Connect with the maintainers and community through these channels: -- Bug report or feature request? Please [open an issue](https://github.com/HeyPuter/puter/issues/new/choose). -- Discord: [https://discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) -- X (Twitter): [https://x.com/HeyPuter](https://x.com/HeyPuter) -- Reddit: [https://reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- Bug report or feature request? Please [open an issue](github.com/HeyPuter/puter/issues/new/choose). +- Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) +- Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) - Email maintainers at [hi@puter.com](mailto:hi@puter.com) We are always happy to help you with any questions you may have. Don't hesitate to ask! From 81781f80afc07cd1e6278906cdc68c8092fbfedf Mon Sep 17 00:00:00 2001 From: Varun710 Date: Mon, 15 Jul 2024 00:27:35 -0500 Subject: [PATCH 0527/2119] Tamil translation --- src/i18n/translations/ta.js | 350 ++++++++++++++++++++++++++++++++++++ 1 file changed, 350 insertions(+) create mode 100644 src/i18n/translations/ta.js diff --git a/src/i18n/translations/ta.js b/src/i18n/translations/ta.js new file mode 100644 index 0000000000..807862775f --- /dev/null +++ b/src/i18n/translations/ta.js @@ -0,0 +1,350 @@ +/** + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ + +const ta = { + name: "ஆங்கிலம்", + english_name: "English", + code: "ta", + dictionary: { + about: "பற்றி", + account: "கணக்கு", + account_password: "கணக்கு கடவுச்சொல்லை சரிபார்க்கவும்", + access_granted_to: "அனுமதி வழங்கப்பட்ட", + add_existing_account: "ஏற்கனவே உள்ள கணக்கைச் சேர்க்கவும்", + all_fields_required: 'அனைத்து புலங்களும் தேவை.', + allow: 'அனுமதி', + apply: "விண்ணப்பிக்கவும்", + ascending: 'ஏறுமுகம்', + associated_websites: "தொடர்புடைய இணையதளங்கள்", + auto_arrange: 'ஆட்டோ ஏற்பாடு', + background: "பின்னணி", + browse: "உலாவவும்", + cancel: 'ரத்து செய்', + center: 'மையம்', + change_desktop_background: 'டெஸ்க்டாப் பின்னணியை மாற்றவும்…', + change_email: "மின்னஞ்சலை மாற்றவும்", + change_language: "மொழியை மாற்றவும்", + change_password: "கடவுச்சொல்லை மாற்றவும்", + change_ui_colors: "யுஐ நிறங்களை மாற்றவும்", + change_username: "பயனர் பெயரை மாற்றவும்", + close: 'மூடு', + close_all_windows: "அனைத்து விண்டோஸ் மூடு", + close_all_windows_confirm: "எல்லா சாளரங்களையும் நிச்சயமாக மூட விரும்புகிறீர்களா?", + close_all_windows_and_log_out: 'விண்டோஸை மூடிவிட்டு வெளியேறவும்', + change_always_open_with: "இந்த வகையான கோப்பை எப்போதும் திறக்க விரும்புகிறீர்களா?", + color: 'நிறம்', + confirm_2fa_setup: 'எனது அங்கீகரிப்பு பயன்பாட்டில் குறியீட்டைச் சேர்த்துள்ளேன்', + confirm_2fa_recovery: 'எனது மீட்புக் குறியீடுகளை பாதுகாப்பான இடத்தில் சேமித்துள்ளேன்', + confirm_account_for_free_referral_storage_c2a: '1 ஜிபி இலவச சேமிப்பிடத்தைப் பெற, கணக்கை உருவாக்கி உங்கள் மின்னஞ்சல் முகவரியை உறுதிப்படுத்தவும். உங்கள் நண்பருக்கு 1 ஜிபி இலவச சேமிப்பகமும் கிடைக்கும்.', + confirm_code_generic_incorrect: "தவறான குறியீடு.", + confirm_code_generic_too_many_requests: "பல கோரிக்கைகள். தயவுசெய்து சில நிமிடங்கள் காத்திருக்கவும்.", + confirm_code_generic_submit: "குறியீட்டை சமர்ப்பிக்கவும்", + confirm_code_generic_try_again: "மீண்டும் முயற்சி செய்யவும்", + confirm_code_generic_title: "உறுதிப்படுத்தல் குறியீட்டை உள்ளிடவும்", + confirm_code_2fa_instruction: "உங்கள் அங்கீகரிப்பு பயன்பாட்டிலிருந்து 6 இலக்கக் குறியீட்டை உள்ளிடவும்.", + confirm_code_2fa_submit_btn: "சமர்ப்பிக்கவும்", + confirm_code_2fa_title: "2FA குறியீட்டை உள்ளிடவும்", + confirm_delete_multiple_items: 'இந்த உருப்படிகளை நிரந்தரமாக நீக்க விரும்புகிறீர்களா?', + confirm_delete_single_item: 'இந்த உருப்படியை நிரந்தரமாக நீக்க வேண்டுமா?', + confirm_open_apps_log_out: 'உங்களிடம் திறந்த பயன்பாடுகள் உள்ளன. நிச்சயமாக வெளியேற விரும்புகிறீர்களா?', + confirm_new_password: "புதிய கடவு சொல்லை உறுதி செய்யவும்", + confirm_delete_user: "உங்கள் கணக்கை நிச்சயமாக நீக்க விரும்புகிறீர்களா? உங்கள் எல்லா கோப்புகளும் தரவுகளும் நிரந்தரமாக நீக்கப்படும். இந்தச் செயலைச் செயல்தவிர்க்க முடியாது.", + confirm_delete_user_title: "கணக்கை நீக்குக?", + confirm_session_revoke: "இந்த அமர்வை நிச்சயமாக திரும்பப் பெற விரும்புகிறீர்களா?", + confirm_your_email_address: "உங்கள் மின்னஞ்சல் முகவரியை உறுதிப்படுத்தவும்", + contact_us: "எங்களை தொடர்பு கொள்ள", + contact_us_verification_required: "இதைப் பயன்படுத்த, சரிபார்க்கப்பட்ட மின்னஞ்சல் முகவரி உங்களிடம் இருக்க வேண்டும்.", + contain: 'கொண்டிருக்கும்', + continue: "தொடரவும்", + copy: 'நகலெடுக்கவும்', + copy_link: "இணைப்பை நகலெடுக்கவும்", + copying: "நகலெடுக்கிறது", + copying_file: "நகலெடுக்கிறது %%", + cover: 'கவர்', + create_account: "உங்கள் கணக்கை துவங்குங்கள்", + create_free_account: "இலவச கணக்கை உருவாக்கவும்", + create_shortcut: "குறுக்குவழியை உருவாக்க", + credits: "கடன்கள்", + current_password: "தற்போதைய கடவுச்சொல்", + cut: 'வெட்டு', + clock: "கடிகாரம்", + clock_visible_hide: 'மறை - எப்போதும் மறைந்திருக்கும்', + clock_visible_show: 'காட்டு - எப்போதும் தெரியும்', + clock_visible_auto: 'தானியங்கு - இயல்புநிலை, முழுத்திரை பயன்முறையில் மட்டுமே தெரியும்.', + close_all: 'அனைத்தையும் மூடு', + created: 'உருவாக்கப்பட்டது', + date_modified: 'தேதி மாற்றப்பட்டது', + default: 'இயல்புநிலை', + delete: 'அழி', + delete_account: "கணக்கை நீக்குக", + delete_permanently: "நிரந்தரமாக நீக்குக", + deleting_file: "நீக்குகிறது %%", + deploy_as_app: 'பயன்பாடாக வரிசைப்படுத்து', + descending: 'இறங்குதல்', + desktop: 'டெஸ்க்டாப்', + desktop_background_fit: "பொருத்தம்", + developers: "டெவலப்பர்கள்", + dir_published_as_website: `%strong% வெளியிடப்பட்டது:`, + disable_2fa: '2FA ஐ முடக்கு', + disable_2fa_confirm: "2FA ஐ நிச்சயமாக முடக்க விரும்புகிறீர்களா?", + disable_2fa_instructions: "2FA ஐ முடக்க உங்கள் கடவுச்சொல்லை உள்ளிடவும்.", + disassociate_dir: "டிஸ்ஸோசியேட் டைரக்டரி", + documents: 'ஆவணங்கள்', + dont_allow: 'அனுமதிக்காதே', + download: 'பதிவிறக்கவும்', + download_file: 'பதிவிறக்க கோப்பு', + downloading: "பதிவிறக்குகிறது", + email: "மின்னஞ்சல்", + email_change_confirmation_sent: "உங்கள் புதிய மின்னஞ்சல் முகவரிக்கு உறுதிப்படுத்தல் மின்னஞ்சல் அனுப்பப்பட்டுள்ளது. செயல்முறையை முடிக்க உங்கள் இன்பாக்ஸைச் சரிபார்த்து, வழிமுறைகளைப் பின்பற்றவும்.", + email_invalid: 'மின்னஞ்சல் தவறானது.', + email_or_username: "மின்னஞ்சல் அல்லது பயனர் பெயர்", + email_required: 'மின்னஞ்சல் தேவை.', + empty_trash: 'வெற்று குப்பை', + empty_trash_confirmation: `குப்பையில் உள்ள உருப்படிகளை நிரந்தரமாக நீக்க விரும்புகிறீர்களா?`, + emptying_trash: 'குப்பையைக் காலியாக்குகிறது…', + enable_2fa: '2FA ஐ இயக்கவும்', + end_hard: "கடினமாக முடிக்கவும்", + end_process_force_confirm: "இந்தச் செயல்முறையை கட்டாயப்படுத்தி வெளியேற விரும்புகிறீர்களா?", + end_soft: "மென்மையான முடிக்கவும்", + enlarged_qr_code: "விரிவாக்கப்பட்ட QR குறியீடு", + enter_password_to_confirm_delete_user: "கணக்கு நீக்குதலை உறுதிப்படுத்த உங்கள் கடவுச்சொல்லை உள்ளிடவும்", + error_message_is_missing: "பிழை செய்தி காணவில்லை.", + error_unknown_cause: "அறியப்படாத பிழை ஏற்பட்டது.", + error_uploading_files: "கோப்புகளைப் பதிவேற்றுவதில் தோல்வி", + favorites: "பிடித்தவை", + feedback: "பின்னூட்டம்", + feedback_c2a: "உங்கள் கருத்து, கருத்துகள் மற்றும் பிழை அறிக்கைகளை எங்களுக்கு அனுப்ப கீழே உள்ள படிவத்தைப் பயன்படுத்தவும்.", + feedback_sent_confirmation: "எங்களை தொடர்பு கொண்டதற்கு நன்றி. உங்கள் கணக்குடன் தொடர்புடைய மின்னஞ்சலை நீங்கள் வைத்திருந்தால், கூடிய விரைவில் எங்களிடமிருந்து பதிலளிப்பீர்கள்.", + fit: "பொருத்தம்", + folder: 'கோப்புறை', + force_quit: 'கட்டாயம் வெளியேறு', + forgot_pass_c2a: "கடவுச்சொல்லை மறந்துவிட்டீர்களா?", + from: "இருந்து", + general: "பொது", + get_a_copy_of_on_puter: `Puter.com இல் '%%' நகலைப் பெறுங்கள்!`, + get_copy_link: 'நகல் இணைப்பைப் பெறவும்', + hide_all_windows: "அனைத்து விண்டோஸையும் மறைக்கவும்", + home: 'வீடு', + html_document: 'HTML ஆவணம்', + hue: 'சாயல்', + image: 'படம்', + incorrect_password: "தவறான கடவுச்சொல்", + invite_link: "அழைப்பு இணைப்பு", + item: 'பொருள்', + items_in_trash_cannot_be_renamed: `இந்த உருப்படி குப்பையில் இருப்பதால் மறுபெயரிட முடியாது. இந்த உருப்படியை மறுபெயரிட, முதலில் அதை குப்பையிலிருந்து வெளியே இழுக்கவும்.`, + jpeg_image: 'JPEG படம்', + keep_in_taskbar: 'பணிப்பட்டியில் வைக்கவும்', + language: "மொழி", + license: "உரிமம்", + lightness: 'லேசான தன்மை', + link_copied: "இணைப்பு நகலெடுக்கப்பட்டது", + loading: 'ஏற்றுகிறது', + log_in: "உள்நுழைய", + log_into_another_account_anyway: 'எப்படியும் மற்றொரு கணக்கில் உள்நுழைக', + log_out: 'வெளியேறு', + looks_good: "நன்றாக இருக்கிறது!", + manage_sessions: "அமர்வுகளை நிர்வகிக்கவும்", + menubar_style: "மெனுபார் உடை", + menubar_style_desktop: "டெஸ்க்டாப்", + menubar_style_system: "அமைப்பு", + menubar_style_window: "ஜன்னல்", + modified: 'மாற்றியமைக்கப்பட்டது', + move: 'நகர்வு', + moving_file: "நகரும் %%", + my_websites: "எனது இணையதளங்கள்", + name: 'பெயர்', + name_cannot_be_empty: 'பெயர் காலியாக இருக்கக்கூடாது.', + name_cannot_contain_double_period: "பெயர் '..' எழுத்தாக இருக்க முடியாது.", + name_cannot_contain_period: "பெயர் '.' எழுத்தாக இருக்க முடியாது.", + name_cannot_contain_slash: "பெயரில் '/' எழுத்து இருக்கக்கூடாது.", + name_must_be_string: "பெயர் ஒரு சரமாக மட்டுமே இருக்க முடியும்.", + name_too_long: `பெயர் %% எழுத்துகளுக்கு மேல் இருக்கக்கூடாது.`, + new: 'புதியது', + new_email: 'புதிய மின்னஞ்சல்', + new_folder: 'புதிய அடைவை', + new_password: "புதிய கடவுச்சொல்", + new_username: "புதிய பயனர் பெயர்", + no: 'இல்லை', + no_dir_associated_with_site: 'இந்த முகவரியுடன் எந்த கோப்பகமும் இணைக்கப்படவில்லை.', + no_websites_published: "நீங்கள் இதுவரை எந்த இணையதளத்தையும் வெளியிடவில்லை.", + ok: 'சரி', + open: "திற", + open_in_new_tab: "புதிய தாவலில் திறக்கவும்", + open_in_new_window: "Open in New Window", + open_with: "உடன் திற", + original_name: 'அசல் பெயர்', + original_path: 'அசல் பாதை', + oss_code_and_content: "திறந்த மூல மென்பொருள் மற்றும் உள்ளடக்கம்", + password: "கடவுச்சொல்", + password_changed: "கடவுச்சொல் மாற்றப்பட்டது.", + password_recovery_rate_limit: "எங்கள் கட்டண வரம்பை அடைந்துவிட்டீர்கள்; தயவுசெய்து சில நிமிடங்கள் காத்திருக்கவும். எதிர்காலத்தில் இதைத் தடுக்க, பக்கத்தை பல முறை மீண்டும் ஏற்றுவதைத் தவிர்க்கவும்.", + password_recovery_token_invalid: "இந்த கடவுச்சொல் மீட்பு டோக்கன் இனி செல்லுபடியாகாது.", + password_recovery_unknown_error: "அறியப்படாத பிழை ஏற்பட்டது. பிறகு முயற்சிக்கவும்.", + password_required: 'கடவுச்சொல் தேவை.', + password_strength_error: "கடவுச்சொல் குறைந்தபட்சம் 8 எழுத்துக்கள் நீளமாக இருக்க வேண்டும் மற்றும் குறைந்தபட்சம் ஒரு பெரிய எழுத்து, ஒரு சிறிய எழுத்து, ஒரு எண் மற்றும் ஒரு சிறப்பு எழுத்து ஆகியவற்றைக் கொண்டிருக்க வேண்டும்.", + passwords_do_not_match: '`புதிய கடவுச்சொல்` மற்றும் `புதிய கடவுச்சொல்லை உறுதிப்படுத்து` ஆகியவை பொருந்தவில்லை.', + paste: 'ஒட்டவும்', + paste_into_folder: "கோப்புறையில் ஒட்டவும்", + path: 'பாதை', + personalization: "தனிப்பயனாக்கம்", + pick_name_for_website: "உங்கள் வலைத்தளத்திற்கு ஒரு பெயரைத் தேர்ந்தெடுக்கவும்:", + picture: "படம்", + pictures: 'படங்கள்', + plural_suffix: 'கள்', + powered_by_puter_js: `மூலம் இயக்கப்படுகிறது {{link=docs}}Puter.js{{/link}}`, + preparing: "தயாராகிறது...", + preparing_for_upload: "பதிவேற்றம் செய்ய தயாராகிறது...", + print: 'அச்சிடுக', + privacy: "தனியுரிமை", + proceed_to_login: 'உள்நுழைய தொடரவும்', + proceed_with_account_deletion: "கணக்கு நீக்குதலைத் தொடரவும்", + process_status_initializing: "துவக்குதல்", + process_status_running: "ஓடுதல்", + process_type_app: 'செயலி', + process_type_init: 'Init', + process_type_ui: 'யுஐ', + properties: "பண்புகள்", + public: 'பொது', + publish: "வெளியிடு", + publish_as_website: 'இணையதளமாக வெளியிடவும்', + puter_description: `உங்கள் கோப்புகள், பயன்பாடுகள் மற்றும் கேம்கள் அனைத்தையும் ஒரே பாதுகாப்பான இடத்தில் வைத்திருக்க, எந்த நேரத்திலும் எங்கிருந்தும் அணுகக்கூடிய தனியுரிமை-முதல் தனிப்பட்ட கிளவுட் புட்டர் ஆகும்.`, + reading_file: "படித்தல் %strong%", + recent: "அண்மையில்", + recommended: "பரிந்துரைக்கப்படுகிறது", + recover_password: "கடவுச்சொல்லை மீட்டெடுக்கவும்", + refer_friends_c2a: "புட்டர் இல் கணக்கை உருவாக்கி உறுதிப்படுத்தும் ஒவ்வொரு நண்பருக்கும் 1 GB கிடைக்கும். உங்கள் நண்பருக்கும் 1 ஜிபி கிடைக்கும்!", + refer_friends_social_media_c2a: `Puter.com இல் 1 GB இலவச சேமிப்பிடத்தைப் பெறுங்கள்!`, + refresh: 'புதுப்பிப்பு', + release_address_confirmation: `இந்த முகவரியை நிச்சயமாக வெளியிட விரும்புகிறீர்களா?`, + remove_from_taskbar:'பணிப்பட்டியில் இருந்து அகற்று', + rename: 'மறுபெயரிடவும்', + repeat: 'மீண்டும் செய்யவும்', + replace: 'மாற்றவும்', + replace_all: 'அனைத்தையும் மாற்றவும்', + resend_confirmation_code: "உறுதிப்படுத்தல் குறியீட்டை மீண்டும் அனுப்பவும்", + reset_colors: "வண்ணங்களை மீட்டமைக்கவும்", + restart_puter_confirm: "நிச்சயமாக புட்டர்-ஐ மீண்டும் தொடங்க விரும்புகிறீர்களா?", + restore: "மீட்டமை", + save: 'சேமிக்கவும்', + saturation: 'செறிவூட்டல்', + save_account: 'கணக்கைச் சேமிக்கவும்', + save_account_to_get_copy_link: "தொடர ஒரு கணக்கை உருவாக்கவும்.", + save_account_to_publish: 'தொடர ஒரு கணக்கை உருவாக்கவும்.', + save_session: 'அமர்வை சேமிக்கவும்', + save_session_c2a: 'உங்கள் தற்போதைய அமர்வைச் சேமிக்க ஒரு கணக்கை உருவாக்கவும் மற்றும் உங்கள் வேலையை இழப்பதைத் தவிர்க்கவும்.', + scan_qr_c2a: 'பிற சாதனங்களிலிருந்து இந்த அமர்வில் உள்நுழைய, \nகீழே உள்ள குறியீட்டை ஸ்கேன் செய்யவும்', + scan_qr_2fa: 'உங்கள் அங்கீகரிப்பு பயன்பாட்டின் மூலம் QR குறியீட்டை ஸ்கேன் செய்யவும்', + scan_qr_generic: 'உங்கள் தொலைபேசி அல்லது மற்றொரு சாதனத்தைப் பயன்படுத்தி இந்த QR குறியீட்டை ஸ்கேன் செய்யவும்', + search: 'தேடு', + seconds: 'வினாடிகள்', + security: "பாதுகாப்பு", + select: "தேர்ந்தெடு", + selected: 'தேர்ந்தெடுக்கப்பட்டது', + select_color: 'வண்ணத்தைத் தேர்ந்தெடுக்கவும்…', + sessions: "அமர்வுகள்", + send: "அனுப்பு", + send_password_recovery_email: "கடவுச்சொல் மீட்பு மின்னஞ்சலை அனுப்பவும்", + session_saved: "கணக்கை உருவாக்கியதற்கு நன்றி. இந்த அமர்வு சேமிக்கப்பட்டது.", + settings: "அமைப்புகள்", + set_new_password: "புதிய கடவுச்சொல்லை அமை", + share: "பகிர்", + share_to: "பகிரவும்", + share_with: "இவர்களுடன் பகிரவும்:", + shortcut_to: "குறுக்குவழி", + show_all_windows: "அனைத்து விண்டோஸையும் காட்டு", + show_hidden: 'மறைக்கப்பட்டதைக் காட்டு', + sign_in_with_puter: "புட்டர் மூலம் உள்நுழையவும்", + sign_up: "பதிவு செய்யவும்", + signing_in: "உள்நுழைகிறேன்…", + size: 'அளவு', + skip: 'தவிர்க்கவும்', + something_went_wrong: "ஏதோ தவறு நடந்துவிட்டது.", + sort_by: 'வரிசைப்படுத்து', + start: 'தொடங்கு', + status: "நிலை", + storage_usage: "சேமிப்பக பயன்பாடு", + storage_puter_used: 'புட்டரால் பயன்படுத்தப்பட்டது', + taking_longer_than_usual: 'வழக்கத்தை விட சிறிது நேரம் எடுக்கும். தயவுசெய்து காத்திருங்கள்...', + task_manager: "பணி மேலாளர்", + taskmgr_header_name: "பெயர்", + taskmgr_header_status: "நிலை", + taskmgr_header_type: "வகை", + terms: "விதிமுறை", + text_document: 'உரை ஆவணம்', + tos_fineprint: `'இலவச கணக்கை உருவாக்கு' என்பதைக் கிளிக் செய்வதன் மூலம், புட்டர் இன் {{link=terms}}சேவை விதிமுறைகள்{{/link}} மற்றும் {{link=privacy}}தனியுரிமைக் கொள்கையை{{/link}} ஏற்கிறீர்கள்.`, + transparency: "வெளிப்படைத்தன்மை", + trash: 'குப்பை', + two_factor: 'இரண்டு காரணி அங்கீகாரம்', + two_factor_disabled: '2FA முடக்கப்பட்டது', + two_factor_enabled: '2FA இயக்கப்பட்டது', + type: 'வகை', + type_confirm_to_delete_account: "உங்கள் கணக்கை நீக்க, 'உறுதிப்படுத்து' என தட்டச்சு செய்யவும்.", + ui_colors: "UI நிறங்கள்", + ui_manage_sessions: "அமர்வு மேலாளர்", + ui_revoke: "திரும்பப் பெறு", + undo: 'செயல்தவிர்', + unlimited: 'வரம்பற்ற', + unzip: "அன்ஜிப்", + upload: 'பதிவேற்றவும்', + upload_here: 'இங்கே பதிவேற்றவும்', + usage: 'பயன்பாடு', + username: "பயனர் பெயர்", + username_changed: 'பயனர்பெயர் வெற்றிகரமாக புதுப்பிக்கப்பட்டது.', + username_required: 'பயனர் பெயர் தேவை.', + versions: "Versions", + videos: 'வீடியோக்கள்', + visibility: 'தெரிவுநிலை', + yes: 'ஆம்', + yes_release_it: 'ஆம், வெளியிடு', + you_have_been_referred_to_puter_by_a_friend: "நீங்கள் ஒரு நண்பரால் புட்டருக்கு பரிந்துரைக்கப்பட்டீர்கள்!", + zip: "ஜிப்", + zipping_file: "ஜிப்பிங் %strong%", + + // === 2FA Setup === + setup2fa_1_step_heading: 'உங்கள் அங்கீகரிப்பு பயன்பாட்டைத் திறக்கவும்', + setup2fa_1_instructions: ` + Time-based One-Time Password (TOTP) நெறிமுறையை ஆதரிக்கும் எந்த அங்கீகார பயன்பாட்டையும் நீங்கள் பயன்படுத்தலாம். + தேர்வு செய்ய பல உள்ளன, ஆனால் நீங்கள் உறுதியாக தெரியவில்லை என்றால் + Authy + ஆண்ட்ராய்டு மற்றும் iOSக்கு ஒரு திடமான தேர்வாகும். + `, + setup2fa_2_step_heading: 'QR குறியீட்டை ஸ்கேன் செய்யவும்', + setup2fa_3_step_heading: '6 இலக்கக் குறியீட்டை உள்ளிடவும்', + setup2fa_4_step_heading: 'உங்கள் மீட்பு குறியீடுகளை நகலெடுக்கவும்', + setup2fa_4_instructions: ` + உங்கள் ஃபோனை இழந்தாலோ அல்லது அங்கீகரிப்பு பயன்பாட்டைப் பயன்படுத்த முடியாமலோ உங்கள் கணக்கை அணுக இந்த மீட்புக் குறியீடுகள் மட்டுமே ஒரே வழி. +அவற்றை பாதுகாப்பான இடத்தில் சேமித்து வைப்பதை உறுதி செய்யவும். + `, + setup2fa_5_step_heading: '2FA அமைப்பை உறுதிப்படுத்தவும்', + setup2fa_5_confirmation_1: 'எனது மீட்புக் குறியீடுகளை பாதுகாப்பான இடத்தில் சேமித்துள்ளேன்', + setup2fa_5_confirmation_2: '2FA ஐ இயக்க நான் தயாராக இருக்கிறேன்', + setup2fa_5_button: '2FA ஐ இயக்கவும்', + + // === 2FA Login === + login2fa_otp_title: '2FA குறியீட்டை உள்ளிடவும்', + login2fa_otp_instructions: 'உங்கள் அங்கீகரிப்பு பயன்பாட்டிலிருந்து 6 இலக்கக் குறியீட்டை உள்ளிடவும்.', + login2fa_recovery_title: 'மீட்புக் குறியீட்டை உள்ளிடவும்', + login2fa_recovery_instructions: 'உங்கள் கணக்கை அணுக, உங்கள் மீட்புக் குறியீடுகளில் ஒன்றை உள்ளிடவும்.', + login2fa_use_recovery_code: 'மீட்புக் குறியீட்டைப் பயன்படுத்தவும்', + login2fa_recovery_back: 'மீண்டும்', + login2fa_recovery_placeholder: 'XXXXXXXX', + } +}; + +export default ta; From 7a12e699de0293f3fbfa708a64ef6b9ebc3746a0 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 15 Jul 2024 13:20:43 -0400 Subject: [PATCH 0528/2119] Update SECURITY-ACKNOWLEDGEMENTS.md --- SECURITY-ACKNOWLEDGEMENTS.md | 1 + 1 file changed, 1 insertion(+) diff --git a/SECURITY-ACKNOWLEDGEMENTS.md b/SECURITY-ACKNOWLEDGEMENTS.md index 5702f03b47..b047f25f38 100644 --- a/SECURITY-ACKNOWLEDGEMENTS.md +++ b/SECURITY-ACKNOWLEDGEMENTS.md @@ -5,3 +5,4 @@ We would like to thank the following security researchers for their responsible - Tim Suess: [GitHub](https://github.com/blackfortresslabs) | [Email](tim@blackfortresslabs.com) | [Website](https://www.blackfortresslabs.com) - xyzeva: [Github](https://github.com/xyzeva) | [Email](mailto:xyzeva@riseup.net) | [Website](https://kibty.town/) +- Yusuf Kelany: [GitHub](https://github.com/YusufYaser) | [Twitter](x.com/RealYusufYaser) From a259755fe5319fbed6870961a63dea6eed70cc42 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 15 Jul 2024 13:22:15 -0400 Subject: [PATCH 0529/2119] Fix broken link --- SECURITY-ACKNOWLEDGEMENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SECURITY-ACKNOWLEDGEMENTS.md b/SECURITY-ACKNOWLEDGEMENTS.md index b047f25f38..d4c0da1cf8 100644 --- a/SECURITY-ACKNOWLEDGEMENTS.md +++ b/SECURITY-ACKNOWLEDGEMENTS.md @@ -5,4 +5,4 @@ We would like to thank the following security researchers for their responsible - Tim Suess: [GitHub](https://github.com/blackfortresslabs) | [Email](tim@blackfortresslabs.com) | [Website](https://www.blackfortresslabs.com) - xyzeva: [Github](https://github.com/xyzeva) | [Email](mailto:xyzeva@riseup.net) | [Website](https://kibty.town/) -- Yusuf Kelany: [GitHub](https://github.com/YusufYaser) | [Twitter](x.com/RealYusufYaser) +- Yusuf Kelany: [GitHub](https://github.com/YusufYaser) | [Twitter](https://x.com/RealYusufYaser) From 56820cf6ee56ff810a6b495a281ccbb2e7f9d8fb Mon Sep 17 00:00:00 2001 From: XYCert <107841184+Szab54@users.noreply.github.com> Date: Mon, 15 Jul 2024 20:58:31 +0200 Subject: [PATCH 0530/2119] Update translations.js to Hungarian lang --- src/gui/src/i18n/translations/translations.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/src/i18n/translations/translations.js b/src/gui/src/i18n/translations/translations.js index 36d55e2644..6dcd3547ae 100644 --- a/src/gui/src/i18n/translations/translations.js +++ b/src/gui/src/i18n/translations/translations.js @@ -46,6 +46,7 @@ import tr from './tr.js'; import ur from './ur.js'; import ua from './ua.js'; import zh from './zh.js'; +import hu from './hu.js'; import zhtw from './zhtw.js'; import emoji from './emoji.js'; @@ -80,6 +81,7 @@ export default { tr, ua, zh, + hu, zhtw, ur, emoji, From 69a80ab3d2c94ee43d96021c3bcbdab04a4b5dc6 Mon Sep 17 00:00:00 2001 From: XYCert <107841184+Szab54@users.noreply.github.com> Date: Mon, 15 Jul 2024 21:04:38 +0200 Subject: [PATCH 0531/2119] Create hu.js hungarian language --- src/gui/src/i18n/translations/hu.js | 339 ++++++++++++++++++++++++++++ 1 file changed, 339 insertions(+) create mode 100644 src/gui/src/i18n/translations/hu.js diff --git a/src/gui/src/i18n/translations/hu.js b/src/gui/src/i18n/translations/hu.js new file mode 100644 index 0000000000..38769e3556 --- /dev/null +++ b/src/gui/src/i18n/translations/hu.js @@ -0,0 +1,339 @@ +/** + * Copyright (C) 2024 Puter Technologies Inc. + * + * Ez a fájl a Puter része. + * + * A Puter szabad szoftver: terjesztheted és/vagy módosíthatod + * a GNU Affero General Public License feltételei szerint, amelyet a Free Software Foundation adott ki, akár a licenc 3-as verziója, akár (választásod szerint) bármely későbbi verzió alapján. + * + * Ez a program abban a reményben kerül terjesztésre, hogy hasznos lesz, + * de mindenféle GARANCIA NÉLKÜL; még az ELADHATÓSÁGRA vagy egy adott célra való ALKALMASSÁG hallgatólagos garanciája nélkül is. További részletekért lásd a GNU Affero General Public License-t. + * + * A programhoz mellékelték a GNU Affero General Public License egy példányát. + * Ha nem, látogass el a oldalra. + */ + +const hu = { + name: "Magyar", + english_name: "Hungarian", + code: "hu", + dictionary: { + about: "Névjegy", + account: "Fiók", + account_password: "Fiók jelszó megerősítése", + access_granted_to: "Hozzáférés engedélyezve", + add_existing_account: "Meglévő fiók hozzáadása", + all_fields_required: "Minden mező kitöltése kötelező.", + allow: "Engedélyez", + apply: "Alkalmaz", + ascending: "Növekvő", + associated_websites: "Kapcsolódó weboldalak", + auto_arrange: "Automatikus elrendezés", + background: "Háttér", + browse: "Böngészés", + cancel: "Mégsem", + center: "Középre", + change_desktop_background: "Asztal háttérképének módosítása...", + change_email: "Email módosítása", + change_language: "Nyelv módosítása", + change_password: "Jelszó módosítása", + change_ui_colors: "UI színek módosítása", + change_username: "Felhasználónév módosítása", + close: "Bezár", + close_all_windows: "Minden ablak bezárása", + close_all_windows_confirm: "Biztosan be akarod zárni az összes ablakot?", + close_all_windows_and_log_out: "Ablakok bezárása és kijelentkezés", + change_always_open_with: "Mindig ezzel az alkalmazással nyitja meg ezt a fájlt?", + color: "Szín", + confirm: "Megerősít", + confirm_2fa_setup: "A kódot hozzáadtam a hitelesítő alkalmazásomhoz", + confirm_2fa_recovery: "A helyreállítási kódokat biztonságos helyen tároltam", + confirm_account_for_free_referral_storage_c2a: "Hozz létre egy fiókot és erősítsd meg email címedet, hogy 1 GB ingyenes tárhelyet kapj. A barátod is kap 1 GB ingyenes tárhelyet.", + confirm_code_generic_incorrect: "Hibás kód.", + confirm_code_generic_too_many_requests: "Túl sok kérés. Kérlek, várj néhány percet.", + confirm_code_generic_submit: "Kód beküldése", + confirm_code_generic_try_again: "Próbáld újra", + confirm_code_generic_title: "Megerősítő kód megadása", + confirm_code_2fa_instruction: "Add meg a 6-jegyű kódot a hitelesítő alkalmazásodból.", + confirm_code_2fa_submit_btn: "Beküldés", + confirm_code_2fa_title: "2FA kód megadása", + confirm_delete_multiple_items: "Biztosan véglegesen törölni akarod ezeket az elemeket?", + confirm_delete_single_item: "Biztosan véglegesen törölni akarod ezt az elemet?", + confirm_open_apps_log_out: "Nyitott alkalmazásaid vannak. Biztosan ki akarsz jelentkezni?", + confirm_new_password: "Új jelszó megerősítése", + confirm_delete_user: "Biztosan törölni akarod a fiókodat? Minden fájlod és adatod véglegesen törlődik. Ez a művelet nem visszavonható.", + confirm_delete_user_title: "Fiók törlése?", + confirm_session_revoke: "Biztosan visszavonod ezt a munkamenetet?", + confirm_your_email_address: "Email címed megerősítése", + contact_us: "Kapcsolat", + contact_us_verification_required: "A használathoz érvényesített email címmel kell rendelkezned.", + contain: "Tartalmaz", + continue: "Folytatás", + copy: "Másolás", + copy_link: "Link másolása", + copying: "Másolás", + copying_file: "Másolás: %%", + cover: "Borító", + create_account: "Fiók létrehozása", + create_free_account: "Ingyenes fiók létrehozása", + create_shortcut: "Parancsikon létrehozása", + credits: "Kreditek", + current_password: "Jelenlegi jelszó", + cut: "Kivágás", + clock: "Óra", + clock_visible_hide: "Elrejt - Mindig rejtett", + clock_visible_show: "Megjelenít - Mindig látható", + clock_visible_auto: "Automatikus - Alapértelmezett, csak teljes képernyős módban látható.", + close_all: "Összes bezárása", + created: "Létrehozva", + date_modified: "Módosítás dátuma", + default: "Alapértelmezett", + delete: "Törlés", + delete_account: "Fiók törlése", + delete_permanently: "Végleges törlés", + deleting_file: "Törlés: %%", + deploy_as_app: "Alkalmazásként telepít", + descending: "Csökkenő", + desktop: "Asztal", + desktop_background_fit: "Illesztés", + developers: "Fejlesztők", + dir_published_as_website: "%strong% közzétéve a következő címen:", + disable_2fa: "2FA letiltása", + disable_2fa_confirm: "Biztosan letiltod a 2FA-t?", + disable_2fa_instructions: "Add meg a jelszavad a 2FA letiltásához.", + disassociate_dir: "Könyvtár leválasztása", + documents: "Dokumentumok", + dont_allow: "Nem engedélyez", + download: "Letöltés", + download_file: "Fájl letöltése", + downloading: "Letöltés", + email: "Email", + email_change_confirmation_sent: "Megerősítő emailt küldtünk az új email címedre. Kérlek, ellenőrizd a postaládádat és kövesd az utasításokat a folyamat befejezéséhez.", + email_invalid: "Érvénytelen email cím.", + email_or_username: "Email vagy Felhasználónév", + email_required: "Email szükséges.", + empty_trash: "Kuka ürítése", + empty_trash_confirmation: "Biztosan véglegesen törölni akarod a Kukában lévő elemeket?", + emptying_trash: "Kuka ürítése...", + enable_2fa: "2FA engedélyezése", + end_hard: "Kemény befejezés", + end_process_force_confirm: "Biztosan kényszerített kilépést hajtasz végre erre a folyamatra?", + end_soft: "Lágy befejezés", + enlarged_qr_code: "Nagyított QR kód", + enter_password_to_confirm_delete_user: "Add meg a jelszavad a fiók törlésének megerősítéséhez", + error_message_is_missing: "Hiányzik a hibaüzenet.", + error_unknown_cause: "Ismeretlen hiba történt.", + error_uploading_files: "Fájlok feltöltése sikertelen", + favorites: "Kedvencek", + feedback: "Visszajelzés", + feedback_c2a: "Kérlek, használd az alábbi űrlapot, hogy elküldd nekünk visszajelzésedet, észrevételeidet és hibajelentéseidet.", + feedback_sent_confirmation: "Köszönjük, hogy kapcsolatba léptél velünk. Ha van email címed a fiókodhoz társítva, hamarosan hallani fogsz rólunk.", + fit: "Illesztés", + folder: "Mappa", + force_quit: "Kényszerített kilépés", + forgot_pass_c2a: "Elfelejtetted a jelszavad?", + from: "Tól", + general: "Általános", + get_a_copy_of_on_puter: "Szerezz egy példányt a(z) '%%' Puter.com-on!", + get_copy_link: "Másolási link megszerzése", + hide_all_windows: "Minden ablak elrejtése", + home: "Otthon", + html_document: "HTML dokumentum", + hue: "Színárnyalat", + image: "Kép", + incorrect_password: "Helytelen jelszó", + invite_link: "Meghívó link", + item: "elem", + items_in_trash_cannot_be_renamed: "Ez az elem nem nevezhető át, mert a kukában van. A név megváltoztatásához először húzd ki a Kukából.", + jpeg_image: "JPEG kép", + keep_in_taskbar: "Tartsa a tálcán", + language: "Nyelv", + license: "Licenc", + lightness: "Világosság", + link_copied: "Link másolva", + loading: "Betöltés", + log_in: "Bejelentkezés", + log_into_another_account_anyway: "Bejelentkezés egy másik fiókba", + log_out: "Kijelentkezés", + looks_good: "Jól néz ki!", + manage_sessions: "Munkamenetek kezelése", + menubar_style: "Menü stílusa", + menubar_style_desktop: "Asztal", + menubar_style_system: "Rendszer", + menubar_style_window: "Ablak", + modified: "Módosítva", + move: "Mozgatás", + moving_file: "Mozgatás: %%", + my_websites: "Saját weboldalaim", + name: "Név", + name_cannot_be_empty: "A név nem lehet üres.", + name_cannot_contain_double_period: "A név nem tartalmazhatja a '..' karaktert.", + name_cannot_contain_period: "A név nem tartalmazhatja a '.' karaktert.", + name_cannot_contain_slash: "A név nem tartalmazhatja a '/' karaktert.", + name_must_be_string: "A név csak szöveg lehet.", + name_too_long: "A név nem lehet hosszabb, mint %% karakter.", + new: "Új", + new_email: "Új email", + new_folder: "Új mappa", + new_password: "Új jelszó", + new_username: "Új felhasználónév", + no: "Nem", + no_dir_associated_with_site: "Ehhez a címhez nincs társítva könyvtár.", + no_websites_published: "Még nem publikáltál egyetlen weboldalt sem. Kattints jobb gombbal egy mappára a kezdéshez.", + ok: "Rendben", + open: "Megnyitás", + open_in_new_tab: "Megnyitás új lapon", + open_in_new_window: "Megnyitás új ablakban", + open_with: "Megnyitás ezzel", + original_name: "Eredeti név", + original_path: "Eredeti útvonal", + oss_code_and_content: "Nyílt forráskódú szoftver és tartalom", + password: "Jelszó", + password_changed: "Jelszó megváltoztatva.", + password_recovery_rate_limit: "Elérted a korlátunkat; kérlek, várj néhány percet. A jövőben kerüld az oldal túl sokszori újratöltését.", + password_recovery_token_invalid: "Ez a jelszó visszaállítási token már nem érvényes.", + password_recovery_unknown_error: "Ismeretlen hiba történt. Kérlek, próbáld újra később.", + password_required: "Jelszó szükséges.", + password_strength_error: "A jelszónak legalább 8 karakter hosszúnak kell lennie és tartalmaznia kell legalább egy nagybetűt, egy kisbetűt, egy számot és egy speciális karaktert.", + passwords_do_not_match: "'Új jelszó' és 'Új jelszó megerősítése' nem egyeznek.", + paste: "Beillesztés", + paste_into_folder: "Beillesztés a mappába", + path: "Útvonal", + personalization: "Személyre szabás", + pick_name_for_website: "Válassz nevet a weboldaladnak:", + picture: "Kép", + pictures: "Képek", + plural_suffix: "k", + powered_by_puter_js: "A Puter.js hajtja", + preparing: "Előkészítés...", + preparing_for_upload: "Feltöltés előkészítése...", + print: "Nyomtatás", + privacy: "Adatvédelem", + proceed_to_login: "Folytatás a bejelentkezéshez", + proceed_with_account_deletion: "Fiók törlésének folytatása", + process_status_initializing: "Inicializálás", + process_status_running: "Fut", + process_type_app: "Alkalmazás", + process_type_init: "Inicializálás", + process_type_ui: "Felhasználói felület", + properties: "Tulajdonságok", + public: "Nyilvános", + publish: "Közzététel", + publish_as_website: "Közzététel weboldalként", + puter_description: "A Puter egy adatvédelmi elsőként kezelt személyes felhő, amelyben minden fájlodat, alkalmazásodat és játékodat egy biztonságos helyen tárolhatod, bárhonnan, bármikor elérhetően.", + reading_file: "Fájl olvasása: %strong%", + recent: "Legutóbbi", + recommended: "Ajánlott", + recover_password: "Jelszó visszaállítása", + refer_friends_c2a: "Kapj 1 GB-ot minden barátodért, aki létrehoz és megerősít egy fiókot a Puteren. A barátod is kap 1 GB-ot!", + refer_friends_social_media_c2a: "Kapj 1 GB ingyenes tárhelyet a Puter.com-on!", + refresh: "Frissítés", + release_address_confirmation: "Biztosan felszabadítod ezt a címet?", + remove_from_taskbar: "Eltávolítás a tálcáról", + rename: "Átnevezés", + repeat: "Ismétlés", + replace: "Csere", + replace_all: "Összes cseréje", + resend_confirmation_code: "Megerősítő kód újraküldése", + reset_colors: "Színek visszaállítása", + restart_puter_confirm: "Biztosan újraindítod a Putert?", + restore: "Visszaállítás", + save: "Mentés", + saturation: "Telítettség", + save_account: "Fiók mentése", + save_account_to_get_copy_link: "A folytatáshoz kérlek, hozz létre egy fiókot.", + save_account_to_publish: "A folytatáshoz kérlek, hozz létre egy fiókot.", + save_session: "Munkamenet mentése", + save_session_c2a: "Hozz létre egy fiókot, hogy mentsd az aktuális munkamenetedet és elkerüld a munkád elvesztését.", + scan_qr_c2a: "Olvasd be az alábbi kódot, hogy bejelentkezhess ebbe a munkamenetbe más eszközökről", + scan_qr_2fa: "Olvasd be a QR-kódot a hitelesítő alkalmazásoddal", + scan_qr_generic: "Olvasd be ezt a QR-kódot a telefonoddal vagy más eszközzel", + search: "Keresés", + seconds: "másodperc", + security: "Biztonság", + select: "Kiválasztás", + selected: "kiválasztva", + select_color: "Szín kiválasztása...", + sessions: "Munkamenetek", + send: "Küldés", + send_password_recovery_email: "Jelszó visszaállító email küldése", + session_saved: "Köszönjük, hogy létrehoztál egy fiókot. Ez a munkamenet mentésre került.", + settings: "Beállítások", + set_new_password: "Új jelszó beállítása", + share: "Megosztás", + share_to: "Megosztás ide:", + share_with: "Megosztás valakivel:", + shortcut_to: "Parancsikon ide:", + show_all_windows: "Összes ablak megjelenítése", + show_hidden: "Rejtett megjelenítése", + sign_in_with_puter: "Bejelentkezés Puterrel", + sign_up: "Regisztráció", + signing_in: "Bejelentkezés...", + size: "Méret", + skip: "Kihagyás", + something_went_wrong: "Valami hiba történt.", + sort_by: "Rendezés", + start: "Indítás", + status: "Állapot", + storage_usage: "Tárhely használat", + storage_puter_used: "Puter által használt", + taking_longer_than_usual: "Kicsit tovább tart, mint általában. Kérlek várj...", + task_manager: "Feladatkezelő", + taskmgr_header_name: "Név", + taskmgr_header_status: "Állapot", + taskmgr_header_type: "Típus", + terms: "Feltételek", + text_document: "Szöveges dokumentum", + tos_fineprint: "A 'Ingyenes fiók létrehozása' gombra kattintva elfogadod a Puter {{link=terms}}Szolgáltatási feltételeit{{/link}} és {{link=privacy}}Adatvédelmi irányelveit{{/link}}.", + transparency: "Átlátszóság", + trash: "Kuka", + two_factor: "Kétfaktoros hitelesítés", + two_factor_disabled: "2FA letiltva", + two_factor_enabled: "2FA engedélyezve", + type: "Típus", + type_confirm_to_delete_account: "Írd be, hogy 'megerősít' a fiók törléséhez.", + ui_colors: "UI színek", + ui_manage_sessions: "Munkamenetkezelő", + ui_revoke: "Visszavonás", + undo: "Visszavonás", + unlimited: "Korlátlan", + unzip: "Kibontás", + upload: "Feltöltés", + upload_here: "Feltöltés ide", + usage: "Használat", + username: "Felhasználónév", + username_changed: "A felhasználónév sikeresen frissítve.", + username_required: "Felhasználónév szükséges.", + versions: "Verziók", + videos: "Videók", + visibility: "Láthatóság", + yes: "Igen", + yes_release_it: "Igen, Engedd El", + you_have_been_referred_to_puter_by_a_friend: "Egy barátod ajánlott téged a Puterhez!", + zip: "Zip", + zipping_file: "Tömörítés: %strong%", + + // === 2FA Setup === + setup2fa_1_step_heading: "Nyisd meg a hitelesítő alkalmazásod", + setup2fa_1_instructions: "Bármely hitelesítő alkalmazást használhatod, amely támogatja az időalapú egyszeri jelszó (TOTP) protokollt. Sok választási lehetőség van, de ha nem vagy biztos benne, az Authy jó választás Android és iOS rendszeren.", + setup2fa_2_step_heading: "Olvasd be a QR-kódot", + setup2fa_3_step_heading: "Add meg a 6-jegyű kódot", + setup2fa_4_step_heading: "Másold le a helyreállítási kódjaidat", + setup2fa_4_instructions: "Ezek a helyreállítási kódok az egyetlen módja annak, hogy hozzáférj a fiókodhoz, ha elveszíted a telefonodat vagy nem tudod használni a hitelesítő alkalmazásodat. Ügyelj arra, hogy biztonságos helyen tárold őket.", + setup2fa_5_step_heading: "2FA beállítás megerősítése", + setup2fa_5_confirmation_1: "A helyreállítási kódokat biztonságos helyen tároltam", + setup2fa_5_confirmation_2: "Készen állok a 2FA engedélyezésére", + setup2fa_5_button: "2FA engedélyezése", + + // === 2FA Login === + login2fa_otp_title: "2FA kód megadása", + login2fa_otp_instructions: "Add meg a 6-jegyű kódot a hitelesítő alkalmazásodból.", + login2fa_recovery_title: "Add meg egy helyreállítási kódot", + login2fa_recovery_instructions: "Add meg az egyik helyreállítási kódodat a fiókhoz való hozzáféréshez.", + login2fa_use_recovery_code: "Használj helyreállítási kódot", + login2fa_recovery_back: "Vissza", + login2fa_recovery_placeholder: "XXXXXXXX", + } +}; + +export default hu; From 747d7dea89876014b410c162f0b5c6a290d4a757 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 15 Jul 2024 20:03:14 -0400 Subject: [PATCH 0532/2119] Update SECURITY-ACKNOWLEDGEMENTS.md --- SECURITY-ACKNOWLEDGEMENTS.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/SECURITY-ACKNOWLEDGEMENTS.md b/SECURITY-ACKNOWLEDGEMENTS.md index d4c0da1cf8..499c24e901 100644 --- a/SECURITY-ACKNOWLEDGEMENTS.md +++ b/SECURITY-ACKNOWLEDGEMENTS.md @@ -5,4 +5,4 @@ We would like to thank the following security researchers for their responsible - Tim Suess: [GitHub](https://github.com/blackfortresslabs) | [Email](tim@blackfortresslabs.com) | [Website](https://www.blackfortresslabs.com) - xyzeva: [Github](https://github.com/xyzeva) | [Email](mailto:xyzeva@riseup.net) | [Website](https://kibty.town/) -- Yusuf Kelany: [GitHub](https://github.com/YusufYaser) | [Twitter](https://x.com/RealYusufYaser) +- Yusuf Kelany: [GitHub](https://github.com/YusufYaser) | [Twitter](https://x.com/RealYusufYaser) | [Website](https://yusufyaser.xyz) From 64e4299ac0a4c9e1de7a9d089e2d7529a9530818 Mon Sep 17 00:00:00 2001 From: bryanthaboi <116906279+bryanthaboi@users.noreply.github.com> Date: Tue, 16 Jul 2024 09:10:38 -0400 Subject: [PATCH 0533/2119] Update README.md --- README.md | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 60b7973bf0..03b495236a 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 100
-### 🐙 Docker Compose +### 🐙 Docker Compose (non-windows) ```bash @@ -72,6 +72,19 @@ docker compose up ```
+### 🐙 Docker Compose (windows powershell) + + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ ### ☁️ Puter.com Puter is available as a hosted service at [**puter.com**](https://puter.com). From 5833b391f100efa792bc4322f10151071dc32397 Mon Sep 17 00:00:00 2001 From: bryanthaboi <116906279+bryanthaboi@users.noreply.github.com> Date: Tue, 16 Jul 2024 09:17:35 -0400 Subject: [PATCH 0534/2119] Update README.md --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 03b495236a..7b9dd17216 100644 --- a/README.md +++ b/README.md @@ -61,7 +61,7 @@ mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 100
-### 🐙 Docker Compose (non-windows) +### 🐙 x 🍎🐧 Docker Compose (non-windows) ```bash @@ -72,7 +72,7 @@ docker compose up ```
-### 🐙 Docker Compose (windows powershell) +### 🐙 x 🪟 Docker Compose (windows powershell) ```powershell From 8e297cd7e30757073e2f96593c363a273b639466 Mon Sep 17 00:00:00 2001 From: Michal Hobot Date: Tue, 16 Jul 2024 17:55:34 +0200 Subject: [PATCH 0535/2119] Translate en.js as of 2024-07-10 --- src/gui/src/i18n/translations/pl.js | 177 ++++++++++++++++++++++++++-- 1 file changed, 170 insertions(+), 7 deletions(-) diff --git a/src/gui/src/i18n/translations/pl.js b/src/gui/src/i18n/translations/pl.js index 631dafc553..a3d2294bb4 100644 --- a/src/gui/src/i18n/translations/pl.js +++ b/src/gui/src/i18n/translations/pl.js @@ -22,77 +22,150 @@ const pl = { english_name: "Polish", code: "pl", dictionary: { + about: "Informacje o", + account: "Konto", + account_password: "Sprawdź hasło konta", access_granted_to: "Przyznano dostęp do", add_existing_account: "Dodaj istniejące konto", all_fields_required: 'Wszystkie pola są wymagane.', + allow: 'Pozwól', apply: "Zaaplikuj", ascending: 'Rosnąco', + associated_websites: "Powiązane strony", auto_arrange: 'Auto Aranżacja', background: "Tło", browse: "Przeglądaj", cancel: 'Anuluj', center: 'Środek', change_desktop_background: 'Zmień tło pulpitu…', + change_email: "Zmień email", change_language: "Zmień język", change_password: "Zmień hasło", + change_ui_colors: "Zmień kolory interfejsu", change_username: "Zmień użytkownika", + close: 'Zamknij', close_all_windows: "Zamknij wszystkie okna", + close_all_windows_confirm: "Czy jesteś pewien że chcesz zamknąć wszystkie okna?", close_all_windows_and_log_out: 'Zamknij wszystkie okna i wyloguj', change_always_open_with: "Czy chcesz zawsze otwierać ten typ pliku używając", color: 'Kolor', + confirm: 'Potwierdzam', + confirm_2fa_setup: 'Dodałem kod do mojej aplikacji autentykującej', + confirm_2fa_recovery: 'Zapisałem moje kody odzyskiwania w bezpiecznym miejscu', confirm_account_for_free_referral_storage_c2a: 'Stwórz konto i potwierdź swój adres e-mail, żeby dostać 1 GB darmowego miejsca. Twój znajomy również dostanie 1 GB darmowego miejsca.', + confirm_code_generic_incorrect: "Nieprawidłowy kod.", + confirm_code_generic_too_many_requests: "Zbyt wiele zapytań. Zaczekaj kilka minut.", + confirm_code_generic_submit: "Podaj kod", + confirm_code_generic_try_again: "Spróbuj jeszcze raz", + confirm_code_generic_title: "Wprowadź kod odzyskiwania", + confirm_code_2fa_instruction: "Wprowadź 6-cyfrowy kod ze swojej aplikacji autentykującej.", + confirm_code_2fa_submit_btn: "Wyślij", + confirm_code_2fa_title: "Wprowadź kod uwierzytelniania dwuskładnikowego", confirm_delete_multiple_items: 'Czy na pewno chcesz na zawsze usunąć te przedmioty?', confirm_delete_single_item: 'Czy chcesz na zawsze usunąć ten przedmiot?', confirm_open_apps_log_out: 'Masz otwarte aplikacje. Czy chcesz na pewno się wylogować?', confirm_new_password: "Potwierdź nowe hasło", + confirm_delete_user: "Czy jesteś pewien że chcesz skasować swoje konto? Wszystkie twoje pliki i dane zostaną trwale skasowane. Tej czynności nie da się cofnąć.", + confirm_delete_user_title: "Skasować konto?", + confirm_session_revoke: "Czy jesteś pewien że chcesz unieważnić tą sesję?", + confirm_your_email_address: "Potwierdź swój adres email", contact_us: "Skontaktuj się z nami", + contact_us_verification_required: "Twój adres email musi być potwierdzony aby tego użyć.", contain: 'Zawieraj', continue: "Kontynuuj", copy: 'Kopiuj', copy_link: "Kopiuj Link", copying: "Kopiowanie", + copying_file: "Kopiowanie %%", cover: 'Zakryj', create_account: "Stwórz konto", create_free_account: "Stwórz darmowe konto", create_shortcut: "Stwórz skrót", + credits: "Autorzy", current_password: "Aktualne hasło", cut: 'Wytnij', + clock: "Zegar", + clock_visible_hide: 'Ukryj - zawsze ukryty', + clock_visible_show: 'Pokaż - zawsze widoczny', + clock_visible_auto: 'Automatycznie - domyślne, widoczny tylko w trybie pełnoekranowym.', + close_all: 'Zamknij wszystko', + created: 'Stworzone', date_modified: 'Data zmodyfikowania', + default: 'Domyślne', delete: 'Usuń', + delete_account: "Skasuj konto", delete_permanently: "Usuń permamentnie", - deploy_as_app: 'Deploy as app', + deleting_file: "Usuwanie %%", + deploy_as_app: 'Wdrożenie jako apkę', descending: 'Malejąco', - desktop_background_fit: "Dostosuj", + desktop: 'Pulpit', + desktop_background_fit: "Dopasuj", + developers: "Deweloperzy", dir_published_as_website: `%strong% został opublikowany do:`, - disassociate_dir: "Disassociate Directory", + disable_2fa: 'Wyłącz uwierzytelnianie dwuskładnikowe', + disable_2fa_confirm: "Czy jesteś pewien że chcesz wyłączyć uwierzytelnianie dwuskładnikowe?", + disable_2fa_instructions: "Wprowadź swoje hasło aby wyłączyć uwierzytelnianie dwuskładnikowe.", + disassociate_dir: "Odłącz katalog", + documents: 'Dokumenty', + dont_allow: 'Nie pozwalaj', download: 'Pobierz', download_file: 'Pobierz plik', downloading: "Pobieranie", email: "Email", + email_change_confirmation_sent: "Email z potwierdzeniem został wysłany na twój adres. Sprawdź swoją skrzynkę mailową i wykonaj przesłane instrukcje aby zakończyć proces.", + email_invalid: 'Email jest nieprawidłowy.', email_or_username: "Email lub nazwa użytkownika", + email_required: 'Email jest wymagany.', empty_trash: 'Opróżnij Kosz', - empty_trash_confirmation: `Czy chcesz permanentnie usunąć pliki z kosza?`, + empty_trash_confirmation: `Czy chcesz nieodwracalnie usunąć pliki z kosza?`, emptying_trash: 'Opróżnianie Kosza...', + enable_2fa: 'Włącz uwierzytelnianie dwuskładnikowe', + end_hard: "Wymuś zakończenie", + end_process_force_confirm: "Czy jesteś pewien, że chcesz wymusić zakończenie tego procesu?", + end_soft: "Zakończ łagodnie", + enlarged_qr_code: "Powiększony kod QR", + enter_password_to_confirm_delete_user: "Wpisz swoje hasło aby potwierdzić skasowanie konta", + error_message_is_missing: "Brak komunikatu błędu.", + error_unknown_cause: "Wystąpił nieznany błąd.", + error_uploading_files: "Wgrywanie plików nie powiodło się", + favorites: "Ulubione", feedback: "Opinie", feedback_c2a: "Prosimy, aby użyć poniższego formularza do zwracania opinii, komentarzy i zgłaszania błędów.", - feedback_sent_confirmation: "Thank you for contacting us. If you have an email associated with your account, you will hear back from us as soon as possible.", + feedback_sent_confirmation: "Dziękujemy za kontakt. Jeżeli z twoim kontem powiązany jest adres email, skontaktujemy się z tobą tak szybko jak to możliwe.", + fit: "Dopasuj", + folder: 'Folder', + force_quit: 'Wymuś zakończenie', forgot_pass_c2a: "Zapomniałeś hasła?", from: "Od", general: "Ogólne", get_a_copy_of_on_puter: `Pobierz kopię '%%' na Puter.com!`, get_copy_link: 'Pobierz skopiowany link', hide_all_windows: "Zamknij wszystkie okna", + home: 'Początek', html_document: 'dokument HTML', + hue: 'Odcień', image: 'Obraz', + incorrect_password: "Nieprawidłowe hasło", invite_link: "Link zaproszeniowy", item: 'przedmiot', items_in_trash_cannot_be_renamed: `Nazwa tego przedmiotu nie może zostać zmieniona, ponieważ znajduje się on w koszu. Aby zmienić jego nazwę, wyciągnij go z kosza.`, jpeg_image: 'Obraz JPEG', keep_in_taskbar: 'Zachowaj na pasku zadań', + language: "Język", + license: "Licencja", + lightness: 'Jasność', + link_copied: "Link skopiowany", loading: 'Ładowanie', log_in: "Zaloguj się", log_into_another_account_anyway: 'Zaloguj się do innego konta mimo wszystko', log_out: 'Wyloguj się', + looks_good: "W porządku!", + manage_sessions: "Zarządzaj sesjami", + menubar_style: "Styl paska menu", + menubar_style_desktop: "Pulpit", + menubar_style_system: "System", + menubar_style_window: "Okno", + modified: 'Zmodyfikowany', move: 'Przenieś', moving_file: "Przenoszenie %%", my_websites: "Moje strony", @@ -104,6 +177,7 @@ const pl = { name_must_be_string: "Nazwa musi być napisem", name_too_long: `Nazwa nie może być dłuższa niż %% znaków.`, new: 'Nowy', + new_email: 'Nowy email', new_folder: 'Nowy folder', new_password: "Nowe hasło", new_username: "Nowa nazwa użytkownika", @@ -115,22 +189,45 @@ const pl = { open_in_new_tab: "Otwórz w nowej karcie", open_in_new_window: "Otwórz w nowym oknie", open_with: "Otwórz za pomocą", + original_name: 'Oryginalna nazwa', + original_path: 'Oryginalna ścieżka', + oss_code_and_content: "Oprogramowanie i treści open source", password: "Hasło", password_changed: "Hasło zostało zmienione.", + password_recovery_rate_limit: "Osiągnąłeś limit szybkości powtórzeń; poczekaj kilka minut. Aby zapobiec temu w przyszłości, unikaj wielokrotnego przeładowywania strony.", + password_recovery_token_invalid: "Ten kod odzyskiwania hasła nie jest już ważny.", + password_recovery_unknown_error: "Wystąpił nieznany błąd. Proszę spróbować później.", + password_required: 'Wymagane jest hasło.', + password_strength_error: "Hasło musi mieć co najmniej 8 znaków i musi zawierać co najmniej jedną: dużą literę, małą literę, cyfrę i znak specjalny.", passwords_do_not_match: 'Pola `Nowe hasło` i `Potwierdź nowe hasło` nie są takie same.', paste: 'Wklej', paste_into_folder: "Wklej do folderu", + path: 'Ścieżka', + personalization: "Personalizacja", pick_name_for_website: "Wybierz nazwę dla swojej strony:", picture: "Obraz", + pictures: 'Obrazy', + plural_suffix: '', //In polish there is a ton of plural suffixes, so I just left it empty powered_by_puter_js: `Zasilane za pomocą {{link=docs}}Puter.js{{/link}}`, preparing: "Przygotowywanie...", preparing_for_upload: "Przygotowywanie do wgrania...", + print: 'Drukuj', + privacy: "Prywatność", proceed_to_login: 'Przejdź do logowania', + proceed_with_account_deletion: "Przejdź do kasowania konta", + process_status_initializing: "Rozpoczynanie", + process_status_running: "Działanie", + process_type_app: 'Apka', + process_type_init: 'Start', + process_type_ui: 'UI', properties: "Właściwości", + public: 'Publiczny', publish: "Opublikuj", publish_as_website: 'Opublikuj jako stronę', - plural_suffix: '', //In polish there is a ton of plural suffixes, so I just left it empty + puter_description: `Puter to zachowująca twoją prywatność osobista chmura, służąca do przechowywania wszystkich twoich plików, aplikacji i gier w jednym, bezpiecznym miejscu, dostępnym z dowolnego miejsca w dowolnej chwili.`, + reading_file: "Odczyt %strong%", recent: "Ostatni", + recommended: "Polecane", recover_password: "Odzyskaj hasło", refer_friends_c2a: "Zdobądź 1 GB za każdego znajomego, który założy konto na Puter! On również otrzyma 1 GB.", refer_friends_social_media_c2a: `Zdobądź 1 GB darmowego miejsca na Puter.com!`, @@ -142,21 +239,35 @@ const pl = { replace: 'Zamień', replace_all: 'Zamień wszystkie', resend_confirmation_code: "Wyślij kod potwierdzający ponownie.", + reset_colors: "Przywróc kolory", + restart_puter_confirm: "Na pewno zrestartować Puter?", restore: "Odzyskaj", + save: 'Zapisz', + saturation: 'Nasycenie', save_account: 'Zapisz konto', save_account_to_get_copy_link: "Zapisz konto, aby uzyskać link do skopiowania", save_account_to_publish: 'Zapisz konto, aby opublikować', save_session: 'Zapisz sesję', save_session_c2a: 'Stwórz konto, żeby zapisać aktualną sesję i nie utracić swojej pracy.', scan_qr_c2a: 'Zeskanuj kod poniżej, żeby zalogować się na tą sesję z innych urządzeń.', + scan_qr_2fa: 'Zeskanuj kod QR za pomocą apki autentykującej', + scan_qr_generic: 'Zeskanuj ten kod QR za pomocą swojego telefonu albo innego urządzenia', + search: 'Szukaj', + seconds: 'sekund', + security: "Bezpieczeństwo", select: "Wybierz", selected: 'Wybrany', select_color: 'Wybierz kolor…', + sessions: "Sesje", send: "Wyślij", send_password_recovery_email: "Wyślij email do odzyskania hasła", session_saved: "Dziękujemy za stworzenie konta. Ta sesja została zapisana. ", + settings: "Ustawienia", set_new_password: "Ustaw nowe hasło.", + share: "Udostępnij", share_to: "Udostępnij do", + share_with: "Udostępnij dla:", + shortcut_to: "Skrót do", show_all_windows: "Pokaż wszystkie okna", show_hidden: 'Pokaż ukryte', sign_in_with_puter: "Zaloguj się z Puter", @@ -164,25 +275,77 @@ const pl = { signing_in: "Logowanie…", size: 'Rozmiar', skip: 'Pomiń', + something_went_wrong: "Coś poszło nie tak.", sort_by: 'Sortuj', start: 'Start', + status: "Status", + storage_usage: "Wykorzystanie miejsca", + storage_puter_used: 'wykorzystane przez Puter', taking_longer_than_usual: 'To trwa chwilę dłużej niż zwyklę. Prosimy poczekać...', + task_manager: "Menedżer zadań", + taskmgr_header_name: "Nazwa", + taskmgr_header_status: "Status", + taskmgr_header_type: "Typ", + terms: "Warunki", text_document: 'Dokument tekstowy', tos_fineprint: `Klikając 'Stwórz darmowe konto' Zgadzasz się z {{link=terms}}Warunkami Obsługi{{/link}} i {{link=privacy}}Polityką Prywatności{{/link}}.`, + transparency: "Przejrzystość", trash: 'Kosz', + two_factor: 'Uwierzytelnianie dwuetapowe', + two_factor_disabled: 'Uwierzytelnianie dwuetapowe zablokowane', + two_factor_enabled: 'Uwierzytelnianie dwuetapowe odblokowane', type: 'Wpisz', + type_confirm_to_delete_account: "Wpisz 'potwierdzam', aby skasować swoje konto.", + ui_colors: "Kolory interfejsu użytkownika", + ui_manage_sessions: "Menedżer sesji", + ui_revoke: "Wycofaj", undo: 'Cofnij', + unlimited: 'Nieograniczone', unzip: "Rozpakuj", upload: 'Wgraj', upload_here: 'Wgraj tutaj', + usage: 'Wykorzystanie', username: "Nazwa użytkownika", username_changed: 'Nazwa użytkownika została zmieniona pomyślnie.', + username_required: 'Nazwa użytkownika jest wymagana.', versions: "Wersje", + videos: 'Wideo', + visibility: 'Widoczność', yes: 'Tak', yes_release_it: 'Tak, Opublikuj', you_have_been_referred_to_puter_by_a_friend: "Zostałeś wspomniany od znajomego!", zip: "Spakuj", + zipping_file: "Pakowanie %strong%", + + // === 2FA Setup === + setup2fa_1_step_heading: 'Otwórz swoją aplikację autentykującą', + setup2fa_1_instructions: ` + Możesz użyć dowolnej aplikacji autentykującej, która wspiera protokół haseł jednorazowych opartych o czas (TOTP). + Jest ich wiele, ale jeżeli nie masz pewności, + Authy + to solidny wybór dla systemów Android i iOS. + `, + setup2fa_2_step_heading: 'Zeskanuj kod QR', + setup2fa_3_step_heading: 'Wprowadź 6-cyfrowy kod', + setup2fa_4_step_heading: 'Skopiuj swoje kody odzyskiwania', + setup2fa_4_instructions: ` + Te kody odzyskiwania są jedynym sposobem aby uzyskać dostęp do twojego konta jeżeli stracisz swój telefon lub nie jesteś w stanie użyć aplikacji autentykującej. + Upewnij się, że przechowujesz je w bezpiecznym miejscu + `, + setup2fa_5_step_heading: 'Potwierdź ustawienia autentykacji dwuetapowej', + setup2fa_5_confirmation_1: 'Zachowałem moje kody odzyskiwania w bezpiecznym miejscu', + setup2fa_5_confirmation_2: 'Jestem gotów aby włączyć autentykację dwuetapową', + setup2fa_5_button: 'Włącz autentykację dwuetapową', + + // === 2FA Login === + login2fa_otp_title: 'Wprowadź kod autentykacji dwuetapowej', + login2fa_otp_instructions: 'Wprowadź 6-cyfrowy kod ze swojej aplikacji autentykującej.', + login2fa_recovery_title: 'Wprowadź kod odzyskiwania', + login2fa_recovery_instructions: 'Wprowadź jeden ze swoich kodów odzyskiwania aby uzyskać dostęp do swojego konta.', + login2fa_use_recovery_code: 'Użyj kod odzyskiwania', + login2fa_recovery_back: 'Powrót', + login2fa_recovery_placeholder: 'XXXXXXXX', } }; -export default pl; \ No newline at end of file +export default pl; From 3ca92955cb002e3a9f0b99b0f3b91f36faeae897 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 16 Jul 2024 15:56:37 -0700 Subject: [PATCH 0536/2119] Make the screenshot a little larger --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 60b7973bf0..4aee172050 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Bug Bounty

-

screenshot

+

screenshot


From cc4c93b77f95e854e950c6e53ab68f722eeb7cb1 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 16 Jul 2024 15:56:59 -0700 Subject: [PATCH 0537/2119] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 4aee172050..539932a284 100644 --- a/README.md +++ b/README.md @@ -19,7 +19,7 @@ Bug Bounty

-

screenshot

+

screenshot


From 151527825f1eb4b060aaf97feb7d18af4fcddbf2 Mon Sep 17 00:00:00 2001 From: Koppeks Date: Tue, 16 Jul 2024 20:30:42 -0300 Subject: [PATCH 0538/2119] update translation file es.js to be up to date with the file en.js --- src/gui/src/i18n/translations/es.js | 236 +++++++++++++++++++++++++--- 1 file changed, 213 insertions(+), 23 deletions(-) diff --git a/src/gui/src/i18n/translations/es.js b/src/gui/src/i18n/translations/es.js index 8ff49e19f4..2de11e0b1b 100644 --- a/src/gui/src/i18n/translations/es.js +++ b/src/gui/src/i18n/translations/es.js @@ -17,72 +17,162 @@ * along with this program. If not, see . */ +/** + * Traslation notes: + * - Change all "Email" to "Correo electrónico" + * - puter_description the most acurated translation for "privacy-first personal cloud" I could think of is "servicio de nube personal enfocado en privacidad" + * - plural_suffix: 's' has no direct translation to spanish. There are multiple plural suffix in spanish 'as' || "es" || "os || "s". Leave "s" as it is only been used on item: 'elemento' and will end up as 'elementos' +*/ + const es = { name: "Español", english_name: "Spanish", code: "es", dictionary: { + about: "Acerca De", + account: "Cuenta", + account_password: "Verifica Contraseña De La Cuenta", access_granted_to: "Acceso Permitido A", add_existing_account: "Añadir una cuenta existente", all_fields_required: 'Todos los campos son obligatorios.', + allow: 'Permitir', apply: "Aplicar", ascending: 'Ascendiente', + associated_websites: "Sitios Web Asociados", + auto_arrange: 'Organización Automática', background: "Fondo", browse: "Buscar", cancel: 'Cancelar', center: 'Centrar', change_desktop_background: 'Cambiar el fondo de pantalla…', + change_email: "Cambiar Correo Electrónico", change_language: "Cambiar Idioma", change_password: "Cambiar Contraseña", + change_ui_colors: "Cambiar colores de la interfaz", change_username: "Cambiar Nombre de Usuario", + close: 'Cerrar', close_all_windows: "Cerrar todas las ventanas", + close_all_windows_confirm: "¿Estás seguro de que quieres cerrar todas las ventanas?", + close_all_windows_and_log_out: 'Cerrar ventanas y cerrar sesión', + change_always_open_with: "¿Quieres abrir siempre este tipo de archivos con", color: 'Color', - confirm_account_for_free_referral_storage_c2a: 'Crea una cuenta y confirma tu dirección de email para recibir 1 GB de almacenamiento gratuito. Tu amigo recibirá 1 GB de almacenamiento gratuito también.', + confirm: 'Confirmar', + confirm_2fa_setup: 'He añadido el código a mi aplicación de autenticación', + confirm_2fa_recovery: 'He guardado mis códigos de recuperación en un lugar seguro', + confirm_account_for_free_referral_storage_c2a: 'Crea una cuenta y confirma tu correo electrónico para recibir 1 GB de almacenamiento gratuito. Tu amigo recibirá 1 GB de almacenamiento gratuito también.', + confirm_code_generic_incorrect: "Código incorrecto.", + confirm_code_generic_too_many_requests: "Too many requests. Please wait a few minutes.", + confirm_code_generic_submit: "Enviar código", + confirm_code_generic_try_again: "Intenta nuevamente", + confirm_code_generic_title: "Enter Confirmation Code", + confirm_code_2fa_instruction: "Ingresa los 6 dígitos de tu aplicación de autenticación.", + confirm_code_2fa_submit_btn: "Enviar", + confirm_code_2fa_title: "Ingrese el código de 2FA", + confirm_delete_multiple_items: '¿Estás seguro de que quieres eliminar permanentemente estos elementos?', + confirm_delete_single_item: '¿Quieres eliminar este elemento permanentemente?', + confirm_open_apps_log_out: 'Tienes aplicaciones abiertas.¿Estás seguro de que quieres cerrar sesión?', confirm_new_password: "Confirma la Nueva Contraseña", + confirm_delete_user: "¿Estás seguro que quieres borrar esta cuenta? Todos tus archivos e información serán borrados permanentemente. Esta acción no se puede deshacer.", + confirm_delete_user_title: "¿Eliminar cuenta?", + confirm_session_revoke: "¿Estás seguro de que quieres revocar esta sesión?", + confirm_your_email_address: "Confirma tu dirección de correo electrónico", contact_us: "Contáctanos", + contact_us_verification_required: "Debes tener un correo electrónico verificado para usar esto.", contain: 'Contiene', continue: "Continuar", copy: 'Copiar', copy_link: "Copiar Enlace", copying: "Copiando", + copying_file: "Copiando %%", cover: 'Cubrir', create_account: "Crear una cuenta", create_free_account: "Crear una cuenta gratuita", create_shortcut: "Crear un acceso directo", + credits: "Creditos", current_password: "Contraseña actual", cut: 'Cortar', + clock: "Reloj", + clock_visible_hide: 'Ocultar - Siempre oculto', + clock_visible_show: 'Mostrar - Siempre visible', + clock_visible_auto: 'Auto - Por defecto, visible solo en modo pantalla completa.', + close_all: 'Cerrar todo', + created: 'Creado', date_modified: 'Fecha de modificación', + default: 'Por defecto', delete: 'Borrar', + delete_account: "Borrar cuenta", delete_permanently: "Borrar permanentemente", + deleting_file: "Eliminando %%", deploy_as_app: 'Desplegar como una aplicación', descending: 'Descendiente', - desktop_background_fit: "Llenar", - dir_published_as_website: `%strong% ha sido publicado a:`, + desktop: 'Escritorio', + desktop_background_fit: "Ajustar", + developers: "Desarrolladores", + dir_published_as_website: `%strong% ha sido publicado en:`, + disable_2fa: 'Deshabilitar 2FA', + disable_2fa_confirm: "¿Estás seguro que quieres deshabilitar 2FA?", + disable_2fa_instructions: "Ingresa tu contraseña para deshabilitar 2FA.", disassociate_dir: "Desvincular directorio", + documents: 'Documentos', + dont_allow: 'No permitir', download: 'Descargar', + download_file: 'Descargar archivo', downloading: "Descargando", - email: "Email", - email_or_username: "Email o Nombre de Usuario", + email: "Correo electrónico", + email_change_confirmation_sent: "Se ha enviado un mensaje de confirmación a tu nueva dirección de correo electrónico. Por favor, revisa tu bandeja de entrada y sigue las instrucciónes para completar el proceso.", + email_invalid: 'El correo electrónico no es válido.', + email_or_username: "Correo electrónico o Nombre de Usuario", + email_required: 'El correo electrónico es obligatorio.', empty_trash: 'Vaciar la papelera', empty_trash_confirmation: `¿Estás seguro de que quieres borrar permanentemente todos los elementos de la Papelera?`, emptying_trash: 'Vaciando la papelera…', - feedback: "Feedback", - feedback_c2a: "Por favor, usa el formulario para enviarnos tu feedback, comentario y reportar bugs.", - feedback_sent_confirmation: "Gracias por ponerte en contacto con nosotros. Si tienes un email vinculado con la cuenta, nos pondremos en contacto contigo tan pronto como podamos.", - forgot_pass_c2a: "¿Contraseña olvidada?", + enable_2fa: 'Habilitar 2FA', + end_hard: "Finalizar abruptamente", + end_process_force_confirm: "¿Estás seguro de que quieres forzar la salida de este proceso?", + end_soft: "Finalizar suavemente", + enlarged_qr_code: "Código QR ampliado", + enter_password_to_confirm_delete_user: "Ingresa tu contraseña para confirmar la eliminación de la cuenta", + error_message_is_missing: "Falta el mensaje de error.", + error_unknown_cause: "Un error desconocido a ocurrido.", + error_uploading_files: "Error al subir archivos", + favorites: "Favoritos", + feedback: "Sugerencias", + feedback_c2a: "Por favor, usa el formulario para enviarnos tus sugerencias, comentarios y reporte de errores.", + feedback_sent_confirmation: "Gracias por ponerte en contacto con nosotros. Si tienes un correo electrónico vinculado a esta cuenta, nos pondremos en contacto contigo tan pronto como podamos.", + fit: "Ajustar", + folder: 'Carpeta', + force_quit: 'Forzar cierre', + forgot_pass_c2a: "¿Olvidaste tu contraseña?", from: "De", general: "General", get_a_copy_of_on_puter: `¡Consigue una copia de '%%' en Puter.com!`, get_copy_link: 'Copiar el enlace', - hide_all_windows: "Ocultar Todas las Ventanas", + hide_all_windows: "Ocultar todas las ventanas", + home: 'Inicio', html_document: 'Documento HTML', + hue: 'Hue', image: 'Imagen', + incorrect_password: "Contraseña incorrecta", invite_link: "Enlace de invitación", + item: 'elemento', items_in_trash_cannot_be_renamed: `Este elemento no se puede renombrar porque está en la papelera. Para cambiar el nombre de este archivo, primero extráelo fuera de la misma.`, jpeg_image: 'Imagen JPEG', - keep_in_taskbar: 'Fijar a la barra de tareas', + keep_in_taskbar: 'Mantener en la barra de tareas', + language: "Lenguage", + license: "Licencia", + lightness: 'Claridad', + link_copied: "Enlace copiado", + loading: 'Cargando', log_in: "Iniciar sesión", + log_into_another_account_anyway: 'Iniciar sesión en otra cuenta de todos modos', log_out: 'Cerrar sesión', + looks_good: "Se ve bien!", + manage_sessions: "Administrar sesión", + menubar_style: "Estilo de la barra de menú", + menubar_style_desktop: "Escritorio", + menubar_style_system: "Sistema", + menubar_style_window: "Ventana", + modified: 'Modified', move: 'Mover', moving_file: "Moviendo %%", my_websites: "Mis páginas web", @@ -94,74 +184,174 @@ const es = { name_must_be_string: "El nombre debe ser una cadena de texto.", name_too_long: `El nombre no puede tener más de %% caracteres.`, new: 'Nuevo', + new_email: 'Nuevo correo electrónico', new_folder: 'Nueva carpeta', new_password: "Nueva contraseña", new_username: "Nuevo nombre de usuario", + no: 'No', no_dir_associated_with_site: 'No hay un directorio vinculado con esta dirección.', - no_websites_published: "No has publicado ninguna página web todavía.", + no_websites_published: "Aun no has publicado ningún sitio web. Haz click derecho en una carpeta para empezar", ok: 'OK', open: "Abrir", - open_in_new_tab: "Abrir en una Nueva Pestaña", - open_in_new_window: "Abrir en una Nueva Ventana", - open_with: "Abrir Con", + open_in_new_tab: "Abrir en una nueva pestaña", + open_in_new_window: "Abrir en una nueva ventana", + open_with: "Abrir con", + original_name: 'Nombre original', + original_path: 'Ruta original', + oss_code_and_content: "Software y contenido de código abierto", password: "Contraseña", password_changed: "Contraseña cambiada.", - passwords_do_not_match: '`Nueva Contraseña` y `Confirmar Nueva Contraseña` no coincide.', + password_recovery_rate_limit: "Haz alcanzado nuestra tasa de refresco; por favor espera unos minutos. Para evitar esto en el futuro, evita refrescar la página muchas veces.", + password_recovery_token_invalid: "La contraseña de token de recuperación ya no es válida.", + password_recovery_unknown_error: "Ocurrió un error desconocido. Por favor, inténtalo de nuevo más tarde.", + password_required: 'La contraseña es obligatoria.', + password_strength_error: "La contraseña debe tener almenos 8 caracteres de largo y contener almenos una letra mayúscula, una minúscula, un numero, y un caracter especial.", + passwords_do_not_match: '`Nueva Contraseña` y `Confirmar Nueva Contraseña` no coinciden.', paste: 'Pegar', paste_into_folder: "Pegar en la Carpeta", + path: 'Ruta', + personalization: "Personalización", pick_name_for_website: "Escoge un nombre para tu página web:", picture: "Imagen", + pictures: 'Imagenes', + plural_suffix: 's', powered_by_puter_js: `Creado por {{link=docs}}Puter.js{{/link}}`, preparing: "Preparando...", preparing_for_upload: "Preparando para la subida...", + print: 'Imprimir', + privacy: "Privacidad", + proceed_to_login: 'Procede a iniciar sesión', + proceed_with_account_deletion: "Procede con la eliminación de la cuenta", + process_status_initializing: "Inicializando", + process_status_running: "El ejecución", + process_type_app: 'Aplicación', + process_type_init: 'Inicialización', + process_type_ui: 'Interfaz de usuario', properties: "Propiedades", + public: 'Publico', publish: "Publicar", publish_as_website: 'Publicar como página web', + puter_description: `Puter es un servicio de nube personal enfocado en privacidad que mantiene tus archivos, aplicaciónes, y juegos en un solo lugar, accesible desde cualquier lugar en cualquier momento.`, + reading_file: "Leyendo %strong%", recent: "Reciente", + recommended: "Recomendado", recover_password: "Recuperar Contraseña", refer_friends_c2a: "Consigue 1 GB por cada amigo que cree y confirme una cuenta en Puter ¡Tu amigo recibirá 1GB también!", refer_friends_social_media_c2a: `¡Consigue 1 GB de almacenamiento gratuito en Puter.com!`, refresh: 'Refrescar', - release_address_confirmation: `¿Estás seguro de liberar esta dirección?`, + release_address_confirmation: `¿Estás seguro de que quieres liberar esta dirección?`, remove_from_taskbar:'Eliminar de la barra de tareas', rename: 'Renombrar', repeat: 'Repetir', + replace: 'Remplazar', + replace_all: 'Replace All', resend_confirmation_code: "Reenviar Código de Confirmación", + reset_colors: "Restablecer colores", + restart_puter_confirm: "¿Estás seguro que deseas reiniciar Puter?", restore: "Restaurar", + save: 'Guardar', + saturation: 'Saturación', + save_account: 'Guardar cuenta', save_account_to_get_copy_link: "Por favor, crea una cuenta para continuar.", save_account_to_publish: 'Por favor, crea una cuenta para continuar.', + save_session: 'Guardar sesión', save_session_c2a: 'Crea una cuenta para guardar tu sesión actual y evitar así perder tu trabajo.', - scan_qr_c2a: 'Escanea el código de debajo e inicia sesión desde otros dispositivos', + scan_qr_c2a: 'Escanee el código a continuación para inicia sesión desde otros dispositivos', + scan_qr_2fa: 'Escanee el codigo QR con su aplicación de autenticación', + scan_qr_generic: 'Scan this QR code using your phone or another device', + search: 'Buscar', + seconds: 'segundos', + security: "Seguridad", select: "Seleccionar", + selected: 'seleccionado', select_color: 'Seleccionar color…', + sessions: "Sesión", send: "Enviar", send_password_recovery_email: "Enviar la contraseña al correo de recuperación", session_saved: "Gracias por crear una cuenta. La sesión ha sido guardada.", set_new_password: "Establecer una nueva contraseña", - share_to: "Compartir con", + settings: "Opciones", + share: "Compartir", + share_to: "Compartir a", + share_with: "Compartir con:", + shortcut_to: "Acceso directo a", show_all_windows: "Mostrar todas las ventanas", show_hidden: 'Mostrar ocultos', sign_in_with_puter: "Inicia sesión con Puter", sign_up: "Registrarse", signing_in: "Registrándose…", size: 'Tamaño', + skip: 'Saltar', + something_went_wrong: "Algo salió mal.", sort_by: 'Ordenar Por', start: 'Inicio', - taking_longer_than_usual: 'Tardando un poco más de lo usual. Por favor, espere...', + status: "Estado", + storage_usage: "Uso del almacenamiento", + storage_puter_used: 'Usado por Puter', + taking_longer_than_usual: 'Tardando un poco más de lo habitual. Por favor, espere...', + task_manager: "Administrador de tareas", + taskmgr_header_name: "Nombre", + taskmgr_header_status: "Estado", + taskmgr_header_type: "Tipo", + terms: "Terminos", text_document: 'Documento de Texto', - tos_fineprint: `Pulsando sobre 'Crear una cuenta gratuita' aceptas los {{link=terms}}términos del servicio{{/link}} de Puter y {{link=privacy}}la política de privacidad{{/link}}.`, + tos_fineprint: `Al hacer clic en 'Crear una cuenta gratuita' aceptas los {{link=terms}}términos del servicio{{/link}} y {{link=privacy}}la política de privacidad{{/link}} de Puter.`, + transparency: "Transparencia", trash: 'Papelera', + two_factor: 'Autenticación de dos factores', + two_factor_disabled: '2FA Deshabilitadp', + two_factor_enabled: '2FA Habilitado', type: 'Tipo', + type_confirm_to_delete_account: "Ingrese 'Confirmar' para borrar esta cuenta.", + ui_colors: "Colores de interfaz", + ui_manage_sessions: "Administrador de sesión", + ui_revoke: "Revocar", undo: 'Deshacer', + unlimited: 'Ilimitado', unzip: "Descomprimir", upload: 'Subir', upload_here: 'Subir aquí', + usage: 'Uso', username: "Nombre de usuario", username_changed: 'Nombre de usuario actualizado correctamente.', + username_required: 'El nombre de usuario es obligatorio.', versions: "Versiones", - yes_release_it: 'Sí, liberar', + videos: 'Videos', + visibility: 'Visibilidad', + yes: 'Si', + yes_release_it: 'Sí, libéralo', you_have_been_referred_to_puter_by_a_friend: "¡Has sido invitado a Puter por un amigo!", - zip: "Comprimir en Zip", + zip: "Zip", + zipping_file: "Compriminendo %strong%", + + // === 2FA Setup === + setup2fa_1_step_heading: 'Abre tu aplicación de autenticación', + setup2fa_1_instructions: ` + Puedes usar cualquier aplicación de autenticación que soporte el protocolo de Time-based One-time (TOTP). + Hay muchos para elegir, pero si no estas seguro + Authy + es una opción segura para Android y iOS. + `, + setup2fa_2_step_heading: 'Escanea el código QR', + setup2fa_3_step_heading: 'Ingresa el código de 6 dígitos', + setup2fa_4_step_heading: 'Copiar tus códigos de recuperación', + setup2fa_4_instructions: ` + Estos códigos de recuperación son la única forma de acceder a tu cuenta, si pierdes tu teléfono o no puedes usar la aplicación de autenticación. + Asegurate de guardarlos en un lugar seguro. + `, + setup2fa_5_step_heading: 'Confirmar la configuración de 2FA', + setup2fa_5_confirmation_1: 'He guardado mis códigos de recuperación en un lugar seguro', + setup2fa_5_confirmation_2: 'Estoy listo para habilitar 2FA', + setup2fa_5_button: 'Habilitar 2FA', + + // === 2FA Login === + login2fa_otp_title: 'Ingresar el código 2FA', + login2fa_otp_instructions: 'Ingresa tu código de 6 dígitos de tu aplicación de autenticación.', + login2fa_recovery_title: 'Ingresa tu código de recuperación', + login2fa_recovery_instructions: 'Ingresa uno de tus códigos de recuperación para acceder a tu cuenta.', + login2fa_use_recovery_code: 'Usar un código de recuperación', + login2fa_recovery_back: 'Atras', + login2fa_recovery_placeholder: 'XXXXXXXX', } }; From c19c18bfcf163b37e3d173b8fa50393dfb9f540f Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 16 Jul 2024 16:32:42 -0700 Subject: [PATCH 0539/2119] Bring both Windows and Linux/Mac instructions under Docker Compose --- README.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 7b9dd17216..c2286d94aa 100644 --- a/README.md +++ b/README.md @@ -61,9 +61,10 @@ mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 100
-### 🐙 x 🍎🐧 Docker Compose (non-windows) +### 🐙 Docker Compose +#### Linux/macOS ```bash mkdir -p puter/config puter/data sudo chown -R 1000:1000 puter @@ -72,7 +73,7 @@ docker compose up ```
-### 🐙 x 🪟 Docker Compose (windows powershell) +#### Windows ```powershell From 6c29427e162922d4f95a0571008dd5c3998c9af3 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 16 Jul 2024 19:06:46 -0700 Subject: [PATCH 0540/2119] close #174 --- src/gui/src/UI/Settings/UIWindowSettings.js | 52 +++++- src/gui/src/css/style.css | 179 +++++++++++++++++--- 2 files changed, 204 insertions(+), 27 deletions(-) diff --git a/src/gui/src/UI/Settings/UIWindowSettings.js b/src/gui/src/UI/Settings/UIWindowSettings.js index e50999511c..fe80bf57ae 100644 --- a/src/gui/src/UI/Settings/UIWindowSettings.js +++ b/src/gui/src/UI/Settings/UIWindowSettings.js @@ -33,11 +33,15 @@ async function UIWindowSettings(options){ h += `
`; h += `
`; - // side bar + // sidebar toggle + h += ``; + // sidebar h += `
`; - tabs.forEach((tab, i) => { - h += `
${i18n(tab.title_i18n_key)}
`; - }); + // sidebar items + h += `
`; + tabs.forEach((tab, i) => { + h += `
${i18n(tab.title_i18n_key)}
`; + }); h += `
`; // content @@ -123,5 +127,45 @@ async function UIWindowSettings(options){ }); } +$(document).on('mousedown', '.sidebar-toggle', function(e) { + e.preventDefault(); + $('.settings-sidebar').toggleClass('active'); + $('.sidebar-toggle-button').toggleClass('active'); + // move sidebar toggle button + setTimeout(() => { + $('.sidebar-toggle').css({ + left: $('.settings-sidebar').hasClass('active') ? 243 : 2 + }); + }, 10); +}) + +$(document).on('click', '.settings-sidebar-item', function(e) { + // hide sidebar + $('.settings-sidebar').removeClass('active'); + // move sidebar toggle button ro the right + setTimeout(() => { + $('.sidebar-toggle').css({ + left: 2 + }); + }, 10); + +}) + +// clicking anywhere on the page will close the sidebar +$(document).on('click', function(e) { + // print event target class + + if (!$(e.target).closest('.settings-sidebar').length && !$(e.target).closest('.sidebar-toggle-button').length && !$(e.target).hasClass('sidebar-toggle-button') && !$(e.target).hasClass('sidebar-toggle')) { + $('.settings-sidebar').removeClass('active'); + $('.sidebar-toggle-button').removeClass('active'); + // move sidebar toggle button ro the right + setTimeout(() => { + $('.sidebar-toggle').css({ + left: 2 + }); + }, 10); + + } +}) export default UIWindowSettings \ No newline at end of file diff --git a/src/gui/src/css/style.css b/src/gui/src/css/style.css index e0cc475da2..1948ee6f66 100644 --- a/src/gui/src/css/style.css +++ b/src/gui/src/css/style.css @@ -17,7 +17,7 @@ * along with this program. If not, see . */ - @font-face { +@font-face { font-family: 'Inter'; src: url('/fonts/Inter-Thin.ttf') format('truetype'); font-weight: 100; @@ -805,6 +805,7 @@ span.header-sort-icon img { .window-menubar:not(.window-menubar-global):empty { display: none !important; } + .window-menubar { display: flex; box-sizing: border-box; @@ -815,7 +816,7 @@ span.header-sort-icon img { padding: 2px 5px; } -.window-menubar-global{ +.window-menubar-global { background-color: transparent; color: white; border-bottom: none; @@ -825,7 +826,8 @@ span.header-sort-icon img { margin-left: 15px; padding: 0; } -.window-menubar-global .window-menubar-item span{ + +.window-menubar-global .window-menubar-item span { padding: 3px 10px; font-size: 13px; border-radius: 3px; @@ -1595,13 +1597,16 @@ span.header-sort-icon img { display: none; pointer-events: none; } + .context-menu .has-open-context-menu-submenu, .context-menu .context-menu-item-active { border-radius: 4px; } -.context-menu .has-open-context-menu-submenu{ + +.context-menu .has-open-context-menu-submenu { background-color: #dfdfdf; } + .context-menu .context-menu-item-active { background-color: var(--select-color); color: white; @@ -2456,10 +2461,11 @@ label { /***************************************************** * Notification *****************************************************/ -.notification, .notification-wrapper{ +.notification, .notification-wrapper { width: 320px; border-radius: 11px; } + .notification { min-height: 54px; background: #ffffffcd; @@ -2472,9 +2478,11 @@ label { flex-direction: row; pointer-events: all; } -.notification-wrapper{ + +.notification-wrapper { overflow: visible; } + .notification-close { position: absolute; background: white; @@ -2491,7 +2499,8 @@ label { .notification:hover .notification-close { display: block; } -.notification-icon{ + +.notification-icon { width: 40px; margin: 10px 5px 10px 15px; border-radius: 50%; @@ -2500,25 +2509,30 @@ label { align-items: center; filter: drop-shadow(0px 0px 0.5px rgb(51, 51, 51)); } -.notification-icon img{ + +.notification-icon img { width: 35px; height: 35px; } -.notification-title{ + +.notification-title { font-size: 12px; font-weight: 600; } -.notification-text{ - font-size: 12px; + +.notification-text { + font-size: 12px; margin-top: 4px; } -.notification-content{ - flex-grow:1; + +.notification-content { + flex-grow: 1; display: flex; flex-direction: column; padding: 10px; } -.notification-container{ + +.notification-container { position: absolute; top: 40px; right: 10px; @@ -2527,7 +2541,7 @@ label { pointer-events: none; } -.notifications-close-all{ +.notifications-close-all { opacity: 0; position: absolute; top: 0px; @@ -2542,16 +2556,20 @@ label { cursor: pointer; filter: drop-shadow(0px 0px 0.5px rgb(51, 51, 51)); } -.notifications-close-all:hover{ + +.notifications-close-all:hover { background-color: #dee1e3; } -.notification-container.has-multiple{ + +.notification-container.has-multiple { pointer-events: all; } -.notification-container.has-multiple:hover .notifications-close-all{ + +.notification-container.has-multiple:hover .notifications-close-all { pointer-events: all; opacity: 1 !important; } + /***************************************************** * Start *****************************************************/ @@ -3027,12 +3045,13 @@ fieldset[name=number-code] { border: 2px solid #CCC; } -.launch-search-wrapper{ - margin-bottom: 10px; - padding: 5px; +.launch-search-wrapper { + margin-bottom: 10px; + padding: 5px; position: relative; } -.device-phone .launch-search-wrapper{ + +.device-phone .launch-search-wrapper { margin-top: 15px; } @@ -3572,7 +3591,7 @@ fieldset[name=number-code] { background-color: #f9f9f9; border-right: 1px solid #e0e0e0; padding: 20px; - + position: relative; } .settings-sidebar-item { @@ -3996,4 +4015,118 @@ fieldset[name=number-code] { flex-direction: row; gap: 10px; justify-content: flex-end; +} + +/* Extra small devices (phones, less than 576px) */ +@media (max-width: 575.98px) { + .hidden-xs { + display: none !important; + } +} + +/* Small devices (landscape phones, 576px and up) */ +@media (min-width: 576px) and (max-width: 767.98px) { + .hidden-sm { + display: none !important; + } +} + +/* Medium devices (tablets, 768px and up) */ +@media (min-width: 768px) and (max-width: 991.98px) { + .hidden-md { + display: none !important; + } +} + +/* Large devices (desktops, 992px and up) */ +@media (min-width: 992px) and (max-width: 1199.98px) { + .hidden-lg { + display: none !important; + } +} + +/* Extra large devices (large desktops, 1200px and up) */ +@media (min-width: 1200px) { + .hidden-xl { + display: none !important; + } +} + +/* Visible classes */ +.visible-xs, +.visible-sm, +.visible-md, +.visible-lg, +.visible-xl { + display: none !important; +} + +@media (max-width: 575.98px) { + .visible-xs { + display: block !important; + } + .settings-sidebar { + display: none; + position: fixed; + height: 100%; + z-index: 9; + } +} + +@media (min-width: 576px) and (max-width: 767.98px) { + .visible-sm { + display: block !important; + } + .settings-sidebar { + display: none; + position: fixed; + height: 100%; + z-index: 9; + } +} + +@media (min-width: 768px) and (max-width: 991.98px) { + .visible-md { + display: block !important; + } +} + +@media (min-width: 992px) and (max-width: 1199.98px) { + .visible-lg { + display: block !important; + } +} + +@media (min-width: 1200px) { + .visible-xl { + display: block !important; + } +} + +.sidebar-toggle{ + position: fixed; + z-index: 9999999999; + top: 32px; + left: 2px; + border: 0; + padding-top: 5px; + padding-bottom: 5px; +} +.sidebar-toggle .sidebar-toggle-button { + height: 20px; + width: 20px; +} + +.sidebar-toggle span:nth-child(1) { + margin-top: 5px; +} + +.sidebar-toggle span { + border-bottom: 2px solid #858585; + display: block; + margin-bottom: 5px; + width: 100%; +} +.settings-sidebar.active { + display: block; } \ No newline at end of file From 8bece96f6224a060d5b408e08c58865fadb8b79c Mon Sep 17 00:00:00 2001 From: Michal Hobot Date: Wed, 17 Jul 2024 15:43:23 +0200 Subject: [PATCH 0541/2119] Translation improvements, mainly style and context-based After using a Polish-translated puter I found out several places for improvement --- src/gui/src/i18n/translations/pl.js | 36 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/gui/src/i18n/translations/pl.js b/src/gui/src/i18n/translations/pl.js index a3d2294bb4..cb6ba1531c 100644 --- a/src/gui/src/i18n/translations/pl.js +++ b/src/gui/src/i18n/translations/pl.js @@ -22,7 +22,7 @@ const pl = { english_name: "Polish", code: "pl", dictionary: { - about: "Informacje o", + about: "Informacje", account: "Konto", account_password: "Sprawdź hasło konta", access_granted_to: "Przyznano dostęp do", @@ -36,7 +36,7 @@ const pl = { background: "Tło", browse: "Przeglądaj", cancel: 'Anuluj', - center: 'Środek', + center: 'Na środku', change_desktop_background: 'Zmień tło pulpitu…', change_email: "Zmień email", change_language: "Zmień język", @@ -55,7 +55,7 @@ const pl = { confirm_account_for_free_referral_storage_c2a: 'Stwórz konto i potwierdź swój adres e-mail, żeby dostać 1 GB darmowego miejsca. Twój znajomy również dostanie 1 GB darmowego miejsca.', confirm_code_generic_incorrect: "Nieprawidłowy kod.", confirm_code_generic_too_many_requests: "Zbyt wiele zapytań. Zaczekaj kilka minut.", - confirm_code_generic_submit: "Podaj kod", + confirm_code_generic_submit: "Wyślij kod", confirm_code_generic_try_again: "Spróbuj jeszcze raz", confirm_code_generic_title: "Wprowadź kod odzyskiwania", confirm_code_2fa_instruction: "Wprowadź 6-cyfrowy kod ze swojej aplikacji autentykującej.", @@ -71,23 +71,23 @@ const pl = { confirm_your_email_address: "Potwierdź swój adres email", contact_us: "Skontaktuj się z nami", contact_us_verification_required: "Twój adres email musi być potwierdzony aby tego użyć.", - contain: 'Zawieraj', + contain: 'Dopasuj do ekranu', continue: "Kontynuuj", copy: 'Kopiuj', copy_link: "Kopiuj Link", copying: "Kopiowanie", copying_file: "Kopiowanie %%", - cover: 'Zakryj', + cover: 'Wypełnij ekran', create_account: "Stwórz konto", create_free_account: "Stwórz darmowe konto", create_shortcut: "Stwórz skrót", - credits: "Autorzy", + credits: "Licencje", current_password: "Aktualne hasło", cut: 'Wytnij', clock: "Zegar", clock_visible_hide: 'Ukryj - zawsze ukryty', clock_visible_show: 'Pokaż - zawsze widoczny', - clock_visible_auto: 'Automatycznie - domyślne, widoczny tylko w trybie pełnoekranowym.', + clock_visible_auto: 'Automatycznie (domyślne) - widoczny tylko w trybie pełnoekranowym', close_all: 'Zamknij wszystko', created: 'Stworzone', date_modified: 'Data zmodyfikowania', @@ -99,8 +99,8 @@ const pl = { deploy_as_app: 'Wdrożenie jako apkę', descending: 'Malejąco', desktop: 'Pulpit', - desktop_background_fit: "Dopasuj", - developers: "Deweloperzy", + desktop_background_fit: "Dopasowanie", + developers: "Dla deweloperów", dir_published_as_website: `%strong% został opublikowany do:`, disable_2fa: 'Wyłącz uwierzytelnianie dwuskładnikowe', disable_2fa_confirm: "Czy jesteś pewien że chcesz wyłączyć uwierzytelnianie dwuskładnikowe?", @@ -141,7 +141,7 @@ const pl = { get_a_copy_of_on_puter: `Pobierz kopię '%%' na Puter.com!`, get_copy_link: 'Pobierz skopiowany link', hide_all_windows: "Zamknij wszystkie okna", - home: 'Początek', + home: 'Folder domowy', html_document: 'dokument HTML', hue: 'Odcień', image: 'Obraz', @@ -163,7 +163,7 @@ const pl = { manage_sessions: "Zarządzaj sesjami", menubar_style: "Styl paska menu", menubar_style_desktop: "Pulpit", - menubar_style_system: "System", + menubar_style_system: "Jak w systemie", menubar_style_window: "Okno", modified: 'Zmodyfikowany', move: 'Przenieś', @@ -198,7 +198,7 @@ const pl = { password_recovery_token_invalid: "Ten kod odzyskiwania hasła nie jest już ważny.", password_recovery_unknown_error: "Wystąpił nieznany błąd. Proszę spróbować później.", password_required: 'Wymagane jest hasło.', - password_strength_error: "Hasło musi mieć co najmniej 8 znaków i musi zawierać co najmniej jedną: dużą literę, małą literę, cyfrę i znak specjalny.", + password_strength_error: "Hasło musi mieć co najmniej 8 znaków i musi zawierać co najmniej jedną dużą literę, małą literę, cyfrę i znak specjalny.", passwords_do_not_match: 'Pola `Nowe hasło` i `Potwierdź nowe hasło` nie są takie same.', paste: 'Wklej', paste_into_folder: "Wklej do folderu", @@ -221,12 +221,12 @@ const pl = { process_type_init: 'Start', process_type_ui: 'UI', properties: "Właściwości", - public: 'Publiczny', + public: 'Publiczne', publish: "Opublikuj", publish_as_website: 'Opublikuj jako stronę', puter_description: `Puter to zachowująca twoją prywatność osobista chmura, służąca do przechowywania wszystkich twoich plików, aplikacji i gier w jednym, bezpiecznym miejscu, dostępnym z dowolnego miejsca w dowolnej chwili.`, reading_file: "Odczyt %strong%", - recent: "Ostatni", + recent: "Ostatnie", recommended: "Polecane", recover_password: "Odzyskaj hasło", refer_friends_c2a: "Zdobądź 1 GB za każdego znajomego, który założy konto na Puter! On również otrzyma 1 GB.", @@ -235,7 +235,7 @@ const pl = { release_address_confirmation: `Jesteś pewien, że chcesz wypuścić ten adres?`, remove_from_taskbar:'Usuń z paska zadań', rename: 'Zmień nazwę', - repeat: 'Powtórz', + repeat: 'Powtarzaj', replace: 'Zamień', replace_all: 'Zamień wszystkie', resend_confirmation_code: "Wyślij kod potwierdzający ponownie.", @@ -249,7 +249,7 @@ const pl = { save_account_to_publish: 'Zapisz konto, aby opublikować', save_session: 'Zapisz sesję', save_session_c2a: 'Stwórz konto, żeby zapisać aktualną sesję i nie utracić swojej pracy.', - scan_qr_c2a: 'Zeskanuj kod poniżej, żeby zalogować się na tą sesję z innych urządzeń.', + scan_qr_c2a: 'Zeskanuj poniższy kod, aby zalogować się do tej sesji z innego urządzenia.', scan_qr_2fa: 'Zeskanuj kod QR za pomocą apki autentykującej', scan_qr_generic: 'Zeskanuj ten kod QR za pomocą swojego telefonu albo innego urządzenia', search: 'Szukaj', @@ -289,7 +289,7 @@ const pl = { terms: "Warunki", text_document: 'Dokument tekstowy', tos_fineprint: `Klikając 'Stwórz darmowe konto' Zgadzasz się z {{link=terms}}Warunkami Obsługi{{/link}} i {{link=privacy}}Polityką Prywatności{{/link}}.`, - transparency: "Przejrzystość", + transparency: "Przezroczystość", trash: 'Kosz', two_factor: 'Uwierzytelnianie dwuetapowe', two_factor_disabled: 'Uwierzytelnianie dwuetapowe zablokowane', @@ -298,7 +298,7 @@ const pl = { type_confirm_to_delete_account: "Wpisz 'potwierdzam', aby skasować swoje konto.", ui_colors: "Kolory interfejsu użytkownika", ui_manage_sessions: "Menedżer sesji", - ui_revoke: "Wycofaj", + ui_revoke: "Unieważnij", undo: 'Cofnij', unlimited: 'Nieograniczone', unzip: "Rozpakuj", From 5c636d4fd25e14ba3813f7fca3b70ff7bd6860e7 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 17 Jul 2024 13:55:38 -0400 Subject: [PATCH 0542/2119] fix: remove abnoxious debug file --- src/backend/src/fun/dev-console-ui-utils.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/backend/src/fun/dev-console-ui-utils.js b/src/backend/src/fun/dev-console-ui-utils.js index 84ac3eddb8..102370a1ab 100644 --- a/src/backend/src/fun/dev-console-ui-utils.js +++ b/src/backend/src/fun/dev-console-ui-utils.js @@ -56,9 +56,6 @@ const surrounding_box = (col, lines, lengths) => { const c = str => `\x1b[${col}m${str}\x1b[0m`; const bar = c(Array(max_length + 4).fill('━').join('')); for ( let i = 0 ; i < lines.length ; i++ ) { - require('fs').appendFileSync('/tmp/asdfqwer', - '' + lines[i] +':'+ lines[i].length +':'+ lengths[i]+ - ':'+max_length+'\n'); if ( lengths[i] < max_length ) { lines[i] += Array(max_length - lengths[i]) .fill(' ') From d80f2fa847bfaef98dc8d482898f5c15f268e4bd Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 17 Jul 2024 13:36:22 -0700 Subject: [PATCH 0543/2119] fix: fix path issues under win32 platform --- src/backend/src/api/filesystem/FSNodeParam.js | 4 ++- src/backend/src/helpers.js | 13 ++++++--- .../src/routers/filesystem_api/readdir.js | 10 ------- src/backend/src/util/pathutil.js | 27 ++++++++++++++----- 4 files changed, 33 insertions(+), 21 deletions(-) diff --git a/src/backend/src/api/filesystem/FSNodeParam.js b/src/backend/src/api/filesystem/FSNodeParam.js index 5097c8a6f7..a7ee048e52 100644 --- a/src/backend/src/api/filesystem/FSNodeParam.js +++ b/src/backend/src/api/filesystem/FSNodeParam.js @@ -19,6 +19,7 @@ const { is_valid_path } = require("../../filesystem/validation"); const { is_valid_uuid4 } = require("../../helpers"); const { Context } = require("../../util/context"); +const { PathBuilder } = require("../../util/pathutil"); const APIError = require("../APIError"); const _path = require('path'); @@ -73,6 +74,7 @@ module.exports = class FSNodeParam { }); } - return await fs.node({ path: _path.resolve('/', uidOrPath) }); + const resolved_path = PathBuilder.resolve(uidOrPath, { puterfs: true }); + return await fs.node({ path: resolved_path }); } } \ No newline at end of file diff --git a/src/backend/src/helpers.js b/src/backend/src/helpers.js index 8205bb14a8..cdcf4c963c 100644 --- a/src/backend/src/helpers.js +++ b/src/backend/src/helpers.js @@ -31,6 +31,7 @@ const { BaseDatabaseAccessService } = require('./services/database/BaseDatabaseA const { LLRmNode } = require('./filesystem/ll_operations/ll_rmnode'); const { Context } = require('./util/context'); const { NodeUIDSelector } = require('./filesystem/node/selectors'); +const { PathBuilder } = require('./util/pathutil'); let systemfs = null; let services = null; @@ -1155,8 +1156,12 @@ async function jwt_auth(req){ async function mkdir(options){ const fs = systemfs; - const dirpath = _path.dirname(_path.resolve('/', options.path)); - let target_name = _path.basename(_path.resolve('/', options.path)); + debugger; + + const resolved_path = PathBuilder.resolve(options.path, { puterfs: true }); + + const dirpath = _path.dirname(resolved_path); + let target_name = _path.basename(resolved_path); const overwrite = options.overwrite ?? false; const dedupe_name = options.dedupe_name ?? false; const immutable = options.immutable ?? false; @@ -1182,7 +1187,7 @@ async function mkdir(options){ // dirpath not found if(parent === false && !create_missing_parents) - throw "Target path not found"; + throw new Error("Target path not found"); // create missing parent directories else if(parent === false && create_missing_parents){ const dirs = _path.resolve('/', dirpath).split('/'); @@ -1206,7 +1211,7 @@ async function mkdir(options){ // try setting parent again parent = await convert_path_to_fsentry(dirpath); if(parent === false) - throw "Target path not found"; + throw new Error("Target path not found"); } // check permission diff --git a/src/backend/src/routers/filesystem_api/readdir.js b/src/backend/src/routers/filesystem_api/readdir.js index cc1280fd32..180b09ceb6 100644 --- a/src/backend/src/routers/filesystem_api/readdir.js +++ b/src/backend/src/routers/filesystem_api/readdir.js @@ -81,16 +81,6 @@ module.exports = eggspress('/readdir', { const no_thumbs = req.values.no_thumbs; const no_assocs = req.values.no_assocs; - { - const fs = require('fs'); - fs.appendFileSync('/tmp/readdir.log', - JSON.stringify({ - recursive, - no_thumbs, - no_assocs, - }, null, 2) + '\n'); - } - const hl_readdir = new HLReadDir(); const result = await hl_readdir.run({ subject, diff --git a/src/backend/src/util/pathutil.js b/src/backend/src/util/pathutil.js index 489827f8f5..c75d070a38 100644 --- a/src/backend/src/util/pathutil.js +++ b/src/backend/src/util/pathutil.js @@ -28,25 +28,40 @@ class PathBuilder extends AdvancedBase { path: require('path'), } - constructor() { + constructor(parameters = {}) { super(); + if ( parameters.puterfs ) { + this.modules.path = + this.modules.path.posix; + } this.path_ = ''; } - static create () { - return new PathBuilder(); + static create (parameters) { + return new PathBuilder(parameters); } static add (fragment, options) { return PathBuilder.create().add(fragment, options); } - static resolve (fragment) { - const p = PathBuilder.create(); + static resolve (fragment, parameters = {}) { + const { puterfs } = parameters; + + const p = PathBuilder.create(parameters); const require = p.require; const node_path = require('path'); fragment = node_path.resolve(fragment); - return p.add(fragment).build(); + if ( process.platform === 'win32' && !parameters.puterfs ) { + fragment = '/' + fragment.slice('c:\\'.length); // >:-( + } + let result = p.add(fragment).build(); + if ( puterfs && process.platform === 'win32' && + result.startsWith('\\') + ) { + result = '/' + result.slice(1); + } + return result; } add (fragment, options) { From 45f131f8eaf94cf3951ca7ffeb6f311590233b8a Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 17 Jul 2024 14:05:49 -0700 Subject: [PATCH 0544/2119] No scrollbar for session list --- src/gui/src/UI/UIWindowSessionList.js | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/src/gui/src/UI/UIWindowSessionList.js b/src/gui/src/UI/UIWindowSessionList.js index 751f2e1857..023b554656 100644 --- a/src/gui/src/UI/UIWindowSessionList.js +++ b/src/gui/src/UI/UIWindowSessionList.js @@ -28,15 +28,17 @@ async function UIWindowSessionList(options){ return new Promise(async (resolve) => { let h = ''; h += `
`; - h += `
${i18n('signing_in')}
` - h += `
`; - h += `

${i18n('sign_in_with_puter')}

` - for (let index = 0; index < window.logged_in_users.length; index++) { - const l_user = window.logged_in_users[index]; - h += `
${l_user.username}
`; - } + // loading indicator + h += `
${i18n('signing_in')}
`; + // session list + h += `
`; + h += `

${i18n('sign_in_with_puter')}

` + for (let index = 0; index < window.logged_in_users.length; index++) { + const l_user = window.logged_in_users[index]; + h += `
${l_user.username}
`; + } h += `
`; - + // c2a h += `
`; h += `
`; From 29f919c98a7e4eca724ffae0fa2882f47da30842 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 17 Jul 2024 17:15:23 -0400 Subject: [PATCH 0545/2119] sync: package-lock.json --- package-lock.json | 316 ++-------------------------------------------- 1 file changed, 10 insertions(+), 306 deletions(-) diff --git a/package-lock.json b/package-lock.json index fedf9fff0d..0f974767da 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "puter.com", - "version": "1.0.0", + "version": "2.4.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "puter.com", - "version": "1.0.0", + "version": "2.4.1", "license": "AGPL-3.0-only", "workspaces": [ "src/*", @@ -1024,102 +1024,6 @@ "url": "https://github.com/sponsors/nzakas" } }, - "node_modules/@isaacs/cliui": { - "version": "8.0.2", - "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", - "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", - "license": "ISC", - "dependencies": { - "string-width": "^5.1.2", - "string-width-cjs": "npm:string-width@^4.2.0", - "strip-ansi": "^7.0.1", - "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", - "wrap-ansi": "^8.1.0", - "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" - }, - "engines": { - "node": ">=12" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-regex": { - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", - "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-regex?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/ansi-styles": { - "version": "6.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", - "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", - "license": "MIT", - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/ansi-styles?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/emoji-regex": { - "version": "9.2.2", - "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", - "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==", - "license": "MIT" - }, - "node_modules/@isaacs/cliui/node_modules/string-width": { - "version": "5.1.2", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", - "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", - "license": "MIT", - "dependencies": { - "eastasianwidth": "^0.2.0", - "emoji-regex": "^9.2.2", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" - } - }, - "node_modules/@isaacs/cliui/node_modules/strip-ansi": { - "version": "7.1.0", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", - "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^6.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/strip-ansi?sponsor=1" - } - }, - "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { - "version": "8.1.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", - "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^6.1.0", - "string-width": "^5.0.1", - "strip-ansi": "^7.0.1" - }, - "engines": { - "node": ">=12" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/@istanbuljs/load-nyc-config": { "version": "1.1.0", "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", @@ -6435,6 +6339,7 @@ "version": "7.0.3", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", @@ -6820,12 +6725,6 @@ "url": "https://dotenvx.com" } }, - "node_modules/eastasianwidth": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", - "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", - "license": "MIT" - }, "node_modules/ecdsa-sig-formatter": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", @@ -8133,10 +8032,6 @@ "url": "https://github.com/sponsors/isaacs" } }, - "node_modules/google-license": { - "resolved": "tools/google-license", - "link": true - }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -8818,7 +8713,8 @@ "node_modules/isexe": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", - "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==" + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true }, "node_modules/isobject": { "version": "3.0.1", @@ -9024,24 +8920,6 @@ "node": ">=8" } }, - "node_modules/jackspeak": { - "version": "4.0.1", - "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-4.0.1.tgz", - "integrity": "sha512-cub8rahkh0Q/bw1+GxP7aeSe29hHHn2V4m29nnDlvCdlgU+3UGxkZp7Z53jLUdpX3jdTO0nJZUDl3xvbWc2Xog==", - "license": "BlueOak-1.0.0", - "dependencies": { - "@isaacs/cliui": "^8.0.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - }, - "optionalDependencies": { - "@pkgjs/parseargs": "^0.11.0" - } - }, "node_modules/jest-worker": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", @@ -10926,12 +10804,6 @@ "node": ">=8" } }, - "node_modules/package-json-from-dist": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/package-json-from-dist/-/package-json-from-dist-1.0.0.tgz", - "integrity": "sha512-dATvCeZN/8wQsGywez1mzHtTlP22H8OEfPrVMLNr4/eGa+ijtLn/6M5f0dY8UKNrC2O9UCU6SSoG3qRKnt7STw==", - "license": "BlueOak-1.0.0" - }, "node_modules/pako": { "version": "1.0.11", "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", @@ -11027,6 +10899,7 @@ "version": "3.1.1", "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, "engines": { "node": ">=8" } @@ -11036,40 +10909,6 @@ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, - "node_modules/path-scurry": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-2.0.0.tgz", - "integrity": "sha512-ypGJsmGtdXUOeM5u93TyeIEfEhM6s+ljAhrk5vAvSx8uyY/02OvrZnA0YNGUrPXfpJMgI1ODd3nwz8Npx4O4cg==", - "license": "BlueOak-1.0.0", - "dependencies": { - "lru-cache": "^11.0.0", - "minipass": "^7.1.2" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "node_modules/path-scurry/node_modules/lru-cache": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-11.0.0.tgz", - "integrity": "sha512-Qv32eSV1RSCfhY3fpPE2GNZ8jgM9X7rdAfemLWqTUxwiyIC4jJ6Sy0fZ8H+oLWevO6i4/bizg7c8d8i6bxrzbA==", - "license": "ISC", - "engines": { - "node": "20 || >=22" - } - }, - "node_modules/path-scurry/node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, "node_modules/path-to-regexp": { "version": "0.1.7", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", @@ -12170,6 +12009,7 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, "dependencies": { "shebang-regex": "^3.0.0" }, @@ -12181,6 +12021,7 @@ "version": "3.0.0", "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, "engines": { "node": ">=8" } @@ -12644,21 +12485,6 @@ "node": ">=8" } }, - "node_modules/string-width-cjs": { - "name": "string-width", - "version": "4.2.3", - "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", - "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", - "license": "MIT", - "dependencies": { - "emoji-regex": "^8.0.0", - "is-fullwidth-code-point": "^3.0.0", - "strip-ansi": "^6.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-ansi": { "version": "6.0.1", "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", @@ -12670,19 +12496,6 @@ "node": ">=8" } }, - "node_modules/strip-ansi-cjs": { - "name": "strip-ansi", - "version": "6.0.1", - "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", - "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", - "license": "MIT", - "dependencies": { - "ansi-regex": "^5.0.1" - }, - "engines": { - "node": ">=8" - } - }, "node_modules/strip-bom": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", @@ -13620,6 +13433,7 @@ "version": "2.0.2", "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, "dependencies": { "isexe": "^2.0.0" }, @@ -13761,24 +13575,6 @@ "url": "https://github.com/chalk/wrap-ansi?sponsor=1" } }, - "node_modules/wrap-ansi-cjs": { - "name": "wrap-ansi", - "version": "7.0.0", - "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", - "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", - "license": "MIT", - "dependencies": { - "ansi-styles": "^4.0.0", - "string-width": "^4.1.0", - "strip-ansi": "^6.0.0" - }, - "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/chalk/wrap-ansi?sponsor=1" - } - }, "node_modules/wrappy": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", @@ -14559,6 +14355,7 @@ }, "tools/google-license": { "version": "1.0.0", + "extraneous": true, "license": "ISC", "dependencies": { "commander": "^12.1.0", @@ -14566,99 +14363,6 @@ "handlebars": "^4.7.8" } }, - "tools/google-license/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "license": "MIT", - "dependencies": { - "balanced-match": "^1.0.0" - } - }, - "tools/google-license/node_modules/commander": { - "version": "12.1.0", - "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", - "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", - "license": "MIT", - "engines": { - "node": ">=18" - } - }, - "tools/google-license/node_modules/foreground-child": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.2.1.tgz", - "integrity": "sha512-PXUUyLqrR2XCWICfv6ukppP96sdFwWbNEnfEMt7jNsISjMsvaLNinAHNDYyvkyU+SZG2BTSbT5NjG+vZslfGTA==", - "license": "ISC", - "dependencies": { - "cross-spawn": "^7.0.0", - "signal-exit": "^4.0.1" - }, - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "tools/google-license/node_modules/glob": { - "version": "11.0.0", - "resolved": "https://registry.npmjs.org/glob/-/glob-11.0.0.tgz", - "integrity": "sha512-9UiX/Bl6J2yaBbxKoEBRm4Cipxgok8kQYcOPEhScPwebu2I0HoQOuYdIO6S3hLuWoZgpDpwQZMzTFxgpkyT76g==", - "license": "ISC", - "dependencies": { - "foreground-child": "^3.1.0", - "jackspeak": "^4.0.1", - "minimatch": "^10.0.0", - "minipass": "^7.1.2", - "package-json-from-dist": "^1.0.0", - "path-scurry": "^2.0.0" - }, - "bin": { - "glob": "dist/esm/bin.mjs" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "tools/google-license/node_modules/minimatch": { - "version": "10.0.1", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-10.0.1.tgz", - "integrity": "sha512-ethXTt3SGGR+95gudmqJ1eNhRO7eGEGIgYA9vnPatK4/etz2MEVDno5GMCibdMTuBMyElzIlgxMna3K94XDIDQ==", - "license": "ISC", - "dependencies": { - "brace-expansion": "^2.0.1" - }, - "engines": { - "node": "20 || >=22" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, - "tools/google-license/node_modules/minipass": { - "version": "7.1.2", - "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.1.2.tgz", - "integrity": "sha512-qOOzS1cBTWYF4BH8fVePDBOO9iptMnGUEZwNc/cMWnTV2nVLZ7VoNWEPHkYczZA0pdoA7dl6e7FL659nX9S2aw==", - "license": "ISC", - "engines": { - "node": ">=16 || 14 >=14.17" - } - }, - "tools/google-license/node_modules/signal-exit": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", - "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", - "license": "ISC", - "engines": { - "node": ">=14" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" - } - }, "tools/license-headers": { "version": "1.0.0", "license": "AGPL-3.0-only", From 4d6edff169f3d3f2772ccfd64fa13dd9711d326b Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 17 Jul 2024 18:32:02 -0700 Subject: [PATCH 0546/2119] Escape arguments passed to dev-center --- src/dev-center/js/dev-center.js | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/src/dev-center/js/dev-center.js b/src/dev-center/js/dev-center.js index 5a677f3f1a..7eb3263913 100644 --- a/src/dev-center/js/dev-center.js +++ b/src/dev-center/js/dev-center.js @@ -62,21 +62,20 @@ if(domain === 'puter.localhost'){ static_hosting_domain = 'site.puter.localhost'; } -// port +// add port to static_hosting_domain if provided if (URLParams.has('puter.port') && URLParams.get('puter.port')) { - static_hosting_domain = static_hosting_domain + `:` + URLParams.get('puter.port'); + static_hosting_domain = static_hosting_domain + `:` + html_encode(URLParams.get('puter.port')); } // protocol let protocol = 'https'; -if (URLParams.has('puter.protocol')) { - protocol = URLParams.get('puter.protocol'); -} +if (URLParams.has('puter.protocol') && URLParams.get('puter.protocol') === 'http') + protocol = 'http'; // port let port = ''; if (URLParams.has('puter.port') && URLParams.get('puter.port')) { - port = URLParams.get('puter.port'); + port = html_encode(URLParams.get('puter.port')); } $(document).ready(function () { From e6833253c7399155348e68fc09ab25cf5e40d36d Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 17 Jul 2024 20:14:07 -0700 Subject: [PATCH 0547/2119] close #276 --- src/gui/src/manifest.json | 49 ++++++++++++++++++++++++++++++++++++++- 1 file changed, 48 insertions(+), 1 deletion(-) diff --git a/src/gui/src/manifest.json b/src/gui/src/manifest.json index e9e65657e4..e460628e74 100644 --- a/src/gui/src/manifest.json +++ b/src/gui/src/manifest.json @@ -3,6 +3,51 @@ "short_name": "Puter", "display": "standalone", "start_url": "/", + "id": "puter", + "description": "Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time.", + "dir": "auto", + "lang": "en", + "orientation": "any", + "scope": "/", + "categories": [ + "productivity", + "entertainment", + "games", + "navigation", + "utilities" + ], + "shortcuts": [ + { + "name": "Notepad", + "short_name": "Notepad", + "description": "Cloud Notepad", + "url": "/app/editor" + }, + { + "name": "Dev Center", + "short_name": "Dev Center", + "description": "Publish your apps and games on the Puter", + "url": "/app/dev-center" + }, + { + "name": "Camera", + "short_name": "Camera", + "description": "Take a picture or record a video", + "url": "/app/camera" + }, + { + "name":"Recorder", + "short_name":"Recorder", + "description":"Record audio notes and voice memos", + "url":"/app/recorder" + }, + { + "name": "Terminal", + "short_name": "Terminal", + "description": "Terminal", + "url": "/app/terminal" + } + ], "icons": [ { "src": "/favicons/android-icon-36x36.png", @@ -40,5 +85,7 @@ "type": "image/png", "density": "4.0" } - ] + ], + "theme_color": "#000000", + "background_color": "#000000" } \ No newline at end of file From 8e7306c23be01ee6c31cdb4c99f2fb1f71a2247f Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 17 Jul 2024 20:56:36 -0700 Subject: [PATCH 0548/2119] Add support for dropping multiple Puter items onto Dev Center (close #311) --- src/dev-center/js/dev-center.js | 94 +++++++++++++++++++++++++++++++-- 1 file changed, 90 insertions(+), 4 deletions(-) diff --git a/src/dev-center/js/dev-center.js b/src/dev-center/js/dev-center.js index 7eb3263913..fe04404806 100644 --- a/src/dev-center/js/dev-center.js +++ b/src/dev-center/js/dev-center.js @@ -566,7 +566,7 @@ async function edit_app_section(cur_app_name) { let items = e.detail.items; // ---------------------------------------------------- - // one file dropped + // one Puter files dropped // ---------------------------------------------------- if (items.length === 1 && !items[0].isDirectory) { if (items[0].name.toLowerCase() === 'index.html') { @@ -592,7 +592,41 @@ async function edit_app_section(cur_app_name) { return; } // ---------------------------------------------------- - // one directory dropped + // Multiple Puter files dropped + // ---------------------------------------------------- + else if (items.length > 1) { + let hasIndexHtml = false; + for (let item of items) { + if (item.name.toLowerCase() === 'index.html') { + hasIndexHtml = true; + break; + } + } + + if (hasIndexHtml) { + dropped_items = items; + $('.drop-area').removeClass('drop-area-hover'); + $('.drop-area').addClass('drop-area-ready-to-deploy'); + drop_area_content = `

${items.length} items

Ready to deploy 🚀

`; + $('.drop-area').html(drop_area_content); + + // enable deploy button + $('.deploy-btn').removeClass('disabled'); + } else { + puter.ui.alert(`You need to have an index.html file in your deployment.`, [ + { + label: 'Ok', + }, + ]); + $('.drop-area').removeClass('drop-area-ready-to-deploy'); + $('.drop-area').removeClass('drop-area-hover'); + $('.deploy-btn').addClass('disabled'); + dropped_items = []; + } + return; + } + // ---------------------------------------------------- + // One Puter directory dropped // ---------------------------------------------------- else if (items.length === 1 && items[0].isDirectory) { let children = await puter.fs.readdir(items[0].path); @@ -1306,13 +1340,15 @@ window.deploy = async function (app, items) { } // -------------------------------------------------------------------- - // (A) Puter Items: If 'items' is a string and starts with /, it's a path to a Puter item + // (A) One Puter Item: If 'items' is a string and starts with /, it's a path to a Puter item // -------------------------------------------------------------------- if (typeof items === 'string' && (items.startsWith('/') || items.startsWith('~'))) { // perform stat on 'items' const stat = await puter.fs.stat(items); + // -------------------------------------------------------------------- // Puter Directory + // -------------------------------------------------------------------- // Perform readdir on 'items' // todo there is apparently a bug in Puter where sometimes path is literally missing from the items // returned by readdir. This is the 'path' that readdit didn't return a path for: "~/Desktop/particle-clicker-master" @@ -1332,7 +1368,9 @@ window.deploy = async function (app, items) { } } } + // -------------------------------------------------------------------- // Puter File + // -------------------------------------------------------------------- else { // copy the 'files' to the app directory await puter.fs.copy( @@ -1369,9 +1407,57 @@ window.deploy = async function (app, items) { reset_drop_area(); }) } + // -------------------------------------------------------------------- + // (B) Multiple Puter Items: If `items` is an Array `items[0]` has `uid` + // then it's a Puter Item Array. + // -------------------------------------------------------------------- + else if (Array.isArray(items) && items[0].uid) { + // If there's no index.html in the root, return + if (!hasRootIndexHtml) + return; + + // copy the 'files' to the app directory + for (let item of items) { + // perform copy + await puter.fs.copy( + item.fullPath ? item.fullPath : item.path ? item.path : item.filepath, + appdata_dir.path, + { overwrite: true } + ); + // update progress + $('.deploy-percent').text(`(${Math.round((items.indexOf(item) / items.length) * 100)}%)`); + } + + // generate new hostname with a random suffix + let hostname = `${currently_editing_app.name}-${(Math.random() + 1).toString(36).substring(7)}`; + + // -------------------------------------------------------------------- + // Create a router for the app with the fresh hostname + // we change hostname every time to prevent caching issues + // -------------------------------------------------------------------- + puter.hosting.create(hostname, appdata_dir.path).then(async (res) => { + // TODO this endpoint needs to be able to update only the specified fields + puter.apps.update(currently_editing_app.name, { + indexURL: protocol + `://${hostname}.` + static_hosting_domain, + title: currently_editing_app.title, + name: currently_editing_app.name, + icon: currently_editing_app.icon, + description: currently_editing_app.description, + maximizeOnStart: currently_editing_app.maximize_on_start, + background: currently_editing_app.background, + filetypeAssociations: currently_editing_app.filetype_associations, + }) + // set the 'Index URL' field for the 'Settings' tab + $('#edit-app-index-url').val(protocol + `://${hostname}.` + static_hosting_domain); + // show success message + $('.deploy-success-msg').show(); + // reset drop area + reset_drop_area(); + }) + } // -------------------------------------------------------------------- - // (B) Local Items: Upload new deploy + // (C) Local Items: Upload new deploy // -------------------------------------------------------------------- else { puter.fs.upload( From ba50d0f96d58075abec067d24e6532bd874093f0 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 18 Jul 2024 00:30:54 -0400 Subject: [PATCH 0549/2119] feat: add some default groups --- .../database/SqliteDatabaseAccessService.js | 7 +++- .../sqlite_setup/0024_default-groups.sql | 34 +++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-) create mode 100644 src/backend/src/services/database/sqlite_setup/0024_default-groups.sql diff --git a/src/backend/src/services/database/SqliteDatabaseAccessService.js b/src/backend/src/services/database/SqliteDatabaseAccessService.js index 4d987c4067..c99ba115e7 100644 --- a/src/backend/src/services/database/SqliteDatabaseAccessService.js +++ b/src/backend/src/services/database/SqliteDatabaseAccessService.js @@ -42,7 +42,7 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { this.db = new Database(this.config.path); // Database upgrade logic - const TARGET_VERSION = 21; + const TARGET_VERSION = 22; if ( do_setup ) { this.log.noticeme(`SETUP: creating database at ${this.config.path}`); @@ -70,6 +70,7 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { '0021_app-owner-id.sql', '0022_dev-center-max.sql', '0023_fix-kv.sql', + '0024_default-groups.sql', ].map(p => path_.join(__dirname, 'sqlite_setup', p)); const fs = require('fs'); for ( const filename of sql_files ) { @@ -170,6 +171,10 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { upgrade_files.push('0023_fix-kv.sql'); } + if ( user_version <= 21 ) { + upgrade_files.push('0024_default-groups.sql'); + } + if ( upgrade_files.length > 0 ) { this.log.noticeme(`Database out of date: ${this.config.path}`); this.log.noticeme(`UPGRADING DATABASE: ${user_version} -> ${TARGET_VERSION}`); diff --git a/src/backend/src/services/database/sqlite_setup/0024_default-groups.sql b/src/backend/src/services/database/sqlite_setup/0024_default-groups.sql new file mode 100644 index 0000000000..90668d007a --- /dev/null +++ b/src/backend/src/services/database/sqlite_setup/0024_default-groups.sql @@ -0,0 +1,34 @@ +INSERT INTO `group` ( + `uid`, + `owner_user_id`, + `extra`, + `metadata` +) VALUES + ('26bfb1fb-421f-45bc-9aa4-d81ea569e7a5', 1, + '{"critical": true, "type": "default", "name": "system"}', + '{"title": "System", "color": "#000000"}'), + ('ca342a5e-b13d-4dee-9048-58b11a57cc55', 1, + '{"critical": true, "type": "default", "name": "admin"}', + '{"title": "Admin", "color": "#a83232"}'), + ('78b1b1dd-c959-44d2-b02c-8735671f9997', 1, + '{"critical": true, "type": "default", "name": "user"}', + '{"title": "User", "color": "#3254a8"}'), + ('3c2dfff7-d22a-41aa-a193-59a61dac4b64', 1, + '{"type": "default", "name": "moderator"}', + '{"title": "Moderator", "color": "#a432a8"}'), + ('5e8f251d-3382-4b0d-932c-7bb82f48652f', 1, + '{"type": "default", "name": "developer"}', + '{"title": "Developer", "color": "#32a852"}') + ; + +INSERT INTO `jct_user_group` ( + `user_id`, + `group_id`, + `extra`, + `metadata` +) VALUES ( + 1, + (SELECT `id` FROM `group` WHERE uid='ca342a5e-b13d-4dee-9048-58b11a57cc55'), + '{}', + '{"default": true}' +); From f9333b3d1e05bd0dffaecd2e29afd08ea61559fc Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 18 Jul 2024 09:59:42 -0700 Subject: [PATCH 0550/2119] feat: add option to disable temporary users --- src/backend/src/config.js | 4 +++- src/backend/src/routers/signup.js | 4 +++- src/backend/src/services/PuterHomepageService.js | 1 + src/gui/src/index.js | 3 +++ src/gui/src/initgui.js | 4 ++-- 5 files changed, 12 insertions(+), 4 deletions(-) diff --git a/src/backend/src/config.js b/src/backend/src/config.js index 233c4bb2c0..2ff733f337 100644 --- a/src/backend/src/config.js +++ b/src/backend/src/config.js @@ -25,6 +25,9 @@ let config = {}; // Static defaults config.servers = []; +// Will disable the auto-generated temp users. If a user lands on the site, they will be required to sign up or log in. +config.disable_temp_users = false; + config.max_file_size = 100_000_000_000, config.max_thumb_size = 1_000, config.max_fsentry_name_length = 767, @@ -131,7 +134,6 @@ const config_pointer = {}; config_to_export = config_pointer; } - // We have some methods that can be called on `config` { // Add configuration values with precedence over the current config diff --git a/src/backend/src/routers/signup.js b/src/backend/src/routers/signup.js index 1809a17b64..e94b7b95ae 100644 --- a/src/backend/src/routers/signup.js +++ b/src/backend/src/routers/signup.js @@ -100,10 +100,12 @@ module.exports = eggspress(['/signup'], { } // temporary user - if(req.body.is_temp){ + if(req.body.is_temp && !config.disable_temp_users){ req.body.username = await generate_random_username(); req.body.email = req.body.username + '@gmail.com'; req.body.password = 'sadasdfasdfsadfsa'; + }else if(config.disable_temp_users){ + return res.status(400).send('Temp users are disabled.'); } // send_confirmation_code diff --git a/src/backend/src/services/PuterHomepageService.js b/src/backend/src/services/PuterHomepageService.js index 1e1ffbe779..57208f80fe 100644 --- a/src/backend/src/services/PuterHomepageService.js +++ b/src/backend/src/services/PuterHomepageService.js @@ -108,6 +108,7 @@ class PuterHomepageService extends BaseService { require_email_verification_to_publish_website: config.require_email_verification_to_publish_website, short_description: config.short_description, long_description: config.long_description, + disable_temp_users: config.disable_temp_users, }, })); } diff --git a/src/gui/src/index.js b/src/gui/src/index.js index 450cff7982..08fe713fb4 100644 --- a/src/gui/src/index.js +++ b/src/gui/src/index.js @@ -31,6 +31,7 @@ window.puter_gui_enabled = true; * @param {string} [options.api_origin='https://api.puter.com'] - The origin URL for the API. * @param {number} [options.max_item_name_length=500] - Maximum allowed length for an item name. * @param {boolean} [options.require_email_verification_to_publish_website=true] - Flag to decide whether email verification is required to publish a website. + * @param {boolean} [options.disable_temp_users=false] - Flag to disable auto-generated temporary users. * * @property {string} [options.app_domain] - Extracted domain name from gui_origin. It's derived automatically if not provided. * @property {string} [window.gui_env] - The environment in which the GUI is running (e.g., "dev" or "prod"). @@ -54,6 +55,7 @@ window.gui = async function(options){ window.api_origin = options.api_origin ?? "https://api.puter.com"; window.max_item_name_length = options.max_item_name_length ?? 500; window.require_email_verification_to_publish_website = options.require_email_verification_to_publish_website ?? true; + window.disable_temp_users = options.disable_temp_users ?? false; // DEV: Load the initgui.js file if we are in development mode if(!window.gui_env || window.gui_env === "dev"){ @@ -73,6 +75,7 @@ window.gui = async function(options){ // 🚀 Launch the GUI 🚀 window.initgui(options); + } /** diff --git a/src/gui/src/initgui.js b/src/gui/src/initgui.js index a4ed477b86..cd7bf0b33d 100644 --- a/src/gui/src/initgui.js +++ b/src/gui/src/initgui.js @@ -831,7 +831,7 @@ window.initgui = async function(options){ // ------------------------------------------------------------------------------------- // Un-authed but not first visit -> try to log in/sign up // ------------------------------------------------------------------------------------- - if(!window.is_auth() && !window.first_visit_ever){ + if(!window.is_auth() && (!window.first_visit_ever || window.disable_temp_users)){ if(window.logged_in_users.length > 0){ UIWindowSessionList(); } @@ -849,7 +849,7 @@ window.initgui = async function(options){ // ------------------------------------------------------------------------------------- // Un-authed and first visit ever -> create temp user // ------------------------------------------------------------------------------------- - else if(!window.is_auth() && window.first_visit_ever){ + else if(!window.is_auth() && window.first_visit_ever && !window.disable_temp_users){ let referrer; try{ referrer = new URL(window.location.href).pathname; From 8c8904cb36f3282bf1b53b506fa71b701ec00671 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 18 Jul 2024 14:22:12 -0400 Subject: [PATCH 0551/2119] doc: update documentation for boot sequence --- src/backend/doc/contributors/boot-sequence.md | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/backend/doc/contributors/boot-sequence.md b/src/backend/doc/contributors/boot-sequence.md index bdc111e1e4..b98e8facd8 100644 --- a/src/backend/doc/contributors/boot-sequence.md +++ b/src/backend/doc/contributors/boot-sequence.md @@ -2,7 +2,13 @@ This document describes the boot sequence of Puter's backend. -**Constriction** +**Runtime Environment** + - Configuration directory is determined + - Runtime directory is determined + - Mod directory is determined + - Services are instantiated + +**Construction** - Data structures are created **Initialization** From e53993207077aecd2c01712519251993bb2562bc Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 18 Jul 2024 14:22:30 -0400 Subject: [PATCH 0552/2119] feat: add cross_origin_isolation option --- src/backend/src/services/WebServerService.js | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/src/backend/src/services/WebServerService.js b/src/backend/src/services/WebServerService.js index 187f4956d5..633fd2972f 100644 --- a/src/backend/src/services/WebServerService.js +++ b/src/backend/src/services/WebServerService.js @@ -360,6 +360,8 @@ class WebServerService extends BaseService { app.use(function (req, res, next) { const origin = req.headers.origin; + + const is_site = req.hostname.endsWith(config.static_hosting_domain); if ( req.path === '/signup' || req.path === '/login' ) { res.setHeader('Access-Control-Allow-Origin', origin ?? '*'); @@ -386,9 +388,14 @@ class WebServerService extends BaseService { // to the API (e.g. in case you use sessions) // res.setHeader('Access-Control-Allow-Credentials', true); - //needed for SharedArrayBuffer - // res.setHeader('Cross-Origin-Opener-Policy', 'same-origin'); - // res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp') + // Needed for SharedArrayBuffer + // NOTE: This is put behind a configuration flag because we + // need some experimentation to ensure the interface + // between apps and Puter doesn't break. + if ( config.cross_origin_isolation ) { + res.setHeader('Cross-Origin-Opener-Policy', 'same-origin'); + res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp'); + } res.setHeader('Cross-Origin-Resource-Policy', 'cross-origin'); // Pass to next layer of middleware From ad3d318d07377c78c0429247225655e489b68be4 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 18 Jul 2024 14:50:53 -0400 Subject: [PATCH 0553/2119] fix: make webpack output not look like errors --- src/backend/src/services/DevWatcherService.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/src/services/DevWatcherService.js b/src/backend/src/services/DevWatcherService.js index f980273786..4620a6d19e 100644 --- a/src/backend/src/services/DevWatcherService.js +++ b/src/backend/src/services/DevWatcherService.js @@ -89,8 +89,8 @@ class DevWatcherService extends BaseService { log_ (name, isErr, line) { let txt = `[${name}:`; txt += isErr - ? `\x1B[31;1merr\x1B[0m` - : `\x1B[32;1mout\x1B[0m`; + ? `\x1B[34;1m2\x1B[0m` + : `\x1B[32;1m1\x1B[0m`; txt += '] ' + line; this.log.info(txt); } From 82fa2d08622c20dc9ca8a7f475d847f83884900e Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 18 Jul 2024 13:01:14 -0700 Subject: [PATCH 0554/2119] close #169 --- src/dev-center/css/style.css | 2 +- src/dev-center/js/dev-center.js | 82 ++++++++++++++++++++++++++++--- src/gui/src/helpers/launch_app.js | 53 +++++++++++++++++--- 3 files changed, 124 insertions(+), 13 deletions(-) diff --git a/src/dev-center/css/style.css b/src/dev-center/css/style.css index e4c7a4ba5b..02a9f37672 100644 --- a/src/dev-center/css/style.css +++ b/src/dev-center/css/style.css @@ -278,7 +278,7 @@ label, input[type="text"] { text-decoration: underline; } -input[type="text"], textarea { +input[type="text"], textarea, input[type="number"] { display: block; width: 100%; height: 34px; diff --git a/src/dev-center/js/dev-center.js b/src/dev-center/js/dev-center.js index fe04404806..a70485fa2c 100644 --- a/src/dev-center/js/dev-center.js +++ b/src/dev-center/js/dev-center.js @@ -435,6 +435,8 @@ function generate_edit_app_section(app) { if(app.result) app = app.result; + let maximize_on_start = app.maximize_on_start ? 'checked' : ''; + let h = ``; h += `
@@ -485,11 +487,6 @@ function generate_edit_app_section(app) { -
- - -
-
@@ -500,6 +497,35 @@ function generate_edit_app_section(app) {
+
+ + +
+ +
+ + + + +
+ +
+ + + + +
+ +
+ + +
+ +
+ + +
+
Change App Icon
@@ -804,6 +830,11 @@ $(document).on('click', '.edit-app-save-btn', async function (e) { const index_url = $('#edit-app-index-url').val(); const description = $('#edit-app-description').val(); const uid = $('#edit-app-uid').val(); + const height = $('#edit-app-window-height').val(); + const width = $('#edit-app-window-width').val(); + const top = $('#edit-app-window-top').val(); + const left = $('#edit-app-window-left').val(); + let filetype_associations = $('#edit-app-filetype-associations').val(); let icon; @@ -827,6 +858,24 @@ $(document).on('click', '.edit-app-save-btn', async function (e) { error = `Index URL must be a valid url.`; else if (!index_url.toLowerCase().startsWith('https://') && !index_url.toLowerCase().startsWith('http://')) error = `Index URL must start with 'https://' or 'http://'.`; + // height must be a number + else if (isNaN(height)) + error = `Window Height must be a number.`; + // height must be greater than 0 + else if (height <= 0) + error = `Window Height must be greater than 0.`; + // width must be a number + else if (isNaN(width)) + error = `Window Width must be a number.`; + // width must be greater than 0 + else if (width <= 0) + error = `Window Width must be greater than 0.`; + // top must be a number + else if (top && isNaN(top)) + error = `Window Top must be a number.`; + // left must be a number + else if (left && isNaN(left)) + error = `Window Left must be a number.`; // download icon from URL else { @@ -871,6 +920,16 @@ $(document).on('click', '.edit-app-save-btn', async function (e) { background: $('#edit-app-background').is(":checked"), metadata: { fullpage_on_landing: $('#edit-app-fullpage-on-landing').is(":checked"), + window_size: { + width: width ?? 800, + height: height ?? 600, + }, + window_position: { + top: top, + left: left, + }, + window_resizable: $('#edit-app-window-resizable').is(":checked"), + hide_titlebar: $('#edit-app-hide-titlebar').is(":checked"), }, filetypeAssociations: filetype_associations, }).then(async (app) => { @@ -2013,4 +2072,15 @@ function getMimeType(extension) { // Return the MIME type if found, otherwise return 'application/octet-stream' return mimeTypes[cleanExtension] || 'application/octet-stream'; -} \ No newline at end of file +} + +// if edit-app-maximize-on-start is checked, disable window size and position fields +$(document).on('change', '#edit-app-maximize-on-start', function (e) { + if ($(this).is(':checked')) { + $('#edit-app-window-width, #edit-app-window-height').prop('disabled', true); + $('#edit-app-window-top, #edit-app-window-left').prop('disabled', true); + } else { + $('#edit-app-window-width, #edit-app-window-height').prop('disabled', false); + $('#edit-app-window-top, #edit-app-window-left').prop('disabled', false); + } +}) \ No newline at end of file diff --git a/src/gui/src/helpers/launch_app.js b/src/gui/src/helpers/launch_app.js index 40a33d96a0..bdce5b3063 100644 --- a/src/gui/src/helpers/launch_app.js +++ b/src/gui/src/helpers/launch_app.js @@ -36,7 +36,7 @@ const launch_app = async (options)=>{ } // If the app object is not provided, get it from the server - let app_info = options.app_obj ?? await window.get_apps(options.name); + let app_info = options.app_obj ?? await puter.apps.get(options.name); // For backward compatibility reasons we need to make sure that both `uuid` and `uid` are set app_info.uuid = app_info.uuid ?? app_info.uid; @@ -68,7 +68,7 @@ const launch_app = async (options)=>{ //----------------------------------- // maximize on start //----------------------------------- - if(app_info.maximize_on_start && app_info.maximize_on_start === 1) + if(app_info.maximize_on_start) options.maximized = 1; //----------------------------------- @@ -254,6 +254,44 @@ const launch_app = async (options)=>{ // register app_instance_uid window.app_instance_ids.add(uuid); + // width + let window_width; + if(app_info.metadata?.window_size?.width !== undefined) + window_width = parseFloat(app_info.metadata.window_size.width); + if(options.maximized) + window_width = '100%'; + + // height + let window_height; + if(app_info.metadata?.window_size?.height !== undefined){ + window_height = parseFloat(app_info.metadata.window_size.height); + }if(options.maximized) + window_height = `calc(100% - ${window.taskbar_height + window.toolbar_height + 1}px)`; + + // top + let top; + if(app_info.metadata?.window_position?.top !== undefined) + top = parseFloat(app_info.metadata.window_position.top) + window.toolbar_height + 1; + if(options.maximized) + top = 0; + + // left + let left; + if(app_info.metadata?.window_position?.left !== undefined) + left = parseFloat(app_info.metadata.window_position.left); + if(options.maximized) + left = 0; + + // window_resizable + let window_resizable = true; + if(app_info.metadata?.window_resizable !== undefined && typeof app_info.metadata.window_resizable === 'boolean') + window_resizable = app_info.metadata.window_resizable; + + // hide_titlebar + let hide_titlebar = false; + if(app_info.metadata?.hide_titlebar !== undefined && typeof app_info.metadata.hide_titlebar === 'boolean') + hide_titlebar = app_info.metadata.hide_titlebar; + // open window el_win = UIWindow({ element_uuid: uuid, @@ -264,18 +302,21 @@ const launch_app = async (options)=>{ window_class: 'window-app', update_window_url: true, app_uuid: app_info.uuid ?? app_info.uid, - top: options.maximized ? 0 : undefined, - left: options.maximized ? 0 : undefined, - height: options.maximized ? `calc(100% - ${window.taskbar_height + window.toolbar_height + 1}px)` : undefined, - width: options.maximized ? `100%` : undefined, + top: top, + left: left, + height: window_height, + width: window_width, app: options.name, is_visible: ! app_info.background, is_maximized: options.maximized, is_fullpage: options.is_fullpage, ...window_options, + is_resizable: window_resizable, + has_head: ! hide_titlebar, show_in_taskbar: app_info.background ? false : window_options?.show_in_taskbar, }); + // If the app is not in the background, show the window if ( ! app_info.background ) { $(el_win).show(); } From 58c199c15356ac087a04b16dd18e8fe0f1aea359 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 18 Jul 2024 16:10:38 -0400 Subject: [PATCH 0555/2119] fix: run mocha within packages in monorepo --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 4ffb10390b..bd9e49655e 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "webpack-cli": "^5.1.1" }, "scripts": { - "test": "mocha ./src/phoenix/test ./src/phoenix/packages/contextlink/test", + "test": "cd src/phoenix && npx mocha && cd - && cd src/phoenix/packages/contextlink && npx mocha && cd -", "start=gui": "nodemon --exec \"node dev-server.js\" ", "start": "node ./tools/run-selfhosted.js", "build": "cd src/gui; node ./build.js", From aebe89a1acb070764551e8e89e325325ffbed8f9 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 18 Jul 2024 16:16:31 -0400 Subject: [PATCH 0556/2119] fix: fix CI attempt #2 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index bd9e49655e..61a744aebd 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "webpack-cli": "^5.1.1" }, "scripts": { - "test": "cd src/phoenix && npx mocha && cd - && cd src/phoenix/packages/contextlink && npx mocha && cd -", + "test": "cd src/phoenix && npx mocha && cd - && cd src/contextlink && npx mocha && cd -", "start=gui": "nodemon --exec \"node dev-server.js\" ", "start": "node ./tools/run-selfhosted.js", "build": "cd src/gui; node ./build.js", From 3bca973f5f4e65a2bd24c634c347fbd681a7458b Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 18 Jul 2024 16:20:57 -0400 Subject: [PATCH 0557/2119] fix: fix CI attempt #3 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 61a744aebd..622e9f6869 100644 --- a/package.json +++ b/package.json @@ -26,7 +26,7 @@ "webpack-cli": "^5.1.1" }, "scripts": { - "test": "cd src/phoenix && npx mocha && cd - && cd src/contextlink && npx mocha && cd -", + "test": "cd src/phoenix && npm run test && cd - && cd src/contextlink && npm run test && cd -", "start=gui": "nodemon --exec \"node dev-server.js\" ", "start": "node ./tools/run-selfhosted.js", "build": "cd src/gui; node ./build.js", From 84b993bce913c3ad99127063bcfaae19331b199c Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 18 Jul 2024 16:27:36 -0400 Subject: [PATCH 0558/2119] fix: fix CI attempt #4 --- package-lock.json | 1 + package.json | 1 + 2 files changed, 2 insertions(+) diff --git a/package-lock.json b/package-lock.json index 0f974767da..8a116899e3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,7 @@ "globals": "^15.0.0", "html-entities": "^2.3.3", "license-check-and-add": "^4.0.5", + "mocha": "^10.6.0", "nodemon": "^3.1.0", "uglify-js": "^3.17.4", "webpack": "^5.88.2", diff --git a/package.json b/package.json index 622e9f6869..277c49cfab 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "globals": "^15.0.0", "html-entities": "^2.3.3", "license-check-and-add": "^4.0.5", + "mocha": "^10.6.0", "nodemon": "^3.1.0", "uglify-js": "^3.17.4", "webpack": "^5.88.2", From d9a90a67c17db22c0df482b35e4cd501977ab3b6 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 18 Jul 2024 13:30:05 -0700 Subject: [PATCH 0559/2119] let me try fixing mocha! --- package-lock.json | 4 ++-- package.json | 1 + src/phoenix/package.json | 2 +- 3 files changed, 4 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index 0f974767da..54a4d4815d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -29,6 +29,7 @@ "globals": "^15.0.0", "html-entities": "^2.3.3", "license-check-and-add": "^4.0.5", + "mocha": "^10.6.0", "nodemon": "^3.1.0", "uglify-js": "^3.17.4", "webpack": "^5.88.2", @@ -9938,7 +9939,6 @@ "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.6.0.tgz", "integrity": "sha512-hxjt4+EEB0SA0ZDygSS015t65lJw/I2yRCS3Ae+SJ5FrbzrXgfYwJr96f0OvIXdj7h4lv/vLCrH3rkiuizFSvw==", "dev": true, - "license": "MIT", "dependencies": { "ansi-colors": "^4.1.3", "browser-stdout": "^1.3.1", @@ -14183,7 +14183,7 @@ "@rollup/plugin-commonjs": "^24.1.0", "@rollup/plugin-node-resolve": "^15.0.2", "@rollup/plugin-replace": "^5.0.2", - "mocha": "^10.2.0", + "mocha": "^10.6.0", "rollup": "^3.21.4", "rollup-plugin-copy": "^3.4.0" }, diff --git a/package.json b/package.json index 622e9f6869..277c49cfab 100644 --- a/package.json +++ b/package.json @@ -20,6 +20,7 @@ "globals": "^15.0.0", "html-entities": "^2.3.3", "license-check-and-add": "^4.0.5", + "mocha": "^10.6.0", "nodemon": "^3.1.0", "uglify-js": "^3.17.4", "webpack": "^5.88.2", diff --git a/src/phoenix/package.json b/src/phoenix/package.json index 22191b1473..7275463d17 100644 --- a/src/phoenix/package.json +++ b/src/phoenix/package.json @@ -13,7 +13,7 @@ "@rollup/plugin-commonjs": "^24.1.0", "@rollup/plugin-node-resolve": "^15.0.2", "@rollup/plugin-replace": "^5.0.2", - "mocha": "^10.2.0", + "mocha": "^10.6.0", "rollup": "^3.21.4", "rollup-plugin-copy": "^3.4.0" }, From 5a4328e44935cd07c7c5482fa959804f7c063652 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 18 Jul 2024 13:33:02 -0700 Subject: [PATCH 0560/2119] Update Dockerfile --- Dockerfile | 3 +++ 1 file changed, 3 insertions(+) diff --git a/Dockerfile b/Dockerfile index 5e41d7a000..76961e1b50 100644 --- a/Dockerfile +++ b/Dockerfile @@ -23,6 +23,9 @@ COPY package*.json ./ # Copy the source files COPY . . +# Install mocha +RUN npm install -g mocha + # Install node modules RUN npm cache clean --force && \ for i in 1 2 3; do \ From 74adcddc1d60e0a513408a0716ed2b301126225d Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 18 Jul 2024 16:36:33 -0400 Subject: [PATCH 0561/2119] fix: fix CI attempt #5 --- src/phoenix/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/phoenix/package.json b/src/phoenix/package.json index 7275463d17..1d8f754e52 100644 --- a/src/phoenix/package.json +++ b/src/phoenix/package.json @@ -4,7 +4,7 @@ "description": "ANSI Terminal for Puter", "main": "exports.js", "scripts": { - "test": "mocha ./test" + "test": "npx mocha" }, "author": "Puter Technologies Inc.", "license": "AGPL-3.0-only", From 9d549b192d149eac96c316ded645bf7c2e96153d Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 18 Jul 2024 16:38:56 -0400 Subject: [PATCH 0562/2119] fix: fix CI attempt #6 --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 277c49cfab..00c5fba75c 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "webpack-cli": "^5.1.1" }, "scripts": { - "test": "cd src/phoenix && npm run test && cd - && cd src/contextlink && npm run test && cd -", + "test": "cd src/phoenix && npm ci && npm run test && cd - && cd src/contextlink && npm ci && npm run test && cd -", "start=gui": "nodemon --exec \"node dev-server.js\" ", "start": "node ./tools/run-selfhosted.js", "build": "cd src/gui; node ./build.js", From 614f2c5061525f230ccd879bfb047434ac46a9ba Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 18 Jul 2024 16:44:11 -0400 Subject: [PATCH 0563/2119] fix: fix CI attempt #7 --- package-lock.json | 1 + package.json | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 54a4d4815d..0568e05cb8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9939,6 +9939,7 @@ "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.6.0.tgz", "integrity": "sha512-hxjt4+EEB0SA0ZDygSS015t65lJw/I2yRCS3Ae+SJ5FrbzrXgfYwJr96f0OvIXdj7h4lv/vLCrH3rkiuizFSvw==", "dev": true, + "license": "MIT", "dependencies": { "ansi-colors": "^4.1.3", "browser-stdout": "^1.3.1", diff --git a/package.json b/package.json index 00c5fba75c..0a6bc77824 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "webpack-cli": "^5.1.1" }, "scripts": { - "test": "cd src/phoenix && npm ci && npm run test && cd - && cd src/contextlink && npm ci && npm run test && cd -", + "test": "npx mocha src/phoenix", "start=gui": "nodemon --exec \"node dev-server.js\" ", "start": "node ./tools/run-selfhosted.js", "build": "cd src/gui; node ./build.js", From 602a19895c05b45a7d283470e7af3ae786be1bf2 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 18 Jul 2024 16:58:36 -0400 Subject: [PATCH 0564/2119] fix: it was github actions the entire time --- .github/workflows/build-and-test.yml | 31 ---------------------------- 1 file changed, 31 deletions(-) delete mode 100644 .github/workflows/build-and-test.yml diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml deleted file mode 100644 index f7d4bb1676..0000000000 --- a/.github/workflows/build-and-test.yml +++ /dev/null @@ -1,31 +0,0 @@ -# This workflow will do a clean installation of node dependencies, cache/restore them, build the source code and run tests across different versions of node -# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-nodejs - -name: Node.js CI - -on: - push: - branches: [ "main" ] - pull_request: - branches: [ "main" ] - -jobs: - build: - - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [20.x, 21.x, 22.x] - # See supported Node.js release schedule at https://nodejs.org/en/about/releases/ - - steps: - - uses: actions/checkout@v4 - - name: Use Node.js ${{ matrix.node-version }} - uses: actions/setup-node@v4 - with: - node-version: ${{ matrix.node-version }} - cache: 'npm' - - run: npm ci - - run: npm run build --if-present - - run: npm test From ae25711a13718f11f785566aa9ec68913f3ae33d Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 18 Jul 2024 17:02:31 -0400 Subject: [PATCH 0565/2119] update package.json for local testing --- package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/package.json b/package.json index 0a6bc77824..886b2def04 100644 --- a/package.json +++ b/package.json @@ -27,7 +27,7 @@ "webpack-cli": "^5.1.1" }, "scripts": { - "test": "npx mocha src/phoenix", + "test": "npx mocha src/phoenix/test src/contextlink/test", "start=gui": "nodemon --exec \"node dev-server.js\" ", "start": "node ./tools/run-selfhosted.js", "build": "cd src/gui; node ./build.js", From eeda9fb56806111db2fde29c6facfd027b8373dd Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 18 Jul 2024 16:06:45 -0700 Subject: [PATCH 0566/2119] close #409 --- src/gui/src/helpers.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/gui/src/helpers.js b/src/gui/src/helpers.js index 394bcc65f1..a85be51b5a 100644 --- a/src/gui/src/helpers.js +++ b/src/gui/src/helpers.js @@ -1169,7 +1169,13 @@ window.trigger_download = (paths)=>{ urls.forEach(async function (e) { const anti_csrf = await (async () => { - const resp = await fetch(`${window.gui_origin}/get-anticsrf-token`); + const resp = await fetch( + `${window.gui_origin}/get-anticsrf-token`,{ + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + window.auth_token, + } + },) const { token } = await resp.json(); return token; })(); From 7043b9400c63842c4c54d82724167666708d3119 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 18 Jul 2024 20:16:08 -0400 Subject: [PATCH 0567/2119] fix: well kinda (HOSTNAME in phoenix) --- src/phoenix/src/platform/puter/env.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/phoenix/src/platform/puter/env.js b/src/phoenix/src/platform/puter/env.js index 0c7b23896d..e69e948cc8 100644 --- a/src/phoenix/src/platform/puter/env.js +++ b/src/phoenix/src/platform/puter/env.js @@ -22,7 +22,7 @@ export const CreateEnvProvider = ({ config }) => { return { USER: config['puter.auth.username'], HOME: '/' + config['puter.auth.username'], - HOSTNAME: config['puter.domain'], + HOSTNAME: config['puter.domain'] ?? 'puter.com', } }, From e58da265ba30654309b51c6d3a2c774b3a8c3463 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 18 Jul 2024 20:58:09 -0400 Subject: [PATCH 0568/2119] try cross-origin isolation only on sites --- src/backend/src/services/WebServerService.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/src/services/WebServerService.js b/src/backend/src/services/WebServerService.js index 633fd2972f..57fe8b8213 100644 --- a/src/backend/src/services/WebServerService.js +++ b/src/backend/src/services/WebServerService.js @@ -392,7 +392,7 @@ class WebServerService extends BaseService { // NOTE: This is put behind a configuration flag because we // need some experimentation to ensure the interface // between apps and Puter doesn't break. - if ( config.cross_origin_isolation ) { + if ( config.cross_origin_isolation && is_site ) { res.setHeader('Cross-Origin-Opener-Policy', 'same-origin'); res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp'); } From 333d6e3b651e460caca04a896cbc8c175555b79b Mon Sep 17 00:00:00 2001 From: Alfika07 Date: Fri, 19 Jul 2024 09:43:23 +0200 Subject: [PATCH 0569/2119] Move Tamil translation to the rest of translations --- src/{ => gui/src}/i18n/translations/ta.js | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename src/{ => gui/src}/i18n/translations/ta.js (100%) diff --git a/src/i18n/translations/ta.js b/src/gui/src/i18n/translations/ta.js similarity index 100% rename from src/i18n/translations/ta.js rename to src/gui/src/i18n/translations/ta.js From 8a3d0430f39f872b8a460c344cce652c340b700b Mon Sep 17 00:00:00 2001 From: Alfika07 Date: Fri, 19 Jul 2024 09:46:04 +0200 Subject: [PATCH 0570/2119] Add Tamil translation to translations.js --- src/gui/src/i18n/translations/translations.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/src/i18n/translations/translations.js b/src/gui/src/i18n/translations/translations.js index 6dcd3547ae..debc5a3076 100644 --- a/src/gui/src/i18n/translations/translations.js +++ b/src/gui/src/i18n/translations/translations.js @@ -41,6 +41,7 @@ import pt from './pt.js'; import ro from './ro.js'; import ru from './ru.js'; import sv from './sv.js'; +import ta from './ta.js'; import th from './th.js'; import tr from './tr.js'; import ur from './ur.js'; @@ -77,6 +78,7 @@ export default { pl, pt, sv, + ta, th, tr, ua, From f2bb551e759a1f15f2e39f68d82990731565749e Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Fri, 19 Jul 2024 08:52:19 -0700 Subject: [PATCH 0571/2119] Change `english_name` from `English` to `Tamil` --- src/gui/src/i18n/translations/ta.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/ta.js b/src/gui/src/i18n/translations/ta.js index 807862775f..878024b784 100644 --- a/src/gui/src/i18n/translations/ta.js +++ b/src/gui/src/i18n/translations/ta.js @@ -19,7 +19,7 @@ const ta = { name: "ஆங்கிலம்", - english_name: "English", + english_name: "Tamil", code: "ta", dictionary: { about: "பற்றி", From 98e69642d027a83975a0b2b825317213098bb689 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Fri, 19 Jul 2024 13:11:26 -0700 Subject: [PATCH 0572/2119] fix: `launch_app` not considering `explorer` as a special case --- src/gui/src/UI/UIWindowShare.js | 9 ++++----- src/gui/src/helpers/launch_app.js | 12 +++++++++++- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/gui/src/UI/UIWindowShare.js b/src/gui/src/UI/UIWindowShare.js index 9d0aca875a..67aebc8a73 100644 --- a/src/gui/src/UI/UIWindowShare.js +++ b/src/gui/src/UI/UIWindowShare.js @@ -22,14 +22,14 @@ async function UIWindowShare(items, recipient){ return new Promise(async (resolve) => { let h = ''; h += `
`; - h += `
×
`; + h += `
×
`; //------------------------------------------------ - // Icon + // Icons //------------------------------------------------ - // 1 item shared - h += `
`; + h += `
`; + // 1 item shared if(items.length === 1) h += ``; // 2 items shared @@ -58,7 +58,6 @@ async function UIWindowShare(items, recipient){ h += ``; h += ``; } - h += `
`; // ------------------------------------------------ diff --git a/src/gui/src/helpers/launch_app.js b/src/gui/src/helpers/launch_app.js index bdce5b3063..607d9a30b0 100644 --- a/src/gui/src/helpers/launch_app.js +++ b/src/gui/src/helpers/launch_app.js @@ -36,7 +36,17 @@ const launch_app = async (options)=>{ } // If the app object is not provided, get it from the server - let app_info = options.app_obj ?? await puter.apps.get(options.name); + let app_info; + + // explorer is a special case + if(options.name === 'explorer'){ + console.log('explorer'); + app_info = []; + } + else if(options.app_obj) + app_info = options.app_obj; + else + app_info = await puter.apps.get(options.name); // For backward compatibility reasons we need to make sure that both `uuid` and `uid` are set app_info.uuid = app_info.uuid ?? app_info.uid; From f897e844989083b0b369ba0ce4d2c5a9f3db5ad8 Mon Sep 17 00:00:00 2001 From: Koppeks Date: Fri, 19 Jul 2024 19:42:47 -0300 Subject: [PATCH 0573/2119] Temporal commit for issue #432 --- src/gui/src/globals.js | 2 + src/gui/src/helpers.js | 54 +++++++++ src/gui/src/helpers/new_context_menu_item.js | 114 ++++++++++++------- src/gui/src/icons/file-template.svg | 11 ++ src/gui/src/initgui.js | 2 + 5 files changed, 141 insertions(+), 42 deletions(-) create mode 100644 src/gui/src/icons/file-template.svg diff --git a/src/gui/src/globals.js b/src/gui/src/globals.js index 4f0c2d98a3..ae54414801 100644 --- a/src/gui/src/globals.js +++ b/src/gui/src/globals.js @@ -231,6 +231,8 @@ window.is_auto_arrange_enabled = true; window.desktop_item_positions = {}; window.reset_item_positions = true; // The variable decides if the item positions should be reset when the user enabled auto arrange +window.file_templates = [] + // default language window.locale = 'en'; diff --git a/src/gui/src/helpers.js b/src/gui/src/helpers.js index a85be51b5a..3d15fb029a 100644 --- a/src/gui/src/helpers.js +++ b/src/gui/src/helpers.js @@ -837,6 +837,60 @@ window.create_file = async(options)=>{ } } +window.available_templates = async () => { + console.log(window.user.username) + const baseRoute = `/${window.user.username}` + const keywords = ["template", "templates", i18n('template')] + //make sure all its lowercase + const lowerCaseKeywords = keywords.map(keywords => keywords.toLowerCase()) + + //create file + try{ + // search the folder name i18n("template"), "template" or "templates" + const files = await puter.fs.readdir(baseRoute) + + const hasTemplateFolder = files.find(file => lowerCaseKeywords.includes(file.name.toLowerCase())) + console.log(hasTemplateFolder) + + if(!hasTemplateFolder){ + console.log("No template folder") + return [] + } + + const hasTemplateFiles = await puter.fs.readdir(baseRoute + "/" + hasTemplateFolder.name) + console.log(hasTemplateFiles) + + if(hasTemplateFiles.length == 0) { + console.log("There are no templates") + return [] + } + + let result = [] + + hasTemplateFiles.forEach(element => { + console.log(element) + const elementInformation = element.name.split(".") + const name = elementInformation[0] + let extension = elementInformation[1] + console.log(extension) + if(extension == "txt") extension = "text" + const itemStructure = { + html: `${extension.toUpperCase()} ${name}`, + extension:extension, + name: element.name + } + console.log(extension) + result.push(itemStructure) + }); + + // return result + return result + + } catch (err) { + console.log(err) + } +} + window.create_shortcut = async(filename, is_dir, basedir, appendto_element, shortcut_to, shortcut_to_path)=>{ let dirname = basedir; const extname = path.extname(filename); diff --git a/src/gui/src/helpers/new_context_menu_item.js b/src/gui/src/helpers/new_context_menu_item.js index 6c2ea49e14..602a8ae2b8 100644 --- a/src/gui/src/helpers/new_context_menu_item.js +++ b/src/gui/src/helpers/new_context_menu_item.js @@ -27,52 +27,82 @@ */ const new_context_menu_item = function(dirname, append_to_element){ - return { - html: i18n('new'), - items: [ - // New Folder - { - html: i18n('new_folder'), - icon: ``, - onClick: function(){ - window.create_folder(dirname, append_to_element); - } - }, - // divider - '-', - // Text Document - { - html: i18n('text_document'), - icon: ``, - onClick: async function(){ - window.create_file({dirname: dirname, append_to_element: append_to_element, name: 'New File.txt'}); - } - }, - // HTML Document - { - html: i18n('html_document'), - icon: ``, - onClick: async function(){ - window.create_file({dirname: dirname, append_to_element: append_to_element, name: 'New File.html'}); - } + + const baseItems = [ + // New Folder + { + html: i18n('new_folder'), + icon: ``, + onClick: function() { + window.create_folder(dirname, append_to_element); }, - // JPG Image - { - html: i18n('jpeg_image'), - icon: ``, - onClick: async function(){ - var canvas = document.createElement("canvas"); + }, + // divider + '-', + // Text Document + { + html: i18n('text_document'), + icon: ``, + onClick: async function() { + window.create_file({dirname: dirname, append_to_element: append_to_element, name: 'New File.txt'}); + } + }, + // HTML Document + { + html: i18n('html_document'), + icon: ``, + onClick: async function() { + window.create_file({dirname: dirname, append_to_element: append_to_element, name: 'New File.html'}); + } + }, + // JPG Image + { + html: i18n('jpeg_image'), + icon: ``, + onClick: async function() { + var canvas = document.createElement("canvas"); - canvas.width = 800; - canvas.height = 600; - - canvas.toBlob((blob) =>{ - window.create_file({dirname: dirname, append_to_element: append_to_element, name: 'New Image.jpg', content: blob}); - }); + canvas.width = 800; + canvas.height = 600; + + canvas.toBlob((blob) => { + window.create_file({dirname: dirname, append_to_element: append_to_element, name: 'New Image.jpg', content: blob}); + }); + } + }, + // divider + '-' + ]; + + //Show file_templates on the lower part of "New" + if (window.file_templates.length > 0) { + baseItems.push({ + html: "User templates", + icon: ``, + items: window.file_templates.map(template => ({ + html: template.html, + icon: ``, + onClick: function() { + window.create_file({dirname: dirname, append_to_element: append_to_element, name: template.name}); } - }, - ] + })) + }); + } else { + baseItems.push({ + html: "No templates found", + icon: ``, + //Add function to ask user to create new template folder + // onClick: function() { + // window.create_file({dirname: dirname, append_to_element: append_to_element, name: template.name}); + // } + }); } + + //Conditional rendering for the templates + return { + html: i18n('new'), + items: baseItems + }; } export default new_context_menu_item; \ No newline at end of file diff --git a/src/gui/src/icons/file-template.svg b/src/gui/src/icons/file-template.svg new file mode 100644 index 0000000000..2fd3284be8 --- /dev/null +++ b/src/gui/src/icons/file-template.svg @@ -0,0 +1,11 @@ + + + + + + + + + + + diff --git a/src/gui/src/initgui.js b/src/gui/src/initgui.js index cd7bf0b33d..a28b1a659f 100644 --- a/src/gui/src/initgui.js +++ b/src/gui/src/initgui.js @@ -108,6 +108,8 @@ const launch_services = async function (options) { const svc_process = globalThis.services.get('process'); svc_process.get_init().chstatus(PROCESS_RUNNING); } + // Search and store user templates + window.file_templates = await window.available_templates() }; // This code snippet addresses the issue flagged by Lighthouse regarding the use of From 37fd666a9a6788d5f0c59311499f29896b48bc82 Mon Sep 17 00:00:00 2001 From: mlgzackfly Date: Sat, 20 Jul 2024 19:36:45 +0800 Subject: [PATCH 0574/2119] fix(i18n): update zhtw.js to match en.js --- src/gui/src/i18n/translations/zhtw.js | 134 +++++++++++++++++++++++++- 1 file changed, 129 insertions(+), 5 deletions(-) diff --git a/src/gui/src/i18n/translations/zhtw.js b/src/gui/src/i18n/translations/zhtw.js index 276284d440..4429f6a2eb 100644 --- a/src/gui/src/i18n/translations/zhtw.js +++ b/src/gui/src/i18n/translations/zhtw.js @@ -24,11 +24,14 @@ const zhtw = { dictionary: { about: "關於", account: "帳號", + account_password: "驗證帳號密碼", access_granted_to: "已授予存取權限給", add_existing_account: "新增現有帳號", all_fields_required: '所有欄位都必須填寫。', + allow: "允許", apply: "套用", ascending: '升序', + associated_websites: "相關網站", auto_arrange: '自動排列', background: "背景", browse: "瀏覽", @@ -40,24 +43,40 @@ const zhtw = { change_password: "更改密碼", change_ui_colors: "更改 UI 顏色", change_username: "更改使用者名稱", + close: '關閉', close_all_windows: "關閉所有視窗", + close_all_windows_confirm: "您確定要關閉所有視窗嗎?", close_all_windows_and_log_out: '關閉視窗並登出', change_always_open_with: "您是否希望總是用此程式開啟這類型的檔案", color: '顏色', - hue: '色調', + confirm: '確認', + confirm_2fa_setup: '我已將程式碼新增至我的身份驗證器應用程式中', + confirm_2fa_recovery: '我已將恢復代碼保存在安全位置', confirm_account_for_free_referral_storage_c2a: '建立帳號並確認您的電子郵件地址以獲得 1 GB 的免費儲存空間。您的朋友也將獲得 1 GB 的免費儲存空間。', + confirm_code_generic_incorrect: "不正確的代碼。", + confirm_code_generic_too_many_requests: "請求太多。請稍等幾分鐘。", + confirm_code_generic_submit: "送出代碼", + confirm_code_generic_try_again: "再試一次", + confirm_code_generic_title: "輸入驗證碼", + confirm_code_2fa_instruction: "輸入驗證器應用程式中的 6 位數代碼。", + confirm_code_2fa_submit_btn: "送出", + confirm_code_2fa_title: "輸入 2FA 代碼", confirm_delete_multiple_items: '您確定要永久刪除這些項目嗎?', confirm_delete_single_item: '您確定要永久刪除此項目嗎?', confirm_open_apps_log_out: '您有開啟的應用程式。您確定要登出嗎?', confirm_new_password: "確認新密碼", confirm_delete_user: "您確定要刪除您的帳號嗎?您的所有檔案和資料將被永久刪除。此操作無法復原。", confirm_delete_user_title: "刪除帳號?", + confirm_session_revoke: "您確定要撤銷此會話嗎?", + confirm_your_email_address: "確認您的電子郵件地址", contact_us: "聯絡我們", + contact_us_verification_required: "您必須擁有經過驗證的電子郵件地址才能使用。", contain: '包含', continue: "繼續", copy: '複製', copy_link: "複製連結", copying: "正在複製", + copying_file: "正在複製 %%", cover: '覆蓋', create_account: "建立帳號", create_free_account: "建立免費帳號", @@ -69,36 +88,62 @@ const zhtw = { clock_visible_hide: '隱藏 - 總是隱藏', clock_visible_show: '顯示 - 總是顯示', clock_visible_auto: '自動 - 預設,僅在全螢幕模式下可見。', + close_all: '關閉全部', + created: '創建於', date_modified: '修改日期', + default: '預設', delete: '刪除', delete_account: "刪除帳號", delete_permanently: "永久刪除", + deleting_file: "正在刪除 %%", deploy_as_app: '部署為應用程式', descending: '降序', + desktop: '桌面', desktop_background_fit: "適應", developers: "開發者", dir_published_as_website: `%strong% 已發布到:`, + disable_2fa: '停用 2FA', + disable_2fa_confirm: "你確定要停用 2FA 嗎?", + disable_2fa_instructions: "輸入您的密碼以停用 2FA。", disassociate_dir: "取消關聯目錄", + documents: '文件', + dont_allow: '不允許', download: '下載', download_file: '下載檔案', downloading: "正在下載", email: "電子郵件", + email_change_confirmation_sent: "確認電子郵件已發送到您的新電子郵件地址。請檢查您的收件箱並按照說明完成過程。A confirmation email has been sent to your new email address. Please check your inbox and follow the instructions to complete the process.", + email_invalid: '無效的電子郵件。', email_or_username: "電子郵件或使用者名稱", + email_required: '電子郵件是必需的。', empty_trash: '清空垃圾桶', empty_trash_confirmation: `您確定要永久刪除垃圾桶中的項目嗎?`, emptying_trash: '正在清空垃圾桶…', + enable_2fa: '啟用 2FA', + end_hard: "強制結束", + end_process_force_confirm: "您確定要強制結束此程式嗎?", + end_soft: "正常結束", + enlarged_qr_code: "放大 QR Code", enter_password_to_confirm_delete_user: "輸入您的密碼以確認刪除帳號", + error_message_is_missing: "遺失錯誤信息。", + error_unknown_cause: "發生未知錯誤。An unknown error occurred.", + error_uploading_files: "文件上傳失敗", + favorites: "收藏", feedback: "回饋", feedback_c2a: "請使用下面的表單向我們傳送您的回饋、評論和錯誤報告。", feedback_sent_confirmation: "感謝您聯絡我們。如果您的帳號有關聯的電子郵件,我們將盡快回覆您。", fit: "適應", + folder: '資料夾', + force_quit: '強制退出', forgot_pass_c2a: "忘記密碼?", from: "從", general: "一般", get_a_copy_of_on_puter: `在 Puter.com 上取得 '%%' 的副本!`, get_copy_link: '取得複製連結', hide_all_windows: "隱藏所有視窗", + home: '首頁', html_document: 'HTML 文件', + hue: '色調', image: '圖片', incorrect_password: "密碼錯誤", invite_link: "邀請連結", @@ -109,10 +154,18 @@ const zhtw = { language: "語言", license: "許可證", lightness: '亮度', + link_copied: "連結已複製", loading: '載入中', log_in: "登入", log_into_another_account_anyway: '無論如何都要登入另一個帳號', log_out: '登出', + looks_good: "看起來不錯!", + manage_sessions: "管理 Session", + menubar_style: "選單列樣式", + menubar_style_desktop: "桌面", + menubar_style_system: "系統", + menubar_style_window: "視窗", + modified: '修改的', move: '移動', moving_file: "正在移動 %%", my_websites: "我的網站", @@ -124,6 +177,7 @@ const zhtw = { name_must_be_string: "名稱只能是字串。", name_too_long: `名稱不能超過 %% 個字元。`, new: '新建', + new_email: '新電子郵件', new_folder: '新資料夾', new_password: "新密碼", new_username: "新使用者名稱", @@ -135,28 +189,45 @@ const zhtw = { open_in_new_tab: "在新標籤頁中開啟", open_in_new_window: "在新視窗中開啟", open_with: "開啟方式", + original_name: '原始名稱', + original_path: '原始路徑', oss_code_and_content: "開源軟體和內容", password: "密碼", password_changed: "密碼已更改。", - passwords_do_not_match: '`新密碼` 和 `確認新密碼` 不符。', + password_recovery_rate_limit: "您已達到我們的速率限制;請等幾分鐘再試。為了避免未來出現此問題,請避免過於頻繁地重新載入頁面。", + password_recovery_token_invalid: "此密碼恢復 Token 已不再有效。", + password_recovery_unknown_error: "發生未知錯誤。請稍後再試。", + password_required: '需要密碼。', + password_strength_error: "密碼必須至少包含 8 個字元,並包含至少一個大寫字母、一個小寫字母、一個數字和一個特殊字元。", + passwords_do_not_match: '`新密碼` 和 `確認新密碼` 不匹配。', paste: '貼上', paste_into_folder: "貼入資料夾", + path: '路徑', personalization: "個人化", pick_name_for_website: "為您的網站選擇一個名稱:", picture: "圖片", + pictures: '圖片', plural_suffix: '個', powered_by_puter_js: `由 {{link=docs}}Puter.js{{/link}} 提供技術支援`, preparing: "準備中...", preparing_for_upload: "準備上傳...", + print: '輸出', privacy: "隱私", proceed_to_login: '繼續登入', proceed_with_account_deletion: "繼續刪除帳號", + process_status_initializing: "初始化中", + process_status_running: "運行中", + process_type_app: '應用程式', + process_type_init: '初始化', + process_type_ui: '使用者介面', properties: "屬性", + public: '公開', publish: "發布", publish_as_website: '發布為網站', - puter_description: `Puter 是一個以隱私為首的個人雲端,將您的所有檔案、應用程式和遊戲保留在一個 - 安全的地方,隨時隨地都可以存取。`, + puter_description: `Puter 是一個以隱私為首的個人雲端,將您的所有檔案、應用程式和遊戲保留在一個安全的地方,隨時隨地都可以存取。`, + reading_file: "讀取 %strong%", recent: "最近", + recommended: "推薦", recover_password: "找回密碼", refer_friends_c2a: "每推薦一位朋友在 Puter 上建立並確認帳號,您就可以獲得 1 GB 的儲存空間。您的朋友也會獲得 1 GB 的儲存空間!", refer_friends_social_media_c2a: `在 Puter.com 上獲得 1 GB 的免費儲存空間!`, @@ -169,7 +240,9 @@ const zhtw = { replace_all: '全部取代', resend_confirmation_code: "重新傳送確認碼", reset_colors: "重設顏色", + restart_puter_confirm: "你確定要重新啟動 Puter 嗎?", restore: "還原", + save: '儲存', saturation: '飽和度', save_account: '儲存帳號', save_account_to_get_copy_link: "請建立帳號以繼續。", @@ -177,15 +250,24 @@ const zhtw = { save_session: '儲存工作階段', save_session_c2a: '建立帳號以儲存您目前的工作階段,避免遺失您的工作。', scan_qr_c2a: '掃描下方的 QR Code,從其他裝置登入此工作階段', + scan_qr_2fa: '使用您的驗證器應用程式掃描 QR Code', + scan_qr_generic: '使用您的手機或其他裝置掃描此 QR Code', + search: '搜尋', + seconds: '秒', + security: '安全性', select: "選擇", selected: '已選擇', select_color: '選擇顏色…', + sessions: "Sessions", send: "傳送", send_password_recovery_email: "傳送密碼恢復電子郵件", session_saved: "感謝您建立帳號。此工作階段已儲存。", settings: "設定", set_new_password: "設定新密碼", + share: "分享", share_to: "分享到", + share_with: "分享給:", + shortcut_to: "捷徑到", show_all_windows: "顯示所有視窗", show_hidden: '顯示隱藏項目', sign_in_with_puter: "使用 Puter 登入", @@ -193,19 +275,30 @@ const zhtw = { signing_in: "正在登入…", size: '大小', skip: '跳過', + something_went_wrong: "出了些問題。", sort_by: '排序方式', start: '開始', status: "狀態", storage_usage: "儲存空間使用情況", + storage_puter_used: "由 Puter 使用", taking_longer_than_usual: '花費的時間比預期的還長。請稍候...', + task_manager: "任務管理器", + taskmgr_header_name: "名稱", + taskmgr_header_status: "狀態", + taskmgr_header_type: "類型", terms: "條款", text_document: '文字文件', tos_fineprint: `點選 '建立免費帳號' 即表示您同意 Puter 的 {{link=terms}}服務條款{{/link}} 和 {{link=privacy}}隱私政策{{/link}}。`, transparency: "透明度", trash: '垃圾桶', + two_factor: '雙重要素驗證', + two_factor_disabled: '2FA 已禁用', + two_factor_enabled: '2FA 已啟用', type: '類型', type_confirm_to_delete_account: "輸入 'confirm' 以刪除您的帳號。", ui_colors: "UI 顏色", + ui_manage_sessions: "Session 管理器", + ui_revoke: "撤銷", undo: '復原', unlimited: '無限', unzip: "解壓縮", @@ -214,13 +307,44 @@ const zhtw = { usage: '使用情況', username: "使用者名稱", username_changed: '使用者名稱已成功更新。', + username_required: '使用者名稱是必需的。', versions: "版本", visibility: '可視性', + website: "網站", yes: '是', yes_release_it: '是的,釋放它', you_have_been_referred_to_puter_by_a_friend: "您的朋友推薦您使用 Puter!", zip: "壓縮", - storage_puter_used: "由 Puter 使用", + zipping_file: "壓縮檔案 %strong%", + + // === 2FA Setup === + setup2fa_1_step_heading: '打開您的驗證器應用程式', + setup2fa_1_instructions: ` + 您可以使用任何支援時間基礎一次性密碼(TOTP)協議的驗證器應用程式。 + 有很多選擇,如果您不確定 + Authy + 是 Android 和 iOS 的可靠選擇。 + `, + setup2fa_2_step_heading: '掃描 QR Code', + setup2fa_3_step_heading: '輸入 6 位數碼', + setup2fa_4_step_heading: '複製您的恢復代碼', + setup2fa_4_instructions: ` + 這些恢復代碼是您在遺失手機或無法使用驗證器應用程式時訪問帳戶的唯一方法。 + 請確保將它們儲存在安全的地方。 + `, + setup2fa_5_step_heading: '確認 2FA 設定', + setup2fa_5_confirmation_1: '我已經將恢復代碼儲存在安全的位置', + setup2fa_5_confirmation_2: '我準備啟用 2FA', + setup2fa_5_button: '啟用 2FA', + + // === 2FA Login === + login2fa_otp_title: '輸入 2FA 代碼', + login2fa_otp_instructions: '輸入您驗證器應用程式中的 6 位數碼代碼。', + login2fa_recovery_title: '輸入恢復代碼', + login2fa_recovery_instructions: '輸入您的恢復代碼之一以訪問您的帳戶。', + login2fa_use_recovery_code: '使用恢復代碼', + login2fa_recovery_back: '返回', + login2fa_recovery_placeholder: 'XXXXXXXX', } }; From b9e73b7288aebb14e6bbf1915743e9157fc950b1 Mon Sep 17 00:00:00 2001 From: WHL Date: Sat, 20 Jul 2024 22:18:05 +0800 Subject: [PATCH 0575/2119] Update zhtw.js, Complete Traditional Chinese translation based on English file #550 --- src/gui/src/i18n/translations/zhtw.js | 328 ++++++++++++++++++-------- 1 file changed, 226 insertions(+), 102 deletions(-) diff --git a/src/gui/src/i18n/translations/zhtw.js b/src/gui/src/i18n/translations/zhtw.js index 276284d440..dbc8dd5b13 100644 --- a/src/gui/src/i18n/translations/zhtw.js +++ b/src/gui/src/i18n/translations/zhtw.js @@ -23,143 +23,214 @@ const zhtw = { code: "zhtw", dictionary: { about: "關於", - account: "帳號", - access_granted_to: "已授予存取權限給", - add_existing_account: "新增現有帳號", - all_fields_required: '所有欄位都必須填寫。', + account: "帳戶", + account_password: "驗證帳戶密碼", + access_granted_to: "已授予存取權給", + add_existing_account: "新增現有帳戶", + all_fields_required: '所有欄位都是必填的。', + allow: '允許', apply: "套用", ascending: '升序', + associated_websites: "關聯的網站", auto_arrange: '自動排列', background: "背景", browse: "瀏覽", cancel: '取消', - center: '中心', + center: '置中', change_desktop_background: '更改桌面背景…', change_email: "更改電子郵件", change_language: "更改語言", change_password: "更改密碼", - change_ui_colors: "更改 UI 顏色", + change_ui_colors: "更改使用者介面顏色", change_username: "更改使用者名稱", + close: '關閉', close_all_windows: "關閉所有視窗", + close_all_windows_confirm: "您確定要關閉所有視窗嗎?", close_all_windows_and_log_out: '關閉視窗並登出', - change_always_open_with: "您是否希望總是用此程式開啟這類型的檔案", + change_always_open_with: "您是否要始終使用以下程式開啟此類型的檔案", color: '顏色', - hue: '色調', - confirm_account_for_free_referral_storage_c2a: '建立帳號並確認您的電子郵件地址以獲得 1 GB 的免費儲存空間。您的朋友也將獲得 1 GB 的免費儲存空間。', + confirm: '確認', + confirm_2fa_setup: '我已將驗證碼新增到我的驗證器應用程式中', + confirm_2fa_recovery: '我已將我的恢復碼儲存在安全的位置', + confirm_account_for_free_referral_storage_c2a: '建立帳戶並確認您的電子郵件地址,即可獲得 1 GB 的免費儲存空間。您的朋友也會獲得 1 GB 的免費儲存空間。', + confirm_code_generic_incorrect: "驗證碼不正確。", + confirm_code_generic_too_many_requests: "請求次數過多。請稍等幾分鐘。", + confirm_code_generic_submit: "提交驗證碼", + confirm_code_generic_try_again: "再試一次", + confirm_code_generic_title: "輸入確認碼", + confirm_code_2fa_instruction: "輸入您的驗證器應用程式中的 6 位數驗證碼。", + confirm_code_2fa_submit_btn: "提交", + confirm_code_2fa_title: "輸入雙重驗證碼", confirm_delete_multiple_items: '您確定要永久刪除這些項目嗎?', - confirm_delete_single_item: '您確定要永久刪除此項目嗎?', + confirm_delete_single_item: '您要永久刪除此項目嗎?', confirm_open_apps_log_out: '您有開啟的應用程式。您確定要登出嗎?', confirm_new_password: "確認新密碼", - confirm_delete_user: "您確定要刪除您的帳號嗎?您的所有檔案和資料將被永久刪除。此操作無法復原。", - confirm_delete_user_title: "刪除帳號?", + confirm_delete_user: "您確定要刪除您的帳戶嗎?所有您的檔案和資料將被永久刪除。此操作無法撤銷。", + confirm_delete_user_title: "刪除帳戶?", + confirm_session_revoke: "您確定要撤銷此工作階段嗎?", + confirm_your_email_address: "確認您的電子郵件地址", contact_us: "聯絡我們", + contact_us_verification_required: "您必須有一個已驗證的電子郵件地址才能使用此功能。", contain: '包含', continue: "繼續", copy: '複製', copy_link: "複製連結", copying: "正在複製", + copying_file: "正在複製 %%", cover: '覆蓋', - create_account: "建立帳號", - create_free_account: "建立免費帳號", + create_account: "建立帳戶", + create_free_account: "建立免費帳戶", create_shortcut: "建立捷徑", - credits: "鳴謝", - current_password: "目前的密碼", + credits: "製作群", + current_password: "目前密碼", cut: '剪下', clock: "時鐘", - clock_visible_hide: '隱藏 - 總是隱藏', - clock_visible_show: '顯示 - 總是顯示', + clock_visible_hide: '隱藏 - 始終隱藏', + clock_visible_show: '顯示 - 始終可見', clock_visible_auto: '自動 - 預設,僅在全螢幕模式下可見。', + close_all: '全部關閉', + created: '已建立', date_modified: '修改日期', + default: '預設', delete: '刪除', - delete_account: "刪除帳號", + delete_account: "刪除帳戶", delete_permanently: "永久刪除", + deleting_file: "正在刪除 %%", deploy_as_app: '部署為應用程式', descending: '降序', + desktop: '桌面', desktop_background_fit: "適應", developers: "開發者", dir_published_as_website: `%strong% 已發布到:`, - disassociate_dir: "取消關聯目錄", + disable_2fa: '停用雙重驗證', + disable_2fa_confirm: "您確定要停用雙重驗證嗎?", + disable_2fa_instructions: "輸入您的密碼以停用雙重驗證。", + disassociate_dir: "解除關聯目錄", + documents: '文件', + dont_allow: '不允許', download: '下載', download_file: '下載檔案', downloading: "正在下載", email: "電子郵件", + email_change_confirmation_sent: "確認電子郵件已發送到您的新電子郵件地址。請查看您的收件匣並按照指示完成此過程。", + email_invalid: '電子郵件無效。', email_or_username: "電子郵件或使用者名稱", + email_required: '電子郵件是必填的。', empty_trash: '清空垃圾桶', empty_trash_confirmation: `您確定要永久刪除垃圾桶中的項目嗎?`, emptying_trash: '正在清空垃圾桶…', - enter_password_to_confirm_delete_user: "輸入您的密碼以確認刪除帳號", - feedback: "回饋", - feedback_c2a: "請使用下面的表單向我們傳送您的回饋、評論和錯誤報告。", - feedback_sent_confirmation: "感謝您聯絡我們。如果您的帳號有關聯的電子郵件,我們將盡快回覆您。", + enable_2fa: '啟用雙重驗證', + end_hard: "強制結束", + end_process_force_confirm: "您確定要強制結束此程序嗎?", + end_soft: "正常結束", + enlarged_qr_code: "放大的 QR 碼", + enter_password_to_confirm_delete_user: "輸入您的密碼以確認刪除帳戶", + error_message_is_missing: "錯誤訊息缺失。", + error_unknown_cause: "發生未知錯誤。", + error_uploading_files: "上傳檔案失敗", + favorites: "收藏", + feedback: "意見回饋", + feedback_c2a: "請使用以下表單向我們發送您的意見、評論和錯誤報告。", + feedback_sent_confirmation: "感謝您聯絡我們。如果您的帳戶有關聯的電子郵件,我們將盡快回覆您。", fit: "適應", + folder: '資料夾', + force_quit: '強制退出', forgot_pass_c2a: "忘記密碼?", - from: "從", + from: "來自", general: "一般", - get_a_copy_of_on_puter: `在 Puter.com 上取得 '%%' 的副本!`, - get_copy_link: '取得複製連結', + get_a_copy_of_on_puter: `在 Puter.com 上獲取 '%%' 的副本!`, + get_copy_link: '獲取副本連結', hide_all_windows: "隱藏所有視窗", + home: '首頁', html_document: 'HTML 文件', + hue: '色相', image: '圖片', - incorrect_password: "密碼錯誤", + incorrect_password: "密碼不正確", invite_link: "邀請連結", item: '項目', items_in_trash_cannot_be_renamed: `此項目無法重新命名,因為它在垃圾桶中。要重新命名此項目,請先將其從垃圾桶中拖出。`, jpeg_image: 'JPEG 圖片', keep_in_taskbar: '保留在工作列', language: "語言", - license: "許可證", + license: "授權", lightness: '亮度', + link_copied: "連結已複製", loading: '載入中', log_in: "登入", - log_into_another_account_anyway: '無論如何都要登入另一個帳號', + log_into_another_account_anyway: '仍然登入另一個帳戶', log_out: '登出', + looks_good: "看起來不錯!", + manage_sessions: "管理工作階段", + menubar_style: "選單列樣式", + menubar_style_desktop: "桌面", + menubar_style_system: "系統", + menubar_style_window: "視窗", + modified: '已修改', move: '移動', moving_file: "正在移動 %%", my_websites: "我的網站", name: '名稱', name_cannot_be_empty: '名稱不能為空。', - name_cannot_contain_double_period: "名稱不能為 '..' 字元。", - name_cannot_contain_period: "名稱不能為 '.' 字元。", - name_cannot_contain_slash: "名稱不能包含 '/' 字元。", + name_cannot_contain_double_period: "名稱不能是 '..' 字符。", + name_cannot_contain_period: "名稱不能是 '.' 字符。", + name_cannot_contain_slash: "名稱不能包含 '/' 字符。", name_must_be_string: "名稱只能是字串。", - name_too_long: `名稱不能超過 %% 個字元。`, - new: '新建', + name_too_long: `名稱不能超過 %% 個字符。`, + new: '新增', + new_email: '新電子郵件', new_folder: '新資料夾', new_password: "新密碼", new_username: "新使用者名稱", no: '否', - no_dir_associated_with_site: '此地址沒有關聯的目錄。', - no_websites_published: "您尚未發布任何網站。", + no_dir_associated_with_site: '沒有與此地址關聯的目錄。', + no_websites_published: "您還沒有發布任何網站。右鍵點擊資料夾以開始。", ok: '確定', open: "開啟", - open_in_new_tab: "在新標籤頁中開啟", + open_in_new_tab: "在新分頁中開啟", open_in_new_window: "在新視窗中開啟", open_with: "開啟方式", + original_name: '原始名稱', + original_path: '原始路徑', oss_code_and_content: "開源軟體和內容", password: "密碼", password_changed: "密碼已更改。", - passwords_do_not_match: '`新密碼` 和 `確認新密碼` 不符。', + password_recovery_rate_limit: "您已達到我們的速率限制;請稍等幾分鐘。為了避免將來發生這種情況,請避免過於頻繁地重新載入頁面。", + password_recovery_token_invalid: "此密碼恢復令牌已不再有效。", + password_recovery_unknown_error: "發生未知錯誤。請稍後再試。", + password_required: '密碼是必填的。', + password_strength_error: "密碼必須至少 8 個字符長,並且包含至少一個大寫字母、一個小寫字母、一個數字和一個特殊字符。", + passwords_do_not_match: '`新密碼`和`確認新密碼`不匹配。', paste: '貼上', - paste_into_folder: "貼入資料夾", + paste_into_folder: "貼上到資料夾", + path: '路徑', personalization: "個人化", pick_name_for_website: "為您的網站選擇一個名稱:", picture: "圖片", + pictures: '圖片', plural_suffix: '個', - powered_by_puter_js: `由 {{link=docs}}Puter.js{{/link}} 提供技術支援`, + powered_by_puter_js: `由 {{link=docs}}Puter.js{{/link}} 提供支援`, preparing: "準備中...", preparing_for_upload: "準備上傳...", - privacy: "隱私", + print: '列印', + privacy: "隱私權", proceed_to_login: '繼續登入', - proceed_with_account_deletion: "繼續刪除帳號", + proceed_with_account_deletion: "繼續刪除帳戶", + process_status_initializing: "初始化中", + process_status_running: "運行中", + process_type_app: '應用程式', + process_type_init: '初始化', + process_type_ui: '使用者介面', properties: "屬性", + public: '公開', publish: "發布", publish_as_website: '發布為網站', - puter_description: `Puter 是一個以隱私為首的個人雲端,將您的所有檔案、應用程式和遊戲保留在一個 - 安全的地方,隨時隨地都可以存取。`, + puter_description: `Puter 是一個以隱私為先的個人雲端,可將您所有的檔案、應用程式和遊戲保存在一個安全的地方,隨時隨地都能存取。`, + reading_file: "正在讀取 %strong%", recent: "最近", - recover_password: "找回密碼", - refer_friends_c2a: "每推薦一位朋友在 Puter 上建立並確認帳號,您就可以獲得 1 GB 的儲存空間。您的朋友也會獲得 1 GB 的儲存空間!", - refer_friends_social_media_c2a: `在 Puter.com 上獲得 1 GB 的免費儲存空間!`, + recommended: "推薦", + recover_password: "恢復密碼", + refer_friends_c2a: "每邀請一位朋友在 Puter 上建立並確認帳戶,您就可獲得 1 GB 空間。您的朋友也會獲得 1 GB!", + refer_friends_social_media_c2a: `在 Puter.com 上獲得 1 GB 免費儲存空間!`, refresh: '重新整理', release_address_confirmation: `您確定要釋放此地址嗎?`, remove_from_taskbar:'從工作列移除', @@ -167,60 +238,113 @@ const zhtw = { repeat: '重複', replace: '取代', replace_all: '全部取代', - resend_confirmation_code: "重新傳送確認碼", - reset_colors: "重設顏色", - restore: "還原", - saturation: '飽和度', - save_account: '儲存帳號', - save_account_to_get_copy_link: "請建立帳號以繼續。", - save_account_to_publish: '請建立帳號以繼續。', - save_session: '儲存工作階段', - save_session_c2a: '建立帳號以儲存您目前的工作階段,避免遺失您的工作。', - scan_qr_c2a: '掃描下方的 QR Code,從其他裝置登入此工作階段', - select: "選擇", - selected: '已選擇', - select_color: '選擇顏色…', - send: "傳送", - send_password_recovery_email: "傳送密碼恢復電子郵件", - session_saved: "感謝您建立帳號。此工作階段已儲存。", - settings: "設定", - set_new_password: "設定新密碼", - share_to: "分享到", - show_all_windows: "顯示所有視窗", - show_hidden: '顯示隱藏項目', - sign_in_with_puter: "使用 Puter 登入", - sign_up: "註冊", - signing_in: "正在登入…", - size: '大小', - skip: '跳過', - sort_by: '排序方式', - start: '開始', - status: "狀態", - storage_usage: "儲存空間使用情況", - taking_longer_than_usual: '花費的時間比預期的還長。請稍候...', - terms: "條款", - text_document: '文字文件', - tos_fineprint: `點選 '建立免費帳號' 即表示您同意 Puter 的 {{link=terms}}服務條款{{/link}} 和 {{link=privacy}}隱私政策{{/link}}。`, - transparency: "透明度", - trash: '垃圾桶', - type: '類型', - type_confirm_to_delete_account: "輸入 'confirm' 以刪除您的帳號。", - ui_colors: "UI 顏色", - undo: '復原', - unlimited: '無限', - unzip: "解壓縮", - upload: '上傳', - upload_here: '在此上傳', - usage: '使用情況', - username: "使用者名稱", - username_changed: '使用者名稱已成功更新。', - versions: "版本", - visibility: '可視性', - yes: '是', - yes_release_it: '是的,釋放它', - you_have_been_referred_to_puter_by_a_friend: "您的朋友推薦您使用 Puter!", - zip: "壓縮", - storage_puter_used: "由 Puter 使用", + resend_confirmation_code: "重新發送確認碼", + reset_colors: "重設顏色", + restart_puter_confirm: "您確定要重新啟動 Puter 嗎?", + restore: "還原", + save: '儲存', + saturation: '飽和度', + save_account: '儲存帳戶', + save_account_to_get_copy_link: "請建立帳戶以繼續。", + save_account_to_publish: '請建立帳戶以繼續。', + save_session: '儲存工作階段', + save_session_c2a: '建立帳戶以儲存您目前的工作階段並避免失去您的工作。', + scan_qr_c2a: '掃描下方的代碼\n以從其他裝置登入此工作階段', + scan_qr_2fa: '使用您的驗證器應用程式掃描 QR 碼', + scan_qr_generic: '使用您的手機或其他裝置掃描此 QR 碼', + search: '搜尋', + seconds: '秒', + security: "安全性", + select: "選擇", + selected: '已選擇', + select_color: '選擇顏色…', + sessions: "工作階段", + send: "發送", + send_password_recovery_email: "發送密碼恢復電子郵件", + session_saved: "感謝您建立帳戶。此工作階段已儲存。", + settings: "設定", + set_new_password: "設定新密碼", + share: "分享", + share_to: "分享到", + share_with: "分享給:", + shortcut_to: "捷徑到", + show_all_windows: "顯示所有視窗", + show_hidden: '顯示隱藏項目', + sign_in_with_puter: "使用 Puter 登入", + sign_up: "註冊", + signing_in: "正在登入…", + size: '大小', + skip: '跳過', + something_went_wrong: "發生了一些錯誤。", + sort_by: '排序依據', + start: '開始', + status: "狀態", + storage_usage: "儲存空間使用量", + storage_puter_used: '由 Puter 使用', + taking_longer_than_usual: '正在花費比平常更長的時間。請稍候...', + task_manager: "工作管理員", + taskmgr_header_name: "名稱", + taskmgr_header_status: "狀態", + taskmgr_header_type: "類型", + terms: "條款", + text_document: '文字文件', + tos_fineprint: 點擊「建立免費帳戶」即表示您同意 Puter 的{{link=terms}}服務條款{{/link}}和{{link=privacy}}隱私政策{{/link}}。, + transparency: "透明度", + trash: '垃圾桶', + two_factor: '雙重驗證', + two_factor_disabled: '雙重驗證已停用', + two_factor_enabled: '雙重驗證已啟用', + type: '類型', + type_confirm_to_delete_account: "輸入「confirm」以刪除您的帳戶。", + ui_colors: "使用者介面顏色", + ui_manage_sessions: "工作階段管理器", + ui_revoke: "撤銷", + undo: '復原', + unlimited: '無限制', + unzip: "解壓縮", + upload: '上傳', + upload_here: '上傳到這裡', + usage: '使用量', + username: "使用者名稱", + username_changed: '使用者名稱更新成功。', + username_required: '使用者名稱是必填的。', + versions: "版本", + videos: '影片', + visibility: '可見性', + yes: '是', + yes_release_it: '是的,釋放它', + you_have_been_referred_to_puter_by_a_friend: "您已被朋友推薦到 Puter!", + zip: "壓縮", + zipping_file: "正在壓縮 %strong%", + + // === 2FA Setup === + setup2fa_1_step_heading: '開啟您的驗證器應用程式', + setup2fa_1_instructions: ` + 您可以使用任何支援基於時間的一次性密碼(TOTP)協議的驗證器應用程式。 + 有許多選擇,但如果您不確定, + Authy + 是 Android 和 iOS 的一個不錯的選擇。 + `, + setup2fa_2_step_heading: '掃描 QR 碼', + setup2fa_3_step_heading: '輸入 6 位數驗證碼', + setup2fa_4_step_heading: '複製您的恢復碼', + setup2fa_4_instructions: ` + 如果您遺失手機或無法使用驗證器應用程式,這些恢復碼是存取您帳戶的唯一方法。 + 請確保將它們儲存在安全的地方。 + `, + setup2fa_5_step_heading: '確認雙重驗證設置', + setup2fa_5_confirmation_1: '我已將恢復碼儲存在安全的位置', + setup2fa_5_confirmation_2: '我已準備好啟用雙重驗證', + setup2fa_5_button: '啟用雙重驗證', + + // === 2FA Login === + login2fa_otp_title: '輸入雙重驗證碼', + login2fa_otp_instructions: '輸入您驗證器應用程式中的 6 位數驗證碼。', + login2fa_recovery_title: '輸入恢復碼', + login2fa_recovery_instructions: '輸入您的其中一個恢復碼以存取您的帳戶。', + login2fa_use_recovery_code: '使用恢復碼', + login2fa_recovery_back: '返回', + login2fa_recovery_placeholder: 'XXXXXXXX', } }; From 3a09e84838fe8b74bd050641620eec87d9f59dfc Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sat, 20 Jul 2024 08:05:14 -0700 Subject: [PATCH 0576/2119] fix: syntax error and formatting issue --- src/gui/src/i18n/translations/zhtw.js | 194 +++++++++++++------------- 1 file changed, 97 insertions(+), 97 deletions(-) diff --git a/src/gui/src/i18n/translations/zhtw.js b/src/gui/src/i18n/translations/zhtw.js index dbc8dd5b13..9dc5165047 100644 --- a/src/gui/src/i18n/translations/zhtw.js +++ b/src/gui/src/i18n/translations/zhtw.js @@ -233,118 +233,118 @@ const zhtw = { refer_friends_social_media_c2a: `在 Puter.com 上獲得 1 GB 免費儲存空間!`, refresh: '重新整理', release_address_confirmation: `您確定要釋放此地址嗎?`, - remove_from_taskbar:'從工作列移除', + remove_from_taskbar: '從工作列移除', rename: '重新命名', repeat: '重複', replace: '取代', replace_all: '全部取代', resend_confirmation_code: "重新發送確認碼", - reset_colors: "重設顏色", - restart_puter_confirm: "您確定要重新啟動 Puter 嗎?", - restore: "還原", - save: '儲存', - saturation: '飽和度', - save_account: '儲存帳戶', - save_account_to_get_copy_link: "請建立帳戶以繼續。", - save_account_to_publish: '請建立帳戶以繼續。', - save_session: '儲存工作階段', - save_session_c2a: '建立帳戶以儲存您目前的工作階段並避免失去您的工作。', - scan_qr_c2a: '掃描下方的代碼\n以從其他裝置登入此工作階段', - scan_qr_2fa: '使用您的驗證器應用程式掃描 QR 碼', - scan_qr_generic: '使用您的手機或其他裝置掃描此 QR 碼', - search: '搜尋', - seconds: '秒', - security: "安全性", - select: "選擇", - selected: '已選擇', - select_color: '選擇顏色…', - sessions: "工作階段", - send: "發送", - send_password_recovery_email: "發送密碼恢復電子郵件", - session_saved: "感謝您建立帳戶。此工作階段已儲存。", - settings: "設定", - set_new_password: "設定新密碼", - share: "分享", - share_to: "分享到", - share_with: "分享給:", - shortcut_to: "捷徑到", - show_all_windows: "顯示所有視窗", - show_hidden: '顯示隱藏項目', - sign_in_with_puter: "使用 Puter 登入", - sign_up: "註冊", - signing_in: "正在登入…", - size: '大小', - skip: '跳過', - something_went_wrong: "發生了一些錯誤。", - sort_by: '排序依據', - start: '開始', - status: "狀態", - storage_usage: "儲存空間使用量", - storage_puter_used: '由 Puter 使用', - taking_longer_than_usual: '正在花費比平常更長的時間。請稍候...', - task_manager: "工作管理員", - taskmgr_header_name: "名稱", - taskmgr_header_status: "狀態", - taskmgr_header_type: "類型", - terms: "條款", - text_document: '文字文件', - tos_fineprint: 點擊「建立免費帳戶」即表示您同意 Puter 的{{link=terms}}服務條款{{/link}}和{{link=privacy}}隱私政策{{/link}}。, - transparency: "透明度", - trash: '垃圾桶', - two_factor: '雙重驗證', - two_factor_disabled: '雙重驗證已停用', - two_factor_enabled: '雙重驗證已啟用', - type: '類型', - type_confirm_to_delete_account: "輸入「confirm」以刪除您的帳戶。", - ui_colors: "使用者介面顏色", - ui_manage_sessions: "工作階段管理器", - ui_revoke: "撤銷", - undo: '復原', - unlimited: '無限制', - unzip: "解壓縮", - upload: '上傳', - upload_here: '上傳到這裡', - usage: '使用量', - username: "使用者名稱", - username_changed: '使用者名稱更新成功。', - username_required: '使用者名稱是必填的。', - versions: "版本", - videos: '影片', - visibility: '可見性', - yes: '是', - yes_release_it: '是的,釋放它', - you_have_been_referred_to_puter_by_a_friend: "您已被朋友推薦到 Puter!", - zip: "壓縮", - zipping_file: "正在壓縮 %strong%", + reset_colors: "重設顏色", + restart_puter_confirm: "您確定要重新啟動 Puter 嗎?", + restore: "還原", + save: '儲存', + saturation: '飽和度', + save_account: '儲存帳戶', + save_account_to_get_copy_link: "請建立帳戶以繼續。", + save_account_to_publish: '請建立帳戶以繼續。', + save_session: '儲存工作階段', + save_session_c2a: '建立帳戶以儲存您目前的工作階段並避免失去您的工作。', + scan_qr_c2a: '掃描下方的代碼\n以從其他裝置登入此工作階段', + scan_qr_2fa: '使用您的驗證器應用程式掃描 QR 碼', + scan_qr_generic: '使用您的手機或其他裝置掃描此 QR 碼', + search: '搜尋', + seconds: '秒', + security: "安全性", + select: "選擇", + selected: '已選擇', + select_color: '選擇顏色…', + sessions: "工作階段", + send: "發送", + send_password_recovery_email: "發送密碼恢復電子郵件", + session_saved: "感謝您建立帳戶。此工作階段已儲存。", + settings: "設定", + set_new_password: "設定新密碼", + share: "分享", + share_to: "分享到", + share_with: "分享給:", + shortcut_to: "捷徑到", + show_all_windows: "顯示所有視窗", + show_hidden: '顯示隱藏項目', + sign_in_with_puter: "使用 Puter 登入", + sign_up: "註冊", + signing_in: "正在登入…", + size: '大小', + skip: '跳過', + something_went_wrong: "發生了一些錯誤。", + sort_by: '排序依據', + start: '開始', + status: "狀態", + storage_usage: "儲存空間使用量", + storage_puter_used: '由 Puter 使用', + taking_longer_than_usual: '正在花費比平常更長的時間。請稍候...', + task_manager: "工作管理員", + taskmgr_header_name: "名稱", + taskmgr_header_status: "狀態", + taskmgr_header_type: "類型", + terms: "條款", + text_document: '文字文件', + tos_fineprint: `點擊「建立免費帳戶」即表示您同意 Puter 的{{link=terms}}服務條款{{/link}}和{{link=privacy}}隱私政策{{/link}}`, + transparency: "透明度", + trash: '垃圾桶', + two_factor: '雙重驗證', + two_factor_disabled: '雙重驗證已停用', + two_factor_enabled: '雙重驗證已啟用', + type: '類型', + type_confirm_to_delete_account: "輸入「confirm」以刪除您的帳戶。", + ui_colors: "使用者介面顏色", + ui_manage_sessions: "工作階段管理器", + ui_revoke: "撤銷", + undo: '復原', + unlimited: '無限制', + unzip: "解壓縮", + upload: '上傳', + upload_here: '上傳到這裡', + usage: '使用量', + username: "使用者名稱", + username_changed: '使用者名稱更新成功。', + username_required: '使用者名稱是必填的。', + versions: "版本", + videos: '影片', + visibility: '可見性', + yes: '是', + yes_release_it: '是的,釋放它', + you_have_been_referred_to_puter_by_a_friend: "您已被朋友推薦到 Puter!", + zip: "壓縮", + zipping_file: "正在壓縮 %strong%", - // === 2FA Setup === - setup2fa_1_step_heading: '開啟您的驗證器應用程式', - setup2fa_1_instructions: ` + // === 2FA Setup === + setup2fa_1_step_heading: '開啟您的驗證器應用程式', + setup2fa_1_instructions: ` 您可以使用任何支援基於時間的一次性密碼(TOTP)協議的驗證器應用程式。 有許多選擇,但如果您不確定, Authy 是 Android 和 iOS 的一個不錯的選擇。 `, - setup2fa_2_step_heading: '掃描 QR 碼', - setup2fa_3_step_heading: '輸入 6 位數驗證碼', - setup2fa_4_step_heading: '複製您的恢復碼', - setup2fa_4_instructions: ` + setup2fa_2_step_heading: '掃描 QR 碼', + setup2fa_3_step_heading: '輸入 6 位數驗證碼', + setup2fa_4_step_heading: '複製您的恢復碼', + setup2fa_4_instructions: ` 如果您遺失手機或無法使用驗證器應用程式,這些恢復碼是存取您帳戶的唯一方法。 請確保將它們儲存在安全的地方。 `, - setup2fa_5_step_heading: '確認雙重驗證設置', - setup2fa_5_confirmation_1: '我已將恢復碼儲存在安全的位置', - setup2fa_5_confirmation_2: '我已準備好啟用雙重驗證', - setup2fa_5_button: '啟用雙重驗證', + setup2fa_5_step_heading: '確認雙重驗證設置', + setup2fa_5_confirmation_1: '我已將恢復碼儲存在安全的位置', + setup2fa_5_confirmation_2: '我已準備好啟用雙重驗證', + setup2fa_5_button: '啟用雙重驗證', - // === 2FA Login === - login2fa_otp_title: '輸入雙重驗證碼', - login2fa_otp_instructions: '輸入您驗證器應用程式中的 6 位數驗證碼。', - login2fa_recovery_title: '輸入恢復碼', - login2fa_recovery_instructions: '輸入您的其中一個恢復碼以存取您的帳戶。', - login2fa_use_recovery_code: '使用恢復碼', - login2fa_recovery_back: '返回', - login2fa_recovery_placeholder: 'XXXXXXXX', + // === 2FA Login === + login2fa_otp_title: '輸入雙重驗證碼', + login2fa_otp_instructions: '輸入您驗證器應用程式中的 6 位數驗證碼。', + login2fa_recovery_title: '輸入恢復碼', + login2fa_recovery_instructions: '輸入您的其中一個恢復碼以存取您的帳戶。', + login2fa_use_recovery_code: '使用恢復碼', + login2fa_recovery_back: '返回', + login2fa_recovery_placeholder: 'XXXXXXXX', } }; From b3c1b128e2d8519bc816cdcd3220c8f40e05bb01 Mon Sep 17 00:00:00 2001 From: Christian Neff Date: Sat, 20 Jul 2024 18:09:37 +0200 Subject: [PATCH 0577/2119] Add issue template for app ideas --- .github/ISSUE_TEMPLATE/app_idea.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/app_idea.md diff --git a/.github/ISSUE_TEMPLATE/app_idea.md b/.github/ISSUE_TEMPLATE/app_idea.md new file mode 100644 index 0000000000..5ac79428b0 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/app_idea.md @@ -0,0 +1,12 @@ +--- +name: App idea +about: Suggest a potential app for Puter +title: '' +labels: + - idea + - app +assignees: '' + +--- + + From fe63839bbbc44abee0606353270d2df232a611a4 Mon Sep 17 00:00:00 2001 From: Christian Neff Date: Sat, 20 Jul 2024 19:38:22 +0200 Subject: [PATCH 0578/2119] Add issue template for meta suggestions --- .github/ISSUE_TEMPLATE/meta.md | 12 ++++++++++++ 1 file changed, 12 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/meta.md diff --git a/.github/ISSUE_TEMPLATE/meta.md b/.github/ISSUE_TEMPLATE/meta.md new file mode 100644 index 0000000000..ac68debee1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/meta.md @@ -0,0 +1,12 @@ +--- +name: Meta suggestion +about: Suggest an idea for the ecosystem around Puter, its "health" files, or other meta files +title: '' +labels: + - idea + - meta +assignees: '' + +--- + + From 452b7495b1736df90bc748dbf818407488875754 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sat, 20 Jul 2024 11:46:20 -0700 Subject: [PATCH 0579/2119] use `app-request` as label for `app idea` issues --- .github/ISSUE_TEMPLATE/app_idea.md | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/app_idea.md b/.github/ISSUE_TEMPLATE/app_idea.md index 5ac79428b0..ffc016b489 100644 --- a/.github/ISSUE_TEMPLATE/app_idea.md +++ b/.github/ISSUE_TEMPLATE/app_idea.md @@ -3,8 +3,7 @@ name: App idea about: Suggest a potential app for Puter title: '' labels: - - idea - - app + - app-request assignees: '' --- From 71f4b4d71fa697489b1c3580c0945bef50ba9b75 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sat, 20 Jul 2024 13:34:36 -0700 Subject: [PATCH 0580/2119] When setting size/position of app window make sure it's not an empty string --- src/gui/src/helpers/launch_app.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gui/src/helpers/launch_app.js b/src/gui/src/helpers/launch_app.js index 607d9a30b0..940b6d0b13 100644 --- a/src/gui/src/helpers/launch_app.js +++ b/src/gui/src/helpers/launch_app.js @@ -266,28 +266,28 @@ const launch_app = async (options)=>{ // width let window_width; - if(app_info.metadata?.window_size?.width !== undefined) + if(app_info.metadata?.window_size?.width !== undefined && app_info.metadata?.window_size?.width !== '') window_width = parseFloat(app_info.metadata.window_size.width); if(options.maximized) window_width = '100%'; // height let window_height; - if(app_info.metadata?.window_size?.height !== undefined){ + if(app_info.metadata?.window_size?.height !== undefined && app_info.metadata?.window_size?.height !== ''){ window_height = parseFloat(app_info.metadata.window_size.height); }if(options.maximized) window_height = `calc(100% - ${window.taskbar_height + window.toolbar_height + 1}px)`; // top let top; - if(app_info.metadata?.window_position?.top !== undefined) + if(app_info.metadata?.window_position?.top !== undefined && app_info.metadata?.window_position?.top !== '') top = parseFloat(app_info.metadata.window_position.top) + window.toolbar_height + 1; if(options.maximized) top = 0; // left let left; - if(app_info.metadata?.window_position?.left !== undefined) + if(app_info.metadata?.window_position?.left !== undefined && app_info.metadata?.window_position?.left !== '') left = parseFloat(app_info.metadata.window_position.left); if(options.maximized) left = 0; From c2d3d69dbe33f36fcae13bcbc8e2a31a86025af9 Mon Sep 17 00:00:00 2001 From: pvhuwung Date: Sun, 21 Jul 2024 03:53:14 +0700 Subject: [PATCH 0581/2119] feat: add vietnamese localization-a --- src/gui/src/i18n/translations/translations.js | 2 + src/gui/src/i18n/translations/vi.js | 352 ++++++++++++++++++ 2 files changed, 354 insertions(+) create mode 100644 src/gui/src/i18n/translations/vi.js diff --git a/src/gui/src/i18n/translations/translations.js b/src/gui/src/i18n/translations/translations.js index debc5a3076..6e8ba73625 100644 --- a/src/gui/src/i18n/translations/translations.js +++ b/src/gui/src/i18n/translations/translations.js @@ -49,6 +49,7 @@ import ua from './ua.js'; import zh from './zh.js'; import hu from './hu.js'; import zhtw from './zhtw.js'; +import vi from "./vi.js"; import emoji from './emoji.js'; @@ -86,5 +87,6 @@ export default { hu, zhtw, ur, + vi, emoji, }; diff --git a/src/gui/src/i18n/translations/vi.js b/src/gui/src/i18n/translations/vi.js new file mode 100644 index 0000000000..55283ca669 --- /dev/null +++ b/src/gui/src/i18n/translations/vi.js @@ -0,0 +1,352 @@ +/** + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ + + +const vi = { + name: "Tiếng Việt", + english_name: "Vietnamese", + code: "vi", + dictionary: { + about: "Giới thiệu", + account: "Tài khoản", + account_password: "Xác minh mật khẩu tài khoản", + access_granted_to: "Đã cấp quyền truy cập cho", + add_existing_account: "Thêm tài khoản hiện có", + all_fields_required: 'Tất cả các trường đều bắt buộc.', + allow: 'Cho phép', + apply: "Áp dụng", + ascending: 'Tăng dần', + associated_websites: "Các trang web liên kết", + auto_arrange: 'Tự động sắp xếp', + background: "Nền", + browse: "Duyệt", + cancel: 'Hủy', + center: 'Giữa', + change_desktop_background: 'Thay đổi hình nền màn hình…', + change_email: "Thay đổi email", + change_language: "Thay đổi ngôn ngữ", + change_password: "Thay đổi mật khẩu", + change_ui_colors: "Thay đổi màu sắc giao diện", + change_username: "Thay đổi tên người dùng", + close: 'Đóng', + close_all_windows: "Đóng tất cả cửa sổ", + close_all_windows_confirm: "Bạn có chắc chắn muốn đóng tất cả cửa sổ không?", + close_all_windows_and_log_out: 'Đóng cửa sổ và đăng xuất', + change_always_open_with: "Bạn có muốn luôn mở loại tệp này bằng", + color: 'Màu sắc', + confirm: 'Xác nhận', + confirm_2fa_setup: 'Tôi đã thêm mã vào ứng dụng xác thực của mình', + confirm_2fa_recovery: 'Tôi đã lưu mã khôi phục của mình ở một nơi an toàn', + confirm_account_for_free_referral_storage_c2a: 'Tạo tài khoản và xác nhận địa chỉ email của bạn để nhận 1 GB dung lượng lưu trữ miễn phí. Bạn của bạn cũng sẽ nhận được 1 GB dung lượng lưu trữ miễn phí.', + confirm_code_generic_incorrect: "Mã không chính xác.", + confirm_code_generic_too_many_requests: "Quá nhiều yêu cầu. Vui lòng đợi vài phút.", + confirm_code_generic_submit: "Gửi mã", + confirm_code_generic_try_again: "Thử lại", + confirm_code_generic_title: "Nhập mã xác nhận", + confirm_code_2fa_instruction: "Nhập mã 6 chữ số từ ứng dụng xác thực của bạn.", + confirm_code_2fa_submit_btn: "Gửi", + confirm_code_2fa_title: "Nhập mã 2FA", + confirm_delete_multiple_items: 'Bạn có chắc chắn muốn xóa vĩnh viễn những mục này không?', + confirm_delete_single_item: 'Bạn có muốn xóa vĩnh viễn mục này không?', + confirm_open_apps_log_out: 'Bạn có ứng dụng đang mở. Bạn có chắc chắn muốn đăng xuất không?', + confirm_new_password: "Xác nhận mật khẩu mới", + confirm_delete_user: "Bạn có chắc chắn muốn xóa tài khoản của mình không? Tất cả các tệp và dữ liệu của bạn sẽ bị xóa vĩnh viễn. Hành động này không thể hoàn tác.", + confirm_delete_user_title: "Xóa tài khoản?", + confirm_session_revoke: "Bạn có chắc chắn muốn thu hồi phiên này không?", + confirm_your_email_address: "Xác nhận địa chỉ email của bạn", + contact_us: "Liên hệ chúng tôi", + contact_us_verification_required: "Bạn phải có địa chỉ email đã xác minh để sử dụng tính năng này.", + contain: 'Chứa', + continue: "Tiếp tục", + copy: 'Sao chép', + copy_link: "Sao chép liên kết", + copying: "Đang sao chép", + copying_file: "Đang sao chép %%", + cover: 'Che phủ', + create_account: "Tạo tài khoản", + create_free_account: "Tạo tài khoản miễn phí", + create_shortcut: "Tạo lối tắt", + credits: "Tín dụng", + current_password: "Mật khẩu hiện tại", + cut: 'Cắt', + clock: "Đồng hồ", + clock_visible_hide: 'Ẩn - Luôn ẩn', + clock_visible_show: 'Hiện - Luôn hiển thị', + clock_visible_auto: 'Tự động - Mặc định, chỉ hiển thị ở chế độ toàn màn hình.', + close_all: 'Đóng tất cả', + created: 'Đã tạo', + date_modified: 'Ngày sửa đổi', + default: 'Mặc định', + delete: 'Xóa', + delete_account: "Xóa tài khoản", + delete_permanently: "Xóa vĩnh viễn", + deleting_file: "Đang xóa %%", + deploy_as_app: 'Triển khai như ứng dụng', + descending: 'Giảm dần', + desktop: 'Màn hình chính', + desktop_background_fit: "Vừa khít", + developers: "Nhà phát triển", + dir_published_as_website: `%strong% đã được xuất bản tại:`, + disable_2fa: 'Tắt 2FA', + disable_2fa_confirm: "Bạn có chắc chắn muốn tắt 2FA không?", + disable_2fa_instructions: "Nhập mật khẩu của bạn để tắt 2FA.", + disassociate_dir: "Hủy liên kết thư mục", + documents: 'Tài liệu', + dont_allow: 'Không cho phép', + download: 'Tải xuống', + download_file: 'Tải xuống tệp', + downloading: "Đang tải xuống", + email: "Email", + email_change_confirmation_sent: "Một email xác nhận đã được gửi đến địa chỉ email mới của bạn. Vui lòng kiểm tra hộp thư đến và làm theo hướng dẫn để hoàn tất quy trình.", + email_invalid: 'Email không hợp lệ.', + email_or_username: "Email hoặc tên người dùng", + email_required: 'Email là bắt buộc.', + empty_trash: 'Dọn sạch thùng rác', + empty_trash_confirmation: `Bạn có chắc chắn muốn xóa vĩnh viễn các mục trong Thùng rác không?`, + emptying_trash: 'Đang dọn sạch Thùng rác…', + enable_2fa: 'Bật 2FA', + end_hard: "Kết thúc cứng", + end_process_force_confirm: "Bạn có chắc chắn muốn buộc kết thúc quá trình này không?", + end_soft: "Kết thúc mềm", + enlarged_qr_code: "Mã QR phóng to", + enter_password_to_confirm_delete_user: "Nhập mật khẩu của bạn để xác nhận xóa tài khoản", + error_message_is_missing: "Thiếu thông báo lỗi.", + error_unknown_cause: "Đã xảy ra lỗi không xác định.", + error_uploading_files: "Không thể tải lên tệp", + favorites: "Yêu thích", + feedback: "Phản hồi", + feedback_c2a: "Vui lòng sử dụng biểu mẫu dưới đây để gửi phản hồi, nhận xét và báo cáo lỗi của bạn.", + feedback_sent_confirmation: "Cảm ơn bạn đã liên hệ với chúng tôi. Nếu bạn có email liên kết với tài khoản của mình, chúng tôi sẽ phản hồi bạn trong thời gian sớm nhất.", + fit: "Vừa khít", + folder: 'Thư mục', + force_quit: 'Buộc thoát', + forgot_pass_c2a: "Quên mật khẩu?", + from: "Từ", + general: "Chung", + get_a_copy_of_on_puter: `Nhận một bản sao của '%%' trên Puter.com!`, + get_copy_link: 'Lấy liên kết sao chép', + hide_all_windows: "Ẩn tất cả cửa sổ", + home: 'Trang chủ', + html_document: 'Tài liệu HTML', + hue: 'Màu sắc', + image: 'Hình ảnh', + incorrect_password: "Mật khẩu không chính xác", + invite_link: "Liên kết mời", + item: 'mục', + items_in_trash_cannot_be_renamed: `Mục này không thể đổi tên vì nó đang ở trong thùng rác. Để đổi tên mục này, trước tiên hãy kéo nó ra khỏi Thùng rác.`, + jpeg_image: 'Hình ảnh JPEG', + keep_in_taskbar: 'Giữ trong thanh tác vụ', + language: "Ngôn ngữ", + license: "Giấy phép", + lightness: 'Độ sáng', + link_copied: "Đã sao chép liên kết", + loading: 'Đang tải', + log_in: "Đăng nhập", + log_into_another_account_anyway: 'Vẫn đăng nhập vào tài khoản khác', + log_out: 'Đăng xuất', + looks_good: "Trông tốt!", + manage_sessions: "Quản lý phiên", + menubar_style: "Kiểu thanh menu", + menubar_style_desktop: "Màn hình chính", + menubar_style_system: "Hệ thống", + menubar_style_window: "Cửa sổ", + modified: 'Đã sửa đổi', + move: 'Di chuyển', + moving_file: "Đang di chuyển %%", + my_websites: "Trang web của tôi", + name: 'Tên', + name_cannot_be_empty: 'Tên không thể để trống.', + name_cannot_contain_double_period: "Tên không thể là ký tự '..'.", + name_cannot_contain_period: "Tên không thể là ký tự '.'.", + name_cannot_contain_slash: "Tên không thể chứa ký tự '/'.", + name_must_be_string: "Tên chỉ có thể là chuỗi.", + name_too_long: `Tên không thể dài hơn %% ký tự.`, + new: 'Mới', + new_email: 'Email mới', + new_folder: 'Thư mục mới', + new_password: "Mật khẩu mới", + new_username: "Tên người dùng mới", + no: 'Không', + no_dir_associated_with_site: 'Không có thư mục nào liên kết với địa chỉ này.', + no_websites_published: "Bạn chưa xuất bản trang web nào. Nhấp chuột phải vào một thư mục để bắt đầu.", + ok: 'OK', + open: "Mở", + open_in_new_tab: "Mở trong tab mới", + open_in_new_window: "Mở trong cửa sổ mới", + open_with: "Mở bằng", + original_name: 'Tên gốc', + original_path: 'Đường dẫn gốc', + oss_code_and_content: "Phần mềm mã nguồn mở và nội dung", + password: "Mật khẩu", + password_changed: "Đã thay đổi mật khẩu.", + password_recovery_rate_limit: "Bạn đã đạt đến giới hạn tốc độ của chúng tôi; vui lòng đợi vài phút. Để tránh điều này trong tương lai, hãy tránh tải lại trang quá nhiều lần.", + password_recovery_token_invalid: "Mã khôi phục mật khẩu này không còn hợp lệ.", + password_recovery_unknown_error: "Đã xảy ra lỗi không xác định. Vui lòng thử lại sau.", + password_required: 'Mật khẩu là bắt buộc.', + password_strength_error: "Mật khẩu phải có ít nhất 8 ký tự và chứa ít nhất một chữ cái viết hoa, một chữ cái viết thường, một số và một ký tự đặc biệt.", + passwords_do_not_match: '`Mật khẩu mới` và `Xác nhận mật khẩu mới` không khớp.', + paste: 'Dán', + paste_into_folder: "Dán vào thư mục", + path: 'Đường dẫn', + personalization: "Cá nhân hóa", + pick_name_for_website: "Chọn một tên cho trang web của bạn:", + picture: "Hình ảnh", + pictures: 'Hình ảnh', + plural_suffix: '', + powered_by_puter_js: `Được hỗ trợ bởi {{link=docs}}Puter.js{{/link}}`, + preparing: "Đang chuẩn bị...", + preparing_for_upload: "Đang chuẩn bị để tải lên...", + print: 'In', + privacy: "Quyền riêng tư", + proceed_to_login: 'Tiếp tục đăng nhập', + proceed_with_account_deletion: "Tiếp tục xóa tài khoản", + process_status_initializing: "Đang khởi tạo", + process_status_running: "Đang chạy", + process_type_app: 'Ứng dụng', + process_type_init: 'Khởi tạo', + process_type_ui: 'Giao diện', + properties: "Thuộc tính", + public: 'Công khai', + publish: "Xuất bản", + publish_as_website: 'Xuất bản như trang web', + puter_description: `Puter là một đám mây cá nhân đặt quyền riêng tư lên hàng đầu để lưu trữ tất cả các tệp, ứng dụng và trò chơi của bạn trong một nơi an toàn, có thể truy cập từ mọi nơi vào bất kỳ lúc nào.`, + reading_file: "Đang đọc %strong%", + recent: "Gần đây", + recommended: "Được đề xuất", + recover_password: "Khôi phục mật khẩu", + refer_friends_c2a: "Nhận 1 GB cho mỗi người bạn tạo và xác nhận tài khoản trên Puter. Bạn của bạn cũng sẽ nhận được 1 GB!", + refer_friends_social_media_c2a: `Nhận 1 GB dung lượng lưu trữ miễn phí trên Puter.com!`, + refresh: 'Làm mới', + release_address_confirmation: `Bạn có chắc chắn muốn giải phóng địa chỉ này không?`, + remove_from_taskbar: 'Xóa khỏi thanh tác vụ', + rename: 'Đổi tên', + repeat: 'Lặp lại', + replace: 'Thay thế', + replace_all: 'Thay thế tất cả', + resend_confirmation_code: "Gửi lại mã xác nhận", + reset_colors: "Đặt lại màu sắc", + restart_puter_confirm: "Bạn có chắc chắn muốn khởi động lại Puter không?", + restore: "Khôi phục", + save: 'Lưu', + saturation: 'Độ bão hòa', + save_account: 'Lưu tài khoản', + save_account_to_get_copy_link: "Vui lòng tạo một tài khoản để tiếp tục.", + save_account_to_publish: 'Vui lòng tạo một tài khoản để tiếp tục.', + save_session: 'Lưu phiên', + save_session_c2a: 'Tạo một tài khoản để lưu phiên hiện tại của bạn và tránh mất công việc của bạn.', + scan_qr_c2a: 'Quét mã bên dưới\nđể đăng nhập vào phiên này từ các thiết bị khác', + scan_qr_2fa: 'Quét mã QR bằng ứng dụng xác thực của bạn', + scan_qr_generic: 'Quét mã QR này bằng điện thoại hoặc thiết bị khác của bạn', + search: 'Tìm kiếm', + seconds: 'giây', + security: "Bảo mật", + select: "Chọn", + selected: 'đã chọn', + select_color: 'Chọn màu…', + sessions: "Phiên", + send: "Gửi", + send_password_recovery_email: "Gửi email khôi phục mật khẩu", + session_saved: "Cảm ơn bạn đã tạo tài khoản. Phiên này đã được lưu.", + settings: "Cài đặt", + set_new_password: "Đặt mật khẩu mới", + share: "Chia sẻ", + share_to: "Chia sẻ đến", + share_with: "Chia sẻ với:", + shortcut_to: "Lối tắt đến", + show_all_windows: "Hiển thị tất cả cửa sổ", + show_hidden: 'Hiển thị mục ẩn', + sign_in_with_puter: "Đăng nhập bằng Puter", + sign_up: "Đăng ký", + signing_in: "Đang đăng nhập…", + size: 'Kích thước', + skip: 'Bỏ qua', + something_went_wrong: "Đã xảy ra lỗi.", + sort_by: 'Sắp xếp theo', + start: 'Bắt đầu', + status: "Trạng thái", + storage_usage: "Sử dụng bộ nhớ", + storage_puter_used: 'đã sử dụng bởi Puter', + taking_longer_than_usual: 'Đang mất nhiều thời gian hơn bình thường. Vui lòng đợi...', + task_manager: "Trình quản lý tác vụ", + taskmgr_header_name: "Tên", + taskmgr_header_status: "Trạng thái", + taskmgr_header_type: "Loại", + terms: "Điều khoản", + text_document: 'Tài liệu văn bản', + tos_fineprint: `Bằng cách nhấp vào 'Tạo tài khoản miễn phí', bạn đồng ý với {{link=terms}}Điều khoản dịch vụ{{/link}} và {{link=privacy}}Chính sách quyền riêng tư{{/link}} của Puter.`, + transparency: "Độ trong suốt", + trash: 'Thùng rác', + two_factor: 'Xác thực hai yếu tố', + two_factor_disabled: '2FA đã tắt', + two_factor_enabled: '2FA đã bật', + type: 'Loại', + type_confirm_to_delete_account: "Gõ 'xác nhận' để xóa tài khoản của bạn.", // "Type 'confirm' to delete your account." + ui_colors: "Màu sắc giao diện", + ui_manage_sessions: "Quản lý phiên", + ui_revoke: "Thu hồi", + undo: 'Hoàn tác', + unlimited: 'Không giới hạn', + unzip: "Giải nén", + upload: 'Tải lên', + upload_here: 'Tải lên tại đây', + usage: 'Sử dụng', + username: "Tên người dùng", + username_changed: 'Đã cập nhật tên người dùng thành công.', + username_required: 'Tên người dùng là bắt buộc.', + versions: "Phiên bản", + videos: 'Video', + visibility: 'Hiển thị', + yes: 'Có', + yes_release_it: 'Có, giải phóng nó', + you_have_been_referred_to_puter_by_a_friend: "Bạn đã được giới thiệu đến Puter bởi một người bạn!", + zip: "Nén", + zipping_file: "Đang nén %strong%", + + // === 2FA Setup === + setup2fa_1_step_heading: 'Mở ứng dụng xác thực của bạn', + setup2fa_1_instructions: ` + Bạn có thể sử dụng bất kỳ ứng dụng xác thực nào hỗ trợ giao thức Mật khẩu một lần dựa trên thời gian (TOTP). + Có nhiều lựa chọn, nhưng nếu bạn không chắc chắn + Authy + là một lựa chọn tốt cho Android và iOS. + `, + setup2fa_2_step_heading: 'Quét mã QR', + setup2fa_3_step_heading: 'Nhập mã 6 chữ số', + setup2fa_4_step_heading: 'Sao chép mã khôi phục của bạn', + setup2fa_4_instructions: ` + Những mã khôi phục này là cách duy nhất để truy cập tài khoản của bạn nếu bạn mất điện thoại hoặc không thể sử dụng ứng dụng xác thực. + Hãy đảm bảo lưu trữ chúng ở một nơi an toàn. + `, + setup2fa_5_step_heading: 'Xác nhận thiết lập 2FA', + setup2fa_5_confirmation_1: 'Tôi đã lưu mã khôi phục của mình ở một nơi an toàn', + setup2fa_5_confirmation_2: 'Tôi đã sẵn sàng để bật 2FA', + setup2fa_5_button: 'Bật 2FA', + + // === 2FA Login === + login2fa_otp_title: 'Nhập mã 2FA', + login2fa_otp_instructions: 'Nhập mã 6 chữ số từ ứng dụng xác thực của bạn.', + login2fa_recovery_title: 'Nhập mã khôi phục', + login2fa_recovery_instructions: 'Nhập một trong các mã khôi phục của bạn để truy cập tài khoản.', + login2fa_use_recovery_code: 'Sử dụng mã khôi phục', + login2fa_recovery_back: 'Quay lại', + login2fa_recovery_placeholder: 'XXXXXXXX', + } +}; + +export default vi; \ No newline at end of file From 02e1b1e8f5f8e22d7ab39ebff99f7dd8e08a4221 Mon Sep 17 00:00:00 2001 From: pvhuwung Date: Sun, 21 Jul 2024 03:59:01 +0700 Subject: [PATCH 0582/2119] chore: fix confirm for type_confirm_to_delete_account --- src/gui/src/i18n/translations/vi.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/vi.js b/src/gui/src/i18n/translations/vi.js index 55283ca669..a8a0e6c184 100644 --- a/src/gui/src/i18n/translations/vi.js +++ b/src/gui/src/i18n/translations/vi.js @@ -296,7 +296,7 @@ const vi = { two_factor_disabled: '2FA đã tắt', two_factor_enabled: '2FA đã bật', type: 'Loại', - type_confirm_to_delete_account: "Gõ 'xác nhận' để xóa tài khoản của bạn.", // "Type 'confirm' to delete your account." + type_confirm_to_delete_account: "Gõ 'confirm' để xóa tài khoản của bạn.", ui_colors: "Màu sắc giao diện", ui_manage_sessions: "Quản lý phiên", ui_revoke: "Thu hồi", From 2a5cec7ee914c9c97ae90b85464f9fc5332ad2fb Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sat, 20 Jul 2024 18:53:58 -0400 Subject: [PATCH 0583/2119] fix: add necessary iframe attributes for co isolation --- package-lock.json | 24 +++++++++++++++++++ src/backend/package.json | 1 + .../src/services/PuterHomepageService.js | 1 + src/backend/src/services/WebServerService.js | 20 +++++++++++++++- src/gui/src/UI/UIWindow.js | 4 ++++ src/gui/src/index.js | 1 + 6 files changed, 50 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index 0568e05cb8..569e54660d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -13032,6 +13032,29 @@ "node": ">=14.17" } }, + "node_modules/ua-parser-js": { + "version": "1.0.38", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.38.tgz", + "integrity": "sha512-Aq5ppTOfvrCMgAPneW1HfWj66Xi7XL+/mIy996R1/CLS/rcyJQm6QZdsKrUeivDFQ+Oc9Wyuwor8Ze8peEoUoQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "license": "MIT", + "engines": { + "node": "*" + } + }, "node_modules/uglify-js": { "version": "3.17.4", "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz", @@ -14074,6 +14097,7 @@ "string-length": "^6.0.0", "svgo": "^3.0.2", "tiktoken": "^1.0.11", + "ua-parser-js": "^1.0.38", "uglify-js": "^3.17.4", "uuid": "^9.0.0", "validator": "^13.9.0", diff --git a/src/backend/package.json b/src/backend/package.json index daa5753a0f..f3d0d950b0 100644 --- a/src/backend/package.json +++ b/src/backend/package.json @@ -66,6 +66,7 @@ "string-length": "^6.0.0", "svgo": "^3.0.2", "tiktoken": "^1.0.11", + "ua-parser-js": "^1.0.38", "uglify-js": "^3.17.4", "uuid": "^9.0.0", "validator": "^13.9.0", diff --git a/src/backend/src/services/PuterHomepageService.js b/src/backend/src/services/PuterHomepageService.js index 57208f80fe..b623662086 100644 --- a/src/backend/src/services/PuterHomepageService.js +++ b/src/backend/src/services/PuterHomepageService.js @@ -109,6 +109,7 @@ class PuterHomepageService extends BaseService { short_description: config.short_description, long_description: config.long_description, disable_temp_users: config.disable_temp_users, + co_isolation_enabled: req.co_isolation_enabled, }, })); } diff --git a/src/backend/src/services/WebServerService.js b/src/backend/src/services/WebServerService.js index 57fe8b8213..3aeb068a05 100644 --- a/src/backend/src/services/WebServerService.js +++ b/src/backend/src/services/WebServerService.js @@ -357,11 +357,29 @@ class WebServerService extends BaseService { app.use(helmet.xssFilter()); // app.use(helmet.referrerPolicy()); app.disable('x-powered-by'); + + const uaParser = require('ua-parser-js'); + app.use(function (req, res, next) { + const ua_header = req.headers['user-agent']; + const ua = uaParser(ua_header); + req.ua = ua; + console.log('\x1B[26;1m===== UA =====\x1B[0m', ua); + next(); + }); + + app.use(function (req, res, next) { + req.co_isolation_enabled = + ['Chrome', 'Edge'].includes(req.ua.browser.name) + && (Number(req.ua.browser.major) >= 110); + next(); + }); app.use(function (req, res, next) { const origin = req.headers.origin; const is_site = req.hostname.endsWith(config.static_hosting_domain); + + const co_isolation_okay = is_site || req.co_isolation_enabled; if ( req.path === '/signup' || req.path === '/login' ) { res.setHeader('Access-Control-Allow-Origin', origin ?? '*'); @@ -392,7 +410,7 @@ class WebServerService extends BaseService { // NOTE: This is put behind a configuration flag because we // need some experimentation to ensure the interface // between apps and Puter doesn't break. - if ( config.cross_origin_isolation && is_site ) { + if ( config.cross_origin_isolation && co_isolation_okay ) { res.setHeader('Cross-Origin-Opener-Policy', 'same-origin'); res.setHeader('Cross-Origin-Embedder-Policy', 'require-corp'); } diff --git a/src/gui/src/UI/UIWindow.js b/src/gui/src/UI/UIWindow.js index 223a6d6adc..1af86ef7f4 100644 --- a/src/gui/src/UI/UIWindow.js +++ b/src/gui/src/UI/UIWindow.js @@ -323,6 +323,10 @@ async function UIWindow(options) { frameborder="0" ${options.iframe_url ? 'src="'+ html_encode(options.iframe_url)+'"' : ''} ${options.iframe_srcdoc ? 'srcdoc="'+ html_encode(options.iframe_srcdoc) +'"' : ''} + ${window.co_isolation_enabled + ? 'credentialless allow="cross-origin-isolated" ' + : '' + } allow = "accelerometer; camera; encrypted-media; gamepad; display-capture; geolocation; gyroscope; microphone; midi; clipboard-read; clipboard-write; fullscreen;" allowtransparency="true" allowpaymentrequest="true" diff --git a/src/gui/src/index.js b/src/gui/src/index.js index 08fe713fb4..59ea79837b 100644 --- a/src/gui/src/index.js +++ b/src/gui/src/index.js @@ -56,6 +56,7 @@ window.gui = async function(options){ window.max_item_name_length = options.max_item_name_length ?? 500; window.require_email_verification_to_publish_website = options.require_email_verification_to_publish_website ?? true; window.disable_temp_users = options.disable_temp_users ?? false; + window.co_isolation_enabled = options.co_isolation_enabled; // DEV: Load the initgui.js file if we are in development mode if(!window.gui_env || window.gui_env === "dev"){ From 8f87770cebab32c00cb10133979d426306685292 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sat, 20 Jul 2024 20:46:03 -0400 Subject: [PATCH 0584/2119] fix: popup login in co isolation mode --- src/backend/src/services/WebServerService.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/backend/src/services/WebServerService.js b/src/backend/src/services/WebServerService.js index 3aeb068a05..c149a37266 100644 --- a/src/backend/src/services/WebServerService.js +++ b/src/backend/src/services/WebServerService.js @@ -378,9 +378,10 @@ class WebServerService extends BaseService { const origin = req.headers.origin; const is_site = req.hostname.endsWith(config.static_hosting_domain); + const is_popup = !! req.query.embedded_in_popup; + + const co_isolation_okay = !is_popup && (is_site || req.co_isolation_enabled); - const co_isolation_okay = is_site || req.co_isolation_enabled; - if ( req.path === '/signup' || req.path === '/login' ) { res.setHeader('Access-Control-Allow-Origin', origin ?? '*'); } From 382fb24dbb1737a8a54ed2491f80b2e2276cde61 Mon Sep 17 00:00:00 2001 From: enweazudaniel Date: Sun, 21 Jul 2024 17:04:33 +0100 Subject: [PATCH 0585/2119] Update ig.js --- src/gui/src/i18n/translations/ig.js | 146 +++++++++++++++++++++++----- 1 file changed, 121 insertions(+), 25 deletions(-) diff --git a/src/gui/src/i18n/translations/ig.js b/src/gui/src/i18n/translations/ig.js index 7bc7e88c79..ef583e65fb 100644 --- a/src/gui/src/i18n/translations/ig.js +++ b/src/gui/src/i18n/translations/ig.js @@ -22,32 +22,46 @@ const ig = { english_name: "Igbo", code: "ig", dictionary: { - about: "maka", + about: "banyere", account: "akaụntụ", + account_password: "nyochaa paswọọdụ akaụntụ", access_granted_to: "Enyere ohere", add_existing_account: "Tinye Akaụntụ dị adị", all_fields_required: 'A chọrọ mpaghara niile.', + allow: 'ekwe', apply: "Tinye", ascending: 'Na-arịgo', - auto_arrange: 'Hazie akpaaka', + associated_websites: "Weebụsaịtị Ejikọtara", + auto_arrange: 'ndokwa onwe', background: "ndabere", browse: "Chọgharịa", cancel: 'Kagbuo', center: 'etiti', - change_desktop_background: 'Gbanwee ndabere desktọpụ…', - change_email: "Gbanwee email", - change_language: "Gbanwee Asụsụ", - change_password: "Gbanwee paswọọdụ", - change_ui_colors: "Gbanwee agba UI", - change_username: "Gbanwee aha njirimara", + change_desktop_background: 'ịgbanwe ndabere desktọpụ…', + change_email: "ịgbanwe email", + change_language: "ịgbanwe Asụsụ", + change_password: "ịgbanwe paswọọdụ", + change_ui_colors: "ịgbanwe agba UI", + change_username: "ịgbanwe aha njirimara", close: 'mmechi', close_all_windows: "mmechi Windows niile", close_all_windows_confirm: "Ị ji n'aka na ị chọrọ imechi windo niile?", - close_all_windows_and_log_out: 'mmechi Windows wee pụọ', - change_always_open_with: "Ịchọrọ iji ụdị faịlụ a mepee mgbe niile", + close_all_windows_and_log_out: 'mmechi Windows na wee pụọ', + change_always_open_with: "Ị chọrọ I na mepee ụdị faịlụ site na", color: 'Agba', + confirm: 'gosi', + confirm_2fa_setup: 'Etinyela m koodu ahụ na ngwa nyocha m', + confirm_2fa_recovery: 'Echekwala m koodu mgbake m na ebe echedoro', hue: 'Hue', confirm_account_for_free_referral_storage_c2a: 'Mepụta akaụntụ wee kwado adreesị ozi-e gị iji nweta 1 GB nke nchekwa efu. Enyi gị ga-enwetakwa 1 GB nke nchekwa efu.', + confirm_code_generic_incorrect: "Koodu ezighi ezi.", + confirm_code_generic_too_many_requests: "Ọtụtụ ọchịchọ. Biko chere nkeji ole na ole.", + confirm_code_generic_submit: "Nye koodu", + confirm_code_generic_try_again: "Nwa ọzọ", + confirm_code_generic_title: "Tinye koodu Nkwenye", + confirm_code_2fa_instruction: "Tinye koodu ọnụọgụ isi site na ngwa nyocha gị.", + confirm_code_2fa_submit_btn: "tinye", + confirm_code_2fa_title: "Tinye koodu 2FA", confirm_delete_multiple_items: "Ị ji n'aka na ịchọrọ ihichapụ ihe ndị a kpamkpam?", confirm_delete_single_item: 'Ịchọrọ ihichapụ ihe a kpamkpam?', confirm_open_apps_log_out: "Ị nwere ngwa mepere emepe. Ị ji n'aka na ị chọrọ ịpụ?", @@ -55,34 +69,46 @@ const ig = { confirm_delete_user: "Ị ji n'aka na ịchọrọ ihichapụ akaụntụ gị? A ga-ehichapụ faịlụ gị niile na data gị kpamkpam. Enweghị ike imegharị ihe a.", confirm_delete_user_title: "Hichapụ Akaụntụ?", confirm_session_revoke: "O doro gị anya na ịchọrọ kagbuo nnọkọ a?", + confirm_your_email_address: "Kwenye na adreesị email", contact_us: "Kpọtụrụ anyị", + contact_us_verification_required: "Ị ga-enwerịrị adreesị email ekwenyesiri ike ka ị jiri nke a.", contain: 'nwere', continue: "Gaa n'ihu", copy: 'Detuo', copy_link: "Detuo njikọ", - copying: "Na-eṅomi", + copying: "n'ide", + copying_file: "n'ide %%", cover: 'Mkpuchi', - create_account: "Mebe akaụntụ", + create_account: "Mepe akaụntụ", create_free_account: "Mepụta Akaụntụ efu", create_shortcut: "Mepụta Ụzọ mkpirisi", credits: "Ebe e si nweta", current_password: "paswọọdụ Ugbu a", cut: 'Bee', clock: "Elekere", - clock_visible_hide: 'Zoo - ezoro ezo mgbe niile', + clock_visible_hide: 'Ezo - ezoro ezo mgbe niile', clock_visible_show: 'Gosi - A na-ahụ ya mgbe niile', clock_visible_auto: 'Nchekwa onwe - Emepụtara, a na-ahụ ya naanị na ọnọdụ ihuenyo zuru oke.', - date_modified: 'Ụbọchị gbanwee', + close_all: 'Mechie ha niile', + created: 'kere', + date_modified: 'Ụbọchị ịgbanwe', default: 'Default', delete: 'Hichapụ', delete_account: "Hichapụ Akaụntụ", delete_permanently: "Hichapụ kpamkpam", + deleting_file: "ihichapụ %%", deploy_as_app: 'Bugharịa dị ka ngwa', descending: 'agbadata', + desktop: 'desktọpụ', desktop_background_fit: "dabara", - developers: "Ndị mmepe", + developers: "Ndị mme ya", dir_published_as_website: `%strong% e bipụtara ya:`, + disable_2fa: 'Gbanyụọ 2FA', + disable_2fa_confirm: "Ị ji n'aka na ịchọrọ gbanyụọ 2FA?", + disable_2fa_instructions: "Tinye paswọọdụ gị i ji gbanyụọ 2FA.", disassociate_dir: "hapụ Akwụkwọ ndekọ", + documents: 'akwụkwọ', + dont_allow: 'Ekwela', download: 'Budata', download_file: 'Budata faịlụ', downloading: "Nbudata", @@ -94,22 +120,31 @@ const ig = { empty_trash: 'Mkpofu ahịhịa', empty_trash_confirmation: `Ị ji n'aka na ịchọrọ ihichapụ ihe ndị dị na ahịhịa?`, emptying_trash: 'Mkpofu ahịhịa…', + enable_2fa: 'Kwado 2FA', end_hard: "Kwụsị ike", end_process_force_confirm: "O doro gị anya na ịchọrọ ịmanye-akwụsị usoro a?", end_soft: "Kwụsị nwayọọ", + enlarged_qr_code: "gbasawanyere QR Koodu", enter_password_to_confirm_delete_user: "Tinye paswọọdụ gị iji kwado nhichapụ akaụntụ gị", + error_message_is_missing: "Ozi mmebe na-efu.", + error_unknown_cause: "Nhe amaghị ama mere.", + error_uploading_files: "Ibulite faịlụ agaghị", + favorites: "ọkacha mmasị", feedback: "nzaghachi", feedback_c2a: "Biko jiri fọm dị n'okpuru zitere anyị nzaghachi gị, nkwupụta gị na mkpesa ahụhụ.", feedback_sent_confirmation: "Daalụ maka ịkpọtụrụ anyị. Ọ bụrụ na ị nwere email metụtara akaụntụ gị, ị ga-anụghachi anyị ozugbo enwere ike.", fit: "dabara", + folder: 'nchekwa', force_quit: 'ịkwụsị ike', forgot_pass_c2a: "Chefuru paswọọdụ?", from: "si", general: "Izugbe", get_a_copy_of_on_puter: `Nweta otu '%%' na Puter.com!`, get_copy_link: 'Nweta njikọ nke', - hide_all_windows: "Zoo Windows niile", + hide_all_windows: "Ezo Windows niile", + home: 'ụlọ', html_document: 'akwụkwọ HTML', + hue: 'Hue', image: 'Onyonyo', incorrect_password: "paswọọdụ ezighi ezi", invite_link: "Njikọ ịkpọ òkù", @@ -121,11 +156,17 @@ const ig = { license: "ikike", lightness: 'ìhè', link_copied: "depụtagha njikọ", - loading: 'Na-ebugo', + loading: 'Na-ebugo ibu', log_in: "Banye", log_into_another_account_anyway: 'Banye na akaụntụ ọzọ na agbanyeghị', log_out: 'pụọ', + looks_good: "Ọ mara mma!", manage_sessions: "Jikwaa Oge", + menubar_style: "Ụdị Menubar", + menubar_style_desktop: "Desktọpụ", + menubar_style_system: "Sistemu", + menubar_style_window: "Window", + modified: 'gbanwee', move: 'Bugharịa', moving_file: "Na Bugharịa %%", my_websites: "Weebụsaịtị m", @@ -147,23 +188,31 @@ const ig = { ok: 'OK', open: "Mepee", open_in_new_tab: "Mepee na Tab ọhụrụ", - open_in_new_window: "Mepee na windo ọhụrụ", - open_with: "Mepee Ya", + open_in_new_window: "Mepee na window ọhụrụ", + open_with: "Ji Mepee Ya", + original_name: 'Aha izizi', + original_path: 'Ụzọ izizi', oss_code_and_content: "Ngwanrọ na ọdịnaya mepere emepe", password: "paswọọdụ", password_changed: "gbanwere paswọọdụ.", + password_recovery_rate_limit: "Ị ruru oke ọnụ ahịa anyị; biko chere nkeji ole na ole. Iji gbochie nke a n'ọdịnihu, zere ibugharị ibe ahụ ọtụtụ oge.", + password_recovery_token_invalid: "Ihe mgbake mgbake okwuntughe adịkwaghị irè.", + password_recovery_unknown_error: "Nhe amaghị ama mere. Biko nwaa ọzọ ma emechaa.", password_required: 'Achọrọ paswọọdụ.', password_strength_error: "paswọọdụ ga-enwerịrị opekata mpe mkpụrụedemede 8 ma nwee opekata mpe otu mkpụrụedemede ukwu, otu mkpụrụedemede obere, otu nọmba na otu agwa pụrụ iche..", passwords_do_not_match: '`paswọọdụ ọhụrụ` na `Kwenye paswọọdụ ọhụrụ` adabaghị.', - paste: 'tapawa', - paste_into_folder: "Tapawa n'ime nchekwa", + paste: 'tinye', + paste_into_folder: "Tinye n'ime nchekwa", + path: 'ụzọ', personalization: "Nhazi onwe", pick_name_for_website: "Họrọ aha maka weebụsaịtị gị:", picture: "Foto", + pictures: 'Foto', plural_suffix: 's', powered_by_puter_js: `Kwadoro site na {{link=docs}}Puter.js{{/link}}`, preparing: "Na-akwado...", preparing_for_upload: "Na-akwado maka bulite...", + print: 'ebipụta', privacy: "Nzuzo", proceed_to_login: 'Gaba na nbanye', proceed_with_account_deletion: "Gaa n'ihu na ihichapụ akaụntụ", @@ -173,10 +222,13 @@ const ig = { process_type_init: 'Init', process_type_ui: 'UI', properties: "Njirimara", + public: 'eze', publish: "Bipụta", publish_as_website: 'Bipụta dị ka webụsaịtị', puter_description: `Puter bụ igwe ojii nzuzo nke mbụ iji dobe faịlụ gị, ngwa na egwuregwu gị n'otu ebe echekwara, enwere ike ịnweta ya ebe ọ bụla n'oge ọ bụla..`, + reading_file: "ọgụgụ %strong%", recent: "Na nso nso a", + recommended: "nwere ike ikwu", recover_password: "Weghachite paswọọdụ", refer_friends_c2a: "Nweta 1 GB maka enyi ọ bụla mepụtara ma kwado akaụntụ na Puter. Enyi gị ga-enwetakwa 1 GB!", refer_friends_social_media_c2a: `Nweta 1 GB nke nchekwa efu na Puter.com!`, @@ -191,6 +243,7 @@ const ig = { reset_colors: "Tọgharịa Agba", restart_puter_confirm: "Ị ji n'aka na ịchọrọ ịmalitegharịa Puter?", restore: "weghachi", + save: 'chekwa', saturation: 'juputa', save_account: 'Chekwa akaụntụ', save_account_to_get_copy_link: "Biko mepụta akaụntụ iji gaa n'ihu.", @@ -198,6 +251,11 @@ const ig = { save_session: 'Chekwa oge', save_session_c2a: "Mepụta akaụntụ iji chekwaa nnọkọ gị ugbu a ma zere ịla n'iyi ọrụ gị.", scan_qr_c2a: "Chọgharịa koodu dị n'okpuru ka ịbanye na nnọkọ a site na ngwaọrụ ndị ọzọ", + scan_qr_2fa: 'Jiri ngwa nyocha gị nyochaa QR koodu', + scan_qr_generic: 'Jiri ekwentị gị ma ọ bụ ngwaọrụ ọzọ nyochaa QR koodu a', + search: 'Chọọ', + seconds: 'sekọnd', + security: "nche", select: "Họrọ", selected: 'họrọ', select_color: 'Họrọ agba…', @@ -206,20 +264,24 @@ const ig = { send_password_recovery_email: "Zipu ozi-e mgbake paswọọdụ ", session_saved: "Daalụ maka ịmepụta akaụntụ. Achekwala nnọkọ a.", settings: "Ntọala", - set_new_password: "Tọọ paswọọdụ ọhụrụ", - share_to: "Kekọrịta na", + set_new_password: "Tinye paswọọdụ ọhụrụ", + share: "ike", + share_to: "ike nye", + share_with: "ji ike nye:", + shortcut_to: "Ụzọ mkpirisi ka", show_all_windows: "Gosi Windows niile", - show_hidden: 'Show hidden', + show_hidden: 'Gosi ihe ezozo', sign_in_with_puter: "Jiri Puter banye", sign_up: "Debanye aha", signing_in: "Ịbanye…", size: 'Nha', skip: 'Mafee', + something_went_wrong: "Ọ nwere ihe adịghị mma.", sort_by: 'Hazie site na', start: 'mbido', status: "Ọnọdụ", storage_usage: "Ojiji Nchekwa", - storage_puter_used: 'nke Puter na-eji', + storage_puter_used: 'nke Puter na-ji', taking_longer_than_usual: 'Na-ewe obere oge karịa ka ọ dị na mbụ. Biko chere...', task_manager: "Onye njikwa ọrụ", taskmgr_header_name: "Aha", @@ -230,6 +292,9 @@ const ig = { tos_fineprint: `Site na ịpị 'Mepụta Akaụntụ efu' ị kwenyere na Puter {{link=terms}} Usoro ọrụ{{/link}} na {{link=privacy}}Amụma nzuzo{{/link}} Puter.`, transparency: "nghọta", trash: 'ahịhịa', + two_factor: 'Nyocha ihe abụọ', + two_factor_disabled: 'Agbanyụrụ 2FA', + two_factor_enabled: 'Agbanyere 2FA', type: 'Ụdị', type_confirm_to_delete_account: "Pịnye 'kwenye' ka ihichapụ akaụntụ gị.", ui_colors: "Agba UI", @@ -245,11 +310,42 @@ const ig = { username_changed: 'Emelitere aha njirimara nke ọma.', username_required: 'Achọrọ aha njirimara.', versions: "Ụdịdị", + videos: 'Vidiyo', visibility: 'Nhụta', yes: 'Ee', yes_release_it: 'Ee, Hapụ ya', you_have_been_referred_to_puter_by_a_friend: "Otu enyi zigara gị na Puter!", zip: "Zip", + zipping_file: "Zipping %strong%", + + // === 2FA Setup === + setup2fa_1_step_heading: 'Mepee ngwa nyocha', + setup2fa_1_instructions: ` + Ị nwere ike iji ngwa nyocha ọ bụla na-akwado protocol Paswọdu Otu oge (TOTP) dabere na Oge. + Enwere ọtụtụ nhọrọ, mana ọ bụrụ na ị maghị + Authy + bụ nhọrọ siri ike maka android na iOS. + `, + setup2fa_2_step_heading: 'Nyochaa QR koodu', + setup2fa_3_step_heading: 'Tinye koodu ọnụọgụ isi', + setup2fa_4_step_heading: 'Detuo koodu mgbake gị', + setup2fa_4_instructions: ` + Koodu mgbake ndị a bụ naanị ụzọ ị ga-esi iba akaụntụ gị ma ọ bụrụ na ekwentị gị furu ma ọ bụ enweghị ike iji ngwa nyocha gị.. + Gbaa mbọ hụ na ịchekwaa ha n'ebe dị mma. + `, + setup2fa_5_step_heading: 'Kwenye ntọlite ​​2FA', + setup2fa_5_confirmation_1: 'Echekwala m koodu mgbake m na ebe echekwa', + setup2fa_5_confirmation_2: 'Adị m njikere i Kwado 2FA', + setup2fa_5_button: 'Kwado 2FA', + + // === 2FA Login === + login2fa_otp_title: 'Tinye koodu 2FA', + login2fa_otp_instructions: 'Tinye koodu ọnụọgụ isi site na ngwa nyocha.', + login2fa_recovery_title: 'Tinye koodu mgbake', + login2fa_recovery_instructions: 'Tinye otu koodu mgbake gị i ji eba akaụntụ gị.', + login2fa_use_recovery_code: 'Ji koodu mgbake', + login2fa_recovery_back: 'Azu', + login2fa_recovery_placeholder: 'XXXXXXXX', } }; From a0113788f94c6b018fd1b9087091a2be108f1cca Mon Sep 17 00:00:00 2001 From: Koppeks Date: Sun, 21 Jul 2024 17:32:33 -0300 Subject: [PATCH 0586/2119] remove extra comments --- src/gui/src/helpers/new_context_menu_item.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/gui/src/helpers/new_context_menu_item.js b/src/gui/src/helpers/new_context_menu_item.js index 602a8ae2b8..16e9fb469d 100644 --- a/src/gui/src/helpers/new_context_menu_item.js +++ b/src/gui/src/helpers/new_context_menu_item.js @@ -91,10 +91,6 @@ const new_context_menu_item = function(dirname, append_to_element){ baseItems.push({ html: "No templates found", icon: ``, - //Add function to ask user to create new template folder - // onClick: function() { - // window.create_file({dirname: dirname, append_to_element: append_to_element, name: template.name}); - // } }); } From 2d5a0bb89430b70f92b2f0b837e20ee307cfdf50 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sun, 21 Jul 2024 17:01:24 -0700 Subject: [PATCH 0587/2119] closes #614 --- src/gui/src/UI/UIDesktop.js | 4 ++-- src/gui/src/UI/UIItem.js | 6 +++--- src/gui/src/css/style.css | 6 +++++- src/gui/src/helpers.js | 2 +- src/gui/src/helpers/get_html_element_from_options.js | 2 +- 5 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/gui/src/UI/UIDesktop.js b/src/gui/src/UI/UIDesktop.js index fcad9b24d3..c02e455927 100644 --- a/src/gui/src/UI/UIDesktop.js +++ b/src/gui/src/UI/UIDesktop.js @@ -215,7 +215,7 @@ async function UIDesktop(options){ // Update matching items // set new item name - $(`.item[data-uid='${html_encode(item.uid)}'] .item-name`).html(html_encode(truncate_filename(item.name)).replaceAll(' ', ' ')); + $(`.item[data-uid='${html_encode(item.uid)}'] .item-name`).html(html_encode(truncate_filename(item.name))); // Set new icon const new_icon = (item.is_dir ? window.icons['folder.svg'] : (await item_icon(item)).image); @@ -419,7 +419,7 @@ async function UIDesktop(options){ // Update matching items // Set new item name - $(`.item[data-uid='${html_encode(item.uid)}'] .item-name`).html(html_encode(truncate_filename(item.name)).replaceAll(' ', ' ')); + $(`.item[data-uid='${html_encode(item.uid)}'] .item-name`).html(html_encode(truncate_filename(item.name))); // Set new icon const new_icon = (item.is_dir ? window.icons['folder.svg'] : (await item_icon(item)).image); diff --git a/src/gui/src/UI/UIItem.js b/src/gui/src/UI/UIItem.js index 5ef43227b4..e7db916cb4 100644 --- a/src/gui/src/UI/UIItem.js +++ b/src/gui/src/UI/UIItem.js @@ -162,7 +162,7 @@ function UIItem(options){ h += `
`; // name - h += `${options.is_trash ? i18n('trash') : html_encode(truncate_filename(options.name)).replaceAll(' ', ' ')}` + h += `
${options.is_trash ? i18n('trash') : html_encode(truncate_filename(options.name))}
` // name editor h += `` h += `
`; @@ -653,7 +653,7 @@ function UIItem(options){ UIAlert(`The name ".." is not allowed, because it is a reserved name. Please choose another name.`) } - $(el_item_name).html(html_encode(truncate_filename(options.name)).replaceAll(' ', ' ')); + $(el_item_name).html(html_encode(truncate_filename(options.name))); $(el_item_name).show(); $(el_item_name_editor).val($(el_item).attr('data-name')); $(el_item_name_editor).hide(); @@ -1412,7 +1412,7 @@ function UIItem(options){ // -------------------------------------------------------- $(el_item_name_editor).on('input keypress focus', function(){ const val = $(el_item_name_editor).val(); - $('.item-name-shadow').html(html_encode(val).replaceAll(' ', ' ')); + $('.item-name-shadow').html(html_encode(val)); if(val !== ''){ const w = $('.item-name-shadow').width(); const h = $('.item-name-shadow').height(); diff --git a/src/gui/src/css/style.css b/src/gui/src/css/style.css index 1948ee6f66..279c980fff 100644 --- a/src/gui/src/css/style.css +++ b/src/gui/src/css/style.css @@ -77,7 +77,10 @@ font-optical-sizing: auto; font-style: normal; font-variation-settings: "slnt"0; +} +pre{ + font-family: "Inter", "Helvetica Neue", HelveticaNeue, Helvetica, Arial, sans-serif; } :root { @@ -617,8 +620,9 @@ span.header-sort-icon img { display: inline-block; font-weight: bold; border-radius: 4px; - line-break: anywhere; box-sizing: border-box; + white-space: pre-wrap; + word-break: break-word; } .item-name { diff --git a/src/gui/src/helpers.js b/src/gui/src/helpers.js index a85be51b5a..b258028b56 100644 --- a/src/gui/src/helpers.js +++ b/src/gui/src/helpers.js @@ -2095,7 +2095,7 @@ window.rename_file = async(options, new_name, old_name, old_path, el_item, el_it } // Set new item name - $(`.item[data-uid='${$(el_item).attr('data-uid')}'] .item-name`).html(html_encode(truncate_filename(new_name)).replaceAll(' ', ' ')); + $(`.item[data-uid='${$(el_item).attr('data-uid')}'] .item-name`).html(html_encode(truncate_filename(new_name))); $(el_item_name).show(); // Hide item name editor diff --git a/src/gui/src/helpers/get_html_element_from_options.js b/src/gui/src/helpers/get_html_element_from_options.js index ee464d5f22..6f19787890 100644 --- a/src/gui/src/helpers/get_html_element_from_options.js +++ b/src/gui/src/helpers/get_html_element_from_options.js @@ -136,7 +136,7 @@ const get_html_element_from_options = async function(options){ h += `
`; // name - h += `${html_encode(truncate_filename(options.name)).replaceAll(' ', ' ')}` + h += `${html_encode(truncate_filename(options.name))}` // name editor h += `` h += `
`; From a9801fc10db3db3317bad60486c613a4d7dbfc07 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Mon, 22 Jul 2024 11:07:57 -0700 Subject: [PATCH 0588/2119] place `available_templates` call in `update_auth_data` to guarantee that `user` object exists --- src/gui/src/helpers.js | 6 ++++-- src/gui/src/initgui.js | 2 -- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/gui/src/helpers.js b/src/gui/src/helpers.js index 3d15fb029a..2fcfb46c96 100644 --- a/src/gui/src/helpers.js +++ b/src/gui/src/helpers.js @@ -432,7 +432,7 @@ window.refresh_user_data = async (auth_token)=>{ } } -window.update_auth_data = (auth_token, user)=>{ +window.update_auth_data = async (auth_token, user)=>{ window.auth_token = auth_token; localStorage.setItem('auth_token', auth_token); @@ -493,6 +493,9 @@ window.update_auth_data = (auth_token, user)=>{ $('.user-options-login-btn, .user-options-create-account-btn').hide(); $('.user-options-menu-btn').show(); } + + // Search and store user templates + window.file_templates = await window.available_templates() } window.mutate_user_preferences = function(user_preferences_delta) { @@ -838,7 +841,6 @@ window.create_file = async(options)=>{ } window.available_templates = async () => { - console.log(window.user.username) const baseRoute = `/${window.user.username}` const keywords = ["template", "templates", i18n('template')] //make sure all its lowercase diff --git a/src/gui/src/initgui.js b/src/gui/src/initgui.js index a28b1a659f..cd7bf0b33d 100644 --- a/src/gui/src/initgui.js +++ b/src/gui/src/initgui.js @@ -108,8 +108,6 @@ const launch_services = async function (options) { const svc_process = globalThis.services.get('process'); svc_process.get_init().chstatus(PROCESS_RUNNING); } - // Search and store user templates - window.file_templates = await window.available_templates() }; // This code snippet addresses the issue flagged by Lighthouse regarding the use of From d8dd2180895656e2d7d1b135fc126b06908c77bc Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Mon, 22 Jul 2024 11:31:01 -0700 Subject: [PATCH 0589/2119] Don't show `No templates found` for now. --- src/gui/src/helpers.js | 2 -- src/gui/src/helpers/new_context_menu_item.js | 14 ++++++++------ 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/gui/src/helpers.js b/src/gui/src/helpers.js index 2fcfb46c96..331a4b2dd0 100644 --- a/src/gui/src/helpers.js +++ b/src/gui/src/helpers.js @@ -855,7 +855,6 @@ window.available_templates = async () => { console.log(hasTemplateFolder) if(!hasTemplateFolder){ - console.log("No template folder") return [] } @@ -863,7 +862,6 @@ window.available_templates = async () => { console.log(hasTemplateFiles) if(hasTemplateFiles.length == 0) { - console.log("There are no templates") return [] } diff --git a/src/gui/src/helpers/new_context_menu_item.js b/src/gui/src/helpers/new_context_menu_item.js index 16e9fb469d..11a091ecc4 100644 --- a/src/gui/src/helpers/new_context_menu_item.js +++ b/src/gui/src/helpers/new_context_menu_item.js @@ -70,12 +70,14 @@ const new_context_menu_item = function(dirname, append_to_element){ }); } }, - // divider - '-' ]; //Show file_templates on the lower part of "New" if (window.file_templates.length > 0) { + // divider + baseItems.push('-'); + + // User templates baseItems.push({ html: "User templates", icon: ``, @@ -88,10 +90,10 @@ const new_context_menu_item = function(dirname, append_to_element){ })) }); } else { - baseItems.push({ - html: "No templates found", - icon: ``, - }); + // baseItems.push({ + // html: "No templates found", + // icon: ``, + // }); } //Conditional rendering for the templates From 5d2a6fce305a3dcd4857f52ebb75f529dffe4790 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 22 Jul 2024 17:10:58 -0400 Subject: [PATCH 0590/2119] fix: fix templates --- src/gui/src/helpers.js | 20 +++++++++++++++++--- src/gui/src/helpers/new_context_menu_item.js | 10 ++++++++-- 2 files changed, 25 insertions(+), 5 deletions(-) diff --git a/src/gui/src/helpers.js b/src/gui/src/helpers.js index b1103b5265..575f26676f 100644 --- a/src/gui/src/helpers.js +++ b/src/gui/src/helpers.js @@ -869,12 +869,26 @@ window.available_templates = async () => { hasTemplateFiles.forEach(element => { console.log(element) - const elementInformation = element.name.split(".") - const name = elementInformation[0] - let extension = elementInformation[1] + + const extIndex = element.name.lastIndexOf('.'); + const name = extIndex === -1 + ? element.name + : element.name.slice(0, extIndex); + let extension = extIndex === -1 + ? '' + : element.name.slice(extIndex + 1); + console.log(extension) if(extension == "txt") extension = "text" + + // TODO: should use path join utility + const path = + baseRoute + "/" + + hasTemplateFolder.name + '/' + + element.name; + const itemStructure = { + path, html: `${extension.toUpperCase()} ${name}`, extension:extension, name: element.name diff --git a/src/gui/src/helpers/new_context_menu_item.js b/src/gui/src/helpers/new_context_menu_item.js index 11a091ecc4..64c0da2bf8 100644 --- a/src/gui/src/helpers/new_context_menu_item.js +++ b/src/gui/src/helpers/new_context_menu_item.js @@ -84,8 +84,14 @@ const new_context_menu_item = function(dirname, append_to_element){ items: window.file_templates.map(template => ({ html: template.html, icon: ``, - onClick: function() { - window.create_file({dirname: dirname, append_to_element: append_to_element, name: template.name}); + onClick: async function () { + const content = await puter.fs.read(template.path); + window.create_file({ + dirname: dirname, + append_to_element: append_to_element, + name: template.name, + content, + }); } })) }); From 5d58764316eb84babd61586492c89461f8eb4661 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Mon, 22 Jul 2024 16:38:45 -0700 Subject: [PATCH 0591/2119] Use join. to build target path --- src/gui/src/helpers.js | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/gui/src/helpers.js b/src/gui/src/helpers.js index 575f26676f..27de886399 100644 --- a/src/gui/src/helpers.js +++ b/src/gui/src/helpers.js @@ -878,22 +878,17 @@ window.available_templates = async () => { ? '' : element.name.slice(extIndex + 1); - console.log(extension) if(extension == "txt") extension = "text" - // TODO: should use path join utility - const path = - baseRoute + "/" + - hasTemplateFolder.name + '/' + - element.name; + const _path = path.join( baseRoute, hasTemplateFolder.name, element.name); + console.log(_path) const itemStructure = { - path, + path: _path, html: `${extension.toUpperCase()} ${name}`, extension:extension, name: element.name } - console.log(extension) result.push(itemStructure) }); From 203669a79f7faf2d1892538a32c232e0249dec9b Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 22 Jul 2024 20:23:40 -0400 Subject: [PATCH 0592/2119] release: v2.4.2 --- CHANGELOG.md | 59 ++++++++++++++++++++++++++++++++++++++ tools/gen-release-notes.js | 56 ++++++++++++++++++++++++++++++++---- 2 files changed, 110 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 2eb896735c..9447f498e8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,64 @@ # Changelog +## v2.4.2 (2024-07-22) + +### Puter + +#### Features + +- add new file templates ([1f7f094](https://github.com/HeyPuter/puter/commit/1f7f094282fae915a2436701cfb756444cd3f781)) +- add cross_origin_isolation option ([e539932](https://github.com/HeyPuter/puter/commit/e53993207077aecd2c01712519251993bb2562bc)) +- add option to disable temporary users ([f9333b3](https://github.com/HeyPuter/puter/commit/f9333b3d1e05bd0dffaecd2e29afd08ea61559fc)) +- add some default groups ([ba50d0f](https://github.com/HeyPuter/puter/commit/ba50d0f96d58075abec067d24e6532bd874093f0)) +- Add support for dropping multiple Puter items onto Dev Center (close #311) ([8e7306c](https://github.com/HeyPuter/puter/commit/8e7306c23be01ee6c31cdb4c99f2fb1f71a2247f)) + +#### Translations + +- Update ig.js ([382fb24](https://github.com/HeyPuter/puter/commit/382fb24dbb1737a8a54ed2491f80b2e2276cde61)) +- feat: add vietnamese localization-a ([c2d3d69](https://github.com/HeyPuter/puter/commit/c2d3d69dbe33f36fcae13bcbc8e2a31a86025af9)) +- Update zhtw.js, Complete Traditional Chinese translation based on English file #550 ([b9e73b7](https://github.com/HeyPuter/puter/commit/b9e73b7288aebb14e6bbf1915743e9157fc950b1)) +- update zhtw.js to match en.js ([37fd666](https://github.com/HeyPuter/puter/commit/37fd666a9a6788d5f0c59311499f29896b48bc82)) +- Add Tamil translation to translations.js ([8a3d043](https://github.com/HeyPuter/puter/commit/8a3d0430f39f872b8a460c344cce652c340b700b)) +- Move Tamil translation to the rest of translations ([333d6e3](https://github.com/HeyPuter/puter/commit/333d6e3b651e460caca04a896cbc8c175555b79b)) +- Translation improvements, mainly style and context-based ([8bece96](https://github.com/HeyPuter/puter/commit/8bece96f6224a060d5b408e08c58865fadb8b79c)) +- update translation file es.js to be up to date with the file en.js ([1515278](https://github.com/HeyPuter/puter/commit/151527825f1eb4b060aaf97feb7d18af4fcddbf2)) +- Translate en.js as of 2024-07-10 ([8e297cd](https://github.com/HeyPuter/puter/commit/8e297cd7e30757073e2f96593c363a273b639466)) +- Create hu.js hungarian language ([69a80ab](https://github.com/HeyPuter/puter/commit/69a80ab3d2c94ee43d96021c3bcbdab04a4b5dc6)) +- Update translations.js to Hungarian lang ([56820cf](https://github.com/HeyPuter/puter/commit/56820cf6ee56ff810a6b495a281ccbb2e7f9d8fb)) +- Tamil translation ([81781f8](https://github.com/HeyPuter/puter/commit/81781f80afc07cd1e6278906cdc68c8092fbfedf)) +- Update it.js ([84e31ef](https://github.com/HeyPuter/puter/commit/84e31eff2f58584d8fab7dd10606f2f6ced933a2)) +- Update Armenian translation file ([3b8af7c](https://github.com/HeyPuter/puter/commit/3b8af7cc5c1be8ed67be827360bbfe0f0b5027e9)) + +#### Bug Fixes + +- fix templates ([5d2a6fc](https://github.com/HeyPuter/puter/commit/5d2a6fce305a3dcd4857f52ebb75f529dffe4790)) +- popup login in co isolation mode ([8f87770](https://github.com/HeyPuter/puter/commit/8f87770cebab32c00cb10133979d426306685292)) +- add necessary iframe attributes for co isolation ([2a5cec7](https://github.com/HeyPuter/puter/commit/2a5cec7ee914c9c97ae90b85464f9fc5332ad2fb)) +- chore: fix confirm for type_confirm_to_delete_account ([02e1b1e](https://github.com/HeyPuter/puter/commit/02e1b1e8f5f8e22d7ab39ebff99f7dd8e08a4221)) +- syntax error and formatting issue ([3a09e84](https://github.com/HeyPuter/puter/commit/3a09e84838fe8b74bd050641620eec87d9f59dfc)) +- #432 ([f897e84](https://github.com/HeyPuter/puter/commit/f897e844989083b0b369ba0ce4d2c5a9f3db5ad8)) +- `launch_app` not considering `explorer` as a special case ([98e6964](https://github.com/HeyPuter/puter/commit/98e69642d027a83975a0b2b825317213098bb689)) +- well kinda (HOSTNAME in phoenix) ([7043b94](https://github.com/HeyPuter/puter/commit/7043b9400c63842c4c54d82724167666708d3119)) +- it was github actions the entire time ([602a198](https://github.com/HeyPuter/puter/commit/602a19895c05b45a7d283470e7af3ae786be1bf2)) +- fix CI attempt #7 ([614f2c5](https://github.com/HeyPuter/puter/commit/614f2c5061525f230ccd879bfb047434ac46a9ba)) +- fix CI attempt #6 ([9d549b1](https://github.com/HeyPuter/puter/commit/9d549b192d149eac96c316ded645bf7c2e96153d)) +- fix CI attempt #5 ([74adcdd](https://github.com/HeyPuter/puter/commit/74adcddc1d60e0a513408a0716ed2b301126225d)) +- fix CI attempt #4 ([84b993b](https://github.com/HeyPuter/puter/commit/84b993bce913c3ad99127063bcfaae19331b199c)) +- fix CI attempt #3 ([3bca973](https://github.com/HeyPuter/puter/commit/3bca973f5f4e65a2bd24c634c347fbd681a7458b)) +- fix CI attempt #2 ([aebe89a](https://github.com/HeyPuter/puter/commit/aebe89a1acb070764551e8e89e325325ffbed8f9)) +- run mocha within packages in monorepo ([58c199c](https://github.com/HeyPuter/puter/commit/58c199c15356ac087a04b16dd18e8fe0f1aea359)) +- make webpack output not look like errors ([ad3d318](https://github.com/HeyPuter/puter/commit/ad3d318d07377c78c0429247225655e489b68be4)) +- No scrollbar for session list ([45f131f](https://github.com/HeyPuter/puter/commit/45f131f8eaf94cf3951ca7ffeb6f311590233b8a)) +- fix path issues under win32 platform ([d80f2fa](https://github.com/HeyPuter/puter/commit/d80f2fa847bfaef98dc8d482898f5c15f268e4bd)) +- remove abnoxious debug file ([5c636d4](https://github.com/HeyPuter/puter/commit/5c636d4fd25e14ba3813f7fca3b70ff7bd6860e7)) +- read_only fields in ES ([e8f4c32](https://github.com/HeyPuter/puter/commit/e8f4c328bff5c36b95fe460b80803e12e619f8ee)) + +### Security + +#### Bug Fixes + +- hoist acl check in ll_read ([6a2fbc1](https://github.com/HeyPuter/puter/commit/6a2fbc1925952ecceed741afe138270d1eeda7b7)) + ## v2.4.1 (2024-07-11) ### Puter diff --git a/tools/gen-release-notes.js b/tools/gen-release-notes.js index 5f9b519714..e2f1e0271b 100644 --- a/tools/gen-release-notes.js +++ b/tools/gen-release-notes.js @@ -21,10 +21,10 @@ import { simpleGit } from 'simple-git'; const REPO_URL = 'https://github.com/HeyPuter/puter'; const params = { - from: 'v2.4.0', + from: 'v2.4.1', // from: 'v2.4.0', - to: 'v2.4.1', - date: '2024-07-11', + to: 'v2.4.2', + date: '2024-07-22', }; const git = simpleGit(); @@ -72,6 +72,9 @@ const scopes = { tools: { ignore: true, }, + security: { + label: 'Security', + }, }; const scope_aliases = { @@ -80,6 +83,15 @@ const scope_aliases = { parsely: 'phoenix', }; +const complicated_cases = [ + function fix_i18n ({ commit, meta }) { + if ( meta.type === 'fix' && meta.scope === 'i18n' ) { + meta.type = 'i18n'; + meta.scope = undefined; + } + } +]; + const retro_prefixes_0 = { i18n: [ '883601142873f10d69c84874499065a7d29af054', @@ -95,15 +107,43 @@ const retro_prefixes_0 = { '8440f566b91c9eb4f01addcb850061e3fbe3afc7', '92abc9947f811f94f17a5ee5a4b73ee2b210900a', 'cff488f4f4378ca6c7568a585a665f2a3b87b89c', - + '3b8af7cc5c1be8ed67be827360bbfe0f0b5027e9', + '84e31eff2f58584d8fab7dd10606f2f6ced933a2', + '81781f80afc07cd1e6278906cdc68c8092fbfedf', + '56820cf6ee56ff810a6b495a281ccbb2e7f9d8fb', + '69a80ab3d2c94ee43d96021c3bcbdab04a4b5dc6', + '8e297cd7e30757073e2f96593c363a273b639466', + '151527825f1eb4b060aaf97feb7d18af4fcddbf2', + '8bece96f6224a060d5b408e08c58865fadb8b79c', + '333d6e3b651e460caca04a896cbc8c175555b79b', + '8a3d0430f39f872b8a460c344cce652c340b700b', + 'b9e73b7288aebb14e6bbf1915743e9157fc950b1', + 'c2d3d69dbe33f36fcae13bcbc8e2a31a86025af9', + '382fb24dbb1737a8a54ed2491f80b2e2276cde61', ], fix: [ '535475b3c36a37e3319ed067a24fb671790dcda3', + '45f131f8eaf94cf3951ca7ffeb6f311590233b8a', + '02e1b1e8f5f8e22d7ab39ebff99f7dd8e08a4221', ], doc: [ '338004474f078a00608af1d0ebf8a7f9534bad28', '6c4c73a9e85ff8eb5e7663dcce11f4d1f824032b', + 'c19c18bfcf163b37e3d173b8fa50393dfb9f540f', + ], + feat: [ + '8e7306c23be01ee6c31cdb4c99f2fb1f71a2247f', ], + meta: [ + 'b3c1b128e2d8519bc816cdcd3220c8f40e05bb01', + '452b7495b1736df90bc748dbf818407488875754', + ], +}; + +const message_changes = { + '1f7f094282fae915a2436701cfb756444cd3f781': 'feat: add new file templates', + '64e4299ac0a4c9e1de7a9d089e2d7529a9530818': 'doc: docker instructions for Windows', + 'f897e844989083b0b369ba0ce4d2c5a9f3db5ad8': 'fix: #432', }; const retro_prefixes = {}; @@ -122,12 +162,18 @@ const ensure_scope = name => { }; for ( const commit of commits ) { + if ( message_changes.hasOwnProperty(commit.hash) ) { + commit.message = message_changes[commit.hash]; + } if ( retro_prefixes.hasOwnProperty(commit.hash) ) { commit.message = retro_prefixes[commit.hash] + ': ' + commit.message; } const meta = parse_conventional_commit(commit.message); if ( ! meta ) continue; + for ( const transformer of complicated_cases ) { + transformer({ commit, meta }); + } let scope = meta.scope ?? 'puter'; while ( scope in scope_aliases ) { scope = scope_aliases[scope]; @@ -145,7 +191,7 @@ for ( const commit of commits ) { } let s = ''; -s += `## ${params.from} (${params.date})\n\n`; +s += `## ${params.to} (${params.date})\n\n`; for ( const scope_name in data ) { const scope = data[scope_name]; s += `### ${scopes[scope_name].label}\n\n`; From cc0800d60a4338d9b80dff6f11a013b863952daf Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Mon, 22 Jul 2024 19:43:50 -0700 Subject: [PATCH 0593/2119] Remove unnecessary `console.log` calls --- src/gui/src/helpers.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/gui/src/helpers.js b/src/gui/src/helpers.js index 27de886399..c4da072471 100644 --- a/src/gui/src/helpers.js +++ b/src/gui/src/helpers.js @@ -852,14 +852,12 @@ window.available_templates = async () => { const files = await puter.fs.readdir(baseRoute) const hasTemplateFolder = files.find(file => lowerCaseKeywords.includes(file.name.toLowerCase())) - console.log(hasTemplateFolder) if(!hasTemplateFolder){ return [] } const hasTemplateFiles = await puter.fs.readdir(baseRoute + "/" + hasTemplateFolder.name) - console.log(hasTemplateFiles) if(hasTemplateFiles.length == 0) { return [] @@ -868,8 +866,6 @@ window.available_templates = async () => { let result = [] hasTemplateFiles.forEach(element => { - console.log(element) - const extIndex = element.name.lastIndexOf('.'); const name = extIndex === -1 ? element.name @@ -882,7 +878,6 @@ window.available_templates = async () => { const _path = path.join( baseRoute, hasTemplateFolder.name, element.name); - console.log(_path) const itemStructure = { path: _path, html: `${extension.toUpperCase()} ${name}`, From 5d5f5660b4020650b68b79ccf3860d3fb0bf98a9 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 24 Jul 2024 01:52:07 -0400 Subject: [PATCH 0594/2119] feat: add options to disable winston and devwatch --- src/backend/src/SelfHostedModule.js | 2 ++ src/backend/src/services/runtime-analysis/LogService.js | 1 + 2 files changed, 3 insertions(+) diff --git a/src/backend/src/SelfHostedModule.js b/src/backend/src/SelfHostedModule.js index 0e21c196a2..bc4a5183a8 100644 --- a/src/backend/src/SelfHostedModule.js +++ b/src/backend/src/SelfHostedModule.js @@ -34,6 +34,8 @@ class SelfHostedModule extends AdvancedBase { const DevWatcherService = require('./services/DevWatcherService'); const path_ = require('path'); + + if ( ! config.no_devwatch ) services.registerService('__dev-watcher', DevWatcherService, { root: path_.resolve(__dirname, '../../../'), commands: [ diff --git a/src/backend/src/services/runtime-analysis/LogService.js b/src/backend/src/services/runtime-analysis/LogService.js index 8566513b17..860b29a195 100644 --- a/src/backend/src/services/runtime-analysis/LogService.js +++ b/src/backend/src/services/runtime-analysis/LogService.js @@ -339,6 +339,7 @@ class LogService extends BaseService { let logger; + if ( ! config.no_winston ) logger = new WinstonLogger( winston.createLogger({ levels: WINSTON_LEVELS, From fa9cc8efcfda5e573c73841ae49c423879e5fcd8 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 24 Jul 2024 02:31:45 -0400 Subject: [PATCH 0595/2119] fix: prevent large logs from service events (1) --- src/backend/src/services/BroadcastService.js | 5 ++++- src/backend/src/services/WebServerService.js | 7 ++++++- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/backend/src/services/BroadcastService.js b/src/backend/src/services/BroadcastService.js index 81266c2594..45a468a5f1 100644 --- a/src/backend/src/services/BroadcastService.js +++ b/src/backend/src/services/BroadcastService.js @@ -119,8 +119,11 @@ class BroadcastService extends BaseService { } } - async ['__on_install.websockets'] (_, { server }) { + async ['__on_install.websockets'] () { const svc_event = this.services.get('event'); + const svc_webServer = this.services.get('web-server'); + + const server = svc_webServer.get_server(); const io = require('socket.io')(server, { cors: { origin: '*' }, diff --git a/src/backend/src/services/WebServerService.js b/src/backend/src/services/WebServerService.js index c149a37266..1dc68cf405 100644 --- a/src/backend/src/services/WebServerService.js +++ b/src/backend/src/services/WebServerService.js @@ -189,7 +189,12 @@ class WebServerService extends BaseService { }); }); - await this.services.emit('install.websockets', { server }); + this.server_ = server; + await this.services.emit('install.websockets'); + } + + get_server () { + return this.server_; } async _init () { From 48c819ac7317c928c12f55ba9ded6a63b0afbd29 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 24 Jul 2024 13:35:26 -0400 Subject: [PATCH 0596/2119] chore: update SLA for chat model Resolves: #630 --- src/backend/src/services/sla/SLAService.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/src/services/sla/SLAService.js b/src/backend/src/services/sla/SLAService.js index 9a49547af8..58975f269a 100644 --- a/src/backend/src/services/sla/SLAService.js +++ b/src/backend/src/services/sla/SLAService.js @@ -102,7 +102,7 @@ class SLAService extends BaseService { max: 40, period: 30000, }, - monthly_limit: 1000, + monthly_limit: 3000, }, 'driver:impl:public-openai-image-generation:generate': { rate_limit: { From 22d71348021e28803a7e5f450c0816ef87275ac6 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 24 Jul 2024 12:36:19 -0700 Subject: [PATCH 0597/2119] Pass `window.crossOriginIsolated` value to the popup --- src/puter-js/src/modules/Auth.js | 3 +-- src/puter-js/src/modules/PuterDialog.js | 2 +- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/puter-js/src/modules/Auth.js b/src/puter-js/src/modules/Auth.js index 7c877bbe2c..5963feaf9c 100644 --- a/src/puter-js/src/modules/Auth.js +++ b/src/puter-js/src/modules/Auth.js @@ -45,13 +45,12 @@ class Auth{ signIn = () =>{ return new Promise((resolve, reject) => { let msg_id = this.#messageID++; - let w = 600; let h = 600; let title = 'Puter'; var left = (screen.width/2)-(w/2); var top = (screen.height/2)-(h/2); - window.open(puter.defaultGUIOrigin + '/action/sign-in?embedded_in_popup=true&msg_id=' + msg_id, + window.open(puter.defaultGUIOrigin + '/action/sign-in?embedded_in_popup=true&msg_id=' + msg_id + (window.crossOriginIsolated ? '&cross_origin_isolated=true' : ''), title, 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, width='+w+', height='+h+', top='+top+', left='+left); diff --git a/src/puter-js/src/modules/PuterDialog.js b/src/puter-js/src/modules/PuterDialog.js index 8be194176c..b1e039a461 100644 --- a/src/puter-js/src/modules/PuterDialog.js +++ b/src/puter-js/src/modules/PuterDialog.js @@ -347,7 +347,7 @@ class PuterDialog extends HTMLElement { let title = 'Puter'; var left = (screen.width/2)-(w/2); var top = (screen.height/2)-(h/2); - window.open(puter.defaultGUIOrigin + '/?embedded_in_popup=true&request_auth=true', + window.open(puter.defaultGUIOrigin + '/?embedded_in_popup=true&request_auth=true' + (window.crossOriginIsolated ? '&cross_origin_isolated=true' : ''), title, 'toolbar=no, location=no, directories=no, status=no, menubar=no, scrollbars=no, resizable=no, copyhistory=no, width='+w+', height='+h+', top='+top+', left='+left); }) From bef38dfc96c2374f82b777e7380f37dfa06b9470 Mon Sep 17 00:00:00 2001 From: Zac0511 Date: Wed, 24 Jul 2024 22:24:19 +0200 Subject: [PATCH 0598/2119] meta: Create config.yml to add Puter Discord to the issue screen (#631) This adds a config file which will show the Puter Discord Server in the issue menu, allowing users to quickly ask help on the Puter Discord --- .github/ISSUE_TEMPLATE/config.yml | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .github/ISSUE_TEMPLATE/config.yml diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..eff1dcb3d9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,5 @@ +blank_issues_enabled: true +contact_links: + - name: Puter Discord + url: https://discord.gg/PQcx7Teh8u + about: Chat on Puter's Discord, find help, share your apps, etc... From 9250e23d96f85d55fc12f0474a1d504b34d7fd64 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 24 Jul 2024 16:34:33 -0700 Subject: [PATCH 0599/2119] Update meta.md --- .github/ISSUE_TEMPLATE/meta.md | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/.github/ISSUE_TEMPLATE/meta.md b/.github/ISSUE_TEMPLATE/meta.md index ac68debee1..8563f218eb 100644 --- a/.github/ISSUE_TEMPLATE/meta.md +++ b/.github/ISSUE_TEMPLATE/meta.md @@ -1,12 +1,11 @@ --- name: Meta suggestion -about: Suggest an idea for the ecosystem around Puter, its "health" files, or other meta files +about: Suggest an idea for the community and ecosystem around Puter including the metadata files title: '' labels: - idea - meta -assignees: '' - +assignees: 'jelveh' --- From d22abb36cb8be644b8627db709f6892c5c48f86c Mon Sep 17 00:00:00 2001 From: Zac0511 Date: Thu, 25 Jul 2024 12:22:24 +0200 Subject: [PATCH 0600/2119] Update README.md Added two shields displaying the repo size and latest version, and gets updated automatically --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index f8fd92e3aa..2dc4489421 100644 --- a/README.md +++ b/README.md @@ -2,6 +2,10 @@

The Internet OS! Free, Open-Source, and Self-Hostable.

+

+ GitHub repo size GitHub Release +

+

« LIVE DEMO »
From 5c49e83378318e8b82d336df0bab7d3db603dd4a Mon Sep 17 00:00:00 2001 From: Zac0511 Date: Thu, 25 Jul 2024 13:00:28 +0200 Subject: [PATCH 0601/2119] Update README.md Added the license shield --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2dc4489421..72e3bfff75 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,7 @@

The Internet OS! Free, Open-Source, and Self-Hostable.

- GitHub repo size GitHub Release + GitHub repo size GitHub Release GitHub License

From 6cfea963a0295c04fc9fae2106675ea40858d593 Mon Sep 17 00:00:00 2001 From: Zac0511 Date: Thu, 25 Jul 2024 17:33:10 +0200 Subject: [PATCH 0602/2119] Add badges Added install badges, Puter.js badges, and source Figma files --- .../compact-minimal/compact-minimal_46h.png | Bin 0 -> 3535 bytes .../compact-minimal_vector.svg | 30 +++++++++++ badges/compact/compact_46h.png | Bin 0 -> 13274 bytes badges/compact/compact_vector.svg | 49 ++++++++++++++++++ badges/cozy-minimal/cozy-minimal_64h.png | Bin 0 -> 5859 bytes badges/cozy-minimal/cozy-minimal_vector.svg | 30 +++++++++++ badges/cozy/cozy_64h.png | Bin 0 -> 14951 bytes badges/cozy/cozy_vector.svg | 44 ++++++++++++++++ badges/puter-badge.fig | Bin 0 -> 69816 bytes badges/puter.js-badge.fig | Bin 0 -> 70317 bytes badges/puter.js-compact/compact_46h.png | Bin 0 -> 14404 bytes badges/puter.js-compact/compact_vector.svg | 49 ++++++++++++++++++ badges/puter.js-cozy/js-cozy_64h.png | Bin 0 -> 15273 bytes badges/puter.js-cozy/js-cozy_vector.svg | 44 ++++++++++++++++ 14 files changed, 246 insertions(+) create mode 100644 badges/compact-minimal/compact-minimal_46h.png create mode 100644 badges/compact-minimal/compact-minimal_vector.svg create mode 100644 badges/compact/compact_46h.png create mode 100644 badges/compact/compact_vector.svg create mode 100644 badges/cozy-minimal/cozy-minimal_64h.png create mode 100644 badges/cozy-minimal/cozy-minimal_vector.svg create mode 100644 badges/cozy/cozy_64h.png create mode 100644 badges/cozy/cozy_vector.svg create mode 100644 badges/puter-badge.fig create mode 100644 badges/puter.js-badge.fig create mode 100644 badges/puter.js-compact/compact_46h.png create mode 100644 badges/puter.js-compact/compact_vector.svg create mode 100644 badges/puter.js-cozy/js-cozy_64h.png create mode 100644 badges/puter.js-cozy/js-cozy_vector.svg diff --git a/badges/compact-minimal/compact-minimal_46h.png b/badges/compact-minimal/compact-minimal_46h.png new file mode 100644 index 0000000000000000000000000000000000000000..702ce1849d84bac91b88261d46fddf50184f745b GIT binary patch literal 3535 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 JPDHLkV1j$B!%_eM literal 0 HcmV?d00001 diff --git a/badges/compact-minimal/compact-minimal_vector.svg b/badges/compact-minimal/compact-minimal_vector.svg new file mode 100644 index 0000000000..452f510fd5 --- /dev/null +++ b/badges/compact-minimal/compact-minimal_vector.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/badges/compact/compact_46h.png b/badges/compact/compact_46h.png new file mode 100644 index 0000000000000000000000000000000000000000..e84ec60751691869439d71f22fbaa06037d18775 GIT binary patch literal 13274 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 YKP(Nd0yG6G1poj507*qoM6N<$g5({Mp#T5? literal 0 HcmV?d00001 diff --git a/badges/compact/compact_vector.svg b/badges/compact/compact_vector.svg new file mode 100644 index 0000000000..75a01cd2c3 --- /dev/null +++ b/badges/compact/compact_vector.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/badges/cozy-minimal/cozy-minimal_64h.png b/badges/cozy-minimal/cozy-minimal_64h.png new file mode 100644 index 0000000000000000000000000000000000000000..a871a74fa31ea92a9413ff2e4892098927c15afd GIT binary patch literal 5859 zcmV<9798n`P)m0K5*w!~ zxNKM10v9C4!A?wkfCym621{V9fDlL+!VTsSAS5BJ_R!AG?EWvWyWi3ONZ=nvGk^cx zuiyE-*WLdj?B`m#eAO`Ylz#<;%fc;xhW#lK0AhB}ACzB2{vh=6XB~Yj4=B=%4d~A> zqlfZOK6g$++lf-E%{>ZGZUN}J1G-@CmY?16GIU(HkMMtR?rIkNY9=sL6=WYNs7j}^ zsdE~l{ms`wGw;8jag{kbJBXH|;xam^YiuXFcFVnYuI}V42_CFoE7x($(l~^#W^)>w z)6>vux8oe92}C4Pt0m2An`vJRMd?u*DBVE2sTkH@L8_L{H39AG0we-fiUp?6ob{uyVl=C2C_m0i0>ar@3)K~qXU$|)R?NFDiC`7s&U z0#z(wgR*9jcnx3L2a^Wnaj8~LqG2^`Q1yaUEn^j13<;vaW@k&-yLT$KHX6O5+kpoi zdN^!*>ACxH=^w6oFU-vRHjLggKFOAU8{Fck?1IKX=9MIKXnztbQ~}P7K?Np1-6!O; zkaelZ+6ml)A$KrU8eoNvdlPCznerDcT!?e}>Y-&1hr;^`m@Ur}MrqgRC`cS9Dv^0| zG^TtmwqRKTm9uGZ@E8)c$XNXdLs*9Xd|%FTOB^fXpcH}mne^dj>05|$f9_hc0!#Jz zG+zmRFB4XkNZBKRox#A#mW+A*SJ#;Gs=&rnvxzh988FE$6(vR| z8ui|Aznm2iQ6Hz8(>{&z!CysD2nf1jQPDO|RCW%*h|P&n>KZ(V8cQ$2#$g|aV&I^t z%$Xg}!`>}Fz}D7BVRrmY(KHY39f010Pr%+oKMp+yAFus^rpLM8Htzozv|hR&TCYFm zM$b}VbU!RWED-rlR#7NR;lK)@zIt!a?NVHN`pP(V+m5$kd}0DRE=zS}`AW=NW^k`g zA%U7=zJ$JGFNFS6uZDNJX2;%yJ@@<_%i>igcOT#*t@2ZRBw1 z8a$9c2SuS~$F{{z^&`(RL7UIq&4RuVZPjz=GHQI_EQ7N4>zko_@o_F-u=H;qfHGSC zEhu{W`T6nGd)TSiC0-G($&EL|1i9L|(MS01OF-%)3)a;J`u}I^zqNGyP82)YEsv#IL?iK^RmN;2DCl4mf{JMWE>y z?}zcwm)$+5VOHhuIxBq6$(P6RnG&>?;7n6k-2&CZQIjnM4_LThB=)O;Ae~B>04-rh z04PDBl<)c9#xZ}yu6jADtA_Y&ZQV@l#>O;TE5>lJd~j8=!c7wz0~~wF%#PZrz;~#=2MP-!J6F9ZyHV|xb&3V*{44U7;3btCx z<0W~q<7x{bq)dd?Ab6Ni1)qHQW|(^B9w?jRh!vZ$r-+4oog*?x7N~zytv>NK@~X2)$ms>8 zhdzPkukgFE^a2w;#OTgj&SxaQ4X8P;+$Eey&`aeW#)3U>kQM|awSwl>pv*9A>Z!X} zkvCPNHsgV`7$5*EHl_F2Fa9YC9lWvc*b4-QiLiUW6dDKdC{Sd>TX%N5?Jyxqi)UpV& zPdWBRG(x!8K&*)VeR!8TKq>?B=OT4sjWN!s>d8sv#MX*hj%n+z&w;ME@{dR>!t10G zlWIvRXW9KD`RNzevk-5Br*RL!GR3{N*?a)iSmSykdO^Yb^>F==8Pq&ey-5qA9488$ z#Eb3H3>$bT1`b4Jm|c~X@P=u(LP@I*oyf~T@OmMssW!4C-Zo!+K&)a#iqx5@#3aqZ z$)g~1PZOnVj!~PzG+e!m2Ua>mDdD63?dxsK76=7onielZ;XArz{jg>6am?i$uaMjX z)f^fGGG2wZwJB&K5rwfrt=O5_@vJhZ#fy6&S^Sz(fuN#z;UiX-(V7grVJ=KA6!mBP ziP91sm$~MlNtwY?pYUJr`%jCHL)l6m>TZ2kt*pZ%pr#5Uwk6shTK2Fo)tpDmR)h70GV>!lU1qY*_lFC2zOnKRYAGz6*h+p>4=WQ#Z!iATM>p@A^?^!^oel<*e}OM3_ix zX)t5Chas4IqIrqZ3&qjgi*JS6{KJLI1cG7Z2^K;rOQ;~eBNQH%q;QEU4HJ!>+dH03 zo@iE<90R^Jks*SaabVeBW8ZNXnip{x5i1h|Vi$vpq5qUmN5<#yH)j^yyZHyHb_LIh zn%k4Nk}ODl1vd56e+T!+1}ifdEGT>TkFLP>Th9iV7fDjgyCaFsRgH?V4#Xt&5#&+< z_!b!g_zH`tnxcYY0z-YrT@=So{O?V~OmV?-7q+%PORd))rRGz2!mjUM9K9=C^`p*l z<`M|2iQQ_N(G|0JA_it0`}u0x`ETb^z^afDhR?YkiuynjzD!j;rkx~EXOpZQF1y)@!dbXg7$9y&tNr`9b|rV z&8wljnDOkAK0y(C?z~3$T?D}ZS_??d5C`_KDKfOB%%WPgrL@OaZT=B}S%D?4f)cVB zQi*1{(9u{NUw^&iqYRC0ZNNK4?D`Y;e>GN>u1te`Y0KuQ7CTBi%FyCaoql0`q|kfV za`()%(dCB+rT{QZMQ{f&CAD7N6u-Mi4tFa+W^nR*A~y|9kHOggtcI!oyA#@5A4O4? zWiX)5F*-8zE6HM(pBK8OCq?jTe{`^qznffOMWZb^!qTTrmVnIDvLJ)+(x=t0sjB(n zy7-{ykQ1P1@d?-=zxrcEh~Pb8`5VA#?B~~-v0{G*%#Ja6C`Dh>?JY0S!&O>duZ+*R zD8*|77ElGSP&W+}MMELv44F2Gq*kEl0U8E#K72*8gI6UW`4sK9Jx&{$>aKAYol4Vu z+z*WDh78cq#;1KmG|wVAO(EaoBQh_NlxzQLsx2daIgls6BHz0XO46sM>2xDVk!BlT zcfEN*-|-hm7ljN8l@ZL0k;qj1mGXs=mL8cSpaQ%SPO_C`V^r8I?PLIq3Sjm3FOLl~ z+n*KO1P4DNPg@kTq-j~^NtO&fb%&|>!a82Ktc(2ym;VjSIsQ*9{Xtf)x~Kw9s&R6V zqK*fa+eq_uX}ly4QPj=T7l55uxrfE}+VEmb=@cUVm}*16(v_`VTv$Fbrfn_^X}Czc ztT6V|FNXDf{5`-*7+8J{)P@#SP|z9j)u5ecNId7Bq1)r8Hp)sg4_&pmD8*`VAqA-F zgq}Gxbk0}f_`qxH)kmURgmVb=uq9)N|LOe?Q(O4ZdTmfKfZateRte+mMw;Y(DOg@ zQ`9v`eobt+kt@m@?LP3(|B)&mp>P}Da05*}_8;mc@(&s$4G!?O_{d0n6zZ^pJn&F5<{R0 z_vn}|wM#`t<5OkR7Pq)4NKyn=N?)|%hbqvP^CL;E&}B>93jjUF(_JDHrhpDY)De)X zR2`lPqL`w!cwY24j|deo(ted1$rGX0Db7P@%FvBhQct6zb}M(S|wnc>!HFd=5G>#oD6v(ldAw-30QH{swF@nBeJaUWtB}O z@~xc5gdY~(#!;bDXwXUqsP4{!Gi}C>f>(Bw`MitI_c<+QRuM(Wz9CU(oMhIsc~MW0 z5UZ<+NSjZJ)0!de52moS7mKv~#4O$Es=~vZoWFuHC&esAD0?9SK!HOSBAISee8k4V z6`zOhg-6Cg(~RUK|K&dJv^p>83-XGN#9h$c^mF&c9)b4IioZ2i(d{h-M3f8$vYC^} zhQr&u+~@!*=+*7*HZFm&dZl85vRU~QPwDSu-omHtG`;Dl5* zP@Bg%swp?dQdYp`Srx^Ho0@8c zvP75R1f)%j^t?8-80KDd3kJ*QmkJ-O#Ed$a3b^TBG{QT3fZ4!~An&QbEWJ%u{>&(>8A6ky~l|4WEELcmI79 zI`B5<#6Qi|nY$b)XeN3I9*d4$8`F*qA_RZ)NVUHAi92BW`CszE!_(2_qu_k?E?J>d zOP(!VC}#`yDQ^5M(m_~41XYPLr04feHf4|B_Z1AKF!MuupSV4?*O#1b#x&r|inl6# z!h$Mk&!jhGjpNId^zBfS1=qY56)lU9qCN-!`$KrJw+7=FJ{9Ue=~8>x|FOSFfNFj7 zp;dCmgKW-dhf?mtVTh-lSPUzkbf5MFqpYfQopArIp~X1=&u_;*byY~nKJVi1LctgVIarG2wKNWw@xb2J75WFr;*6y9 zT5mlAne?ECv@W)JM6`P?xJh`k3KX`z_V)#n=x}`Fcd2*D=@{H_!Ik&MRU0cKdPZ=? z)+-w!)d*Hmy0#_MhF4w}84s(&y^sF{x*CH_@nIa8;}>_iHn4p=rnB$ zCo&L1Bv>g3KYaFAqRR$C1E>CFq!V{|cwbMwNKA#QVk?zE{zwDNe`C@Mug>S5BjN4h z+ABw(0F_E%ixu!gcv*)aWJB_SqGfqif^z+%E8RT(@kA%Te)u;A@m zFG;AYDP9^fej^?wboHwm$sqtJk5{Ra9Kq zU0bx0mC^*hxFD)jjLM(-Y?c!wvm*EwHM*OVy?^O$3glr9R%DfsA$j73^o0#FVxY%n zY7G9_(_O=QZ(SK*Thy98-(c#aVaWWE5p`;-%OxVRJv^nYI8myi)FYxI^5R9FtJh@C z?Z4cK6J6auAbHmh6r=2{4#+H0Np+4<2)S=08gqvauqkKSw6<&8wwId=4nBnaA5QD( z?v5@qH8lnKrYBTm&F;w@-~P!w$k#FP#t%YMXUq!^?D%MyIffuQt!$7Ft`=VszLkD3 zZ|+qdC_@s#R0XCy zYI8>NjS0!RW-Y55I>v%5NIP1Ei0@%I9~sf^?jD#wG7tDbREceQa^r^h*BPLI52?xfo8KA{)&`lW@a!GFp;RGJNLlVn zW2u9dPJ;ei%9wEM)zt-!MuYfc#^QgrOtyMXGeMx^I{L&@zQ|vzK>{w5(PSdX-(*FN zZ0fj&YQ(te@|d*_QecIzlB$BbYAwbgQxMs1BT*(6K_!j}M_K%@Ke_3lYjb(`Q9!tk zTzblTYXzOhIb{`7UdodU162ImBvY&Hk4|+bLM>ZhXZ5+iabbm8+Uqe6G}a{#Gw8^Y tV3}n!xI6z^KQUAP#>-pMA57=h{{v~3|Ig`9H|_uc002ovPDHLkV1m2|O)mfd literal 0 HcmV?d00001 diff --git a/badges/cozy-minimal/cozy-minimal_vector.svg b/badges/cozy-minimal/cozy-minimal_vector.svg new file mode 100644 index 0000000000..fa67584571 --- /dev/null +++ b/badges/cozy-minimal/cozy-minimal_vector.svg @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/badges/cozy/cozy_64h.png b/badges/cozy/cozy_64h.png new file mode 100644 index 0000000000000000000000000000000000000000..0c3d51960c410f12ad4bda3fee1f1ae8365092ed GIT binary patch literal 14951 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 lH*M% + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/badges/puter-badge.fig b/badges/puter-badge.fig new file mode 100644 index 0000000000000000000000000000000000000000..67d7fba52a673a282104ac947eb5145366750cfb GIT binary patch literal 69816 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�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

$yDbj#qWQ*7N2BGxE#VR-f0jx5ui7+3kVT)jk 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 BJpBLw literal 0 HcmV?d00001 diff --git a/badges/puter.js-badge.fig b/badges/puter.js-badge.fig new file mode 100644 index 0000000000000000000000000000000000000000..3f6d40b3fedc4dedce207c020f882783b7f714ba GIT binary patch literal 70317 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 SiXDK3aiubffQ6s&0Q?IdRlYa? literal 0 HcmV?d00001 diff --git a/badges/puter.js-compact/compact_46h.png b/badges/puter.js-compact/compact_46h.png new file mode 100644 index 0000000000000000000000000000000000000000..5ced917f0b5e2f94791e89c41c2276e2c214b353 GIT binary patch literal 14404 zcmV-KIJ?J*P)fB%$eult-)tH0TcyR8T-{Q~~EFJQ1B41r?s70!nxw5UQYt zB0TB(5Tw|EB#4EMBO@tDNxAo?CuhxGd#|?7_eI|vxc7eFIs5Fr_A38X_C6;FJ&xVq z`@vZN&7shN4+6mseg)GHQTm%cQ2K`HH|cpOzp%7S2NAV;*0%hC5cB8UhcqPgM&&%V z2G?scUb|x|9}0b~cI5rk^QfENmwL>tqBpXn zrBjiQHdp9P(?6VJI2Gx_UVT>diHutPbxry4bn1ol_twYnx%FCr-Xq(w`};q*18kye zQYW)Ol)MP8IED}QuQ8OM8UsYeaghJy;mr$= z5M2(f@qI3GQ@LKNu^UsjEV||aZgh$_dafGZ6oxj-XI6fK|37`%9Bm@ssHRt~ttwEP9 zfHK*~gkCZ>T0MaB{zLnomK*peG7qRNL|_b|1PW~KMws?mDEa%iL;)0(|7|^MITSE< znk7V9qMn%c>Etl>9dwjX^o~R?915t?gPPtl)~Nn|7&mS#^!N2S4;uXR-6w_LEu0oKB4f4OQ_hR3n)h$B zJu+4ASK%wu^qe&}MGEaPf|hz{)Op5!OlHnO;R;ZFuL}-9BCZ1B?%^t-MGz4qspyfW zh8++92ux`)>U%|V2m-=)m79=O(bfw^E1sHVw4&9>B~|3W=ZXjATvh@HhZ<<09y2Ok z0J{PNU>bs^qhwewZPZ|}loO$S#dnpV zewj3B0&F>P5_LKqad5EzYte&Ac!MbeU81PT^L8JyO-QR05T+P|08WR-;j^Gjgi2 zLdXf&m4D}PvD}9$Yb-F{a%Cd)(igTa1S`wx=#baqMW8!0QmiGyapgJULO|Cav+Mx`GdGXTx1S7jXGj*7@t$&@78Se&Rd2(l?ED@u)Ec4@E} zl>>V*&cpVq-*S(8K_gCS)Kd}`TePAYXLJMukbbcCZ~~ZWe6?q*4Nrg=B7;Jx4X*g@ z`53PvJ5T`&&E?reMV$}{U;r#*C?Z7l2xJ1pdAdbL{LK7m5heDiL&Z>p9LKfqh?Eky zLyHGNCjuMeN9CiqPen2XA%e&~bBMu4TShAMsKBX~QPd}FN1b*#1QV(kP1E4|^&4

BmEv@af6EcD#XiTg0oznI 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/badges/puter.js-cozy/js-cozy_64h.png b/badges/puter.js-cozy/js-cozy_64h.png new file mode 100644 index 0000000000000000000000000000000000000000..0d920437094416602cdf2744727f26eb92db9ccb GIT binary patch literal 15273 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

-zHM-^(;%2MBA1md-YoSyez&puh37{6r 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

Y3}7sp zAfD7&1!rT@gZ|_vY{xq>J9~+$dA)o~4<;y`o}lkq!X%&xueE}}K + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + From f30bbbd3750f03a6f9141cc639706fbc705460fe Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 25 Jul 2024 14:48:12 -0700 Subject: [PATCH 0603/2119] Add translation template for Kurdish --- src/gui/src/i18n/translations/ku.js | 352 ++++++++++++++++++ src/gui/src/i18n/translations/translations.js | 2 + 2 files changed, 354 insertions(+) create mode 100644 src/gui/src/i18n/translations/ku.js diff --git a/src/gui/src/i18n/translations/ku.js b/src/gui/src/i18n/translations/ku.js new file mode 100644 index 0000000000..fb70861d8d --- /dev/null +++ b/src/gui/src/i18n/translations/ku.js @@ -0,0 +1,352 @@ +/** + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ + + +const en = { + name: "کوردی", + english_name: "Kurdish", + code: "ku", + dictionary: { + about: "About", + account: "Account", + account_password: "Verify Account Password", + access_granted_to: "Access Granted To", + add_existing_account: "Add Existing Account", + all_fields_required: 'All fields are required.', + allow: 'Allow', + apply: "Apply", + ascending: 'Ascending', + associated_websites: "Associated Websites", + auto_arrange: 'Auto Arrange', + background: "Background", + browse: "Browse", + cancel: 'Cancel', + center: 'Center', + change_desktop_background: 'Change desktop background…', + change_email: "Change Email", + change_language: "Change Language", + change_password: "Change Password", + change_ui_colors: "Change UI Colors", + change_username: "Change Username", + close: 'Close', + close_all_windows: "Close All Windows", + close_all_windows_confirm: "Are you sure you want to close all windows?", + close_all_windows_and_log_out: 'Close Windows and Log Out', + change_always_open_with: "Do you want to always open this type of file with", + color: 'Color', + confirm: 'Confirm', + confirm_2fa_setup: 'I have added the code to my authenticator app', + confirm_2fa_recovery: 'I have saved my recovery codes in a secure location', + confirm_account_for_free_referral_storage_c2a: 'Create an account and confirm your email address to receive 1 GB of free storage. Your friend will get 1 GB of free storage too.', + confirm_code_generic_incorrect: "Incorrect Code.", + confirm_code_generic_too_many_requests: "Too many requests. Please wait a few minutes.", + confirm_code_generic_submit: "Submit Code", + confirm_code_generic_try_again: "Try Again", + confirm_code_generic_title: "Enter Confirmation Code", + confirm_code_2fa_instruction: "Enter the 6-digit code from your authenticator app.", + confirm_code_2fa_submit_btn: "Submit", + confirm_code_2fa_title: "Enter 2FA Code", + confirm_delete_multiple_items: 'Are you sure you want to permanently delete these items?', + confirm_delete_single_item: 'Do you want to permanently delete this item?', + confirm_open_apps_log_out: 'You have open apps. Are you sure you want to log out?', + confirm_new_password: "Confirm New Password", + confirm_delete_user: "Are you sure you want to delete your account? All your files and data will be permanently deleted. This action cannot be undone.", + confirm_delete_user_title: "Delete Account?", + confirm_session_revoke: "Are you sure you want to revoke this session?", + confirm_your_email_address: "Confirm Your Email Address", + contact_us: "Contact Us", + contact_us_verification_required: "You must have a verified email address to use this.", + contain: 'Contain', + continue: "Continue", + copy: 'Copy', + copy_link: "Copy Link", + copying: "Copying", + copying_file: "Copying %%", + cover: 'Cover', + create_account: "Create Account", + create_free_account: "Create Free Account", + create_shortcut: "Create Shortcut", + credits: "Credits", + current_password: "Current Password", + cut: 'Cut', + clock: "Clock", + clock_visible_hide: 'Hide - Always hidden', + clock_visible_show: 'Show - Always visible', + clock_visible_auto: 'Auto - Default, visible only in full-screen mode.', + close_all: 'Close All', + created: 'Created', + date_modified: 'Date modified', + default: 'Default', + delete: 'Delete', + delete_account: "Delete Account", + delete_permanently: "Delete Permanently", + deleting_file: "Deleting %%", + deploy_as_app: 'Deploy as app', + descending: 'Descending', + desktop: 'Desktop', + desktop_background_fit: "Fit", + developers: "Developers", + dir_published_as_website: `%strong% has been published to:`, + disable_2fa: 'Disable 2FA', + disable_2fa_confirm: "Are you sure you want to disable 2FA?", + disable_2fa_instructions: "Enter your password to disable 2FA.", + disassociate_dir: "Disassociate Directory", + documents: 'Documents', + dont_allow: 'Don\'t Allow', + download: 'Download', + download_file: 'Download File', + downloading: "Downloading", + email: "Email", + email_change_confirmation_sent: "A confirmation email has been sent to your new email address. Please check your inbox and follow the instructions to complete the process.", + email_invalid: 'Email is invalid.', + email_or_username: "Email or Username", + email_required: 'Email is required.', + empty_trash: 'Empty Trash', + empty_trash_confirmation: `Are you sure you want to permanently delete the items in Trash?`, + emptying_trash: 'Emptying Trash…', + enable_2fa: 'Enable 2FA', + end_hard: "End Hard", + end_process_force_confirm: "Are you sure you want to force-quit this process?", + end_soft: "End Soft", + enlarged_qr_code: "Enlarged QR Code", + enter_password_to_confirm_delete_user: "Enter your password to confirm account deletion", + error_message_is_missing: "Error message is missing.", + error_unknown_cause: "An unknown error occurred.", + error_uploading_files: "Failed to upload files", + favorites: "Favorites", + feedback: "Feedback", + feedback_c2a: "Please use the form below to send us your feedback, comments, and bug reports.", + feedback_sent_confirmation: "Thank you for contacting us. If you have an email associated with your account, you will hear back from us as soon as possible.", + fit: "Fit", + folder: 'Folder', + force_quit: 'Force Quit', + forgot_pass_c2a: "Forgot password?", + from: "From", + general: "General", + get_a_copy_of_on_puter: `Get a copy of '%%' on Puter.com!`, + get_copy_link: 'Get Copy Link', + hide_all_windows: "Hide All Windows", + home: 'Home', + html_document: 'HTML document', + hue: 'Hue', + image: 'Image', + incorrect_password: "Incorrect password", + invite_link: "Invite Link", + item: 'item', + items_in_trash_cannot_be_renamed: `This item can't be renamed because it's in the trash. To rename this item, first drag it out of the Trash.`, + jpeg_image: 'JPEG image', + keep_in_taskbar: 'Keep in Taskbar', + language: "Language", + license: "License", + lightness: 'Lightness', + link_copied: "Link copied", + loading: 'Loading', + log_in: "Log In", + log_into_another_account_anyway: 'Log into another account anyway', + log_out: 'Log Out', + looks_good: "Looks good!", + manage_sessions: "Manage Sessions", + menubar_style: "Menubar Style", + menubar_style_desktop: "Desktop", + menubar_style_system: "System", + menubar_style_window: "Window", + modified: 'Modified', + move: 'Move', + moving_file: "Moving %%", + my_websites: "My Websites", + name: 'Name', + name_cannot_be_empty: 'Name cannot be empty.', + name_cannot_contain_double_period: "Name can not be the '..' character.", + name_cannot_contain_period: "Name can not be the '.' character.", + name_cannot_contain_slash: "Name cannot contain the '/' character.", + name_must_be_string: "Name can only be a string.", + name_too_long: `Name can not be longer than %% characters.`, + new: 'New', + new_email: 'New Email', + new_folder: 'New folder', + new_password: "New Password", + new_username: "New Username", + no: 'No', + no_dir_associated_with_site: 'No directory associated with this address.', + no_websites_published: "You have not published any websites yet. Right click on a folder to get started.", + ok: 'OK', + open: "Open", + open_in_new_tab: "Open in New Tab", + open_in_new_window: "Open in New Window", + open_with: "Open With", + original_name: 'Original Name', + original_path: 'Original Path', + oss_code_and_content: "Open Source Software and Content", + password: "Password", + password_changed: "Password changed.", + password_recovery_rate_limit: "You've reached our rate-limit; please wait a few minutes. To prevent this in the future, avoid reloading the page too many times.", + password_recovery_token_invalid: "This password recovery token is no longer valid.", + password_recovery_unknown_error: "An unknown error occurred. Please try again later.", + password_required: 'Password is required.', + password_strength_error: "Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, one number, and one special character.", + passwords_do_not_match: '`New Password` and `Confirm New Password` do not match.', + paste: 'Paste', + paste_into_folder: "Paste Into Folder", + path: 'Path', + personalization: "Personalization", + pick_name_for_website: "Pick a name for your website:", + picture: "Picture", + pictures: 'Pictures', + plural_suffix: 's', + powered_by_puter_js: `Powered by {{link=docs}}Puter.js{{/link}}`, + preparing: "Preparing...", + preparing_for_upload: "Preparing for upload...", + print: 'Print', + privacy: "Privacy", + proceed_to_login: 'Proceed to login', + proceed_with_account_deletion: "Proceed with Account Deletion", + process_status_initializing: "Initializing", + process_status_running: "Running", + process_type_app: 'App', + process_type_init: 'Init', + process_type_ui: 'UI', + properties: "Properties", + public: 'Public', + publish: "Publish", + publish_as_website: 'Publish as website', + puter_description: `Puter is a privacy-first personal cloud to keep all your files, apps, and games in one secure place, accessible from anywhere at any time.`, + reading_file: "Reading %strong%", + recent: "Recent", + recommended: "Recommended", + recover_password: "Recover Password", + refer_friends_c2a: "Get 1 GB for every friend who creates and confirms an account on Puter. Your friend will get 1 GB too!", + refer_friends_social_media_c2a: `Get 1 GB of free storage on Puter.com!`, + refresh: 'Refresh', + release_address_confirmation: `Are you sure you want to release this address?`, + remove_from_taskbar:'Remove from Taskbar', + rename: 'Rename', + repeat: 'Repeat', + replace: 'Replace', + replace_all: 'Replace All', + resend_confirmation_code: "Re-send Confirmation Code", + reset_colors: "Reset Colors", + restart_puter_confirm: "Are you sure you want to restart Puter?", + restore: "Restore", + save: 'Save', + saturation: 'Saturation', + save_account: 'Save account', + save_account_to_get_copy_link: "Please create an account to proceed.", + save_account_to_publish: 'Please create an account to proceed.', + save_session: 'Save session', + save_session_c2a: 'Create an account to save your current session and avoid losing your work.', + scan_qr_c2a: 'Scan the code below\nto log into this session from other devices', + scan_qr_2fa: 'Scan the QR code with your authenticator app', + scan_qr_generic: 'Scan this QR code using your phone or another device', + search: 'Search', + seconds: 'seconds', + security: "Security", + select: "Select", + selected: 'selected', + select_color: 'Select color…', + sessions: "Sessions", + send: "Send", + send_password_recovery_email: "Send Password Recovery Email", + session_saved: "Thank you for creating an account. This session has been saved.", + settings: "Settings", + set_new_password: "Set New Password", + share: "Share", + share_to: "Share to", + share_with: "Share with:", + shortcut_to: "Shortcut to", + show_all_windows: "Show All Windows", + show_hidden: 'Show hidden', + sign_in_with_puter: "Sign in with Puter", + sign_up: "Sign Up", + signing_in: "Signing in…", + size: 'Size', + skip: 'Skip', + something_went_wrong: "Something went wrong.", + sort_by: 'Sort by', + start: 'Start', + status: "Status", + storage_usage: "Storage Usage", + storage_puter_used: 'used by Puter', + taking_longer_than_usual: 'Taking a little longer than usual. Please wait...', + task_manager: "Task Manager", + taskmgr_header_name: "Name", + taskmgr_header_status: "Status", + taskmgr_header_type: "Type", + terms: "Terms", + text_document: 'Text document', + tos_fineprint: `By clicking 'Create Free Account' you agree to Puter's {{link=terms}}Terms of Service{{/link}} and {{link=privacy}}Privacy Policy{{/link}}.`, + transparency: "Transparency", + trash: 'Trash', + two_factor: 'Two Factor Authentication', + two_factor_disabled: '2FA Disabled', + two_factor_enabled: '2FA Enabled', + type: 'Type', + type_confirm_to_delete_account: "Type 'confirm' to delete your account.", + ui_colors: "UI Colors", + ui_manage_sessions: "Session Manager", + ui_revoke: "Revoke", + undo: 'Undo', + unlimited: 'Unlimited', + unzip: "Unzip", + upload: 'Upload', + upload_here: 'Upload here', + usage: 'Usage', + username: "Username", + username_changed: 'Username updated successfully.', + username_required: 'Username is required.', + versions: "Versions", + videos: 'Videos', + visibility: 'Visibility', + yes: 'Yes', + yes_release_it: 'Yes, Release It', + you_have_been_referred_to_puter_by_a_friend: "You have been referred to Puter by a friend!", + zip: "Zip", + zipping_file: "Zipping %strong%", + + // === 2FA Setup === + setup2fa_1_step_heading: 'Open your authenticator app', + setup2fa_1_instructions: ` + You can use any authenticator app that supports the Time-based One-Time Password (TOTP) protocol. + There are many to choose from, but if you're unsure + Authy + is a solid choice for Android and iOS. + `, + setup2fa_2_step_heading: 'Scan the QR code', + setup2fa_3_step_heading: 'Enter the 6-digit code', + setup2fa_4_step_heading: 'Copy your recovery codes', + setup2fa_4_instructions: ` + These recovery codes are the only way to access your account if you lose your phone or can't use your authenticator app. + Make sure to store them in a safe place. + `, + setup2fa_5_step_heading: 'Confirm 2FA setup', + setup2fa_5_confirmation_1: 'I have saved my recovery codes in a secure location', + setup2fa_5_confirmation_2: 'I am ready to enable 2FA', + setup2fa_5_button: 'Enable 2FA', + + // === 2FA Login === + login2fa_otp_title: 'Enter 2FA Code', + login2fa_otp_instructions: 'Enter the 6-digit code from your authenticator app.', + login2fa_recovery_title: 'Enter a recovery code', + login2fa_recovery_instructions: 'Enter one of your recovery codes to access your account.', + login2fa_use_recovery_code: 'Use a recovery code', + login2fa_recovery_back: 'Back', + login2fa_recovery_placeholder: 'XXXXXXXX', + } +}; + +export default en; \ No newline at end of file diff --git a/src/gui/src/i18n/translations/translations.js b/src/gui/src/i18n/translations/translations.js index 6e8ba73625..cef1bc15c5 100644 --- a/src/gui/src/i18n/translations/translations.js +++ b/src/gui/src/i18n/translations/translations.js @@ -33,6 +33,7 @@ import it from './it.js'; import ig from './ig.js'; import ja from './ja.js'; import ko from './ko.js'; +import ku from './ku.js'; import nb from './nb.js'; import nl from './nl.js'; import nn from './nn.js'; @@ -71,6 +72,7 @@ export default { ig, ja, ko, + ku, nb, nl, nn, From 5fee393b67d4437da0f08826d4cf304e0033774e Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 25 Jul 2024 18:01:00 -0400 Subject: [PATCH 0604/2119] data: add startup and shutdown chimes --- src/gui/src/audio/puter_bedtime.mp3 | Bin 0 -> 50805 bytes src/gui/src/audio/puter_chime.mp3 | Bin 0 -> 67001 bytes 2 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/gui/src/audio/puter_bedtime.mp3 create mode 100644 src/gui/src/audio/puter_chime.mp3 diff --git a/src/gui/src/audio/puter_bedtime.mp3 b/src/gui/src/audio/puter_bedtime.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..b094dded0edb4a37341878e6a0cd52c4931a53ac GIT binary patch literal 50805 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 literal 0 HcmV?d00001 diff --git a/src/gui/src/audio/puter_chime.mp3 b/src/gui/src/audio/puter_chime.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..bf7c216d4247f9ae325709e3dfa917723cb92bb2 GIT binary patch literal 67001 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 Date: Thu, 25 Jul 2024 18:28:16 -0400 Subject: [PATCH 0605/2119] data: add extra sound --- src/gui/src/audio/puter_theme_song.mp3 | Bin 0 -> 175670 bytes 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/gui/src/audio/puter_theme_song.mp3 diff --git a/src/gui/src/audio/puter_theme_song.mp3 b/src/gui/src/audio/puter_theme_song.mp3 new file mode 100644 index 0000000000000000000000000000000000000000..114c6198fce8ffeb7411b0fff683bb7f066d580d GIT binary patch literal 175670 zcmeF&=Tj4J_%84b1PBn2PUxXZHxvO8kluTfPUu~_fQW_;5_%0qdhZ=XkluSoK#*Rf z3W$nw{QhRnoH;Y+PdNJ`nc2;&%{`yznrolE|D7if{Qu+s-vQwMcb+W(V7J+7FCdUu zGNBRQOAr993dX5D9Yyk+lzmkg_3th*QzSa`)FF|FymZN9C|uBx-?CBt7z&`IIp}zc=q5$i~K|`WyZGeN+knBKhP2=05$qe{cC`eQla(lKIWq z{ok+M1DPBs01|$h72FkN`MV3{UO@fFPb_K^z*Ty~$awz%z>x+8-YVmwq#+L?kq`io zmgnG|tA|2BfS9^%8gsP6sq>{#8hi2va{S-%=YEj-(@&Moi=ZKTEie_tD;TA#_Jpl| za7UNpoqUqAH7SX2EcEOzvGU-q0*xXPh0!74kzC|p=R>_KA-(!}!(rXkOK1CWoDqT6 zn+`7t3z8_;ub{GcXfx@XZF_=`9+gl_^0Adwcr=wFkf<6mv)HYRKPJR$RMAlS;N@iR zJG-=>?~23z^a_2n&^Y-d_$k-#s^pP`+I0lpQUJ}Ki*if+Cso~);=?TKtgd5Wjvs{2 z=AFgkSMw#-YR@iIF382kzf94k7a~qXBk&TeKK{C=3+|Mki`yPi&%MXa)O&UgLTH1) zSpWVGq6uk023HcIKd;NF3T6O)a1&srG_1$OJ2bIJ$sntp5HtdHb06b<>?!)YoUB}t zEo|xS_FXh3Kw|?4adP;(_#(70E*@U*5MCJ+HQE!IYec;FzYA=M@vrV*EDqTr0jceu zh?6P+hSR6R#~$B(_P{oHg4c1pn2RA|*99KEB$6J)rPi0x7`Nt8fM;kb!xN!ae(qed zqBGT|L2a=(f6%BiRq6U7Q)Joo#ZtKgW7Fz~*YMGU#+4=ij@l4gImGa5@S^Gc^6% ziVQjo)*}O|MA>v#&cuM5H+O7n{B!r@_yTK^&4ecCRgrb`gP`puJB{cRFXB=3 YM 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

KVeQ8-A9kXS{NO%%8ALcW^%2VN=T4HCLt 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 literal 0 HcmV?d00001 From 2cd68100d2683ccd2f4f96b107bf96240b9c81aa Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 17 Jul 2024 23:20:26 -0400 Subject: [PATCH 0606/2119] refactor: add traits and services as drivers --- src/backend/src/CoreModule.js | 3 + src/backend/src/services/Container.js | 28 ++++++- src/backend/src/services/HelloWorldService.js | 25 ++++++ src/backend/src/services/RegistryService.js | 14 ++++ src/backend/src/services/SelfhostedService.js | 1 - .../src/services/drivers/DriverService.js | 84 +++++++++++++++---- src/puter-js-common/src/AdvancedBase.js | 1 + src/puter-js-common/src/bases/FeatureBase.js | 11 +-- .../src/features/TraitsFeature.js | 20 +++++ 9 files changed, 164 insertions(+), 23 deletions(-) create mode 100644 src/backend/src/services/HelloWorldService.js create mode 100644 src/puter-js-common/src/features/TraitsFeature.js diff --git a/src/backend/src/CoreModule.js b/src/backend/src/CoreModule.js index 0a28490ad2..30d5c97c42 100644 --- a/src/backend/src/CoreModule.js +++ b/src/backend/src/CoreModule.js @@ -302,6 +302,9 @@ const install = async ({ services, app, useapi }) => { const { AnomalyService } = require('./services/AnomalyService'); services.registerService('anomaly', AnomalyService); + + const { HelloWorldService } = require('./services/HelloWorldService'); + services.registerService('hello-world', HelloWorldService); } const install_legacy = async ({ services }) => { diff --git a/src/backend/src/services/Container.js b/src/backend/src/services/Container.js index d496ffecc7..d9ba8b1ecd 100644 --- a/src/backend/src/services/Container.js +++ b/src/backend/src/services/Container.js @@ -16,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ +const { AdvancedBase } = require("@heyputer/puter-js-common"); const config = require("../config"); const { Context } = require("../util/context"); const { CompositeError } = require("../util/errorutil"); @@ -26,6 +27,7 @@ class Container { constructor ({ logger }) { this.logger = logger; this.instances_ = {}; + this.implementors_ = {}; this.ready = new TeePromise(); } /** @@ -37,9 +39,24 @@ class Container { */ registerService (name, cls, args) { const my_config = config.services?.[name] || {}; - this.instances_[name] = cls.getInstance + const instance = cls.getInstance ? cls.getInstance({ services: this, config, my_config, name, args }) : new cls({ services: this, config, my_config, name, args }) ; + this.instances_[name] = instance; + + if ( !(instance instanceof AdvancedBase) ) return; + + const traits = instance.list_traits(); + for ( const trait of traits ) { + if ( ! this.implementors_[trait] ) { + this.implementors_[trait] = []; + } + this.implementors_[trait].push({ + name, + instance, + impl: instance.as(trait), + }); + } } /** * patchService allows overriding methods on a service that is already @@ -54,6 +71,15 @@ class Container { const patch_instance = new patch(); patch_instance.patch({ original_service, args }); } + + // get_implementors returns a list of implementors for the specified + // interface name. + get_implementors (interface_name) { + const internal_list = this.implementors_[interface_name]; + const clone = [...internal_list]; + return clone; + } + set (name, instance) { this.instances_[name] = instance; } get (name, opts) { if ( this.instances_[name] ) { diff --git a/src/backend/src/services/HelloWorldService.js b/src/backend/src/services/HelloWorldService.js new file mode 100644 index 0000000000..efc0a56861 --- /dev/null +++ b/src/backend/src/services/HelloWorldService.js @@ -0,0 +1,25 @@ +const BaseService = require("./BaseService"); + +class HelloWorldService extends BaseService { + static IMPLEMENTS = { + ['driver-metadata']: { + get_response_meta () { + return { + driver: 'hello-world', + driver_version: 'v1.0.0', + driver_interface: 'helloworld', + }; + } + }, + helloworld: { + async greet ({ subject }) { + if ( subject ) { + return `Hello, ${subject}!`; + } + return `Hello, World!`; + } + }, + } +} + +module.exports = { HelloWorldService }; diff --git a/src/backend/src/services/RegistryService.js b/src/backend/src/services/RegistryService.js index 2b611f82df..cd966727d3 100644 --- a/src/backend/src/services/RegistryService.js +++ b/src/backend/src/services/RegistryService.js @@ -43,6 +43,10 @@ class MapCollection extends AdvancedBase { del (key) { return this.kv.del(this._mk_key(key)); } + + keys () { + return this.kv.keys(`registry:map:${this.map_id}:*`); + } _mk_key (key) { return `registry:map:${this.map_id}:${key}`; @@ -58,6 +62,16 @@ class RegistryService extends BaseService { this.collections_ = {}; } + async ['__on_boot.consolidation'] () { + const services = this.services; + await services.emit('registry.collections', { + svc_registry: this, + }); + await services.emit('registry.entries', { + svc_registry: this, + }); + } + register_collection (name) { if ( this.collections_[name] ) { throw Error(`collection ${name} already exists`); diff --git a/src/backend/src/services/SelfhostedService.js b/src/backend/src/services/SelfhostedService.js index bfc952326b..fda861d634 100644 --- a/src/backend/src/services/SelfhostedService.js +++ b/src/backend/src/services/SelfhostedService.js @@ -29,7 +29,6 @@ class SelfhostedService extends BaseService { async _init () { const svc_driver = this.services.get('driver'); - svc_driver.register_driver('helloworld', new HelloWorld()); svc_driver.register_driver('puter-kvstore', new DBKVStore()); svc_driver.register_driver('puter-apps', new EntityStoreImplementation({ service: 'es:app' })); svc_driver.register_driver('puter-subdomains', new EntityStoreImplementation({ service: 'es:subdomain' })); diff --git a/src/backend/src/services/drivers/DriverService.js b/src/backend/src/services/drivers/DriverService.js index 8dbd898e56..861957c330 100644 --- a/src/backend/src/services/drivers/DriverService.js +++ b/src/backend/src/services/drivers/DriverService.js @@ -21,6 +21,7 @@ const APIError = require("../../api/APIError"); const { DriverError } = require("./DriverError"); const { TypedValue } = require("./meta/Runtime"); const BaseService = require("../BaseService"); +const { Driver } = require("../../definitions/Driver"); /** * DriverService provides the functionality of Puter drivers. @@ -31,10 +32,30 @@ class DriverService extends BaseService { } _construct () { - this.interfaces = require('./interfaces'); + this.drivers = {}; this.interface_to_implementation = {}; } + async ['__on_registry.collections'] (_, { svc_registry }) { + svc_registry.register_collection('interfaces'); + svc_registry.register_collection('drivers'); + } + async ['__on_registry.entries'] (_, { svc_registry }) { + const services = this.services; + const col_interfaces = svc_registry.get('interfaces'); + const col_drivers = svc_registry.get('drivers'); + { + const default_interfaces = require('./interfaces'); + for ( const k in default_interfaces ) { + col_interfaces.set(k, default_interfaces[k]); + } + } + await services.emit('driver.register.interfaces', + { col_interfaces }); + await services.emit('driver.register.drivers', + { col_drivers }); + } + _init () { const svc_registry = this.services.get('registry'); svc_registry.register_collection(''); @@ -43,9 +64,27 @@ class DriverService extends BaseService { register_driver (interface_name, implementation) { this.interface_to_implementation[interface_name] = implementation; } - + get_interface (interface_name) { - return this.interfaces[interface_name]; + const o = {}; + const col_interfaces = svc_registry.get('interfaces'); + const keys = col_interfaces.keys(); + for ( const k of keys ) o[k] = col_interfaces.get(k); + return col_interfaces.get(interface_name); + } + + get_default_implementation (interface_name) { + // If there's a hardcoded implementation, use that + // (^ temporary, until all are migrated) + if (this.interface_to_implementation.hasOwnProperty(interface_name)) { + return this.interface_to_implementation[interface_name]; + } + + this.log.noticeme('HERE IT IS'); + const options = this.services.get_implementors(interface_name); + this.log.info('test', { options }); + if ( options.length < 1 ) return; + return options[0]; } async call (...a) { @@ -76,16 +115,33 @@ class DriverService extends BaseService { throw APIError.create('permission_denied'); } - const instance = this.interface_to_implementation[interface_name]; + const svc_registry = this.services.get('registry'); + const c_interfaces = svc_registry.get('interfaces'); + + const instance = this.get_default_implementation(interface_name); if ( ! instance ) { throw APIError.create('no_implementation_available', null, { interface_name }) } - const meta = await instance.get_response_meta(); - const sla_override = await this.maybe_get_sla(interface_name, method); + const meta = await (async () => { + if ( instance instanceof Driver ) { + return await instance.get_response_meta(); + } + if ( ! instance.instance.as('driver-metadata') ) return; + const t = instance.instance.as('driver-metadata'); + return t.get_response_meta(); + })(); try { - let result = await instance.call(method, processed_args, sla_override); + let result; + if ( instance instanceof Driver ) { + result = await instance.call( + method, processed_args); + } else { + // TODO: SLA and monthly limits do not apply do drivers + // from service traits (yet) + result = await instance.impl[method](processed_args); + } if ( result instanceof TypedValue ) { - const interface_ = this.interfaces[interface_name]; + const interface_ = c_interfaces.get(interface_name); let desired_type = interface_.methods[method] .result_choices[0].type; const svc_coercion = services.get('coercion'); @@ -127,16 +183,12 @@ class DriverService extends BaseService { return this.interfaces; } - async maybe_get_sla (interface_name, method) { - const services = this.services; - const fs = services.get('filesystem'); - - return false; - } - async _process_args (interface_name, method_name, args) { + const svc_registry = this.services.get('registry'); + const c_interfaces = svc_registry.get('interfaces'); + // Note: 'interface' is a strict mode reserved word. - const interface_ = this.interfaces[interface_name]; + const interface_ = c_interfaces.get(interface_name); if ( ! interface_ ) { throw APIError.create('interface_not_found', null, { interface_name }); } diff --git a/src/puter-js-common/src/AdvancedBase.js b/src/puter-js-common/src/AdvancedBase.js index 4732410ab4..3712a8a44c 100644 --- a/src/puter-js-common/src/AdvancedBase.js +++ b/src/puter-js-common/src/AdvancedBase.js @@ -25,6 +25,7 @@ class AdvancedBase extends FeatureBase { static FEATURES = [ require('./features/NodeModuleDIFeature'), require('./features/PropertiesFeature'), + require('./features/TraitsFeature'), ] } diff --git a/src/puter-js-common/src/bases/FeatureBase.js b/src/puter-js-common/src/bases/FeatureBase.js index ab7f4fb3ac..5ef78b73b6 100644 --- a/src/puter-js-common/src/bases/FeatureBase.js +++ b/src/puter-js-common/src/bases/FeatureBase.js @@ -21,7 +21,12 @@ const { BasicBase } = require("./BasicBase"); class FeatureBase extends BasicBase { constructor (parameters, ...a) { super(parameters, ...a); - for ( const feature of this.features ) { + + this._ = { + features: this._get_merged_static_array('FEATURES'), + }; + + for ( const feature of this._.features ) { feature.install_in_instance( this, { @@ -30,10 +35,6 @@ class FeatureBase extends BasicBase { ) } } - - get features () { - return this._get_merged_static_array('FEATURES'); - } } module.exports = { diff --git a/src/puter-js-common/src/features/TraitsFeature.js b/src/puter-js-common/src/features/TraitsFeature.js new file mode 100644 index 0000000000..68b4ac5f59 --- /dev/null +++ b/src/puter-js-common/src/features/TraitsFeature.js @@ -0,0 +1,20 @@ +module.exports = { + install_in_instance: (instance, { parameters }) => { + const impls = instance._get_merged_static_object('IMPLEMENTS'); + + instance._.impls = {}; + + for ( const impl_name in impls ) { + const impl = impls[impl_name]; + const bound_impl = {}; + for ( const method_name in impl ) { + const fn = impl[method_name]; + bound_impl[method_name] = fn.bind(instance); + } + instance._.impls[impl_name] = bound_impl; + } + + instance.as = trait_name => instance._.impls[trait_name]; + instance.list_traits = () => Object.keys(instance._.impls); + }, +}; From ab156297a746c0754145c2abdb2c99bb1b30651a Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 19 Jul 2024 15:19:04 -0400 Subject: [PATCH 0607/2119] feat: add system user --- .../database/SqliteDatabaseAccessService.js | 33 +++++++++- .../sqlite_setup/0025_system-user.dbmig.js | 63 +++++++++++++++++++ 2 files changed, 94 insertions(+), 2 deletions(-) create mode 100644 src/backend/src/services/database/sqlite_setup/0025_system-user.dbmig.js diff --git a/src/backend/src/services/database/SqliteDatabaseAccessService.js b/src/backend/src/services/database/SqliteDatabaseAccessService.js index c99ba115e7..7de3982b01 100644 --- a/src/backend/src/services/database/SqliteDatabaseAccessService.js +++ b/src/backend/src/services/database/SqliteDatabaseAccessService.js @@ -42,7 +42,7 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { this.db = new Database(this.config.path); // Database upgrade logic - const TARGET_VERSION = 22; + const TARGET_VERSION = 23; if ( do_setup ) { this.log.noticeme(`SETUP: creating database at ${this.config.path}`); @@ -71,6 +71,7 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { '0022_dev-center-max.sql', '0023_fix-kv.sql', '0024_default-groups.sql', + '0025_system-user.dbmig.js' ].map(p => path_.join(__dirname, 'sqlite_setup', p)); const fs = require('fs'); for ( const filename of sql_files ) { @@ -175,6 +176,10 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { upgrade_files.push('0024_default-groups.sql'); } + if ( user_version <= 22 ) { + upgrade_files.push('0025_system-user.dbmig.js'); + } + if ( upgrade_files.length > 0 ) { this.log.noticeme(`Database out of date: ${this.config.path}`); this.log.noticeme(`UPGRADING DATABASE: ${user_version} -> ${TARGET_VERSION}`); @@ -188,7 +193,20 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { const basename = path_.basename(filename); this.log.noticeme(`applying ${basename}`); const contents = fs.readFileSync(filename, 'utf8'); - this.db.exec(contents); + switch ( path_.extname(filename) ) { + case '.sql': + this.db.exec(contents); + break; + case '.js': + await this.run_js_migration_({ + filename, contents, + }); + break; + default: + throw new Error( + `unrecognized migration type: ${filename}` + ); + } } // Update version number @@ -273,6 +291,17 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { return p; }); } + + async run_js_migration_ ({ filename, contents }) { + contents = `(async () => {${contents}})()`; + const vm = require('vm'); + const context = vm.createContext({ + read: this.read.bind(this), + write: this.write.bind(this), + log: this.log, + }); + await vm.runInContext(contents, context); + } _register_commands (commands) { commands.registerCommands('sqlite', [ diff --git a/src/backend/src/services/database/sqlite_setup/0025_system-user.dbmig.js b/src/backend/src/services/database/sqlite_setup/0025_system-user.dbmig.js new file mode 100644 index 0000000000..4b12a72797 --- /dev/null +++ b/src/backend/src/services/database/sqlite_setup/0025_system-user.dbmig.js @@ -0,0 +1,63 @@ +/* +Add a user called `system`. + +If a user called `system` already exists, first rename the existing +user to the first username in this sequence: + system_, system_0, system_1, system_2, ... +*/ + +let existing_user; + +;[existing_user] = await read( + "SELECT username FROM `user` WHERE username='system'", +); + +if ( existing_user ) { + let replace_num = 0; + let replace_name = 'system_'; + + for (;;) { + ;[existing_user] = await read( + 'SELECT username FROM `user` WHERE username=?', + [replace_name] + ); + if ( ! existing_user ) break; + replace_name = 'system_' + (replace_num++); + } + + log.noticeme('updating existing user called system', { + replace_num, + replace_name, + }); + + await write( + `UPDATE \`user\` SET username=? WHERE username='system' LIMIT 1`, + [replace_name] + ); +} + +const { insertId: system_user_id } = await write( + 'INSERT INTO `user` (`uuid`, `username`) VALUES (?, ?)', + [ + '5d4adce0-a381-4982-9c02-6e2540026238', + 'system', + ] +); + +const [{id: system_group_id}] = await read( + 'SELECT id FROM `group` WHERE uid=?', + ['26bfb1fb-421f-45bc-9aa4-d81ea569e7a5'] +); + +const [{id: admin_group_id}] = await read( + 'SELECT id FROM `group` WHERE uid=?', + ['ca342a5e-b13d-4dee-9048-58b11a57cc55'] +); + +// admin group has unlimited access to all drivers +await write( + 'INSERT INTO `user_to_group_permissions` ' + + '(`user_id`, `group_id`, `permission`, `extra`) ' + + 'VALUES (?, ?, ?, ?)', + [system_user_id, admin_group_id, 'driver', '{}'] +); From d1261460bac6b365db808127be36a16dd2a79cc0 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 19 Jul 2024 16:36:14 -0400 Subject: [PATCH 0608/2119] dev: obtain driver permission from system user --- src/backend/src/services/auth/PermissionService.js | 2 +- src/backend/src/services/drivers/DriverService.js | 1 - .../src/structured/sequence/check-user-permission.js | 8 ++++++-- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/src/backend/src/services/auth/PermissionService.js b/src/backend/src/services/auth/PermissionService.js index b18d1a2a50..e913ddb0b4 100644 --- a/src/backend/src/services/auth/PermissionService.js +++ b/src/backend/src/services/auth/PermissionService.js @@ -88,7 +88,7 @@ const implicit_user_app_permissions = [ ]; const implicit_user_permissions = { - 'driver': {}, + // 'driver': {}, }; class PermissionRewriter { diff --git a/src/backend/src/services/drivers/DriverService.js b/src/backend/src/services/drivers/DriverService.js index 861957c330..0553714ad6 100644 --- a/src/backend/src/services/drivers/DriverService.js +++ b/src/backend/src/services/drivers/DriverService.js @@ -91,7 +91,6 @@ class DriverService extends BaseService { try { return await this._call(...a); } catch ( e ) { - console.error(e); return this._driver_response_from_error(e); } } diff --git a/src/backend/src/structured/sequence/check-user-permission.js b/src/backend/src/structured/sequence/check-user-permission.js index 421a78ca75..f28d12a78f 100644 --- a/src/backend/src/structured/sequence/check-user-permission.js +++ b/src/backend/src/structured/sequence/check-user-permission.js @@ -20,9 +20,13 @@ const { Sequence } = require("../../codex/Sequence"); const { get_user } = require("../../helpers"); const { Actor, UserActorType } = require("../../services/auth/Actor"); - - module.exports = new Sequence([ + async function grant_if_system (a) { + const { actor } = a.values(); + if ( actor.type.user.username === 'system' ) { + return a.stop({}); + } + }, async function rewrite_permission (a) { let { permission } = a.values(); permission = await a.icall('_rewrite_permission', permission); From f0c36a1cdf16f11765c29360a5c38140008b90c7 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 19 Jul 2024 18:16:55 -0400 Subject: [PATCH 0609/2119] feat: replace default_user with admin --- src/backend/src/services/DefaultUserService.js | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/src/backend/src/services/DefaultUserService.js b/src/backend/src/services/DefaultUserService.js index 556f203df3..c27f7fefd7 100644 --- a/src/backend/src/services/DefaultUserService.js +++ b/src/backend/src/services/DefaultUserService.js @@ -24,7 +24,7 @@ const BaseService = require("./BaseService"); const { Actor, UserActorType } = require("./auth/Actor"); const { DB_WRITE } = require("./database/consts"); -const USERNAME = 'default_user'; +const USERNAME = 'admin'; class DefaultUserService extends BaseService { static MODULES = { @@ -34,11 +34,11 @@ class DefaultUserService extends BaseService { async _init () { } async ['__on_ready.webserver'] () { - // check if a user named `default-user` exists + // check if a user named `admin` exists let user = await get_user({ username: USERNAME, cached: false }); if ( ! user ) user = await this.create_default_user_(); - // check if user named `default-user` is using default password + // check if user named `admin` is using default password const require = this.require; const tmp_password = await this.get_tmp_password_(user); const bcrypt = require('bcrypt'); @@ -51,7 +51,7 @@ class DefaultUserService extends BaseService { // show console widget this.default_user_widget = () => { const lines = [ - `Your default user has been created!`, + `Your admin user has been created!`, `\x1B[31;1musername:\x1B[0m ${USERNAME}`, `\x1B[32;1mpassword:\x1B[0m ${tmp_password}`, `(change the password to remove this message)` @@ -82,7 +82,7 @@ class DefaultUserService extends BaseService { }, interval); } async create_default_user_ () { - const db = this.services.get('database').get(DB_WRITE, 'default-user'); + const db = this.services.get('database').get(DB_WRITE, USERNAME); await db.write( ` INSERT INTO user (uuid, username, free_storage) @@ -94,7 +94,12 @@ class DefaultUserService extends BaseService { 1024 * 1024 * 1024 * 10, // 10 GB ], ); - const user = await get_user({ username: USERNAME }); + const svc_group = this.services.get('group'); + await svc_group.add_users({ + uid: 'ca342a5e-b13d-4dee-9048-58b11a57cc55', // admin + users: [USERNAME] + }); + const user = await get_user({ username: USERNAME, cached: false }); const tmp_password = await this.get_tmp_password_(user); const bcrypt = require('bcrypt'); const password_hashed = await bcrypt.hash(tmp_password, 8); From c9ded89b22bb822c20aea379a17a8bdf74a658de Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sat, 20 Jul 2024 00:55:26 -0400 Subject: [PATCH 0610/2119] feat: grant user driver perms from admin --- src/backend/src/config.js | 3 + src/backend/src/routers/signup.js | 19 ++++ .../src/services/DefaultUserService.js | 80 ++++++++++++++++ .../database/SqliteDatabaseAccessService.js | 11 ++- .../sqlite_setup/0026_user-groups.dbmig.js | 95 +++++++++++++++++++ src/backend/src/util/structutil.js | 35 +++++++ 6 files changed, 241 insertions(+), 2 deletions(-) create mode 100644 src/backend/src/services/database/sqlite_setup/0026_user-groups.dbmig.js create mode 100644 src/backend/src/util/structutil.js diff --git a/src/backend/src/config.js b/src/backend/src/config.js index 2ff733f337..c23f357c07 100644 --- a/src/backend/src/config.js +++ b/src/backend/src/config.js @@ -28,6 +28,9 @@ config.servers = []; // Will disable the auto-generated temp users. If a user lands on the site, they will be required to sign up or log in. config.disable_temp_users = false; +config.default_user_group = '78b1b1dd-c959-44d2-b02c-8735671f9997'; +config.default_temp_group = 'b7220104-7905-4985-b996-649fdcdb3c8f'; + config.max_file_size = 100_000_000_000, config.max_thumb_size = 1_000, config.max_fsentry_name_length = 767, diff --git a/src/backend/src/routers/signup.js b/src/backend/src/routers/signup.js index e94b7b95ae..50a503b433 100644 --- a/src/backend/src/routers/signup.js +++ b/src/backend/src/routers/signup.js @@ -214,6 +214,14 @@ module.exports = eggspress(['/signup'], { 'UPDATE `user` SET `last_activity_ts` = now() WHERE id=? LIMIT 1', [insert_res.insertId] ); + + // TODO: cache group id + const svc_group = req.services.get('group'); + await svc_group.add_users({ + uid: req.body.is_temp ? + config.default_temp_group : config.default_user_group, + users: [req.body.username] + }); } // ----------------------------------- // Pseudo User converting @@ -244,6 +252,17 @@ module.exports = eggspress(['/signup'], { ] ); + // TODO: cache group ids + const svc_group = req.services.get('group'); + await svc_group.remove_users({ + uid: config.default_temp_group, + users: [req.body.username], + }); + await svc_group.add_users({ + uid: config.default_user_group, + users: [req.body.username] + }); + // record activity db.write('UPDATE `user` SET `last_activity_ts` = now() WHERE id=? LIMIT 1', [pseudo_user.id]); invalidate_cached_user_by_id(pseudo_user.id); diff --git a/src/backend/src/services/DefaultUserService.js b/src/backend/src/services/DefaultUserService.js index c27f7fefd7..9f76a33d30 100644 --- a/src/backend/src/services/DefaultUserService.js +++ b/src/backend/src/services/DefaultUserService.js @@ -16,16 +16,55 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ +const { QuickMkdir } = require("../filesystem/hl_operations/hl_mkdir"); +const { HLWrite } = require("../filesystem/hl_operations/hl_write"); +const { NodePathSelector } = require("../filesystem/node/selectors"); const { surrounding_box } = require("../fun/dev-console-ui-utils"); const { get_user, generate_system_fsentries, invalidate_cached_user } = require("../helpers"); const { Context } = require("../util/context"); const { asyncSafeSetInterval } = require("../util/promise"); +const { buffer_to_stream } = require("../util/streamutil"); const BaseService = require("./BaseService"); const { Actor, UserActorType } = require("./auth/Actor"); const { DB_WRITE } = require("./database/consts"); const USERNAME = 'admin'; +const DEFAULT_FILES = { + '.policy': { + 'drivers.json': JSON.stringify({ + "temp": { + "kv": { + "rate-limit": { + "max": 1000, + "period": 30000 + } + }, + "es": { + "date-limit": { + "max": 1000, + "period": 30000 + } + }, + }, + "user": { + "kv": { + "rate-limit": { + "max": 3000, + "period": 30000 + } + }, + "es": { + "rate-limit": { + "max": 3000, + "period": 30000 + } + } + } + }, undefined, ' '), + } +}; + class DefaultUserService extends BaseService { static MODULES = { bcrypt: require('bcrypt'), @@ -100,6 +139,7 @@ class DefaultUserService extends BaseService { users: [USERNAME] }); const user = await get_user({ username: USERNAME, cached: false }); + const actor = Actor.adapt(user); const tmp_password = await this.get_tmp_password_(user); const bcrypt = require('bcrypt'); const password_hashed = await bcrypt.hash(tmp_password, 8); @@ -112,6 +152,46 @@ class DefaultUserService extends BaseService { ); user.password = password_hashed; await generate_system_fsentries(user); + // generate default files for admin user + const svc_fs = this.services.get('filesystem'); + const make_tree_ = async ({ components, tree }) => { + const parent = await svc_fs.node( + new NodePathSelector('/'+components.join('/')), + ); + for ( const k in tree ) { + if ( typeof tree[k] === 'string' ) { + const buffer = Buffer.from(tree[k], 'utf-8'); + const hl_write = new HLWrite(); + await hl_write.run({ + destination_or_parent: parent, + specified_name: k, + file: { + size: buffer.length, + stream: buffer_to_stream(buffer), + }, + user, + }); + } else { + const hl_qmkdir = new QuickMkdir(); + await hl_qmkdir.run({ + parent, + path: k, + }); + const components_ = [...components, k]; + await make_tree_({ + components: components_, + tree: tree[k], + }); + } + + } + }; + await Context.get().sub({ user, actor }).arun(async () => { + await make_tree_({ + components: ['admin'], + tree: DEFAULT_FILES + }); + }); invalidate_cached_user(user); await new Promise(rslv => setTimeout(rslv, 2000)); return user; diff --git a/src/backend/src/services/database/SqliteDatabaseAccessService.js b/src/backend/src/services/database/SqliteDatabaseAccessService.js index 7de3982b01..c9d2f8e1d1 100644 --- a/src/backend/src/services/database/SqliteDatabaseAccessService.js +++ b/src/backend/src/services/database/SqliteDatabaseAccessService.js @@ -18,6 +18,7 @@ */ const { es_import_promise } = require("../../fun/dev-console-ui-utils"); const { surrounding_box } = require("../../fun/dev-console-ui-utils"); +const structutil = require("../../util/structutil"); const { BaseDatabaseAccessService } = require("./BaseDatabaseAccessService"); class SqliteDatabaseAccessService extends BaseDatabaseAccessService { @@ -42,7 +43,7 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { this.db = new Database(this.config.path); // Database upgrade logic - const TARGET_VERSION = 23; + const TARGET_VERSION = 24; if ( do_setup ) { this.log.noticeme(`SETUP: creating database at ${this.config.path}`); @@ -71,7 +72,8 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { '0022_dev-center-max.sql', '0023_fix-kv.sql', '0024_default-groups.sql', - '0025_system-user.dbmig.js' + '0025_system-user.dbmig.js', + '0026_user-groups.dbmig.js', ].map(p => path_.join(__dirname, 'sqlite_setup', p)); const fs = require('fs'); for ( const filename of sql_files ) { @@ -180,6 +182,10 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { upgrade_files.push('0025_system-user.dbmig.js'); } + if ( user_version <= 23 ) { + upgrade_files.push('0026_user-groups.dbmig.js'); + } + if ( upgrade_files.length > 0 ) { this.log.noticeme(`Database out of date: ${this.config.path}`); this.log.noticeme(`UPGRADING DATABASE: ${user_version} -> ${TARGET_VERSION}`); @@ -299,6 +305,7 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { read: this.read.bind(this), write: this.write.bind(this), log: this.log, + structutil, }); await vm.runInContext(contents, context); } diff --git a/src/backend/src/services/database/sqlite_setup/0026_user-groups.dbmig.js b/src/backend/src/services/database/sqlite_setup/0026_user-groups.dbmig.js new file mode 100644 index 0000000000..204c55f72a --- /dev/null +++ b/src/backend/src/services/database/sqlite_setup/0026_user-groups.dbmig.js @@ -0,0 +1,95 @@ +const { insertId: temp_group_id } = await write( + 'INSERT INTO `group` (`uid`, `owner_user_id`, `extra`, `metadata`) '+ + 'VALUES (?, ?, ?, ?)', + [ + 'b7220104-7905-4985-b996-649fdcdb3c8f', + 1, + '{"critical": true, "type": "default", "name": "temp"}', + '{"title": "Guest", "color": "#777777"}' + ] +); +const [{id: system_user_id}] = await read( + "SELECT id FROM `user` WHERE username='system'" +); +const [{id: user_group_id}] = await read( + 'SELECT id FROM `group` WHERE uid=?', + ['78b1b1dd-c959-44d2-b02c-8735671f9997'] +); + +const user_types = structutil.apply_keys( + ['name', 'group_id'], + ['temp', temp_group_id], + ['user', user_group_id], +); +const drivers = structutil.apply_keys( + ['driver_id', 'selector'], + ['driver:puter-kvstore', 'kv'], + ['driver:puter-notifications', 'es'], + ['driver:puter-apps', 'es'], + ['driver:puter-subdomains', 'es'], +); + +const perms = structutil.cart_product( + [user_types, drivers]); + +for ( const perm of perms ) { + const [user_type, driver] = perm; + log.info('permission info', { user_type, driver }); + debugger; + // temp user drivers + await write( + 'INSERT INTO `user_to_group_permissions` ' + + '(`user_id`, `group_id`, `permission`, `extra`) ' + + 'VALUES (?, ?, ?, ?)', + [ + system_user_id, user_type.group_id, + driver.driver_id, + JSON.stringify({ + policy: { + $: 'json-address', + path: '/admin/.policy/drivers.json', + selector: user_type.name + '.' + + driver.selector, + } + }), + ] + ); +} + +/* +// temp user drivers +await write( + 'INSERT INTO `user_to_group_permissions` ' + + '(`user_id`, `group_id`, `permission`, `extra`) ' + + 'VALUES (?, ?, ?, ?)', + [ + system_user_id, temp_group_id, + 'driver:puter-kvstore', + JSON.stringify({ + policy: { + $: 'json-address', + path: '/admin/.policy/drivers.json', + selector: 'temp.kv', + } + }), + ] +); + +// registered user drivers +await write( + 'INSERT INTO `user_to_group_permissions` ' + + '(`user_id`, `group_id`, `permission`, `extra`) ' + + 'VALUES (?, ?, ?, ?)', + [ + system_user_id, user_group_id, + 'driver:puter-kvstore', + JSON.stringify({ + policy: { + $: 'json-address', + path: '/admin/.policy/drivers.json', + selector: 'user.kv', + } + }), + ] +); +*/ diff --git a/src/backend/src/util/structutil.js b/src/backend/src/util/structutil.js new file mode 100644 index 0000000000..2142501842 --- /dev/null +++ b/src/backend/src/util/structutil.js @@ -0,0 +1,35 @@ +const cart_product = (obj) => { + // Get array of keys + let keys = Object.keys(obj); + + // Generate the Cartesian Product + return keys.reduce((acc, key) => { + let appendArrays = Array.isArray(obj[key]) ? obj[key] : [obj[key]]; + + let newAcc = []; + acc.forEach(arr => { + appendArrays.forEach(item => { + newAcc.push([...arr, item]); + }); + }); + + return newAcc; + }, [[]]); // start with the "empty product" +} + +const apply_keys = (keys, ...entries) => { + const l = []; + for ( const entry of entries ) { + const o = {}; + for ( let i=0 ; i < keys.length ; i++ ) { + o[keys[i]] = entry[i]; + } + l.push(o); + } + return l; +} + +module.exports = { + cart_product, + apply_keys, +}; From 54471fada946a70eaa0df6bfceae995bc4e5848c Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 23 Jul 2024 01:27:39 -0400 Subject: [PATCH 0611/2119] feat: add server command to scan permissions --- .../src/services/auth/PermissionService.js | 43 ++++++ .../sequence/scan-user-permission.js | 56 ++++++++ .../src/unstructured/permission-scanners.js | 124 ++++++++++++++++++ 3 files changed, 223 insertions(+) create mode 100644 src/backend/src/structured/sequence/scan-user-permission.js create mode 100644 src/backend/src/unstructured/permission-scanners.js diff --git a/src/backend/src/services/auth/PermissionService.js b/src/backend/src/services/auth/PermissionService.js index e913ddb0b4..bd3fc358ef 100644 --- a/src/backend/src/services/auth/PermissionService.js +++ b/src/backend/src/services/auth/PermissionService.js @@ -243,7 +243,33 @@ class PermissionService extends BaseService { return res; }); } + + async scan (actor, permission) { + const reading = []; + { + const old_perm = permission; + permission = await this._rewrite_permission(permission); + if ( permission !== old_perm ) { + reading.push({ + $: 'rewrite', + from: old_perm, + to: permission, + }); + } + } + + + await require('../../structured/sequence/scan-user-permission') + .call(this, { + actor, + permission, + reading, + }); + + return reading; + } + async check__ (actor, permission) { permission = await this._rewrite_permission(permission); @@ -856,6 +882,23 @@ class PermissionService extends BaseService { await this.grant_user_app_permission(actor, app_uid, permission, extra); } + }, + { + id: 'scan', + handler: async (args, ctx) => { + const [ username, permission ] = args; + + // actor from username + const actor = new Actor({ + type: new UserActorType({ + user: await get_user({ username }), + }), + }) + + const reading = await this.scan(actor, permission); + const util = require('node:util'); + ctx.log(JSON.stringify(reading, undefined, ' ')); + } } ]); } diff --git a/src/backend/src/structured/sequence/scan-user-permission.js b/src/backend/src/structured/sequence/scan-user-permission.js new file mode 100644 index 0000000000..ebcabe3545 --- /dev/null +++ b/src/backend/src/structured/sequence/scan-user-permission.js @@ -0,0 +1,56 @@ +/* + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ +const { Sequence } = require("../../codex/Sequence"); +const { get_user } = require("../../helpers"); +const { Actor, UserActorType } = require("../../services/auth/Actor"); +const { PERMISSION_SCANNERS } = require("../../unstructured/permission-scanners"); + +module.exports = new Sequence([ + async function grant_if_system (a) { + const reading = a.get('reading'); + const { actor } = a.values(); + if ( actor.type.user.username === 'system' ) { + reading.push({ + $: 'option', + source: 'implied', + data: {} + }) + return a.stop({}); + } + }, + async function rewrite_permission (a) { + let { permission } = a.values(); + permission = await a.icall('_rewrite_permission', permission); + a.values({ permission }); + }, + async function explode_permission (a) { + const { permission } = a.values(); + const permission_options = + await a.icall('get_higher_permissions', permission); + a.values({ permission_options }); + }, + async function run_scanners (a) { + const scanners = PERMISSION_SCANNERS; + const ps = []; + for ( const scanner of scanners ) { + ps.push(scanner.scan(a)); + } + await Promise.all(ps); + }, +]); diff --git a/src/backend/src/unstructured/permission-scanners.js b/src/backend/src/unstructured/permission-scanners.js new file mode 100644 index 0000000000..334b7f8d94 --- /dev/null +++ b/src/backend/src/unstructured/permission-scanners.js @@ -0,0 +1,124 @@ +const { get_user } = require("../helpers"); +const { Actor, UserActorType } = require("../services/auth/Actor"); + +const PERMISSION_SCANNERS = [ + { + name: 'implied', + async scan (a) { + const reading = a.get('reading'); + const { actor, permission } = a.values(); + + const _permission_implicators = a.iget('_permission_implicators'); + for ( const implicator of _permission_implicators ) { + if ( ! implicator.matches(permission) ) { + continue; + } + const implied = await implicator.check({ + actor, + permission, + }); + if ( implied ) { + reading.push({ + $: 'option', + source: 'implied', + data: implied, + }); + } + } + } + }, + { + name: 'user-user', + async scan (a) { + const reading = a.get('reading'); + const db = a.iget('db'); + const { actor, permission_options } = a.values(); + + let sql_perm = permission_options.map(perm => { + return `\`permission\` = ?` + }).join(' OR '); + + if ( permission_options.length > 1 ) { + sql_perm = '(' + sql_perm + ')'; + } + + // SELECT permission + const rows = await db.read( + 'SELECT * FROM `user_to_user_permissions` ' + + 'WHERE `holder_user_id` = ? AND ' + + sql_perm, + [ + actor.type.user.id, + ...permission_options, + ] + ); + + // Return the first matching permission where the + // issuer also has the permission granted + for ( const row of rows ) { + const issuer_actor = new Actor({ + type: new UserActorType({ + user: await get_user({ id: row.issuer_user_id }), + }), + }); + + // const issuer_perm = await this.check(issuer_actor, row.permission); + const issuer_reading = await a.icall('scan', issuer_actor, row.permission); + reading.push({ + $: 'path', + via: 'user', + // issuer: issuer_actor, + issuer_username: issuer_actor.type.user.username, + reading: issuer_reading, + }); + } + } + }, + { + name: 'user-group-user', + async scan (a) { + const reading = a.get('reading'); + const { actor, permission_options } = a.values(); + const db = a.iget('db'); + + let sql_perm = permission_options.map((perm) => + `p.permission = ?`).join(' OR '); + + if ( permission_options.length > 1 ) { + sql_perm = '(' + sql_perm + ')'; + } + const rows = await db.read( + 'SELECT p.permission, p.user_id, p.group_id, p.extra FROM `user_to_group_permissions` p ' + + 'JOIN `jct_user_group` ug ON p.group_id = ug.group_id ' + + 'WHERE ug.user_id = ? AND ' + sql_perm, + [ + actor.type.user.id, + ...permission_options, + ] + ); + + for ( const row of rows ) { + const issuer_actor = new Actor({ + type: new UserActorType({ + user: await get_user({ id: row.user_id }), + }), + }); + + const issuer_reading = await a.icall('scan', issuer_actor, row.permission); + + reading.push({ + $: 'path', + via: 'user-group', + // issuer: issuer_actor, + issuer_username: issuer_actor.type.user.username, + reading: issuer_reading, + group_id: row.group_id, + }); + } + } + } +]; + +module.exports = { + PERMISSION_SCANNERS, +}; From 4a6055d23956dff74a2738f78a20d6826fbd8c6d Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 23 Jul 2024 15:16:27 -0400 Subject: [PATCH 0612/2119] dev: add user-app to permission scanning --- src/backend/src/data/hardcoded-permissions.js | 68 ++++++++++++++ .../src/services/auth/PermissionService.js | 88 +++++------------- .../sequence/scan-user-permission.js | 3 + .../src/unstructured/permission-scanners.js | 90 +++++++++++++++++-- 4 files changed, 179 insertions(+), 70 deletions(-) create mode 100644 src/backend/src/data/hardcoded-permissions.js diff --git a/src/backend/src/data/hardcoded-permissions.js b/src/backend/src/data/hardcoded-permissions.js new file mode 100644 index 0000000000..16d2898730 --- /dev/null +++ b/src/backend/src/data/hardcoded-permissions.js @@ -0,0 +1,68 @@ +const default_implicit_user_app_permissions = { + 'driver:helloworld:greet': {}, + 'driver:puter-kvstore': {}, + 'driver:puter-ocr:recognize': {}, + 'driver:puter-chat-completion': {}, + 'driver:puter-image-generation': {}, + 'driver:puter-tts': {}, + 'driver:puter-apps': {}, + 'driver:puter-subdomains': {}, + 'driver:temp-email': {}, +}; + +const implicit_user_app_permissions = [ + { + id: 'builtin-apps', + apps: [ + 'app-0bef044f-918f-4cbf-a0c0-b4a17ee81085', // about + 'app-838dfbc4-bf8b-48c2-b47b-c4adc77fab58', // editor + 'app-58282b08-990a-4906-95f7-fa37ff92452b', // draw + 'app-0087b701-da09-4f49-a37d-2d6bcabc81ee', // minipaint + 'app-3fea7529-266e-47d9-8776-31649cd06557', // terminal + 'app-5584fbf7-ed69-41fc-99cd-85da21b1ef51', // camera + 'app-7bdca1a4-6373-4c98-ad97-03ff2d608ca1', // recorder + 'app-240a43f4-43b1-49bc-b9fc-c8ae719dab77', // dev-center + 'app-a2ae72a4-1ba3-4a29-b5c0-6de1be5cf178', // app-center + 'app-74378e84-b9cd-5910-bcb1-3c50fa96d6e7', // https://nj.puter.site + 'app-13a38aeb-f9f6-54f0-9bd3-9d4dd655ccfe', // https://cdpn.io + 'app-dce8f797-82b0-5d95-a2f8-ebe4d71b9c54', // https://null.jsbin.com + 'app-93005ce0-80d1-50d9-9b1e-9c453c375d56', // https://markus.puter.com + ], + permissions: { + 'driver:helloworld:greet': {}, + 'driver:puter-ocr:recognize': {}, + 'driver:puter-kvstore:get': {}, + 'driver:puter-kvstore:set': {}, + 'driver:puter-kvstore:del': {}, + 'driver:puter-kvstore:list': {}, + 'driver:puter-kvstore:flush': {}, + 'driver:puter-chat-completion:complete': {}, + 'driver:puter-image-generation:generate': {}, + 'driver:puter-analytics:create_trace': {}, + 'driver:puter-analytics:record': {}, + }, + }, + { + id: 'local-testing', + apps: [ + 'app-a392f3e5-35ca-5dac-ae10-785696cc7dec', // https://localhost + 'app-a6263561-6a84-5d52-9891-02956f9fac65', // https://127.0.0.1 + 'app-26149f0b-8304-5228-b995-772dadcf410e', // http://localhost + 'app-c2e27728-66d9-54dd-87cd-6f4e9b92e3e3', // http://127.0.0.1 + ], + permissions: { + 'driver:helloworld:greet': {}, + 'driver:puter-ocr:recognize': {}, + 'driver:puter-kvstore:get': {}, + 'driver:puter-kvstore:set': {}, + 'driver:puter-kvstore:del': {}, + 'driver:puter-kvstore:list': {}, + 'driver:puter-kvstore:flush': {}, + }, + }, +]; + +module.exports = { + implicit_user_app_permissions, + default_implicit_user_app_permissions, +}; diff --git a/src/backend/src/services/auth/PermissionService.js b/src/backend/src/services/auth/PermissionService.js index bd3fc358ef..1b8bc6b8cd 100644 --- a/src/backend/src/services/auth/PermissionService.js +++ b/src/backend/src/services/auth/PermissionService.js @@ -16,6 +16,11 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ +const { + implicit_user_app_permissions, + default_implicit_user_app_permissions +} = require("../../data/hardcoded-permissions"); + const { get_user, get_app } = require("../../helpers"); const { AssignableMethodsFeature } = require("../../traits/AssignableMethodsFeature"); const { Context } = require("../../util/context"); @@ -23,70 +28,6 @@ const BaseService = require("../BaseService"); const { DB_WRITE } = require("../database/consts"); const { UserActorType, Actor, AppUnderUserActorType, AccessTokenActorType, SiteActorType } = require("./Actor"); -const default_implicit_user_app_permissions = { - 'driver:helloworld:greet': {}, - 'driver:puter-kvstore': {}, - 'driver:puter-ocr:recognize': {}, - 'driver:puter-chat-completion': {}, - 'driver:puter-image-generation': {}, - 'driver:puter-tts': {}, - 'driver:puter-apps': {}, - 'driver:puter-subdomains': {}, - 'driver:temp-email': {}, -}; - -const implicit_user_app_permissions = [ - { - id: 'builtin-apps', - apps: [ - 'app-0bef044f-918f-4cbf-a0c0-b4a17ee81085', // about - 'app-838dfbc4-bf8b-48c2-b47b-c4adc77fab58', // editor - 'app-58282b08-990a-4906-95f7-fa37ff92452b', // draw - 'app-0087b701-da09-4f49-a37d-2d6bcabc81ee', // minipaint - 'app-3fea7529-266e-47d9-8776-31649cd06557', // terminal - 'app-5584fbf7-ed69-41fc-99cd-85da21b1ef51', // camera - 'app-7bdca1a4-6373-4c98-ad97-03ff2d608ca1', // recorder - 'app-240a43f4-43b1-49bc-b9fc-c8ae719dab77', // dev-center - 'app-a2ae72a4-1ba3-4a29-b5c0-6de1be5cf178', // app-center - 'app-74378e84-b9cd-5910-bcb1-3c50fa96d6e7', // https://nj.puter.site - 'app-13a38aeb-f9f6-54f0-9bd3-9d4dd655ccfe', // https://cdpn.io - 'app-dce8f797-82b0-5d95-a2f8-ebe4d71b9c54', // https://null.jsbin.com - 'app-93005ce0-80d1-50d9-9b1e-9c453c375d56', // https://markus.puter.com - ], - permissions: { - 'driver:helloworld:greet': {}, - 'driver:puter-ocr:recognize': {}, - 'driver:puter-kvstore:get': {}, - 'driver:puter-kvstore:set': {}, - 'driver:puter-kvstore:del': {}, - 'driver:puter-kvstore:list': {}, - 'driver:puter-kvstore:flush': {}, - 'driver:puter-chat-completion:complete': {}, - 'driver:puter-image-generation:generate': {}, - 'driver:puter-analytics:create_trace': {}, - 'driver:puter-analytics:record': {}, - }, - }, - { - id: 'local-testing', - apps: [ - 'app-a392f3e5-35ca-5dac-ae10-785696cc7dec', // https://localhost - 'app-a6263561-6a84-5d52-9891-02956f9fac65', // https://127.0.0.1 - 'app-26149f0b-8304-5228-b995-772dadcf410e', // http://localhost - 'app-c2e27728-66d9-54dd-87cd-6f4e9b92e3e3', // http://127.0.0.1 - ], - permissions: { - 'driver:helloworld:greet': {}, - 'driver:puter-ocr:recognize': {}, - 'driver:puter-kvstore:get': {}, - 'driver:puter-kvstore:set': {}, - 'driver:puter-kvstore:del': {}, - 'driver:puter-kvstore:list': {}, - 'driver:puter-kvstore:flush': {}, - }, - }, -]; - const implicit_user_permissions = { // 'driver': {}, }; @@ -895,6 +836,25 @@ class PermissionService extends BaseService { }), }) + const reading = await this.scan(actor, permission); + const util = require('node:util'); + ctx.log(JSON.stringify(reading, undefined, ' ')); + } + }, + { + id: 'scan-app', + handler: async (args, ctx) => { + const [ username, app_name, permission ] = args; + const app = await get_app({ name: app_name }); + + // actor from username + const actor = new Actor({ + type: new AppUnderUserActorType({ + app, + user: await get_user({ username }), + }), + }) + const reading = await this.scan(actor, permission); const util = require('node:util'); ctx.log(JSON.stringify(reading, undefined, ' ')); diff --git a/src/backend/src/structured/sequence/scan-user-permission.js b/src/backend/src/structured/sequence/scan-user-permission.js index ebcabe3545..3dbffc812f 100644 --- a/src/backend/src/structured/sequence/scan-user-permission.js +++ b/src/backend/src/structured/sequence/scan-user-permission.js @@ -25,6 +25,9 @@ module.exports = new Sequence([ async function grant_if_system (a) { const reading = a.get('reading'); const { actor } = a.values(); + if ( !(actor.type instanceof UserActorType) ) { + return; + } if ( actor.type.user.username === 'system' ) { reading.push({ $: 'option', diff --git a/src/backend/src/unstructured/permission-scanners.js b/src/backend/src/unstructured/permission-scanners.js index 334b7f8d94..c0d3deb06d 100644 --- a/src/backend/src/unstructured/permission-scanners.js +++ b/src/backend/src/unstructured/permission-scanners.js @@ -1,5 +1,9 @@ +const { + default_implicit_user_app_permissions, + implicit_user_app_permissions, +} = require("../data/hardcoded-permissions"); const { get_user } = require("../helpers"); -const { Actor, UserActorType } = require("../services/auth/Actor"); +const { Actor, UserActorType, AppUnderUserActorType } = require("../services/auth/Actor"); const PERMISSION_SCANNERS = [ { @@ -21,6 +25,7 @@ const PERMISSION_SCANNERS = [ reading.push({ $: 'option', source: 'implied', + by: `implicator:${implicator.id}`, data: implied, }); } @@ -30,9 +35,11 @@ const PERMISSION_SCANNERS = [ { name: 'user-user', async scan (a) { - const reading = a.get('reading'); + const { reading, actor, permission_options } = a.values(); + if ( !(actor.type instanceof UserActorType) ) { + return; + } const db = a.iget('db'); - const { actor, permission_options } = a.values(); let sql_perm = permission_options.map(perm => { return `\`permission\` = ?` @@ -77,8 +84,10 @@ const PERMISSION_SCANNERS = [ { name: 'user-group-user', async scan (a) { - const reading = a.get('reading'); - const { actor, permission_options } = a.values(); + const { reading, actor, permission_options } = a.values(); + if ( !(actor.type instanceof UserActorType) ) { + return; + } const db = a.iget('db'); let sql_perm = permission_options.map((perm) => @@ -116,7 +125,76 @@ const PERMISSION_SCANNERS = [ }); } } - } + }, + { + name: 'user-app', + async scan (a) { + const { reading, actor, permission_options } = a.values(); + if ( !(actor.type instanceof AppUnderUserActorType) ) { + return; + } + const db = a.iget('db'); + + const app_uid = actor.type.app.uid; + + for ( const permission of permission_options ) { + { + const implied = default_implicit_user_app_permissions[permission]; + if ( implied ) { + reading.push({ + $: 'option', + source: 'implied', + by: 'user-app-hc-1', + data: implied, + }); + } + } { + const implicit_permissions = {}; + for ( const implicit_permission of implicit_user_app_permissions ) { + if ( implicit_permission.apps.includes(app_uid) ) { + implicit_permissions[permission] = implicit_permission.permissions[permission]; + } + } + if ( implicit_permissions[permission] ) { + reading.push({ + $: 'option', + source: 'implied', + by: 'user-app-hc-2', + data: implicit_permissions[permission], + }); + } + } + } + + let sql_perm = permission_options.map(() => + `\`permission\` = ?`).join(' OR '); + if ( permission_options.length > 1 ) sql_perm = '(' + sql_perm + ')'; + + // SELECT permission + const rows = await db.read( + 'SELECT * FROM `user_to_app_permissions` ' + + 'WHERE `user_id` = ? AND `app_id` = ? AND ' + + sql_perm, + [ + actor.type.user.id, + actor.type.app.id, + ...permission_options, + ] + ); + + if ( rows[0] ) { + const row = rows[0]; + const issuer_actor = actor.get_related_actor(UserActorType); + const issuer_reading = await a.icall('scan', issuer_actor, row.permission); + reading.push({ + $: 'path', + via: 'user-app', + issuer_username: actor.type.user.username, + reading: issuer_reading, + }); + } + } + }, ]; module.exports = { From a0f01514464adb4386de20d455dc7a8379941f96 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 23 Jul 2024 18:47:04 -0400 Subject: [PATCH 0613/2119] dev: improve permission scan reading --- .../src/filesystem/FilesystemService.js | 2 ++ src/backend/src/services/PuterSiteService.js | 1 + .../src/services/auth/PermissionService.js | 23 ++++-------- ...-user-permission.js => scan-permission.js} | 36 +++++++++++++++---- .../src/unstructured/permission-scanners.js | 11 ++++-- 5 files changed, 48 insertions(+), 25 deletions(-) rename src/backend/src/structured/sequence/{scan-user-permission.js => scan-permission.js} (60%) diff --git a/src/backend/src/filesystem/FilesystemService.js b/src/backend/src/filesystem/FilesystemService.js index bfb9d3d698..c335efe5be 100644 --- a/src/backend/src/filesystem/FilesystemService.js +++ b/src/backend/src/filesystem/FilesystemService.js @@ -132,6 +132,7 @@ class FilesystemService extends BaseService { }, })); svc_permission.register_implicator(PermissionImplicator.create({ + id: 'is-owner', matcher: permission => { return permission.startsWith('fs:'); }, @@ -164,6 +165,7 @@ class FilesystemService extends BaseService { }, })); svc_permission.register_exploder(PermissionExploder.create({ + id: 'fs-access-levels', matcher: permission => { return permission.startsWith('fs:') && PermissionUtil.split(permission).length >= 3; diff --git a/src/backend/src/services/PuterSiteService.js b/src/backend/src/services/PuterSiteService.js index 4100a68a91..97cdcda922 100644 --- a/src/backend/src/services/PuterSiteService.js +++ b/src/backend/src/services/PuterSiteService.js @@ -50,6 +50,7 @@ class PuterSiteService extends BaseService { // Imply that sites can read their own files svc_permission.register_implicator(PermissionImplicator.create({ + id: 'in-site', matcher: permission => { return permission.startsWith('fs:'); }, diff --git a/src/backend/src/services/auth/PermissionService.js b/src/backend/src/services/auth/PermissionService.js index 1b8bc6b8cd..df92cde369 100644 --- a/src/backend/src/services/auth/PermissionService.js +++ b/src/backend/src/services/auth/PermissionService.js @@ -185,26 +185,17 @@ class PermissionService extends BaseService { }); } - async scan (actor, permission) { + async scan (actor, permission_options) { const reading = []; - - { - const old_perm = permission; - permission = await this._rewrite_permission(permission); - if ( permission !== old_perm ) { - reading.push({ - $: 'rewrite', - from: old_perm, - to: permission, - }); - } - } - - await require('../../structured/sequence/scan-user-permission') + if ( ! Array.isArray(permission_options) ) { + permission_options = [permission_options]; + } + + await require('../../structured/sequence/scan-permission') .call(this, { actor, - permission, + permission_options, reading, }); diff --git a/src/backend/src/structured/sequence/scan-user-permission.js b/src/backend/src/structured/sequence/scan-permission.js similarity index 60% rename from src/backend/src/structured/sequence/scan-user-permission.js rename to src/backend/src/structured/sequence/scan-permission.js index 3dbffc812f..19f333d563 100644 --- a/src/backend/src/structured/sequence/scan-user-permission.js +++ b/src/backend/src/structured/sequence/scan-permission.js @@ -16,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ +const { permission } = require("process"); const { Sequence } = require("../../codex/Sequence"); const { get_user } = require("../../helpers"); const { Actor, UserActorType } = require("../../services/auth/Actor"); @@ -31,22 +32,43 @@ module.exports = new Sequence([ if ( actor.type.user.username === 'system' ) { reading.push({ $: 'option', + permission: '*', source: 'implied', + by: 'system', data: {} }) return a.stop({}); } }, async function rewrite_permission (a) { - let { permission } = a.values(); - permission = await a.icall('_rewrite_permission', permission); - a.values({ permission }); + let { reading, permission_options } = a.values(); + for ( let i=0 ; i < permission_options.length ; i++ ) { + const old_perm = permission_options[i]; + const permission = await a.icall('_rewrite_permission', old_perm); + if ( permission === old_perm ) continue; + permission_options[i] = permission; + reading.push({ + $: 'rewrite', + from: old_perm, + to: permission, + }); + } }, async function explode_permission (a) { - const { permission } = a.values(); - const permission_options = - await a.icall('get_higher_permissions', permission); - a.values({ permission_options }); + const { reading, permission_options } = a.values(); + for ( let i=0 ; i < permission_options.length ; i++ ) { + const permission = permission_options[i]; + permission_options[i] = + await a.icall('get_higher_permissions', permission); + if ( permission_options[i].length > 1 ) { + reading.push({ + $: 'explode', + from: permission, + to: permission_options[i], + }); + } + } + a.set('permission_options', permission_options.flat()); }, async function run_scanners (a) { const scanners = PERMISSION_SCANNERS; diff --git a/src/backend/src/unstructured/permission-scanners.js b/src/backend/src/unstructured/permission-scanners.js index c0d3deb06d..4ed86363cd 100644 --- a/src/backend/src/unstructured/permission-scanners.js +++ b/src/backend/src/unstructured/permission-scanners.js @@ -10,9 +10,11 @@ const PERMISSION_SCANNERS = [ name: 'implied', async scan (a) { const reading = a.get('reading'); - const { actor, permission } = a.values(); + const { actor, permission_options } = a.values(); const _permission_implicators = a.iget('_permission_implicators'); + + for ( const permission of permission_options ) for ( const implicator of _permission_implicators ) { if ( ! implicator.matches(permission) ) { continue; @@ -24,8 +26,9 @@ const PERMISSION_SCANNERS = [ if ( implied ) { reading.push({ $: 'option', + permission, source: 'implied', - by: `implicator:${implicator.id}`, + by: implicator.id, data: implied, }); } @@ -74,6 +77,7 @@ const PERMISSION_SCANNERS = [ reading.push({ $: 'path', via: 'user', + permission: row.permission, // issuer: issuer_actor, issuer_username: issuer_actor.type.user.username, reading: issuer_reading, @@ -119,6 +123,7 @@ const PERMISSION_SCANNERS = [ $: 'path', via: 'user-group', // issuer: issuer_actor, + permission: row.permission, issuer_username: issuer_actor.type.user.username, reading: issuer_reading, group_id: row.group_id, @@ -158,6 +163,7 @@ const PERMISSION_SCANNERS = [ if ( implicit_permissions[permission] ) { reading.push({ $: 'option', + permission, source: 'implied', by: 'user-app-hc-2', data: implicit_permissions[permission], @@ -189,6 +195,7 @@ const PERMISSION_SCANNERS = [ reading.push({ $: 'path', via: 'user-app', + permission: row.permission, issuer_username: actor.type.user.username, reading: issuer_reading, }); From 3b85e4eebadb356c5176931d8e4b06fe3322850c Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 23 Jul 2024 19:20:29 -0400 Subject: [PATCH 0614/2119] dev: migrate ACLService to use scan() --- src/backend/src/services/auth/ACLService.js | 6 ++++-- .../src/services/auth/PermissionService.js | 18 +++++++++++++++--- 2 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/backend/src/services/auth/ACLService.js b/src/backend/src/services/auth/ACLService.js index 84594cc05c..9edd85cce1 100644 --- a/src/backend/src/services/auth/ACLService.js +++ b/src/backend/src/services/auth/ACLService.js @@ -22,6 +22,7 @@ const { get_user } = require("../../helpers"); const { Context } = require("../../util/context"); const BaseService = require("../BaseService"); const { AppUnderUserActorType, UserActorType, Actor, SystemActorType, AccessTokenActorType } = require("./Actor"); +const { PermissionUtil } = require("./PermissionService"); class ACLService extends BaseService { async check (actor, resource, mode) { @@ -119,11 +120,12 @@ class ACLService extends BaseService { let perm_fsNode = fsNode; while ( ! await perm_fsNode.get('is-root') ) { for ( const mode of modes ) { - const perm = await svc_permission.check( + const reading = await svc_permission.scan( actor, `fs:${await perm_fsNode.get('uid')}:${mode}` ); - if ( perm ) { + const options = PermissionUtil.reading_to_options(reading); + if ( options.length > 0 ) { // console.log('TRUE BECAUSE PERMISSION', perm) // console.log(`fs:${await perm_fsNode.get('uid')}:${mode}`) return true; diff --git a/src/backend/src/services/auth/PermissionService.js b/src/backend/src/services/auth/PermissionService.js index df92cde369..c0f4105e65 100644 --- a/src/backend/src/services/auth/PermissionService.js +++ b/src/backend/src/services/auth/PermissionService.js @@ -154,6 +154,18 @@ class PermissionUtil { .join(':') ; } + + static reading_to_options (reading, options = []) { + for ( let finding of reading ) { + if ( finding.$ === 'option' ) { + options.push(finding); + } + if ( finding.$ === 'path' ) { + this.reading_to_options(finding.reading, options); + } + } + return options; + } } class PermissionService extends BaseService { @@ -827,8 +839,8 @@ class PermissionService extends BaseService { }), }) - const reading = await this.scan(actor, permission); - const util = require('node:util'); + let reading = await this.scan(actor, permission); + // reading = PermissionUtil.reading_to_options(reading); ctx.log(JSON.stringify(reading, undefined, ' ')); } }, @@ -847,7 +859,7 @@ class PermissionService extends BaseService { }) const reading = await this.scan(actor, permission); - const util = require('node:util'); + // reading = PermissionUtil.reading_to_options(reading); ctx.log(JSON.stringify(reading, undefined, ' ')); } } From 191be84e320c07d2eaa1eb6324b6ff23bc556c13 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 23 Jul 2024 19:24:40 -0400 Subject: [PATCH 0615/2119] dev: migrate svc_permission check() to scan() --- src/backend/src/om/entitystorage/ProtectedAppES.js | 6 ++++-- src/backend/src/routers/auth/check-app.js | 5 ++++- src/backend/src/routers/hosting/puter-site.js | 5 ++++- src/backend/src/services/drivers/DriverService.js | 6 ++++-- 4 files changed, 16 insertions(+), 6 deletions(-) diff --git a/src/backend/src/om/entitystorage/ProtectedAppES.js b/src/backend/src/om/entitystorage/ProtectedAppES.js index 7ee537ae6d..270247049d 100644 --- a/src/backend/src/om/entitystorage/ProtectedAppES.js +++ b/src/backend/src/om/entitystorage/ProtectedAppES.js @@ -17,6 +17,7 @@ * along with this program. If not, see . */ const { AppUnderUserActorType, UserActorType } = require("../../services/auth/Actor"); +const { PermissionUtil } = require("../../services/auth/PermissionService"); const { Context } = require("../../util/context"); const { BaseES } = require("./BaseES"); @@ -84,11 +85,12 @@ class ProtectedAppES extends BaseES { const app_uid = await entity.get('uid'); const svc_permission = services.get('permission'); const permission_to_check = `app:uid#${app_uid}:access`; - const perm = await svc_permission.check( + const reading = await svc_permission.scan( actor, permission_to_check, ); + const options = PermissionUtil.reading_to_options(reading); - if ( perm ) return; + if ( options.length > 0 ) return; // `true` here means "do not send downstream" return true; diff --git a/src/backend/src/routers/auth/check-app.js b/src/backend/src/routers/auth/check-app.js index 91f2224058..586f1dfae0 100644 --- a/src/backend/src/routers/auth/check-app.js +++ b/src/backend/src/routers/auth/check-app.js @@ -23,6 +23,7 @@ const { NodeUIDSelector, NodePathSelector } = require("../../filesystem/node/sel const { NodeChildSelector } = require("../../filesystem/node/selectors"); const { get_app } = require("../../helpers"); const { UserActorType, Actor, AppUnderUserActorType } = require("../../services/auth/Actor"); +const { PermissionUtil } = require("../../services/auth/PermissionService"); const { Context } = require("../../util/context"); module.exports = eggspress('/auth/check-app', { @@ -68,7 +69,9 @@ module.exports = eggspress('/auth/check-app', { }), }); - const authenticated = !! await svc_permission.check(app_actor, 'flag:app-is-authenticated'); + const reading = await svc_permission.scan(app_actor, 'flag:app-is-authenticated'); + const options = PermissionUtil.reading_to_options(reading); + const authenticated = options.length > 0; let token; if ( authenticated ) token = await svc_auth.get_user_app_token(app_uid); diff --git a/src/backend/src/routers/hosting/puter-site.js b/src/backend/src/routers/hosting/puter-site.js index fbf9ce5f7a..3e77fedff6 100644 --- a/src/backend/src/routers/hosting/puter-site.js +++ b/src/backend/src/routers/hosting/puter-site.js @@ -26,6 +26,7 @@ const { TYPE_DIRECTORY } = require("../../filesystem/FSNodeContext"); const { LLRead } = require("../../filesystem/ll_operations/ll_read"); const { Actor, UserActorType, SiteActorType } = require("../../services/auth/Actor"); const APIError = require("../../api/APIError"); +const { PermissionUtil } = require("../../services/auth/PermissionService"); const AT_DIRECTORY_NAMESPACE = '4aa6dc52-34c1-4b8a-b63c-a62b27f727cf'; @@ -251,9 +252,11 @@ class PuterSiteMiddleware extends AdvancedBase { return {}; } - return await svc_permission.check( + const reading = await svc_permission.scan( user_actor, `site:uid#${site.uuid}:access` ); + const options = PermissionUtil.reading_to_options(reading); + return options.length > 0; })(); if ( ! perm ) { diff --git a/src/backend/src/services/drivers/DriverService.js b/src/backend/src/services/drivers/DriverService.js index 0553714ad6..032514051f 100644 --- a/src/backend/src/services/drivers/DriverService.js +++ b/src/backend/src/services/drivers/DriverService.js @@ -22,6 +22,7 @@ const { DriverError } = require("./DriverError"); const { TypedValue } = require("./meta/Runtime"); const BaseService = require("../BaseService"); const { Driver } = require("../../definitions/Driver"); +const { PermissionUtil } = require("../auth/PermissionService"); /** * DriverService provides the functionality of Puter drivers. @@ -109,8 +110,9 @@ class DriverService extends BaseService { const services = Context.get('services'); const svc_permission = services.get('permission'); - const perm = await svc_permission.check(actor, `driver:${interface_name}:${method}`); - if ( ! perm ) { + const reading = await svc_permission.scan(actor, `driver:${interface_name}:${method}`); + const options = PermissionUtil.reading_to_options(reading); + if ( ! (options.length > 0) ) { throw APIError.create('permission_denied'); } From cca19ad49587b88c2b7dfddd5b0c5aa426b49fd5 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 23 Jul 2024 19:34:12 -0400 Subject: [PATCH 0616/2119] dev: remove svc_permission.check --- .../src/services/auth/PermissionService.js | 174 ------------------ .../sequence/check-user-permission.js | 146 --------------- 2 files changed, 320 deletions(-) delete mode 100644 src/backend/src/structured/sequence/check-user-permission.js diff --git a/src/backend/src/services/auth/PermissionService.js b/src/backend/src/services/auth/PermissionService.js index c0f4105e65..7b8179630b 100644 --- a/src/backend/src/services/auth/PermissionService.js +++ b/src/backend/src/services/auth/PermissionService.js @@ -188,15 +188,6 @@ class PermissionService extends BaseService { return permission; } - async check () { - const ld = (Context.get('logdent') ?? 0) + 1; - return await Context.get().sub({ logdent: ld }).arun(async () => { - const res = await this.check__(...arguments); - // this.log.noticeme('RETURN ' + res); - return res; - }); - } - async scan (actor, permission_options) { const reading = []; @@ -214,171 +205,6 @@ class PermissionService extends BaseService { return reading; } - async check__ (actor, permission) { - permission = await this._rewrite_permission(permission); - - this.log.info(`checking permission ${permission} for actor ${actor.uid}`, { - actor: actor.uid, - permission, - }); - - // for ( const implicator of this._permission_implicators ) { - // if ( ! implicator.matches(permission) ) continue; - // const implied = await implicator.check({ - // actor, - // permission, - // recurse: this.check.bind(this), - // }); - // if ( implied ) return implied; - // } - - // For now we're only checking driver permissions, and users have all of them - if ( actor.type instanceof UserActorType ) { - return await this.check_user_permission(actor, permission); - } - - if ( actor.type instanceof AccessTokenActorType ) { - // Authorizer must have permission - const authorizer_permission = await this.check(actor.type.authorizer, permission); - if ( ! authorizer_permission ) return false; - - return await this.check_access_token_permission( - actor.type.authorizer, actor.type.token, permission - ); - } - - // Prevent undefined behaviour - if ( actor.type instanceof AppUnderUserActorType ) { - // NEXT: - const app_uid = actor.type.app.uid; - const user_actor = actor.get_related_actor(UserActorType); - // const user_has_permission = await this.check_user_permission(user_actor, permission); - const user_has_permission = await this.check__( - user_actor, permission, - ); - if ( ! user_has_permission ) return undefined; - - // This was a useful log so I'm keeping it here - // console.log('\x1B[36;1m>=== THIS IS HERE ===<\x1B[0m', - // app_uid, - // permission, - // ) - - return await this.check_user_app_permission(actor, app_uid, permission); - } - - if ( actor.type instanceof SiteActorType ) { - return await this.check_site_permission(actor, permission); - } - - console.log ('WHAT ACTOR TYPE THEN???', actor.type); - - throw new Error('unrecognized actor type'); - } - - // TODO: context meta for cycle detection - async check_user_permission (actor, permission) { - return await require('../../structured/sequence/check-user-permission') - .call(this, { - // passed - actor, - permission, - // constants - implicit_user_permissions, - }); - } - - async check_access_token_permission (authorizer, token, permission) { - const rows = await this.db.read( - 'SELECT * FROM `access_token_permissions` ' + - 'WHERE `token_uid` = ? AND `permission` = ?', - [ - token, - permission, - ] - ); - - // Token must have permission - if ( ! rows[0] ) return undefined; - - return rows[0].extra; - } - - async check_user_app_permission (actor, app_uid, permission) { - permission = await this._rewrite_permission(permission); - - let app = await get_app({ uid: app_uid }); - if ( ! app ) app = await get_app({ name: app_uid }); - const app_id = app.id; - - // const parent_perms = this.get_parent_permissions(permission); - const parent_perms = await this.get_higher_permissions(permission); - - for ( const permission of parent_perms ) { - // Check hardcoded permissions - if ( default_implicit_user_app_permissions[permission] ) { - return default_implicit_user_app_permissions[permission]; - } - - // Check implicit permissions - const implicit_permissions = {}; - for ( const implicit_permission of implicit_user_app_permissions ) { - if ( implicit_permission.apps.includes(app_uid) ) { - implicit_permissions[permission] = implicit_permission.permissions[permission]; - } - } - if ( implicit_permissions[permission] ) { - return implicit_permissions[permission]; - } - } - - // My biggest gripe with SQL is doing string manipulation for queries. - // If the grammar for SQL was simpler we could model it, write this as - // data, and even implement macros for common patterns. - let sql_perm = parent_perms.map((perm) => - `\`permission\` = ?`).join(' OR '); - if ( parent_perms.length > 1 ) sql_perm = '(' + sql_perm + ')'; - - // SELECT permission - const rows = await this.db.read( - 'SELECT * FROM `user_to_app_permissions` ' + - 'WHERE `user_id` = ? AND `app_id` = ? AND ' + - sql_perm, - [ - actor.type.user.id, - app_id, - ...parent_perms, - ] - ); - - if ( ! rows[0] ) return undefined; - - return rows[0].extra; - } - - async check_site_permission (actor, permission) { - permission = await this._rewrite_permission(permission); - // const parent_perms = this.get_parent_permissions(permission); - const parent_perms = await this.get_higher_permissions(permission); - - // Check implicit permissions - for ( const parent_perm of parent_perms ) { - if ( implicit_user_permissions[parent_perm] ) { - return implicit_user_permissions[parent_perm]; - } - } - - for ( const implicator of this._permission_implicators ) { - if ( ! implicator.matches(permission) ) continue; - const implied = await implicator.check({ - actor, - permission, - recurse: this.check.bind(this), - }); - if ( implied ) return implied; - } - } - async grant_user_app_permission (actor, app_uid, permission, extra = {}, meta) { permission = await this._rewrite_permission(permission); diff --git a/src/backend/src/structured/sequence/check-user-permission.js b/src/backend/src/structured/sequence/check-user-permission.js deleted file mode 100644 index f28d12a78f..0000000000 --- a/src/backend/src/structured/sequence/check-user-permission.js +++ /dev/null @@ -1,146 +0,0 @@ -/* - * Copyright (C) 2024 Puter Technologies Inc. - * - * This file is part of Puter. - * - * Puter 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 . - */ -const { Sequence } = require("../../codex/Sequence"); -const { get_user } = require("../../helpers"); -const { Actor, UserActorType } = require("../../services/auth/Actor"); - -module.exports = new Sequence([ - async function grant_if_system (a) { - const { actor } = a.values(); - if ( actor.type.user.username === 'system' ) { - return a.stop({}); - } - }, - async function rewrite_permission (a) { - let { permission } = a.values(); - permission = await a.icall('_rewrite_permission', permission); - a.values({ permission }); - }, - async function explode_permission (a) { - const { permission } = a.values(); - const permission_options = - await a.icall('get_higher_permissions', permission); - a.values({ permission_options }); - }, - async function try_hardcoded_permission (a) { - const { - permission_options, - implicit_user_permissions - } = a.values(); - - for ( const perm of permission_options ) { - if ( implicit_user_permissions[perm] ) { - return a.stop(implicit_user_permissions[perm]); - } - } - }, - async function try_permission_implicators (a) { - // NOTE: it's really weird that we check `permission` only and not - // the `permission_options` list here. I haven't changed this - // to avoid regressions but it's something to consider. - const { actor, permission } = a.values(); - - const _permission_implicators = a.iget('_permission_implicators'); - - for ( const implicator of _permission_implicators ) { - if ( ! implicator.matches(permission) ) continue; - const implied = await implicator.check({ - actor, - permission, - recurse: this.check.bind(this), - }); - if ( implied ) { - return a.stop(implied); - } - } - }, - async function try_user_to_user_permissions (a) { - const { actor, permission_options } = a.values(); - const db = a.iget('db'); - - let sql_perm = permission_options.map((perm) => - `\`permission\` = ?`).join(' OR '); - - if ( permission_options.length > 1 ) { - sql_perm = '(' + sql_perm + ')'; - } - - // SELECT permission - const rows = await db.read( - 'SELECT * FROM `user_to_user_permissions` ' + - 'WHERE `holder_user_id` = ? AND ' + - sql_perm, - [ - actor.type.user.id, - ...permission_options, - ] - ); - - // Return the first matching permission where the - // issuer also has the permission granted - for ( const row of rows ) { - const issuer_actor = new Actor({ - type: new UserActorType({ - user: await get_user({ id: row.issuer_user_id }), - }), - }); - - // const issuer_perm = await this.check(issuer_actor, row.permission); - const issuer_perm = await a.icall('check', issuer_actor, row.permission); - - if ( ! issuer_perm ) continue; - - return a.stop(row.extra); - } - }, - async function try_user_to_group_permissions (a) { - const { actor, permission_options } = a.values(); - const db = a.iget('db'); - - let sql_perm = permission_options.map((perm) => - `p.permission = ?`).join(' OR '); - - if ( permission_options.length > 1 ) { - sql_perm = '(' + sql_perm + ')'; - } - const rows = await db.read( - 'SELECT p.permission, p.user_id, p.extra FROM `user_to_group_permissions` p ' + - 'JOIN `jct_user_group` ug ON p.group_id = ug.group_id ' + - 'WHERE ug.user_id = ? AND ' + sql_perm, - [ - actor.type.user.id, - ...permission_options, - ] - ); - - for ( const row of rows ) { - const issuer_actor = new Actor({ - type: new UserActorType({ - user: await get_user({ id: row.user_id }), - }), - }); - - const issuer_perm = await a.icall('check', issuer_actor, row.permission); - - if ( ! issuer_perm ) continue; - - return a.stop(row.extra); - } - } -]); From 580fbdb113f753ae2fe8ef58b894debb0b9907cf Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 23 Jul 2024 19:40:44 -0400 Subject: [PATCH 0617/2119] tweak: record time for permission scans --- src/backend/src/services/auth/PermissionService.js | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/backend/src/services/auth/PermissionService.js b/src/backend/src/services/auth/PermissionService.js index 7b8179630b..3e5fa9c8a3 100644 --- a/src/backend/src/services/auth/PermissionService.js +++ b/src/backend/src/services/auth/PermissionService.js @@ -195,13 +195,19 @@ class PermissionService extends BaseService { permission_options = [permission_options]; } + const start_ts = Date.now(); await require('../../structured/sequence/scan-permission') .call(this, { actor, permission_options, reading, }); - + const end_ts = Date.now(); + reading.push({ + $: 'time', + value: end_ts - start_ts, + }); + return reading; } From 984ae9e6a23da17414e43d58fc0e861827031269 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 23 Jul 2024 20:15:34 -0400 Subject: [PATCH 0618/2119] feat: add password reset from server console --- .../src/services/DefaultUserService.js | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) diff --git a/src/backend/src/services/DefaultUserService.js b/src/backend/src/services/DefaultUserService.js index 9f76a33d30..7cdc2cf5ac 100644 --- a/src/backend/src/services/DefaultUserService.js +++ b/src/backend/src/services/DefaultUserService.js @@ -71,6 +71,7 @@ class DefaultUserService extends BaseService { uuidv4: require('uuid').v4, } async _init () { + this._register_commands(this.services.get('commands')); } async ['__on_ready.webserver'] () { // check if a user named `admin` exists @@ -213,6 +214,41 @@ class DefaultUserService extends BaseService { return tmp_password; }); } + async force_tmp_password_ (user) { + const db = this.services.get('database') + .get(DB_WRITE, 'terminal-password-reset'); + const actor = await Actor.create(UserActorType, { user }); + return await Context.get().sub({ actor }).arun(async () => { + const svc_driver = this.services.get('driver'); + const tmp_password = require('crypto').randomBytes(4).toString('hex'); + const bcrypt = require('bcrypt'); + const password_hashed = await bcrypt.hash(tmp_password, 8); + await svc_driver.call( + 'puter-kvstore', 'set', { + key: 'tmp_password', + value: tmp_password }); + await db.write( + `UPDATE user SET password = ? WHERE id = ?`, + [ + password_hashed, + user.id, + ], + ); + return tmp_password; + }); + } + _register_commands (commands) { + commands.registerCommands('default-user', [ + { + id: 'reset-password', + handler: async (args, ctx) => { + const [ username ] = args; + const user = await get_user({ username }); + await this.force_tmp_password_(user); + } + } + ]); + } } module.exports = DefaultUserService; From e0d30f041b8325620c6b526fa6fa09a5377093bc Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 23 Jul 2024 21:34:17 -0400 Subject: [PATCH 0619/2119] dev: move implied system perms --- src/backend/src/data/hardcoded-permissions.js | 50 +++++++++++ .../sqlite_setup/0026_user-groups.dbmig.js | 85 ------------------- .../src/unstructured/permission-scanners.js | 56 ++++++++++++ 3 files changed, 106 insertions(+), 85 deletions(-) diff --git a/src/backend/src/data/hardcoded-permissions.js b/src/backend/src/data/hardcoded-permissions.js index 16d2898730..575c48a123 100644 --- a/src/backend/src/data/hardcoded-permissions.js +++ b/src/backend/src/data/hardcoded-permissions.js @@ -62,7 +62,57 @@ const implicit_user_app_permissions = [ }, ]; +const hardcoded_user_group_permissions = { + system: { + 'b7220104-7905-4985-b996-649fdcdb3c8f': { + 'driver:puter-kvstore': { + $: 'json-address', + path: '/admin/.policy/drivers.json', + selector: 'temp.kv' + }, + 'driver:puter-notifications': { + $: 'json-address', + path: '/admin/.policy/drivers.json', + selector: 'temp.es' + }, + 'driver:puter-apps': { + $: 'json-address', + path: '/admin/.policy/drivers.json', + selector: 'temp.es' + }, + 'driver:puter-subdomains': { + $: 'json-address', + path: '/admin/.policy/drivers.json', + selector: 'temp.es' + }, + }, + '78b1b1dd-c959-44d2-b02c-8735671f9997': { + 'driver:puter-kvstore': { + $: 'json-address', + path: '/admin/.policy/drivers.json', + selector: 'user.kv' + }, + 'driver:puter-notifications': { + $: 'json-address', + path: '/admin/.policy/drivers.json', + selector: 'user.es' + }, + 'driver:puter-apps': { + $: 'json-address', + path: '/admin/.policy/drivers.json', + selector: 'user.es' + }, + 'driver:puter-subdomains': { + $: 'json-address', + path: '/admin/.policy/drivers.json', + selector: 'user.es' + }, + }, + }, +}; + module.exports = { implicit_user_app_permissions, default_implicit_user_app_permissions, + hardcoded_user_group_permissions, }; diff --git a/src/backend/src/services/database/sqlite_setup/0026_user-groups.dbmig.js b/src/backend/src/services/database/sqlite_setup/0026_user-groups.dbmig.js index 204c55f72a..ce212de495 100644 --- a/src/backend/src/services/database/sqlite_setup/0026_user-groups.dbmig.js +++ b/src/backend/src/services/database/sqlite_setup/0026_user-groups.dbmig.js @@ -8,88 +8,3 @@ const { insertId: temp_group_id } = await write( '{"title": "Guest", "color": "#777777"}' ] ); -const [{id: system_user_id}] = await read( - "SELECT id FROM `user` WHERE username='system'" -); -const [{id: user_group_id}] = await read( - 'SELECT id FROM `group` WHERE uid=?', - ['78b1b1dd-c959-44d2-b02c-8735671f9997'] -); - -const user_types = structutil.apply_keys( - ['name', 'group_id'], - ['temp', temp_group_id], - ['user', user_group_id], -); -const drivers = structutil.apply_keys( - ['driver_id', 'selector'], - ['driver:puter-kvstore', 'kv'], - ['driver:puter-notifications', 'es'], - ['driver:puter-apps', 'es'], - ['driver:puter-subdomains', 'es'], -); - -const perms = structutil.cart_product( - [user_types, drivers]); - -for ( const perm of perms ) { - const [user_type, driver] = perm; - log.info('permission info', { user_type, driver }); - debugger; - // temp user drivers - await write( - 'INSERT INTO `user_to_group_permissions` ' + - '(`user_id`, `group_id`, `permission`, `extra`) ' + - 'VALUES (?, ?, ?, ?)', - [ - system_user_id, user_type.group_id, - driver.driver_id, - JSON.stringify({ - policy: { - $: 'json-address', - path: '/admin/.policy/drivers.json', - selector: user_type.name + '.' + - driver.selector, - } - }), - ] - ); -} - -/* -// temp user drivers -await write( - 'INSERT INTO `user_to_group_permissions` ' + - '(`user_id`, `group_id`, `permission`, `extra`) ' + - 'VALUES (?, ?, ?, ?)', - [ - system_user_id, temp_group_id, - 'driver:puter-kvstore', - JSON.stringify({ - policy: { - $: 'json-address', - path: '/admin/.policy/drivers.json', - selector: 'temp.kv', - } - }), - ] -); - -// registered user drivers -await write( - 'INSERT INTO `user_to_group_permissions` ' + - '(`user_id`, `group_id`, `permission`, `extra`) ' + - 'VALUES (?, ?, ?, ?)', - [ - system_user_id, user_group_id, - 'driver:puter-kvstore', - JSON.stringify({ - policy: { - $: 'json-address', - path: '/admin/.policy/drivers.json', - selector: 'user.kv', - } - }), - ] -); -*/ diff --git a/src/backend/src/unstructured/permission-scanners.js b/src/backend/src/unstructured/permission-scanners.js index 4ed86363cd..7f8b1d58c2 100644 --- a/src/backend/src/unstructured/permission-scanners.js +++ b/src/backend/src/unstructured/permission-scanners.js @@ -1,10 +1,18 @@ const { default_implicit_user_app_permissions, implicit_user_app_permissions, + hardcoded_user_group_permissions, } = require("../data/hardcoded-permissions"); const { get_user } = require("../helpers"); const { Actor, UserActorType, AppUnderUserActorType } = require("../services/auth/Actor"); +/* + OPTIMAL FOLD LEVEL: 3 + + "Ctrl+K, Ctrl+3" or "⌘K, ⌘3"; + "Ctrl+K, Ctrl+J" or "⌘K, ⌘J"; +*/ + const PERMISSION_SCANNERS = [ { name: 'implied', @@ -85,6 +93,54 @@ const PERMISSION_SCANNERS = [ } } }, + { + name: 'hc-user-group-user', + async scan (a) { + const { reading, actor, permission_options } = a.values(); + if ( !(actor.type instanceof UserActorType) ) { + return; + } + + const svc_group = await a.iget('services').get('group'); + const groups = await svc_group.list_groups_with_member( + { user_id: actor.type.user.id }); + console.log('uh, groups?', actor.type.user.id, groups); + const group_uids = {}; + for ( const group of groups ) { + group_uids[group.values.uid] = group; + } + console.log('group uids', group_uids); + + for ( const issuer_username in hardcoded_user_group_permissions ) { + const issuer_actor = new Actor({ + type: new UserActorType({ + user: await get_user({ username: issuer_username }), + }), + }); + const issuer_groups = + hardcoded_user_group_permissions[issuer_username]; + console.log('issuer groups', issuer_groups); + for ( const group_uid in issuer_groups ) { + if ( ! group_uids[group_uid] ) continue; + const issuer_group = issuer_groups[group_uid]; + for ( const permission of permission_options ) { + console.log('permission?', permission); + if ( ! issuer_group.hasOwnProperty(permission) ) continue; + const issuer_reading = + await a.icall('scan', issuer_actor, permission) + reading.push({ + $: 'path', + via: 'hc-user-group', + permission, + issuer_username, + reading: issuer_reading, + group_id: group_uids[group_uid].id, + }); + } + } + } + } + }, { name: 'user-group-user', async scan (a) { From d5ec40078fb07314a0f8bbcac9657261ccc95ac5 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 24 Jul 2024 01:51:35 -0400 Subject: [PATCH 0620/2119] dev: begin adding new driver call method --- src/backend/src/api/APIError.js | 8 +- src/backend/src/data/hardcoded-permissions.js | 2 + src/backend/src/routers/drivers/call.js | 8 +- src/backend/src/routers/kvstore/getItem.js | 7 +- src/backend/src/routers/kvstore/setItem.js | 9 +- .../src/services/DefaultUserService.js | 27 ++++-- src/backend/src/services/HelloWorldService.js | 12 +-- src/backend/src/services/RegistryService.js | 4 + .../src/services/drivers/DriverService.js | 82 ++++++++++++++++--- .../src/services/drivers/interfaces.js | 2 +- 10 files changed, 124 insertions(+), 37 deletions(-) diff --git a/src/backend/src/api/APIError.js b/src/backend/src/api/APIError.js index 736d762175..ed188c0714 100644 --- a/src/backend/src/api/APIError.js +++ b/src/backend/src/api/APIError.js @@ -321,7 +321,13 @@ module.exports = class APIError { }, 'no_implementation_available': { status: 502, - message: ({ interface_name }) => `No implementation available for interface ${quot(interface_name)}`, + message: ({ + iface, + interface_name, + driver + }) => `No implementation available for ` + + (iface ?? interface_name) ? 'interface' : 'driver' + + ' ' + quot(iface ?? interface_name ?? driver) + '.', }, 'method_not_found': { status: 404, diff --git a/src/backend/src/data/hardcoded-permissions.js b/src/backend/src/data/hardcoded-permissions.js index 575c48a123..939ae1cb41 100644 --- a/src/backend/src/data/hardcoded-permissions.js +++ b/src/backend/src/data/hardcoded-permissions.js @@ -65,6 +65,7 @@ const implicit_user_app_permissions = [ const hardcoded_user_group_permissions = { system: { 'b7220104-7905-4985-b996-649fdcdb3c8f': { + 'service:helloworld:ii:helloworld': {}, 'driver:puter-kvstore': { $: 'json-address', path: '/admin/.policy/drivers.json', @@ -87,6 +88,7 @@ const hardcoded_user_group_permissions = { }, }, '78b1b1dd-c959-44d2-b02c-8735671f9997': { + 'service:helloworld:ii:helloworld': {}, 'driver:puter-kvstore': { $: 'json-address', path: '/admin/.policy/drivers.json', diff --git a/src/backend/src/routers/drivers/call.js b/src/backend/src/routers/drivers/call.js index 7a83b09540..8d0ff7aa91 100644 --- a/src/backend/src/routers/drivers/call.js +++ b/src/backend/src/routers/drivers/call.js @@ -58,7 +58,7 @@ module.exports = eggspress('/drivers/call', { const interface_name = req.body.interface; const test_mode = req.body.test_mode; - const params = req.headers['content-type'].includes('multipart/form-data') + const args = req.headers['content-type'].includes('multipart/form-data') ? await _handle_multipart(req) : req.body.args; @@ -66,7 +66,11 @@ module.exports = eggspress('/drivers/call', { if ( test_mode ) context = context.sub({ test_mode: true }); const result = await context.arun(async () => { - return await svc_driver.call(interface_name, req.body.method, params); + return await svc_driver.call({ + iface: interface_name, + method: req.body.method, + args + }); }); _respond(res, result); diff --git a/src/backend/src/routers/kvstore/getItem.js b/src/backend/src/routers/kvstore/getItem.js index 650a23ea24..e1d564c257 100644 --- a/src/backend/src/routers/kvstore/getItem.js +++ b/src/backend/src/routers/kvstore/getItem.js @@ -60,8 +60,11 @@ router.post('/getItem', auth, express.json(), async (req, res, next)=>{ const svc_driver = Context.get('services').get('driver'); let driver_result; try { - const driver_response = await svc_driver.call( - 'puter-kvstore', 'get', { key: req.body.key }); + const driver_response = await svc_driver.call({ + iface: 'puter-kvstore', + method: 'get', + args: { key: req.body.key }, + }); if ( ! driver_response.success ) { throw new Error(driver_response.error?.message ?? 'Unknown error'); } diff --git a/src/backend/src/routers/kvstore/setItem.js b/src/backend/src/routers/kvstore/setItem.js index c52b3460f0..86a48d4a84 100644 --- a/src/backend/src/routers/kvstore/setItem.js +++ b/src/backend/src/routers/kvstore/setItem.js @@ -72,11 +72,14 @@ router.post('/setItem', auth, express.json(), async (req, res, next)=>{ const svc_driver = Context.get('services').get('driver'); let driver_result; try { - const driver_response = await svc_driver.call( - 'puter-kvstore', 'set', { + const driver_response = await svc_driver.call({ + iface: 'puter-kvstore', + method: 'set', + args: { key: req.body.key, value: req.body.value, - }); + }, + }); if ( ! driver_response.success ) { throw new Error(driver_response.error?.message ?? 'Unknown error'); } diff --git a/src/backend/src/services/DefaultUserService.js b/src/backend/src/services/DefaultUserService.js index 7cdc2cf5ac..e9697e77cf 100644 --- a/src/backend/src/services/DefaultUserService.js +++ b/src/backend/src/services/DefaultUserService.js @@ -201,16 +201,23 @@ class DefaultUserService extends BaseService { const actor = await Actor.create(UserActorType, { user }); return await Context.get().sub({ actor }).arun(async () => { const svc_driver = this.services.get('driver'); - const driver_response = await svc_driver.call( - 'puter-kvstore', 'get', { key: 'tmp_password' }); + const driver_response = await svc_driver.call({ + iface: 'puter-kvstore', + method: 'get', + args: { key: 'tmp_password' }, + }); if ( driver_response.result ) return driver_response.result; const tmp_password = require('crypto').randomBytes(4).toString('hex'); - await svc_driver.call( - 'puter-kvstore', 'set', { + await svc_driver.call({ + iface: 'puter-kvstore', + method: 'set', + args: { key: 'tmp_password', - value: tmp_password }); + value: tmp_password, + } + }); return tmp_password; }); } @@ -223,10 +230,14 @@ class DefaultUserService extends BaseService { const tmp_password = require('crypto').randomBytes(4).toString('hex'); const bcrypt = require('bcrypt'); const password_hashed = await bcrypt.hash(tmp_password, 8); - await svc_driver.call( - 'puter-kvstore', 'set', { + await svc_driver.call({ + iface: 'puter-kvstore', + method: 'set', + args: { key: 'tmp_password', - value: tmp_password }); + value: tmp_password, + } + }); await db.write( `UPDATE user SET password = ? WHERE id = ?`, [ diff --git a/src/backend/src/services/HelloWorldService.js b/src/backend/src/services/HelloWorldService.js index efc0a56861..aa233ca0a7 100644 --- a/src/backend/src/services/HelloWorldService.js +++ b/src/backend/src/services/HelloWorldService.js @@ -2,16 +2,12 @@ const BaseService = require("./BaseService"); class HelloWorldService extends BaseService { static IMPLEMENTS = { - ['driver-metadata']: { - get_response_meta () { - return { - driver: 'hello-world', - driver_version: 'v1.0.0', - driver_interface: 'helloworld', - }; + ['version']: { + get_version () { + return 'v1.0.0'; } }, - helloworld: { + ['hello-world']: { async greet ({ subject }) { if ( subject ) { return `Hello, ${subject}!`; diff --git a/src/backend/src/services/RegistryService.js b/src/backend/src/services/RegistryService.js index cd966727d3..8d28b30b3b 100644 --- a/src/backend/src/services/RegistryService.js +++ b/src/backend/src/services/RegistryService.js @@ -35,6 +35,10 @@ class MapCollection extends AdvancedBase { get (key) { return this.kv.get(this._mk_key(key)); } + + exists (key) { + return this.kv.exists(this._mk_key(key)); + } set (key, value) { return this.kv.set(this._mk_key(key), value); diff --git a/src/backend/src/services/drivers/DriverService.js b/src/backend/src/services/drivers/DriverService.js index 032514051f..0562860d20 100644 --- a/src/backend/src/services/drivers/DriverService.js +++ b/src/backend/src/services/drivers/DriverService.js @@ -81,6 +81,7 @@ class DriverService extends BaseService { return this.interface_to_implementation[interface_name]; } + return; this.log.noticeme('HERE IT IS'); const options = this.services.get_implementors(interface_name); this.log.info('test', { options }); @@ -88,16 +89,17 @@ class DriverService extends BaseService { return options[0]; } - async call (...a) { + async call (o) { try { - return await this._call(...a); + return await this._call(o); } catch ( e ) { + console.error(e); return this._driver_response_from_error(e); } } - async _call (interface_name, method, args) { - const processed_args = await this._process_args(interface_name, method, args); + async _call ({ driver, iface, method, args }) { + const processed_args = await this._process_args(iface, method, args); if ( Context.get('test_mode') ) { processed_args.test_mode = true; } @@ -110,18 +112,44 @@ class DriverService extends BaseService { const services = Context.get('services'); const svc_permission = services.get('permission'); - const reading = await svc_permission.scan(actor, `driver:${interface_name}:${method}`); + + const svc_registry = this.services.get('registry'); + const c_interfaces = svc_registry.get('interfaces'); + + driver = driver ?? iface; + + const driver_service_exists = (() => { + return this.services.has(driver) && + this.services.get(driver).list_traits() + .includes(iface); + })(); + if ( driver_service_exists ) { + const service = this.services.get(driver); + const reading = await svc_permission.scan( + actor, + PermissionUtil.join('driver', driver, 'ii', iface), + ); + const options = PermissionUtil.reading_to_options(reading); + if ( options.length > 0 ) { + return await this.call_new_({ + service_name: driver, + service, + method, + args: processed_args, + iface, + }); + } + } + + const reading = await svc_permission.scan(actor, `driver:${iface}:${method}`); const options = PermissionUtil.reading_to_options(reading); if ( ! (options.length > 0) ) { throw APIError.create('permission_denied'); } - const svc_registry = this.services.get('registry'); - const c_interfaces = svc_registry.get('interfaces'); - - const instance = this.get_default_implementation(interface_name); + const instance = this.get_default_implementation(iface); if ( ! instance ) { - throw APIError.create('no_implementation_available', null, { interface_name }) + throw APIError.create('no_implementation_available', null, { iface }) } const meta = await (async () => { if ( instance instanceof Driver ) { @@ -142,7 +170,7 @@ class DriverService extends BaseService { result = await instance.impl[method](processed_args); } if ( result instanceof TypedValue ) { - const interface_ = c_interfaces.get(interface_name); + const interface_ = c_interfaces.get(iface); let desired_type = interface_.methods[method] .result_choices[0].type; const svc_coercion = services.get('coercion'); @@ -151,8 +179,9 @@ class DriverService extends BaseService { } return { success: true, ...meta, result }; } catch ( e ) { + console.error(e); let for_user = (e instanceof APIError) || (e instanceof DriverError); - if ( ! for_user ) this.errors.report(`driver:${interface_name}:${method}`, { + if ( ! for_user ) this.errors.report(`driver:${iface}:${method}`, { source: e, trace: true, // TODO: alarm will not be suitable for all errors. @@ -164,6 +193,35 @@ class DriverService extends BaseService { return this._driver_response_from_error(e, meta); } } + + async call_new_ ({ + service_name, + service, method, args, + iface, + }) { + const svc_registry = this.services.get('registry'); + const c_interfaces = svc_registry.get('interfaces'); + let result = await service.as(iface)[method](args); + if ( result instanceof TypedValue ) { + const interface_ = c_interfaces.get(iface); + let desired_type = interface_.methods[method] + .result_choices[0].type; + const svc_coercion = services.get('coercion'); + result = await svc_coercion.coerce(desired_type, result); + } + const service_meta = {}; + if ( service.list_traits().includes('version') ) { + service_meta.version = service.as('version').get_version(); + } + return { + success: true, + service: { + ...service_meta, + name: service_name, + }, + result + }; + } async _driver_response_from_error (e, meta) { let serializable = (e instanceof APIError) || (e instanceof DriverError); diff --git a/src/backend/src/services/drivers/interfaces.js b/src/backend/src/services/drivers/interfaces.js index 10a958257b..9f0c6d31d6 100644 --- a/src/backend/src/services/drivers/interfaces.js +++ b/src/backend/src/services/drivers/interfaces.js @@ -70,7 +70,7 @@ const ENTITY_STORAGE_INTERFACE = { } module.exports = { - 'helloworld': { + 'hello-world': { description: 'A simple driver that returns a greeting.', methods: { greet: { From e514dfcf5049771af3901334e37b1a7c53e05452 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 24 Jul 2024 02:31:24 -0400 Subject: [PATCH 0621/2119] fix: prevent large logs from service events (2) --- src/backend/src/services/RegistryService.js | 8 ++------ src/backend/src/services/drivers/DriverService.js | 6 ++++-- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/backend/src/services/RegistryService.js b/src/backend/src/services/RegistryService.js index 8d28b30b3b..789e5ecb4b 100644 --- a/src/backend/src/services/RegistryService.js +++ b/src/backend/src/services/RegistryService.js @@ -68,12 +68,8 @@ class RegistryService extends BaseService { async ['__on_boot.consolidation'] () { const services = this.services; - await services.emit('registry.collections', { - svc_registry: this, - }); - await services.emit('registry.entries', { - svc_registry: this, - }); + await services.emit('registry.collections'); + await services.emit('registry.entries'); } register_collection (name) { diff --git a/src/backend/src/services/drivers/DriverService.js b/src/backend/src/services/drivers/DriverService.js index 0562860d20..03a99b9d74 100644 --- a/src/backend/src/services/drivers/DriverService.js +++ b/src/backend/src/services/drivers/DriverService.js @@ -37,12 +37,14 @@ class DriverService extends BaseService { this.interface_to_implementation = {}; } - async ['__on_registry.collections'] (_, { svc_registry }) { + async ['__on_registry.collections'] () { + const svc_registry = this.services.get('registry'); svc_registry.register_collection('interfaces'); svc_registry.register_collection('drivers'); } - async ['__on_registry.entries'] (_, { svc_registry }) { + async ['__on_registry.entries'] () { const services = this.services; + const svc_registry = services.get('registry'); const col_interfaces = svc_registry.get('interfaces'); const col_drivers = svc_registry.get('drivers'); { From 9e38e048c155aa9c8a2e39a14f08c07a54b6047f Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 24 Jul 2024 23:21:31 -0400 Subject: [PATCH 0622/2119] dev: prepare to implement policy enforcer --- src/backend/src/CoreModule.js | 6 + src/backend/src/data/hardcoded-permissions.js | 60 +++------- src/backend/src/services/SUService.js | 35 ++++++ src/backend/src/services/SystemDataService.js | 58 +++++++++ .../src/services/auth/PermissionService.js | 34 +++++- .../src/services/drivers/DriverService.js | 111 ++++++++++++++++-- .../src/services/drivers/PolicyEnforcer.js | 11 ++ .../structured/sequence/scan-permission.js | 5 +- .../src/unstructured/permission-scanners.js | 22 +++- 9 files changed, 286 insertions(+), 56 deletions(-) create mode 100644 src/backend/src/services/SUService.js create mode 100644 src/backend/src/services/SystemDataService.js create mode 100644 src/backend/src/services/drivers/PolicyEnforcer.js diff --git a/src/backend/src/CoreModule.js b/src/backend/src/CoreModule.js index 30d5c97c42..c320cd1573 100644 --- a/src/backend/src/CoreModule.js +++ b/src/backend/src/CoreModule.js @@ -305,6 +305,12 @@ const install = async ({ services, app, useapi }) => { const { HelloWorldService } = require('./services/HelloWorldService'); services.registerService('hello-world', HelloWorldService); + + const { SystemDataService } = require('./services/SystemDataService'); + services.registerService('system-data', SystemDataService); + + const { SUService } = require('./services/SUService'); + services.registerService('su', SUService); } const install_legacy = async ({ services }) => { diff --git a/src/backend/src/data/hardcoded-permissions.js b/src/backend/src/data/hardcoded-permissions.js index 939ae1cb41..26ba332fb4 100644 --- a/src/backend/src/data/hardcoded-permissions.js +++ b/src/backend/src/data/hardcoded-permissions.js @@ -62,53 +62,29 @@ const implicit_user_app_permissions = [ }, ]; +const policy_perm = selector => ({ + policy: { + $: 'json-address', + path: '/admin/.policy/drivers.json', + selector, + } +}); + const hardcoded_user_group_permissions = { system: { 'b7220104-7905-4985-b996-649fdcdb3c8f': { - 'service:helloworld:ii:helloworld': {}, - 'driver:puter-kvstore': { - $: 'json-address', - path: '/admin/.policy/drivers.json', - selector: 'temp.kv' - }, - 'driver:puter-notifications': { - $: 'json-address', - path: '/admin/.policy/drivers.json', - selector: 'temp.es' - }, - 'driver:puter-apps': { - $: 'json-address', - path: '/admin/.policy/drivers.json', - selector: 'temp.es' - }, - 'driver:puter-subdomains': { - $: 'json-address', - path: '/admin/.policy/drivers.json', - selector: 'temp.es' - }, + 'service:hello-world:ii:hello-world': policy_perm('temp.es'), + 'driver:puter-kvstore': policy_perm('temp.kv'), + 'driver:puter-notifications': policy_perm('temp.es'), + 'driver:puter-apps': policy_perm('temp.es'), + 'driver:puter-subdomains': policy_perm('temp.es'), }, '78b1b1dd-c959-44d2-b02c-8735671f9997': { - 'service:helloworld:ii:helloworld': {}, - 'driver:puter-kvstore': { - $: 'json-address', - path: '/admin/.policy/drivers.json', - selector: 'user.kv' - }, - 'driver:puter-notifications': { - $: 'json-address', - path: '/admin/.policy/drivers.json', - selector: 'user.es' - }, - 'driver:puter-apps': { - $: 'json-address', - path: '/admin/.policy/drivers.json', - selector: 'user.es' - }, - 'driver:puter-subdomains': { - $: 'json-address', - path: '/admin/.policy/drivers.json', - selector: 'user.es' - }, + 'service:hello-world:ii:hello-world': policy_perm('user.es'), + 'driver:puter-kvstore': policy_perm('user.kv'), + 'driver:puter-notifications': policy_perm('user.es'), + 'driver:puter-apps': policy_perm('user.es'), + 'driver:puter-subdomains': policy_perm('user.es'), }, }, }; diff --git a/src/backend/src/services/SUService.js b/src/backend/src/services/SUService.js new file mode 100644 index 0000000000..94124532e5 --- /dev/null +++ b/src/backend/src/services/SUService.js @@ -0,0 +1,35 @@ +const { get_user } = require("../helpers"); +const { Context } = require("../util/context"); +const { TeePromise } = require("../util/promise"); +const { Actor, UserActorType } = require("./auth/Actor"); +const BaseService = require("./BaseService"); + +class SUService extends BaseService { + _construct () { + this.sys_user_ = new TeePromise(); + this.sys_actor_ = new TeePromise(); + } + async ['__on_boot.consolidation'] () { + const sys_user = await get_user({ username: 'system' }); + this.sys_user_.resolve(sys_user); + const sys_actor = new Actor({ + type: new UserActorType({ + user: sys_user, + }), + }); + this.sys_actor_.resolve(sys_actor); + } + async get_system_actor () { + return this.sys_actor_; + } + async sudo (callback) { + return await Context.get().sub({ + user: await this.sys_user_, + actor: await this.sys_actor_, + }).arun(callback); + } +} + +module.exports = { + SUService, +}; diff --git a/src/backend/src/services/SystemDataService.js b/src/backend/src/services/SystemDataService.js new file mode 100644 index 0000000000..dd6e35a34e --- /dev/null +++ b/src/backend/src/services/SystemDataService.js @@ -0,0 +1,58 @@ +const { LLRead } = require("../filesystem/ll_operations/ll_read"); +const { Context } = require("../util/context"); +const { whatis } = require("../util/langutil"); +const { stream_to_buffer } = require("../util/streamutil"); +const BaseService = require("./BaseService"); + +class SystemDataService extends BaseService { + async _init () {} + + async interpret (data) { + if ( whatis(data) === 'object' && data.$ ) { + return await this.dereference_(data); + } + if ( whatis(data) === 'object' ) { + const new_o = {}; + for ( const k in data ) { + new_o[k] = await this.interpret(data[k]); + } + return new_o; + } + if ( whatis(data) === 'array' ) { + const new_a = []; + for ( const v of data ) { + new_a.push(await this.interpret(v)); + } + return new_a; + } + return data; + } + + async dereference_ (data) { + const svc_fs = this.services.get('filesystem'); + if ( data.$ === 'json-address' ) { + const node = await svc_fs.node(data.path); + const ll_read = new LLRead(); + const stream = await ll_read.run({ + actor: Context.get('actor'), + fsNode: node, + }); + const buffer = await stream_to_buffer(stream); + const json = buffer.toString('utf8'); + let result = JSON.parse(json); + result = await this.interpret(result); + if ( data.selector ) { + const parts = data.selector.split('.'); + for ( const part of parts ) { + result = result[part]; + } + } + return result; + } + throw new Error(`unrecognized data type: ${data.$}`); + } +} + +module.exports = { + SystemDataService, +}; diff --git a/src/backend/src/services/auth/PermissionService.js b/src/backend/src/services/auth/PermissionService.js index 3e5fa9c8a3..492799557a 100644 --- a/src/backend/src/services/auth/PermissionService.js +++ b/src/backend/src/services/auth/PermissionService.js @@ -155,13 +155,39 @@ class PermissionUtil { ; } - static reading_to_options (reading, options = []) { + static reading_to_options ( + // actual arguments + reading, parameters = {}, + // recursion state + options = [], extras = [], path = [], + ) { + const to_path_item = finding => ({ + key: finding.key, + holder: finding.holder_username, + data: finding.data, + }); for ( let finding of reading ) { if ( finding.$ === 'option' ) { - options.push(finding); + path = [to_path_item(finding), ...path]; + options.push({ + ...finding, + data: [ + ...(finding.data ? [finding.data] : []), + ...extras, + ], + path, + }); } if ( finding.$ === 'path' ) { - this.reading_to_options(finding.reading, options); + const new_extras = ( finding.data ) ? [ + finding.data, + ...extras, + ] : []; + const new_path = [to_path_item(finding), ...path]; + this.reading_to_options( + finding.reading, parameters, + options, new_extras, new_path, + ); } } return options; @@ -672,7 +698,7 @@ class PermissionService extends BaseService { }) let reading = await this.scan(actor, permission); - // reading = PermissionUtil.reading_to_options(reading); + reading = PermissionUtil.reading_to_options(reading); ctx.log(JSON.stringify(reading, undefined, ' ')); } }, diff --git a/src/backend/src/services/drivers/DriverService.js b/src/backend/src/services/drivers/DriverService.js index 03a99b9d74..8ce8dd4e8d 100644 --- a/src/backend/src/services/drivers/DriverService.js +++ b/src/backend/src/services/drivers/DriverService.js @@ -23,6 +23,7 @@ const { TypedValue } = require("./meta/Runtime"); const BaseService = require("../BaseService"); const { Driver } = require("../../definitions/Driver"); const { PermissionUtil } = require("../auth/PermissionService"); +const { PolicyEnforcer } = require("./PolicyEnforcer"); /** * DriverService provides the functionality of Puter drivers. @@ -129,17 +130,87 @@ class DriverService extends BaseService { const service = this.services.get(driver); const reading = await svc_permission.scan( actor, - PermissionUtil.join('driver', driver, 'ii', iface), + PermissionUtil.join('service', driver, 'ii', iface), ); + console.log({ + perm: PermissionUtil.join('service', driver, 'ii', iface), + reading, + }); const options = PermissionUtil.reading_to_options(reading); if ( options.length > 0 ) { - return await this.call_new_({ - service_name: driver, - service, - method, - args: processed_args, - iface, + const option = await this.select_best_option_(options); + const policies = await this.get_policies_for_option_(option); + console.log('SLA', JSON.stringify(policies, undefined, ' ')); + + // NOT FINAL: For now we apply monthly usage logic + // to the first holder of the permission. Later this + // will be changed so monthly usage can cascade across + // multiple actors. I decided not to implement this + // immediately because it's a hefty time sink and it's + // going to be some time before we can offer this feature + // to the end-user either way. + + let effective_policy = null; + for ( const policy of policies ) { + if ( policy.holder ) { + effective_policy = policy; + break; + } + } + + if ( ! effective_policy ) { + throw new Error( + 'policies with no effective user are not yet ' + + 'supported' + ); + } + + // NOT FINAL: this will be handled by 'get_policies_for_option_' + // when cascading monthly usage is implemented. + const svc_systemData = this.services.get('system-data'); + const svc_su = this.services.get('su'); + effective_policy = await svc_su.sudo(async () => { + return await svc_systemData.interpret(effective_policy.data); }); + + effective_policy = effective_policy.policy; + + console.log('EFFECTIVE', + JSON.stringify(effective_policy, undefined, ' ')); + + const policy_enforcer = new PolicyEnforcer({ + services: this.services, + actor, + policy: effective_policy, + driver, method, + }); + + try { + await policy_enforcer.check(); + const result = await this.call_new_({ + service_name: driver, + service, + method, + args: processed_args, + iface, + }); + await policy_enforcer.on_success(); + return result; + } catch (e) { + policy_enforcer.on_fail(); + console.error(e); + let for_user = (e instanceof APIError) || (e instanceof DriverError); + if ( ! for_user ) this.errors.report(`driver:${iface}:${method}`, { + source: e, + trace: true, + // TODO: alarm will not be suitable for all errors. + alarm: true, + extra: { + args, + } + }); + return this._driver_response_from_error(e, meta); + } } } @@ -196,6 +267,32 @@ class DriverService extends BaseService { } } + async get_policies_for_option_ (option) { + // NOT FINAL: before implementing cascading monthly usage, + // this return will be removed and the code below it will + // be uncommented + return option.path; + /* + const svc_systemData = this.services.get('system-data'); + const svc_su = this.services.get('su'); + + const policies = await Promise.all(option.path.map(async path_node => { + const policy = await svc_su.sudo(async () => { + return await svc_systemData.interpret(option.data); + }); + return { + ...path_node, + policy, + }; + })); + return policies; + */ + } + + async select_best_option_ (options) { + return options[0]; + } + async call_new_ ({ service_name, service, method, args, diff --git a/src/backend/src/services/drivers/PolicyEnforcer.js b/src/backend/src/services/drivers/PolicyEnforcer.js new file mode 100644 index 0000000000..5b2347c891 --- /dev/null +++ b/src/backend/src/services/drivers/PolicyEnforcer.js @@ -0,0 +1,11 @@ +class PolicyEnforcer { + constructor (context) { + this.context = context; + } + + async check () {} + async on_success () {} + async on_fail () {} +} + +module.exports = { PolicyEnforcer }; diff --git a/src/backend/src/structured/sequence/scan-permission.js b/src/backend/src/structured/sequence/scan-permission.js index 19f333d563..b610b970e2 100644 --- a/src/backend/src/structured/sequence/scan-permission.js +++ b/src/backend/src/structured/sequence/scan-permission.js @@ -25,14 +25,15 @@ const { PERMISSION_SCANNERS } = require("../../unstructured/permission-scanners" module.exports = new Sequence([ async function grant_if_system (a) { const reading = a.get('reading'); - const { actor } = a.values(); + const { actor, permission_options } = a.values(); if ( !(actor.type instanceof UserActorType) ) { return; } if ( actor.type.user.username === 'system' ) { reading.push({ $: 'option', - permission: '*', + key: `sys`, + permission: permission_options[0], source: 'implied', by: 'system', data: {} diff --git a/src/backend/src/unstructured/permission-scanners.js b/src/backend/src/unstructured/permission-scanners.js index 7f8b1d58c2..f9c3dd4f2c 100644 --- a/src/backend/src/unstructured/permission-scanners.js +++ b/src/backend/src/unstructured/permission-scanners.js @@ -74,6 +74,11 @@ const PERMISSION_SCANNERS = [ // Return the first matching permission where the // issuer also has the permission granted for ( const row of rows ) { + row.extra = db.case({ + mysql: () => row.extra, + otherwise: () => JSON.parse(row.extra ?? '{}') + })(); + const issuer_actor = new Actor({ type: new UserActorType({ user: await get_user({ id: row.issuer_user_id }), @@ -86,7 +91,8 @@ const PERMISSION_SCANNERS = [ $: 'path', via: 'user', permission: row.permission, - // issuer: issuer_actor, + data: row.extra, + holder_username: actor.type.user.username, issuer_username: issuer_actor.type.user.username, reading: issuer_reading, }); @@ -132,6 +138,8 @@ const PERMISSION_SCANNERS = [ $: 'path', via: 'hc-user-group', permission, + data: issuer_group[permission], + holder_username: actor.type.user.username, issuer_username, reading: issuer_reading, group_id: group_uids[group_uid].id, @@ -167,6 +175,11 @@ const PERMISSION_SCANNERS = [ ); for ( const row of rows ) { + row.extra = db.case({ + mysql: () => row.extra, + otherwise: () => JSON.parse(row.extra ?? '{}') + })(); + const issuer_actor = new Actor({ type: new UserActorType({ user: await get_user({ id: row.user_id }), @@ -180,6 +193,8 @@ const PERMISSION_SCANNERS = [ via: 'user-group', // issuer: issuer_actor, permission: row.permission, + data: row.extra, + holder_username: actor.type.user.username, issuer_username: issuer_actor.type.user.username, reading: issuer_reading, group_id: row.group_id, @@ -246,12 +261,17 @@ const PERMISSION_SCANNERS = [ if ( rows[0] ) { const row = rows[0]; + row.extra = db.case({ + mysql: () => row.extra, + otherwise: () => JSON.parse(row.extra ?? '{}') + })(); const issuer_actor = actor.get_related_actor(UserActorType); const issuer_reading = await a.icall('scan', issuer_actor, row.permission); reading.push({ $: 'path', via: 'user-app', permission: row.permission, + data: row.extra, issuer_username: actor.type.user.username, reading: issuer_reading, }); From 20b58ddcb5fbdb797fb2ae478551e013fd2c789f Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 25 Jul 2024 15:32:16 -0400 Subject: [PATCH 0623/2119] dev: add Invoker --- src/puter-js-common/src/libs/invoker.js | 53 +++++++++++++++++++++++++ src/puter-js-common/test/test.js | 38 ++++++++++++++++++ 2 files changed, 91 insertions(+) create mode 100644 src/puter-js-common/src/libs/invoker.js diff --git a/src/puter-js-common/src/libs/invoker.js b/src/puter-js-common/src/libs/invoker.js new file mode 100644 index 0000000000..3a2ebd4aec --- /dev/null +++ b/src/puter-js-common/src/libs/invoker.js @@ -0,0 +1,53 @@ +const { AdvancedBase } = require("../.."); + +class Invoker extends AdvancedBase { + static create ({ + decorators, + delegate, + }) { + const invoker = new Invoker(); + invoker.decorators = decorators; + invoker.delegate = delegate; + return invoker; + } + async run (args) { + let fn = this.delegate; + const decorators = this.decorators; + for ( let i = decorators.length-1 ; i >= 0 ; i-- ) { + const dec = decorators[i]; + fn = this.add_dec_(dec, fn); + } + return await fn(args); + } + add_dec_ (dec, fn) { + return async (args) => { + try { + if ( dec.on_call ) { + args = await dec.on_call(args); + } + let result = await fn(args); + if ( dec.on_return ) { + result = await dec.on_return(result); + } + return result; + } catch (e) { + if ( ! dec.on_error ) throw e; + + let cancel = false; + const a = { + error () { return e }, + cancel_error () { cancel = true; }, + }; + const result = await dec.on_error(a); + if ( cancel ) { + return result; + } + throw result ?? e; + } + } + } +} + +module.exports = { + Invoker, +}; diff --git a/src/puter-js-common/test/test.js b/src/puter-js-common/test/test.js index 34a36f4d7e..e5f2bb00c4 100644 --- a/src/puter-js-common/test/test.js +++ b/src/puter-js-common/test/test.js @@ -19,6 +19,7 @@ const { expect } = require('chai'); const { BasicBase } = require('../src/bases/BasicBase'); const { AdvancedBase } = require('../src/AdvancedBase'); +const { Invoker } = require('../src/libs/invoker'); class ClassA extends BasicBase { static STATIC_OBJ = { @@ -70,3 +71,40 @@ describe('AdvancedBase', () => { }); }); +describe('lib:invoker', () => { + it('works', async () => { + const invoker = Invoker.create({ + decorators: [ + { + name: 'uphill both ways', + on_call: (args) => { + return { + ...args, + n: args.n + 1, + }; + }, + on_return: (result) => { + return { + n: result.n + 1, + }; + }, + }, + { + name: 'error number five', + on_error: a => { + a.cancel_error(); + return { n: 5 }; + }, + } + ], + async delegate (args) { + const { n } = args; + if ( n === 3 ) { + throw new Error('test error'); + } + return { n: 'oops' }; + } + }); + expect(await invoker.run({ n: 2 })).to.deep.equal({ n: 6 }); + }); +}); From ea409d15785d850dbb67fe312dda377039756240 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 25 Jul 2024 18:00:05 -0400 Subject: [PATCH 0624/2119] dev: begin using Invoker for driver calls --- .../src/services/drivers/DriverService.js | 95 ++++++++++--------- 1 file changed, 48 insertions(+), 47 deletions(-) diff --git a/src/backend/src/services/drivers/DriverService.js b/src/backend/src/services/drivers/DriverService.js index 8ce8dd4e8d..c6f2c1e261 100644 --- a/src/backend/src/services/drivers/DriverService.js +++ b/src/backend/src/services/drivers/DriverService.js @@ -24,6 +24,7 @@ const BaseService = require("../BaseService"); const { Driver } = require("../../definitions/Driver"); const { PermissionUtil } = require("../auth/PermissionService"); const { PolicyEnforcer } = require("./PolicyEnforcer"); +const { Invoker } = require("@heyputer/puter-js-common/src/libs/invoker"); /** * DriverService provides the functionality of Puter drivers. @@ -185,32 +186,16 @@ class DriverService extends BaseService { driver, method, }); - try { - await policy_enforcer.check(); - const result = await this.call_new_({ - service_name: driver, - service, - method, - args: processed_args, - iface, - }); - await policy_enforcer.on_success(); - return result; - } catch (e) { - policy_enforcer.on_fail(); - console.error(e); - let for_user = (e instanceof APIError) || (e instanceof DriverError); - if ( ! for_user ) this.errors.report(`driver:${iface}:${method}`, { - source: e, - trace: true, - // TODO: alarm will not be suitable for all errors. - alarm: true, - extra: { - args, - } - }); - return this._driver_response_from_error(e, meta); - } + await policy_enforcer.check(); + const result = await this.call_new_({ + service_name: driver, + service, + method, + args: processed_args, + iface, + }); + await policy_enforcer.on_success(); + return result; } } @@ -298,28 +283,44 @@ class DriverService extends BaseService { service, method, args, iface, }) { - const svc_registry = this.services.get('registry'); - const c_interfaces = svc_registry.get('interfaces'); - let result = await service.as(iface)[method](args); - if ( result instanceof TypedValue ) { - const interface_ = c_interfaces.get(iface); - let desired_type = interface_.methods[method] - .result_choices[0].type; - const svc_coercion = services.get('coercion'); - result = await svc_coercion.coerce(desired_type, result); - } - const service_meta = {}; - if ( service.list_traits().includes('version') ) { - service_meta.version = service.as('version').get_version(); - } - return { - success: true, - service: { - ...service_meta, - name: service_name, + const invoker = Invoker.create({ + decorators: [ + { + name: 'add metadata', + on_return: async result => { + const service_meta = {}; + if ( service.list_traits().includes('version') ) { + service_meta.version = service.as('version').get_version(); + } + return { + success: true, + service: { + ...service_meta, + name: service_name, + }, + result, + }; + }, + }, + { + name: 'result coercion', + on_return: async (result) => { + if ( result instanceof TypedValue ) { + const interface_ = c_interfaces.get(iface); + let desired_type = interface_.methods[method] + .result_choices[0].type; + const svc_coercion = services.get('coercion'); + result = await svc_coercion.coerce(desired_type, result); + } + return result; + }, + }, + ], + delegate: async (args) => { + return await service.as(iface)[method](args); }, - result - }; + }); + return await invoker.run(args); } async _driver_response_from_error (e, meta) { From 780a9934654e7b158cbba4ff510d2c685d2c84fc Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 25 Jul 2024 19:59:45 -0400 Subject: [PATCH 0625/2119] dev: move policy selection to call_new_ --- .../src/services/drivers/DriverService.js | 131 ++++++++---------- .../src/services/drivers/PolicyEnforcer.js | 11 -- 2 files changed, 61 insertions(+), 81 deletions(-) delete mode 100644 src/backend/src/services/drivers/PolicyEnforcer.js diff --git a/src/backend/src/services/drivers/DriverService.js b/src/backend/src/services/drivers/DriverService.js index c6f2c1e261..354c05b753 100644 --- a/src/backend/src/services/drivers/DriverService.js +++ b/src/backend/src/services/drivers/DriverService.js @@ -23,7 +23,6 @@ const { TypedValue } = require("./meta/Runtime"); const BaseService = require("../BaseService"); const { Driver } = require("../../definitions/Driver"); const { PermissionUtil } = require("../auth/PermissionService"); -const { PolicyEnforcer } = require("./PolicyEnforcer"); const { Invoker } = require("@heyputer/puter-js-common/src/libs/invoker"); /** @@ -129,74 +128,12 @@ class DriverService extends BaseService { })(); if ( driver_service_exists ) { const service = this.services.get(driver); - const reading = await svc_permission.scan( + return await this.call_new_({ actor, - PermissionUtil.join('service', driver, 'ii', iface), - ); - console.log({ - perm: PermissionUtil.join('service', driver, 'ii', iface), - reading, + service, + service_name: driver, + iface, method, args: processed_args, }); - const options = PermissionUtil.reading_to_options(reading); - if ( options.length > 0 ) { - const option = await this.select_best_option_(options); - const policies = await this.get_policies_for_option_(option); - console.log('SLA', JSON.stringify(policies, undefined, ' ')); - - // NOT FINAL: For now we apply monthly usage logic - // to the first holder of the permission. Later this - // will be changed so monthly usage can cascade across - // multiple actors. I decided not to implement this - // immediately because it's a hefty time sink and it's - // going to be some time before we can offer this feature - // to the end-user either way. - - let effective_policy = null; - for ( const policy of policies ) { - if ( policy.holder ) { - effective_policy = policy; - break; - } - } - - if ( ! effective_policy ) { - throw new Error( - 'policies with no effective user are not yet ' + - 'supported' - ); - } - - // NOT FINAL: this will be handled by 'get_policies_for_option_' - // when cascading monthly usage is implemented. - const svc_systemData = this.services.get('system-data'); - const svc_su = this.services.get('su'); - effective_policy = await svc_su.sudo(async () => { - return await svc_systemData.interpret(effective_policy.data); - }); - - effective_policy = effective_policy.policy; - - console.log('EFFECTIVE', - JSON.stringify(effective_policy, undefined, ' ')); - - const policy_enforcer = new PolicyEnforcer({ - services: this.services, - actor, - policy: effective_policy, - driver, method, - }); - - await policy_enforcer.check(); - const result = await this.call_new_({ - service_name: driver, - service, - method, - args: processed_args, - iface, - }); - await policy_enforcer.on_success(); - return result; - } } const reading = await svc_permission.scan(actor, `driver:${iface}:${method}`); @@ -279,10 +216,64 @@ class DriverService extends BaseService { } async call_new_ ({ + actor, + service, service_name, - service, method, args, - iface, + iface, method, args, }) { + const svc_permission = this.services.get('permission'); + const reading = await svc_permission.scan( + actor, + PermissionUtil.join('service', service_name, 'ii', iface), + ); + console.log({ + perm: PermissionUtil.join('service', service_name, 'ii', iface), + reading, + }); + const options = PermissionUtil.reading_to_options(reading); + if ( options.length <= 0 ) { + throw APIError.create('forbidden'); + } + const option = await this.select_best_option_(options); + const policies = await this.get_policies_for_option_(option); + console.log('SLA', JSON.stringify(policies, undefined, ' ')); + + // NOT FINAL: For now we apply monthly usage logic + // to the first holder of the permission. Later this + // will be changed so monthly usage can cascade across + // multiple actors. I decided not to implement this + // immediately because it's a hefty time sink and it's + // going to be some time before we can offer this feature + // to the end-user either way. + + let effective_policy = null; + for ( const policy of policies ) { + if ( policy.holder ) { + effective_policy = policy; + break; + } + } + + if ( ! effective_policy ) { + throw new Error( + 'policies with no effective user are not yet ' + + 'supported' + ); + } + + // NOT FINAL: this will be handled by 'get_policies_for_option_' + // when cascading monthly usage is implemented. + const svc_systemData = this.services.get('system-data'); + const svc_su = this.services.get('su'); + effective_policy = await svc_su.sudo(async () => { + return await svc_systemData.interpret(effective_policy.data); + }); + + effective_policy = effective_policy.policy; + + console.log('EFFECTIVE', + JSON.stringify(effective_policy, undefined, ' ')); + const invoker = Invoker.create({ decorators: [ { @@ -322,7 +313,7 @@ class DriverService extends BaseService { }); return await invoker.run(args); } - + async _driver_response_from_error (e, meta) { let serializable = (e instanceof APIError) || (e instanceof DriverError); if ( serializable ) { diff --git a/src/backend/src/services/drivers/PolicyEnforcer.js b/src/backend/src/services/drivers/PolicyEnforcer.js deleted file mode 100644 index 5b2347c891..0000000000 --- a/src/backend/src/services/drivers/PolicyEnforcer.js +++ /dev/null @@ -1,11 +0,0 @@ -class PolicyEnforcer { - constructor (context) { - this.context = context; - } - - async check () {} - async on_success () {} - async on_fail () {} -} - -module.exports = { PolicyEnforcer }; From 8be7a7d2190889e6539ec3d1821bfc28171ece4f Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 25 Jul 2024 20:23:05 -0400 Subject: [PATCH 0626/2119] dev: add logical rate-limit to new call method --- src/backend/src/services/SUService.js | 11 +++++++--- .../src/services/drivers/DriverService.js | 20 +++++++++++++++++++ 2 files changed, 28 insertions(+), 3 deletions(-) diff --git a/src/backend/src/services/SUService.js b/src/backend/src/services/SUService.js index 94124532e5..30491b55b9 100644 --- a/src/backend/src/services/SUService.js +++ b/src/backend/src/services/SUService.js @@ -22,10 +22,15 @@ class SUService extends BaseService { async get_system_actor () { return this.sys_actor_; } - async sudo (callback) { + async sudo (actor, callback) { + if ( ! callback ) { + callback = actor; + actor = await this.sys_actor_; + } + actor = Actor.adapt(actor); return await Context.get().sub({ - user: await this.sys_user_, - actor: await this.sys_actor_, + actor, + user: actor.type.user, }).arun(callback); } } diff --git a/src/backend/src/services/drivers/DriverService.js b/src/backend/src/services/drivers/DriverService.js index 354c05b753..5e9ef34822 100644 --- a/src/backend/src/services/drivers/DriverService.js +++ b/src/backend/src/services/drivers/DriverService.js @@ -24,6 +24,7 @@ const BaseService = require("../BaseService"); const { Driver } = require("../../definitions/Driver"); const { PermissionUtil } = require("../auth/PermissionService"); const { Invoker } = require("@heyputer/puter-js-common/src/libs/invoker"); +const { get_user } = require("../../helpers"); /** * DriverService provides the functionality of Puter drivers. @@ -261,6 +262,9 @@ class DriverService extends BaseService { ); } + const policy_holder = await get_user( + { username: effective_policy.holder }); + // NOT FINAL: this will be handled by 'get_policies_for_option_' // when cascading monthly usage is implemented. const svc_systemData = this.services.get('system-data'); @@ -276,6 +280,22 @@ class DriverService extends BaseService { const invoker = Invoker.create({ decorators: [ + { + name: 'enforce logical rate-limit', + on_call: async args => { + if ( ! effective_policy['rate-limit'] ) return args; + const svc_su = this.services.get('su'); + const svc_rateLimit = this.services.get('rate-limit'); + await svc_su.sudo(policy_holder, async () => { + await svc_rateLimit.check_and_increment( + `V1:${service_name}:${iface}:${method}`, + effective_policy['rate-limit'].max, + effective_policy['rate-limit'].period, + ); + }); + return args; + }, + }, { name: 'add metadata', on_return: async result => { From af3180a57ff086c860fad64b5b920ef8e6530a4a Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 25 Jul 2024 22:09:24 -0400 Subject: [PATCH 0627/2119] dev: add monthly usage to new call method --- .../src/services/drivers/DriverService.js | 31 +++++ .../src/services/sla/MonthlyUsageService.js | 117 ++++++++++++------ 2 files changed, 108 insertions(+), 40 deletions(-) diff --git a/src/backend/src/services/drivers/DriverService.js b/src/backend/src/services/drivers/DriverService.js index 5e9ef34822..f2f15eac5c 100644 --- a/src/backend/src/services/drivers/DriverService.js +++ b/src/backend/src/services/drivers/DriverService.js @@ -278,6 +278,8 @@ class DriverService extends BaseService { console.log('EFFECTIVE', JSON.stringify(effective_policy, undefined, ' ')); + const method_key = `V1:${service_name}:${iface}:${method}`; + const invoker = Invoker.create({ decorators: [ { @@ -296,6 +298,35 @@ class DriverService extends BaseService { return args; }, }, + { + name: 'enforce monthly usage limit', + on_call: async args => { + if ( ! effective_policy['monthly-limit'] ) return args; + const svc_monthlyUsage = services.get('monthly-usage'); + const count = await svc_monthlyUsage.check_2( + actor, method_key + ); + if ( count >= effective_policy['monthly-limit'] ) { + throw APIError.create('monthly_limit_exceeded', null, { + method_key, + limit: effective_policy['monthly-limit'], + }); + } + return args; + }, + on_return: async result => { + console.log('monthly usage is returning'); + const svc_monthlyUsage = services.get('monthly-usage'); + const extra = { + 'driver.interface': iface, + 'driver.implementation': service_name, + 'driver.method': method, + }; + console.log('calling the increment method') + await svc_monthlyUsage.increment(actor, method_key, extra); + return result; + }, + }, { name: 'add metadata', on_return: async result => { diff --git a/src/backend/src/services/sla/MonthlyUsageService.js b/src/backend/src/services/sla/MonthlyUsageService.js index 5705ff8974..1718039a76 100644 --- a/src/backend/src/services/sla/MonthlyUsageService.js +++ b/src/backend/src/services/sla/MonthlyUsageService.js @@ -34,47 +34,21 @@ class MonthlyUsageService extends BaseService { const maybe_app_id = actor.type.app?.id; - if ( this.db.case({ sqlite: true, otherwise: false }) ) { - return; - } - - const vals = - [ - year, month, key, actor.type.user.id, maybe_app_id, JSON.stringify(extra), - ...this.db.case({ mysql: [JSON.stringify(extra)], otherwise: [] }), - ] - // UPSERT increment count - try { - await this.db.write( - 'INSERT INTO `service_usage_monthly` (`year`, `month`, `key`, `count`, `user_id`, `app_id`, `extra`) ' + - 'VALUES (?, ?, ?, 1, ?, ?, ?) ' + - this.db.case({ - mysql: 'ON DUPLICATE KEY UPDATE `count` = `count` + 1, `extra` = ?', - sqlite: ' ', - // sqlite: 'ON CONFLICT(`year`, `month`, `key`, `user_id`, `app_id`) ' + - // 'DO UPDATE SET `count` = `count` + 1 AND `extra` = ?', - }), - [ - year, month, key, actor.type.user.id, maybe_app_id ?? null, JSON.stringify(extra), - ...this.db.case({ mysql: [JSON.stringify(extra)], otherwise: [] }), - ] - ); - } catch (e) { - // if ( e.code !== 'SQLITE_ERROR' && e.code !== 'SQLITE_CONSTRAINT_PRIMARYKEY' ) throw e; - // The "ON CONFLICT" clause isn't currently working. - await this.db.write( - 'UPDATE `service_usage_monthly` ' + - 'SET `count` = `count` + 1, `extra` = ? ' + - 'WHERE `year` = ? AND `month` = ? AND `key` = ? ' + - 'AND `user_id` = ? AND `app_id` = ?', - [ - JSON.stringify(extra), - year, month, key, actor.type.user.id, maybe_app_id, - ] - ); - - } + await this.db.write( + 'INSERT INTO `service_usage_monthly` (`year`, `month`, `key`, `count`, `user_id`, `app_id`, `extra`) ' + + 'VALUES (?, ?, ?, 1, ?, ?, ?) ' + + this.db.case({ + mysql: 'ON DUPLICATE KEY UPDATE `count` = `count` + 1, `extra` = ?', + // sqlite: ' ', + otherwise: 'ON CONFLICT(`year`, `month`, `key`) ' + + 'DO UPDATE SET `count` = `count` + 1, `extra` = ?', + }), + [ + year, month, key, actor.type.user.id, maybe_app_id ?? null, JSON.stringify(extra), + ...this.db.case({ mysql: [JSON.stringify(extra)], otherwise: [JSON.stringify({ a: 1 })] }), + ] + ); } async check (actor, specifiers) { @@ -88,6 +62,18 @@ class MonthlyUsageService extends BaseService { } + async check_2 (actor, key) { + key = `${actor.uid}:${key}`; + if ( actor.type instanceof UserActorType ) { + return await this._user_check_2(actor, key); + } + + if ( actor.type instanceof AppUnderUserActorType ) { + return await this._app_under_user_check_2(actor, key); + } + + } + async _user_check (actor, specifiers) { const year = new Date().getUTCFullYear(); // months are zero-indexed by getUTCMonth, which could be confusing @@ -106,6 +92,36 @@ class MonthlyUsageService extends BaseService { return rows[0]?.sum || 0; } + async _user_check_2 (actor, key) { + const year = new Date().getUTCFullYear(); + // months are zero-indexed by getUTCMonth, which could be confusing + const month = new Date().getUTCMonth() + 1; + + console.log( + 'what check query?', + 'SELECT SUM(`count`) AS sum FROM `service_usage_monthly` ' + + 'WHERE `year` = ? AND `month` = ? AND `user_id` = ? ' + + 'AND `key` = ?', + [ + year, month, actor.type.user.id, + key, + ] + ); + const rows = await this.db.read( + 'SELECT SUM(`count`) AS sum FROM `service_usage_monthly` ' + + 'WHERE `year` = ? AND `month` = ? AND `user_id` = ? ' + + 'AND `key` = ?', + [ + year, month, actor.type.user.id, + key, + ] + ); + + console.log('what rows?', rows); + + return rows[0]?.sum || 0; + } + async _app_under_user_check (actor, specifiers) { const year = new Date().getUTCFullYear(); // months are zero-indexed by getUTCMonth, which could be confusing @@ -128,6 +144,27 @@ class MonthlyUsageService extends BaseService { return rows[0]?.count || 0; } + + async _app_under_user_check_2 (actor, key) { + const year = new Date().getUTCFullYear(); + // months are zero-indexed by getUTCMonth, which could be confusing + const month = new Date().getUTCMonth() + 1; + + // SELECT count + const rows = await this.db.read( + 'SELECT `count` FROM `service_usage_monthly` ' + + 'WHERE `year` = ? AND `month` = ? AND `user_id` = ? ' + + 'AND `app_id` = ? ' + + 'AND `key` = ?', + [ + year, month, actor.type.user.id, + actor.type.app.id, + key, + ] + ); + + return rows[0]?.count || 0; + } } module.exports = { From 6213806aba1300d0f51046532f13a725089c41b2 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 25 Jul 2024 23:07:50 -0400 Subject: [PATCH 0628/2119] dev: move driver arg types to a registry --- src/backend/src/services/drivers/DriverService.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/backend/src/services/drivers/DriverService.js b/src/backend/src/services/drivers/DriverService.js index f2f15eac5c..510b017fcb 100644 --- a/src/backend/src/services/drivers/DriverService.js +++ b/src/backend/src/services/drivers/DriverService.js @@ -43,18 +43,26 @@ class DriverService extends BaseService { const svc_registry = this.services.get('registry'); svc_registry.register_collection('interfaces'); svc_registry.register_collection('drivers'); + svc_registry.register_collection('types'); } async ['__on_registry.entries'] () { const services = this.services; const svc_registry = services.get('registry'); const col_interfaces = svc_registry.get('interfaces'); const col_drivers = svc_registry.get('drivers'); + const col_types = svc_registry.get('types'); { const default_interfaces = require('./interfaces'); for ( const k in default_interfaces ) { col_interfaces.set(k, default_interfaces[k]); } } + { + const types = this.modules.types; + for ( const k in types ) { + col_types.set(k, types[k]); + } + } await services.emit('driver.register.interfaces', { col_interfaces }); await services.emit('driver.register.drivers', @@ -387,6 +395,7 @@ class DriverService extends BaseService { async _process_args (interface_name, method_name, args) { const svc_registry = this.services.get('registry'); const c_interfaces = svc_registry.get('interfaces'); + const c_types = svc_registry.get('types'); // Note: 'interface' is a strict mode reserved word. const interface_ = c_interfaces.get(interface_name); @@ -399,9 +408,10 @@ class DriverService extends BaseService { if ( ! method ) { throw APIError.create('method_not_found', null, { interface_name, method_name }); } + for ( const [arg_name, arg_descriptor] of Object.entries(method.parameters) ) { const arg_value = args[arg_name]; - const arg_behaviour = this.modules.types[arg_descriptor.type]; + const arg_behaviour = c_types.get(arg_descriptor.type); // TODO: eventually put this in arg behaviour base class. // There's a particular way I want to do this that involves From 654e0b93331a65c336492d19afdc77e393ddb5b4 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 26 Jul 2024 01:23:22 -0400 Subject: [PATCH 0629/2119] move: move selfhosting-related services to a module --- src/backend/exports.js | 2 +- .../ComplainAboutVersionsService.js | 4 +-- .../selfhosted}/DefaultUserService.js | 22 ++++++------- .../selfhosted}/DevWatcherService.js | 2 +- .../selfhosted}/SelfHostedModule.js | 32 +++++++++++-------- .../selfhosted}/SelfhostedService.js | 8 ++--- .../selfhosted}/ServeSingeFileService.js | 2 +- .../selfhosted}/ServeStaticFilesService.js | 2 +- 8 files changed, 39 insertions(+), 35 deletions(-) rename src/backend/src/{services => modules/selfhosted}/ComplainAboutVersionsService.js (96%) rename src/backend/src/{services => modules/selfhosted}/DefaultUserService.js (92%) rename src/backend/src/{services => modules/selfhosted}/DevWatcherService.js (98%) rename src/backend/src/{ => modules/selfhosted}/SelfHostedModule.js (75%) rename src/backend/src/{services => modules/selfhosted}/SelfhostedService.js (84%) rename src/backend/src/{services => modules/selfhosted}/ServeSingeFileService.js (95%) rename src/backend/src/{services => modules/selfhosted}/ServeStaticFilesService.js (95%) diff --git a/src/backend/exports.js b/src/backend/exports.js index 8ffa98695d..77bc94024c 100644 --- a/src/backend/exports.js +++ b/src/backend/exports.js @@ -20,7 +20,7 @@ const CoreModule = require("./src/CoreModule.js"); const { Kernel } = require("./src/Kernel.js"); const DatabaseModule = require("./src/DatabaseModule.js"); const LocalDiskStorageModule = require("./src/LocalDiskStorageModule.js"); -const SelfHostedModule = require("./src/SelfHostedModule.js"); +const SelfHostedModule = require("./src/modules/selfhosted/SelfHostedModule.js"); const PuterDriversModule = require("./src/PuterDriversModule.js"); const { testlaunch } = require("./src/index.js"); const BaseService = require("./src/services/BaseService.js"); diff --git a/src/backend/src/services/ComplainAboutVersionsService.js b/src/backend/src/modules/selfhosted/ComplainAboutVersionsService.js similarity index 96% rename from src/backend/src/services/ComplainAboutVersionsService.js rename to src/backend/src/modules/selfhosted/ComplainAboutVersionsService.js index 11b6b11fa6..9effd10d0b 100644 --- a/src/backend/src/services/ComplainAboutVersionsService.js +++ b/src/backend/src/modules/selfhosted/ComplainAboutVersionsService.js @@ -16,8 +16,8 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { BaseService } = require("../../exports"); -const { surrounding_box } = require("../fun/dev-console-ui-utils"); +const { BaseService } = require("../../../exports"); +const { surrounding_box } = require("../../fun/dev-console-ui-utils"); class ComplainAboutVersionsService extends BaseService { static DESCRIPTION = ` diff --git a/src/backend/src/services/DefaultUserService.js b/src/backend/src/modules/selfhosted/DefaultUserService.js similarity index 92% rename from src/backend/src/services/DefaultUserService.js rename to src/backend/src/modules/selfhosted/DefaultUserService.js index e9697e77cf..d386afef96 100644 --- a/src/backend/src/services/DefaultUserService.js +++ b/src/backend/src/modules/selfhosted/DefaultUserService.js @@ -16,17 +16,17 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { QuickMkdir } = require("../filesystem/hl_operations/hl_mkdir"); -const { HLWrite } = require("../filesystem/hl_operations/hl_write"); -const { NodePathSelector } = require("../filesystem/node/selectors"); -const { surrounding_box } = require("../fun/dev-console-ui-utils"); -const { get_user, generate_system_fsentries, invalidate_cached_user } = require("../helpers"); -const { Context } = require("../util/context"); -const { asyncSafeSetInterval } = require("../util/promise"); -const { buffer_to_stream } = require("../util/streamutil"); -const BaseService = require("./BaseService"); -const { Actor, UserActorType } = require("./auth/Actor"); -const { DB_WRITE } = require("./database/consts"); +const { QuickMkdir } = require("../../filesystem/hl_operations/hl_mkdir"); +const { HLWrite } = require("../../filesystem/hl_operations/hl_write"); +const { NodePathSelector } = require("../../filesystem/node/selectors"); +const { surrounding_box } = require("../../fun/dev-console-ui-utils"); +const { get_user, generate_system_fsentries, invalidate_cached_user } = require("../../helpers"); +const { Context } = require("../../util/context"); +const { asyncSafeSetInterval } = require("../../util/promise"); +const { buffer_to_stream } = require("../../util/streamutil"); +const BaseService = require("../../services/BaseService"); +const { Actor, UserActorType } = require("../../services/auth/Actor"); +const { DB_WRITE } = require("../../services/database/consts"); const USERNAME = 'admin'; diff --git a/src/backend/src/services/DevWatcherService.js b/src/backend/src/modules/selfhosted/DevWatcherService.js similarity index 98% rename from src/backend/src/services/DevWatcherService.js rename to src/backend/src/modules/selfhosted/DevWatcherService.js index 4620a6d19e..69b5a2d2b2 100644 --- a/src/backend/src/services/DevWatcherService.js +++ b/src/backend/src/modules/selfhosted/DevWatcherService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const BaseService = require("./BaseService"); +const BaseService = require("../../services/BaseService"); class ProxyLogger { constructor (log) { diff --git a/src/backend/src/SelfHostedModule.js b/src/backend/src/modules/selfhosted/SelfHostedModule.js similarity index 75% rename from src/backend/src/SelfHostedModule.js rename to src/backend/src/modules/selfhosted/SelfHostedModule.js index bc4a5183a8..8f1b6e4da0 100644 --- a/src/backend/src/SelfHostedModule.js +++ b/src/backend/src/modules/selfhosted/SelfHostedModule.js @@ -17,27 +17,30 @@ * along with this program. If not, see . */ const { AdvancedBase } = require("@heyputer/puter-js-common"); -const config = require("./config"); +const config = require("../../config"); class SelfHostedModule extends AdvancedBase { async install (context) { const services = context.get('services'); - const { SelfhostedService } = require('./services/SelfhostedService'); + const { SelfhostedService } = require('./SelfhostedService'); services.registerService('__selfhosted', SelfhostedService); - const DefaultUserService = require('./services/DefaultUserService'); + const DefaultUserService = require('./DefaultUserService'); services.registerService('__default-user', DefaultUserService); - const ComplainAboutVersionsService = require('./services/ComplainAboutVersionsService'); + const ComplainAboutVersionsService = require('./ComplainAboutVersionsService'); services.registerService('complain-about-versions', ComplainAboutVersionsService); - const DevWatcherService = require('./services/DevWatcherService'); + const DevWatcherService = require('./DevWatcherService'); const path_ = require('path'); + // TODO: sucks + const RELATIVE_PATH = '../../../../../'; + if ( ! config.no_devwatch ) services.registerService('__dev-watcher', DevWatcherService, { - root: path_.resolve(__dirname, '../../../'), + root: path_.resolve(__dirname, RELATIVE_PATH), commands: [ { name: 'puter.js:webpack-watch', @@ -75,36 +78,37 @@ class SelfHostedModule extends AdvancedBase { ], }); - const { ServeStaticFilesService } = require("./services/ServeStaticFilesService"); + const { ServeStaticFilesService } = require("./ServeStaticFilesService"); services.registerService('__serve-puterjs', ServeStaticFilesService, { directories: [ { prefix: '/sdk', - path: path_.resolve(__dirname, '../../../src/puter-js/dist'), + path: path_.resolve(__dirname, RELATIVE_PATH, 'src/puter-js/dist'), }, { prefix: '/builtin/terminal', - path: path_.resolve(__dirname, '../../../src/terminal/dist'), + path: path_.resolve(__dirname, RELATIVE_PATH, 'src/terminal/dist'), }, { prefix: '/builtin/phoenix', - path: path_.resolve(__dirname, '../../../src/phoenix/dist'), + path: path_.resolve(__dirname, RELATIVE_PATH, 'src/phoenix/dist'), }, { prefix: '/builtin/git', - path: path_.resolve(__dirname, '../../../src/git/dist'), + path: path_.resolve(__dirname, RELATIVE_PATH, 'src/git/dist'), }, { prefix: '/builtin/dev-center', - path: path_.resolve(__dirname, '../../../src/dev-center'), + path: path_.resolve(__dirname, RELATIVE_PATH, 'src/dev-center'), }, ], }); - const { ServeSingleFileService } = require('./services/ServeSingeFileService'); + const { ServeSingleFileService } = require('./ServeSingeFileService'); services.registerService('__serve-puterjs-new', ServeSingleFileService, { path: path_.resolve(__dirname, - '../../../src/puter-js/dist/puter.dev.js'), + RELATIVE_PATH, + 'src/puter-js/dist/puter.dev.js'), route: '/puter.js/v2', }); } diff --git a/src/backend/src/services/SelfhostedService.js b/src/backend/src/modules/selfhosted/SelfhostedService.js similarity index 84% rename from src/backend/src/services/SelfhostedService.js rename to src/backend/src/modules/selfhosted/SelfhostedService.js index fda861d634..7a0109eb33 100644 --- a/src/backend/src/services/SelfhostedService.js +++ b/src/backend/src/modules/selfhosted/SelfhostedService.js @@ -16,10 +16,10 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { DBKVStore } = require("../drivers/DBKVStore"); -const { EntityStoreImplementation } = require("../drivers/EntityStoreImplementation"); -const { HelloWorld } = require("../drivers/HelloWorld"); -const BaseService = require("./BaseService"); +const { DBKVStore } = require("../../drivers/DBKVStore"); +const { EntityStoreImplementation } = require("../../drivers/EntityStoreImplementation"); +const { HelloWorld } = require("../../drivers/HelloWorld"); +const BaseService = require("../../services/BaseService"); class SelfhostedService extends BaseService { static description = ` diff --git a/src/backend/src/services/ServeSingeFileService.js b/src/backend/src/modules/selfhosted/ServeSingeFileService.js similarity index 95% rename from src/backend/src/services/ServeSingeFileService.js rename to src/backend/src/modules/selfhosted/ServeSingeFileService.js index 9f47224d60..77ffdc777e 100644 --- a/src/backend/src/services/ServeSingeFileService.js +++ b/src/backend/src/modules/selfhosted/ServeSingeFileService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const BaseService = require("./BaseService"); +const BaseService = require("../../services/BaseService"); class ServeSingleFileService extends BaseService { async _init (args) { diff --git a/src/backend/src/services/ServeStaticFilesService.js b/src/backend/src/modules/selfhosted/ServeStaticFilesService.js similarity index 95% rename from src/backend/src/services/ServeStaticFilesService.js rename to src/backend/src/modules/selfhosted/ServeStaticFilesService.js index d303d45c6e..3ef7430ce9 100644 --- a/src/backend/src/services/ServeStaticFilesService.js +++ b/src/backend/src/modules/selfhosted/ServeStaticFilesService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const BaseService = require("./BaseService"); +const BaseService = require("../../services/BaseService"); class ServeStaticFilesService extends BaseService { async _init (args) { From 033643b0e757b51ea0be90e2198bbec65d31cfc5 Mon Sep 17 00:00:00 2001 From: Muhammad Fauzi Date: Sat, 27 Jul 2024 02:45:05 +0700 Subject: [PATCH 0630/2119] feat: Add Indonesian Translation for i18n --- src/gui/src/i18n/translations/id.js | 352 ++++++++++++++++++ src/gui/src/i18n/translations/translations.js | 2 + 2 files changed, 354 insertions(+) create mode 100644 src/gui/src/i18n/translations/id.js diff --git a/src/gui/src/i18n/translations/id.js b/src/gui/src/i18n/translations/id.js new file mode 100644 index 0000000000..cd50a12a81 --- /dev/null +++ b/src/gui/src/i18n/translations/id.js @@ -0,0 +1,352 @@ +/** + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ + + +const id = { + name: "Bahasa Indonesia", + english_name: "Indonesian", + code: "id", + dictionary: { + about: "Tentang", + account: "Akun", + account_password: "Verifikasi Kata Sandi Akun", + access_granted_to: "Akses Diberikan Kepada", + add_existing_account: "Tambahkan Akun yang Ada", + all_fields_required: 'Semua kolom diperlukan.', + allow: 'Izinkan', + apply: "Terapkan", + ascending: 'Menaik', + associated_websites: "Situs Web Terkait", + auto_arrange: 'Atur Otomatis', + background: "Latar Belakang", + browse: "Jelajahi", + cancel: 'Batal', + center: 'Tengah', + change_desktop_background: 'Ubah latar belakang desktop…', + change_email: "Ubah Email", + change_language: "Ubah Bahasa", + change_password: "Ubah Kata Sandi", + change_ui_colors: "Ubah Warna UI", + change_username: "Ubah Nama Pengguna", + close: 'Tutup', + close_all_windows: "Tutup Semua Jendela", + close_all_windows_confirm: "Apakah Anda yakin ingin menutup semua jendela?", + close_all_windows_and_log_out: 'Tutup Jendela dan Keluar', + change_always_open_with: "Apakah Anda ingin selalu membuka jenis file ini dengan", + color: 'Warna', + confirm: 'Konfirmasi', + confirm_2fa_setup: 'Saya telah menambahkan kode ke aplikasi autentikator saya', + confirm_2fa_recovery: 'Saya telah menyimpan kode pemulihan saya di tempat yang aman', + confirm_account_for_free_referral_storage_c2a: 'Buat akun dan konfirmasi alamat email Anda untuk menerima 1 GB penyimpanan gratis. Teman Anda juga akan mendapatkan 1 GB penyimpanan gratis.', + confirm_code_generic_incorrect: "Kode Salah.", + confirm_code_generic_too_many_requests: "Terlalu banyak permintaan. Silakan tunggu beberapa menit.", + confirm_code_generic_submit: "Kirim Kode", + confirm_code_generic_try_again: "Coba Lagi", + confirm_code_generic_title: "Masukkan Kode Konfirmasi", + confirm_code_2fa_instruction: "Masukkan kode 6-digit dari aplikasi autentikator Anda.", + confirm_code_2fa_submit_btn: "Kirim", + confirm_code_2fa_title: "Masukkan Kode 2FA", + confirm_delete_multiple_items: 'Apakah Anda yakin ingin menghapus item-item ini secara permanen?', + confirm_delete_single_item: 'Apakah Anda ingin menghapus item ini secara permanen?', + confirm_open_apps_log_out: 'Anda memiliki aplikasi yang terbuka. Apakah Anda yakin ingin keluar?', + confirm_new_password: "Konfirmasi Kata Sandi Baru", + confirm_delete_user: "Apakah Anda yakin ingin menghapus akun Anda? Semua file dan data Anda akan dihapus secara permanen. Tindakan ini tidak dapat dibatalkan.", + confirm_delete_user_title: "Hapus Akun?", + confirm_session_revoke: "Apakah Anda yakin ingin mencabut sesi ini?", + confirm_your_email_address: "Konfirmasi Alamat Email Anda", + contact_us: "Hubungi Kami", + contact_us_verification_required: "Anda harus memiliki alamat email yang terverifikasi untuk menggunakan ini.", + contain: 'Kandung', + continue: "Lanjutkan", + copy: 'Salin', + copy_link: "Salin Tautan", + copying: "Menyalin", + copying_file: "Menyalin %%", + cover: 'Sampul', + create_account: "Buat Akun", + create_free_account: "Buat Akun Gratis", + create_shortcut: "Buat Pintasan", + credits: "Kredit", + current_password: "Kata Sandi Saat Ini", + cut: 'Potong', + clock: "Jam", + clock_visible_hide: 'Sembunyikan - Selalu tersembunyi', + clock_visible_show: 'Tampilkan - Selalu terlihat', + clock_visible_auto: 'Otomatis - Default, terlihat hanya dalam mode layar penuh.', + close_all: 'Tutup Semua', + created: 'Dibuat', + date_modified: 'Tanggal diubah', + default: 'Default', + delete: 'Hapus', + delete_account: "Hapus Akun", + delete_permanently: "Hapus Permanen", + deleting_file: "Menghapus %%", + deploy_as_app: 'Pasang sebagai aplikasi', + descending: 'Menurun', + desktop: 'Desktop', + desktop_background_fit: "Cocokkan", + developers: "Pengembang", + dir_published_as_website: `%strong% telah diterbitkan di:`, + disable_2fa: 'Nonaktifkan 2FA', + disable_2fa_confirm: "Apakah Anda yakin ingin menonaktifkan 2FA?", + disable_2fa_instructions: "Masukkan kata sandi Anda untuk menonaktifkan 2FA.", + disassociate_dir: "Pisahkan Direktori", + documents: 'Dokumen', + dont_allow: 'Jangan Izinkan', + download: 'Unduh', + download_file: 'Unduh File', + downloading: "Mengunduh", + email: "Email", + email_change_confirmation_sent: "Email konfirmasi telah dikirim ke alamat email baru Anda. Silakan periksa kotak masuk Anda dan ikuti petunjuk untuk menyelesaikan prosesnya.", + email_invalid: 'Email tidak valid.', + email_or_username: "Email atau Nama Pengguna", + email_required: 'Email diperlukan.', + empty_trash: 'Kosongkan Sampah', + empty_trash_confirmation: `Apakah Anda yakin ingin menghapus item-item di Sampah secara permanen?`, + emptying_trash: 'Mengosongkan Sampah…', + enable_2fa: 'Aktifkan 2FA', + end_hard: "Akhiri Secara Paksa", + end_process_force_confirm: "Apakah Anda yakin ingin memaksa menghentikan proses ini?", + end_soft: "Akhiri Secara Lembut", + enlarged_qr_code: "Kode QR Diperbesar", + enter_password_to_confirm_delete_user: "Masukkan kata sandi Anda untuk mengonfirmasi penghapusan akun", + error_message_is_missing: "Pesan kesalahan hilang.", + error_unknown_cause: "Terjadi kesalahan yang tidak diketahui.", + error_uploading_files: "Gagal mengunggah file", + favorites: "Favorit", + feedback: "Umpan Balik", + feedback_c2a: "Silakan gunakan formulir di bawah ini untuk mengirimkan umpan balik, komentar, dan laporan bug kepada kami.", + feedback_sent_confirmation: "Terima kasih telah menghubungi kami. Jika Anda memiliki email yang terhubung dengan akun Anda, Anda akan menerima balasan dari kami sesegera mungkin.", + fit: "Cocokkan", + folder: 'Folder', + force_quit: 'Keluar Paksa', + forgot_pass_c2a: "Lupa kata sandi?", + from: "Dari", + general: "Umum", + get_a_copy_of_on_puter: `Dapatkan salinan '%%' di Puter.com!`, + get_copy_link: 'Dapatkan Tautan Salinan', + hide_all_windows: "Sembunyikan Semua Jendela", + home: 'Beranda', + html_document: 'Dokumen HTML', + hue: 'Hue', + image: 'Gambar', + incorrect_password: "Kata sandi salah", + invite_link: "Tautan Undangan", + item: 'item', + items_in_trash_cannot_be_renamed: `Item ini tidak dapat dinamai ulang karena berada di sampah. Untuk mengganti nama item ini, pertama-tama seret keluar dari Sampah.`, + jpeg_image: 'Gambar JPEG', + keep_in_taskbar: 'Pertahankan di Taskbar', + language: "Bahasa", + license: "Lisensi", + lightness: 'Kecerahan', + link_copied: "Tautan disalin", + loading: 'Memuat', + log_in: "Masuk", + log_into_another_account_anyway: 'Masuk ke akun lain saja', + log_out: 'Keluar', + looks_good: "Tampak bagus!", + manage_sessions: "Kelola Sesi", + menubar_style: "Gaya Menubar", + menubar_style_desktop: "Desktop", + menubar_style_system: "Sistem", + menubar_style_window: "Jendela", + modified: 'Dimodifikasi', + move: 'Pindahkan', + moving_file: "Memindahkan %%", + my_websites: "Situs Web Saya", + name: 'Nama', + name_cannot_be_empty: 'Nama tidak boleh kosong.', + name_cannot_contain_double_period: "Nama tidak boleh berisi karakter '..'.", + name_cannot_contain_period: "Nama tidak boleh berisi karakter '.'.", + name_cannot_contain_slash: "Nama tidak boleh berisi karakter '/'", + name_must_be_string: "Nama hanya boleh berupa string.", + name_too_long: `Nama tidak boleh lebih dari %% karakter.`, + new: 'Baru', + new_email: 'Email Baru', + new_folder: "Folder Baru", + new_password: "Kata Sandi Baru", + new_username: "Nama Pengguna Baru", + no: "Tidak", + no_dir_associated_with_site: "Tidak ada direktori yang terkait dengan alamat ini.", + no_websites_published: "Anda belum menerbitkan situs web. Klik kanan pada folder untuk memulai.", + ok: "OK", + open: "Buka", + open_in_new_tab: "Buka di Tab Baru", + open_in_new_window: "Buka di Jendela Baru", + open_with: "Buka Dengan", + original_name: "Nama Asli", + original_path: "Jalur Asli", + oss_code_and_content: "Perangkat Lunak dan Konten Open Source", + password: "Kata Sandi", + password_changed: "Kata sandi telah diubah.", + password_recovery_rate_limit: "Anda telah mencapai batas kecepatan kami; silakan tunggu beberapa menit. Untuk mencegah ini di masa depan, hindari memuat ulang halaman terlalu sering.", + password_recovery_token_invalid: "Token pemulihan kata sandi ini tidak lagi berlaku.", + password_recovery_unknown_error: "Terjadi kesalahan yang tidak dikenal. Silakan coba lagi nanti.", + password_required: "Kata sandi diperlukan.", + password_strength_error: "Kata sandi harus panjangnya setidaknya 8 karakter dan mengandung setidaknya satu huruf kapital, satu huruf kecil, satu angka, dan satu karakter khusus.", + passwords_do_not_match: "`Kata Sandi Baru` dan `Konfirmasi Kata Sandi Baru` tidak cocok.", + paste: "Tempel", + paste_into_folder: "Tempel ke Folder", + path: "Jalur", + personalization: "Personalisasi", + pick_name_for_website: "Pilih nama untuk situs web Anda:", + picture: "Gambar", + pictures: "Gambar-gambar", + plural_suffix: "s", + powered_by_puter_js: `Ditenagai oleh {{link=docs}}Puter.js{{/link}}`, + preparing: "Memproses...", + preparing_for_upload: "Persiapan untuk diunggah...", + print: "Cetak", + privacy: "Privasi", + proceed_to_login: "Lanjutkan ke login", + proceed_with_account_deletion: "Lanjutkan dengan Penghapusan Akun", + process_status_initializing: "Memulai", + process_status_running: "Berjalan", + process_type_app: "Aplikasi", + process_type_init: "Inisialisasi", + process_type_ui: "UI", + properties: "Properti", + public: "Publik", + publish: "Terbitkan", + publish_as_website: "Terbitkan sebagai situs web", + puter_description: `Puter adalah cloud pribadi yang mengutamakan privasi untuk menyimpan semua file, aplikasi, dan permainan Anda di satu tempat yang aman, dapat diakses dari mana saja kapan saja.`, + reading_file: "Membaca %strong%", + recent: "Terbaru", + recommended: "Direkomendasikan", + recover_password: "Pulihkan Kata Sandi", + refer_friends_c2a: "Dapatkan 1 GB untuk setiap teman yang membuat dan mengonfirmasi akun di Puter. Teman Anda juga akan mendapatkan 1 GB!", + refer_friends_social_media_c2a: "Dapatkan 1 GB penyimpanan gratis di Puter.com!", + refresh: "Segarkan", + release_address_confirmation: "Apakah Anda yakin ingin melepaskan alamat ini?", + remove_from_taskbar: "Hapus dari Bilah Tugas", + rename: "Ganti Nama", + repeat: "Ulangi", + replace: "Ganti", + replace_all: "Ganti Semua", + resend_confirmation_code: "Kirim Ulang Kode Konfirmasi", + reset_colors: "Reset Warna", + restart_puter_confirm: "Apakah Anda yakin ingin memulai ulang Puter?", + restore: "Pulihkan", + save: "Simpan", + saturation: "Kenyaringan", + save_account: "Simpan akun", + save_account_to_get_copy_link: "Silakan buat akun untuk melanjutkan.", + save_account_to_publish: "Silakan buat akun untuk melanjutkan.", + save_session: "Simpan sesi", + save_session_c2a: "Buat akun untuk menyimpan sesi Anda saat ini dan menghindari kehilangan pekerjaan Anda.", + scan_qr_c2a: "Pindai kode di bawah ini\nuntuk masuk ke sesi ini dari perangkat lain", + scan_qr_2fa: "Pindai kode QR dengan aplikasi autentikator Anda", + scan_qr_generic: "Pindai kode QR ini menggunakan ponsel atau perangkat lain Anda", + search: "Cari", + seconds: "detik", + security: "Keamanan", + select: "Pilih", + selected: "terpilih", + select_color: "Pilih warna…", + sessions: "Sesi", + send: "Kirim", + send_password_recovery_email: "Kirim Email Pemulihan Kata Sandi", + session_saved: "Terima kasih telah membuat akun. Sesi ini telah disimpan.", + settings: "Pengaturan", + set_new_password: "Tetapkan Kata Sandi Baru", + share: "Bagikan", + share_to: "Bagikan ke", + share_with: "Bagikan dengan:", + shortcut_to: "Jalan Pintas ke", + show_all_windows: "Tampilkan Semua Jendela", + show_hidden: "Tampilkan yang tersembunyi", + sign_in_with_puter: "Masuk dengan Puter", + sign_up: "Daftar", + signing_in: "Masuk…", + size: "Ukuran", + skip: "Lewati", + something_went_wrong: "Terjadi kesalahan.", + sort_by: "Urutkan berdasarkan", + start: "Mulai", + status: "Status", + storage_usage: "Penggunaan Penyimpanan", + storage_puter_used: "digunakan oleh Puter", + taking_longer_than_usual: "Memakan waktu sedikit lebih lama dari biasanya. Silakan tunggu...", + task_manager: "Pengelola Tugas", + taskmgr_header_name: "Nama", + taskmgr_header_status: "Status", + taskmgr_header_type: "Tipe", + terms: "Syarat", + text_document: "Dokumen Teks", + tos_fineprint: `Dengan mengklik 'Buat Akun Gratis', Anda menyetujui {{link=terms}}Syarat Layanan{{/link}} dan {{link=privacy}}Kebijakan Privasi{{/link}} Puter.`, + transparency: "Transparansi", + trash: "Tempat Sampah", + two_factor: "Otentikasi Dua Faktor", + two_factor_disabled: "2FA Dinonaktifkan", + two_factor_enabled: "2FA Diaktifkan", + type: "Tipe", + type_confirm_to_delete_account: "Ketik 'confirm' untuk menghapus akun Anda.", + ui_colors: "Warna UI", + ui_manage_sessions: "Pengelola Sesi", + ui_revoke: "Batalkan", + undo: "Batalkan", + unlimited: "Tak Terbatas", + unzip: "Ekstrak", + upload: "Unggah", + upload_here: "Unggah di sini", + usage: "Penggunaan", + username: "Nama Pengguna", + username_changed: "Nama pengguna berhasil diperbarui.", + username_required: "Nama pengguna diperlukan.", + versions: "Versi", + videos: "Video", + visibility: "Visibilitas", + yes: "Ya", + yes_release_it: "Ya, Lepaskan", + you_have_been_referred_to_puter_by_a_friend: "Anda telah dirujuk ke Puter oleh teman!", + zip: "Zip", + zipping_file: "Mengekstrak %strong%", + + // === 2FA Setup === + setup2fa_1_step_heading: "Buka aplikasi autentikator Anda", + setup2fa_1_instructions: ` + Anda dapat menggunakan aplikasi autentikator apa pun yang mendukung protokol Time-based One-Time Password (TOTP). + Ada banyak pilihan, tetapi jika Anda tidak yakin + Authy + adalah pilihan yang solid untuk Android dan iOS. + `, + setup2fa_2_step_heading: "Pindai kode QR", + setup2fa_3_step_heading: "Masukkan kode 6 digit", + setup2fa_4_step_heading: "Salin kode pemulihan Anda", + setup2fa_4_instructions: ` + Kode pemulihan ini adalah satu-satunya cara untuk mengakses akun Anda jika Anda kehilangan ponsel atau tidak dapat menggunakan aplikasi autentikator Anda. + Pastikan untuk menyimpannya di tempat yang aman. + `, + setup2fa_5_step_heading: "Konfirmasi pengaturan 2FA", + setup2fa_5_confirmation_1: "Saya telah menyimpan kode pemulihan saya di tempat yang aman", + setup2fa_5_confirmation_2: "Saya siap untuk mengaktifkan 2FA", + setup2fa_5_button: "Aktifkan 2FA", + + // === 2FA Login === + login2fa_otp_title: "Masukkan Kode 2FA", + login2fa_otp_instructions: "Masukkan kode 6 digit dari aplikasi autentikator Anda.", + login2fa_recovery_title: "Masukkan kode pemulihan", + login2fa_recovery_instructions: "Masukkan salah satu kode pemulihan Anda untuk mengakses akun Anda.", + login2fa_use_recovery_code: "Gunakan kode pemulihan", + login2fa_recovery_back: "Kembali", + login2fa_recovery_placeholder: "XXXXXXXX" + } +}; + +export default id; \ No newline at end of file diff --git a/src/gui/src/i18n/translations/translations.js b/src/gui/src/i18n/translations/translations.js index cef1bc15c5..0a482c6e42 100644 --- a/src/gui/src/i18n/translations/translations.js +++ b/src/gui/src/i18n/translations/translations.js @@ -52,6 +52,7 @@ import hu from './hu.js'; import zhtw from './zhtw.js'; import vi from "./vi.js"; import emoji from './emoji.js'; +import id from './id.js'; @@ -91,4 +92,5 @@ export default { ur, vi, emoji, + id, }; From 70787ffa2c4d92a25c3d71312ca77e198e8cb41d Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 26 Jul 2024 22:43:11 -0400 Subject: [PATCH 0631/2119] tweak: print new password when resetting pass via server console --- src/backend/src/modules/selfhosted/DefaultUserService.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/backend/src/modules/selfhosted/DefaultUserService.js b/src/backend/src/modules/selfhosted/DefaultUserService.js index d386afef96..a5873cecc8 100644 --- a/src/backend/src/modules/selfhosted/DefaultUserService.js +++ b/src/backend/src/modules/selfhosted/DefaultUserService.js @@ -27,6 +27,7 @@ const { buffer_to_stream } = require("../../util/streamutil"); const BaseService = require("../../services/BaseService"); const { Actor, UserActorType } = require("../../services/auth/Actor"); const { DB_WRITE } = require("../../services/database/consts"); +const { quot } = require("../../util/strutil"); const USERNAME = 'admin'; @@ -255,7 +256,8 @@ class DefaultUserService extends BaseService { handler: async (args, ctx) => { const [ username ] = args; const user = await get_user({ username }); - await this.force_tmp_password_(user); + const tmp_pwd = await this.force_tmp_password_(user); + ctx.log(`New password for ${quot(username)} is: ${tmp_pwd}`); } } ]); From fe119756b530152b0167ff9794b7e77399230826 Mon Sep 17 00:00:00 2001 From: Bryar Ghafoor <155480528+BryarGh@users.noreply.github.com> Date: Sat, 27 Jul 2024 23:19:24 +0300 Subject: [PATCH 0632/2119] Update Kurdish language template --- src/gui/src/i18n/translations/ku.js | 711 +++++++++++++++------------- 1 file changed, 370 insertions(+), 341 deletions(-) diff --git a/src/gui/src/i18n/translations/ku.js b/src/gui/src/i18n/translations/ku.js index fb70861d8d..a73236cead 100644 --- a/src/gui/src/i18n/translations/ku.js +++ b/src/gui/src/i18n/translations/ku.js @@ -1,352 +1,381 @@ /** - * Copyright (C) 2024 Puter Technologies Inc. + * مافی چاپ و بڵاوکردنەوە (C) 2024 پوتەر تەکنەلۆجی هەژمار. * - * This file is part of Puter. + * ئەم فایلە بەشێکە لە پوتەر. * - * Puter 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. + * Bryar Ghafoor کردوویە بە کوردی بڕیار غفور * - * 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. + * پوتەر سەرووخۆ ئازادیە: ئەتەوێت دەبێتەوە یان تێکەڵ دەکەیت + * بە مەرجەکانی GNU Affero General Public License وەک بڵاوکراوی + * لە ڕووی فریستە فوندەیشنی فری، یان بەرژەی 3ی لایسەنسەکە، یان + * (بە مەرجەکانی کەسانەکان یان) بەرژەی داهاتوو. * - * You should have received a copy of the GNU Affero General Public License - * along with this program. If not, see . + * ئەم پرۆگرامە بڵاو دەکرێتەوە بەو پەیوەندییەی ئەوی تایبەتمەندە، + * بەڵام بێ گەرنەکی وا، بێ گەرنەکی خەریکێی بۆ + * فەروش یان تەواوبوون بۆ مەبەستێکی تایبەتی. بینە بەرژەی + * GNU Affero General Public License بۆ زانیاری زۆرتر. + * + * دەبێت کۆپیێک لە GNU Affero General Public License وەرگیراوی + * ئەم پرۆگرامە بۆ خۆت. گەر نەخێر، بینە . */ +const ku = { + name: "کوردی", + english_name: "Kurdish", + code: "ku", + dictionary: { + about: "دەربارە", + account: "هەژمار", + account_password: "وشەی تێپەڕی هەژمارەکەت پشتڕاست بکەوە", + access_granted_to: "ڕێگەپێدان درا بۆ", + add_existing_account: "زیادکردنی هەژماری هەبوو", + all_fields_required: "هەموو بوارەکان پێویستە.", + allow: "ڕێگەدان", + apply: "بەکارهێنان", + ascending: "سەرووەی", + associated_websites: "وێبسایتەکان پەیوەندیدار", + auto_arrange: "ڕیزکردنی ئۆتۆماتیکی", + background: "پاشبنەما", + browse: "گەڕان", + cancel: "ڕەتکردنەوە", + center: "ناوەڕاست", + change_desktop_background: "گۆڕینی پاشبنەمای ڕوومیزی...", + change_email: "گۆڕینی ئیمەیل", + change_language: "گۆڕینی زمان", + change_password: "گۆڕینی وشەی تێپەڕ", + change_ui_colors: "گۆڕینی ڕەنگەکانی وێنەی بەکارهێنەر", + change_username: "گۆڕینی ناوی بەکارهێنەر", + close: "داخستن", + close_all_windows: "داخستنی هەموو پەنجەکان", + close_all_windows_confirm: "دڵنیایت کە ئەتەوێت هەموو پەنجەکان داخەیت؟", + close_all_windows_and_log_out: "داخستن و چوونە دەرەوە", + change_always_open_with: "ئەتەوێت هەمیشە ئەم جۆرە فایلە بکرێتەوە بە", + color: "ڕەنگ", + confirm: "پشتڕاستکردنەوە", + confirm_2fa_setup: "کۆدەکە زیادم کردووە بۆ وەرگرەری پشتڕاستکراوەکان", + confirm_2fa_recovery: + "کۆدەکانی ڕێکخستنەوە پشتڕاست کردووە بۆ مەبەستێکی تایبەتی", + confirm_account_for_free_referral_storage_c2a: + "هەژمارێک دروست بکە و پەیوەندیدانی ئیمەیلەکەت پشتڕاست بکە بۆ وەرگرتنی 1 گیگابایت بەرەوپێشەوە. هاوڕێتیش 1 گیگابایت بەرەوپێشەوە دەبێت.", + confirm_code_generic_incorrect: "کۆدی هەڵە.", + confirm_code_generic_too_many_requests: + "داواکاریی زۆر. تکایە چەند خولەکێک چاوەڕوانبە.", + confirm_code_generic_submit: "ناردنی کۆد", + confirm_code_generic_try_again: "دووبارە هەوڵبەرە", + confirm_code_generic_title: "کۆدی پشتڕاستکردنەوە بنووسە", + confirm_code_2fa_instruction: "کۆدی 6 ژمارەیە بنووسە لە ئەپەکەت.", + confirm_code_2fa_submit_btn: "ناردن", + confirm_code_2fa_title: "کۆدی 2FA بنووسە", + confirm_delete_multiple_items: + "دڵنیایت کە ئەتەوێت ئەم بابەتانە هەمی نابود بکەیتەوە؟", + confirm_delete_single_item: "ئەتەوێت ئەم بابەتە نابود بکەیتەوە؟", + confirm_open_apps_log_out: + "هەبوونەوەی ئەپەکان. دڵنیایت کە ئەتەوێت چوونە دەرەوە؟", + confirm_new_password: "پشتڕاستکردنەوەی وشەی تێپەڕی نوێ", + confirm_delete_user: + "دڵنیایت کە ئەتەوێت هەژمارەکەت نابود بکەیتەوە؟ هەموو فایلەکان و زانیاریەکانت هەمیشە نابود دەکرێنەوە. ئەم کارە ناتوانرێت وەک خواردنەوە.", + confirm_delete_user_title: "نابودکردنی هەژمار؟", + confirm_session_revoke: "دڵنیایت کە ئەتەوێت ئەم دانیشتنە ڕەت بکەیتەوە؟", + confirm_your_email_address: "پشتڕاستکردنەوەی ناونیشانی ئیمەیلەکەت", + contact_us: "پەیوەندی پێوە بکە", + contact_us_verification_required: + "پێویستە ناونیشانی ئیمەیلەکەت پشتڕاست بکرێت بۆ بەکارهێنان.", + contain: "پێکەوە", + continue: "بەردەوامبوون", + copy: "کۆپی", + copy_link: "کۆپی کردنەوەی بەستەر", + copying: "کۆپی کردنەوە", + copying_file: "کۆپی کردنەوەی %%", + cover: "پەوشکردنەوە", + create_account: "دروستکردنی هەژمار", + create_free_account: "دروستکردنی هەژماری ئازاد", + create_shortcut: "دروستکردنی شارتی", + credits: "بڕگەکان", + current_password: "وشەی تێپەڕی ئێستا", + cut: "برین", + clock: "کاژێر", + clock_visible_hide: "شاردنەوە - هەمیشە شاردراوە", + clock_visible_show: "پیشان - هەمیشە پیشاندراوە", + clock_visible_auto: + "ئۆتۆ - بنەڕەت، تەنها پیشاندراوە لە دۆخەکانی شاشەی تەواو.", + close_all: "داخستنەوەی هەموو", + created: "دروستکراو", + date_modified: "بەرواری گۆڕاوە", + default: "بە ڕێگای بنەڕەت", + delete: "سڕینەوە", + delete_account: "سڕینەوەی هەژمار", + delete_permanently: "هەمی سڕینەوە", + deleting_file: "سڕینەوەی %%", + deploy_as_app: "دابەشکردن وەک ئەپ", + descending: "نزەندەی", + desktop: "سەروروومیزی", + desktop_background_fit: "ڕێکخستن", + developers: "پەرەپێدانەران", + dir_published_as_website: `%strong% بەشکراوە بۆ:`, + disable_2fa: "ناچالاککردنی 2FA", + disable_2fa_confirm: "دڵنیایت کە ئەتەوێت 2FA ناچالاک بکەیت؟", + disable_2fa_instructions: "وشەی تێپەڕی نووسە بۆ ناچالاککردنی 2FA.", + disassociate_dir: "جیاکردنەوەی ڕێکەوت", + documents: "بەڵگەکان", + dont_allow: "ڕێگەندان", + download: "داگرتن", + download_file: "داگرتنی فایل", + downloading: "داگرتن", + email: "ئیمەیل", + email_change_confirmation_sent: + "پەیامی پشتڕاستکردنی ئیمەیل بۆ ناونیشانی ئیمەیلە نوێتەوە نێردرا. تکایە پەیامەکانت بپشکنە و ڕێنیشانەکان پەیڕەو بکە بۆ تەواوبوونەوەی ئەم کارە.", + email_invalid: "ئیمەیل نادروستە.", + email_or_username: "ئیمەیل یان ناوی بەکارهێنەر", + email_required: "ئیمەیل پێویستە.", + empty_trash: "بەتاڵکردنەوەی کوڵە", + empty_trash_confirmation: `دڵنیایت کە ئەتەوێت هەموو بابەتەکان لە کوڵەیەکدا هەمی سڕی؟`, + emptying_trash: "بەتاڵکردنەوەی کوڵە...", + enable_2fa: "چالاککردنی 2FA", + end_hard: "کۆتای بەهێز", + end_process_force_confirm: + "دڵنیایت کە ئەتەوێت بەهێزەوە کۆتای پڕۆسەکە بگریت؟", + end_soft: "کۆتای هەواڵ", + enlarged_qr_code: "کۆدی QR گەورەکراو", + enter_password_to_confirm_delete_user: + "وشەی تێپەڕت بنووسە بۆ پشتڕاستکردنی سڕینەوەی هەژمار", + error_message_is_missing: "پەیامی هەڵە نادیاری.", + error_unknown_cause: "هەڵەیەکی نادیاری رووی دا.", + error_uploading_files: "شکستی هێنا لە بارکردنی فایلەکان", + favorites: "دڵخوازەکان", + feedback: "فیدباک", + feedback_c2a: + "تکایە فۆرمەکەی خوارەوە بەکاربە بۆ ناردنی فیدباک، لێدوان، و ڕاپۆرتی کێشەکان بۆ ئێمە.", + feedback_sent_confirmation: + "سوپاس بۆ پەیوەندی کردن. گەر ناونیشانی ئیمەیلەکەت هەیە، بە زووترین کات لەگەڵت پەیوەندیدەکەین.", + fit: "ڕێکخستن", + folder: "فۆڵدەر", + force_quit: "بەهێزەوە کوژاندنەوە", + forgot_pass_c2a: "وشەی تێپەڕت لەبیرچووە؟", + from: "لە", + general: "گشتی", + get_a_copy_of_on_puter: `کۆپیێک وەرگرتنەوەی '%%' لە پوتەر.com!`, + get_copy_link: "کۆپی بەستەر وەرگرتن", + hide_all_windows: "شاردنەوەی هەموو پەنجەکان", + home: "ماڵەوە", + html_document: "بەڵگەی HTML", + hue: "هیو", + image: "وێنە", + incorrect_password: "وشەی تێپەڕ هەڵەیە", + invite_link: "بەستەری بانگکردن", + item: "بابەت", + items_in_trash_cannot_be_renamed: `ئەم بابەتە ناتوانرێت ناونوسێت چونکە لە کوڵەدا هەیە. بۆ ناونوسین، سەبارەکەی لە کوڵەکە دەر بکە.`, + jpeg_image: "وێنەی JPEG", + keep_in_taskbar: "ڕێپێدان لە تاکسبار", + language: "زمان", + license: "لایسەنس", + lightness: "رووناکی", + link_copied: "بەستەر کۆپی کرا", + loading: "بارکردنەوە", + log_in: "چوونەژوورەوە", + log_into_another_account_anyway: "بە هەژماری دیگە هەرچۆنێکەوە چوونەژوورەوە", + log_out: "چوونە دەرەوە", + looks_good: "پەیوەندیدارە!", + manage_sessions: "بەڕێوەبردنی دانیشتنەکان", + menubar_style: "شێوازی منوبار", + menubar_style_desktop: "سەروروومیزی", + menubar_style_system: "سیستەم", + menubar_style_window: "پەنجەرە", + modified: "گۆڕاو", + move: "جوڵاندن", + moving_file: "جوڵاندنەوەی %%", + my_websites: "وێبسایتەکانم", + name: "ناو", + name_cannot_be_empty: "ناو ناتوانرێت بەتاڵ بێت.", + name_cannot_contain_double_period: "ناو ناتوانرێت '..' هەبێت.", + name_cannot_contain_period: "ناو ناتوانرێت '.' هەبێت.", + name_cannot_contain_slash: "ناو ناتوانرێت '/' هەبێت.", + name_must_be_string: "ناو تەنها پیتەکان دەبێت.", + name_too_long: `ناو ناتوانرێت درێژتر بێت لە %% پیتەکان.`, + new: "نوێ", + new_email: "ئیمەیلی نوێ", + new_folder: "فۆڵدەرێکی نوێ", + new_password: "وشەی تێپەڕی نوێ", + new_username: "ناوی بەکارهێنەری نوێ", + no: "نەخێر", + no_dir_associated_with_site: + "هیچ ڕێکەوتێک پەیوەندیداری ئەم ناونیشانە نییە.", + no_websites_published: + "هێشتا هیچ وێبسایتێکت نەبڵاوکردووە. لەسەر فۆڵدەرەکە پەنجەکەی راستبکە بۆ دەستپێکردن.", + ok: "باشە", + open: "کردنەوە", + open_in_new_tab: "کردنەوە لە تابێکی نوێ", + open_in_new_window: "کردنەوە لە پەنجەرەیەکی نوێ", + open_with: "کردنەوە بە", + original_name: "ناوی ڕەسەن", + original_path: "ڕێکەوتی ڕەسەن", + oss_code_and_content: "کۆدی سەرچاوەیەکی کراو و ناوەڕۆک", + password: "وشەی تێپەڕ", + password_changed: "وشەی تێپەڕ گۆڕدرا.", + password_recovery_rate_limit: + "گەیشتووی بەرزەبەند؛ تکایە چەند خولەکێک چاوەڕوانبە. بۆ پشتگیری لە ئایندە، هەوڵبدەرەوە زیاتر لە ڕوونکردنی لاپەڕە بکەیت.", + password_recovery_token_invalid: + "ئەم تۆکنی ڕێکخستنەوەی وشەی تێپەڕە نادروستە.", + password_recovery_unknown_error: + "هەڵەیەکی نادیاری رووی دا. تکایە دووبارە هەوڵبەرە.", + password_required: "وشەی تێپەڕ پێویستە.", + password_strength_error: + "وشەی تێپەڕ دەبێت بەلایەنی کەم 8 پیت بێت و تێیدا پیتێکی گەورە، پیتێکی بچووک، ژمارەیەک، و پیتێکی تایبەتی هەبێت.", + passwords_do_not_match: + "`وشەی تێپەڕی نوێ` و `پشتڕاستکردنی وشەی تێپەڕی نوێ` جیاوازن.", + paste: "دانان", + paste_into_folder: "دانان لە فۆڵدەرەکە", + path: "ڕێکەوت", + personalization: "بەشداربوون", + pick_name_for_website: "ناوێک دیاربکە بۆ وێبسایتەکەت:", + picture: "وێنە", + pictures: "وێنەکان", + plural_suffix: "کان", + powered_by_puter_js: `پێشکەشکراوە لە {{link=docs}}پوتەر.js{{/link}}`, + preparing: "ئامادەکردن...", + preparing_for_upload: "ئامادەکردن بۆ بارکردن...", + print: "چاپکردن", + privacy: "تایبەتمەندی", + proceed_to_login: "بەردەوام بوون بۆ چوونەژوورەوە", + proceed_with_account_deletion: "بەردەوام بوون بە سڕینەوەی هەژمار", + process_status_initializing: "دەستپێکردن", + process_status_running: "کاریگەری", + process_type_app: "ئەپ", + process_type_init: "دەستپێکردن", + process_type_ui: "وێنەی بەکارهێنەر", + properties: "تایبەتمەندیەکان", + public: "گشتی", + publish: "بڵاوکردنەوە", + publish_as_website: "بڵاوکردنەوە وەک وێبسایت", + puter_description: `پوتەر پێشکەشکراوە بۆ پاراستنی تایبەتیە کەسایەتی، جێگایەکی ئازاد بۆ گەیاندنی هەموو فایلەکان، ئەپەکان، و یارییەکان لە هەر شوێنێک بێ هەموو کاتێک.`, + reading_file: "خوێندنی %strong%", + recent: "نوێترین", + recommended: "پێشنیارکراوەکان", + recover_password: "ڕێکخستنەوەی وشەی تێپەڕ", + refer_friends_c2a: + "1 گیگابایت بۆ هەر هاوڕێک دەست بەرکە، پەیوەندیدانی هەژمارێک بۆ پوتەر دروست بکە و پشتڕاست بکە. هاوڕێتیش 1 گیگابایت وەرگرتن دەبێت!", + refer_friends_social_media_c2a: `1 گیگابایت پارێزگاکانی پوتەر.com بۆ هەر هاوڕێک بکە!`, + refresh: "بوژانەوە", + release_address_confirmation: `دڵنیایت کە ئەتەوێت ئەم ناونیشانە بۆ هەڵگرتن؟`, + remove_from_taskbar: "لابردن لە تاکسبار", + rename: "ناونانەوە", + repeat: "دووبارەکردنەوە", + replace: "لە نوێکردنەوە", + replace_all: "لە نوێکردنەوەی هەموو", + resend_confirmation_code: "دووبارە ناردنی کۆدی پشتڕاستکردنەوە", + reset_colors: "ڕێکخستنی ڕەنگەکان", + restart_puter_confirm: "دڵنیایت کە ئەتەوێت پوتەر دووبارە دەستپێبکەیت؟", + restore: "گەڕاندنەوە", + save: "پاشەکەوت", + saturation: "سەرەخۆشی", + save_account: "پاشەکەوتکردنی هەژمار", + save_account_to_get_copy_link: "تکایە هەژمارێک دروست بکە بۆ بەردەوامبوون.", + save_account_to_publish: "تکایە هەژمارێک دروست بکە بۆ بەردەوامبوون.", + save_session: "پاشەکەوتکردنی دانیشتن", + save_session_c2a: + "هەژمارێک دروست بکە بۆ پاشەکەوتکردنی دانیشتنەکەت و جلە نبەرینەوەی کاریەکانت.", + scan_qr_c2a: + "کۆدی خوارەوە پشکنین\nبۆ چوونەژوورەوەی ئەم دانیشتنە لە ئامرازە ترەکان", + scan_qr_2fa: "کۆدی QR پشکنین بە ئەپەکەت", + scan_qr_generic: "ئەم کۆدی QR پشکنین بە بەکارەریکەت یان ئامرازێکی تر", + search: "گەڕان", + seconds: "چرکە", + security: "پاراستن", + select: "دیاریکردن", + selected: "دیاریکراو", + select_color: "دیاریکردنی ڕەنگ …", + sessions: "دانیشتنەکان", + send: "ناردن", + send_password_recovery_email: "پەیامی ڕێکخستنەوەی وشەی تێپەڕ ناردن", + session_saved: "سوپاس بۆ دروستکردنی هەژمار. ئەم دانیشتنە پاشەکەوتکرا.", + settings: "ڕێکخستنەکان", + set_new_password: "وشەی تێپەڕی نوێ دانان", + share: "هاوبەشکردن", + share_to: "هاوبەشکردن بۆ", + share_with: "هاوبەشکردن بە:", + shortcut_to: "شارتی بۆ", + show_all_windows: "پیشاندانی هەموو پەنجەکان", + show_hidden: "پیشاندانی شاردراوەکان", + sign_in_with_puter: "چوونەژوورەوە بە پوتەر", + sign_up: "خۆتۆمارکردن", + signing_in: "چوونەژوورەوە...", + size: "قەبارە", + skip: "هەڵگرتن", + something_went_wrong: "هەڵەیەکی رووی دا.", + sort_by: "ڕیزکردن بە", + start: "دەستپێکردن", + status: "دۆخ", + storage_usage: "بەکاربردنی پارێزگا", + storage_puter_used: "بەکاربردنی لەلایەن پوتەر", + taking_longer_than_usual: "کەمێک زیاتر کەوتە، تکایە چاوەڕوانبە...", + task_manager: "بەڕێوەبەری کارەکان", + taskmgr_header_name: "ناو", + taskmgr_header_status: "دۆخ", + taskmgr_header_type: "جۆر", + terms: "مەرجەکان", + text_document: "بەڵگەی دەقی", + tos_fineprint: + " `بە گەیشتن بۆ 'دروستکردنی هەژماری ئازاد' ڕازییەتی بە {{link=terms}}مەرجەکانی خزمەتگوزاری{{/link}} و {{link=privacy}}پاراستنی تایبەتمەندی{{/link}}ی پوتەر.", + transparency: "ڕووناکی", + trash: "کوڵە", + two_factor: "پشتڕاستکردنی دووجۆرا", + two_factor_disabled: "2FA ناچالاک کرا", + two_factor_enabled: "2FA چالاک کرا", + type: "جۆر", + type_confirm_to_delete_account: "جۆری 'پشتڕاستکردن' بۆ سڕینەوەی هەژمار.", + ui_colors: "ڕەنگەکانی وێنەی بەکارهێنەر", + ui_manage_sessions: "بەڕێوەبردنی دانیشتنەکان", + ui_revoke: "ڕەتکردنەوە", + undo: "پەشیمانبوون", + unlimited: "بێ سنوور", + unzip: "کردنەوەی زیپ", + upload: "بارکردن", + upload_here: "بارکردن لێرە", + usage: "بەکاربردن", + username: "ناوی بەکارهێنەر", + username_changed: "ناوی بەکارهێنەر بەسەرکەوتووی نوێکرا.", + username_required: "ناوی بەکارهێنەر پێویستە.", + versions: "وەشاندنەکان", + videos: "ڤیدیۆکان", + visibility: "پیشاندانی", + yes: "بەڵێ", + yes_release_it: "بەڵێ، بڵاوکردنەوە", + you_have_been_referred_to_puter_by_a_friend: + "هاوڕێکت پەیوەندیداری پوتەر کردووە!", + zip: "زیپ", + zipping_file: "زیپ کردنەوەی %strong%", -const en = { - name: "کوردی", - english_name: "Kurdish", - code: "ku", - dictionary: { - about: "About", - account: "Account", - account_password: "Verify Account Password", - access_granted_to: "Access Granted To", - add_existing_account: "Add Existing Account", - all_fields_required: 'All fields are required.', - allow: 'Allow', - apply: "Apply", - ascending: 'Ascending', - associated_websites: "Associated Websites", - auto_arrange: 'Auto Arrange', - background: "Background", - browse: "Browse", - cancel: 'Cancel', - center: 'Center', - change_desktop_background: 'Change desktop background…', - change_email: "Change Email", - change_language: "Change Language", - change_password: "Change Password", - change_ui_colors: "Change UI Colors", - change_username: "Change Username", - close: 'Close', - close_all_windows: "Close All Windows", - close_all_windows_confirm: "Are you sure you want to close all windows?", - close_all_windows_and_log_out: 'Close Windows and Log Out', - change_always_open_with: "Do you want to always open this type of file with", - color: 'Color', - confirm: 'Confirm', - confirm_2fa_setup: 'I have added the code to my authenticator app', - confirm_2fa_recovery: 'I have saved my recovery codes in a secure location', - confirm_account_for_free_referral_storage_c2a: 'Create an account and confirm your email address to receive 1 GB of free storage. Your friend will get 1 GB of free storage too.', - confirm_code_generic_incorrect: "Incorrect Code.", - confirm_code_generic_too_many_requests: "Too many requests. Please wait a few minutes.", - confirm_code_generic_submit: "Submit Code", - confirm_code_generic_try_again: "Try Again", - confirm_code_generic_title: "Enter Confirmation Code", - confirm_code_2fa_instruction: "Enter the 6-digit code from your authenticator app.", - confirm_code_2fa_submit_btn: "Submit", - confirm_code_2fa_title: "Enter 2FA Code", - confirm_delete_multiple_items: 'Are you sure you want to permanently delete these items?', - confirm_delete_single_item: 'Do you want to permanently delete this item?', - confirm_open_apps_log_out: 'You have open apps. Are you sure you want to log out?', - confirm_new_password: "Confirm New Password", - confirm_delete_user: "Are you sure you want to delete your account? All your files and data will be permanently deleted. This action cannot be undone.", - confirm_delete_user_title: "Delete Account?", - confirm_session_revoke: "Are you sure you want to revoke this session?", - confirm_your_email_address: "Confirm Your Email Address", - contact_us: "Contact Us", - contact_us_verification_required: "You must have a verified email address to use this.", - contain: 'Contain', - continue: "Continue", - copy: 'Copy', - copy_link: "Copy Link", - copying: "Copying", - copying_file: "Copying %%", - cover: 'Cover', - create_account: "Create Account", - create_free_account: "Create Free Account", - create_shortcut: "Create Shortcut", - credits: "Credits", - current_password: "Current Password", - cut: 'Cut', - clock: "Clock", - clock_visible_hide: 'Hide - Always hidden', - clock_visible_show: 'Show - Always visible', - clock_visible_auto: 'Auto - Default, visible only in full-screen mode.', - close_all: 'Close All', - created: 'Created', - date_modified: 'Date modified', - default: 'Default', - delete: 'Delete', - delete_account: "Delete Account", - delete_permanently: "Delete Permanently", - deleting_file: "Deleting %%", - deploy_as_app: 'Deploy as app', - descending: 'Descending', - desktop: 'Desktop', - desktop_background_fit: "Fit", - developers: "Developers", - dir_published_as_website: `%strong% has been published to:`, - disable_2fa: 'Disable 2FA', - disable_2fa_confirm: "Are you sure you want to disable 2FA?", - disable_2fa_instructions: "Enter your password to disable 2FA.", - disassociate_dir: "Disassociate Directory", - documents: 'Documents', - dont_allow: 'Don\'t Allow', - download: 'Download', - download_file: 'Download File', - downloading: "Downloading", - email: "Email", - email_change_confirmation_sent: "A confirmation email has been sent to your new email address. Please check your inbox and follow the instructions to complete the process.", - email_invalid: 'Email is invalid.', - email_or_username: "Email or Username", - email_required: 'Email is required.', - empty_trash: 'Empty Trash', - empty_trash_confirmation: `Are you sure you want to permanently delete the items in Trash?`, - emptying_trash: 'Emptying Trash…', - enable_2fa: 'Enable 2FA', - end_hard: "End Hard", - end_process_force_confirm: "Are you sure you want to force-quit this process?", - end_soft: "End Soft", - enlarged_qr_code: "Enlarged QR Code", - enter_password_to_confirm_delete_user: "Enter your password to confirm account deletion", - error_message_is_missing: "Error message is missing.", - error_unknown_cause: "An unknown error occurred.", - error_uploading_files: "Failed to upload files", - favorites: "Favorites", - feedback: "Feedback", - feedback_c2a: "Please use the form below to send us your feedback, comments, and bug reports.", - feedback_sent_confirmation: "Thank you for contacting us. If you have an email associated with your account, you will hear back from us as soon as possible.", - fit: "Fit", - folder: 'Folder', - force_quit: 'Force Quit', - forgot_pass_c2a: "Forgot password?", - from: "From", - general: "General", - get_a_copy_of_on_puter: `Get a copy of '%%' on Puter.com!`, - get_copy_link: 'Get Copy Link', - hide_all_windows: "Hide All Windows", - home: 'Home', - html_document: 'HTML document', - hue: 'Hue', - image: 'Image', - incorrect_password: "Incorrect password", - invite_link: "Invite Link", - item: 'item', - items_in_trash_cannot_be_renamed: `This item can't be renamed because it's in the trash. To rename this item, first drag it out of the Trash.`, - jpeg_image: 'JPEG image', - keep_in_taskbar: 'Keep in Taskbar', - language: "Language", - license: "License", - lightness: 'Lightness', - link_copied: "Link copied", - loading: 'Loading', - log_in: "Log In", - log_into_another_account_anyway: 'Log into another account anyway', - log_out: 'Log Out', - looks_good: "Looks good!", - manage_sessions: "Manage Sessions", - menubar_style: "Menubar Style", - menubar_style_desktop: "Desktop", - menubar_style_system: "System", - menubar_style_window: "Window", - modified: 'Modified', - move: 'Move', - moving_file: "Moving %%", - my_websites: "My Websites", - name: 'Name', - name_cannot_be_empty: 'Name cannot be empty.', - name_cannot_contain_double_period: "Name can not be the '..' character.", - name_cannot_contain_period: "Name can not be the '.' character.", - name_cannot_contain_slash: "Name cannot contain the '/' character.", - name_must_be_string: "Name can only be a string.", - name_too_long: `Name can not be longer than %% characters.`, - new: 'New', - new_email: 'New Email', - new_folder: 'New folder', - new_password: "New Password", - new_username: "New Username", - no: 'No', - no_dir_associated_with_site: 'No directory associated with this address.', - no_websites_published: "You have not published any websites yet. Right click on a folder to get started.", - ok: 'OK', - open: "Open", - open_in_new_tab: "Open in New Tab", - open_in_new_window: "Open in New Window", - open_with: "Open With", - original_name: 'Original Name', - original_path: 'Original Path', - oss_code_and_content: "Open Source Software and Content", - password: "Password", - password_changed: "Password changed.", - password_recovery_rate_limit: "You've reached our rate-limit; please wait a few minutes. To prevent this in the future, avoid reloading the page too many times.", - password_recovery_token_invalid: "This password recovery token is no longer valid.", - password_recovery_unknown_error: "An unknown error occurred. Please try again later.", - password_required: 'Password is required.', - password_strength_error: "Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, one number, and one special character.", - passwords_do_not_match: '`New Password` and `Confirm New Password` do not match.', - paste: 'Paste', - paste_into_folder: "Paste Into Folder", - path: 'Path', - personalization: "Personalization", - pick_name_for_website: "Pick a name for your website:", - picture: "Picture", - pictures: 'Pictures', - plural_suffix: 's', - powered_by_puter_js: `Powered by {{link=docs}}Puter.js{{/link}}`, - preparing: "Preparing...", - preparing_for_upload: "Preparing for upload...", - print: 'Print', - privacy: "Privacy", - proceed_to_login: 'Proceed to login', - proceed_with_account_deletion: "Proceed with Account Deletion", - process_status_initializing: "Initializing", - process_status_running: "Running", - process_type_app: 'App', - process_type_init: 'Init', - process_type_ui: 'UI', - properties: "Properties", - public: 'Public', - publish: "Publish", - publish_as_website: 'Publish as website', - puter_description: `Puter is a privacy-first personal cloud to keep all your files, apps, and games in one secure place, accessible from anywhere at any time.`, - reading_file: "Reading %strong%", - recent: "Recent", - recommended: "Recommended", - recover_password: "Recover Password", - refer_friends_c2a: "Get 1 GB for every friend who creates and confirms an account on Puter. Your friend will get 1 GB too!", - refer_friends_social_media_c2a: `Get 1 GB of free storage on Puter.com!`, - refresh: 'Refresh', - release_address_confirmation: `Are you sure you want to release this address?`, - remove_from_taskbar:'Remove from Taskbar', - rename: 'Rename', - repeat: 'Repeat', - replace: 'Replace', - replace_all: 'Replace All', - resend_confirmation_code: "Re-send Confirmation Code", - reset_colors: "Reset Colors", - restart_puter_confirm: "Are you sure you want to restart Puter?", - restore: "Restore", - save: 'Save', - saturation: 'Saturation', - save_account: 'Save account', - save_account_to_get_copy_link: "Please create an account to proceed.", - save_account_to_publish: 'Please create an account to proceed.', - save_session: 'Save session', - save_session_c2a: 'Create an account to save your current session and avoid losing your work.', - scan_qr_c2a: 'Scan the code below\nto log into this session from other devices', - scan_qr_2fa: 'Scan the QR code with your authenticator app', - scan_qr_generic: 'Scan this QR code using your phone or another device', - search: 'Search', - seconds: 'seconds', - security: "Security", - select: "Select", - selected: 'selected', - select_color: 'Select color…', - sessions: "Sessions", - send: "Send", - send_password_recovery_email: "Send Password Recovery Email", - session_saved: "Thank you for creating an account. This session has been saved.", - settings: "Settings", - set_new_password: "Set New Password", - share: "Share", - share_to: "Share to", - share_with: "Share with:", - shortcut_to: "Shortcut to", - show_all_windows: "Show All Windows", - show_hidden: 'Show hidden', - sign_in_with_puter: "Sign in with Puter", - sign_up: "Sign Up", - signing_in: "Signing in…", - size: 'Size', - skip: 'Skip', - something_went_wrong: "Something went wrong.", - sort_by: 'Sort by', - start: 'Start', - status: "Status", - storage_usage: "Storage Usage", - storage_puter_used: 'used by Puter', - taking_longer_than_usual: 'Taking a little longer than usual. Please wait...', - task_manager: "Task Manager", - taskmgr_header_name: "Name", - taskmgr_header_status: "Status", - taskmgr_header_type: "Type", - terms: "Terms", - text_document: 'Text document', - tos_fineprint: `By clicking 'Create Free Account' you agree to Puter's {{link=terms}}Terms of Service{{/link}} and {{link=privacy}}Privacy Policy{{/link}}.`, - transparency: "Transparency", - trash: 'Trash', - two_factor: 'Two Factor Authentication', - two_factor_disabled: '2FA Disabled', - two_factor_enabled: '2FA Enabled', - type: 'Type', - type_confirm_to_delete_account: "Type 'confirm' to delete your account.", - ui_colors: "UI Colors", - ui_manage_sessions: "Session Manager", - ui_revoke: "Revoke", - undo: 'Undo', - unlimited: 'Unlimited', - unzip: "Unzip", - upload: 'Upload', - upload_here: 'Upload here', - usage: 'Usage', - username: "Username", - username_changed: 'Username updated successfully.', - username_required: 'Username is required.', - versions: "Versions", - videos: 'Videos', - visibility: 'Visibility', - yes: 'Yes', - yes_release_it: 'Yes, Release It', - you_have_been_referred_to_puter_by_a_friend: "You have been referred to Puter by a friend!", - zip: "Zip", - zipping_file: "Zipping %strong%", - - // === 2FA Setup === - setup2fa_1_step_heading: 'Open your authenticator app', - setup2fa_1_instructions: ` - You can use any authenticator app that supports the Time-based One-Time Password (TOTP) protocol. - There are many to choose from, but if you're unsure - Authy - is a solid choice for Android and iOS. - `, - setup2fa_2_step_heading: 'Scan the QR code', - setup2fa_3_step_heading: 'Enter the 6-digit code', - setup2fa_4_step_heading: 'Copy your recovery codes', - setup2fa_4_instructions: ` - These recovery codes are the only way to access your account if you lose your phone or can't use your authenticator app. - Make sure to store them in a safe place. - `, - setup2fa_5_step_heading: 'Confirm 2FA setup', - setup2fa_5_confirmation_1: 'I have saved my recovery codes in a secure location', - setup2fa_5_confirmation_2: 'I am ready to enable 2FA', - setup2fa_5_button: 'Enable 2FA', + // === 2FA Setup === + setup2fa_1_step_heading: "کردنەوەی ئەپەکەت", + setup2fa_1_instructions: ` + دەتوانیت هەر ئەپێکی پشتڕاستکردنی دووجۆرا بەکاربهێنیت کە پشتگیری + Time-based One-Time Password (TOTP) protocol بیکات. هەندێکە زۆرن بۆ + هەڵبژاردن، بەڵام گەر دڵنیایت + Authy + هەڵبژاردنێکی باشە بۆ ئەندرۆید و iOS. + `, + setup2fa_2_step_heading: "پشکنینی کۆدی QR", + setup2fa_3_step_heading: "ناردنی کۆدی 6 ژمارە", + setup2fa_4_step_heading: "کۆدی پشتڕاستکردنی نوێ پشکنین", + setup2fa_4_instructions: ` + ئەم کۆدانە تەنها ڕێگا بۆ گەیشتنەوە بە هەژمارەکەت گەر تۆ موبایلەکەت + لەبیرچووی یاخود ناتوانی ئەپەکەت بەکاربەریت. + دڵنیابە کەیان لە شوێنێکی پاراستنەوەیەکان بنووسیت. + `, + setup2fa_5_step_heading: "پشتڕاستکردنی ڕێکخستنەوەی 2FA", + setup2fa_5_confirmation_1: "کۆدای پشتڕاستکردنەوەی مەبەستەکانم بنووسنەوە", + setup2fa_5_confirmation_2: "ئامادەم بۆ چالاککردنی 2FA", + setup2fa_5_button: "چالاککردنی 2FA", - // === 2FA Login === - login2fa_otp_title: 'Enter 2FA Code', - login2fa_otp_instructions: 'Enter the 6-digit code from your authenticator app.', - login2fa_recovery_title: 'Enter a recovery code', - login2fa_recovery_instructions: 'Enter one of your recovery codes to access your account.', - login2fa_use_recovery_code: 'Use a recovery code', - login2fa_recovery_back: 'Back', - login2fa_recovery_placeholder: 'XXXXXXXX', - } + // === 2FA Login === + login2fa_otp_title: "ناردنی کۆدی 2FA", + login2fa_otp_instructions: "کۆدی 6 ژمارەیە بنووسە لە ئەپەکەت.", + login2fa_recovery_title: "کۆدی پشتڕاستکردنەوەیەک بنووسە", + login2fa_recovery_instructions: + "یەکێک لە کۆدانە پشتڕاستکردنەوە بنووسە بۆ گەیشتنەوە بە هەژمارەکەت.", + login2fa_use_recovery_code: "بەکارهێنانی کۆدی پشتڕاستکردنەوە", + login2fa_recovery_back: "گەڕانەوە", + login2fa_recovery_placeholder: "XXXXXXXX", + }, }; -export default en; \ No newline at end of file +export default ku; From c71774664667cecd37eab2a5914b8a2c1fd7ef22 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sat, 27 Jul 2024 14:07:24 -0700 Subject: [PATCH 0633/2119] Use the english version of the license header but retain the credit to Bryar Ghafoor --- src/gui/src/i18n/translations/ku.js | 30 +++++++++++++++-------------- 1 file changed, 16 insertions(+), 14 deletions(-) diff --git a/src/gui/src/i18n/translations/ku.js b/src/gui/src/i18n/translations/ku.js index a73236cead..f57e9ab9b3 100644 --- a/src/gui/src/i18n/translations/ku.js +++ b/src/gui/src/i18n/translations/ku.js @@ -1,24 +1,26 @@ /** - * مافی چاپ و بڵاوکردنەوە (C) 2024 پوتەر تەکنەلۆجی هەژمار. + * Copyright (C) 2024 Puter Technologies Inc. * - * ئەم فایلە بەشێکە لە پوتەر. + * This file is part of Puter. * - * Bryar Ghafoor کردوویە بە کوردی بڕیار غفور + * Puter 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. * - * پوتەر سەرووخۆ ئازادیە: ئەتەوێت دەبێتەوە یان تێکەڵ دەکەیت - * بە مەرجەکانی GNU Affero General Public License وەک بڵاوکراوی - * لە ڕووی فریستە فوندەیشنی فری، یان بەرژەی 3ی لایسەنسەکە، یان - * (بە مەرجەکانی کەسانەکان یان) بەرژەی داهاتوو. + * 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. * - * ئەم پرۆگرامە بڵاو دەکرێتەوە بەو پەیوەندییەی ئەوی تایبەتمەندە، - * بەڵام بێ گەرنەکی وا، بێ گەرنەکی خەریکێی بۆ - * فەروش یان تەواوبوون بۆ مەبەستێکی تایبەتی. بینە بەرژەی - * GNU Affero General Public License بۆ زانیاری زۆرتر. - * - * دەبێت کۆپیێک لە GNU Affero General Public License وەرگیراوی - * ئەم پرۆگرامە بۆ خۆت. گەر نەخێر، بینە . + * You should have received a copy of the GNU Affero General Public License + * along with this program. If not, see . */ +// +// Bryar Ghafoor کردوویە بە کوردی بڕیار غفور +// + const ku = { name: "کوردی", english_name: "Kurdish", From d0e461e206300e7fe3f9bc7f54eaa3a25bb762d8 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sat, 27 Jul 2024 18:54:06 -0400 Subject: [PATCH 0634/2119] fix: sqlite migrations error This issue was caused by an INSERT statement which adds the admin user to the admin group. The admin user is created at initialization, so for new installs it does not exist at the time migration scripts are run. Additionally, new javascript-coded migrations (.mig.js) would not have run for new installs because of redundant (WET; not DRY) code for initial setup. This commit also improves error handling of the migration service, which was necessary to diagnose this issue. In the future, setup always needs to be tested after updating migration scripts, even though migration of existing databases is where most of the issues will happen. Resolves: #639 --- .../database/SqliteDatabaseAccessService.js | 72 +++++++------------ .../sqlite_setup/0024_default-groups.sql | 12 ---- 2 files changed, 27 insertions(+), 57 deletions(-) diff --git a/src/backend/src/services/database/SqliteDatabaseAccessService.js b/src/backend/src/services/database/SqliteDatabaseAccessService.js index c9d2f8e1d1..3385970f41 100644 --- a/src/backend/src/services/database/SqliteDatabaseAccessService.js +++ b/src/backend/src/services/database/SqliteDatabaseAccessService.js @@ -18,6 +18,7 @@ */ const { es_import_promise } = require("../../fun/dev-console-ui-utils"); const { surrounding_box } = require("../../fun/dev-console-ui-utils"); +const { CompositeError } = require("../../util/errorutil"); const structutil = require("../../util/structutil"); const { BaseDatabaseAccessService } = require("./BaseDatabaseAccessService"); @@ -45,51 +46,18 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { // Database upgrade logic const TARGET_VERSION = 24; - if ( do_setup ) { - this.log.noticeme(`SETUP: creating database at ${this.config.path}`); - const sql_files = [ - '0001_create-tables.sql', - '0002_add-default-apps.sql', - '0003_user-permissions.sql', - '0004_sessions.sql', - '0005_background-apps.sql', - '0006_update-apps.sql', - '0007_sessions.sql', - '0008_otp.sql', - '0009_app-prefix-fix.sql', - '0010_add-git-app.sql', - '0011_notification.sql', - '0012_appmetadata.sql', - '0013_protected-apps.sql', - '0014_share.sql', - '0015_group.sql', - '0016_group-permissions.sql', - '0017_publicdirs.sql', - '0018_fix-0003.sql', - '0019_fix-0016.sql', - '0020_dev-center.sql', - '0021_app-owner-id.sql', - '0022_dev-center-max.sql', - '0023_fix-kv.sql', - '0024_default-groups.sql', - '0025_system-user.dbmig.js', - '0026_user-groups.dbmig.js', - ].map(p => path_.join(__dirname, 'sqlite_setup', p)); - const fs = require('fs'); - for ( const filename of sql_files ) { - const basename = path_.basename(filename); - this.log.noticeme(`applying ${basename}`); - const contents = fs.readFileSync(filename, 'utf8'); - this.db.exec(contents); - } - await this.db.exec(`PRAGMA user_version = ${TARGET_VERSION};`); - } - - const [{ user_version }] = await this._read('PRAGMA user_version'); + const [{ user_version }] = do_setup + ? [{ user_version: -1 }] + : await this._read('PRAGMA user_version'); this.log.info('database version: ' + user_version); const upgrade_files = []; + if ( user_version === -1 ) { + upgrade_files.push('0001_create-tables.sql'); + upgrade_files.push('0002_add-default-apps.sql'); + } + if ( user_version <= 0 ) { upgrade_files.push('0003_user-permissions.sql'); } @@ -201,12 +169,26 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { const contents = fs.readFileSync(filename, 'utf8'); switch ( path_.extname(filename) ) { case '.sql': - this.db.exec(contents); + const stmts = contents.split(/;\s*\n/); + for ( let i=0 ; i < stmts.length ; i++ ) { + if ( stmts[i].trim() === '' ) continue; + const stmt = stmts[i] + ';'; + try { + this.db.exec(stmt); + } catch (e) { + debugger; + throw new CompositeError(`failed to apply: ${basename} at line ${i}`, e); + } + } break; case '.js': - await this.run_js_migration_({ - filename, contents, - }); + try { + await this.run_js_migration_({ + filename, contents, + }); + } catch (e) { + throw new CompositeError(`failed to apply: ${basename}`, e); + } break; default: throw new Error( diff --git a/src/backend/src/services/database/sqlite_setup/0024_default-groups.sql b/src/backend/src/services/database/sqlite_setup/0024_default-groups.sql index 90668d007a..e496eb0bcf 100644 --- a/src/backend/src/services/database/sqlite_setup/0024_default-groups.sql +++ b/src/backend/src/services/database/sqlite_setup/0024_default-groups.sql @@ -20,15 +20,3 @@ INSERT INTO `group` ( '{"type": "default", "name": "developer"}', '{"title": "Developer", "color": "#32a852"}') ; - -INSERT INTO `jct_user_group` ( - `user_id`, - `group_id`, - `extra`, - `metadata` -) VALUES ( - 1, - (SELECT `id` FROM `group` WHERE uid='ca342a5e-b13d-4dee-9048-58b11a57cc55'), - '{}', - '{"default": true}' -); From 02504690cfb1a790b44b6447f918680047af0148 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sun, 28 Jul 2024 04:02:16 -0400 Subject: [PATCH 0635/2119] test: add database migration tests --- package-lock.json | 23 +- src/backend/package.json | 3 +- src/backend/src/CoreModule.js | 6 + src/backend/src/Kernel.js | 8 +- src/backend/src/services/BootScriptService.js | 42 ++++ src/backend/src/services/ShutdownService.js | 11 + .../database/SqliteDatabaseAccessService.js | 196 +++++++++--------- .../services/runtime-analysis/AlarmService.js | 10 + tools/migrations-test/main.js | 139 +++++++++++++ tools/migrations-test/noop.puter.json | 3 + tools/migrations-test/package.json | 15 ++ 11 files changed, 352 insertions(+), 104 deletions(-) create mode 100644 src/backend/src/services/BootScriptService.js create mode 100644 src/backend/src/services/ShutdownService.js create mode 100644 tools/migrations-test/main.js create mode 100644 tools/migrations-test/noop.puter.json create mode 100644 tools/migrations-test/package.json diff --git a/package-lock.json b/package-lock.json index 569e54660d..b36e5b1314 100644 --- a/package-lock.json +++ b/package-lock.json @@ -9798,6 +9798,10 @@ "node": ">=8.6" } }, + "node_modules/migrations-test": { + "resolved": "tools/migrations-test", + "link": true + }, "node_modules/mime": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", @@ -13728,7 +13732,6 @@ "version": "17.7.2", "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", - "license": "MIT", "dependencies": { "cliui": "^8.0.1", "escalade": "^3.1.1", @@ -14102,7 +14105,8 @@ "uuid": "^9.0.0", "validator": "^13.9.0", "winston": "^3.9.0", - "winston-daily-rotate-file": "^4.7.1" + "winston-daily-rotate-file": "^4.7.1", + "yargs": "^17.7.2" }, "devDependencies": { "@types/node": "^20.5.3", @@ -14399,6 +14403,21 @@ "js-levenshtein": "^1.1.6", "yaml": "^2.4.5" } + }, + "tools/migrations-test": { + "version": "1.0.0", + "license": "AGPL-3.0-only", + "dependencies": { + "commander": "^12.1.0" + } + }, + "tools/migrations-test/node_modules/commander": { + "version": "12.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-12.1.0.tgz", + "integrity": "sha512-Vw8qHK3bZM9y/P10u3Vib8o/DdkvA2OtPtZvD871QKjy74Wj1WSKFILMPRPSdUSx5RFK1arlJzEtA4PkFgnbuA==", + "engines": { + "node": ">=18" + } } } } diff --git a/src/backend/package.json b/src/backend/package.json index f3d0d950b0..cce89a4708 100644 --- a/src/backend/package.json +++ b/src/backend/package.json @@ -71,7 +71,8 @@ "uuid": "^9.0.0", "validator": "^13.9.0", "winston": "^3.9.0", - "winston-daily-rotate-file": "^4.7.1" + "winston-daily-rotate-file": "^4.7.1", + "yargs": "^17.7.2" }, "devDependencies": { "@types/node": "^20.5.3", diff --git a/src/backend/src/CoreModule.js b/src/backend/src/CoreModule.js index c320cd1573..ef875add2b 100644 --- a/src/backend/src/CoreModule.js +++ b/src/backend/src/CoreModule.js @@ -311,6 +311,12 @@ const install = async ({ services, app, useapi }) => { const { SUService } = require('./services/SUService'); services.registerService('su', SUService); + + const { ShutdownService } = require('./services/ShutdownService'); + services.registerService('shutdown', ShutdownService); + + const { BootScriptService } = require('./services/BootScriptService'); + services.registerService('boot-script', BootScriptService); } const install_legacy = async ({ services }) => { diff --git a/src/backend/src/Kernel.js b/src/backend/src/Kernel.js index 9f8f2b0184..30320029e5 100644 --- a/src/backend/src/Kernel.js +++ b/src/backend/src/Kernel.js @@ -20,6 +20,9 @@ const { AdvancedBase } = require("@heyputer/puter-js-common"); const { Context } = require('./util/context'); const BaseService = require("./services/BaseService"); const useapi = require('useapi'); +const yargs = require('yargs/yargs') +const { hideBin } = require('yargs/helpers') + class Kernel extends AdvancedBase { constructor ({ entry_path } = {}) { @@ -67,7 +70,9 @@ class Kernel extends AdvancedBase { } boot () { - this._runtime_init(); + const args = yargs(hideBin(process.argv)).argv + + this._runtime_init({ args }); // const express = require('express') // const app = express(); @@ -111,6 +116,7 @@ class Kernel extends AdvancedBase { services, config, logger: this.bootLogger, + args, }, 'app'); globalThis.root_context = root_context; diff --git a/src/backend/src/services/BootScriptService.js b/src/backend/src/services/BootScriptService.js new file mode 100644 index 0000000000..4b587ceeec --- /dev/null +++ b/src/backend/src/services/BootScriptService.js @@ -0,0 +1,42 @@ +const { Context } = require("../util/context"); +const BaseService = require("./BaseService"); + +class BootScriptService extends BaseService { + static MODULES = { + fs: require('fs'), + } + async ['__on_boot.ready'] () { + const args = Context.get('args'); + if ( ! args['boot-script'] ) return; + const script_name = args['boot-script']; + + const require = this.require; + const fs = require('fs'); + const boot_json_raw = fs.readFileSync(script_name, 'utf8'); + const boot_json = JSON.parse(boot_json_raw); + await this.run_script(boot_json); + } + + async run_script (boot_json) { + const scope = { + runner: 'boot-script', + ['end-puter-process']: ({ args }) => { + const svc_shutdown = this.services.get('shutdown'); + svc_shutdown.shutdown(args[0]); + } + }; + + for ( let i=0 ; i < boot_json.length ; i++ ) { + const statement = boot_json[i]; + const [cmd, ...args] = statement; + if ( ! scope[cmd] ) { + throw new Error(`Unknown command: ${cmd}`); + } + await scope[cmd]({ scope, args }); + } + } +} + +module.exports = { + BootScriptService +}; diff --git a/src/backend/src/services/ShutdownService.js b/src/backend/src/services/ShutdownService.js new file mode 100644 index 0000000000..07a2a94784 --- /dev/null +++ b/src/backend/src/services/ShutdownService.js @@ -0,0 +1,11 @@ +const BaseService = require("./BaseService"); + +class ShutdownService extends BaseService { + shutdown ({ reason, code } = {}) { + this.log.info(`Puter is shutting down: ${reason ?? 'no reason provided'}`); + process.stdout.write('\x1B[0m\r\n'); + process.exit(code ?? 0); + } +} + +module.exports = { ShutdownService }; diff --git a/src/backend/src/services/database/SqliteDatabaseAccessService.js b/src/backend/src/services/database/SqliteDatabaseAccessService.js index 3385970f41..5458cbf370 100644 --- a/src/backend/src/services/database/SqliteDatabaseAccessService.js +++ b/src/backend/src/services/database/SqliteDatabaseAccessService.js @@ -18,6 +18,7 @@ */ const { es_import_promise } = require("../../fun/dev-console-ui-utils"); const { surrounding_box } = require("../../fun/dev-console-ui-utils"); +const { Context } = require("../../util/context"); const { CompositeError } = require("../../util/errorutil"); const structutil = require("../../util/structutil"); const { BaseDatabaseAccessService } = require("./BaseDatabaseAccessService"); @@ -44,7 +45,14 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { this.db = new Database(this.config.path); // Database upgrade logic - const TARGET_VERSION = 24; + const HIGHEST_VERSION = 24; + const TARGET_VERSION = (() => { + const args = Context.get('args'); + if ( args['database-target-version'] ) { + return parseInt(args['database-target-version']); + } + return HIGHEST_VERSION; + })(); const [{ user_version }] = do_setup ? [{ user_version: -1 }] @@ -53,105 +61,93 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { const upgrade_files = []; - if ( user_version === -1 ) { - upgrade_files.push('0001_create-tables.sql'); - upgrade_files.push('0002_add-default-apps.sql'); - } - - if ( user_version <= 0 ) { - upgrade_files.push('0003_user-permissions.sql'); - } - - if ( user_version <= 1 ) { - upgrade_files.push('0004_sessions.sql'); - } - - if ( user_version <= 2 ) { - upgrade_files.push('0005_background-apps.sql'); - } - - if ( user_version <= 3 ) { - upgrade_files.push('0006_update-apps.sql'); - } - - if ( user_version <= 4 ) { - upgrade_files.push('0007_sessions.sql'); - } - - if ( user_version <= 5 ) { - upgrade_files.push('0008_otp.sql'); - } - - if ( user_version <= 6 ) { - upgrade_files.push('0009_app-prefix-fix.sql'); - } - - if ( user_version <= 7 ) { - upgrade_files.push('0010_add-git-app.sql'); - } - - if ( user_version <= 8 ) { - upgrade_files.push('0011_notification.sql'); - } - - if ( user_version <= 9 ) { - upgrade_files.push('0012_appmetadata.sql'); - } - - if ( user_version <= 10 ) { - upgrade_files.push('0013_protected-apps.sql'); - } - - if ( user_version <= 11 ) { - upgrade_files.push('0014_share.sql'); - } - - if ( user_version <= 12 ) { - upgrade_files.push('0015_group.sql'); - } - - if ( user_version <= 13 ) { - upgrade_files.push('0016_group-permissions.sql'); - } - - if ( user_version <= 14 ) { - upgrade_files.push('0017_publicdirs.sql'); - } - - if ( user_version <= 15 ) { - upgrade_files.push('0018_fix-0003.sql'); - } - - if ( user_version <= 16 ) { - upgrade_files.push('0019_fix-0016.sql'); - } - - if ( user_version <= 17 ) { - upgrade_files.push('0020_dev-center.sql'); - } - - if ( user_version <= 18 ) { - upgrade_files.push('0021_app-owner-id.sql'); - } - - if ( user_version <= 19 ) { - upgrade_files.push('0022_dev-center-max.sql'); - } - - if ( user_version <= 20 ) { - upgrade_files.push('0023_fix-kv.sql'); - } - - if ( user_version <= 21 ) { - upgrade_files.push('0024_default-groups.sql'); - } - - if ( user_version <= 22 ) { - upgrade_files.push('0025_system-user.dbmig.js'); - } - - if ( user_version <= 23 ) { - upgrade_files.push('0026_user-groups.dbmig.js'); + const available_migrations = [ + [-1, [ + '0001_create-tables.sql', + '0002_add-default-apps.sql', + ]], + [0, [ + '0003_user-permissions.sql', + ]], + [1, [ + '0004_sessions.sql', + ]], + [2, [ + '0005_background-apps.sql', + ]], + [3, [ + '0006_update-apps.sql', + ]], + [4, [ + '0007_sessions.sql', + ]], + [5, [ + '0008_otp.sql', + ]], + [6, [ + '0009_app-prefix-fix.sql', + ]], + [7, [ + '0010_add-git-app.sql', + ]], + [8, [ + '0011_notification.sql', + ]], + [9, [ + '0012_appmetadata.sql', + ]], + [10, [ + '0013_protected-apps.sql', + ]], + [11, [ + '0014_share.sql', + ]], + [12, [ + '0015_group.sql', + ]], + [13, [ + '0016_group-permissions.sql', + ]], + [14, [ + '0017_publicdirs.sql', + ]], + [15, [ + '0018_fix-0003.sql', + ]], + [16, [ + '0019_fix-0016.sql', + ]], + [17, [ + '0020_dev-center.sql', + ]], + [18, [ + '0021_app-owner-id.sql', + ]], + [19, [ + '0022_dev-center-max.sql', + ]], + [20, [ + '0023_fix-kv.sql', + ]], + [21, [ + '0024_default-groups.sql', + ]], + [22, [ + '0025_system-user.dbmig.js', + ]], + [23, [ + '0026_user-groups.dbmig.js', + ]], + ]; + + for ( const [v_lt_or_eq, files] of available_migrations ) { + if ( v_lt_or_eq + 1 >= TARGET_VERSION && TARGET_VERSION !== HIGHEST_VERSION ) { + this.log.noticeme(`Early exit: target version set to ${TARGET_VERSION}`); + break; + } + if ( user_version <= v_lt_or_eq ) { + upgrade_files.push(...files); + } } if ( upgrade_files.length > 0 ) { diff --git a/src/backend/src/services/runtime-analysis/AlarmService.js b/src/backend/src/services/runtime-analysis/AlarmService.js index 69711b96b5..177ca2ce86 100644 --- a/src/backend/src/services/runtime-analysis/AlarmService.js +++ b/src/backend/src/services/runtime-analysis/AlarmService.js @@ -28,6 +28,7 @@ const { generate_identifier } = require('../../util/identifier.js'); const { stringify_log_entry } = require('./LogService.js'); const BaseService = require('../BaseService.js'); const { split_lines } = require('../../util/stdioutil.js'); +const { Context } = require('../../util/context.js'); class AlarmService extends BaseService { async _construct () { @@ -251,6 +252,15 @@ class AlarmService extends BaseService { svc_devConsole.add_widget(this.alarm_widget); } + const args = Context.get('args'); + if ( args['quit-on-alarm'] ) { + const svc_shutdown = this.services.get('shutdown'); + svc_shutdown.shutdown({ + reason: '--quit-on-alarm is set', + code: 1, + }); + } + if ( alarm.no_alert ) return; const severity = alarm.severity ?? 'critical'; diff --git a/tools/migrations-test/main.js b/tools/migrations-test/main.js new file mode 100644 index 0000000000..5531867dfa --- /dev/null +++ b/tools/migrations-test/main.js @@ -0,0 +1,139 @@ +const path_ = require('node:path'); +const fs = require('node:fs'); +const { spawnSync } = require('node:child_process'); +const prompt = require('prompt-sync')({sigint: true}); + +const ind_str = () => Array(ind).fill(' --').join(''); + +let ind = 0; + +const log = { + // log with unicode warning symbols in yellow + warn: (msg) => { + console.log(`\x1b[33;1m[!]${ind_str()} ${msg}\x1b[0m`); + }, + crit: (msg) => { + console.log(`\x1b[31;1m[!]${ind_str()} ${msg}\x1b[0m`); + }, + info: (msg) => { + console.log(`\x1B[36;1m[i]\x1B[0m${ind_str()} ${msg}`); + }, + named: (name, value) => { + console.log(`\x1B[36;1m[i]${ind_str()} ${name}\x1B[0m ${value}`); + }, + error: e => { + if ( e instanceof UserError ) { + log.crit(e.message); + } else { + console.error(e); + } + }, + indent () { ind++; }, + dedent () { ind--; }, + heading (title) { + const circle = '🔵'; + console.log(`\n\x1b[36;1m${circle} ${title} ${circle}\x1b[0m`); + } +}; + +const areyousure = (message, options = {}) => { + const { crit } = options; + const logfn = crit ? log.crit : log.warn; + + logfn(message); + const answer = prompt(`\x1B[35;1m[?]\x1B[0m ${ options?.prompt ?? 'Are you sure?' } (y/n): `); + if ( answer !== 'y' ) { + + if ( options.fail_hint ) { + log.info(options.fail_hint); + } + + console.log(`\x1B[31;21;1mAborted.\x1B[0m`); + process.exit(1); + } +} + +if ( ! fs.existsSync('.is_puter_repository') ) { + throw new Error('This script must be run from the root of a puter repository'); +} + +areyousure( + 'This script will delete all data in the database. Are you sure you want to proceed?', + { crit: true } +) + +let backup_created = false; + +const DBPATH = 'volatile/runtime/puter-database.sqlite'; +const delete_db = () => { + if ( ! fs.existsSync(DBPATH) ) { + log.info('No database file to remove'); + // no need to create a backup if the database doesn't exist + backup_created = true; + return; + } + if ( ! backup_created ) { + log.info(`Creating a backup of the database...`); + const RANDOM = Math.floor(Math.random() * 1000000); + const DATE = new Date().toISOString().replace(/:/g, '-'); + fs.renameSync(DBPATH, `${DBPATH}_${DATE}_${RANDOM}.bak`); + backup_created = true; + return; + } + log.info('Removing database file'); + fs.unlinkSync(DBPATH); +} + +const pwd = process.cwd(); +const boot_script_path = path_.join(pwd, 'tools/migrations-test/noop.puter.json'); + +const launch_puter = (args) => { + const ret = spawnSync( + 'node', + ['tools/run-selfhosted.js', ...args], + { + stdio: 'inherit', + env: { + ...process.env, + NO_VAR_RUNTIME: '1', + }, + } + ); + ret.ok = ret.status === 0; + return ret; +}; + +{ + delete_db(); + log.info(`Test case: fresh install`); + if ( ! launch_puter([ + '--quit-on-alarm', + `--boot-script=${boot_script_path}`, + ]).ok ) { + log.crit('Migration to v21 raised alarm'); + process.exit(1); + } +} +{ + delete_db(); + log.info(`Test case: migrate to 21, then migrate to 24`); + if ( ! launch_puter([ + `--database-target-version=21`, + '--quit-on-alarm', + `--boot-script=${boot_script_path}`, + ]).ok ) { + log.crit('Migration to v21 raised alarm'); + process.exit(1); + } + if ( ! launch_puter([ + `--database-target-version=24`, + '--quit-on-alarm', + `--boot-script=${boot_script_path}`, + ]).ok ) { + log.crit('Migration to v24 raised alarm'); + process.exit(1); + } +} + +log.info('No migration scripts produced any obvious errors.'); +log.warn('This is not a substitute for release candidate migration testing!'); diff --git a/tools/migrations-test/noop.puter.json b/tools/migrations-test/noop.puter.json new file mode 100644 index 0000000000..8afc862549 --- /dev/null +++ b/tools/migrations-test/noop.puter.json @@ -0,0 +1,3 @@ +[ + ["end-puter-process", { "reason": "migrations test" }] +] diff --git a/tools/migrations-test/package.json b/tools/migrations-test/package.json new file mode 100644 index 0000000000..e960d4c04b --- /dev/null +++ b/tools/migrations-test/package.json @@ -0,0 +1,15 @@ +{ + "name": "migrations-test", + "version": "1.0.0", + "main": "main.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "AGPL-3.0-only", + "description": "", + "dependencies": { + "commander": "^12.1.0" + } +} From 1e753843d2c795ec7837d5af794d63fdc3fa1d7f Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sun, 28 Jul 2024 12:41:52 -0700 Subject: [PATCH 0636/2119] Remove some of the unused component imports --- src/gui/src/UI/UIWindow2FASetup.js | 2 -- src/gui/src/UI/UIWindowLogin.js | 2 -- src/gui/src/UI/UIWindowQR.js | 1 - src/gui/src/UI/UIWindowTaskManager.js | 2 -- src/gui/src/css/style.css | 1 - 5 files changed, 8 deletions(-) diff --git a/src/gui/src/UI/UIWindow2FASetup.js b/src/gui/src/UI/UIWindow2FASetup.js index 62aad9b9e6..bd0b82966a 100644 --- a/src/gui/src/UI/UIWindow2FASetup.js +++ b/src/gui/src/UI/UIWindow2FASetup.js @@ -48,8 +48,6 @@ import RecoveryCodesView from "./Components/RecoveryCodesView.js"; import StepHeading from "./Components/StepHeading.js"; import StepView from "./Components/StepView.js"; import StringView from "./Components/StringView.js"; -import TestView from "./Components/TestView.js"; -import UIAlert from "./UIAlert.js"; import UIComponentWindow from "./UIComponentWindow.js"; const UIWindow2FASetup = async function UIWindow2FASetup () { diff --git a/src/gui/src/UI/UIWindowLogin.js b/src/gui/src/UI/UIWindowLogin.js index ba7e100294..0363fc6064 100644 --- a/src/gui/src/UI/UIWindowLogin.js +++ b/src/gui/src/UI/UIWindowLogin.js @@ -21,13 +21,11 @@ import UIWindow from './UIWindow.js' import UIWindowSignup from './UIWindowSignup.js' import UIWindowRecoverPassword from './UIWindowRecoverPassword.js' import TeePromise from '../util/TeePromise.js'; -import UIAlert from './UIAlert.js'; import UIComponentWindow from './UIComponentWindow.js'; import Flexer from './Components/Flexer.js'; import CodeEntryView from './Components/CodeEntryView.js'; import JustHTML from './Components/JustHTML.js'; import StepView from './Components/StepView.js'; -import TestView from './Components/TestView.js'; import Button from './Components/Button.js'; import RecoveryCodeEntryView from './Components/RecoveryCodeEntryView.js'; diff --git a/src/gui/src/UI/UIWindowQR.js b/src/gui/src/UI/UIWindowQR.js index 8976fc685e..d940184f28 100644 --- a/src/gui/src/UI/UIWindowQR.js +++ b/src/gui/src/UI/UIWindowQR.js @@ -18,7 +18,6 @@ */ import Placeholder from '../util/Placeholder.js'; -import TeePromise from '../util/TeePromise.js'; import Flexer from './Components/Flexer.js'; import QRCodeView from './Components/QRCode.js'; import UIWindow from './UIWindow.js' diff --git a/src/gui/src/UI/UIWindowTaskManager.js b/src/gui/src/UI/UIWindowTaskManager.js index 47c58e224a..5ff1e3ffb3 100644 --- a/src/gui/src/UI/UIWindowTaskManager.js +++ b/src/gui/src/UI/UIWindowTaskManager.js @@ -23,8 +23,6 @@ import UIWindow from "./UIWindow.js"; import { Component, defineComponent } from '../util/Component.js'; import UIComponentWindow from './UIComponentWindow.js'; import Table from './Components/Table.js'; -import Placeholder from '../util/Placeholder.js'; -import TestView from './Components/TestView.js'; const end_process = async (uuid, force) => { const svc_process = globalThis.services.get('process'); diff --git a/src/gui/src/css/style.css b/src/gui/src/css/style.css index 279c980fff..d6912ab62d 100644 --- a/src/gui/src/css/style.css +++ b/src/gui/src/css/style.css @@ -981,7 +981,6 @@ span.header-sort-icon img { flex-flow: row; padding-left: 5px; margin-bottom: -1px; - } .device-phone .window-head { From c7ab7e04a6bd4a6ffd4b5251e383c8394a9a1e83 Mon Sep 17 00:00:00 2001 From: RandomStrangerOnTheInternet Date: Wed, 31 Jul 2024 22:56:36 +0200 Subject: [PATCH 0637/2119] Update Dutch translations (fixes https://github.com/HeyPuter/puter/issues/543) --- src/gui/src/i18n/translations/nl.js | 419 +++++++++++++++++++--------- 1 file changed, 282 insertions(+), 137 deletions(-) diff --git a/src/gui/src/i18n/translations/nl.js b/src/gui/src/i18n/translations/nl.js index d02da55d23..97b0e8d825 100644 --- a/src/gui/src/i18n/translations/nl.js +++ b/src/gui/src/i18n/translations/nl.js @@ -16,192 +16,337 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ +import en from "./en.js"; const nl = { - name: "Nederlands", - english_name: "Dutch", - code: "nl", + name: 'Nederlands', + english_name: 'Dutch', + code: 'nl', dictionary: { - about: "Over", - account: "Account", - access_granted_to: "Toegang gegeven aan", - add_existing_account: "Bestaand Account Toevoegen", + about: 'Over', + account: 'Account', + account_password: 'Verifieer Account Wachtwoord', + access_granted_to: 'Toegang gegeven aan', + add_existing_account: 'Bestaand Account Toevoegen', all_fields_required: 'Alle velden zijn vereist.', - apply: "Toepassen", + allow: 'Toestaan', + apply: 'Toepassen', ascending: 'Oplopend', + associated_websites: 'Geassocieerde Websites', auto_arrange: 'Automatisch sorteren', - background: "Achtergrond", - browse: "Verkennen", + background: 'Achtergrond', + browse: 'Bladeren', cancel: 'Annuleren', center: 'Centreren', - change_desktop_background: 'Achtergrond veranderen…', - change_language: "Taal veranderen", - change_password: "Wachtwoord veranderen", - change_username: "Gebruikersnaam veranderen", - close_all_windows: "Alle schermen sluiten", - close_all_windows_and_log_out: 'Alle schermen sluiten en afmelden', - change_always_open_with: "Dit type bestand altijd openen met", + change_desktop_background: 'Bureaubladachtergrond veranderen…', + change_email: 'E-mail Wijzigen', + change_language: 'Taal veranderen', + change_password: 'Wachtwoord veranderen', + change_ui_colors: 'UI Kleuren veranderen', + change_username: 'Gebruikersnaam veranderen', + close: 'Sluiten', + close_all_windows: 'Alle vensters sluiten', + close_all_windows_confirm: 'Weet u zeker dat u alle vensters wilt sluiten?', + close_all_windows_and_log_out: 'Vensters sluiten en afmelden', + change_always_open_with: 'Wilt u dit bestandstype altijd openen met', color: 'Kleur', confirm: 'Bevestig', - confirm_account_for_free_referral_storage_c2a: 'Maak een account en bevestig uw emailadres om 1 GB aan gratis opslag te ontvangen. Uw vriend krijgt ook 1 GB aan gratis opslag.', - confirm_delete_multiple_items: 'Weet u zeker dat u deze bestanden permanent wilt verwijderen?', - confirm_delete_single_item: 'Weet u zeker dat u dit bestand permanent wilt verwijderen?', - confirm_delete_user: 'Weet u zeker dat u uw account wilt verwijderen? Al uw bestanden en gegevens zal permanent verwijderd worden. Deze actie kan niet ongedaan gemaakt worden.', - confirm_open_apps_log_out: 'U heeft nog geopende applicaties. Weet u zeker dat u wilt uitloggen?', - confirm_new_password: "Bevestig Nieuw Wachtwoord", - contact_us: "Neem contact met ons op", + confirm_2fa_setup: 'Ik heb de code toegevoegd aan mijn authenticatie-app', + confirm_2fa_recovery: 'Ik heb mijn herstelcodes op een veilige plaats opgeslagen', + confirm_account_for_free_referral_storage_c2a: 'Maak een account aan en bevestig uw e-mailadres om 1 GB gratis opslag te ontvangen. Uw vriend krijgt ook 1 GB gratis opslag.', + confirm_code_generic_incorrect: 'Onjuiste code.', + confirm_code_generic_too_many_requests: 'Te veel aanvragen. Wacht een paar minuten.', + confirm_code_generic_submit: 'Code invoeren', + confirm_code_generic_try_again: 'Probeer opnieuw', + confirm_code_generic_title: 'Bevestigingscode Invoeren', + confirm_code_2fa_instruction: 'Voer de 6-cijferige code in van uw authenticatie-app.', + confirm_code_2fa_submit_btn: 'Verzenden', + confirm_code_2fa_title: 'Voer 2FA Code In', + confirm_delete_multiple_items: 'Weet u zeker dat u deze items permanent wilt verwijderen?', + confirm_delete_single_item: 'Wilt u dit item permanent verwijderen?', + confirm_open_apps_log_out: 'U heeft geopende apps. Weet u zeker dat u wilt uitloggen?', + confirm_new_password: 'Bevestig Nieuw Wachtwoord', + confirm_delete_user: 'Weet u zeker dat u uw account wilt verwijderen? Al uw bestanden en gegevens worden permanent verwijderd. Deze actie kan niet ongedaan worden gemaakt.', + confirm_delete_user_title: 'Account Verwijderen?', + confirm_session_revoke: 'Weet u zeker dat u deze sessie wilt intrekken?', + confirm_your_email_address: 'Bevestig Uw E-mailadres', + contact_us: 'Neem Contact Op', + contact_us_verification_required: 'U moet een geverifieerd e-mailadres hebben om dit te gebruiken.', contain: 'Bevatten', - continue: "Doorgaan", + continue: 'Doorgaan', copy: 'Kopiëren', - copy_link: "Kopieer koppeling", - copying: "Kopiëren", + copy_link: 'Link Kopiëren', + copying: 'Kopiëren', + copying_file: 'Bestand Kopiëren %%', cover: 'Omslag', - create_account: "Maak Account", - create_free_account: "Maak Gratis Account", - create_shortcut: "Maak Snelkoppeling", - credits: "Credits", - current_password: "Huidig Wachtwoord", + create_account: 'Account Aanmaken', + create_free_account: 'Gratis Account Aanmaken', + create_shortcut: 'Snelkoppeling Maken', + credits: 'Credits', + current_password: 'Huidig Wachtwoord', cut: 'Knippen', - date_modified: 'Datum gewijzigd', + clock: 'Klok', + clock_visible_hide: 'Verbergen - Altijd verborgen', + clock_visible_show: 'Weergeven - Altijd zichtbaar', + clock_visible_auto: 'Auto - Standaard, alleen zichtbaar in de volledige schermmodus.', + close_all: 'Alles Sluiten', + created: 'Gemaakt', + date_modified: 'Datum Gewijzigd', + default: 'Standaard', delete: 'Verwijderen', - delete_account: "Account Verwijderen", - delete_permanently: "Permanent Verwijderen", - deploy_as_app: 'Uitrollen als applicatie', + delete_account: 'Account Verwijderen', + delete_permanently: 'Permanent Verwijderen', + deleting_file: 'Bestand Verwijderen %%', + deploy_as_app: 'Uitrollen als app', descending: 'Aflopend', - desktop_background_fit: "Passend", - developers: "Ontwikkelaars", - dir_published_as_website: `%strong% is gepubliceerd naar:`, - disassociate_dir: "Map Ontkoppelen", + desktop: 'Bureaublad', + desktop_background_fit: 'Aanpassen', + developers: 'Ontwikkelaars', + dir_published_as_website: `%strong% is gepubliceerd op:`, + disable_2fa: '2FA Uitschakelen', + disable_2fa_confirm: 'Weet u zeker dat u 2FA wilt uitschakelen?', + disable_2fa_instructions: 'Voer uw wachtwoord in om 2FA uit te schakelen.', + disassociate_dir: 'Map Loskoppelen', + documents: 'Documenten', + dont_allow: 'Niet Toestaan', download: 'Downloaden', download_file: 'Bestand Downloaden', - downloading: "Aan het downloaden", - email: "Emailadres", - email_or_username: "Emailadres of Gebruikersnaam", - empty_trash: 'Prullenbak Legen', - empty_trash_confirmation: `Weet u zeker dat u alle bestanden in de Prullenbak permanent wilt verwijderen?`, + downloading: 'Downloaden', + email: 'E-mail', + email_change_confirmation_sent: 'Er is een bevestigingsmail gestuurd naar uw nieuwe e-mailadres. Controleer uw inbox en volg de instructies om het proces te voltooien.', + email_invalid: 'E-mail is ongeldig.', + email_or_username: 'E-mail of Gebruikersnaam', + email_required: 'E-mail is verplicht.', + empty_trash: 'Prullenbak Leegmaken', + empty_trash_confirmation: `Weet u zeker dat u de items in de prullenbak permanent wilt verwijderen?`, emptying_trash: 'Prullenbak Legen…', - enter_password_to_confirm_delete_user: "Voer uw wachtwoord in om te bevestigen dat uw account verwijderd wordt", - feedback: "Feedback", - feedback_c2a: "Gebruik alstublieft het onderstaande formulier om ons uw feedback, opmerkingen en foutmeldingsrapporten te sturen.", - feedback_sent_confirmation: "Bedankt dat u contact met ons opneemt. Als er een emailadres aan uw account is gekoppeld, hoort u zo snel mogelijk van ons terug.", - forgot_pass_c2a: "Wachtwoord Vergeten?", - from: "Van", - general: "Algemeen", - get_a_copy_of_on_puter: `Bemachtig een kopie van '%%' op Puter.com!`, - get_copy_link: 'Krijg Kopieer Koppeling', - hide_all_windows: "Verberg alle Vensters", + enable_2fa: '2FA Inschakelen', + end_hard: 'Hard Stoppen', + end_process_force_confirm: 'Weet u zeker dat u dit proces geforceerd wilt beëindigen?', + end_soft: 'Zacht Stoppen', + enlarged_qr_code: 'Vergrote QR Code', + enter_password_to_confirm_delete_user: 'Voer uw wachtwoord in om de verwijdering van het account te bevestigen', + error_message_is_missing: 'Foutbericht ontbreekt.', + error_unknown_cause: 'Er is een onbekende fout opgetreden.', + error_uploading_files: 'Bestanden uploaden mislukt', + favorites: 'Favorieten', + feedback: 'Feedback', + feedback_c2a: 'Gebruik het onderstaande formulier om ons uw feedback, opmerkingen en bugrapporten te sturen.', + feedback_sent_confirmation: 'Bedankt dat u contact met ons heeft opgenomen. Als u een e-mail heeft gekoppeld aan uw account, hoort u zo snel mogelijk van ons.', + fit: 'Aanpassen', + folder: 'Map', + force_quit: 'Geforceerd Stoppen', + forgot_pass_c2a: 'Wachtwoord vergeten?', + from: 'Van', + general: 'Algemeen', + get_a_copy_of_on_puter: `Krijg een kopie van '%%' op Puter.com!`, + get_copy_link: 'Krijg Kopieerlink', + hide_all_windows: 'Alle Vensters Verbergen', + home: 'Home', html_document: 'HTML document', + hue: 'Tint', image: 'Afbeelding', - invite_link: "Uitnodiging Koppeling", - item: 'Bestand', - items_in_trash_cannot_be_renamed: `Dit bestand kan niet hernoemd worden omdat het in de Prullenbak zit. Om dit bestand te hernoemen, verplaats het eerst uit de Prullenbak.`, + incorrect_password: 'Onjuist wachtwoord', + invite_link: 'Uitnodigingslink', + item: 'item', + items_in_trash_cannot_be_renamed: `Dit item kan niet worden hernoemd omdat het in de prullenbak zit. Om dit item te hernoemen, sleept u het eerst uit de prullenbak.`, jpeg_image: 'JPEG afbeelding', - keep_in_taskbar: 'In Taakbalk houden', - language: "Taal", - license: "Licentie", + keep_in_taskbar: 'In Taakbalk Houden', + language: 'Taal', + license: 'Licentie', + lightness: 'Helderheid', + link_copied: 'Link gekopieerd', loading: 'Laden', - log_in: "Inloggen", - log_into_another_account_anyway: 'Alsnog met ander account inloggen', + log_in: 'Inloggen', + log_into_another_account_anyway: 'Log toch in op een ander account', log_out: 'Uitloggen', + looks_good: 'Ziet er goed uit!', + manage_sessions: 'Sessies Beheren', + menubar_style: 'Menubalk Stijl', + menubar_style_desktop: 'Bureaublad', + menubar_style_system: 'Systeem', + menubar_style_window: 'Venster', + mobile_device: 'Mobiel apparaat', + modified: 'Gewijzigd', move: 'Verplaatsen', - moving_file: "Aan het verplaatsen %%", - my_websites: "Mijn Websites", + moving_file: 'Verplaatsen %%', + my_websites: 'Mijn Websites', name: 'Naam', name_cannot_be_empty: 'Naam kan niet leeg zijn.', - name_cannot_contain_double_period: "Naam mag geen '..'-karakter bevatten.", - name_cannot_contain_period: "Naam mag geen '.'-karakter bevatten.", - name_cannot_contain_slash: "Naam mag geen '/'-karakter bevatten.", - name_must_be_string: "Naam kan alleen een tekenreeks zijn.", - name_too_long: `Naam kan niet langer zijn dan %% karakters.`, + name_cannot_contain_double_period: 'Naam mag geen dubbele punt \'..\' bevatten.', + name_cannot_contain_period: 'Naam mag geen punt \' . \' bevatten.', + name_cannot_contain_slash: 'Naam mag geen schuine streep \' / \' bevatten.', + name_must_be_string: 'Naam moet een alfanumerieke tekenreeks zijn.', + name_too_long: 'Naam mag niet langer zijn dan %% karakters.', new: 'Nieuw', + new_email: 'Nieuwe E-mail', new_folder: 'Nieuwe Map', - new_password: "Nieuw Wachtwoord", - new_username: "Nieuwe Gebruikersnaam", + new_password: 'Nieuw Wachtwoord', + new_username: 'Nieuwe Gebruikersnaam', no: 'Nee', - no_dir_associated_with_site: 'Er is geen map gekoppeld aan dit adres.', - no_websites_published: "U heeft nog geen websites gepubliceerd.", - ok: 'Oke', - open: "Open", - open_in_new_tab: "Open in Nieuw Tabblad", - open_in_new_window: "Open in Nieuw Scherm", - open_with: "Openen met", - oss_code_and_content: "Open source-software en inhoud", - password: "Wachtwoord", - password_changed: "Wachtwoord veranderd.", - passwords_do_not_match: '`Nieuw Wachtwoord` en `Bevestig Nieuw Wachtwoord` komen niet overeen.', + no_dir_associated_with_site: 'Geen map geassocieerd met dit adres.', + no_websites_published: 'Je hebt nog geen websites gepubliceerd. Klik met de rechtermuisknop op een map om te beginnen.', + ok: 'OK', + open: 'Openen', + open_in_new_tab: 'Openen in Nieuw Tabblad', + open_in_new_window: 'Openen in Nieuw Venster', + open_with: 'Openen met', + original_name: 'Originele Naam', + original_path: 'Origineel Pad', + oss_code_and_content: 'Open Source Software Code en Inhoud', + password: 'Wachtwoord', + password_changed: 'Wachtwoord gewijzigd', + password_recovery_rate_limit: 'U heeft te veel verzoeken ingediend. Wacht een paar minuten voordat u het opnieuw probeert.', + password_recovery_token_invalid: 'Wachtwoord hersteltoken is verlopen of ongeldig.', + password_recovery_unknown_error: 'Onbekende fout opgetreden bij het herstellen van het wachtwoord. Probeer het opnieuw.', + password_required: 'Wachtwoord is verplicht.', + password_strength_error: 'Wachtwoord moet minimaal 8 tekens lang zijn en minimaal één hoofdletter, één kleine letter, één cijfer en één speciaal teken bevatten.', + passwords_do_not_match: 'Wachtwoorden komen niet overeen.', paste: 'Plakken', - paste_into_folder: "Plakken in Map", - pick_name_for_website: "Kies een naam voor uw website:", - picture: "Foto", - powered_by_puter_js: `Aangedreven door {{link=docs}}Puter.js{{/link}}`, - preparing: "Voorbereiden...", - preparing_for_upload: "Upload voorbereiden...", - proceed_to_login: 'Doorgaan naar Inloggen', - properties: "Eigenschappen", - privacy: "Privacy", - proceed_with_account_deletion: "Doorgaan met Account Verwijderen", - publish: "Publiceren", - publish_as_website: 'Publiceren als website', - puter_description: `Puter is een persoonlijke cloud waarin privacy centraal staat en waarmee u al uw bestanden, apps en games in één veilige plek kunt bewaren die altijd en overal toegankelijk.`, - recent: "Recent", - recover_password: "Wachtwoord herstellen", - refer_friends_c2a: "Krijg 1 GB voor elke vriend die een account maakt en bevestigt bij Puter. uw vriend ontvangt ook 1 GB!", - refer_friends_social_media_c2a: `Krijg 1 GB gratig opslag op Puter.com!`, - refresh: 'Verversen', - release_address_confirmation: `Weet u zeker dat u dit adres wilt vrijgeven?`, - remove_from_taskbar:'Losmaken van Taakbalk', + paste_into_folder: 'Plakken in Map', + path: 'Pad', + personalization: 'Personalisatie', + pick_name_for_website: 'Kies een naam voor uw website', + picture: 'Afbeelding', + pictures: 'Afbeeldingen', + plural_suffix: 'en', + powered_by_puter_js: 'Aangedreven door {{link=docs}}Puter.js{{/link}}', + preparing: 'Voorbereiden...', + preparing_for_upload: 'Voorbereiden voor upload...', + print: 'Afdrukken', + privacy: 'Privacy', + proceed_to_login: 'Doorgaan naar inloggen', + proceed_with_account_deletion: 'Doorgaan met accountverwijdering', + process_status_initializing: 'Initialiseren', + process_status_running: 'Bezig', + process_type_app: 'App', + process_type_init: 'Init', + process_type_ui: 'UI', + properties: 'Eigenschappen', + public: 'Openbaar', + publish: 'Publiceren', + publish_as_website: 'Publiceer als website', + puter_description: `Puter is een privacy-first persoonlijke cloud om al je bestanden, apps en games op één veilige plek te bewaren, overal en altijd toegankelijk.`, + reading_file: 'Lezen %strong%', + recent: 'Recent', + recommended: 'Aanbevolen', + recover_password: 'Wachtwoord herstellen', + refer_friends_c2a: 'Krijg 1 GB voor elke vriend die een account aanmaakt en bevestigt op Puter. Je vriend krijgt ook 1 GB!', + refer_friends_social_media_c2a: `Krijg 1 GB gratis opslagruimte op Puter.com!`, + refresh: 'Vernieuwen', + release_address_confirmation: `Weet je zeker dat je dit adres wilt vrijgeven?`, + remove_from_taskbar: 'Verwijderen van taakbalk', rename: 'Hernoemen', repeat: 'Herhalen', replace: 'Vervangen', - replace_all: 'Alles Vervangen', - resend_confirmation_code: "Confirmatie Code opnieuw verzenden", - restore: "Herstellen", + replace_all: 'Alles vervangen', + resend_confirmation_code: 'Bevestigingscode opnieuw verzenden', + reset_colors: 'Kleuren resetten', + restart_puter_confirm: 'Weet je zeker dat je Puter wilt herstarten?', + restore: 'Herstellen', + save: 'Opslaan', + saturation: 'Verzadiging', save_account: 'Account opslaan', - save_account_to_get_copy_link: "Maak alstublieft een account om door te gaan.", - save_account_to_publish: 'Maak alstublieft een account om door te gaan.', - save_session: 'Sessie Opslaan', - save_session_c2a: 'Maak een account aan om uw huidige sessie op te slaan en te voorkomen dat u uw werk kwijtraakt.', - scan_qr_c2a: 'Scan de onderstaande QR-code om op deze sessie in te loggen op een ander apparaat', - select: "Selecteren", + save_account_to_get_copy_link: 'Maak een account aan om verder te gaan.', + save_account_to_publish: 'Maak een account aan om verder te gaan.', + save_session: 'Sessie opslaan', + save_session_c2a: 'Maak een account aan om je huidige sessie op te slaan en verlies van werk te voorkomen.', + scan_qr_c2a: 'Scan de onderstaande code\nom in te loggen op deze sessie vanaf andere apparaten', + scan_qr_2fa: 'Scan de QR-code met je authenticator-app', + scan_qr_generic: 'Scan deze QR-code met je telefoon of een ander apparaat', + search: 'Zoeken', + seconds: 'seconden', + security: 'Beveiliging', + select: 'Selecteren', selected: 'geselecteerd', select_color: 'Selecteer kleur…', - send: "Versturen", - send_password_recovery_email: "Verstuur Wachtwoord Herstel Email", - session_saved: "Bedankt voor het maken van een account. Deze sessie is nu opgeslagen.", + sessions: 'Sessies', + send: 'Verzenden', + send_password_recovery_email: 'Wachtwoordherstelsmail verzenden', + session_saved: 'Bedankt voor het aanmaken van een account. Deze sessie is opgeslagen.', settings: 'Instellingen', - set_new_password: "Stel een nieuw wachtwoord in", - share_to: "Delen naar", - show_all_windows: "Toon alle vensters", - show_hidden: 'Toon Verborgen', - sign_in_with_puter: "Inloggen met Puter", - sign_up: "Aanmelden", - signing_in: "Aan het inloggen…", + set_new_password: 'Nieuw wachtwoord instellen', + share: 'Delen', + share_to: 'Delen met', + share_with: 'Delen met:', + shortcut_to: 'Snelkoppeling naar', + show_all_windows: 'Toon alle vensters', + show_hidden: 'Toon verborgen', + sign_in_with_puter: 'Inloggen met Puter', + sign_up: 'Aanmelden', + signing_in: 'Inloggen…', size: 'Grootte', skip: 'Overslaan', + something_went_wrong: 'Er is iets misgegaan.', sort_by: 'Sorteren op', start: 'Start', - status: "Status", - storage_usage: "Opslaggebruik", - taking_longer_than_usual: 'Het duurt iets langer dan normaal. Even geduld aub...', - terms: "Voorwaarden", - text_document: 'Tekst document', - tos_fineprint: `Door te klikken op 'Maak Gratis Account' gaat u akkoord met Puter's {{link=terms}}Gebruiksvoorwaarden{{/link}} en {{link=privacy}}Privacybeleid{{/link}}.`, + status: 'Status', + storage_usage: 'Opslaggebruik', + storage_puter_used: 'gebruikt door Puter', + taking_longer_than_usual: 'Het duurt langer dan normaal. Even geduld alstublieft...', + task_manager: 'Taakbeheer', + taskmgr_header_name: 'Naam', + taskmgr_header_status: 'Status', + taskmgr_header_type: 'Type', + terms: 'Voorwaarden', + text_document: 'Tekstdocument', + tos_fineprint: `Door op 'Gratis Account Aanmaken' te klikken, ga je akkoord met de {{link=terms}}Servicevoorwaarden{{/link}} en de {{link=privacy}}Privacybeleid{{/link}} van Puter.`, + transparency: 'Transparantie', trash: 'Prullenbak', + two_factor: 'Tweestapsverificatie', + two_factor_disabled: '2FA Uitgeschakeld', + two_factor_enabled: '2FA Ingeschakeld', type: 'Type', - type_confirm_to_delete_account: "Type 'bevestig' om uw account te verwijderen.", + type_confirm_to_delete_account: 'Typ 'bevestigen' om je account te verwijderen.', + ui_colors: 'UI Kleuren', + ui_manage_sessions: 'Sessiebeheer', + ui_revoke: 'Intrekken', undo: 'Ongedaan maken', unlimited: 'Onbeperkt', - unzip: "Uitpakken", + unzip: 'Uitpakken', upload: 'Uploaden', - upload_here: 'Hier Uploaden', + upload_here: 'Hier uploaden', usage: 'Gebruik', - username: "Gebruikersnaam", - username_changed: 'Gebruikersnaam succesvol aangepast.', - versions: "Versies", + username: 'Gebruikersnaam', + username_changed: 'Gebruikersnaam succesvol bijgewerkt.', + username_required: 'Gebruikersnaam is vereist.', + versions: 'Versies', + videos: 'Video\'s', + visibility: 'Zichtbaarheid', yes: 'Ja', - yes_release_it: 'Ja, Geef het vrij', - you_have_been_referred_to_puter_by_a_friend: "Je bent door een vriend naar Puter verwezen!", - zip: "Inpakken", + yes_release_it: 'Ja, vrijgeven', + you_have_been_referred_to_puter_by_a_friend: 'Je bent door een vriend doorverwezen naar Puter!', + zip: 'Zip', + zipping_file: 'Bestand inpakken %strong%', + + // === 2FA Setup === + setup2fa_1_step_heading: 'Open je authenticator-app', + setup2fa_1_instructions: ` + Je kunt elke authenticator-app gebruiken die het Time-based One-Time Password (TOTP) protocol ondersteunt. + Er zijn veel opties om uit te kiezen, maar als je twijfelt, + Authy + is een goede keuze voor Android en iOS. + `, + setup2fa_2_step_heading: 'Scan de QR-code', + setup2fa_3_step_heading: 'Voer de 6-cijferige code in', + setup2fa_4_step_heading: 'Kopieer je herstelcodes', + setup2fa_4_instructions: ` + Deze herstelcodes zijn de enige manier om toegang te krijgen tot je account als je je telefoon kwijtraakt of je authenticator-app niet kunt gebruiken. + Zorg ervoor dat je ze op een veilige plaats bewaart. + `, + setup2fa_5_step_heading: 'Bevestig 2FA-instelling', + setup2fa_5_confirmation_1: 'Ik heb mijn herstelcodes op een veilige plaats opgeslagen', + setup2fa_5_confirmation_2: 'Ik ben klaar om 2FA in te schakelen', + setup2fa_5_button: '2FA inschakelen', + + // === 2FA Login === + login2fa_otp_title: 'Voer 2FA-code in', + login2fa_otp_instructions: 'Voer de 6-cijferige code in uit je authenticator-app.', + login2fa_recovery_title: 'Voer een herstelcode in', + login2fa_recovery_instructions: 'Voer een van je herstelcodes in om toegang te krijgen tot je account.', + login2fa_use_recovery_code: 'Gebruik een herstelcode', + login2fa_recovery_back: 'Terug', + login2fa_recovery_placeholder: 'XXXXXXXX', } }; From ade66bd1da6a738101daca063f940afa158f7784 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 31 Jul 2024 17:04:22 -0400 Subject: [PATCH 0638/2119] escape unescaped single quote causing syntax error --- src/gui/src/i18n/translations/nl.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/gui/src/i18n/translations/nl.js b/src/gui/src/i18n/translations/nl.js index 97b0e8d825..e4bc171b0f 100644 --- a/src/gui/src/i18n/translations/nl.js +++ b/src/gui/src/i18n/translations/nl.js @@ -16,7 +16,6 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import en from "./en.js"; const nl = { name: 'Nederlands', @@ -297,7 +296,7 @@ const nl = { two_factor_disabled: '2FA Uitgeschakeld', two_factor_enabled: '2FA Ingeschakeld', type: 'Type', - type_confirm_to_delete_account: 'Typ 'bevestigen' om je account te verwijderen.', + type_confirm_to_delete_account: 'Typ \'bevestigen\' om je account te verwijderen.', ui_colors: 'UI Kleuren', ui_manage_sessions: 'Sessiebeheer', ui_revoke: 'Intrekken', From c28f2cb4dfbbdc2f2a770540b336652e876f0f7c Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 29 Jul 2024 15:05:55 -0400 Subject: [PATCH 0639/2119] dev: add service to test images through drivers --- src/backend/exports.js | 2 + src/backend/src/data/hardcoded-permissions.js | 3 + .../test-drivers/TestAssetHostService.js | 16 ++++ .../modules/test-drivers/TestDriversModule.js | 17 ++++ .../modules/test-drivers/TestImageService.js | 85 ++++++++++++++++++ .../modules/test-drivers/assets/starry.jpg | Bin 0 -> 1391462 bytes .../src/modules/test-drivers/assets/wave.jpg | Bin 0 -> 973284 bytes .../src/services/drivers/CoercionService.js | 1 + .../src/services/drivers/DriverService.js | 18 +++- tools/run-selfhosted.js | 4 +- 10 files changed, 141 insertions(+), 5 deletions(-) create mode 100644 src/backend/src/modules/test-drivers/TestAssetHostService.js create mode 100644 src/backend/src/modules/test-drivers/TestDriversModule.js create mode 100644 src/backend/src/modules/test-drivers/TestImageService.js create mode 100644 src/backend/src/modules/test-drivers/assets/starry.jpg create mode 100644 src/backend/src/modules/test-drivers/assets/wave.jpg diff --git a/src/backend/exports.js b/src/backend/exports.js index 77bc94024c..a8649af662 100644 --- a/src/backend/exports.js +++ b/src/backend/exports.js @@ -25,6 +25,7 @@ const PuterDriversModule = require("./src/PuterDriversModule.js"); const { testlaunch } = require("./src/index.js"); const BaseService = require("./src/services/BaseService.js"); const { Context } = require("./src/util/context.js"); +const { TestDriversModule } = require("./src/modules/test-drivers/TestDriversModule.js"); module.exports = { @@ -46,4 +47,5 @@ module.exports = { PuterDriversModule, LocalDiskStorageModule, SelfHostedModule, + TestDriversModule, }; diff --git a/src/backend/src/data/hardcoded-permissions.js b/src/backend/src/data/hardcoded-permissions.js index 26ba332fb4..8308d123f9 100644 --- a/src/backend/src/data/hardcoded-permissions.js +++ b/src/backend/src/data/hardcoded-permissions.js @@ -72,6 +72,9 @@ const policy_perm = selector => ({ const hardcoded_user_group_permissions = { system: { + 'ca342a5e-b13d-4dee-9048-58b11a57cc55': { + 'service': {}, + }, 'b7220104-7905-4985-b996-649fdcdb3c8f': { 'service:hello-world:ii:hello-world': policy_perm('temp.es'), 'driver:puter-kvstore': policy_perm('temp.kv'), diff --git a/src/backend/src/modules/test-drivers/TestAssetHostService.js b/src/backend/src/modules/test-drivers/TestAssetHostService.js new file mode 100644 index 0000000000..dd991959ec --- /dev/null +++ b/src/backend/src/modules/test-drivers/TestAssetHostService.js @@ -0,0 +1,16 @@ +const BaseService = require("../../services/BaseService"); + +class TestAssetHostService extends BaseService { + async ['__on_install.routes'] () { + const { app } = this.services.get('web-server'); + const path_ = require('node:path'); + + app.use('/test-assets', require('express').static( + path_.join(__dirname, 'assets') + )); + } +} + +module.exports = { + TestAssetHostService +}; diff --git a/src/backend/src/modules/test-drivers/TestDriversModule.js b/src/backend/src/modules/test-drivers/TestDriversModule.js new file mode 100644 index 0000000000..609324a183 --- /dev/null +++ b/src/backend/src/modules/test-drivers/TestDriversModule.js @@ -0,0 +1,17 @@ +const { AdvancedBase } = require("@heyputer/puter-js-common"); + +class TestDriversModule extends AdvancedBase { + async install (context) { + const services = context.get('services'); + + const { TestAssetHostService } = require('./TestAssetHostService') + services.registerService('__test-assets', TestAssetHostService); + + const { TestImageService } = require('./TestImageService'); + services.registerService('test-image', TestImageService); + } +} + +module.exports = { + TestDriversModule, +}; diff --git a/src/backend/src/modules/test-drivers/TestImageService.js b/src/backend/src/modules/test-drivers/TestImageService.js new file mode 100644 index 0000000000..4c0603042b --- /dev/null +++ b/src/backend/src/modules/test-drivers/TestImageService.js @@ -0,0 +1,85 @@ +const config = require("../../config"); +const BaseService = require("../../services/BaseService"); +const { TypedValue } = require("../../services/drivers/meta/Runtime"); +const { buffer_to_stream } = require("../../util/streamutil"); + +const PUBLIC_DOMAIN_IMAGES = [ + { + name: 'starry-night', + url: 'https://upload.wikimedia.org/wikipedia/commons/e/ea/Van_Gogh_-_Starry_Night_-_Google_Art_Project.jpg', + file: 'starry.jpg', + }, +]; + +class TestImageService extends BaseService { + async ['__on_driver.register.interfaces'] () { + const svc_registry = this.services.get('registry'); + const col_interfaces = svc_registry.get('interfaces'); + + col_interfaces.set('test-image', { + methods: { + echo_image: { + parameters: { + source: { + type: 'file', + }, + }, + result: { + type: { + $: 'stream', + content_type: 'image' + }, + }, + }, + get_image: { + parameters: { + source_type: { + type: 'string' + }, + }, + result: { + type: { + $: 'stream', + content_type: 'image' + } + } + } + } + }); + } + + static IMPLEMENTS = { + ['version']: { + get_version () { + return 'v1.0.0'; + } + }, + ['test-image']: { + async echo_image ({ + source, + }) { + const stream = await source.get('stream'); + return new TypedValue({ + $: 'stream', + content_type: 'image/jpeg' + }, stream); + }, + async get_image ({ + source_type, + }) { + const image = PUBLIC_DOMAIN_IMAGES[0]; + if ( source_type === 'string:url:web' ) { + return new TypedValue({ + $: 'string:url:web', + content_type: 'image', + }, `${config.origin}/test-assets/${image.file}`); + } + throw new Error('not implemented yet'); + } + }, + } +} + +module.exports = { + TestImageService +}; diff --git a/src/backend/src/modules/test-drivers/assets/starry.jpg b/src/backend/src/modules/test-drivers/assets/starry.jpg new file mode 100644 index 0000000000000000000000000000000000000000..9a24b899d073f7ad4a55f0dc7110b457adfdc378 GIT binary patch literal 1391462 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%0Aqbo@dS-ZplmupPu>pHrSQ(D445k; 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⪤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

O~LGK#L?0y@dDb@?=%OD6|k!+5iC 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

X?gRp9I%M3LD& z$&yg{80Z;@l_6D9cF-jHi6DyPo|tg7?JQ*E#Q??0iZ3Li_VLJ%dxUJ=DN1JYYc^s z7-YtD3^FE?U#OM18$gi=R9}@!C*0R}T}n5b1jnfAa7zS!TyaE*6$1eiZB_ivD1l%K z=b(AGT9#TzkD*}X&mQJelNCiAs!7;ZjTb9i-xXEw(D0)S4A(vb-eh?x#8s^kO;>1^ zIPr!=yCTL~ju9H719l&19JLy=e0-jI<1Z~#h@u%1Pc4{~KxJklleH_F{W_W-4eHpq zIMLZyfTA)fx3@l)r~VlheHD?wO3t6L}>n_8xzag7*Pmj zvVHp}x$8~eRG~$Mlo_U*x!P8E!oH(}syPeBT*bvQKAoL5z!qGer3q&E1c5;F$8Oya z#e7{rd2-0P({4hTSdcbLkyptcmA%65_&4p*nEXA1Ge#rPzO~fSHl>ivi)5cnDgYwM zs~lf`jAP+Ag|XUq7{bD0Va72bAaG5#DkD*_x<`~ z$Hk8n1coSac;#VENd1Q=_3Cv!FK-sv+rH)Y| zjfAp4$RG9U?ZebN6>|kw6AvpDNt-qozUD}eKYJDZ==BbzgxMH!GKd!<5Yj=kv5r$m z(%e`C@pNkMo~Dyk!h%0CSC}ax%(HD<_8y`-SIyR9&dQOo+E}7SVdREoLH__5X!&pa zw_mSDWh#NfHA8dR22j>~03sRb7|W42vb>;jdz(Jj@ITM02`-xfw9JG^M?PDYJb&dK zSI)_Y9p-e%W{Up+5>`?H=egZqaqKz?o2z5}7N;&c7)G6p&ihrxxB#jhr_x%~4s7lm zb?Ip`t63%8c%Q<`Ib7%sMzXaS4H}c*=FcfdK zZohDA*SLxo z_O7pKI$ph#is`Is5)D2^Ws)4(m`3t#APv-0b+F_TM?7`TrBMF>^&`mp-*>jzQYkf} zUI&D&Hb`W_n<5QM#L<0DJq(4D4P!`&t_`VC`tGCbdMuhgY+?g6Ns$c12%0z*k&Sl+ z829Ts(U(B*{{Yv;fuDy9Wa6A@6|%|NjYEYjERDjhz$dp|PXN*2h-v!R!N^0xqi2ZtB09eMkxTxiJ%_-j?w{4XKMXr$Kk?3k*h&v{`Wv0(AAW3jAW z?(|PWb!}rSFGIz_)V0aA0>Bmy?8d z2CA}Trx!$V$3Sg-Lyves-~9!5VZiQ#B|9dA3zeH>X4oDeB%igY2m26s=%4a@JpDiD zCBn(a#mJRol2~;K<5erdzm+V7c;Jg2tZ~wphrfvWj4YgUO@zJzem|yP4t*Pf|M8n}?-o`eSa%^YSHzc-gODb07$;XnKEI=~un)ad-W8 z&*Ime`*tEWo0uUP*1Q#|>3A8LI$orjj-QSJTv=yPHqD~O*YsZEKmddG@6zIGa8w0g zlL|ogNrlX0ufmdSkA1vz`*cSu#u^T_Izfq@kDa$9C#AyNo}s{2^&?#ZIV2joJxeSL zmxf@t7S0vdt!3Me8!Ro=%Wqeed21Stw;7XOhzh(x%YQ8=FfNEYGT%1`WGE1?& zEM;e_gUts*e8#X)9!y}Mf&T( zFHVrG4qqj$K8FYM80W@(S?2QE4TZ#IOAtuoX}&vpy8;OJo;_1m(A>OIG|<@%1o4s= zo@s#$r2CP$e1p&p2gdq-zqC%+*mJi75_!O3Mu1XA*1rA0_UVHjInhePCQ>+G#Ewc@ zv(KddRqlHqeuPB|lbBrGsfx7BZbdZxLl-_JNRV$6vX~Opqa+eIy{xB^OI+|kzKH41 z20P@PB3Pq&Q_GPW5X7k+_OLa>8n5np13DB>HfUodPTldEU}*Ely?ldxd5scFI)RiD zHT5${wp0OD2;`dJaBJGS1zae|d(u4pHt^@=GQ?yhFVe zjGh1$U>fK9o67L!g`I+eT{}$^vhMTDl0_!(FpDUL_U!=e1otD3En_QMeK5pQZTRlz z@g-0fZSYl?)$nawZymX=k78zG%CM^u6FDfPN*oeJ&>+#jj!$wz z4T)id9?^;^tsBy9=FQ;#D# z+QER_-Ou?CfA7_~B!?;)V8}2_jUz_8OVKw*kF}p~diFggcq90S4~P@#wXAHNFHuI2 zPq{Y4y@5rMnzxYGvFU&Si{SLffsZ73cx(d zt}4@UW7`BRT497sO3l1i{5%-MW@y<8p(1G;8R(N+xQ>nP0SPKcVn1y4UOBSn#m&Y8 zDFG$oU<(QqRe|*i=8yXI`T{6q#wi?fVnG|^Z)R*Xxh)6)g20y}`oK07tP8HQZx;AB z&YEd7>`5Vwawc3!RY&GheI;(xlBa3x)$GHcL-enzI-|Q9=KBxe@BFOHW)Z9z>5hLX z9L7ALSIVDzrsW1!pnkr9JA2 zjUE(nX<56VWRXodNeSIzRU`vjXc2rhadptGBP-|%N03@bCEO(o%P?(5aBmKA?V+E{d&?nKwf`c`>PJap7uqk#-b3F#iCj9^#M5 z9E*<=$CC~;aTY-lkbqeZ;8@rk62KGp1dqA~sp84>&0c79tc+>!CB}+uP|8&^A>mAI z?yS6kK@~tB=;@b9@kX1Kk|D*)^Kqt(H>?owx3=%`5O^eXP&1NH@)k7{$j59vgvr2S zu2gR4Z>x?!a!q~t>`zS4X2YsMBeuqs$w{Ik{on(?>s`ls{W=K;;;gv&46_L%7R7-c z)z7i*$oqWsGf&H1KUkj{XO199U=WeCiuOE%eEbkabpScwwCWT{)Fpoy=uhF@O{alY zY#gA{6>bY{?g{>;P=8WBNH>4O-ZPU?#X5F;<025Ziz6M+8*Njx^UCwb>-%)?tLa!; z-ZZ%R9;}Rr$CeZPNO)x*ZS{W*N4HrE;l-qCIHwL&F`=3VB^aP!Rgi=3XfWfqZ?{oR z@5|m81Pi11k zmiT-4JRk4Hf;z%{JCrBImN&hzNOl$?sP3h{#E?x_->o;oIWOfy3rbP(*49BNV$la4 zkzmj@Onx~8bJDn~c}`*1U$ts3GnAzt73nhgKgNP=c8PS~5TwyTEb}~Ti!`JehUK~- z5>=QQ4bSE4tRD~0;S9`eV*w6G!^e(1+*j0CK0*aUE5-^7Dp)qsLA2l+J!!ry@ZLX+ z{5JY_M*L}{0&GdRFN;3YwU0j6wSYW>`}LYb{>!Z$Hz{%-Q%F_joWtZZvnQ#eZKZ8W zv}){6u_o9ag69Vb8j*f6wtP<=sN&lACc&AGkq_q6zGu@5FTZffjGk410_&0}SqpVy zx(Sh;fHfF&tgNPdoUCaV4dff6&PMcePh624@?*vx7HA1j zqjA{QK=lHogwJrf3L*K8XT z_(H3ioA@m^LV+~Mp~G0>jbo%TEh&~x`^A5WdE>Kg9{qcnr6hh)#7(P*kYtWLbX4@c zo_OpF6T#-sbJkhlUl=wvqb?S`ESVXiFtEwxt4%!}tbh&#sylZLu#e0^>qWwd`9A{*Lviv;RwJ!`qoe2%9>8td)(L{E*kwM#Dz}D6t#PRNH zHt`9MBVWVTnc~O8)?rnh{I)3^z>&xRvXIJHacj7WHPfGoGXDVZKk*wYCmJ^zUVJGg zW+;znng=$_ordJ)f&T!7l-E*f-XF%rZAr4`l3f!cYi7I&XBT>d7NHM3?I9W0+y?i) zoT$@c4Ylyte;&GPYHkfP8ucA=OIXrLD4k?vX%u>pVHdo8ibzH>P;)u%`^75sKDT+lGQ!NTAZu`+m7mkap-fa03|e(JX5^6zMA`=Ea;gMll;gM>2vMFfN6G z?d?=P0>W-7lx}8tt};cPY!3jlmmPeT95>B!}2{My|1SU?O1x|k^caSqP?sP zj6dagdWWguiNtwFG~}6-IHC{bR0q`g7O_1Yd=nIv;JC4T$uf1|T@~XkL9}dTv~}(vut+9J7uV7Hy@C8{=;474gS= zeemNdx)}g2Ub~K(;Zd+_jp(No3;24&^DQpw>9Uas2 z+B|YG(nx27D(!0X1afh_DCdU>e`znQcNS8^HnyZT{7Y@WXtzIBX_DubaZQ@zv>2Hd ztf8X%d8J7JRX{^-rsDk}e^S4Gq44&<8fB)BsX)8(*&i1vkO7q2c~{ygB=jB)8{^{3 z!Xei5_@kyGTdKsEntZX!^DZ2~gMiz+06DJX z9;3w?)T>g0*A5a}BTXcUu)LB*rc;e+dtB46W${{X{nCYsScd}U|GQcEK`-{IIDn%OLm>I8}hp&Cz#Ftlt)Gj%fBem+!? zV{OQZ{M>byc~K!AkjmgGAZ_QG@75MRh^W?7A9G?p500KY)`lE_V_{4l6lwDGO?6gg zjOAw>ozMA&ysA`tizt?Tx$2gK;WL@zElVKc;)y0W@t|O((om#sVh<`ZzXiJvruN{dmFDHY9&pgAPKfnhkF^No<+1uL$O8KEI_aiPWqIPWNJ%`fJf3{!yX(m-wvrju=@fiAB8<{eKomi z#C5;$QdooBOTHn-hJ8C)k1atTLpw${Z6aY1F>SI2?ch-PJt6-936&SbzBtuji*M5D zSeUTQ#}XL8HNdMb2_k{pe49Nwc)omO(KT7JqLx_YU6}g-{{Vc_FP2UA18FDUjydQD zgY*I6-{HnQg=9>>6Y4LMl3jsu2bwl5(DvA%{1frltD-YIt;;FLDC>H$2!<&(WGh3D zkdwoZ#&U&mrGzA9li$EvoWt5Amj0IBm;h;8xqz;~D6gA;j;;-6d~HE60TAXz3&@fM+`&fW1d1!qnZ3bR^O=C%ELqrBZ78lbMVB8J zDiRTyK~W;LgJZVtSYOE=-B|u1V#JuO=xL6jwcbT*E{LQW`Le^c3ci5<01k_v1MAp% zY<$c=H3N_a(vw6%JW(4YQ+@evjMlkpFYrrP^`i*NVT>V`v(5~8o|hDUm`CgPc*Q7IGs^h%+lRpnk=}=>{(<0PameXn|<3hiU9t-XS%DZzDTj% zI_h?qzxGk`!z{FK33!e*#)C3AB**iVd9gB;WF+^maDF~`__6*x#+OIcH2(k+Xt?Jm z5tZT8(OQ}~LvIWPau&%0zu3_o5AeQR+OOAPY7wkcrdz=YE-GXK$m6!w6bpU7UYzt@ zO|=XeaIzQ)SqxJKPEY(m1K;1h-|N?(#rG=qqGW5tY(Dd`O9;^DP>f`WGM^oj&Bo3` z>qL;rwDbBE1b(1&zlyWq__G5RY}YVh;w(@no#>i2l664B>%5c+=F0uLy{+i^nlwMl zp)=-bSo0i|$wnqjWws!ra(07FwAi)yU;eZ{% z=EuPv!h}Vu%q7!v@pD%PR>OGm@g~RG8aCY4mDsM*z^@>R2c>J^D%7Es*CW$+m>bbM zp~cP6uhI#mE|smEye0ntW6HK<1P>{I9D(q7{m(%3{{RsG0QF-~z}4LnPc>u5pKp{_ zQRzef01J>oR`=r19Wr=7#PE3ELB-XR3Gp%=s7^igK!0&2*2v<%zuudeLDL@PSASuL@s+^vtoD0ntfHE zmU)zF7)DPkxK2R~jF-x~istC{zPN_)YM)>A!9dVmi(| zE8_|9b7Rx>oRp48$XN26@Ima3Zq*Sip-f?$lPh8?m0ZX`z0`JzMf(B4 z;>!2sMc@h*ewkabtM;7^&U}vD)+y6bxXM}E_XWmQ7B+q)`gW~~axn4`!#rVkd)R%a zi&6mx*stHAx+X?ulaqs`c#Tmdd0q`aH5&2rQElVf$=fkfMH;Xi4#0F~b0#$Dk21FF zAs7oSU(@$B$UoG-an!8uJpj>i&UQe8 zXdV)oZv&OyRzpR%6(i7WcE5r+BciFPM=maIKFMXs#f+oOpdj;u0)bC9+gk3p=jW{K zWkv@FGG$^P46TeO$eOm69(-~d0?1I~ zN#HH%l>qqMsNjBAq6XF-Fl5A89z|7=)OwWm zk!Xfr+*s=`5Z6-gjh>_PZ%88cS`^54bnR4I9zh7j$p!J@y_70wdE^%NTmJymJ&(6j z`NkcoF^wW+K3wGO3P9uZKK}q6UEUmSKnj{7{ts{0z4SXTC+UcgK(n$n6p=v;52S(( zf~*Z+++Rvmsd)m(^x)X8G5krR>JdeYjjCbF$gUS@B@HnH)CF))aC)=&xN!yrWX0R~ zflZYC#})fg`*g41zYNdeZv?)Hq(->->#AkswE3`Rk0%yPylkmf0ox}eC$x3_f9?W_9zkLfR6@{h1LFR@~@k*sZ ztL`xLW{{XVL=2AFPJ^ujA_WuB#bxK`5RZ(HdmRBii{CS9XSYhnL zu-bk;{anq(%Sa@X8z2pUD4FBltUe@Fw=ikBEA%&DD@d5k0r+po37XTl+{=3 z)yd|^K^#6*tgt7U^${Ssl%D5l+|~LTv(Hs>*B4mEb9-Jk5)i<|@v!&#Mj!WMp_uUJ zVTmee^$40qXfev|BItwWsjzOrDk_KsS6OTV2$(yM$F&JZXGQ;@r$PF;248H*T zkFo2>EtnXlW{e7S{-8no@@wGp`t?G6TNWwil3C}{vLDqvlY&v7zb*#P*?{lWsWb4? zPoF1H+cL&b3Gv3|Rb$C&x&!UUJl9k-ov>@wmjbNDauJ?bU0jd_I+CZKX1fQse~!G1 zS=bSBqI@=M*!8_h=iG7+9f<4bnWTxI21LkBmah!Kh+nzve{Q)>iT?Ga9@0GzzxkHA)bi3J4FtvB1t5U zvrjbgO0-3m3;_4a*uI92qd;w05~E3VF*IAn#JZ z`r3i8ybI)>-B!|c)y8~tAbgCcTAq2OF77FIDc}gzMbe4`yt zKA76xWDY*7D3kOUt;h>3!j1N zpd^6O4_4a%^F}>4!}3PZCUj}1;YOfiFVmmHO6-u<=0EW;00G!_>^_t9tS%Luy;o*& z(rxW>PT)^Fkgzeh+ST3Jv_MrfJsw$dvL~Kd^<7IaUQT969&D(;mXvy8iEq-10;ud5 zlEt**{RRxvEj;^JA|SSD0{T@J?{Pau^T@HsU_s>g<4(iW*G2H=E9L5qDx9Tu7mFSL z0KCXydl`WAM|+r%XehqBn+4NC$J6{(^!koOIHU1~*yV#fs|J*iDA03UUC{uZweb}y zynz{7c4%Nnmf(=5O|6nlmCmECjUz)zb6*}kMm%CNRU{ zyxiSNG2y7=Yzt4U%9|XGps8byi1hDv;iOWrjjL8qS3E^Fp_zx1l-QEuWkHLH=H}x_ zWLXhe)60xG^d%}1SeXeV_9oJNL8<3zlVs!IY7xb+>WmoV%mb`sFx@1NR!vnZ3oH}` zZ*OPxkEGCLBVMo&HUm43z&0Hu$E+}0^!Z4Y1&qFz9^Zn z;>X80_PI>>>E-!9h}+7fU^kmZ2qmlmYuYxJx(0je-ZPMEJ~Ya?A&nc%k55y`3dgZ0 zyoc7_!n@Vhw5Z_LGj+{L^5WEWc-Xm`YsmU#Bnaxp#UVi^?DM&WmFm`up--#F6w%{( zI4(D?;k8KTk=dLYKjBs&kQ@TQrI>mYyGo9Rop_zYhXJfys&^|qCFvR+%I%)cRGTh3$P&U~%o&zf%%f*fV0MZWb30fSuvSH!J zFu7rkz>MP{K3Xb*%v6EJ@mvM4O^Y2#uITgs0O7X8m<)|BY)K~6qsEnlnXv8Lm=VY* zraOQ0rLfO?K>S12MOxIFOIf$5_3KnH$JIAUJ}&e8btGOM@J2|3L4}p`^|V4FWGZ4O z9QSfmNgQlFDuLJ%(h?YOVUI%7p~1s|V`5`L9yT%s_6@@E$!}Vz_XKrsEqsh@=5rn# zxhRd2S8A$Qt)jgl1Zq)0^wC-u(r1Y^onr~GlSNOYn^eq?6Hc0Ja#gadw&V@Vd24M{ zKqOf=T{A+Q3&fOcz;{8iH;4Q~j&B#>XnHEE~ln>42wQ?(?@#Lq`7~B<|+2JxdExn5! zzxudgf7NPz`dH7xm0^}lreTRRs$$8CBfB0@QR0zLxmKbGH$YJ~M@RH+Q8h^?Oz|9f zcyUQ4U_rV!Pb$^p?Q3si+%1mkE9sdtFpZldt(|DRe30quuC}kCpCTw{!`M({NEDAP z42l4@KuN#;i(SoQuZy)Xy2MS`+m9FHaENTF@g#~D*5GOR?A@<%V&*|2+% zGiuVN+Q%>u;BV!BEqEqry~dr5!U33a5<+zhku<3B9X~2KHU&jh9$WjVO^iztcT;{| z0lR@LdC30&TO^9nu0Y6%6c$3;$Z)>vVNHA6b?&jIf|I5@#kN>g5?!E$&x1|3%wQ%TbG4F?cp#g7zGWkm3VXUFr1QyVbcB~S~g28~fCb#xaM zPLHl(LmcGHsRYe8m$g|6lfXQNj)5ckfg`xFp4_<5PJ|O^ff)jK8_aJ~3P3BRW0 zM|NOmHwUh_?^U%N`M-yn?xm|VuG&7MlNJW9%N<0ds;)kG3OHpxiEHyLmIa0DOMFa} zk|ab%lNL2eRt8rpPqSAAYn%7{!oee~=UCUYoqtTv((=G$)b(uKTuCI0%!sH+WtBN6 zZBv8Vf`{yS2y^nkhf(P%sK_-90~SPw8#6Xj=iwm%(hRbPY>0A;AVB6+%on1ynV!BUU~shaxP5PdrByY8oP-$sD`+ zOZ>Dz{KNCD9t{qbHO)>PO%5~TK=?}bB-7`HVubF*Ri zPf&GWa=crwHELiNAzCv{1co$!EXP2|OF2?K6v!xZeb$Et(rm_y8y6_1JIS$PGQXD_ zIAUL8b~2SvRcsa@S7X+6x{SUOfi#U$c9X+0zm=rt%1a$KLO}Xy{mgaw9R5>RV!G31 z$-|u!A5nuJFB(Y7%a4#&XyuLF3ahER9qW&i?PpsLjAeRx2!q!|Br9RvN%?`0hU(fv zYbrHOK1sCi5aGolhbmIpEC}U7EbVo0FR*6-({#U=;e9W~gX`N8OdU@t0%R1GlVss} zTIY`BH4w@N#~LOMkuENq1UQ*_IhfH#!xeH}rhItIZV-tLxk3FQuV~x>t~wE@Y9mj~ z#ax)Cf;k*{a+tix%7g10lo}%LkG0oMGNoKAgPUM>j5)eO-Lmivan^;P;~x^}vgN^%EV)QaEDoDpqvLT__a?7zAW))r9-MK^ zGs88Ee5^NXogG$Kyu{$RQfqMKSbM3j()|AbLxG^D@=QoD#+>2df+{iX1cy~W19s}* z(Cx=hVzFlvOD#dA?XN?wHe?4&by;qy;mkaynKH2CgC`A3Fn3s;wg3vNs)PA?3T)A_ zV$Vxj^24AeG%@CG!N@WgAe9<=Wm8OrMTH{4^+7^#6FZdb2rp@9oxcV zBV0%}ST>WDr)imax&9c)`dp`l)_1{ek}47lFy0EfTK@o2o)~r_#M;!&;(an)%-l58 z^$chcG4k z6dj8T^$-YJ>2E&+I~7A}P$c9=COOb;-LuolWu%nuUd#M{JqqGWK-@qh^m$*w zR6XsmD~}KV06T{zW}6CKTLTT6F*Fi{$bnkGS5R%eh_GvqZaSx%;w*uWlcnWFh-Q$e zW0oBq_J#^Vy8x$Y?mfw>=$0OHnT!%+4MS~4#x^M+9>8BDeYqVFz|i!J**v^pk(k?Q zf_Mceq6wqL_p24triE_LEhow28@XQFNjs3Uv^rkZoCktM-0UG>)vquNkT`D8_H!nY!U$gjz_h{d@F>{{V(H2$ys-BYOr(ixNI81O2*zAk4uf<1!Re zPPb$bFM_B0U&!e6t5l#zZA{0SquAPmy5+DeSQEvPBY!B1^JN(;xYJN(DcoIhz@B=y z^qG4^Y+}nRe~3L!hNxH!o4b#0vV-Djv008DRI#&Ak~)|WKo@OB`5d2qdT-Hxh`3V< z*Ai8n%62qJ<~^h+0?6Df-H*8ILY_Me`!&(#kbWAgM1d%)E~$w!4Ob~LVJrui362|3 zd8p+V+t?G(9Yr%kr`2O7?<)NTV_`)8b)n4xWCA(h^nNcE==s?(U}0plO)RRAiAR|m zxf}pk3;6Baj=9w}JvR$G0!>aRcWE-K;~494Qb{ooEVAyVsy^elMRjQ(c45s$Jk2+3 zcqKe{nF7>uLn3m4sjatr@nj12`*hKz&pxw@H;NjC!QFifkclK-gLW9s;Gt9#)08aas_nT zJP<>@rGcQfuw;x=8u=7@f=T0tYa*9h4a*c1ERN^rtG5j1OuGIb+V0)X(PnaK*_iUN zQH_rnC(4-*m*xOXI4mx%yYtZ;O-Z!lT85_6(&-ryUT2?GdA~?fO$C8Hh z0b9Ro0`IqCPi}_mc+g{Jq*!62gexcv=X)LO3$Q%%U5`IKEb!_?G2~xl9qOPp{ooRx zieYSA_jLk2>IA^8ej?hpU?>JsD128n*U?-ma1^*>12jZ!CE6*x#i}>?eBc29@;IZ@ z4~wV%Yo|$-7AlV}R5=swrt{@SE~Iy0S~9@<62SNAHU|2AK{BHrXVbWy!`LpUH!%6V zfUjOh7RIGcJBU zD#-HASmVmk?I{|N!iCt}z59-pbrm>RuL4Qm;@1n{P^j4VnmOe~azX=0-L&+3y~bBz#v3Bn8+b6d)1_`!$Y5bl0MI z0xfUD!zUI@{9MtHo?_;GJP^)|JueK6>TgSOw_BILBE4gAtiv!?CIOC*Lz>Jqvy#O; z8OfZWViA(%z*I)2CjS6xKK*#otKlYAM0s#x5=2DE5lH}F>U~Sc+I$ZI-{9p+M%W`Tw0=z z+!X{@JrSQ??WzXSqFuhoi0pKK_kY122tu112=9qlSaTE=J@vN zWzGC1n+e_Eb_ndrOTkv-iUd;s0H?o9n7$6d$it6044P&O5h`Jrh*kidvg})8^xe$` z70*2sIQWS8_|f@u7;Dmw)@w})|qMR zu1RylLk}xHPdh4kCxSma>9F7u$jF}KW7wna+yHpztriV;NW{Z^dMK5kP9xMZrvlS? zS79UF(<%Ib@JD;=IPtDdM~9+FaB|-p5@cffd>G3dK?&PTsy$qr^_C>jrLMCK$?`R= zN?eH*@@8o_KKCb|l5UgiKd|X6U(^2p@-;hGIsx6gcFlR86wMbJZH27(&-k5@tHYZI zhrB|#a25z37ZtbV)M~NVZQ}QHbIaxEz>tV+vZvn!x zmH_YxC+*cuH%Ckq6XfIwU8`r}6x>0v>NnW?eY7 z;%S(}7ZxEFK5Q7sNR~uW1CzQi*-93!;z~UINpC6y6e^13Ao(A0m4o7&$WeJ58y&8>lrCL~wdF zI&^6;7hkTrmBhKk>{WG5dT8R#ixx0tf>$0?0p?_CEJFjeRDeLP<9M;pRrQT8BUqCg z>T^KB4(%o|1^qyR2j=By4^vqr@C9}5E{msV=uk$hD$3Iqea*Gn_cgI6wf8@%J^GVB zSI5VNVTnZ2sWJqQzdrmQ&;$OxE=!#8+0Na0DVDXSQ7j0dS811Q^9HXiV^hAWi64{- z_8%Qdm#=wg3+p+_i2x(;)Nb4bSPG(taA;qClQVUkmR5={LIm3C2#;ytn*;A-p8e~p z&|wyUNt+r2zRZm)Zkbd76j|g7G(hD0@m*Q8Km##CH6)ltbLYlP{Hb+lXH)daI^$UL zBm~)4Zps3v1uo6|*Gt)XQs>IjOuQOF8i1-4000%h04k53K6>IwWFyU*O^P_(AqChD z7xgrI^>LmGnY*kAuY>Y*yj-bU zRGS_Qi{Av(MoL01j@9>WMPF`t>620M9-pVAt)yf}32#i9B#9GfakY9zbIrG)cNyhU@0L4|D#19bC|KN%lpV;<%;Kai$3P`b1F=u9SA& zHt$R+&tuQG+owGb!kTA>S>(i-=hfO4kLs5906`oj@J}Og3N& zyee-kV%SLixa04AtE@_x?EUG1)#BfXI)a*QAlm?gX!zmYd34Pu8%~}%l01BecF1s} zn`R&`;m+Nh19sQb9zKtQrsSqt!z9^_`6OlYW|57Pu}=zr;`aM>d2uE+9y*je0Z77t z5R-R6*X%w0&q^LE)nJ(>({%jV7BmcXOvsr==+u9>S3i_;H#Y-{8@a6B+NLt6WX(Su zVh3I**;`CzcB(CF#9EeQ@@e{0W5X4JK14Ds%NtiQt9ExD=dkQPO*~Msgp--t_V02@ zkozk8w?6&4r>0^{ndPi-$Bm53x(ElQ5<2eQd~FwxzzjLNGK4Ml7E z_HZuwB>bL?T3Xo(jT_K+$;H-kau*pUkIR>1W=%D#0m(7KzN6exBroe-GilhkIy^pp zoMeJ|BM8$;#H=rnNbC>5`S(2xO%3!_$Hd0Y4D78YOAw3x^7Hc_PV|D1Wk$87;juJCF~xd-O__ zSjI>_d8!8zRd`^D(m5IAnka07=G0Y-3)oQ~e{On#b zHQB0OJ%}8E&qN)*z6Fve7Xaran^T5CD()Od3jgcZOaHKGYAsJ&E-oO|0 zbO#@A*Q84Wq;wGhBI&+Q3ye)z=HcrZS(CIvGdRN;GCLAUlrwErBoIC50bN+d@a{@v zNs@Cl4?cBNc``FdZJ^j2Bj9uGXTMf3JZq-Q8Z6l_jLHJ}Y$TP%ao8dL_tl5-ew0-_ zsdFaYq1B_pkODq;Fao~!)>mNhV$z(>HWl7BfgCL%-pZ_RWL}Ft_SRVc0Di4OrQ_ot zG8mN`ZEqa0{rjKq(B|ccWv^a3QpIFT+dPdm*X0G;qxF0>)X8RH(C1X$g`9F933<fbTOtnN1C$8N91{sPy`nIs0S6_o8z_h1}}m1eSa!Q zr_7T#90itKsEJ&7M%g3?yz#X|@M?zw?)rS3j3%Xrq7xaI*x%JxZxeWPOU9GU*RWM_ zn6H_e^o1ObMIOMD&wj1_POG1eXVSE6jA)zGa<$yArcJlpLYt)ISAD&Cr+5Ry zSs3{Gj4cis5}zVBNnglt;BJ*aEBZ(x%^jzkyCnG;O_1?Rm-X$u6fH_0fNfAPv3&FI z@7FgILR<^3HQ22BSzv)PzxDY+bkLAx%Lb|A3{68V7?X*E5FSTAl$GB6cJ*yMbJ5eL zVr53q?+D%iOq0tY;8j3^_Ya8ClyS}e(yK$+`mSlsI!a0uD(Z-?g#=I9!0 zZZt%gF{$^e^!>W4k^DaJ(nlf3@W!0Z0cBRlCwFp10d@Ly!J9S|M2>mhG(}kCYIz*? z+|9P{?|sio`ktE%vU!i6o@Wdgsnn)s5~^qn$%%r6LN z*^e0&3gXPt9!MZ60#6if)OY)IHa`qw%ZjJ}00Lu)nH{%7hax3{03Nm7WD-SkYumq8 zu=VVW9B-z^b%YQ?&5xAkYrD3QiDP}MkJNRap^JQM!_ zJL9f2Lu7&IjM}aO2|m9nyJ)}6bj*Dl#GV?*Se!Iiv*R#^TtEms17OFwgA}25TZ4TL z9st13)1`w6lxo=VJ1WVPkGhaExa}NtgfSfOD}s7s(_@DPOc7~VxiE(FBS?`Ucac=n zmZL>)kJh>&nTrOg1dprZjHQ_k!zdE0M3M@vRECE#l)Hzr^Uy`$(Bha%G2^h5~YQt00p%Lc~;v*lVqCddTzwifNv3F z14+^e_TUp)={W1}`2h#gb?s*c2qDa!;?t94hz=|g79|_Y21TMhMMV#vQ3m>}qMr2TH^U57jTp1*cnHEq<|Hgi$PqC&)5D zRNX7Oif^+DBfmYmxs1_EtCKA5anTbVUA5-BaA>aLLa|jf>Hx1Cj+?a1$>X@!C1*$v z4y>j|3<Gj6ixU@En<2EWL}@%*=_1vc6OlB94Ki|4- zn1)sEyK2+$GIXC1Mln1&uVrLBDg~paQl&5DG&e6KRr-DpR<$iH5-_Jvo;gSgWPzEl z{vrsl56CV#>jlxZ`1H&-O)m&fs6mnDE=(@b%@EyOI11#GTybEVQ{3#H3H~s{l?&r* z(mp;^lB8$qTnF8JwW@$Y=Z&_!*sil0D^tBArpb}}@e1`RG>-83U9J{pBy&NHILLxk zJMs4&(*+-vx#V*|{1JaD+6RL&;m^lSYevb;ca_o^V?`41>;~w_1dthQ51aPuZH6S) zF@Cd5*$Ha`U#Ce)QS3-QtFG1vvBh;Jp$aZ8#|+ers5TX#!SF3R34@ZC!MK5hvTzU9mKORqjUWq4~`o>;ZGXK65_%Ow3oOsl>mcJ4z4 zZN2HN4i8FtMzk}7WNEXQH5_&!vBWi<4m3{Jeq)+G@v4de(#g0EmQZ^%LSxhrJgiQ)@}R z8Au@TP!nZOrG<`^twNqDfS&h_zh8owr%}|20?O*;jH8hc)yy9rP>l<@4GmD*RExg< z0Dfrm)GdZ{{-aLGX?~fYGO-i2ZW0Z(-iRXq06|@5c#>+GMsZ0narEqhrz7c`aaKi+ z_Ny`AlV@Xlo*SODEgM?I)bbbUrd)d_5Uz*J5_`r${X35T0J!TsV1+7;ku5%*9w@!B za5uU`@wbLzY`oBuq z1Kx)x^cJV1E~%yDVPq93%E4p++LCO2=o&T;w^=r=rpJqu{J+Ez1A<`l#)RzR~tjlViVIVf@J?wPhsK*GKbPz*a2q7e4#U7QHiHYLeNhH&nS7ERf+qptC z&_B4Xr)~cL!o#8ZmYb2`eNAF~gqjJX^YJoKiCN)hrE&3Od;U{k_UWrs(GlW&T#&fg z2`r{rBrUclShsm5D+(-y^$Key?yIW$elACdJT`P$kQuNY=F??n+;Pp1HWU6NWjpr# zS?_h8Lzr`pwdS4<2E{S>Z&+NIv7ddFAtg{L(XNQEkMGo2`sC1RxcQkY5t<^fWTru+ zV7tI;_YQ>qgmLZCevg?x46YV0E^Jn1pB+Hn%fNIe`nJ~PKLj6si)txagkm{k`b@$d zT!L2G`+?j7Nul%8>|-i|PSBMgvCtNarR49%MGnSQi0x+^Sgp}Dd=ScS_xb2|h%^za zX*oJ(D#sj)weiRsb~rnQ6Wi1Q=eQ#KbOT4%pB_wT$Db~n6wX8i%eVx+`iQ-@cMzll z&GXX+o2$c-lN^DbJZa{9SXqs!F`83Hk-1oX?RrJbb6#5EW4EolRkRtKs7f9m*Bk1- zr%=a_OLtEvB^?Y&6QzK_1Nw{o{rc1K*C$8EgH??ZOjwXHW;S-7JhSczs|L28o_fxF zLxf}T7DgijEIOnL`y?mO!Ku_&UrKQZX*!+5|wn@ zN3h)>A-|-P?R`Z_btb!Rhm06Mu8J#K9OE5I{XM2+DO5~T3&Avs@uYFl2;6Stjl2Lz z;8*F@O=C}CpAK7OOt_Aw8Q?AWNZhi^xBNtar`U@g{VaGJTF1@O5;Kt^m}8Dc-kd5m zl`3wXZowjmvJG_Xo>oQ)gDIqqgg#V`;kJXw1T%0?7tNmCWjUEiVcF0rfM)4u8g<0f z@n1c{L6Ficp|Qgd?xk8X1zGiqVh^OR!RZrPG5A@2yBh*|r-mT%LbDWuDlS;svXZQX zZUI2tF8Nb$TBbBILq0l~u@&zcNZIXt^3@!w>@2O2gmP)YKbNIlZYgyQ6M8`tIbplj=eQnEXCo*U3&c_nBz(CQ~v;nbzJ`d3~Tc~9tPb%P^qx|qxdsQk59c< z@;>uSEK-m_BwtN}EZH>mn^VG;Jn3Upoo3nt(C!NGY;m}HPSI7!>fHKdTK@otu-_{V zT#PwlUnv&RqIE6*0LvkE(=ZozWZx7*yzvhVVdZCL#i-=G#bKF~A(>)}X&d%88cO%p7# z>}04|QRmz`@KeAzNFCb|-6BvUa8&iwo`vIyhOUdG7Pj9ef7O-l{uH?I7wEnAK#)bcwfxPf0!f zzvajI^ebPnsKb{Q$-<}siqh^{Dj0lr`1k0*0vY_WH^&)O4|TdT`A_U@bMf}-Jxd5> zY5B0c+gcI15thg0ety;5x7+mToI`t@kg1%nloJKaT7-F+`;36B#Sis|Ve#Im^zo>` zrWs^aVjp~hxFt%{FVA%+^*t=41Zdc9>I!4H#(L~G4o#1SzJC2Mu5ioIqR9^Kz@LND zo}UsOBNduh(`vGy*@j(aaYg`p++7)N{iv8?VjKF;p8(u3#_>$6aq#aXGU>WQYPL!4}ZUrDH%? zZemvBrSJJ{9((5)Krp#kVKqPkKkxgFsQ9!-**;oI z<15PyBW0zKFe7Uocwxc#zuTbt&Lr7G1NlQw6!^029%J%ga@>YC3ac6m>=$p`#H|s` z%v@;(YOdcYpCzPbi~y!U7+7nuLxb(#tV|n5Bviqu?C#EOy@GVs^8QFe-t4 zzdRK$3FT$tYg&FxxwGNv{{U3%bm_JP>5%Y4}VQIF$;RnRwdU$t<)>4|^ML+Wj>XRfVjc^LE=wx9V>IOr*(a1=|W_ zf;n{9)ny_{x2fF(V`Qw&Mbv*zNtC`W-tWJe*vNW}Yc_?hd=S_3qnd&opb^ z&+F3WSBtf0f;b|BA156NS4^ebFQ@XbbUSN{NMSF<+0R9uK;Itk*L&c5jRIP9d0}Z{z2jtA4Sg0iDWXVp<$HKWi{A0 zdm#Mv)>n~&UOg96#?&LW^5A{0wrtSd$ou{O0Dgr=&`FanG;>EJj9J*EypzS<{+~D1 zyle;y%OsLY8+E8sBca6$;-di|#V0G3)HtGaKCW_6Pn3mz>g z9#a&ON2f^>GXcf!t)PM2f#0GVqkuc*Ngg~v0L=0#kNmg50=lIJ7A`hCIFSM(jJD8Z z-M4YGWQqpK{klZfPAg`!$kKT+nn%vbdBouG89|{KEC2*qJn$@ayMp>_skpXdj^B>A z>Kgc#k(gas*YacWF0H2H8DmIHwN1)KuVEPT$=a;M{5Kya=9#KwN2cM%^9@ctJ~N4@ zPBEQbm(3+h3gLKDW13&J^bZdTePVdh2wr7%Du}?TEKM07+zJ2z-oIK7xH>QXA2@Sr zQjKF>mCSLxaI6WB4RabT(x%bsa(6c*kPhCqF?2FDjiO+WXzSe}LZNYco`TP-ybxp= z0>zasBcWK-IcYq=izy(I5EAD2HY&$PG`twJJt?vBWpgHWYwCH0*i=xem5MQ31p!!| z{Mq*%5Ahqep_I|b6mnr@Vlu|eNMIPQ`CE`e9_0Y%axZr3%n{>aW62cb&N2Y3k}%yb zs_Wn_{$tox4zqAH4I=64G)z@+AVRCCgwE7vgCZc%41MylzQV(3*qgt@%QwXymvfW( zCYP6#AjimTRP`eIl2>8{izL@P{E>g77M&(ON@|%|B2_b(!(@*{ZMj^csZnFxkz4}2 z^U}Vj7uRIPi4cD#MV@JqeIiFxVoB%ngYC#95013(L6vK{$L$1fx=OQ)SsO~Lra_UD zI1y=y9Dy9U81cZetF`it>Y>2g2`m@500LhmWQ{&Yov_j;1r*NYF;q~_8i#Yd@GINn zsC+hp52wdme0Yni1|)@-Ag?=_y8-T8o&f!XQe>R$iDhV^nI3e+!j!}1N{K;S@jMM?GI<(o517JclQ9)bFa?Q5AwvF^D14jv z>2FbzJb4mg#H@1pfP>z)mHz-SRncD)&ysO;NaOq@$;}cg@7hsTDH@5cXuSbSKZ<}`3(AY26S>|M-d_XzcXWQ+&zOg1pfe^eQeEs z8v8o-MFePi=%z0b<)Uc#d8r|Ve8deZ6#;=|3T?Q))$PFOj)@t^zyao2hURGl@TyBU z;wAR`k7LN-o~P5|Z7)?#JzX&;hE~N%GBK8A$0fFh+T0qYAp3L=U2Q`HDs7qAI*v=0 z4Gu9#LNbK`_OGG$24V`(+z%Ek=e@<1a_`fq{P<|0fH{`fi^}gN0ghP|COomsjOnuy`sewC1kXLYG9I5=llWyVeD35;qx=UdxN#o57utvH4gfAv5J@p8(vtQUd620>o~k^uRk^P5`=`t*+Rvwtol*U3RQMI3EBvuV0;aufnCYz7gW<_jpaE(Lk9BH zMiqp9jmnj0b*R6!8|J##b-Z@S4)Up%V4sLjcUu6EdE|P3`X%WzHavLXjx5v@W6dmJ zvM>~-Tq6VDh9OA4$L-gxp;Q)!=yW}G?v!aQC8bsHZnXx3p89u)+d4fad{O3%X$rYU za>Yf_bV@ajiB=8I8B?l768(1qWWO<45Jk>lmMEp&ks6nFQcy}gfCeWpkMxUw2 zj!fbuD$$=Z$X1M@TH(kfAIeW&a~Vt=QSQjvH}P)Jc^_h%1Z7a`x#_5^c-oExczJFN zu{08Ijg^VCumLB9+uXOSw@h9U@xE39oDD-DTwaJLWiHHw{zeDC+p!-106icivTK@T z83X-?F~Z2M;E@cwi6Vg>hy1{g*q(~xP5jyBk(8!J-L{+A_hJhW*XkbUo{xz7 zb{X_T944N-;&zT3#+y>jsP;U#7%OPQ*5cMi;gh=+CGzqFf|@o21mp`|YCWrmA4s*0-1^kri304FHL%n;R z`%Z!4Ejz^;PCkB@kftnwVFz?-1(Ws%x5527@PApr*T6lbNvFT?e+Txqa8IXMr0C>7 zIt;k7m?lerS((*H9(s^yU-Xb@fRNJaY6i04~vVJ}&uF{{S!7uBJqqKZir;HR?ise%~Y9bz2)zhd&-1gbres zk&;-#uwla^k7Ho{xHZKdxd-VRddyxc;1I;dr{>2a^(2nRq+dbJHtVaVBoM3VxnoGf z#m2}}91x;o$+(MxTCY*4hg`>tk~srx+;x8gUPDpP4mI$o~cO;8Lb-m zd!u-aZ0bSu_bbl~r@bD>p8WJ4O#F`u#kWyYnWCWdN~+Azi{KR&)IEoBTocly#DXLq zy4sA_17oUVWx$=E>E)fhR9ng^BH7?wZGNN4)8?BVK=DVY<4C@so|j?pRPcXdKHXP@ zehgAzNOB;M??Te6VIGVCE2;^3VTC$Ep5C`ku_UcPW`+DWMO}3z` z;g2PLqXSfSjv_q7n3Ir}e=8Ojw~_gQ;CDUx3E~d|e=rg%H`Bl*EZ}1_l=pjv)&v{o zz!iNyOFCxbfFx5O2W|6Q_Tr6o0MvKoW~NF>34zpkn;0X88-pv?BEPZV^z(7Junt!c z0KU=VsN1y&)23E$CYP@&Krp1k&z3nE4puba$P}If$01hWcl925uWp7$G>vX4H0P$Xa}QX?*(OAjtjEm| zWFpF{KPsP4vFTCR`}LH{I8fZLr?*f@KM}Y>Z?&s39J9Q=3&dDath!U_y6g}Z^J2=( zIMXC_1&L4;B+(=g2Oiy4!p6tR88YdS1kOb<IQ>8DNDnJ zF+!u!^@^Z3&u{zq>Zj@WYK95)arOPG993Ab_E9FCrOL)xCG#7xK4PVR=>S*x^<}g? zS=)388t^EQyW@^O@1DF1sN_1A)A2nd+fACMpN`q{{YXUvglEHzEa{C<+}ACZQT67KHUn<)^yE2Z!H;e<`=j`;KvKJ*3gC+%3@yby;W>ICn`PiWao(xv61m{aeyO$05XQNM0+p5 z;B`ONYFL<(KCE$M&5~7U7ikkTdwB#K1;OM{77cVBZxrehgp&bFZEcI?!?F?Hhxnhj z%J%3?x_)-M=ZyU9xsfbS6bH#gyWoYVaq*mKuU4n7bI2+C&}pp6s!IS7TB?{)HfO)Wh)( zE@g&=$FD`iifx1C*Shz`UMj-UrfoK5Ia%{YC5|NIa!9e=i*N|q3Fqz9I!}iq)5(`n z@>e1tTm>J6g&hLStNt&)aeeO3U1%BtX)i3gMjB76ysI3qEdFeR)ok+4LF6wxSBnGy z1)is9pz$P`T23>}`b3CEMrzCDE=f~vksk5`$afxq8myCDJ6jQl`gIZuplv%z;3xCW z$pPBp-<5$QVrZI&j66rE>binW9*8|yu{rY$krVhxzSKb60Q8b~TUCu73{`?CqcLq& zq$|4om7&8E-MAmvdjLA`A{&zll2H~YEjyHEwxrwmV44aAa7Pp?wHl2)nbS)&ksN(8 z1Ln%c>@9=6hvp%U;40YBCcAZkR}o+8wOaBrv7!LnH1Q{C+vc@{Y2hiBjZd%WD;QYI zmeI@-BLbm~3n}1PwjloiK&}C^c6sU_6y-8apy`mSHcn`oc`unG#Dzf@_jy`2W9(AD zr>glLB+~R4;K$7@+1X_><-}SuNUBJ)WCa__AS8jo0?&NQ_=n@XRXg=I$jHppal}~K zRveVuJk9OA_XVY~$BjC92ehz|~FTFBECIMwyeT%c#t&44zDR zSh4w=rZO=|vA1yY0IIDZ^ned1k1 zvRXr4qs3P-=^h@;)$`L;@m!H)YKa+KTzIHsX_40p8lDN-JyIX^710epDLhX;2l6Iq zF(y`6nOAYnQiqiXvI3X6hddG5y7rBuOASoAr(Jb@Gl4EJ-#)thu=pg;o%}_^)C7;M7DddwXz%7ALf{9F?!9r1A_nbsLrX<7EF1a*?tQ{6#ewfY|SN^Okz6Tzuz z>PAL1awOQG?h|9OvofLi1a1TF!2W9*4!eaWZkrr3NKxgPV0nC!#yW_~v_sJRwPbBS z0M({tB-oCAsChYY$fL^$KpZeEr1x4Pk8Vgm9eo4oZ>A}_lMTV2Z_iM?zA!&9dDpver4V<%{COAy4>}sIQ7E?Oj^%uBy6jnU{~KhgFZx^HCAxi~|^H zWd(`ayA*NkLn-A&gvXLC79F`44~KP`bB4bi@uuHMjPJALGO9=5{tj#DG9y5dvnx8z4O zDFm1@;|V01B1$wnViAG!z0W&)5{@gIgDW03f-;O|h%-Jk;P+)`Hb~`p0AI}!*n+i# zpQu4D6uN$++-;DG z9_y1*(*VHNJo8;1m~}S6)7zivbDN&yRDVwK9(I$bN2N4NmlH<@E;P>wEUvRNo;^X0 zy6||aWe0+7VS3|fSFR9e0Hr2d#-a-5gz6u`4_#TJtDP|_2rFgHzGw1DHE<{y< zqUJQ9vF~yK+NQt~bGLf}c86Y%;_49N_=hteR!^+b^}!A%JW~?PfJG;pj^cSP{AfXLT=Hs8Z?OG zxeW`isZ?{gNQ7Kgc~vozNJ3cwm6%#|GwZA!pN>06C5A^)*YuWf8gBz-;b>W;$*0R8 zhXX2lQlRi~=CXZD#>YRW_-y>}MJ_t!VzUSy5O*-LJ6+$s17qL6anw2vGHW|Arh0uPJE;rklSZ;$RaapS*J=y26@uuolexL(PR9$Z|AGU1Ca6Dh<^k2`v0 z9Ncz$8U(9;$EEELS)0L{o;EJ8mS)f!@U-nxaCc&x{{ZV;lkH4+X6vIo z4}u2!`V_>m^4SYV(lxY+-y3NL0=E*Ksz$)T#!q$a&u$M#cM}ikzER3>VZ5_&kw~tf6NdTd`9It9;{{RX2>}q*) z;?EoD+QvCl&cxlkMtz<)x_I0vAd4N3UV{sa6^2@d{dMfJYhleJEzuI!bd3E!Gb35T zY$&po0nEchF~ym-nH>phj&%WmZg+#U*9W6`@*_Z8#FAr4Ok0w>Nc5Hj15N$cqfuqW zo}kW#CyCLJju}{cf$@F17WmJJ=AAx2Jz7sNvt%&bO0Z==;jvxKa65PD_ct$jrh4ml zIZA^%*(_?>OskGQj#-92Jgy->*9dB$*Tbi7f9qv?2R9-a{H%mgJCn9ZR+)(diX&@& z$Mx$-#!Otv(-|67O}~i|LN9fKE1yU#c;}kwN5onbnnbn`$pGL$AHNKn7zZ4y6|qG3 z73|b~udG_n>?*?#7+O@n$jJ;>W*2rtoefM(d}l z#Iij}jgjhE5RU$#!4-Yazg)gjunOTz@*Nr3Sx-LXZd1p<_voG`pmqc@2?T>~*+p5q z_Ti6y-8(}X3!+Hnr-;z{@<6GFaBZ$S)1b2d0225qa5JR5Y4KPE^urTN8Z3rh=c8$r5Z z!vGI7z}GzduIk|epjTlNwtqJy3o5IX_ZyK!%6%**RLG~fMd zl?}F6@LARtxg3yyxsu_eyet_&HDC2CfZuLC$ocC28)M}xc*~g+LR=L80BuGE4-BBq zWPOObu6nPZ{5qQoa^`&e%p&a1oG0AE{{SdxLXw{L!C6HwV0eo~{u*NInG&{-uMCVh z-J^C`B9=l2cL^EXrmu!kUi~#o>V~6dEboH3^aD-Icq4gU62)jFeIHWX0;;qbP$*)n z{ux5oHFiUNx~#q((mY3kgCTyGRmH`NAL=n&MJkAps_q8&3il%T@4%tC-@)$?Vo2Xb zJ}N~jdDy9t&5rXTkSsAxio~DFSa#?xsipXz!KVx2eH0?85}+y{Q@K=(ZpkH#8)s|zlp zhC{aoSc*wkSK5tztElV%bkcDg7Yda??}_4-v7u2eR7|r(K^|m5N`z|wmIv~YN8{SM zH}vm3c$qqmOta65Dmhidak|A5eDic}_y?oP_)}t|>AA|n7mkGMyefhT1Ke}S98v4p zJSekdK15QZO!Ksn&|)^Q4P^HQX9MD ziv4=MCxl}}P_Sdl9f4xX$VWU~k_qS8udC7MLDd7K;6zD9^LDNJR>uSz09QWU5v{64 zz#e~qLX6BCdh<&|SA0Uz;LAQbxdo6~uixDD(&u4sXZmedabw?_`}NLkN?^K0yj9xjZnBpn zQW(%G$qZ0V6&a&v+GJ8e6l;qVM?JY6dp1U7pZ#w2gt+4GB2KDaHUj>uxNmLcL((8XH;=)Iob`Kd+8;sjV~)YH)WJl#T=0AlYZ_HgUxqSxN<7^Bd&8ZW6HseGgcPz=4k z%pjo%4G<{%U2;!ZIJ&gxG#ZBRHf#Cc=i-k|j(P6rs`zKa(fEg3%G1!I;7^Mob0ezy zM(-)LWXWJE`iL&2jTw_wU!~Py8C*3(3dSaWL_6KMC!i zm&y(bnD$eG#O))!f?M@HetOg(g)uUshk5cGeLnF`u$nu+;@e-`_2%()J6eLM(2IB; zj>VydfWqCQ@}!DI$&fI=rqr?IR*bPGDHI6Y0#6_j8-jhPdv#X>Bph&(DJ~yli>k5P z`|lsys?f_MF=0nAA{gd#$S8jkU_94v!vuc)cMMO7n!{)^f_7~--e4e)?o`+QZkCH8 z%sFj-0?X31>{ZjXY;%{Cfn>&>JYOxbL~+RemsSK^p)9Z~Lx4T>Eniv7e7RjT$g!Ux z%!|KHXya|hOY)T1AnxFk-FOsu{Q2PA+41w*Ogz@aZ>M0h2)BT=Th&0YUr!}Q?m-vU z>Egc_Pds{lW|=?G#gtS@5=kU+G>r3!42j0(9+GZ=4Pik&J%Eap+f27NJqKHCfrtb& zkYN;u7IUVgy54$XM=Ebf7C&16dsPGN?7z6^R#u~osDG1bGHNoZKaD@Xz3nGzjythE zTENI@w6r5TO_vWQSt40iB8~acp#_K~fi8p!>{yEydSBIiQY4Wf#GL_PrR0%H5N^R; zfT3+a51#WR#Ndub_r7zHl&P06LKvxDB{lUcX8PCC+Pe|l{}{w4L<>=0;P?&IZ^QD z*aP~D{W$2}kNh_>O1V13@;u7MW=P^$EZ+sU1JCS5`}D;}Q(%&L1y+!hTT9h^TPo$` zeLg-I0BuH9LPxTxHc!2h-TVAE>HY~2K&b>{E=|fyM7J7!w;BY|=ig`*c$pWhjdSMo-N0}jzi1}t? zMM3y#AoNosR)-0R)Ko2#v&jrg0p9(``hEHbs(8ySQ^@f43CPHx;Z)KNE}CKrhOR=c z<{%Tm=d7dKJlxuK9C)UHXc{A9P1AIgX*C&P#l=|0_>lso1491*sQrMU$3rLaT$-%U zkELOVG}xsAOpJlF$ck;AH2(ky`Q-Qg$7#4TEYf7^`FOhCqBP;18$0bq!*`?Q(EtMK zqjMhX>^h))MUVBEGU_;wmy();ImL^An~w-tBULViLh=DAZF`N~gVU7g7fY^V-VU?N zY$_K9h|{jOrf72^II?B5zfP0NzF|$wz`Cggm;*{egT+v;$El*9A)?5IL(rCVy}_j@1sUN{&r-Uc-wcj+v_7%$FU6M>*N&26aoarf%zaqCZ`SqCkn6nzH1? z?%U&);oHB9B(;{{j^pzh0QFxpQCRQ->Cr)_##*C87nFqvvdXkKHILu9Jqgq`sPepk z`gz0I5d+Gd10!E2cHOE-{YgE@u5D?W21d6YZ_?#Mg6Sf8vgF~s@`d)1PC}h?rsgxHR?U8`QgQmH;0~7(&zGWWdLR7<~Nxnv_%TwQNF^3)%G1Iok6Ag ztf-|kHsm5~mK&_!7DmuG?4r*Dwe)s}K+IJ#v>8HMAz?KGN9EI0@~5n+B8c}LzftpD zeI7nWL`GYlOo6I>GwDD`*nXGPR+}RK6&z0 zBt=-HZLArZtljooH|@Z?;7)N)%@S3Eb6n`V(XnvCiLxPV{FDu7i zE}tf5V=_V?EnNWHwxW%B^z9zs0DkAHSQ>hnX2B9Pc&yFlN{U_7l@y$RR}>G)_#Hc7 zVn>IDVZ%O45w+Wrp}GAppYL4tla9v<1h5HzqGpXO{q2cgNAR{EpP8Sn>JP(Rgbn`F{nIJC|3rbgx_S@-~LZps1Xhq&)oVDyP) z@kXErojYU0k9m1)s~gA|0p%@nRFveBe=B<)ouP^>Ral`w7VIkbC*=PCZ_socO+Vth zEAH*vhaI!G%F5K;+6fvVTJ)J(Zi|yPoV%xGXiF$(XwiYUQDAQE%Mhdea-1m!ej4E% zG>b*4AdUqGc4W?_OGx9?!54QTfG2@`^{i_?UTzHdQ>?{jjH?K^x+By26W`~afMDsm zc3xa?`Qjnvw0n`ll~m%CR|*OBQU0Ox){oM|OC6h8w_01Rs5Qw1LYo6hnq?4Syg0}a zNof;!ugki>sQ&U%ae zGdMAz-OIfaS%|I)pnD7KOCKfXCTw!ZRh?6U9D+gItZIS(02li4)oggZZ{|dxql$0< zORwo2+P}oz4wV}9PG_C7*AF@MR&&_V0Blt7@CzwvLmk91E;btd2jx;gq1@2tt7XR0 zsM{d})WA_A?e_lw;66-~x<-uI3?oGZzUJV4$^QVq?Z-g%LzR^iG$_zR86AfUPXhU**L7T2lV~#1Z-AAJv5+-DfQ73Az zdI0w}X!UJ8HJucx^^A=u!CRkhqZlP*Q`CyoG0<3~UpTM;b`xRsfQ3)z5LqZ_s|^^gt<93y%VQyZ-=4{rZY*2oe!Csg*W7ENDjTxY2y_0p3s9nEssgLs#(xM7EuyW-OVr zN(0Z9T1AL%04Tl*=YTj`B=R~{&&SM_B$HapD;7G&#!~ko^E&|{;YbGdf}(-yjbmP5 zm_N|`g$4OUfQ{-NA*QokKoL1*^$}l|gAJ+{>{;jr zrK@TBEVE)|=G4)%38KeQD+5$ix%7fNaew8|e4iLaD>G@pVZv*1LS&k|4bN0RLB~CF zt59Pyhx*_2uG&v7oT-@j$1@8GXdVn-KH1hxyl}E6?bPcfGuYfpfmP7GGgXW}M47oc z`IAo|W>{Bf3^}{K#NReg>^c^7{YN)V$JC?Kq@M{P+9f41zo?c4q$77d*k5ojit0QJ zocx&2@|`%UsHJh8vd!{KF$!Ce!1*06D**h?2K){9?kL$Mun)3&$Da;(#HSA@kweXa z*pq)JuTp$$mI}}#EfKx2$sl`yLa+Ysp_*QHuF~w(adGkdsdgXs;>~{`ucZ8Nd-W*I zShkO%%1KJ@c@}3YwB1(iz5DgH$A`ASiQs*bIS4oRM=_*0gsgaytZ7vXV--8SfE?9< z+z<8Y)Eb6N`3MsUrDQDi7!TfxUg!M!6Q|~F)bSfngD*2U%7s+NEaAu^mcjhQ zf$zu9M6nVvo|=SFNX>^lXgsGc2$n;%Z$?wNpH%`+Bkg@FU4@+ib8k5#nzLHdswa)) z$sA0tw7ZoG}*)=+o@MRDBQfcEMas!OSAfBy!?NR!CW+s#&p^%Nv2*4@f^f$4&2< z=R+hdm^`$QIRJ$Tb?UF0QGHm8O^Yi^)iVOzSn|fk_*e*j-@yZJbZ0%}|m zHyubC#~stn8JQknd}$}}lyI{kZ2XK^wEV40Dky8p#E}unJnjUr+y}afKHYfwwjMt7 zn~SSy(y88tOh*ZP@LjmR2lwNmm{|E(5X+7+^EbmKx;t);MI-=Y?dt}^B@O^0`RI;5 zNm(6Tb1~#qAOQm@{{SF=u^li2pWn^lAHPt9;@uT6PJgz$Zs#rh0ewa<(j_Z-jB!k>AEQL%CkcZ84yf%)!Qiz{U*0BHEO`v z{;s>sgA*f8c#Iiv=0!1CT#{ALk4=u~Y(L07s=@1-TeEaH5(5@t21?~L_&JL<2x!(kaTpUvOIN@O0X?>n`A?_k z?5qjkMzAs?3S7#S=~2N9J-xrnw?px>q)QUURd>-1>HyjMbYXl#ycpF=I({E6V z+CMBCrtKqF%VUis=yI|0300kA^5jNd2xK%``w}X>`eHCcJTt)1h7EpXF|Za#HC?P9 z^XXqp)t(G2tagy2$gqel+@lEOX7b1#)R%4=$LZ1hR>9SL_tYbwA61JkJZLc9akxb9 zQW)E_>}MPgQ2zi3=cKCCt%Y$F1c~#Q{GSc_C=^*z?Kl4ZKT4Kffv0Mdrn!kT==!b{ zBW_=nMHLj9o;Kn|6?efN&D*4%H$w3ag`KGDxUlJ&qb`3t>v6HX@e+bg<;V2DC648y zXd2zytru6wlS0(AHlPc2qL&$Y^FQi7mMi zkz{Qm=pOa@S6erRHOaMI6=U%RY$>T@AH*M?H&MtggMz?!Wjx*fxqpeg6Q}sIR+>yG z6Hdv7A z>;bC=w{B6%=_>eA0VA%ra*c_m)ob+fTGm#Z1nZZjW<>r*QZabxtSqTLzfsb-OhKbpf!Ea#h!vv^{zApvqZeShF4#_4$EAfWnx2t5_YY zpU{r8eS5>&riAm!l>-c1SxT-%gaA~z3t*le&44~h9To8Aua7qE?2DVYNfgo{0ojf1 zHhnE!$TZ($&t9MwRRS)QsZP=s{if=YXZU*>9bFeO^43UaEg2hvo&x|1-yqnodr|1J z__rTV!q@ZlS)v$vb3|i?6}e1XDX1|U>4C1?U5+`;w5>u!Lq0mRD?`jf>O(S{0=NgT z9P&pT8tJCx98`=rjLUKJM4hZQ}Uc$%vJlvfc zcs#YhX{Pc4^pf!_MBobyH*VzG2HQYY7Y~RP38sJA-gfIxJvyx-(U@#nABOb5j;Z*&MmczLONOkotTG~+?5*85dtF#Q#=iX~_*2Aj zLd}n=#Vm!ST!^Gb^Cn494XjXB`%*=(BwqxI>rIYE%*Q~gB!!EXB;MO^LHpYL*H^C6 z!4A}Dt4-Oi789px6(hzxnc4|#qeN9)DY6(oOU66Z$@yh0bs~sC( z({p6}97yD>h@ zG2nrlA80BSNnProZYG#+H)M0SqB=eb>POCnzuM!FGrUAbS(BBKPhiTvpnfbK3F+&{ zdPXz-HlYltFsH|pAL_R#08c3~u{HTYZvNr<_v<9nH5}~|KPMGsiX4ntr1Dls)s`tq z+FqO9fdC)VvE=Lp^m2%hp~Jks@t&JLpQ>W(m{kOY>Sc~PK9Sc+0|BZ6*YH8E+J@i&q>dgoF_7F6L7?O9Wl!I5KHV>btaG}ag}XZUM5xZ_a)lJB zSmqNZNt4!q?c&>Q^T%tij*Mu!iNkGA8)uqv(mhfbV~=+87(Y<4o8*}NK~Fq&+?oXW zIJw%KWusM`ur^#aKh_w4^{>ACJjgEa`gRO_s{eh0kQ&uKLyvza8F_= z_B;{s)AdPxGFzxZ08A9;;yptj$->kI*NzOR#F7Qve5qq)dLxw_1KbV;^o`=YQ-Q25 zRFOwKGMA2Uc@8hsK06!z$4`1@mIhX(qGqzm21K)AhGjH3+Kpc0n8^E%m9in9SMcr{ zbV^8(v;l}GokqF)kw5P#b5YG;#hnotYqP4`MKD!eiJ&l zU6{;Oe84@(uuAtdemdOo^9CfXiK}Hvsz*L_l4HC`3}Pk<$zHBSg(KUJJ;z^@w5er) zE^5uO+G%m;iZ%S9Bv$nk+Lsr-!xUFj!h*K8I3~sR z=x2yAA3@dea&dFS_;YN7DYT_XGNIM*;!iggv5b-`w1u}ns4-$s8@L5ixah{Gs6jqVbGCf>5F`c(^r+mx zB*bV1SNP;(J$7GTzRf9yVMV1AWr2qvHX2(+a zM+GI-q{Pk0&W`|LyxaRHFJ z@W!IJx~tSl~7c=B<6u@?OxCf?uq zm54tZN8h5pB*6N7_0Nt;+6mQR$`Da45o#<4zjU!)!>7X=PO)gP9-!>}Ajz3KP)%wt zti_Wn8_bd>UpS~=Nsf;S2O+ub^Sk8qFB8qp#tI6^&FE&_ra5EehBxg%AF&n3Ml|SK zO_w`Jie#G`NtwcIz0DMa7|r}yBC5l8;PfU;IM-8>EOtZq1J6XqF~oNl4hoU|do*gsB_=s5>11$^IxW5uj-q78$;HW)Hv=I0&>2I!2KuPaH7 zlZhOtHqi?9!GHQ8cl!JFCT<{=@^^ZJ1PZ`=iy)A1+#mGnO*=@`G{u5hCxfqO5+(09r^olAsClo>}&cKb1@CXhzJ=g($+>x{&?bek%^LV4d znAvbw)?)@Tpt@#JMAvid!@s}Vtj9|}UQ1$!5+VFtSr`yVp+f83YlHs1ICw``7#S1d zG)pg=BC-NXs34L-KHY&0@+;hR=dl!xdKsEK&FJ}sMz}S^9SUI6H5Sx#&?EtvAxAXs->SHNY%dDxjQNQKCNnA$uDz^(addv)e!FB%BQji_HJ~_!N7TkaW{aOu zQ|`ZR6?K2xRpGYQS9<6r=-n$MtvPtIW9hQ6p+t{!@Xx zq7Z*d?ZNNG`+W7{!H=IG;7;;KB5qx+`IU{|>0p1SLL}1V)8tmuW0b}zWDrUcQ}XoR zhJW(VzmeCW#Z`6**K@73nyvoeN)A2r|DrFe!AEzN(&<7)R z{=d_8e*I9=wG52-7dsKKa^rQ}iw;Zgla>}2ZSY62By(qur_^66827=Gju$3kvc6t3 zc@p|9mEtrkspXNcgWjvIBZo^&eP0hp#9Rq8(6^fufC%P0cFKy~zum8D?tV{I7}q(? zG@F^OFi(2X!Nf()~Qj7NX`yWkW2yosAB!VcQ49g4=sAe6{?_T_q-u=2^m0aLlCKX)J z*ab1iJ|3B-#}+g=+FlG>cgPv0cVq9k`sH(cdwg`I;yq#9Q%`C~K(S&*ixvtHUoK>fs#q)= zzcs?p=j=^cJ#Jwz&1O~(5_v`ZmUG@}IFh5v)v%(`(WHwY=SwQZj~SpCwWMT~{IP=@ zKfTcJV#neEoiuXbM!50JL~uk0=T;^(74{0m*SoRy2c}(nLs=6LHbZ1Fh{r6;AXG7x z8~m#7&9x)kI7AJ}Bwbv2Qxfxa10E=jDt6h#KA*?{_X+^7Yv#!1Obf%B>Y(aRl=ZIo zM5=BZ2!D+7WS>sc2JhRM28U#j6VGmxn-=kp%6Fqx_{9oM?0MurU<_A^MAz|`S$&~&oD6| zUlNzd$aP4hOo(NPX`35h^#N3SuHb#It)uE8#l?dcH65|?<=f`6{uC_4ZUhryNwc?+ z&#>#reO8ZWh&3tg)NDI?+dPvL$a`RzBm zh8%zb)~AOgSh1}?(#~0Y{h~(4a4ptB*w<%Ya6^t7`a7S6{{VwBWz%&JG9L_TwhDqv zY15uJp&!tF{>Rvksic_$FDp;Yo9XqfJ|GDq;m*dZM<7sTUDm7!WwxRPgV;=2X4wa? zG1l-m(kER)PQcc64-NROwYd`=^0B8m3K}3pWtFKJs?05AR#Do(u)qVhX>(}aH_|dP zG~8LSak6DYorvL8u=0QmB|-@tkOuXzXkYbpk?Lq8ktT*Yml<~-E{EZYCPs;<8w?0! zBAHFs2dY{|t0#bbKzvK#?=Euizt`b0D+Xpe1tm#5BU>v0%H0uMsbdvKw{B(|jVE@n ze+OaUxrEFRifg_T%%mq*LX5uhHJqcSr#(7Xu!$v}3C1xP(u&cvNoEbT63 zOxTdLW!rFMCd6z=8<6wQYbUpUwSBr*iu5;aI(9m4q>BPiv)7FvHi;^p`&jx(_BDK| zY~=l3lZ%C;_@8Idpev_p2sZ@WTXs8-%+ZEcHOWH6i&mlEPsE2b(|wHTrD|!;%@oDy&&is2sQFLTpoZWWGW6Ke*})T!o!x!3-mUhsAJ|FbCBs2#eB%OOSfMSH1?cxv*x$JM_$Qo)!#c*Ix|SXmazU8{U<@p&BP{GU251dFls)5~l`OR!Iuvo6nU^?an zwTa=%*Rh=!pr+x7qb|R`opp57x_&U1>RtmV1Jq-oB@WC!QlNu&yO37v^ z1zW|~fDLY7#cX%v{fRH9W{pW)OsVxSv0SKEk}9p2+=?KNdSTGd75HfDI$-)t*C%&-`8C)&F!+#%f#>BseYgsB@twr^KqU305PlFpo%v{&?EehR`K-(bRSS3 z9N#QgkI}EU`hEHxiIR70Y+3`;OK= z{{W{|uk^yuT}aBBc!29TE^>5cj$f+NTw};MbOfwZ50U-@_wD-iQ~AQHeKw~Eab%^a z+%NZ|`l0shI=zdREFNnz?TtAv7pgJv8AmAHy{PpW$DdYsnp*q#Yd-w@}bNO+D1a(E2F#c;baC70QO$SkBq50 zNgQQC^8up1^|#pn0Dia_Sn(K@HsY%70tu6N2Dui*gU`hdtfnwuLgnS4{{R71MWO5{ zbTNtzxoM9v*CXJqkd^Y}#O`bbn#SNg4bMHn_v61-pq6tEI>=Sv^3uHvxp)K8c&ht@ z`t?R!7HPy->Ka2Lf`Qn-C-V?)xCh&?>a>{c1k{<6MKG^1C4rehCy=xNAE52;(*q?z zG32Rnsx^<2tu(%D@-Yc}T}o~E2kw4uy0wXyhcs>VK1>pZKkm>@gnM$WWA_7~(dADJ znLFmiWJIQQlgnbDjt&02dw1%1yo~#2cxN#hJJnpR^F)GrmJFsf<~sCKD(XC2%Xv6% zNv0dZZT&X^_Tu`O!4MYOa@Wjn8*%f)UsU45;-Q6#2EW3Pk^O<{c=2RgD;X!)lsEoI zt_&R?(Oe4ebSN2)n=2c#yO3G?did*zW5j@LYzH1_+U$2TFz?9(l6d~zc_yLs@))L? z2-p#8C84wWo}vD0lO(GioQX5MEiamgNJzok>0a!_{{Ub<{Ye05q!rGuGG)ZLW<+%& z=00SIS#E+*1e-m;9lim+gk(z6hX^(Pb;X#uiW-BIBiOP?2QWl}dOwq(trx9W2JjRK7l-l`1pkcK~ zn+xPDW;fdDTpP72dF&5TBBF04A(Lw{WO&UD*2Iq2@Avk;-4bmhNr@G*F>s=eHl!&O zaR3kK0OZ$DY8jp#(?Z9rON$4Zq1FbI%y|I*p%?{-`+;1JjB(QF%RYY}lmUg?J$a&0 z7?l!eV;)k5k7trV3}~;n6nhmu^m^(KGGhV=oVG^fK_VEzplr74r5qAXfyX_%27F_Q z3{N%$8iZKN3Z_J=@ozLgDs3`R0=r)x-36b-8F@IS9Xkd#orO)6sLJ1nIVHT9ZHb}) z+{xGyFQQYUUaPy%&T>zHu|7zXNsW+a+s#jBk_;=Vb@5n&`Ov+WDCCEErU*x2ES z1Xl;G%6MMDedWW5k0JX9g3GN{wQK}+w5sipmFLG7?zz2}C(Mq+r7fGt3(y z;T_Cs10t>LHUTVd^c;Vu#7U&bqYf@9fg_h{6jX@-U7~;h8==8x2Z{rwd00bc&gFj!wM=$%|J+!$fhT5O@Ow%U7FzENk7CN zA3@-lW6`mu$6V(~^WJIO(F7(&*|`A>S&fy6ND6|>0mBmUr;PDDKdj(si6l*_G*V9t zS#dk#!iLF{A~p3glE5rVX{(Y3;Bwyx=~^th^!mPjlc@NESIfxy%&kjNkrZSwU|G{2 z)3T@p1bRUL1+Kj&1L^t1G+1@x@3A22y`j$a=ZpMJk>Q;SA6eHUC&fM@i2VkeJPYPU zgtn_Jsy{8Yg-`_!2dd9Y-^1?;WG+i;`siu%CEK(RSg5*DUnj6pz#TYb_-cJi#u+;P ztj8xMqz4$vZT3(AxBOgCPRa)WSuIP)o+Zifjtn{{h4I@r#=4TUcv!JhHY!owD||OJ zFW>K7dPY%h8Io)p)bricRKK)2M&7@)H^%z*MzP`yFX8uwkz_e?AlK$su*tYqF5%cQ zpy!U^N4@Mm9Prd$8^y?xV~;B>OZZ{@D2w=YfhI;y zLuYuBczo=+WGYq{v$~J?xgZ-g%?l*-{h1~_Sy_o9N|9qK3Tig*8MSNl-vHMkT0o#! zJ$dY2Db>juH?Fz(BU8#A7|W}AMAEd8$v>Vk=a>d8gq3iucYKEh2;d6rZuw<~N`g(f zGK7jVW{N1_-rs>-oxb;DzgdQd%XEO_!{`Kz{BNM3d(p`sG>h*gV*>I9SP0nFz{3TfLx?6o&0%_36p+ zCeFcekByHaNWN5QPagJYh`r?3HYfpS=bGy&#nqZEKTFSsSCH3BXPm?1S#mh`p#YTyT)2b?1j7Bcp?I-$42eq34o8kPA{7I9jnHLW`A0|1lbu4J! zB64I`Bpx>aLL#ucze@(NrmlhGIQ%`~IAhf`Y^`H6N{B-PdFvd8HgUOR-Rug55>dVZ zu1{BW{LC!f8XZ-0B+T&cwyPsV(=connl^~bAsj6bj0xpg3GHXBvrerl?vVi45f_X2 z9(LY{VAC8r>u%)Llri&iF>vzV9}g=cG@2=5dd8D#-qk-3cDB}bdU;-!@Ib)1^f)8cu$RMLClSk?qlA$%mB2EBr5aGIHj?Lhx)Du% zfhu}p@eY{;8dNi4;>yd0kmH&q+(HJ;sK1=;A$=yv^>cifp=hZA zx{kUlBJl=`kFVn{hnn$+kzPD}x8Q(SH8CCIcMD^Ut`&ye+z8S22k}M*ewF+~e2q6$ zh&v%%Neo~?z?vL}+~1|l%*TTq!#t8Clf=qxL}T#JAK`XkA2mgR zC(~km7bS8g(Pq_S$!xeWrfBn#c8N~Fr5*nOG;E=HL+Ne_CyH|&MAoM?z$bUd9h{7C zL&MeV%sRubPwg#fJ|)Z1bv-&9*>Uq5RmTStPz)9gOsn(i?2=d@5$SXJXxa@M0AcES zY}lS3em0V{ZCJ5AjQLdKQ2CT*ND^yE=Y`< z2HSCA#^budH`4x>;ay)s8j3m1pCe9TJ~$Aul6+vtbv=#tJt2pyasb=EH(q9jCG-hs z9n+}ykB=3s_A;oFZZ@j=hlMAD>Ju6{KLKBQGhC^Tr361@e5Ncw{8oMBH*nDoypPN8*H!8P``)pO2O6Sq9!!)p!DcJ^R=u$Uk|q zw2ePdR$&@uV&)PZWnU?j4Z(dtTC$qj{1vJ@f#&B6M-$$|m^+VJd8-QbDB7@*zpv6& z&^&RG8bPP(@vc5`qH-eTC9X+8MX3OSRQjmYakEnCr zf%|oPA5qH9#GL0ZnH&rFa&Jh1U5jha2ar7^4*vjtll0AZA3ivq9K`b2*bGRv{{RY; z`CG6c(H#5NQ$r*!?7EC;Bb#C8t>49aA8vp6^{ZP7+TcJ2HlM_N!pvoNQzmUG!#lv5 zcBiI{u=#OpS7u+PGf-7-I0Iojerwy~q>V$vS)Loue0Kn-ZOHD0p`CtIk^2$fxap@% z*M5`?cs$f~9-k$^UeL*ngPAD_db@NUG}Gi;l+DusdlV|{2@-VZWc>65A{Z}(H#1MR!G{Rls=OIi9xqk$Zs zSBoMnbQ#onh!l(NERVIS}_d(HCe-BgP!DWZ{aa$71go?nwA8CI+w zMTYjSZ@qiE5x1=!qjmVZwu)n z9L8bhE6wEsruQ&n^a%d|4RdC?Le_jAs^VlxK4t^Xm2WbT6KGM!@@&wcconzbzgxS= z939IWQxWJKACI^1*FR5>AZ2%tX&$9$%PIXwBmBB{nZ3(f( zJ0M%*!z_-YgSU8Jux01JJ^GXRmSzSx6HhKB0kv7!Z(HDkXrJzS--m&GJFMhhP8)-;VY$0Vo(ZYjtVNTLZG z*{bP=RV@$?p!~|G_}skE^&jU>vtZ0H9fipjLxC8hM24}oc^&V+L@_d&c^(_X%4L*7 z>5rO{Tk+eGyY}f5FT&?e$@+Y}Z9z)b;qDhi7gf!1`*p(=QO7KaJLGKV_zF!HMC?ohQ^cDlY-10bJmbqTs@ZWv^04p6 zxHtFe;lqCrV7vT z6EWd$X-57<3T9dfUAo1CjEjcQVx-BrRv3a2WT^#LpKjl$RB?_(uIllU6$aNa4Yq7= zQFdyto;mD#o-82>pDsPCxN_uk&wkbW^=v_u(FToKVgL=zL0A$;2Ee{}{W>FllR}qz zqqBJd*NPLd^&Msi_3Oz-*^@}BvbdDSg;cDjz`6v0D1C=}9b~`69UBi1T99F;NSjf| zOs8jH(Gx60k}O@8Qq(vV?N!#uF|@2)h@eegY`oIDNyUw12+UX&Byn~}J-^8Gqx@OX z47mD!PCit4>4dUK$1WvYi5QBGHFAAG0U_JEuaF7p3|r~Co>sI7($TgoU~~#T5Ei~k znOJ6>g&t~VV~OtZywpc+hs=zZAyoG?7<}@0q1T#-ASR`Z6+p^mr37tpPNKg+dwu$` zlF5nU3?u1{S0(_nKuo_70w5F%5xJ{^NFd*K9s1#2n;TTbpJwuq!qGA=yTb>Fxamhqal8#)BHE3=(#yL`B|Ac8FNaLyqPlqv9j_!v|0)-hhj(- zeM66nq2ZzaQ-z9gfEH67SIncyZ=ctpaLcIbcxxU6LsTn`m->HOF4;*a<)M770TSp*L2pO!`>g%GFv8L zE=FEnW8#UJ8?<(MF^gcJs~&Fefn)gwRCst$_>06?kVT68X__vd8~JD$ut6}S9F}A7 z%y}oO(W=1m((KS+$iI_h`G7a>L@W&%jk@BL@wF{a!F9V z^t>$sF3R@kviO@XGb17$GAzZy%+4~!ofze}>1F3$H@?Ah}Quc%1M0uvsKl9>@X%=6$`Ji`;iYAkyX~}4q4(;BcZo8lcNkzENp=hsfHrKk(uzO(^t(xPk?OAE)>&NC0eq(O z%j09Kt0v~$2HM)iFORTmCr&3X)wzUpB#IqMUW$cPV#EzlI*V^YW+H>CC(%pZ|kla#i9p$$qU2q zY>t`!86W)J->#xtccAJd?LillnwGfpua;$k~zQmGPlg|c+9Chw~ZYGeC zrqCvCBQ3>^)JU(fKlJL}rK{m+kx0@10JKi*0FELpn{NPL1BL$p*z~0~S(h$M?9&|a z#gZh%F%r_rk|X8?1bTpQ0X4@W`<{|zIv7B5iFNt)aq3ZA_tn(^)U{UB*yUs~m1B&Z zlvG5d&~R#y9xR?uw^ejq4^r`WpY$K>nskyMH#LxeJJ^h$Q=WO|uD5jCq1do?9-xlIPh)!p{)KRckXBsd-UGYh(vM3p%p+1v7ibCc2EU>%dW(IS*!(^VI*xj z4qMFVblctvl<>xLRQ>+C(N)0G@pL?N#nU75;ZbhPOEaF^nEapZ@Br!@ti**Rc5R7A zbHBIg@_xgi*&5U!&onZ!d^5lNG;3! zAk^h%&rG8fN_@O!Km~JcE0PwwdQFZ!&n4PeTD6=U(Uqf3pV>n%YXJu3MLx2U%GnxP z9L%Y5fr>>AHWNxWF#zmZCV=OjqwwlBs{~qxe3>q)NQBIuQCC)@_N!KcDw zSyAMRCFAB*Ug99tciVBKA0+TkGRLFoF=uI*CnM`3j7^!BoUzFSZfvoAp%oX75N>87 zhZauvfCva}VJg0>r(o&Wh}yjVetM%x793-8EAXpesq;3LvMIM30Z1KvFw300ODiV3LYQrl55-DPNB8xTl$uvRGhA|=ZM5kyc zyA$1)k<~bIp}@vS<%`I~-UE7QH>$V%zi!~y9nVO+JwWKO*>0z;RfC$sHu$0wW8kdg zCm^;=%-(iDpJ-n^fw(FIMz{gH*uHypSv6d7o~9_ohGHZl*@BY9Gb*oU@7}mP_Z44 z7qI^TUZ=y;%pq1+5=+UTwX}VO`bXct-=&Wd__j?qB7AHRrEs^$wtMZQBL8ACJO1}WP5co$}aB-cU@|) zCC!Ey3HL5cY)=pA`3VH^MLIsnN-Bif6cMwNux_x=TdT3{)_>yYvvGvas_Qaf$B@*T zY(TMe0Z9U?mbRZ&dvVhg{xh3M!iqgVD>Eiccbx*{npasBLIbc}F4jMC!`O3^tnZbb z44LvNO{Pg`tYv^-bMD*%0p!(p>o*fxy8)+E&c623axDr>J?8c1k7-&u%aos0i7s9o zG9VGWr8h=N+64-;$-ANMIxuytT_R}p91RphF`iY#SIc6!#xfM~-H1Nsh4$!{g@p_0 zxVd>57}%JyiivDXBQWBGYs*ot^gCZsM-DfgsmoHNQ{+2B`7wo%hG55X_G8NcTh&#- z1D9!GolT>&H#==^K3mY8R5+Z&L_M(lMdIw3=gXJt*7uO(WI%4S!LI!Bf45Ds=!=1c z^toA*c|)>es>FbH+vYH`KS9r2$EvO-DJA}z8y=~U+Y{~(a!q{jJ%Q@ZE<~nNBjDtb zw{S8k5?A<*SyleSw|=&0;i=Ol#F9>>BKnVYg@8jcw5+#}B{Z1hhb7@75J@AuNc)t2 zX5`Q$&;W7o)zs2;hzx11WnkmV;7XA&5EdN&08_9wYq+oT>5C6Y`s8NM2W+W(8QBbE z-{nwmwR6Gm)%djiA4V*Y>^UepN%YV zPE#OcWJbjd(ZbTHqup6}s~?-+kJGCdx|qdj44+QuBnsHjWjuS$HJ0u}Q6q5VZXh0d zJ*i~sc`>AVMg~0oX+%?$!Ah}UrM58$D4GNJKOHIL=z5L>q9=*!2iYZ}ew<|y#&HYZiPnwgR=1;P4$;*}TMlr>X8Ne>tO^_vL zAe%Hm0C8J-v!o`YmXcx_74lk86c zUGvX3e|zYZdAYhc!F+r*AIsiJB6!dvejz)B-tT_HkGDXq*0qsL`p(JY%h!R1v84CC zlNil;adEX>PaxzCMkk$2n97LkB-qLdziZ?guaY|J48^I$`g+ZkvQ-q&%jO?m?V(v{ zk~TNFt&Q+{5f6{jJm{WH8y#W|m=X!`Ji!!sEx&2L7<;b@RgWBX7JR-Q)be11PR+{G z<&|n&Xv;itfEU)Glx!rICW-u~wTsMS;#y>D5-cKZX#W6ECs8x7Bf5wtdgr%lE0u#D zb7Tx$v=XR5jVwtn)&}i!Lr!p)AdXBzVgsMkA7Bc|sNj*oG0^i>hEq03Mn~2h-wV`H{XmM+LOuI?^eLgipBKp2ppO;W zReX1qjAl7QdP>N)0lwVPzB%f)v8HM<$oX*M! z3WT)S@wDy!?R~NrKo{B9To+8R$%LzolaDMj0$w$dCJ5t(1wq{#3jUxCSoS>y%FwqL zIDi%a>_;E(NWL%nZ<@b>(~gfGnfyq=!cA&eG`|_Zra1LYIMK=O2%|{KghuS!NS%A?b=WH3u3u9yvb_9rNTnaR3^T6Qr&L0z&p<}G?bq}Ok+|0O1_dXsz zSbdDXd}zg$NsNH}@-DvP=kz^G1~y(qUsn|JJQ2uPqRM%C4Y@$&SXeuU7AnE%$zY7+ z;=W1qvZEIXCI)PM~-J z_Kv+0=BWsSO@QLoJ`>AW`hsLwa5k}3MpMGx!)C}gUgs_G5XjIxNj9aO1aayZd5J5i z{{VNAt3h7U#h-K7-#u(=gO`V>;%XXn_<4~{9%H^Vv0QN|4hbu`g;D|9LA7PCj*#{2 zNjyV{F`$r7G#tJ84`?AGw`a+)wY>-h2zi#datc>P1Fvxrp2jY$K+*7?89U4 zjoBQ6DDVRiLHH;4>+=+gkq?`RHbX`ulsZW=)i)fHc^n%50MZY)Pks~rBV^&h^x3H- z(Z$X!+Z@!c;Hc|#f>61da|)(k?QFG08$Z5zQh7YJazg<*8E>sbDa>E$5$i};5=eb(k zx7mUD>#)^hZ}vVA!N_2x-{J0bTBZWz>N7_sTyw9T1XB9UPr}IYi&AV5YrTsAkb2Vu zF=w)AfF4W*_0kHug|(>zStU;jhBegDq~@cXObD%K5DhyiW^>? zM$^xva(dLfFRaU~X~XI9vN79Eky8?1A)-m*Wgfd_8#n%8?Q|~sa;WVabJt#nf*Yxp z83Afo8BAUrHi_hdSMrk0x-bNlCA*$ObKZ}?d%D&pPG*^}eLP-PeyN9%C_th#o+$@O~Pk1LDe7MBMibtu^ zfpizekz`-L>DQWj3m=$j)A>Aif#oT-K3fNGUnv8`nh3+yaPTma2yvyrgC$cfkDA5Q z3KeF{1GEmn(d2a5;CIel4@j3T#JH~}otGe_^Px}oBrm%S+jo2IJe%o`d<<<`aVDpx zV`?)P76^>0S%g<~zv8}FgM5R~e;sOTgNdPyIye#;*~+Mh1y_ix#Xt%RxElk#j@8z+ zJVUV|vmQ<2sa!RPBhoilUrte+P7DMlbHMYtB0B4Z2r~ z9vz0RD>ej(@;t`NB2n)*A=r`p89VBp0`U$!Y==Gwn=%$y!x?u%$li|R6&1kaaH>5m z{{Sans@3pwBAGtA6@qBPnAKK96irZ|OM(Zu9FC8F2Xe>$FUgA`7AYgaW{FH@+TAx5 zKEi-Mdi!-Bi-u+wi(W$`E;HYeLupnlOM&xl8HXp1-yLav*?{U2*KBM+vSFGhh5Y75 zlN-wl+!G`$%3FeY*|7KaJx!bCPp#^#BM{^35iV>#pUE*znF)3MG6H_%=K5mB@cf=4 z#g1(%D#~;96UJYIDiIWpm%!h;$TTkNw^by-OkB9}B#$C2dE{A|Hy(wQp`r-xte_F{ zZ;yVn=v59mc8x~e-oFTsVHem|L7Rgc>KTi%&}y;9P{--=@{y}|+&3u0+%P@B>%otW z{I?>x#mHws>OU%weKlM#BoXciu8(V)c{!8g7XJWt+vv4z2a`wj=c;&*vr5m8YkgKO zrZS;qPy}K@b^7^+1ZpZ#Z<5OM;56&lgN2eD8?{{ZP7 zMk5LY<`*N>e5x{`Bqs5fCR!$3>5(hiq>UmJvJpbJ1cFKc)n}jArbm@Eh{RLCfq?;l zU&|M@_dM~^cZYmzHOw4rO-2}TA08nVZ`0w1w^u05y1^acBo(~70e<0DTP3GVm zjv60(aRXFwOg*j}(oUreI<9)ApN^sojGS>WiyW+KRBmNc%8{}?o|^!v9>b(B%<2F7Hv5}E3UM`@KjDIxkSyRkLVgcLO_9ObQj;U%9 zHcG^*!4goB`p0K1z<+BU`t(>@U4x4a#E9d^u1hwn^AO|@7cl9W7+H@Z`FIj}%Aj(} z&KRiUpG(LM_W;+h>HRUH^BxUAd9Yi=tpN3TWDr;p&Fy3(=D)HwBulAdED~%x*g)|} zo|aMyU46G$ZvOrHY0~u-%+s+7(@xlH8}q=(#{pbe?`lE&gVfg}wvHWj#Yg%`*iz)5 zRC4i>Y_*Y|CeyOsiu%xyt+?_5brd^|=f6?w(~K=G@}OREN?47*5fF=VXjlqCzBupm z)$Kz8kBK!5+&A*H>}@t3UKH}UY?5RI5_kbjWq|K)JBsQY?8r48KRYWDYB*CYfpkOtDM3g6A|?d@G6Ys_%+ay*rpKv`cNL(Q~cNLK5x0>%3RJ-Km(qs;QM zpk@n^0u6@PFAS%jW5V>+7<{n~umA@tx_+Yu9%c><=wJDS#u(1gXuua+`1k((70!V~ zV&rr&KMn@sqjjnMFOGm`vtZ<5XG0paxH+)os>s1XR#sDF{mAL5rCgY?f*qL}>KN&hid8c4`;cg<6i;uEZqMJT@!a`vYETC-v)gPm zNf&G1-odZaw^a&0BWBGS$jul@3}9KMCw9^EM1O9rct#_u=W00GT0<;zpqm}czFCL{ z2Y4OZ(rUTCSBoKEY_S{#G+oCb(ljxGf*z!w}g7l%HP>m5F z+=M7RSpb22b6%cHM?ASW=9W1pRjA|+3d%>hBenb2?eW$QB7<=h%XQO%5yV0DO|jVu z%=7i-@Z^lJJdH48Gh#^FU4zJI#UQi=Qh_JZ_1f;-aW%x8G0a8C@|YoblWeHm8hE}% ziz~Q&x|3AVbl(ug^x61{iWs z)mI+we6z*T0_y6orfFfBR+nc?<|LVG;t19Oh=H&;aGe(tCo`?Yb?xf4Z8Hb|01;`2 zD@W86M`vn8;kTOPFknDF)JH+{v>ihcmT2Q;g-ZvGvCh_FC@>?0B8S+I)2X7>8VcV3 z08yx{Xp&@{V~X$3W~TMmBG?ni7C_{b9wy1kh95Yhh^CyTCre@>jF*15A$pgY3;NDdDc1jmZGm6Wq0DmF}uL5VIwW&(i#@>jR8JdV1< zz{%DL$HU%Xh+mf1<)|dr01|l}`91mQJloP}M41sZlQdxp5)0Tn*j@TosQa57d^h-F zXf&*-{LEwZat4M)l4Ot{%HEK^niSsm>Hzd`_F>uC(-JuK3R_IP=6Qu{55ltTE9bOK zRHp5s;!|DEYakl;7t;=(iHV1f*r?c&zA~Nh#Hvaw6X>(tw$pd)JytraH;hIWJiD}` zj{*u;l1>-nirPQr`*g9WYtm}ZGUlj(p`PL}k4rf`vvv*X9C7_!4x?*68sWQ-$|E01 zvRm+?)i83rLE^Q_)UlV!!&=A2T+Q(#6Kx}~^!p&=fLDv5*K=i!Iw^2*@v-BVA~%ub z^LI3ajiZ+Qsy!VkmNZk>BFFWt3POE^wIi;eS2pb5Z5d2d@Ru)Di=Z8eo9W<*bqe$l6I@JMaMl z{{Xi_=hQx{GI?Q{ks?V9EEF(%r3AAI_M&+ouRV3Cy5eSLMW&~lsKpnNg$^qhkWU~A zpgk2V?YGs~DzkD0b$N8?BZm_kCJa2OaiESlr;KimrBDGVIrO320QWzyPO_kDh#RfR zQzfp5yl_S_VvjL4Lb1y7m-DBPpdOV_C=0$#DDDTpLG>1GX8=Qv&y2CmBUq_fWL7@1 zz}ewV*zQ;EdYPelRsoP?SlQ{I-9Upt7OEcL*Ra2SI`Q(ngh-=P<)ZD0RGr7L029c* zKK0U=d_6!*TS3jTE`0IBb;)JJXQOxoA){ zw14UFa^V=z@yExjB&}Imga5 zO5h((-UvM3{{Rkphbv5qI2&a0BPI#Z-HCt3F+p$d12$(OI zB{~ti@~aBt@AvlU6DldRtdA!y>8aF_w|F2^fpj_G*JIX=kc=U9{{VUd?t#`oIojJ< zT-YO;28jOvFc7jef9KH47NlW=J_l5Q)dpZc5r6e?cM-#Vx@QdM2aq&9Pg~WXFEy4WA9EDjFf~V363V9%1bI(>+`BZbqk>|yan6WlSTsg72#kYvr3$58I z-{JIu#SRW-xv=&86vB5ws+x^ah}$|h3-;WisQa(qttU;(eRoZhGYm%-L`oI5xIjzx zrzg>L7jfp>Xa>b(VgRP;o&?*%c3xz8O_6&tG!`g!i;{8h@G#J&VZ@NbEUHVQQ=eEP zovX1)p};&I{W#(0Nr^sAE@{X}9%ZQGQ6dH|0)nJ}=2Ay+e*GlD9J<3pA;rp@A1Mwz z5=w-tg$L5L`McF}NFe?CC81|L(Bb0cM)JzCE;_SvOlQ)B+5Vr(N#cMcj*+ZcP(eC% z*NUVNbXsPYk%!{l8z)NEpq3{Eqw-`0Kmmx_tb3I`j|a8%p%e?HWn%bW#fCRUnNnoj>Bv_A_uK`rHUXjUW3NA73i@QcXmw37;D}Z9oYj{d*3~njKZv4Hw&|Mt zP`RSy zy|(rX!3S$|$v5$2#TKQHGNjRo(;3~p19CW_=2-Tj>J@*KfyYgZSRfeZ!{73%=59%v zPl&O6BI&9GpCUZ^$IZkJ8Y_-4f!I~^w6G-lc~Uyn^$a{+N(aK!RxI3kp$t}8d1Vbi zF}v?n-Nk_1pH@Gq;J1@JStZg!rFI(H<+%dyXu9uw{kr$Uo-CVAigd+@+M4b;1aa&->nFr``lgrz334}n z3q>Si)G3>e8 zRe_ElEs?KDrIe> z6sk!{5CTP2DFBd1>(qLWhjK8p4pxbX(?Y?TXyW|pYlZ{gf&QF(_3jk$XFyC2Jfh`- za-a}-1#Z^;%Jqfy5^;bz*5WvM&Enf*g3!XnBOwFvZZ@H#>RN7g9{A@;R2GHFLm(f9 zcp}lz75mT!rmqTkzZ+j!8Zq>_%7y2|Vs=QEThO0x^yd1hpNI8YeEN25CVev@Tr6nY z=Eh^lmK)+l4eHzZffv#|nkH5zR3>bOov1uBM4`q*C6gp|L^%py%dl)Z_n=i{D1AbY zWm+>02Qx5*po|{Kq9&2CA)9^E~j_8DuD=du}B_xS~;zVIZSbGq7_UQ{) z@b0BN>#2BmSuyMQsVEZVD3TnoYeHREOP^{{Ttt_9ULiz7zhO{4qVDf;2lkd4tqS zahSH%9nQHblZkNU!;S=xC1gdcJUIbKqzTAbST51rQ>e4wzg@muSy1ejR>sLh+yuzc zx|7{lRga70ao4EEIlQStJ03ukZE^ZA@A`J?+rrs}V39=Vsu|FLB}neJtNQ{+`4L?S zxcb;vWUX*~{{VemT+pXmyxSi|U2!r4E8}f5>>)A%EXohI;Z0w^Jxhz7HY5?EDVV9M zmF?Ys^ZTEBAot|^^tr8gcT&ZTC(&OkDB^mT5l3ArdjmU^%_C=dVqnj*pDgmj}#MB;oT1eEiWO)YQgxaj|h}B!(cNo z0Md)Fg6h~=p+c_u0fU<^Oi6iv%j8i_9?}Di-__3shjGv-yn2B)$t-b5rx=*->_*WRpWzux#@R;=IFb+~< zE+#0FCJbc%01+XGwj#}o;?HBzNn?dAeCQ!H*!f-lM;$BZkw=xCBF!OuVU83+Wb_v- zOIah`cF_A8>5u7g5kOr&28mXH;DKJ&M_Bc6^{BYAvp_s2=i5ZvYBAzkRsR5_$CqhX zG2+@UauoG_>4kq|)Dq%iq<(%@Bq~jXW)T}7JAv(AJq&F-O5f&xCrF(3WC(Bn0Ja@f z8W)G#Amrp}(#Xee`}n1mKnIFnQvCKES0UdXN^=BCC^W*pYU0*@g|0KE1qS9M%* z$6UzM@M&)XCLh%4ql!3qlPa+vE3;|)-+$ApV=GXB z{{Y(aV9$kAfUO*uvJ>)KX;bgT4*ed{AD+F{Ms59htC(0?K=UWUlPelYipw;}rA&?# zC}!LRouaw+q0t|v$1xSg6JwbThx3l-A0Qhw_UIVaC6FP!krQ3AG&yJ+;+LAEeAnsJ zQ~1XlPG2)SJ|eQ1;(>y)ha}a|;11otw^zwJ4S0f70)N>06iYWEOc~xZ#)?5)6C)Zw za(TbCbP8R2GJVUl8%@TD0V}dOAW@;aXOACS)*`R^J+)&biXZd55I=n#7o?EV-Ma#U#q?I4eoy+R^d zXOu6FR->Qjmoc>5cz{-u$`WKuKgNo{2**9xZu<_R5#nj_GZ zTjzp*OY3NiJ{V_nqh{hyJ$a2b!ay3eJD_#filUG#%| zidBOp*CER*c~Bq9mTjGwieFE9?rZKF&gU{)4IDJiBPBKls6pxYd0 zdMI*eu^ZdHSsuXk2AZjhkeM2mkW*)!ET`)qfLd5VmM^Kz zkIG=pFcJ?_k_V;8wF;mT$_Xd6cQo_0j14;)1=ccguprpZ(4!&*THLHvxZOgn@3}O3 z$uFx}*(r$z(q=pc*!`#4)>0C6>r$Xc%bI+A?QU#E%~fF}k+U!1J3B`k1~kuXSnaX- zP1x$ci~L^~gqIr=7aBcF#kr#K8MEizqxX1kfZJvOoi`MqT`RS({)7U0nI0mY0}K z$41IrCq>L%I!B09;v+Q5%sY!T8=D^H`;NHKd>y1{nb}#oJ|5jdL_bxkWJ(@pUvToC z6a&R51N_fXY8uuTg>>ko$({08(1i+x+ql_wpf=xRi~_`ZjRAcmYW^q8*K!o&Y{rhG z5J9)hB&a(^(kYK_NTJCC`if1bjQWU@d%N@=h)yDz%ACAI;`}WpD1MVMhC<{-6^vV> zWCRx5&pZm_=ks4kz+`xzE6N#T3s1(I&z4!GTx5++mZcn@&RdPrIqTp2J*ebmWz8?* z<;5@(NtHI#Kx~j?K9gH{TfW!a0+Ws6W!Ca%$I>C1EJrC6Q#2c=oXKI95!fN*Z)y}r zdmTSd4}`-smK@I;U>H0$d6?d=#?^EPf#ugwpL{B~ULV#pylp=ZH8kvG$wf>>c4%4E zfhHw2y|(VIPd?Yyvz6xK>e(4GV;`!5GmP-7ljkDH>?9-nM{(rxJ07$D00?G4nc90} z;kr(x;ENnjqb}``OH~x*@(rqWb(IA+Qfpl&$k`=@qbhQ z0Qi$=u=KL^cn|nBoqkmrC(F`C9L)wCFt(uvBRk0=NgtU?fE7|?eZ=>r=f53ho+r`9 zKa2IP3&|MR*;waW(_;$CTuR|5P^a8TgzzZtQ}NT5ZjGm8&8I$InW$&vV&sO0Cl3u= zu(AU+M*hj#qedzv5L4STS{t8!txH2$xUG!}5O#fb@ksN}k}3 z2>9ABzeDohCM_3Di#sb9Cn1p=BPt}Mo<&w0%U!PI3c#oec_f3^-^}s#%pA=8d_#rx zizHc?jCVFRQY#4|Aai9#P3{z(ffB@$Mts?!GUP?WwHVvYRoX{9Edapq zK{tJU^yfy@Vb9ZKk~tz^CIP?`#*l>uPnIY)Zs7h~C%9Idn#!b&3hdIR@qdHxqR)m2 zbtv@g+@x4=@=d%feMMG4eMUD>+hpaEwlH7;=vKF_YMvg}@#f0X(@M-tW=*)K@bV)B z4>k!044;>9zBsT5>qgJg@O*dS!Go2Mapav$xLJ{~FO4?lA(Wo}u)_X9;)&}!@mGv8 z;PGCA;qM$`&4=Kuh+<80c;Ig;ER`;wQ5#Wcxd>lrBeA2%ItI9C1>-Yzays;V5t_n& z+ZAIQQ-@f1vT^?a+BH_59foC1v{^uoL~aKlw(i^yZn(@*1o?cU>Bk4@^7Qw|2Lp1dA1Q z)X-`%XJJUVF|2Z9#;-gut;~Q1B*u4BFDeLHpf0R(`)IVZJ%&Nkhg-j-BIBV)0m;+k z&65DGb}YZ_@F$(H#bE6S{EsWQ;rkU7R{D7Gr|}af)E-@D5;gjP6h+oK3vESt z1*mpVX>ZgbVk@lYA0k|A?2j}>j|{r_5({VI@cpARH}&Dva#p15j)VJJZeN73Ga!Q_ z!_nbj$XVVZkuu&>!=7&98#ql(Gr`!ZBt%lH#l@ zAd!cZ+#?Y8YI~@#IOGfIW>UlA9D8y>J4fXgwyQ{gi~=_mLtpT=nW0c?3v; zJ&O;Qw}cVh4t-p9v(HEqN2qvTHeaP>nj<2EwpDQ?Lw3_5{{T<|`*J!rm!#(DOb$#k zMA%#>{3|B4fC02x*&=)+m9^9^C$Ztxt{SIDCQ>tBE0z7^wuQ=Et%7`yN5} znRG0|*!X!+eQrF=UJ&w*D{$PhD6VMyU&uWd2~!b=y*rJ{n1)fUXX=V!rZVbK<7y0W zqm|UhG>dWhX2FnOBn~c#E8mbgc*e$oKl-1oW5A*XjgO{4MKP{G$oK2f(8se8-F1%cweVQ)!WtlvaEoVXn7WevK0^sNCd5pbywkUx z)W+|cq0ZCUdWtPBeLG7`I1)*5meJAN=0hSAcF{2nVD_TLZ-HEN4?)$lHC32+YgAm# zv4)pM)z{0OJ`I(a0u3HNsBzEFOpxoaHfPag`Is5|H+?=*1a@B5ruN9cbtm@fDq$&A zF`?^W`0!lXj%xZXN6U&S@}QD99@TQO)U;|rAftdwMn!gTN8EH@9ZR5>5!O{d)f0n% zxZ|qPW20m~ND4A5@g$9k^YX&^{ZB!2A4&R&TP_(}Eo5Q!Sg5c~835gdt;3tK(<~1H z96vw5bw?KJ5iI>LPsv95{8+*7x=4WM{{TAC>0496(e$>BWQ@usu)a}uKQu*~uh+N7 zQ!j`l#c>v!KBcV6s?P8n=;M(S`dQ<9B?1Ji<}&U@0{fWm zkKEO9)Vc153Pwou=Oiis*#+Xqt}2wj%E5JImL{#HR#!r3n(PXX*bcmc98I9ZoRa%` z$lO1%AL-SpwQV4wbA>XoZ$n~c+L*}Uw~gw4IP09u+#G$42+zunNj$jR#|+9?3))Qv z29LO-?0Ud(`hYp4-%j_n_j)Y=>?CE4I4e*jGMLg9e0A^s{nc*!9pCaN`*m$ljvh#d z28f++{d!&c>=_34!!RA&k(viiZ@6S`f45OdnWtn<&Vi<#`E9e2e%5yY2T#$(Vi?of zQzwm*kEcP$y6`;H6s7hunKvmlMYjX{bJxorW<{(iA+l|ii2ndDeuiNOTxS839U1=s z5n6lau(~z&2d}@ICMx+k41zSRwhJichxKxJ?fUd_j(ITJW_$9Qn<#ee|`j@eD!s5}nU&&lc-yd^VKMpEX9JXbu|DnF=w`igk|`4tXcxFQ+? zCAVE-_%{U#7J_`XjW&jP0uJ|nk;&`H{5ypV!bQWxLRax5uQ8~9NoKqL^~Y5;9~?;x zkwpe9nGV5x*uW*za*__(01MmPlib%!8kVV>n9|86G|{V#?F%b0Bn}Og19AO5x^!1* z6HEv@e0d*l6e2GUH%wE@qv`FGai+t0;kA-5frxI$bu`VaEzbf4=Se=ssxuw=`9ia#}r zu0N)S*#5mk^g5)1P5AN^LRF}4rUY2v8mkw5dkopyY|c_#WhTKgNGy*2;=w=PqSdGi zOR4?aHfyc=@YM~rv-Cz6SkpATb0pEr^z7l<9B2fiunoeJNHu?MmwbOBYJLpL$&*UF zT`8f+cyb-kFp-r6fTNA1ZDk{oOlpX+XD2T&HeWVOh+$PEAX!PGK`leM;)esE9ywjV z!;Jp`S*6Q|%yo7f*L||>1a1KHM}T?j&EshkK-4b1w$9&=m8XQM6@x&s#C2FvGaZCV z9W9ipe^UU25r3EqsukO*Gcpz}YwE-$yx01NRwRPV$8wA2zcA;TtLLco^mWR}lw=su zp&}ICcQ17)FTW$$mFBL+btb2d9v?n2vPEQ#!E)Wpf<^PR&^(UktclTUkz%MsjR~I^ zD>Hd}!quJ8hBiO+mi@Y&LnCg2M?=UA4Os2{kGSkb-(6TOiIp*w@)|!Z2_Mq6wu$Ud z9Qz(Fy6#Bf#g*}6cW{x5VvMKq-Fkqs2t4*R)oNbqFy_UjYM;XI8^eL9!>8rR1|wu_ zk`^<#X!1m#(_)9EKsIQLua32SYeLlgMXnsIGafcH(c`>1!yqUD5XUq?suyk7xj_m6 zB=UQHW70D7cS8;)Mnq6akgXhPEh6L+svPinAyi#+LjC&v7yKpG@NzWMr^A~wWW<7b zlO{1Amd+L2C>#YXAs`DIc?XgNvZ0{v&{)S_$Zzig2K3=3`~va#gTw}3I$0$+cp7|h z3vw8W^{`#a4U!2Yl6gH*$ItNIg3@Ja8bnE`x2w*YAo6bcGBGR%{#yOI3#@%M7I9S6 z5bp)1-yvd@1s&JOHTFD?I+qt2G7p^^1&X}H^==99eO!L+U!m{Up`(Vv_CfA(IfjF} z4}gnv^I1=;UCtsRJXE@lwVC1!)KlLM{Se_omR7cPJ zLWD54JINKvYx{Tq06wiWxcX#E6I@7E)OU06E9^dcr#@WSL6#g=7{z^3OE0CnUH8A! zo3Cz{4s}Be2*Isjy05EvuM!o-#Ke{bGrL6;ztIbD6b+;ElIj5Cy_3@U(6QTGcg~YC zQ#P-{K^^RcW7wBn#RLbQHnjuWrYX}6U^8kyTjPPb5=99Rp~X&3nQ8_B>2>#nE9a3i?5fcRH{D6YxJ?dZ8vH4J%Kp%yQ=-(_0P1-xN&`fCp4E za^NN`V;cE;(PGAk?JjPH-~l03h-x32tG7>fLXdOn9i8eOL9Xx_o%RD~MG}j9*;*v1adifd zEgi{qSp!Y6K|Hr*CxCDD>4md&`4)H|7Ho;~;a@f-nUH`9+qszSG;ed=D8Ii-P(hh9 zGGIk4`w+;%7xJhg*!%S5qj-Diw5G_{9O8MZ1fl7JDw|XQer{A6`RgW@CZnaJPP+5j zv}#ggAe~WNKTFf%iYTzB$;b*wnc@e0iMY1V#BhL+I2?oX(+|_+=6O)%%rTjW10Eo5 z>cAJ<-;?&}PA0RZ;5-<3n9^e;?qeA&%*-5(+gZCQH`|}vsWn_VA5qi3iZ{rLHjw17 zl)&NHL57>X1_yT+MAuV@#2hCcMc^+pVaE zhp5$`fqauh_v56W5bAQiQ^zK&EO1V)3|?pos0rb=itX)p+i@HYtt0@tKt;bn8HOnO zWDcfDC0abO=XW>2pa(ZVbJv=N1FL1rCy-=GBuLt3QyfwAwUr6xQYyC-wuvisTXbkq z!n)>8%Y6I$*c6=i)fy_AHWp5)lA4_HOO2)>ghLVqx#^D57PvwzpYc(v?g{GI`=B~= zLyWNFw$z1|~qov|m!DYJfn90O`b?r{9o;8N*u*>#nz}3PKiSE#^!4q&Cty z`7C)P{P*jmi9Cmm<&GaoRY&(?4{_Y|Kl$8#Ldk_0Wssj++IoNCUhV!v_2_0y8kTWX z+PFB+NT|i;3R5)OgymM##?DqR~H)dY7 zy`N%Z-IgFa{lEwP;rsqu{{R<6a5OwTXvA?RoBsd`Ms~Re;G1vNiLR_+b)x@}X(;eAcvQeEul#uc&DC2Xm;X&fN0(c#V zR2MLujgUzq%HCTc3$&6HD*!*IwOBr@Cb>ON^~5ZZHaM7=kv#5qAOsg`9+Pw|p5EN` z_M7CcTp1JXd|#-!6JWA{uOR;bQ5R$bVvo)AyV@Njw!>!oe{c^2xl}mJ1Nyr0a`#A= zByjIZRmHFr5Z3ZPHHsD6o@=Nvqnl7nWW-d=nPCfT8KZ{T=n{RvuR`Dax}QqZ+ftb! z$3wI(* zoN?r?Mxi&Ik>!~c+A+mfB0t}PdF}1TOu=Bq2(lRp5IANfn!)uoeE$I5_1-o(hJ+!q za$9hcNeC?G?m(f>$3(RKB3B@7`izLzb9(lqLaNIi7u%jm=~|Br9pu{>PuhdQr^zAn zGnvvdY@(CE=YmIJ_V@es+}gxiel*evF|qul;wSW~d-{*{HFiNtMvMgTse8Q3gbLd!7)aPS#}p!E!$}<6b?@V=Zx<^Q+5mWQb{SY z>l%|mnN%_4->YKXl1cvEMVXN%MCGB05$cstdQ+3z-H$yaYo0L2$Acj>T$PhHDU43f z3!6}BnF!$5+>d^n!{M7pzWcgAxIuH>U%Jt0>Q&u)FCp<}$;y&Z95I(T@Q{;80ip%} z0J~eSRTlUIzggCQi9{HJEHsY<`9?V!J|u0_To3-nza$dx{Y*LyHbdlOmtE4!DcvN) zm$H8R-JZkeqS}6dBFTVCf#+l`vHedMHOhR`PpbU1#Booui)gpJz0maE zt7LeQBZ}!Jl}Jzun;``=kb6}rJ;@w&^AisaM=#M%H2Ee+W_JL*arb9;t-x3GtphXxaKgQP_aI>Q{fX5P&S4#8+x=B=2LDUAW&ilX~s zg)(O2Y0z*>xSFnyL?bg;O-eafNMme?LHeAgwxt9TL7`^B3J)Etx$2^3;lz;*;&+Vt z0QCFuN&)xh_UH*5MBbw)ry?6Jn zuv=cCIigC??3yhpzb`XL)K*oWd_~)elX1R#6IMRow^y`GFAwBt@{QRD{p_dV~L>(Efc;wx0mRgD(gtX}c+#Ul5yjfS|T{VPHGRn5lJAq|lvyMU3a z({ur1J*w%sCb~a?qAJLzDS0Jb}&dI=b?}!PMkBV(ur-p&1OkFjZq) zg8&I{@6_v&^%KMNa;)nm21w55JXO022&9o+hrOP(Dbl4#06jVM4%EBeT_mre(-#V7 zofRT#1hH`Jq=0X^0MYxK1Q0qkE=1XDJa}brqIUHl9&0EZ)v@E|&o%AGQDteX1hZm? zf#k-=8=;BCMz0w_NK#yw@)|alG$^HmL%Vaj$Q@_{#{}OUbCH#quD}v(v-E3` zEawLY9U{gu8)cD#E<)@p9wGIoj0mO!EiJf-FaW!v=|2K~NZrJ3s@t=f6TVY#Fe!OmoiC zARAgAG^$3R0k*EbIR60Ks~R4ek*rL(+C~#iWbSzJ&z7Ggupb`WpN_Oe2GeAhkOtdn zdugYxmqX8(%me50uVBUXDuW+ZXPPl2l1GOOim`#ga!n{xeD@XKw?bp^zD7Q!tqIU% zV&{m{%SKg402?GXW3-SD!yY=?^e+o0h_4=*r>)U^0kElPNRh8aMOC2m1?tEDyR1PZ=SUUIH2ud6I@jguQpaDj4fc%A9Su;qd} z=p;43l5amENQ`qyBfBC<8)&~sRR?eZNEUnhS8lzVP0x}BmmeP{bU@7Pn`H9G%PAed z)8uqZ#C{*tG@UtSTxX64WfJ6|Y^Y-;2LX!uNMOtAJe4)l$ka6)BqUUcw$SahRiX(3 z>|N0y_P(|-V;NSEt4kw?kKpQ-cxzpi@;cV>k{k8uqaRU;WQt5jY;3xbSy}c6L%f}? zIX1MkX^Cp*s5MMyn1s|LF@#NlB~r91g7PSVLb&!HuUbbA%t0VqTWEKAX?cU9t7;l) z4fU-36IPcSSV^?J=$)g}chC;?imbI|=mz}mNj z^;`^%Fhi(8GNjsktsyItO4^aOw#o?~hi1s^MOXu$LqAVrEM)5 zOOEj7#*;wAtcd=wN5?+b(DYyYF_Dip96wj5nFMAQvhg7v$F&2<4Z*qu8V54b{Bb^! zs7ofV47m9XCd|lHffC8LZuU{#fCG>LG;eoqwJj4{!`87HO)6F@uEC=M+A=x6f(Z6M zKG)P%pvtWLq@tx0eH3zHL9JyrewfD(R5F#2y0Wa#{USxbOVv|~JoD^&e(+E647z0L zUMFrJ!n1< z)Md(#CrZ^_Un3p^<;3b($bb-35_#LmqsSaz0F>=lK!j({9MJ@DyJKL+_BSD0jzA*8 zKa_z~Yo;l=?FO5Sk)hwY4f#pV0;dxZEaDqGLQfGUw+)=vy^tA5`BB%yD803FL z17!!lfAt?7Xb{@$gS7}8g;>MG)8*5P!Y0!ENsEl3O!p)c0UxW(Pgg7`wGue(U4_r7 zc!cPAam$Sc7D$<7o@p0%)iS6)VzrS}MUKLz>ilv@$J?-!EHd&Cz;ziUva*^ z(w(MDf$Oc`+Qzl~JbxGI@0${s^TzfH)+8i3xX31s+W-^t4`w}QSZZ-{AjHfOu}z>h z;)UaDuhNb8`1^IXJ|0Jfyg`qY=M}U)Q7Q>G- zg+x3WO#ON%6O1X98Y0cjl=9wT90hZI3R->+Gom#Hi&VVO*-s>M@o z;!Rmk-hsbjI(X5h$Cn_*sBd`HnO3P?9=l!eL9g2DqGE8=z%FBNt+t@G&X{pQv%iHn z+P=Roucm4Zrp2?&XrRYO{7`vrc-zk+xc&H9eGkMwAMu=;jxK0}3MOfx2XezcE0pA$9Hs=bw!RxCe0}Fj|Qu_2iuN1-am(a zBZtJ;lHqC*ddv)29l3VeMUm`5+t~CxWhNFH%)a$3C65d`9TS!&TIFfP$0&|u6&$Vw z!65aiAp4K=AFo1uV+-qE7RibqEM#ffA-LxLUg8`~Lt>&2**WahZwY7;y}Z z^qQW98wO4`NEF7`?nkIN{TL1hNA!qWRPg&8oQG`eh?fp@NeZ-?FtB3wp6-ie@<_5f z^(K}^Q^f;oPnw3Cx{=zIJSC~*MKzu$Eb1cK03scTEx;d{Zc#~3ky3;T&W_&#mNkI1*^*>XlUOQZ|r?!V(Ix2AIFLr0G zi|u1am8D3qwOsr!Hx-a!V<`~28I;Hgje%Y%tG}m$J>`Q;tv&Ly^D&wn3O1g}ng^waQ zR!~@>eZJhgq(KdW0A*@xBCHxe zJpA>scp6RGEEt&y8F-7t+>TY7%usfkuxwY`_3I|oM5kQLk>vAYGLaj^n|69`xHZWq zaP}bd$>0wW3>M1Dl*&Bh#`>7zjF6-sEu}Z?wk+QQ&ui<@<0(450|Meb&)}r#yfwjE z@dSDl>{X^nBiSo4FJ2V_vah2tgI9DCfmQOH-ke$AvN~Xyl`F>X-C^UES zmN=uvE3r~mVCpEey8+{Jlh0yBdlA#8g*9h~!?I$-Kh%9I9g6`S4k zR*j;YAMpitC^rrVHdHtL@zckNF$|h4P)$!PL`Dk6el2$Vf;QEB*GV%@AYD5@AQwz& zm(BFv^bNF+?94jZW!cL9Np>5;>kB)}iD4;>8Bl>DsV+&j+D+AP)m)Bw>eFROK97Wq zH<9P#x2TXxQz$<+wfpr*>5r%6WJ8ts{{Tn>7D_wONdTX^fXqebCOg_@74Vd@x-JXm>NVAV08Q0`F?n8=sKkxY53-G1F_ z85yzbOfw@3G^oF+e&%)x94v2gx;2&<7Qw zX}PF*$W=y_Bod)b%2a}T8srcSp5EQMW6~vajv-8y4$*NQ_fo6~?7sX1T!ICDZnFJD zB1n|9Qi$Yt1}(?Zt-s^m@BMl?;D6#b^W9EuGhT{4D>f;>il=88Eh7`Ol0`7@UFz$s z>{b!MhNEse*o#J__fY=;;wChBnfgzNe96{d<`Kn`n?r@}RqTs5*pp|sYUpOU9N4kC zx-4X6DFb&X1e;BdkVhk@e;eZ*pATyAtZwe?vXET*Ldd+;^Xai&>iO$5)-^*eepVFf z#6Z%7mc>1?vDyb-ndacjPav8pF^1JwWd^qQDnl}n&2Vd}^HMXKk~xVH)Rblf4X6+R zXm|X^`}X_wPhKegO2kQ#Jch_nhtlFLo5>tCji-*@{Wxg~)fx{jyp&TmGMGFgtYUbB zKg3!*Z@Wzq!9EH2YQu;&}Bd! zxe7+pW4Ioh?s>kgRe;pK(brs3%s=CWa0Zhn8feIg<{K=FrYr#!`(N%lt&6B9hfLYp zG;5VMeCoJzloBRAnvp_KB+1A=%d~N4i*b}J@kb(p2$=vCw*LSy{RNNh_Uaj7+?8^%(TJ?V5-?8g2$ne+m4?1it+>1F!$rA1I zmMzz1fZTTrAlC)BJk52I#Nd$U+qn7bA9jJGD0$mFyi{tYV?s>3!zZNujIA4EJ>VW4Ko(sqwvRTQ=I)A7lytOQhTH4i5 z1#0S51^|k0A07b3^3xCGgbEBrvpU&c16jM{96vk52=) za!)?pc?6;dLh{JS%q&WTp5u+x$3OR73Exk9>!5~8G?4; zo^Q8NML0-X9~?M`b9w>V4{}YCPq^>js~EbzpEf$l7^sUB+>n|qI3O_K^T*o0)z_p) zu(XkVRzQ9cl?nm@=7}Dz{{W}orCmYv$9vgGb5%HU8fg$DUV8=d=%XE=^ZEEtx6gjA zM~y78FXF(IN|_ajW68a{dvnL?I`1ky&kM_)8Yx5hTu8gS5H5lC_yWg46C+D}cx5>a zF7Qf_X!>u96hG6q=uK%hlU)uTF~wQMej5XOF{RTc|UpGsf5 z8t>B9Pm493SI(0_!d){Qf*yUIY_zxO+(yLX*aKfZU&X@k{B0NeJIWnP1&vwR{{Ub( z{ZAr~YU!&IVG?;iPBCLu2VrHsq*yx#u>kw?M*7#KR|!M@Hc8`Q856nU&6NW0L2!ZM$MC+lv1HO)D=e3&Z%S{Od9d6=kGHG}0R8kaBqYbS&g++PKad zKoKS|5~tIYGD#R}H0;zkrn(2?rRh99s>d{=DR8vOqYZbLnEA znxon{1AFzjg+j;bLad%D%EL23;k;5Kl1T}f_aS=}T7V7teIt-SBnq?C{uJ?(WVGw3 zLywCTaYqCZ!4cWG6MWwWwvD}q74Kfd;KcJ9ZEH}*>hnB+|ECCd}fyp1`*Hkzbw=FBU>0_^y`2}!Gq!i^2V=h|FBs*kB zA!C)Iz2JL>CWzW-Q9K$JM@#-7*0Ez48FR{wGem|!fU!K-vFvL2zGzSY@RIrZs^*O? zq?;YF(I$f;Sj6N;&Os}*QDRou4(H#i3#DqWsF`8N)iQ8T`?#dVNahr~RZBfB`;rjV z*FDZ#DAg53OCNo9nM`W06pli1Kg2CMo$rFxJb(z*rrKj!jR)iGGob(Gv!PI6xit_5pP8}Ps?m~dsv@?#M6Fi za|SKHUK7-#G3;=HJXVTvj7t_SWtj|WyIr{_+S-Sx*5F45!5zm!^Yqu9rDXNVB9@Q^ z1I((X2e@(X?BD5LJ!s`TX{usCu}{0oogoG{kXG);(4eR)C~YU>o{i5WpGWo24Af)u zX;#_51hE6;5Px64M{PpU6?N;a`_RiK?a?IX>r!}lDawFJhVFt$lq!v`0&fHI*J};O z&ph<6u4GM^%t1M|JKM@7~7m zZvAKZ*s^Hw10Gc7g6cTMSqvr^jAUD@*&j%WwdeS z2lLStYB?n}PM-m`n*zvSYRz>=Q_*33iLz2@BT{5CL*AV2^)L8&0>^It=bo_vmTWJi zR!QMyn;vcAtz;Iw^R$D1`bp>vdvUBXAlM$d)()ucAd4qWbgoij>d?n9&CFGoE6saf zH)^)vM2t&yq#hgkWq7`mDCfk{Ok@F45-o?Pjjp6{Z}WqEa$YkNX%NL4 zMdq|-GRTU|yoTWWpGY8%_I?)}tG%ceniq<_!X}K3pdQM1qk~WoH zsMLdi#C~tk_WijXbrLaD!^po~exR;+$l?OyS=N>;_QuqtXy&ysP7orKWP>3Tc=aeJ z=DEJ4&~vf%O=>+lSYCNqc9!bQI~C{~{{Zh| z$9fn3ohj$|hg{OeCQdZ!_;}A7s`+DlWqAa(TMm67k?s%K=HOar4$jAJ?aHlmx)ZiW zA=BPr0EaIYbf%5h(K2_xl_8HH5X;!{$w$q@lSj+eGV%nIVMehc{X9b>&O+chEqjA5 z&?|yKQb{U0b(dJj*RbQy(~p~nl`otljY|14f$E{`L9t&Pdvq%yJXt;W5{bt z+SF_tJ&7rzO)AcrS{#ckzxWGV04`H(sgZ!(PHX&#WAEWT*olAQbp}A{Xm0N z)-`7u5*~Sb_>WQQnQbvp=4iNE$ASD!9<`;$_|s1eu^q9O205W{If;QDmS1b`5649H z9V$Hhsk89c$<))Cqphnw3J4hskYQ_DOwt5}k|8GL zaNeb4p|(qF8$hs6TEB*TN2hqdO2^dj z!T$h0{VwGuq2c`8jEyaziZ(`kta(PnZ<$XtR>-g_ze0Lz>Dd1O<~Ojf0-)Ql^}C=P zRv)te03|=P`X+;>EkU5~JzIctU-5(wn+{{SwSt%0RkxgHYiuTq(i zRX4}S%v38Q!0{1GjkT2B`|<7lx}%@qjU!RWZ0xymakB{pa$uKf;8w>{3bG$?dA>m% z5y{gqv!UCNl)d{9e%-yt$m^94ix7%X(&L2)7?Mi?_xJ2O^T%FFx6?77Pk(ELaddgd zDZd~Vy*yni&B;_px0(n40EhIoodnukQkOi*uod8&u(w|R$G=`>cppm4CT%?iAF)_6 z3a$KA75@M(jKdQJWlt|LK_rn$B9CG~6nOXl0A9LjqDFZFgp%lje7P8Xm~ekWdh{4C zskaww<*yqj+i4yX!6RCWscHdk{{Wt$E1e%d!?MRd8fN98rF4v{a5?o7)m&e0-+nq` zT;;}n`i=z9Kx*cMq^LgawAkuJ%xO2r6qMU``EI*Ozk1*w+pFSmCHzPuPb~URmF_zb z-?u{gh^ds+B%U+xVvB}*XDC7+UeVNK99)TI^5WcP#~xt2rCqzZW5o)tc|8i7Ud)me zK?Wj{iWw$N*52R{IUjLf+oH4hQ^T{%B%>N{sFh7R%;lpucBi;E?R8$=QyvspQV$|$ zjtJdaNoFCLfHuVL1e^D&KLm8H7*lb|`fn$dy#8#9SiD`YXk1}yleoOREGYTsWX*rK z9YH>!sn0T$)UmN(2XiD)w&wT+i&z}{S8lCFH0-TPeK$_kG`7xxH%pGF`;)P!G(wsn z)!4qJIyCcoC7VfQZ_W7R{{WFeeQi_1&|#j=7GtYbHZDN2qg>YV<<@f*E0Cn-58ve3rwP1|q7;i{{WLgR~CU?ta}4 z*^wM@Niq6-8HrdX$d}4fMB1pUBmwY0&!<|(hLM)sfcA+&mpIMI=lfO`6Cpc(p~ma= zPTN86*ih=;mJ<^rW*#ETYq=KZ*?s6&ya!djrool(6_E;OE4HSTB+`B%SQ zr;Ve?&Hh`UVl0xKq3DQ`H7E12Tc!K^_5hx!>@_O1jWWm^Z64^1eMY-5H|CfdLB!3? z!_9&whG^usFvI1%k+G*%uIJTa&8h5rgDw_!9ynOB-E#9$KrrJem&+q!jT09uYy6YIPb>? z->UsT>B6kGnY(tncK-ldHuG1nS;FqyxjbgfqDP-soMJ$$xTLws8xTLl!-XEig2uaa zl00{cBarEMPpish^9#by1`_uHcfA*($uz`~@zS&9czX^)`I&G}GBFztN7TwlC;Dr- zBj28-I;6R2=M6tM8UZ3mWtuaNh@hGb?pKODf!@1y=s)q8b`Wd49vTFzD^!SJh1|1i z+S_c-&3LiJZO4F^#a}z5Z&MC#_JPM0&}h6lhb%6hB$Lll9!YfA@{~YAl0=SyOUytD zeP)3dTvtvS7N3o-|JkrfQuTaV&o1$9;Uv5L89oI zZk?&-B4lUkjHWS`(=?fdM8OvakH{D7s!hP5F#j&TyTD#Euz#8 z%*DYpIbu|M3vIY;uJ4(XJN8BG%*KOY)@W;jEp3SZ0E*_qz|(Yro?=Z+o%1A{GFanv z-9zx=Hoy=AS^Hhq(VJy>r!G~c`|R32-Sh9c%tXI1BE1xPauksG?IN97H3-C5S3BR>toyid9DW+)~*_XZ7hy9 z_mWQ-)dlVa*`n&K(&lI4<6>)?mUgR)hZu_)Go}jwp>!iqHyRvqW~$Fcyg8+3>iGGK zg)xIoW`T2MAdw)FO|iy`qjZOG+!1T?8@lLjHl8(j7BY^j;>HYIqtZGz*(7SlN&)id!5!IZYh~Yk1i2Aa3G;AfJ4%sAB2;K96R` z!8ZaesGoh&!c+KaF2vNA8R+~V-UHLJ;MF8p@p2y&V|kcbgd}-E9a^PjC)Hr~2X&sp zk58C^q{)@$X1U2_QbO%C)&(9G&jE6Rb2&~OMWZnrshhLTIXi*et z4C)kzUBQn9O@`rtQO5(M3ACKNy%#edT4|-!OOZBfwH-xdaU>aWw{6q_U@K#wGyxqj zYwr|V)>`2LB9T;xpAIya&)<8B>8zGU=YybX%-3g zQr`owXNRUR)T!5KkXj^g+vVywuQ64|tyj|~FK%fwRb!^j{{V`mESUKa#RrJe80^yB zWg_!$6I7$+9oM6o3ffk#l1{24NfqD9ed#VNvCHNaJ)L&8^lybz*U`@u@Et)A<74I^ zig;yk-%m0YQjhFNV#vp_1UF(j7o_8^Hbz&6Ck15ER!q$x$i$hn(Ya*DB=NciZab41 z9?RC->9o@=p6k8$`0LM_&Lq0WQP-kBgBXFGC)#C<9C;Y7?bJvIp5l)kzcKmho^qJa z(;C|&1p&nm$^~C>>Hh%mM^fR)o>nIJxrA+uz#dD*WlufsJ%;|o^*&@nBMF)wWRGi5 z=hf-D2jBj^d6vr`1pvri_)jh7(QAvN8Q2be1>gS6* zR53i9ZAvNP!p&xiY2#w*jp<$6e|rAM{t^`ga^fg(WZe*vLbtIjSlIY$QU|&F^*p(a zGK_so9dmHRhU(PqQg(m`0EW8zRrc#>;VV)ku**)PZ!vzon{8&e2D?$U3(>qjnb;a! zc^J5unbS@tnBy+kvk^ir;a-r%XtLJ~TK5BCSH&J3Y&@BA^!J|$iy86CuHCf6ab1As z$8{pUIyNDb!_(p8qDiP}sXEOZ%JnQYvt*Gf^SllAoP%sA?xMvOb_a}c;SCy0!MxgG zv(1d7D4H{TcM4b7@yIJ}QK)e40BE@Pq^$Et@h(PQd;(}!8&-(AhgC(7HaFd2tWa(2 z+}IrPM~;nP4<+&j4n9=J9%CGAvm=tD%3Y;w?>54y-ygqO=Zdq&Hn)?3k%1&QYdo=G z&x<*4%ukk7umH85R{cYPbPq?gEp8fvGI{3IW{L%dEzx;sU1W^xZsA+fZ*?AcAv;8Nmdup(8Dz)Gjy%msWa`fv@5hoar9i}uzF3#i%0R9j>>K3QR}N}S zsC5lCTnBe0BxspIU`TE|19x@P7NLQu!HUvDs^&B@298X8wa1?sz+*(N&_NUj1cEsB zzJSZAj14`IcxPM4#0*T5;A!%RB-%ToN$EChRA<`juAz)=U>N3~&!xN34a9ENH*^P5FrFVi6A$mjPT zew?&jPf76se7_G$(m^b$SVD#wVPbg>2(@rQ9;G1B^>xOlo1KBHc{rI$ET9J^11TN7 zM0fRA=iaKWx^&VQhGk@R`StZdZAVdbnOVZ7MkIzT%xrd=C)n88p17vkNU+LjzQhsO z*e8yhG>rUYR{9xNE;U=q#hnb9aKstkV@Fpa0!s%#z$oQcxUnv7o2v*$wSxL~MQjrx z-5iVR05@VOiTjVAni)P8ml3hGEjKA;II>3g(<3#=&ESPb8<#a zhUfDF2;-q^o1<$P0!?=tE5lmONVn8qM`emNXp-s^&U zj<{heG-jgd8;@S=yLJ-~5O;*ex}JoPB)i`qA0kzX0~uXM9oCqqp__6sqv^kOTnk{>lc5%(4({II`)^Uuc}TF2G3 z$jidIj5%o1+Wn1@K2DlabS4le)iKE?c9y5MX`b89J)bBU(>(NY@xY}l~ACalU zCOo1$hb1KQJd#fVO)n$habuCwK9{6H5sq1;n=mMEMpFj_nzPF8AExfIeEoM>k{oY8 zHxdE2V3!{XStcMg7i1|`cG(tq2cE9@e^K#AiS<}x(X*t|abXT7pDG|0LI^9eD&0hP zBwxVo);=PwT8_+YdC!)y=9y&>*6{LAS)LEl@ko;wOviLpKZGekH)r+kJM<1sJ4BBx zvC(DIW=ZX4z?tKeP&^e6Rq??eZ+@rD@ixDtX3sWOI%oKPKoKRyg=do;)`NM97$H;mu-XAMYy)GpbJmU#&Z#V}NgKg2{{Z&< zZG^2xmcyCl9TmeiV2)F!Yr2GyhhQUMl175T-6Av=Ew7N{xB|$osJ^$Y2W))UG+jzN zZKd?WfDZnq^DO?OrW`EqrV}DY+gXYo)-A$nC*@L~ZVqOEJRuTa8Ol*#BNHvj ze^R92kfyyrUp0NW>xa|^qn@WLOvIjL1r~Yd4Ye?jswa*Q!M@%2u9I#X>CZ6QWcmD~nwW;_=tlA|qL(4tPRN4} zSK9I}JYlHN75TWZFSlMnqo|SEY39tCxsjcis`1DG8Xs@hpfdje5VVv9Ihu3@l_uk9 z40{4iDF@hl9!(CYWPcOlf+SdQGSOTOrbydw1NuUWx&TrAy3%7?Ou(=Mbo-r%1P5Pg zaLC1j9a1?2SfYAF6G^*ud(gXLIOhKVYw9eWQw}*q%*(ndB-rK>rAb=sJ!IK6L!OaO zj$T=1^CQlLGY!n5NRg0|Xa!px>iQXptKmqKNWoFV7>3}=Rf7Y&x5xJv(U?P=Ma9SG zt`<;a3Dq}d>j{#t9y8A}f-lSz2)@N{^!WV`L1eYJD>TH@ErJvi#f2PSZhuaP;%iuo zFl=nde89zA#=D1c&pdsPMgF>3F<{R)c?yiIu{=Z+V0a-wyB+Kc{kqU;rVn&VP=_5= zipF{6$jFx`E=E*PWROOzr;=EJYP$jV9WQ?n!a?9YQe1M_sMP|hH|H@Pj>Bgp_BVfT z()_kIvCER}4jTGk1`_MgPxKn=tZ`ittuZcIP;b59XK>z6!|B-1n4m&@JQRe-8caCs%WS1=)Fm84jf z7>n3dPyhhX01E@2c;lWp>b6lbrY8A4F>e5N05HA>w;=xjevUvOB`LZdc&oTNiH9XJ z5V0#TvX8NVv&xz@YUt7ZI(z;eYuMUc_{7HTkh1NcBEqMVN+3|9unY~6!3;ZBS)QE0 z7u-E8;(;BTk_~+S0N19i8H@>#(UAT?IWdoEBitjEPrxe5X#5k@HX1{bKH}!D(%Nr_ zVadpsBZb5gD@Pg-i5mNQxw1ok_tVZEnFLJULT&P!Y8H=dVMo9w5(tkU+rTcRCWu_Bq%Yz%n>?4yQW7->uBSUmx`9yqb*C?p#RH zyD0RYCxpQ)u+4pevL1A3eGZ%{+0m`i?@y8XFMCK0TQK0LWMG)G$ZI&6t8}azoR*TtAgAF!Z zl$Wb#oCxKgD75)*NJU27RqQX?{{X1>JyFy2T=VU~)V#>y(Mgz*`hR{Qw|4nCU@eKr!L{(QN3SqSbd@O%D;fzN)Wn>8J= zr3#~YeCA|Su}sH^~Mp8lRcTH~U+d5;fB znmpN*2xKNj9>kPF<*u1H}wm^yLql>|<%ia8~}K^qJ`8YDJ)qL$C8pPQUIbQD@6H<1)w0<1e>l$Jx{FX$))KV zqFE&#N8$OdR4ixHeEN!lK^zWvC#CCsK$F=~8rn}@>4s1MXL^%V)K>~i$CJ&K(_%uS zVt^R-u2cd~H@M#w(wRG?-7xy8)EcGXJ^d;>5Bt8MpD!Xv4n{=pG^_^pC>7jLqxStP zp!vDkZc-dY@)?PYSo0Z}o&u=+#PQRZY%rq8A9mC6)%NfON`>yeh~wtNizzvQWQ5k_ z+7FljA5+YE=H#=YZQg{#T;l-GJw;tGsm-K}yaV)DG0c(WA2RX@{J{!U1aK^0njA9Qqbgio z8V1vKT&-G6tX0KGl~ZQV&nZ^jb^!{c?Y{p2+os(^!x}bhlFu>9C>B3DI3!gC6=`W| zxdBfd{k{4HsCauOY^mN^ap%R5zEm=Kl_Vy~JGWJX*}L6e6-T^1RyeWXSaRaTEQfSC z5;a9fpDn;4kkO?)i>_~_Mk%j3v)t_5Abv!vh6ad_-OtJ|9QfK)OB4{SbIMPbj~^jN zw&Hu9)=$50j*8*LqBD`7F2$e;W6Apk?n(F^`c{WC4<8A0aFO*foeU>WSR5(Il0e6G zwY~6 z85uBX*m7lRGA5aY5n&*c{o|2TqP@lP1=j=LtkYicc4vvvuy9o2=?XV}I-RC(_~kv% z$X>(!1MAw<+U8i!*Rp)y!~8gL;~^rmep(M|B;DPga(U{%^C{)i&I}PIJ}bzwumahb z0tY?R0K^ey{&=pBMwLQCvi`n$=7UnJNQr^&rfj`G4-3n}-IteRe5!Us5dQ!OBfXyW z-?j7?KUKxUS+li_$f9N-G}1L+!hzr0g%)`2*Ko-mViBj!7D*g_41$5=Rf_|)SiZCU zZ^U`{lWK5eOQ-7kbcDwoal%XyvHt)I5E+>Ykzk&0tv1pv)Zc$yd!^XZP{QxVI^6T* zM;<1kpG3?*4hYDvO1AfFvTT}K6}P21aq{zVH7uc%jWjX&OOZVD0Pf6qR8~8j*ye{} z_vMR7&~addXZV&?iyoD+@r0Em>Uj(spGgcuj4^5cqhG`=3NSmPVy%ykF#N1+ITBptn8;X;R>0+(kOJ2~7Jbi0 zbgUU>+lir*Bw>opm}6ykpl{1k2G!h1+)eO*UZKFk(mXeb7DtLQCW9g$7oF&(ToDv?AeCbzZzcJ{Jv ztE`h()#lX8%55P)C{aAKQ031ihqoP0HoGbJT?NB-gRTCWsKZlp`@%r? zM{_(!D&x!iv8MI$XvWZY4W#=5 zy|!I@_cl}XtUo_18!s_m>EMnifK~M!tLbX^_#bb-TCSO(W$KWur2>g2QzDr`cuxl0 zA6DuGtco0Ud=wU%)y}p9z|SsdmAk#hDYVQVugRAl2iocDl^6lF0~37qUVmQSJzvxD zC(F+mSbJ7Rn`Be@TbVfZ6<&E4-|jnf+u*1p)e|oRE^H_xo*7vdblW0J-D6*D&jO5ly5+p&W>E@NpV9F>KlzKzFkm^Z>X(N52Da$@LJ+RqXv-ZAR347%n`n z9!AZi0nH>Sw6rM*2;a@l|qmLL*&A;{M#%I8$z7{<`x)@H{&%M6j%p zwwnY|4Y^b8MGQIgGKy#94k(VQ#f^l%e2_FVWhn_H#YC(ecO;ST?|hy(9TLmNOsN`8 zS2ApeaYuZ#&u6!$sC#Wd1$_0?xma2*0Agap$4(R~2=@Je9{n>;gM+ixGsAa@x%NSI zSrEb3Efje8?;5OFP$o1?_UvP?QRSO&$@%{PUWT0PhJ+kcGw*W}OAKt!Gm&6M58L0X zdSp|0vpQTukeYTrG#^ux(nvhW;3k8xze1mD@AK4B=%ZK4$8V}SSBCPX-HAP{x!Ryq z1%wEAiZuZ8Kwa0#Y8@5zg9V8EdyjCUoigKaleJwkU$0`$xbeph?0IsCiHdT4G5VO2 zLvlr$vU%y7!{1ielHy0>Ja}=`p=fc;$m$wIRcrFe+E}P>i{#Pf=AYo)1E^%Sw~djc z>1e?*Fjp|-I{R#>H1Exo=dt1iInl--3ugX_>*O1WXU{;vKE&$jg|n| zwOgwI_phF#%G9xpY zH=R+PG96nIPfAOS2Go)`nFw{THnQ?Ph_X279(VA&NY+iw@x?>dIPjgm34rdgXB zEXRd`j7KguL5-sTfJ-H#k^!-8ToMUX@h^cPorZ6RFyoF!i_M1{%&6u~#BKoatO*_H z5yxB9{;}Hzw-Pcqi#%yOcSWbx0$tc(*)+_J+j{F%kv54Wx(Z2$g6*qdNYUm(u3Y3o z4J@&qLxtf_ZrAhF+D5XGcz-iR*Ris)^og1`#q#6}^v`7OLQikZMIH_N8tKEr5$7dyC_ZFUx4qYH`I_vWD6nRFmbJ{H!n1 z-+Js#Fl$m{!$Gn1>(ga|<~h-Q5)XxZX%4@qdHG@t43x-NGGJ)}6CqN{=%n@_5J0-I z?0RI%!;G^?2jc^}Hoik`+h5q9@7L#%^_mW*{{U8nGVxo>$Py%<>)elPH*;chU%>{gJiX>l+N0tx)A2eIT1 zyNBmt%-GQ;K_D?h!IejSr`f>dU&S5|0kN~S92}$*MIgY*3zH1-#6rjynkq*O16_6? z)%6Ym(Aa`H^XqJ(HsVoTTTWz?E)S5r#4<=6 zl#zJ-PkZ2Xf56@;k1GdI@Yjfopq(8XvVca*R3ngY@dw3`V!HQA^7LsVV=Jp-9kPQ@ zy;i{8@5+!zV`lmd;_N8&ZDt*J6>k=K*K~+Tr6PlxssJ|Q{{RVpj)hkxQc31NKPb#4 znjr!#9aF?wbUOAs>Nv|Vj$A<}(xL`6akZV6$Mauc3Huy6N@i-0qePE4(;1-?PP;tD zB}9F@u_|NZ)3}T7I-}xT40#$ILk}UR#>kFH=TQ+17@-%pXyV0D_u$`he-R)xnk9{8aU!}{?zi8ydVBr4x8jISSNkrf8^-I8 zz0T8ehGLt7Q01I49lgE*=r)a!l`Ae@bfM%)o+!x$OCl&;)Hv=#b5=`zx^9LiwrgHA zGwY|arA9y_a&t)}XjUe6c0~XN^)Cc*Uc$-#{apHQ=6Hc-J7T4dMk`0!9YWc1@ z9i_3rC=hwL$?15HBt>?>SGli$x8I}rIFeyz=Ok0CnE3LdA&p8bq$cqtRUb(=`d2+= z;=!iz17Fwo=C449G~Y$}zsFcj4sMwskcmtt;ctjrPnq(f ziQDNC-iHgh2q4#Gsy{ZJU;ZI^BUse%8Uf}(BIYX=p(f=}JNK~7+ueRTOwmqOo1dPD z&kStKGe<=?L`yE(`(6FGJqn9|#Ro(ECLMNh3-oV^Ry{{c(et1I(PQ%>nmBBsbtvjb z{;NN6(60%WmnRlAk>DDX9#n}Rq{AY{2yyVhSn12bIr>JeqoZMC42Q+Vv5z!cmwQF| z0X@hz+lRRC)^DJ+x9N#fgS3Xag@T-1m z3Xa#nJCdkh<-Yv~@qR8krm2~QjL~+UGaEFx}2^-L%N^GzEhA=s>1$B#q z52of5w8!J)#TKb+%YfZKpOu~_o{cm)xNjajbF(u?2qhOF$YYsB@+gER`xZ6wM#ZXR z_-j($(upLIf*0Ex?nXYa!a!4yPbRAF$4n5TYFKc?3{{bZnLaGEmLw%N2`}3J01R_? z&%o(-#6m2MF9$gz21B&50C7jNd~rZ~ao489kx`jneV66)DO25jmgKpM{6g?VxjKeM zHlF!#vgRyD$xWz0-yYy-Ze=5I4e0AP(_+!5GQ*!HGrO)fS&_(4 zKly0t7Ef3oov51WYxozhvghXMNfJ#Sp&F~Dp*zHYw(aNg6(k?I9P~bs|D|7A``*kjtk&C2w#%O2LVT|&stlQmznMajm*3ymn ztM#yY=fnB&MgL$S?eEioz^_&@We2CjNWC9$nLebhmvA6-o<2#`B4&sFQK)4J33wec);*S7D+wo0D=KMto{1RHQZc?Ct0V6{X(-O_E&LHQL_*`e?jf;emdhz&dKopotAXj z&`W^QL9wF+61)d+utqj*mFtBVXkd8jtB?F>p4=7IMme{QOHl6a!cnhbd6l#D2&m;=Oq zS$bwZ);5Z-ZlKYlK2%~^Jgtu!h3~u6cK-mG9DbiY7u7U(7|~?N6{Qh8enFy=kl%(m zB7nN**n4#CM|O3=8g=;hFR|({+W4MocF%Oa+rHE_TcbCYz9o(_!Y~2+raZ2_izPUju1F{{W|}S`JTrwlEKNmuc z^=nh}vb+PPPnwVC;N-xrWj4iKb_TJ>A%VV<#kh=1gN2|UQV*q(n_$;*goT5W^J!3t z%}ThNr7gfiu|xj=n10>Q>(TuiF5!Y5Xh{`c)B(5&`lZ; zx!Q&->9cbNiC7AdIs(T30K!>Vj{S)0%fFdV~07)E|C|I4lJiOKwCBN7!Kfc zX?P7I{YCuaKwl!65RAtdYp9cCuMtF@3A@^Y*^0_>rGa(6Tb|7jt9AW<^G-aMt3_ zY9RjrewlNDVLOrlLxA3fXJ)=R!kQC*PP>@7<%EQ*5`F0Hr)%uZ5H475cP}?L&W2+QmpWMYud)O6F^<697O)G)(lL7I>v>Qq1ZXW>A=l zP`hjz?4#fPIw0}+s_d0y5K!=>S7JU0{{UXItp%3~XKYdy8DjveFAbU^*J~oY{>TwyN#ej*Hwy_&{Jdik}#U26TyY!3bQ_bBmx8CTjtn9Gi zA$ybJ%?=nwLgDIOX%>+~4$<7*vr>*n`Sn&08)*{9BV~PN6NxG{l0P%k#TF^p-^WmD z+CDB6OsVHf1pb*JMKUsv@hg5|*b2XnrSSHNpk&WBJI{pjNE6eR;bdM(8*JG4BklY2 z#(X^n!6cr%7Xa6d7jbx-MQN0MV?-lwOENN!_3pioTxDyzdPgM5l#c31F&AQGC-VA~ z4@u&ve#fR2@a_?wc{KcdTvD<)NQg@=h5s*Bd1>H*@7 z`}Z}^OMfbZgoYmy6!u^kl$R%oJVTd^A56r7(4dX>Va@>MO8U!$-F7&u_Z_-k%G7mz zJyhi3M~q}UkxDXlqsreulzUn0UB}Y0@Y5DJmmOk;Hb(O1AdYO`AbScn2>IzF#R(bI z4EmD^Q*FY;H4rErptX;S?0SkW!@2P00Nv#A@I($ESt`S;YSBm=8c3DOmfV}{@W9=$ zBZ9;C=!QOCv!4OR$jp(V@`QUoDuorm=e2M;nmKXgTaFBtL4Kykdfiu6F37&!`i>2E z8&An}%!X(dh}!Tn+Ya3OeuQ-6jtf?aJf&AXO#oUSfpVwP{{WcECx&c{oOOwmpW3WXQIa7Rs2q01Y{{UXIh6S}==hGlg{eD#Dd;s|=qE8a) z*>L%I@eCMUM%2YB9Ge~8tkr*qo1^p5Ppo%IJ-Dvx$pMJJVb2|B*gA%x zl_XwXE+#AhZLc@Yam{{J6@T#GO^^(z@Cq)TuKkWmMREZ^00r^-4&BF2(rzCP4fA+M zUOq~W4?6%(dUhUDVkSbvA}oV?sVX zbEXxV02ffrr6y}inue>9EO8c577HYCil8n306Tu?_8nJ?!+Jq>jN_SJmx&}VwAVb6 zLH6jDE}NL-iE^SbRe_I;_D{~@00Zm?UCX4$<+|jY*|w=ZP>3mW?4yy%JOT20ILHK) zAM#29+IE!|N7CY;e1!($gUciyPbR5&?PmM;rn2|{dc19>skw7u+{{S3u zo;#Cc-}pjv{Hd~;n6yw&T~bu*J{ZrHL2iDxe)0KF1axhe~Ma%qR& z{(4u}VBZkPF|27MV91`bSepd%@y~Pb_8l{0ZwR$C4z5WG1?~XwN66#bkB*e}-B0-> zn5I-|G?$d5nMFw$a&Vy~{{Vp5qyGS8v@tneIt6hVfrPc4rXMO-#6u)y%QOg9fg|%r zdNju`N{|8PyYA-{pcz7Bha+6y9=A*I@EQ}tbShUUf?;* z$AcXq4#nOek*Pjz{j|S->fn6!LnjU4R9N?>&7~x>b{N?_S?n+Ee?5JRBCOcu*a*YG z*BD@|rBsFlb45jud*j&jek^#iF?`IKW7``@kj&DmHsk=%8@EwHK1V0uj z9<}vXyG@lH3Uaf&Q#3KfvNB?A&Z>6>wcFeZB>w>K(R>WdylDQnO^NYN#T)#_k8hf% z(B}9D)(Ejjz4quM;LVMZaD(*_$+{L2tbTI_{HooQl>piI1A;H73_V)|#2E6zP{Er; zvLTusrQZ20obh+a?0FVCwPrS_cw8Mqqn(h*P7-O&;@vY7RMVx!{&R)p&kTqGQq^p& zY6vz+BiQl{9*61B;%n(J#EEpxUmif&SY?9LmD#>Q0PS(g{C6EJ>0UpV!MgO=`oqnY zg2@{BrToW^Fr`%TeM%H4NxAuU~$5z%+uc5K02~d?1h;_lP8098RlhK^n9bfbw#Fu`21w9;8n8s z0FpX+jT0^v%f-frCMeoDaxlZO6I5k{h|5RI-RfWs4m+z5D{2}_#?2WbY<3_n?{9!e z?0yK~{{WXkG>nP-DV+u>XKgllietMDB6DO$ek_tycCtYH)HJKnZFZM8Z(VI0EoBU- zXNdJ$W;TTeb~HH}Y^)Y^+=C%%UU(}Z0IB?-i}fvw-QT7^2tx8lJ~nJ_!WkMhhF~|S zA-8U?YX^&?-|f<#UaJp>@*~t#O{r+D3Cc`Z$yRNtO&Y$^8dN@>N2mlh$mxen@l>-( zhdeWkyk>tXb2lOialm-D61){VNCWNX>7=@Nta`4@r9Pv!gVVBC39wb5eKt7#8>=fhbssEVCp z$aE5HBv#i!{_+``PL{PYJAdR=Sm)oz1^ja;XT>;?Ru1c1l;&@~d8Nx#p zW~cK(M~&B#uMuBEgWMXc6~$TXEZFr7U#`+6SBi5|?5QJ=cG)6vXZtwzBdpU@@K&** zK_7^8K-rmX3;lj3I!EN@HuiUAkdSN|Sb-cU*lUaOT#Sq74^7ejJ}t9F!gh~O=;(o3o9G#fZ(2z(mk9*SrZ?N=nXZ)B3dh`g1|r87 z&D>DuVry8FMdhwcF-p+n!7u_$X9JaS-F>+1!GRVJS;ziApDQ{k^Re;ZpUPqN5Gi!? z0QAX6)wHdvp)5rL3FLHJ!=5F>@iZBl{Md_usN*D1YFRMHZ{;GhEU0;AM79ow&dOoR zkWs|_EQaPHBSJL>dV}T>sN&k=mS=|b9%d$QhV>x&UN8GKD0$@}kW^)uP;J3W0bR%= z1Tt8SDt`sc{owyDag}hova(31Z=(d2WV45 zxd)y)QNKsRx}bX+WNtC&5r3If46a%P`mQL2q=O|B(n_q9UC-O+q3^DVgab~4BRUL{ z%4LQkvF#URw-z`*Kii&?^luR8+Qzkwq3PLB#jZ-q9}+yEWIzFOb^_OG4OsUbIqDjQ zW;}Ca_-1TuM_Lg!Oa~yUp8Jz>wV$yaHCCgj)D+8L#@_DO+ElWOUefH}l(Va8S_#$i zR$QT^c#<-*M>#^0MIiu!$J6Elql-UlHPyxOB4U~1pHRcpjC{p0Pp2+Nec;GN*C4G} z2aE4#C&qa3d2o21d?P6!pqCxC5;#7Y3YxNbzmB4pTJUy8OtES>{t^os`dVxl(b~nD z^_1J~e}1j}tW!i57};s^UHp0`Vd`jnTZUOYm>Vs(dK(IOat+;f4z4+|`F)RFFN&ni z-8y-=qZ~MqGXmMN%T>6sHl$Do@6{g<{{RwvF$9ufX}Xqyp-USiabsgi3`*`m{G#@~ zcINETgQ%N6rj8a+*GH8V-+~8JA5g0?Qi*KsFh4M$;aJfj;GZAbP1hjt zHo1*Fd0LDzV0uc$9L>4U_((+`lpk^rAHPC$&kg43SVjyfFtp(-my$=t63E85c9KUX zMis*l02~2bH%~ByxI`bbzIfM&~&Nu4WBtDm&*kY0gaQzwVU7% zo9O!Jy4RZ*mll9k=5=r~S)CJU+Sc?NkwglszG}KVX+D?S;@RXs6Y7Q9=Qe}q{U!Wu zFHOSAf28tp;s<&1A`v#@+Jd^d{+07?i1A>gsIKmvZ_tky3Yc&kzIE~^r0^Bn_D$uXw26AXBA9UO~{GM(zf zo9qPxW{*Y`+g#<>nJ3Z}Gr5vy%05=3lc!4_l`d{>;1Cxn9G+V|N&#WTntw{|s~~?( z&|J^U@dlvBFH@3iD4k?n7?B#KWi}UWfV=`MitGTcs$=Wgre2{8Z>nYB#u$W_6iF5% zRk%bH2jF%*4hiF<-X+ta%@N7<^T{K?(5j@7mUzLk$b|Z>k9)2<@8dFsd3YI}8_t?Q z)5l$#mFc+FWHxe+u60VSr$}d6;%u3Wj?^7maVI~Rga@Ad9z_w*&A5dkOszuMmfLxy8hFX>Fr;W?)$vc%lN9CdKw{{`b|q{{RBk@>HK|F4e{{Szy1LvVrYa(oa{-);6bBPqsr$-zpIRx;| z+qtg1jty2_{${s1XYM|g7&q8h;2ZV;{PcQQdW6Xl*6RfY^w=O3Qzr&l=1gQ*CM?gj z!|!(ikEzX(LvQ7^0Dpd@#>bN@7s=DjE=scfKxXyx*++Jx$l9TKH@kz>`3~5yK!#LF zBQ590v?9z%0ZW1K)@t^f7swrZlb0}@wilB;D;r59c@9V+J|5Af)!!Ey382DU386|yJH1|& z*?y*ONDMd@O>x)g4=y#ya{)4lc0!@0+`(_RJeKF4ytmcxv~YNlN|7el_53eE^!l%@ zLo@f;WE%BnY64Rrl;y&KWCe(iAyLk$&Ztcz+}Sf zMd4=K7C`nZCc+qtrw#44{U^}zIq3=&H5zdjKAzl`FVv{zd8o|}y#D}wYNE|B=jnO+ zyn;9uY-~(@RtLS2WG!R)rGWmVF{vk#pqYf{hC3(yhfWvMO_w5eTVhp={zrYk zcfa?cLA(o}g$IaqOsshmH$v4hB8Lwqh-hYV&5p!&B-6n6dt3q7o{wf}{{T;`L!>ZB zpE2G|Dqx{R?w~Z7G9KP-a})mnP_;bs(zcJM#U?(Xr+Lyr23AvLLV-kYgP0|`V-<8( zRaPoE4Y>AU)2!`}<2?g67g%M-%nssn5F7DlQR&G=_Sp1z;0?Uj9W2t?q127eqx642 zgaMS2*93_@u0&EqN{Kw#0y3UJ^E}wV9Ean#u^jvLdm=W*%A0B(g^QFc$reapPZkI4 zdmo;N>Zdzh)3UW4S)#@94xD4e)RHKf1lb{EVVNE9(a02EU>F|Yf^K2QkFVeXm67Dj z1QH}A7jKj5k)3%bdaRbfap`3uy6QORVPTa7x72@oklRK{X3?TqiXdbVynbvb<}l2CSEx8eB|?BFKzm=P5-o zmf-fSf8;FsSFshBZ_5=lRhkvtbtaXp{{odvZ|;00H;}cW{{S6XWtt8~ zSA{h^1DzMvVq;_gvCMqdK&7c${{XTjJ?(BlHGB@8X7QvLns3u;Sg_+H8PgY^8H%hx zm*oX|N|`x43ccKQ#&(~BtmC%v63WXlS3(ZkQdes)1gSm80{QpqZCPN{jz(dHu(ce8 zEtLV?4FTfoRVoY!sj9ziQ41!{Oh z07nLyL8}~qc^h~=AJg^ebQ$t8qnTC*-{wa%l|@>szRSrR{P0gUa@}ZPv zxg}a{E-iaR9=iUJK_CY(>FL*!+acC*l7FL;H`8)hxm;Y_X3#Vq=8} z`h^=q9r3ZEXdlST4UbBmh<#$VOXK6uh?6R$uZuITOGXdkAx8i<($`_Vuc)x~th}E# zH;JDWnn`@fVv`=fNh|j-ruK2qx^~&jM2YdQ}a84RH@k2w8Zt)E+Nan)U^4& zo@qSEB#|cih$)c3@jeUa@$>dbT2DFgDXtihmV~updGRd zG2{RP0`%ws^sovEWui&$Iq1f*qe2D(fXS1*M%hugMpU{D?vem#QSE)#pyNB}LdU8@ z9$q^_@pb@Dun0%7nGlqTGf9X!-5OHPo-AX#wJ!A6CYVyt|S)COeVYM$^l2Twdw`ew|ktBOl8x zkq%eq0OBxhi}xH*y6wRB>AF-XSGxu0anryNe;*{RSJh>lZOtFX$T+zZ7xO-$m&%#r zkffVkRI-)=h#;x3efsA!Mbfpl+o(YXT#>n3m^DS_6D8(` z4UPlEn~y37`Y{#!Fg87I>m3=^JrZEfnc$Q0hgj)hz4H4CA;d1j2B-pSh*GUhgJWgX_I}XX*PO)ol;VleY!n-$)^lVI-aaYB7Qs#*-&Vf9b zqW3CGhHI~czLj+^;ue;(d3sba=e4w-SqxLXJ=iAphNIfnyL4WCHRMOg#e9PDx{28& zL{h+QvQd3Tfc1Xf-Ez8Q$`|T0vZE|$53X`aCaZzgi$0rAC@ypnzWntA&JxEE=`r!_ zkS6gY8O4sXv%I&Aw%-CBVS3gz;Aw!j9i46gv^LoGB1~p6Ucju4A)$Hk~)tU z#B)dDpXIsQ##SbsB>qCSb|{iIb3s6VV|{}QZhkAH>ae6@NpXZs*6q9mVnvJF>}%L| z?bWE^X%a&~F~gr8AEio_DhMR?W?0A9YENYvK+-w-@m_3I8x&Q3#Oj)w2_+Finc-nL=!-A ze%y4=V(ITl9RC1F0y-bHoe$yOvR@u;Q&`lY#GFRLNNv?3V?>a~!*D29zqd^1_)n*k z8s%!*&&ObT_FRcP zwwf3nLZzM70OVZ}{{S=7fvt;~LCkgq&Z@CYiS%e%X&Z6#ZTA9C<|mQtIKRDhp7`G` z4F%FOg%V8ok~Bm_l58mHCjEt!^W~BIc0Srm5~LB zUm|hpbskuA8aNKaV;#@U`h^e+abuCxI>fJ#=_JM(rV+pZjuk{cVSW`mep0jm`08l$ z-x_SSiBV@65#*hS#e)r_f!H6!H~aSQ)tx?Hsqr3EamKPn@npoY@OLPI&{~sB02_+k z`gkI`$TqssIzk4#wKQDAnlF`rBz`%%B-sFyfT0oSg>o6&s3%)FPesm`jyAc9tY{g^ndk8 zgWpv#5WCr8tK~?BS40ZX!;d8M!6eFtHcDU`!vMm?gFybFdZxt2j!jr?tmzpZ z9?R0B$;^;y4IV@|?7*(Zjy;UPj_OA?1$=YY=q%k8v9+mjaNTtbhjt-hj)IN!58HqV zB%j}}&w9k!0}goM!p2=YR?CtGl6C>r%7?MN!StCo5J2E4G)O1)r-w7~b2J?$Y)s$g zn3CYYQzhatnb*q!UDx_cZL$TBPfW8NR|^K6=6P)DEQ41L+TU^ug{ER+ANGlHbF<8X zFd4SvM%P3$5;u|khibluYWmKdlcLR$9;&%|iQ5`u#E%lfg?V9M3Q~C;$sZj{;>clx zRl|!g(&h+B^JGoSj-U`o9ft>i$EfkV zN2cl6&o(qqBSjP#@dbUiXj;6!cF_jt6YpaB2*cB-->q}J++XM6AGLG4wCp%0oOVon zI8YzMiV?|C7#`%2zy$J1`<|1$PpabTZyuT?$Cny8R#{0q%+e3YiarI|?`Mvbb?+AH zn%amYk{EH^P{qfvu4}WNN#uRN??{{TLNX?`Kd{%H)E(npGc zkCe$6L_+*EHG)ULqjr0H2bm_+GZIN)e9b~b_%R~09xrVtY76c9lkwC5WIlQcCHh>5 z=2a3imGUGk6>5QE)<`$+6O?k~WaJ}hInm(9y2+J?m@bPamPL{P z9M~4zb~kei8xjoH!NkXCkVzSec96(qk(7p#Ku59dySeRMx=rx(DUF$tjUk)sqMArn zS!4n?lrg(*!}Y(h?bF0rQbCf^HVXYROt483Q@gl4pL+s`=a10zo+v(}@{5yjG}-H6 z393*8>ya~F7y}trK@5y46U%T5uWq7MnNR=WJq@HUrd8&^(x-tIUVVK{RoyE{Jkbk zK0FyPwOs6&@p5I8V;pD#v&a#Y&<>yrUT8AkC#I}o(X^_sb4uj1IJaSZ1Nslw_UIm7 zwsUfm6GnV@XC)spL-=ZL%BdH;@Oxi8ck5;J+m;TV{eNjzIL(4R3^;l&nGP%>Ek6et z1aY7Ma4+MoB07$$*}up!BL@-{Gv!VAVlj8KwU(p1VCU6jue#o>x$vP)KQ0#3Bl6lz zytzd|9@S&9JMUmz1K)#P>}Y-*$P~zK1s(8!9BmDG9J}Yv415VNmZUn7%-wxs3V3T@BsC7XGzn>SA;P& zEPR-Zm}w+iULc3dXJ0diBuFfU4L}3iwv`Va$yVD#SN=hU05mb3_)SWNu?* zd-aW8sG{nb1oybui*3Efjn3z0LMEaz8ICvPb42a}NB+XMQBvHjx z8e32Shae8Z$?J@t2g>dypH;)uS8cM!%=VxFp0VG7RoZ~>(=>X(PyxX| zdE}GH;D3?t-=S%$VC3W`8s|m`P~tUk%7ByV8%OQ>4uMXlA;jk}H*NXdVPp!0rp(u_ zq^Y#rxUqBM!p_N9=aEW9BJsF@J-Mz2W80#!_;U{$dBp1;GswpP^=A<>^9Ji#W`z z?;Im`Z7p`d5J9ua_O7)b7Wj(;1u%ZKGV*Zp-a;1@mOmjvnviax1F#%b0qxN?)aKHY z7XwN#XX-2oiUg^Arga;LMYZ-8T#`ttQNb&t_#HEFGW9J&ES$)278lFIgDGN`RFxUy z^34&qXcpXy+yLVGVbitEH$j42oioF@x@6MAK${~XGy$xDts@oWSEwle06vqW4<*^- z-+#nj2PnH!M$l2^+>80mTmzm0+M$G z{OqQHPX-5=@hbr&&Pnqa_jB$GS7K~-`wCaZHk&d~u-bO1rH6Cfnyt^Gi(AznQOc&} zRPdX(0sH&+A0D_PXhaASEONuyb0 z2Vg?p+l7EAKR*gj9{Uf5^hh+VHcTBZUn?RxBg{!`7}-^VZ<39#EC{~ez4VO=CbPRo z=uch=$J7+YMydQY;VASWruj;%s4}$5{{TuGZ)*fI5$Us33H5IF6vLOQVzd%Y*eLV6 zq-_k@Y<{8TSr}xyU8;Z-9>Rg=->Xv1pQP&(V`+0?MU#xp3$*FJFHqXBjY#i)Ng_!z~OOBhk zj<;wKjVCfp+>&(cNWO^fEi~BVB{w^QpUm8nD3B;!`99afz zmXjiTF1wASKRbPw-?u&a>QgI;8CrUM5(3Lcn3J~0 zw$MnoG^6LMSeh4~jWpR9{{UH<;YJ)Y%7+lC0GZ?{OKlr~P))xjeLVENY+fG?_Z#jS z->s;$@bxO(X~hM7VhmmAnMWo`W+FG-talJeP^v7|aC;8jQlCK8awL50lsasLs$=A5 zT#{QKNQxyCi|$;3LeB0we~%6X)TYbBf++F{+A>UPtBoHu6f0E{4ab4%H_7O3R#?*{ zn^4A{OuVrXSXqYODI^6B%I@rJZa%I+TI8Jic*>Q`HMvKbACEsR?RG3-)_oQ1{ToWt z^n6V+7-LN!IG;LKkjUD`NLt-J5Yi}+hALPBEOrz_OPCiTLf&phY`F?2mE*TG0)*T> zD;m)&8t^y+uiVbDq$MqLOGHpp8HTqEMzQ`F%Hh^T9n)&ew4;)JcaSo-_DL zo|b#N;15cBQxj+4`w-GKglpE`y%jU%HcS}!zfN6pq;EYxp$eO?Vl4cAgSS$7?--G{ zt8E+PAlO0fNFN+yS?>N!~2hCAZv zl1R9zx!)&waBKomNh4|j+}At-$0P=xR|bJ6*eSdjHbCUmr_IzG>9S>q2nR5-v5m4F zNd@c>Rxo>ZzC~Y6dIo+@zb>KW!xV8Kjd#Nk-t0l$eDVh#qv;o47PF1vriUIZd=v&u zqhd)|0_*)wO{ zLKT|hJQ2*F4q{-l&8}x*#1xB`Rx|UthSWenEDC&Z57_jjsGJ;4PDwEJDJC$t;N>J~ z01bbc5CK)dv+vl~SF^I$H&JrYoQ#2OEaB4L6O|aXwa~Fs*GLA%& zn6snEUneyrk7=1euU8(H?MyGQu9-A%72>eQgICOg8D}w%_JT&;uBEHuhy{l?xDnj- znhbd&VLV^pE|Ne(H4l;b93PQKODFMIDcIzIZ<4ttyyYJ|drH zEIR!42}(GcjDBKeYjWW4mNuL5B3Tz~Yb2Jmils?!R@MxEH#RI0(nQ$WkASsSoV>cv zhv(X6T(P;<-M1d}e6>A=TATJgP|-h$`C3<>r|X!CjT0v1g?6wCqmJc3sMf24Wc8zC zXJG62O#_2dMhS*w+WQC|wYvIw-3cycG%cKmlzKC?J#GHj{g89 zeXhO!dda+N;qUx6sVq4}oGF~X6s!pI5Z9m)*^_`p_6TdgOPCs-Zi$|`npFNyel64N zu__Vq{{ZIpKGa8Bb#U#iOctLXo~)E>vX!9!0319jGqmh)6JW;8orZp!Bu5_eCOZag z?e~nUU&v$jJ!Bpp&B*}dKpVfnjuD8>8ZOzfWG0UUj{g8+8Bezdt-n_Bc9r7)0O8+> zU7ARyi%DmiCS8SR8+H|I^;?DKkIXN(S&lb^HCQ}9i>l{i7QmI=w}{+rj!#oaR1On$ z_5+mri;NJ8Wwmw~zaG4i+(B)V$A|S6)^zD4$5f7NZKh}~y(k5e2^`nY+GHCpq)w zq^3C){K;V22$WvdPzPWM1Xn(z>^YLh(tERMXgv0Hy(Z?1LNSRb(y|l*EZEWl&k{E- zwl9zPd(flt&rg|49&U!yX?U19*Au+YG=Ga_C^{cz_CGcD=_|_mxJ+pK8Hh2x{zo0J z{SQ`j4-ihV$%m2?=_M_W7t7{3w^6&R9N!-u`VD$v@cz9z^j%5BNK^)&k%tsJW0@I3 zm}IhdgX*A9EnJKE>8lDTJV~N1CR=_qgJCmQCfKF@y-Ysp$Eh`qBNcEqM8Z7KRU(o` zKbv=BRq49@F8TLef@!pzpEGzRT&#z?o3wX*o%)$MwchGUQ_!e3W41d0>NT31zLqfIipW#;*h^ zsJ3)A(B?(;8;#Y4rmuoQ2EF=B@pcPk=vm1Y=9Vj(HH`Y5(C-4Qb9eWu_vpoNyePq*(8Ya%C)9NJp2l&#_iRL2U8cp0i1@nr%(BCn8x`QmE=q)Ds({TVKmqvU;=- z4#EeXg?*<^<^?Y>P^7AYwb+nN`(E3lef#@#*(CGJrRdozM5j-L#A7FOx~tPI{{ZD2 z4|_G%Z{gg%u&ylesS~hZ&f-O#T8Ei_!JE@vfnoRSQ_|HFOq6=ek!J0JAb_lDR51IV z!B4%a{B@yZgg7&avhdb$o=$#vls-{{X#@?b%z8(Dg(3a>q;6aq(nH z@(j#pSx{Eg+S^&Z*wYZh*sb^Ji};VX11n3;gpHGA$0Z->rr9Syqk;Mp(CLuOb-&nk z*G8~SDBMs?=^G;lB1z#hCLUU3jCkB9)Z@qt?5+##mPs0c+$`5q=o%a8`mR<4`bMP` zErsXB9N8-lOvtRLfTGxtFjK(-z`h9P?w_OM>$)mwIm)H+r1VG-$YW)8UDm_m*S9sz z^fMpA390MubeM9oJhw@+Cn!)N1!XcUz1aGa@6@$*Rn}f!`|`vpHj$!&_55GX1ni7qu-9b)1x>T zBk1x5SQ4~|?dcLDpL+Qm{{VltQR*%v@alvszC4)3V$Y}+s;>V49RiRJd7S|V)U`FuC8hmg#EpCv6KoW$}9A(SxW zZc)enlh0b`jdJvjYr-(EnDFpCs+KpM<TRpJ2pt!0UUhK>W=2dKb!v&Lam;43g!xB#Sh$oysaFBo%1f z6Vf~L>cxNvr zO)Cc@8PFJUBH1SLT1jJ;_JdWzDHr$SspUq&)R~vhjqyuHo??;0zdRG(fga-e8{ufi zKl2#8#%z3TMaDFH>63C6^$&6QpWgazxFO9WZ2bJGY!5 z@6Zn#w3zzNnKVL0k_@y|R5lAKVuX)#xq$sTyZkwo<-(TgS6C-q}rK{V}ADVJ(BDZP>v;5(_;+&BaJvS%OfZNn+31m z?gb8kY7>1nsi(<~{{TizWVD-$1nwEC`w&p`-)~xGo#5=P8xCBpPZnj#pFe9XfEA25 zETN5^`^2&BVaVpk9c5a^GEJErZo+Mf;aNG{0iZp*?eFbga(pUrB^Fvz&1z8vU%D%En23tSopn= z19Foa6hWrc@!7Q{Wiuk;Mq-FWRw9LcB!Vp8etG-!*_)%LcY`%&#-x1h1_)VHu-iT< zAXq(!?OpErT>5u};Kw^}gg!p#0ytGd2n+$cCvm@Wd-K!wgr0VuMo5smB#SoS-mrFA zAE+nhy1pu#9@e-Eb^G&G&RVg>mN~L9^$c`#BjNgxixHx>^ds1sE*p*oA92x)RNWKf zHs8jJA_62NZ{UzV+z@@Mo`z-U@#xUu#N`G)EVARUn{j=+glaF`3is!?e%((#pl~+= z@_#XdEx!~-SzwhEqZhsh1x1_8E-aD4 z#U_iL=2Ns3ZVvDv(CaH$+ z4yA_*7+LIwGBdP_;DTFviaz4O9^E2t1L`lP`wb>7s0Gm}G+`*z9m+iAKibwFV2?o4@Ac%_mlt3Fg9lG<`!F z7s$nz&86B0;kf>w4U3>_n;Zkv4yTKgHjN_~WP>51VzfbOHaA`O2Kl?-9+Y)OmrB>L zrp3vIS+vZdhm?o%r^&66#vWA8_h>j)cwO&!yB(KZj=%X~HPxL6IQyBS#ciP`VBoNUv@{ zJ<1&FZi1-*geoX=pve=j`!-Av?uJNB2~`LT@f*AD%@cezeDu$kt7(!XYndrr(x@lS zk$#z_s`U~Tk%1uBBEEgP_6;98)?AEuSOp5t41vQQ;)etff4{dv3_>YPd2mS*s~ZfL zwY|l0W48m_^yqLYh>2FrAF4Zz<4kO4Aj%}%qyrvBqQ$M(k-Hlodm3e}{uz>-6Y;R+Ka1f_yAY$d@4& zTzKb%tCXSY7Tk_|ix<;W-$CFt);)1u*|$)%Y>em59$sc1Iw)MH?sz11e-2*~7-o+* zP|eEPZ5PayBmV%@O*QeyBy-VCHW|t#S11}dCfwaiFGR+J8$}Sx$XQBC8)yt!ne3Y_ zXPvBIRslb~ll%2& z%$^eMQe?-yeZ)W^6+|07!LEOPrIhGXY0S^cfb+2gXmw*E)_z1VI~f=(tjZdQ1Sp_S zC-2j*f_y0yxaliFospY7nF2?AkVIo+(-J!#6P{S#w?iU$6e7VYo8CeE|nBp#1Yp@%h%{Lz89^8DKi^6eb%O+l~VvBGGVv|ZY8c}}S_5gRj z{PixCj=1XB+I}OX%*NIv49ske#DhbT^U@wAcu0O>}nhos7=uF$J_vl}(o{$6

jL`rV9fxuS^U)kEOzf~u1|x($n~2u$z5f0B7ykg= zAHzB@jCg-Sn^~QStc;mFv=#4VZm-}DglGQ%6+B&=8!nh|G(@eb^wD{e0sbxRXW)Lv zqBf2p_G3IvzDm3?zjM5kzE6VkB7|n^Ik-AbI)aapJcJ7O19cCNlhA!XPr%kQ4n7Ro zI*a1R=Eai|nBtF`1~AGu3$AEbCa<2d+_lcs@_wUL)v~iPdj^=7Vm>XmSATAaK$9|K zol`nrrbVd4^F0Kr3cQLH`*-7`)xo}%GG6QQf%zxQA&0TX!942QG`W#-=G`+AL=q*q z8$svt-!?3Kan%`fWC=4z14yx}NYOu{Hvm{r2hRq#5r4lxS6#=(S9}@r@(mGKn1RXQ z{{U52Z+rObiwQK@Su9x1%vCL1k5B%_x)uXe2n2=lc+tV4_Ph|Ki2Dt6@Q$C#UlRufX`3{10RScV( zh4m3e=-27h84^eccpPslNUTWgEAtN3Tm#fFN2x`JyHK5*7)+S?7;v$U<#0Drefp@^pE<$D0|k87xVOGM12X3daIh}aI= ze%UF+Xk>zMM%A{_9_Gamd;E3QsXo61StXG*O+IDYENJRkmibbQv`58PnFNU>Yvu=C#`cgb z5oA#w)zwqvjJbw9t1OT+2N9YkxU#(b17q)YIqCYinpl7Xn|`_qu;3u6^ZYcDW6X5i zi6feF`=XV10-ONISJVjHY>TTL9(r2R^|<^un~{U!=(6#mnHjY0Xb-43*+PP`WEUhX z7h}diU=H939X9Fugo0E_*~~8J7I@-2g4XX+_auCeu@*V%k;iPw@=WmkL^&Uw2;Qc* zU4jMODZc&do;pC$nGJSbv)7NTtFh#L!a`lvHD=W_v2_VyEryu)GGJ|)l#^a+-}}hO z?iPqOV#Rd*;TSTow2f=Tx&};It_rfm+I!~55Y3T?5l0gXGHorl-HMS-%^+lWNZ_kw zXzI)e^BxIg+q8mIkb8#WtoniXAoO2JjtyX}8Tgo!V(mpL_`i-M3ci^ykl}%4VZ#SC z$mx32YCIM=3;6jPe2v;kLzvN+Xcpd6OYwGskB61@P{igqDza1`Q zM#wR+d`{+1F4qfHiTD8W6xD;s2WcbTh~yBucD0@1jaC`-+@q7DT#1_#uJ&sHscQ8W zQ~hdLsg0?t>ric1LDn%_8zVmzqAsAJn_wjRf|I~yJn}d5hB{1?1jhdWVm>|S_TZ1Q{;j74j#y`leiMSSh8w)4;)8pYzR&H) zYU@bN@Wx(~<}Q;O>RNN3UIfoYM?dc5HZT4b{{SxiCQl|G*S-ug%P9yCk&_EYBtYNc zxFVz-`2^SKdfUMLQ#s1*efsNiUGzx052R~(T0SYm)E#o*M>0ht9_4`rtZ`*Y2j_+y z@zXzte4(E_h>>JmFDUb(W)HQIfMUGgHBH6eZaP|@2xH-aj|rO@7UiY`%8th?!8{A^ zd>-6#Nn-j$`i&u-OQ_up5|ic2LAI7)C>^#rVMT}~cp8qe*GZQMvUT zybNixabQWY)t?=9Oarx3(*P_BByO&0y}`C^FU8qWlsPd;=ER0MBc4JPkTK$q3{4tg z`|>$Knn!{qIPUP0WD=(0%FM!#Zr5a;yl^{nWEWH>2c9AZMDHO;0Um`eZJCdIy8wRw z06k#hK9^3b10K#_zP&;_F$JWMdh4iK){(7!Mm%|X5tcbz2{JVKZi4OZeVlwU^ItW$ zp!xA>+P-G(SWBSiETic%)B>5h4Z7|4Ybt*yH zXsNWYJ-8%x=c;;Eqdt?V1x<_8kl;J zbsYCk9zHXwdY{zV@s;hjU3(_2Ps3R{UTfmCMl6luRaKA_abwjR_FzpA!{+O_>c56H ze2pI~CTQVv1kSH8jxc40c-eq-1G@`gSFr@C?s_fY-BwvLBgK&$iH}e`q^i3L z!h1?iNm|E)G~6uATwFba!}{F+09AqINz58j4!81^(DsJ8?hqGJ+CAk!?7Z$p2w{mXZUMb(DJmLO=)A5)MN&iYqmV-PRC@W zVN4lWeZgVU(ZP>ZMVA{V9%P;(eCQj@hDHR1DotM@f#47c1a$2Rf%3|eBbey#jmnjp z>p6Y}OC0hvof$)2#PW@W$sEIzDDPZe(V~ zkQo!(@--jS1{{BjqWIcQZk(8sVGLZ!B8;O9c!EkeAZ@!=q5dFEf!q#_S(q$We28)8 z-^6(Olr}l++O=Gb9|uv4JVj@OR@pbMOkAH}ZmbTMGXDUFx-8Q>40tyXNHL_5A+uhf zjuDT3E3xg?djo2ER;LzDG#Q#UVW94iENdtO)NE3-d+o1o)zPuzZAM5GJkiOPfChFx zQM&{Hi$I;H-FnHZ^rwr{A>LoH%1D?^GZ1&eW7E7Jq-eTyxcC}&1EYWeFv)RI?yMDv ze)PhKz728Joczfk!;#{^$jx*hh?36b_x}KRrFi6y*YY|JJV%$A1Z|Iaw487qGkg5J5{*t+wIU@M_=&Pqa#Z@>X?$T;r@mNC!YJMkMH;D zeD4K_phGZVsko>x#UW(|!Q`u1`vdmq7EgxbecnrBRdAAHnBVq3ALox;moXwu(iEWqHq~uI8g@RR`D;A=ijvt`Sfca#~AvIOul}kxUmM= zzE^10um1p*5}@SSkD|z9)G#o07b*iv zaORb0kN(LUD7*Ir{{YLTUx30@CB&CIc>O39oe&{xo*Qj1#b@X+a-S#ZqgR=*vVB)} zJ0hx`-xf!|L}Kt(m4`E;wxyCxWgI--VI#~fwYyaj$>4n7SWZS(m9Ajz8f+3}q`~nd zOzES2yp{~INkeaOM)~-%3&pNY{I)D@OHRntawDdNVbteB8Ak=cm6f~qAdmIwA@thK zp3US5(Cg1<;Z@FSwHI5y2Aw;jrkAF)aoA;b!&Fb%tJHY!$m%^x8E~;4T}L`NOGZdp zA}4Z{0)>^fJF1V*#r662A&9cT{{Ty=wrfWq^FNqmv(a$HcRanxp~ruku8K#e3D!9! zRU<0dUnI1JR=qc5@<=p4>MfRi8QG=v1aeFEi~_)|8gComVik+cjglAw7GSR-K*pFL z;POX2_U+P^zvF53Qz}J|G@>GcCuu-YK>DnT1K0pP&&7384K5f@nKWV97uOj(Xp!83 z&))w1aGE?5{t;}0BL%Q!Af>Yap^a7Ss^{;=T2$~DYDR8Pk`8iJElW|4~IK_q>& zK?*1mYiRqL9cR{asS+u>FM#2!^>k+c0Fnt49a(ka%}+@1zL_8Lyv&_{TFuEg`evJt z5Jt(E3ufKyiYT*@#gEh#$BaRysMT^e%&Wg4v5+D&S2W5C1@HY=^YPFOXVLXPGgZdP z#>+VPrWDL1l89J23J>&}<-Ne6V#h_krCKLnt(2n1x3V!FHBaIugQP*_#eo{?(T4IN$P1F8K?*?%LA|bMQ5Gq>4Qy5+wqv#HX+3&3 zLX#bG+jIR{X`UJI%V`c&p^kA>>+otUE(#13+^{MOHpM#z{W zL|~0}jqoE9c6u4riDxW81xC^O_oJ>S^IRw;!*#{gFk@kfkv>XFnGwqSq>eB+88;RSINEEbj{z;I87t0bCK!0*B|L zYS`^3)R?kkNf#e4ZvBdBUN%Gdk*J4^@ZIbX7)_I7~37$kob(4iB z)W}nLR`2(VSWiM9yQZ)C7&Num+<3Q zLpfY|f`S^s{5LgacCq}NQI=_9lM__O3lqk|5O&_lwz!Ou+Uc1{Hnl+5S~Vb!Sn@FO zaxy-Q;=`SYT7ae9k-1pcAe9}*1cEzt79Mn2FiVfCag~iX(&|{{i1P^yqFB#zk|2=Z zaLB@q4!ryDl`y^LIzYJAWAoLZNhN3Yr!Ww9^Ba2kMN(DFhcZmvN_l3UI8-==o=91P zqs2vOz;9AD5wz_!N=>(EFm-K3apaC1e964B#yXBB1-8py(x$c%{uUj!^bJNzVa%B` z1E@odQ%VI1m=^N#MSGjvYqM@0ww|o#>OwqCN>Z{X(qowrF$A&##;o_QIqu8Pd+Vyy zZB|GSfF5SrgnPvE=~!AU&8yE04w(TlOGaK<94L?=L1pTQVemQWYbq&KmC8mEU?-2A zzI;*yk}f-jsXadY0C@t^zl%N|)hBHuS8LQ2>?_vfji`rl7(V|(0iJAF9nH>ZeZ zAV%NF*q5^4i!&ZbvXnd$#^kiAy-9Q`%IbLMkG1o`Ae_b@1#4ayY3K0HKxnb0SDQ%4 zk$@-~iHX|%BmOiti3)M@nc2& zTy%GY02n+=wq2z?&j_G{d=f#v2C#cEkmiVWujB2-F5J{48;!{o^$hJMY^deL$j6d1 zDazC48($rQg=a_Pd=SFcxMA4za!pP=xnIrP3clFnC`vdbt9L$|tD|H5C#Jn$9XwMC z!K#@U$*P%gT{4Q4jicEp3`h8=gL_9Ji0d}-H-_~O1!iiv=wr*%Ba$~+#Gi)9LvU+| z*cPT-<;p(M{Ndq0~>Np~+gi?!VfS#Z2hiurM5DUTme#!CF) zt-3D{-1g_5LH60aJDm90vCXVV(Lp0fOGRgL821B25)G9*Ym2KU`pRP2ogP9_$;MIx zmy3Tsq3c7>&#S+;J^J`~n>)ZzB;FZp?8058TqesyjE*=AS&sHb8*VDagIPp7(r#qnp3hw8b@rimxX z#GWjCcL>>vWQo>BY6i*yL=SV`fjsq+;Qs&_;MVio4^`4~{5JW}p^|)wpDrn-3@KQ( z6pVs)vXe)+BF|bDH;MHIg995cBT;vfRFX%;$upyJ7jKw7fDCS^*e9{9_BOX=BpLm4 z-)>0n4GxW;wZdu`!#xfJ*>GpV(Xx4{u2d-wXaiO#@JQq2Uq^F1T@G@@x|TPQkh0Qc zpaqpE_O5K2;1W6au1D#5hKH+a+4H2C8`mAA#1kx#PSzZ=DDuU*05=pVkGblcF-e;g zazf3H*0IeL(S{O$TXU%co(=Lz`R&oERR_CJ5vBQ#Uq0wAVHauMi{77|aZO&3PZe|z9{oXY>hT(Wmk$Bw=yFFJ0Ug) z9f2d@bV^fl!pn>GP^tm+;SwXwfo`@4vJV`B2OU$))$+0O<-^BCn;lh8m8nVy>~{+z zgMS9O9S~P+<*FmsuMnx(omhJ7inWujLzdCU;!YqFNFC#5MS+TyP^P^Lx``xMuEx(o zbxfU0H#al+7Cs|l!7<+~bM6tTCvUIbhs6V4{Sd{}5**n4+$@X(ym?s*BFl`$tRfZ# zxnc;fxcTTbnsZ>Ls}5e8@x?YgnGwj+Ga@1|-bWl)G{2Yw@zB^PQmZXDwU0ew+dYwi zd)p2kJ{#9^X{o+ZDq}o~spe#~tmLuefC;_{{{W@+BjL#9hC3voeNE+KzW~=Hk;gn& zw^wsicFS~Y$C?Y^1WFB zs4+Yq2R!u63hsS58w_mR4Di=WMbN6SHPPem@v6NRoaFxiwa9LP1s81(k^$<;$kMSD zjG|nfg-0gu@4&jgyq_N%8_S8A@u!XBBOFLUZXE2R$lZMYpKfJc3I^4)gpv8!@Y9v5Nn`&27quUs@6#S8hmC+EV-`kCzfG~(-Zc!$R4prdhXapSy%E=1o2qDe zxl&={;uvCQ$&5~nSwIA;fVF!;9Nm&HrQKbCY2)X?TvI1PkRus_Y*=+n^`8z>vw5np zuap&oDPLCWG!MwLRqcL!bdqu8t@8(*_kCBSy@diPlLGnShX~b?(dTD!~*;1Pc~#ru{!o&M=_Jk>E^m zvMPeuSgrOst`7&Edix4UG&u2~%gWE6Co)p0=CqO*Zpx9VHW!KtJ_$V#hfu=HSBa4r&hr;SWGNio~FY;Vdof)A#L_v$#(8L|pP5Pgz` zA&PAqxV!8uw+FDZ&|KPd!646yur6_e5QfD$8H_45L#eP?@6l*?_#@q*Sl7uh?*ydGqoZm!h;eYHgz&6RSNXT7k8xl z0Yc4wohA4K#TXtlNwC{Ju;jhUsrMU2Zst2wn&3a(8{K~ z;IA&ie?sSv_(#uFCX8e0*bc72=Q5!OZq-zH=+HOKo7@KgRg0k$CKcQ)y~vQ|<>h3( z`I5;av1hV3I~uz0&$sp+56a9}^2AYuV;aWmR0}HYE&J8}r1g3|&GkKpt+~GEcS2_c zr;sV#PQ_?fzeY9*Dq=~M)|oevp9I8(3qDir|ij9W3G?PQbso_eh8Mk$*YT!T%*TvgQd zJSUkXh1v+Cm=MAc$tAE7L$z9?9;>6c_8*`>gc0TD{{RnkKdjHmn;sC!h!m`TR4DYT zz$B1M^LIoJYWn=UsZHl%>8k-Of*ECz1761S+%Z1{uFihruhM_QZ1;!wUx)m@1Cfy) zWU#W)Ws*ZE8)$NU1$ZAnZm4M*jcZ1v!n@y;5}Q0jjSAvOkTAyq438qwy5x)Hi6B?o zxvrIQQDKZp5se?Z*xVG~d-p&0$4xPp$lQ~@R1nE5i{+=~P&s4-a#UY8*Ge>8P+iPB zQB{dX2l}gmZuq`F)z_iI;8{tZ=5R5vet%0b_<~PxM_p=`;lMe$4C@S;GX7%B7^pvG z?fvhsW`S^37E!gB6GM_u>?^;wN9XY#n27#FIWjn3!!oS`Z?P6Q`;L|MZE8&8xnYCw z)~+?J!q2~Z`wAUC{7`E{C~L56KooNl>ZZ$#%}Qkw29soGjf-pg6YX{X0K=h!KPynw zV@dKDOOq-9XxS`92KOYM{f8X(>i#yFlbaf>@kpDOdZ|(f7DdqK*#6x+Y2Fcs6{D3S zAQ;NW3Ro{dTM`Y|Be!mnEfiay5bNGI4ghtho%5QcvWsnL-_Cl~1<`bg+b{|7qmmdh ze8wuO8cMrXlbej!Dm(K;cj?OmPshgc;l+Y5V+A8f{V1iF-?u&fPZiXXoO~USy$%M z*W=To%ZhUhxoh}ps-TG3feXdn?|rv_AP$srGBUE|mEIV9$#%4_wuu0fw(qr)f9LJh zB-8+QGOw1x&Bg_p4;|~DzivAAB@;~RsHD)qi6aDB^GustZ6Ou`VMLMk_v%?h5?u4A zTYA{4YB|u>t2pszVrOGy>C!CItCt2RKveT!20KZsHTFE;M0A6hm#D1zmJ~Q^l`=j! zi3Z^$MH!Gd1V%5GzgavRq0|~&aOm=3=FO-i62|E&s>Oa^1cf1p=Y~=)!Qj_Lw9Pjl zPv>}k2=HLbg+!Uz(T(j+TBC$_1d>TK4&X12uI37kBAAsr7~rt4Tf_1=-9P&-CvtwcMq9dlSu* z>^d)x;p`s|!~DhCNwRU(np}*R-y@*{)DP+G3W3eozE4Zq=Zg%>BV*6>x_X0hA4z|| z@A2QKs9{xg?@! zS1Y)Rq1*Jc(}t}&K!JEm7MC09xs`KuQS{jmj0_hbNU}-mAd2-7@@s)Z=iu603_T`% zh|(;Pk&haPo)t}?u;-QoU<%X-U$Cpby~J5I%tYo5s#0;km8L7SEz=S5J;e`m)#xK4 z8O)Icj1}6_I4s<9PtE*xAK#_BM^twYQ>Ujb^SWf5txLGtY;bOns8Z4vd7PGJZ-IQ1 z_dn!1E2a#1a&hO*!;)<_2}8=8$lq=)P0(kqcGw(Q?MAecg=CqSNaaN+{Ko2!+vdN1 zqR7p~Y)sh%shgdHr@ngONX;5NDJ4h&MQ%AffJh>Z3Oyx`#&%<}ZQOTk+2PGw4@lH@ zWM@ag)O%O8iEP0b??a%Hn90vQALA- za%7ye!9S_gUvNO=k}Ay`vOom&{NO)9`#zkE~|p{{Z4`b}+I; zxhRG7_K-T?`xmW5Ifbp2pF@nA9v{-fi}e0}OE@lVrICR2`J93%PzSgA zFnDJRA3qXVWyZ(dF;OBM+gHFQ8na#c>u*|exZZ^0K6qxg3wjn?d}5m^m-gb((%ZJ z@PCo#zkh!2nNmZYrB50YMlqJK?_;EE@`l7F|SZ6GPevbviC zM-`&~021+Z{{Z38)%0B(AVT@AizDJj%vurUO$!qv4?=D$#gcaLM>}xcRO+59@djS7 zabGVLq&1V0g`tf0t<)Cm?%KC^*pt?S;$IPJI`*llYFf?)CZm+t_^kNMe+Lm&T*kip z+iSBhs-k;P>7QB1g_!5)*e#O2Nb+*^77*j(`fY>}DF6xwwHmu_I>@2)+e6LZPcd&R zChB5xp6IsDy75^Q{uhTv)8l<&XEK&9nCv}snjF_?*XN5AFVtuS#L%*JY0^D95s@Rd z!?02zB+v);KcEEso|-i|p&G2qs*Jg_oB+fGCPVESqVX87p4Zq8@0dOxn-5CF$jiuF zT$tc-DTM|??2%D?y6h@2P$=)*o;oYA)ZTKiY1XQ}v0#@SS8(YVz8}Jv&kimm4JRoI zfLs7T1d-}In`3l17w%WW*b^)>i9i3=4woGvHt*>c{6GaJW+&I+J)@?Y5)^`z^>!u zb)%iM-bFnd?;<(wJExjP9OldQKHYmFnz44peIv><{ak{4sR;7q+*A)G2sRgTzy6+j z=4s24sMHMrv3gm}*46kQe~UeOVO=&UB$LlOrvR+bs}Zp?KY704#yX?oUO$E1=7nxrBadMoPJ|11aDw{{Vum zo3`&t`4P6hB!4K06?2(;#Aou}W0D;EoUFJaP|N_>6noi5PlE zT~6+{bCW5&HWWFXqmcgq;numgR(W#us5LpK&>_mn!P>7L7vjYxJYWGq=*Z7Na^m|} zPLjzcQwcKN$UT(}Gt~iofB*n5AaWrA7P0TBt@%%sT7;;M;ZUC*@& z=UCOI7|@?Jn|sDdR3^b4fj+|hzTackYw3sLPSd}xw7PDi^0YK)6u&2AY2ZkV3p4@dlx?dADBXXr{-eKgE~aG%nG4W5>8L%7AZ5rfTF^U^L6zZnWxNT#8JLAHR%jg+aGGW72l^EJ!vpAWKCld zRmn*h$UM=pQZ#FfF3?G9Hl)xr05x4x6J4dQ>>DnPL4yN!_@C^;B{qOSae$ZgFAKYP zT{N8+Cmq^6k@X6)w1NE9R%J;CrHa{BDoGxoSY372E;Kq!Kt&eZY7oX+b!I98vj!r) zz@-4tQO_LK$klT-G>cEiQ4S(hQN@b8QdZqz5q*FFa3~MIZi(S&{!`<{FcP#+_%TLp zQ|E8m{{XArxZ}EEuV9+a+Dv(C;wB=}QC#M_%pG5@Di{o}ESVE3`SYJoATVCaPrq+r zK$H61I=-O}kBrjGz2$Nd0RJ;*C@d!kb!t*n~x673#Wk&`TG z8njX}gV|S`BWdsVJaoj`#zq`@OQc0Cc-euakh1Ot;U#@ysZD%XJR9pp_3qLe-s1zp zZ?gXYg__Dx92{-q=jUad#g1}LFvzH~kdcj&Vg=){N0#9JVO_cJ*!-CArgmPJzZ*X< z%>qt0llTRsqNr<|QD6bu#~@c%HElB-;XugpW90ddjg^kkZ8-BS6Gr(5zu585eujfC zUf436M?N$~P%L(3UB!!EcB57CWOhAh(t9ejMw%V=pF8{8h)H!aT6&eIWMbiXlT4dT z*W+BQY?UQ#N)m*HwLj9}p5xq)ZaTy~Z{ex@Gn0djCTix#EM`b^r2H~{RZmtuuKRbo z>ss)xRCze56E^WE^CFDZ?NW;BKSt+{2qW**Kg3-Z3tsTgos?D_j5XhlHs44xdP=hU zgWUdurD#`n8m?E_y?YeqQBkrM8>ME+q~}ML6UoWJoV2*}$7sfxSsi`Vg{cI4-(RH| zwz;QclLBdZ6JnCkyKfloR<;r=fplx+_Ui)h=AHH0u9GHsjupzwnH@_P5y6jS7bo)) zJv{#aNCfq;_+vXW7f{!iRaV^7uaz4;1r1S_s^LfgkG=HPHlrN{hfDgzd#bUdSnXIo zrKP@$sbt_wkCBS0BP?;r!9W_QUwW$t+*i$)-3nC9z>_Xyve?DX8(E!CWh5R?sP^~j zKjJ=$MyTx$(UkJU*wr2RgKY?lZm>!1#amVOs@@fO@$zQE)T5p$-X+KhDt=OZJ5RVH zYY+VtYmT&wg?cbe?3Qqj@?*z~$S$gqM-1!dLRgM$dWH5Y{(nCGafJ?JYfhLrUTZjw z)5>rfMnwUf?%*H&sM$SV&4uzt9D7pY6eJ;!1$gw14`I)7)DY{FX%b5=1YpSUG;bh% zthNIqf9Y|2&@@!>&qz2`bu!WccFo6LH`7n;bu!TDm>W?|ZH_X<7EHTk#fZZ+hD!nc zHf%37W80p<9)z5eJmnYh$4vl^)9BFTBaVTb0uk{alE=pCH1h| z%a2G}+v@i{`l*eaxhEIQig@Ponh8sV3eE{CR*4`|kO8CVKW?WF{x-Fw-Ulhx%c_jT zxDL3hljcbJL}(E~g$RglvTJtGPu*C4lse-sIb?=1(Urz#B0Fm=-PqUI(7*b1-Yz)F z%*MxPC2*ZYZCR`t){OXteJS>3V*5nT?pSxdJoidi=B4-yj9#d~tnPzq6^A ztqL1kEhPi~8^Mu*lbw#z`tkRy24HAL(a7{aLbcDp`Rd<{G#yJL!?{r4yjcs4ktSp{ zCgSkWE42GEv1T0hJzT`l{{Z@{ocOXBu&2{Zu^qsybHgZMxVH^pwzGDawJaIma!g4ZNN~Q9T=u=+=0AS1y!}ojno^SOO+-ByE^|i0n6$i=f;>qe#FjV9$K4wV+9PF{T9NRrwEOn> z<;%r5k!$`9Y*9KKtXzi2Ng0T@UTbg%`U(=>d=_WR0Rl82j0YjmcwU z*qwogwGcmc&kAHFQSmM=G`?;|CS*Br%HC`FwmsB(h}x>OIpp`_q2e=Be`r6{{$tAf z6w=+j3-Eq&=0`O1v!qhSzO)ugHC>;6{Exres5LCCjI)$9oJk;u2N2_*r^$GTM`+1p zuxJ-vREjDHBmg?G;q5wTH7$8mL7At9Ws4^cUH(%NSfkw#;2L3F!t#2U z;La*zl6jekMp{w^-buRvQ3Q{BJzeih>m`7G^6!BD7ByNPWr$xnElTluG{qZh>fxk*I084KVW)a2upf zcTn~}>Nx)0HfeErSduf5x>?u?VtYmb=k>m**5!Mem(RC7+l*Rs&8b2J_5rcMFW zH2HF{VrLP|yB-k4DuM_mzr+-Petqt`HT*uyZ6`Y$>GCoLG%`yol8durG;{+MZ%7A# zcJ?Qe$5nJ3W;t2dGGrzf)OmhfiURp=f#em<(*?Q!j{M(t&j-d6P?|5P#)e6E%yB;& zH)zE{e{m5$epWI|qeoDSefhQ2orI;W{ilNP4AjAfGwc@QMbiUDGFk?Fdvt;cc& z`}E1;?EsG!Y9CA%A38{-MeXKpUQ`~#)Csf4wcmB@{XDDyNee8yODB~P-6E33gSO%Z z)vczvCvDd~dOAg=q1*k8AC9y{%#qhxpnt;^b@4`;JD}&$JfB0vmNV=|xmm4vwZ@_(lZ93nLJR*m4lIu8I|H?4l-3s z00}Bg5>mD9_@rSBmVQLMHAXUkgH0iP;g#jCgkWgVve?dT#chKyQ3hJI3 zk5JO{U{{YKc;lJOEXEzaX;~v-!k@!Dn*=xnSm>2|?GSG}w7h)(07~t!Je3dOyzz`| zv5Y?q2}%M<+PnB4u&$?kICb9;_-{;+8J8}6cwLl%#F8tT?Q}sTUv7qf4yO@kYO%_v zaZ$*zOtOVP-=n??haV&OjiF1KBr#)PD@NWmTZUmSJ$(^#FI(RUc$bc8@6W6J}_}i7l1jUkJ3o3IVR&e*;yhd|rVCjq5enmR z+Dw(W0ZMD1dg*r#;YFunx`1Rsjj0TzMVw?j1jxmgbc7bR90OK9K<)F@Ju^M=d`E|s z8vg&iO`h7|WB8a>FeZ-DgFr&9`K76;8)rp|Y!EW2wX@_BOWQHc>MVB(Z%izo|~gpUA^~L zZkqf*lPj41q6U=Y<4+otA~cFP%Q$Krwbqg#ps*!jW*{EyD)~KH)gtnIL#&xi zJ4lq*w20tnZDT zFJjw7bJqZWgs}jr?YI$i#zVa&$*T=NW7CdE7BlqmkRVY-Jbn}8e(Ynv-0U%{4K zHis8k$BTB^P_%O=yp$*vHMM~CBLa9TdP|$cu}6~lTEtnA&4|h#Hc=xgu-qGZ{$X}U z7ApDYqP(@j3auuPOa%sys!JxHCN>^WOpHlxL<9Zo1a1xR@$<+d;PKPGiL6JdM+`Hx zax@;Ccad$N3`M1nQHYh~A5xGHAa$S5jS9lLj-QkD4-sW=A?aqsDobr(4HZ1m&z%t{%NgBeCEVVD3(R;{FQMEB#XiojDjgvITwZ{zQ{9i??3{Vbdk zNU~;JjC_pTDP$xR18txD!?>~8f#|Agd3esFC8LyBU>!i*Ij(zy->~UN0!-~SOJ_Wh zoRZRsOn-wvtJP|G;DcxU{rW6&eC_4smmW7>Jc3yV-)kP<-}ULLFQ`H>;C2_gc242$Q#W6wW50?EV4 zIIHAJ#S)_n5^V%u9;M|E{d$WI4EzXT`nQ)ZDURma6fANpsE$Bt_zc09?RC)WwXC!f zcq>z8*-aQT=riMe964Cx*s))y^3|Ms`n_M+^?Q`rP6v_ZfJ+QG0tewC+} zA$+len}d@}%u~cX(#N^nMIX0szf^IxeO3|zU}8-QdO>M6mKEI9@=xp0*-X?D!yGz= zOow4dv*Xop!1|1MQY5fuNTcB@$u=x@{{Z9ESnG`G=VeT?pp29%g4_!mf$jF{i|Toq zF*3YRKUYakI~haY}NRV2;TMJmUIjLzyU6LOYgMTqVICeOD-%J2w#d_W&6 zLqQf!_!@RC!?I*~BmBE3iT0n|aoqO#=$9xRBU6GztP--BP< ztm*AF)kaq|!f}x5sf{)^9-;Itv@NF9OE>PIF`@Sz0AC6IBTGK3Kbs^$E*3G8_spNE zqAS=Q{{2v25yKKw!% zy&icTUZy6UJwh94xys|q<*jd4P%W)wDn}o0kK3=K`i%G{5D7A5SlQ7Qks!>SYJg^QjjP~?1dXFoqt#m8K%q|01&^4dv5 z`JxD<8<4qBeLGaK+Bgf(K{(dCy21hD&(HhXjM@k8B1Z-GQeD5qrLHhN`PDo@7VQI zU)1!!2xjR+2s>&yRP$;M$mStqYO4}T5$hn?1QEBBeJ*F>N0zOX1nlNd#c4~O?8fQ$ zcMeB;Jn?-mh0k66q`*2@^e^Wo!5XM*85bu!E#ih%Ro?zjm{NgapmXuuasL3s=~Bd1!oJ4alE9E4EVD=PF^U*cA-62Z z#%<(?-V~)AeLhT7p9v(7Buw6z z{X@zi5y|}CqImWk-)j}8V$Gw^22_)xgA+MGFP1CnCtrdAO7Anm*&0^$(N-C;W{}GG88Q`${oXfTVsn3+l|KD+bpHSkYx?#qx~4W(jjTf( z2~atLNz^B%L$=m(pO_USnm6&&j50HYGJuTa6x$$lkbjCf0ov=u*zL$5bT`Bv8^`em znE2C5_>AFRIne{`aoK=9kK9q~766-Ha%HY|gryxGX24a&)^^F5v8ha}q>(p%N*&bu z6Zu=<9*Z1EmI)zsk)UXp+R+Ue954sqcOK*P>3&Fabl>Ipy3D9@Fj!*B(V=A8P3{NS zA4wc`HS^JYT(`!ETQsl}R1f4N_XqlGo9a_e4pzsLB6b*o z*(a6}>c?hMHx#3|0L1O$&%e$5{{R6T>_sr@8csyHq+`VlH&n6V{Y+#-EZ8qRIbuiip;=DU+!J(bVAkbQJL2k3n>JKf_(oioo&3g< zXxuU#%}S<=5Vy+LuuUOMrHsdu4%LCC80{uJttQ4> zt>=Om(5^22eeB0JpQtRjSvhh^8rRY1rX@)c7ivlT%iLEZpJIAnon2+fizv+`EsAmy zNiiGg@;i{Afow{PWqBtjzdXqCq&e8H)48|mQNKpk1 z!Fd6c&{DU+Ha^$XI&|0)%1%41Sqz@F3}SDPSq%by4&UFWDOPP!EjB%Pp%Is5*VC?c zf?}IZ&yhsTs-jVQTDYgLNanp_yICDF#p7LB;7n}dB6bfRQmrh2*5Y;>qd>B_Vx;_Z z9z4(|mlIfMvLgXXNhD*-kyw#ijg8!M_9LSXF~nyjQW*pw?2Xj2n^Fq#R0uuCYv>q^ z9XhA943`eSufn}Lu5Wah2!7Eds)BE-l!xCjJ51JU*?9$tJcDQFq8M#HnTr>Y(&0eJ zOlqhR2_FKs`}YF*=oH!{(iSQs%Ck#uP=W9lw;c1=lWDmS#vLP{7EyHJ&5uoY91v`d z-5(=}45-}E!g}&T&v_Q)n&Z`{ie<}x)S&8 zVvpYV>1lJJSsFDH;^ZhQ%Y5J1au4?E&Edr;dE#i;sAiA@4&!6pcqEVqVeNfc_(&Eg zIa5Y9tvqBIrJ7ia`r&0Vf0*^$-JLw#ZB?djoX)z%KR^{*5H_g{>I$K;! zO-C2ZOuWX&3*|e<5;&vm;Yh#KkKd!%nwv*7nGxo$W3yQjMiEafzyJWf{l9zbCliIO zXHkQ!i}mK3q*wtJI4ESu`o>3<;w)Ectp(%Qitqbz)TusJ1genc%N5?lNh}fiABy?t z%rofu@VjIwhC@Vw`M4d)BAWQ_J-Xmy=*0<+d9g_r6;#U_*sCD!U))#e)(%U! z2%paEWI18(M-SV&IaU>FZ?j;&4Nok?JZ=RRPt zYY-_FU5T?)YpSPM)pZ{-Maas9(4FzgGDe1lf}^qT-{+3~IZp?SWy`?l{VI0CAO%A= z_7HDo8-*YMrvS?@Vd}ff}0xo}}@z{uP+-UGL5E5R1k!+wSYM!fM{9! zb;pcz8w-(Il5lCs^w|Y z<$XSi@EHo@iAs5+%N1&kumD=iHM9jxWOvi!E;fy! ziBrK3!J+pZu8de9)-v&TGQ5t=-dcs)&Pi+F**g`ilHAv79XCt1t*wV1hm;|_v6@_| zqtmCt3|B8nkpl)1rdjj5iv@Oewc$Vps;G4)BV(71a`I!qf?c&N(xB$J02TxO`RA@A z%g6d3A@@TPyS+3+)gk=NN03eT6nPcx)XO9@V@xqJA&3N4c-A_TZQX+RT#whkMKmBl zb^QK4()ochN8wms2+OIk%hNnvK0*p)Tue+?MI*Xhu=eKpzWjEltN1oeLrZ-pTJa9E zkqocrNfVrGEO6q$X*{F>r~}-RKHPN(@b;57ON8>JmWrP%iFX6pq)-@;2t7~qcsLaL3_!XA;B>(X{Wex6 zXo>X_;DqxTJf(LO#g7}&N&*;?ShF70)jTaRmSZfL(od|IX2mo4ah-~9g;iBhpqf+2 z01yWi(FP30y>-C~SX@a;x!=SCE)kOwB*)C$#yDj{g%F=ZF=iCp4iqBi7-#?Nq)mu|ILs?wR43(jDk=;|^nO@x}l%+|*m6=Z9U1V538_U&Q z<<82VBnqV&GCFsvv>`_y7u&y0+9!gBoZftK#~UgW9ElAG+ugbD{2FHLIqBX;5o4Gm zU_Coxg+K&weYqoneNjx}XtSN7LW;t|pga;!HAea5o8VVd{yJh<*idm5D%d8!4`Jjk z7M%v2HO(Z3Hb`XxN$vYHC#uN=mSQ{mjAzaww%@OT&+Ki`Y zV8oW7O%~vh$Fb|d{alAv4jSLCxUW_8$rOu8OPM;6m2wvwDG!w*EO{nLW-!UHGBXDt zx^O|=Myv`HdXG<&{{Rs9b+r^m#mRX<$--$Bml}BPDOQiYqcA6uq+Z~9Ev;#(3>dj3 zSuv!Q;>neQpDi6qiWDqw+A7a++m4a|lTArm9lsg|FFwFgnng6OPkwfe{DWesjS(3d_7(1RIL6Q|}Z z*j1<-8eS~XPMK3W;$_VeJc_j}M;ByjufO`)OA<-t)VAOW>wT5p8X1VO-@NtVtj4D= zAkCVeU3J6lZ$LVez_CsL0M*lvkvvg70jMKQA#e}7p^~WcL2O-CZ{mF;Cst#dftx0s zu4(e0FD-#)3<2L9p!c!?`Qwg9TN7#UYdCoLdV;ntMl8o87Fe7YhI(zXMBeRJUe2|4 zK>;gP!jn|jwH-4P5DydN=a$Pxmuh5VGMdVTSkVNkGb-BxO%1)8CfNw(=g~Z*aI9Z2 zLU1)0^-M#Mv7J9YDAVh()%P4+lJpuo{Lo6La*<<}Lqq}Bnv~Cxj`CspW>T|4W8|wN zF>QeHM1}yH0NTF|*HT1>Q#ly1NfM1XMJl~JDY(qhvv#fZ&k7hX_^+tn3O!&+6v3m& zf>mO{ZIOyNLqzu~dB04GNHoI6XrRWsJ8m_$&Rtt{Aw8oslvSdI+2tydhTO$3ax`w- z?f6z8{)`CyXz5te_+wF@D@%z?6Dl0_QWWGVBk@h~=0@CZ?8w9#G-i?FWlCJ9jbVX%CT|mkKDG8a<{U((Eu72k{3Upi6Ca;?xt}dT`b- zT}-cro@&TUSt!EoY;wSRtpXp|01d6sve88ry&e;p+b0%0Xjr=;Nn$D(H4;FpaYmRR zAeHMvjyTn6w|n~bLVW-X>{!Q)yd5Ni6U4p?#F`TLrcAteWge5b0P&}4yAmNgZ;@BZ zv>M;m81Vc<3Bk>c-Y~O9VIHMYMKJs}q75E76h+@#UYxSx<&Po6O21K)un;zplJU&| zayFI{DJs>rK_F6~gVjxY_&2BO8jd!nkuzlDWE6b0RPyFX2o>ciB%l-l1h&n=X+;9T z#C8TjvAle2q`q-nVNc1D=Euz7w8{AHDCXoXYFl5eqIF0ZP^F=Q;! zpCWK9)sBBlzwA#`&xg;P)8UI(aMJxS1z(EgYJopHZ;t1nx|_x65!W00A~ns?!Ccj{ zv2-+r^?a4a6B4BXDq|q?VAnjJF2ELeuCHi%wkEf`2xScPl<)H~q*+*Us=jX~)6-mo z>^pUs_>)e_&}I|(KMz*L#+d@=ww{>#*PB>B;z(3jSqL zU1mI>HVuMuby&*6Bqh%$8tSmQz`%0rPan2*GV@f0v1Q6WLA zKbV^ZhvC#rR5_VI+%+eut*$n)GPoowH~udaV^7D9Oy# zp@|hW(>}%l8h1Gg7vPsxvIk;l^UrRVWYx8};LBXt@#KO+cRYd?PAiogeK-FAb<;Qg zCh+pdGXDUy!#O-J(oY=9%m4@?CHu71bnTx_iuIvgzRHf(7(?Jj~+u{c$xO|3*X zxddJD?aFM&K9MG)OmPEVf3;`Ok!KH7sRp|y*;ZT)D|0Af-%g7v1Ok_FzfV7ve{YVj z!=3!kB;uwBMsUp&VXPEkBAP=qiq*@5drdE4T;D_C z@b)}0W-0QSawGCn%5ZAkOA@zK0-Ek@j@8pH#n7nITI{CV_#m~9X@?0zex5}nJd=68 zb;yg70+_;!3Z!=&^4IUs{{R=}>NuVkGHJWUAO##8NT1FM%eV&O#@4<&8u{qEcxNB* z;fo$+C5Gu&C@S%{xZ7WQA2fPf@otHohoWR>M-;RDE5{)%FfpV{CgRI=M%TB$Jw;m7 zT+-n2Fn>Bo!HV$CdIFdl=zG{>HJt~lvh6&zcVnE;5_ zo$osZv^OC&S)e;J^gkar@F^QJ!}`vNsKnV3zHXz7l@y+Mns-cfW&}p=;BcfHP(`ll zzL|U{rpF93L#xQzwoXKbY`m#&@uWS;HY&#(dshbQqETqz>@6{lR^`hvV&wKDlV`tw z*P>8hh#;j$3cxKDBERmx&#gLGXEa0IHt^@?=?OPg%w!0^UWf#K1Mt2+F4TuE3Bz+P z6q3YU2WZ>_vb{h7_WimgHY_3CriOP^75>+pKpQ{& znv`Zn7|rG~KmPzGCzJftaDP+P&JY1GpjJ9cM*b^Eso|V)<|*?vC{=VdHEGN2%^ z1kvx_yYbdvnF!0%r+lb|wmwOK6Lx|v>Y;h7E#HdwuDsqXWW+;6M1B_D7|jVcnf&}G zf8wZtVDO|7JLKZQ^|Q$=nI3C2u|~0lC$J>d{C4)PvOOCTOx=4330XYpe5aTZYvyi> z{=k<#5}U*sJ|WXyeNQ0d&xwl`EF*5;L2|{|`;tO}YR=Jj->Ovmc%F6};XO>xaIuW!05Ss)M+>d+d zcHUL$Scu%YNeiy+r~{h>4hbid&3|r(%1_p@x*lNfN8g|M^?8*@xL7z&;QJqbg-q2e zZ8z#1-+!Kt0R;RwOywRxyug{ypNlz0WMOQP!P1^a{#FhP>6%O}DCWbiJ ziD2^4QCW%g5>NEk`E(Cdd33zFWZf(tVh1lO*}egADv2L9D!LbypBy;?EsZOf{I!~L zuI*!jgR-Z^eD>=#_-3`)o!&fu15X>2$gb?UMTZWj!pO{8yc&8kGt(d;SwWGAHXDK7 z{y6S$w<|i1drcJHOgT*p$nPm-2&9%L+m1OV&#~Zj7Dly^4nsK0mJcwrQpp8LAW>EZ z<=gH(famo+ODt1ry56CMq>0-wWlb{~om0yZmMpeL-Ru{OHOVHbx)e5%E_S-lP`Cq7 zKwn3T9z1cG@?I@UNftP3{bSUO_lX_`#fX_1ha@GP+~XRvKi!Tlmt65{{R3#lK2IOC)&C_Ha@8*M*H%cc$tlx)SQ&!b?e8;Q}Fb1!kJlG zobzfEWMuD%<-n)~4puQ%SJ<~3x#PXLr;j9uFyrB4BrO5j>Q$w(-0a`&Rt*aF{W=BU z?*$~#c4Os$f2xIUZ*kavuS`C>o;$V)VAxY(K`w4Yc-Xa=f9(LofL z10xRy%AYaEmo7#5fFZ5R7@~n#IR}lyZ+kV>-6z8k>e|C&=2oMkV&i#P4)(D*Vt)=0 z8*pW11)lp7J^EnQ1|Bz@xF$SzDj9%KRevV59e~7YS z$A$w0CPkxs?qF+u{$3Q>u04lX#$SnN@dieAGs84`PArN95Ti*pbAz_b(fhWY-=1D&O)Nfc^R)Lw^&b++t6*hE;Jrc&+_>ftg&4ws3L#)vsNs$N{`gBn#?$d}PBWy? z=Ho|_(TH|I68TaFQh`qO-jOgS+UTejdUnIZ$Hhf6726ldSqacU^vdigm zrr6N<;PL*QGF2@PlE;R0+4iH!BfJhfd4hv4`G2VC3>{Paf!etDo0jKk zh}P3+zTa1CQFSKeEsd#bGf&FH`e82oEXgAa6UfUmET~VHd;m#Rziz~L1ocy1O)n<~ zY#m%r%qIHG$aIM|@}_$Qnjtt4EQKl_o5OSd+3vR|flVY^~os z@y)Ge$1jlcv0)sUF=Q2rB~b3Di{`fD+F}-s$BmH(;4vp|&_$~P zFPlF7E1axYQC2*K$I8mZc>K8L+REfBZCmYR0Y|Yb$4ovD35y#=E=;re$|R0i95&?y z(69jDKOA;HZkc;~Dt)ChcHhADKiX1zM`d`i_Z>pU{CnZ&*L5sSM<33_o;+NH%8Mp8 zb0$tW0K|k?F4R;W#DVj`ZCAnBTAzk=XtQ-W@Y+KYOQV?fE9Jh_wgZ8+6mPIes=jNj zpZJ7WYT9t~QE}lCPmr_$E6+YFS-5!^f_zPw^W(`HK14;? ze8);88U!e@Kz`j-lS+>pOi}#c%c-lCK{G2PN0kwR{m8aswuht-ZoATQH1L{EUb!R8 zn6SJs2+WVWdlnI^4rvy^`6M3Q0o64f7f{u5j+u#&(Jmy*9!_k{xnvGlvY;eZ#;PRu zEya$ssysEILY6d>6QU{Loe~U{L&eU-mmwNYqlYzFq-6DFuv2n(;X`iPzXHvZeJxI@bW)@vdH7vXpc7H& zkWXG7)9`#Lq0J^vJabJdM>awzELEv)FvQsbj?h5o^yj1aSaL`7d3ueeR#9hz9072` zP^fmV>)c1HvA#d2q0wSPJi-jQlNV%&%Ovhfvnv)=DhT8RzDNLoP4?-l5??R5e3#;=>UpS7YTU z76|~GKVU5N)DvPsnTL)gRSd3PXLLZ6r)jn#g_mRc0p7Y3o2|vB>e&+^GUP&r3^@M) zD0fFt;{Gg>YuNzlZ%xxOJX5UUV2NakOqTPf&RENskXR41*a{#I)8DzB{%+8?=W#>$nnZCvQdk>)F)hSEl63P&q3k6|`9R|F26@>fpKuw&D+X4GWGhc<6BCU6@d z1u;w=i55w|Y^?$LZ=`=5VZJ}`q4i>ni>T#Ks0bF-S?6^z`c!rZA_@(VRG#OrD}<)( z-Lbv;>%ne4!|WRrU%}iq@b`d|J0V6qx~5xZVy*5g8--Zdj>t#_s?QWp$5wSMa%`NG znh9r$Q6ohaMYOUo*iR&SuISeQ@z9+%EUgd1`bL{NMUOT<3~H+wx|N3KED5H5Kp=`V zdZ*#M{7q9>gBQ(QCU~A{r6keF?72Swnx7d1s_vnr$W8+Jcm!jmpMmAfF zc9F5|Rm-s;ZS^mu9J6lb*Ny<{*sRZ_T}+7`bQe$nJO`o^>BmCT@iQlsrd~8=N!Vk% zMDAk%#u$;sw(bDkUepIjx%-Hk|}6g z00#o7kK3ipY=xgyjmaWb$c!xxOO~)dTd(cVKAT0%Us19b z-M9m2{Jp+<&=bSBnEHkvhvCAJH0*qHD$a__k(H=6!{@Y$3Zg`+qj3R$5UPUKI%k$# zeI5xiGgcfuFHeXF<5da@kIINW%MrKd^L+H7q-rWtT*}n(@i6pgm+Q4Q#-DJ`W?#dN zjgrcDB7hJ0y~*jP8knx=vqxI(KRfQK2&c^T*Fjsu)wGN)UQZDCou*gSwFxGUG>Mo< z$eTw8+V*gJ3j1`;qxh3A#Tf3|fchOfHOyGzSbac`IPYSl*#s#*vM_X&WR;+47H9VAgzHwGcP0nJAr&v^p-OR zP5sshbVn%CIh}WSqtV1UnwS$j`Ti8RIM1tQYFJt1qh`R9GcplRz1MKQNLCF;+*iHy z&O9xT{Jn58V=RP379m@qsFnt2PHK#}-a#uKsU(sabtph zdY`2_C>J|WNdEZ$07w}2&0yB%XX!7DhWHX5)+hBmqOPlr|0_)iOb*f}R z23#^ln~%ODUSw}=U=dfv*8}zU>lxJX@+C-fv9b;`;_ukgzR?NndHAtKdmAKk)`zF+ zS+L}J8BZvhK>%RVlCnsn)DG|JG)VnVW7F8GK*QQMo_qZjC_Y3Jxh-nG9L3Q5L8MEk z#@KKy)8R`HjhZ=peC3&zZHVIY?;{9A#JQHvDiN90RFv|s(3TFV2r|>2gk^oO9 za@PZoNIc(EgZmb-#7GiO~kJ;PAIVx=!~NVLG8@ZB)`@$K3@ zJ3b7IHdmYQNeo5V+&CZ#qJBsA?OhPW0$7B&X%w4XWGbPyf_EzgBh)t^EdHa84@}g2 z7;dtaV|TA~*_TJqLNti@6lIVjtq#gU4| zBt@N2f=MhlPqj={J%d0c2qy^@{5%=Psw@{}}+ zpq>`Z{5KqXcLus-*1^=@NIb+d*!v!qya}odp&!>uXDlQyNY}Bf zDdXRk2lwf-LXAZD*x9V+Z7>+FcCzvyPzW7}8^H(kJt*ft`EX*xuDFG8(b-#iBd+D* zXgXF(4X9I1mMmb&Y3cIOLmJ}VL?8N(!RcGX0AcubadA;CqMH>XATXhiA>z*?)BTT4 zI`&K~UkO{yo6g5A8Z{MGoKqi_K2hV}s9#OO&Y4p+LqiHk9ZPQ5T?}r)hXak{{{UCp zq15kU89e&(L?7{(Sa*f-%89YMnu}%fBz!ha zz=ft+5>CWb(*E=;9);=ngGURDk)jCmgI>4+L$-a9fzi8g{>oU{I)FFeX;i%&x&o^D2DtWYs>$b)I+ zy8svGk=7yN%mb$wvgF5$=_YBUd1MTYZa0PC)rJVRd)OW8t&2J0mMA5WV~GG+6Jk=M zfzKVl+{XTFo|QadrekUT4T5~SiZhb(OIfZwNn8rceffC9l)9SwCteie-O>B~4 zByySc*~mh1q&lOZb=S%PhdxdwpMjnk@>?eqG00*863DE@$Rdu?N}f5Ut|;|K!#Oz^ z+V*@we;Q~f#W0uLA9P{1@Z8Z}K6`QP=#L-yL~`jeqvPcUcy>gp@vtBez!FS=Fa(;~ z2=DJxMa>d;t{F7V(qu=NSrR2$D!!Iu{vH9d?ri*Zt(C5(=-huuFhiwlIrxdCYX$=p zajV7-BywZ<8zJY+Q$~-dBMTP0zAmn1X}WekR8nLOjW#c-Jfl(;Af89{Zs+gG9^EPF zQsw1+Ms(?Kos%wPP-99Z!&eWrlONVhY__+5o75N}8vrWJrdw+i@?;|{Hl`OCzh{uHrMhOT4M%>o}(m9|jk8Y>aS*6j@nM{6O zWXo;AVi&pi7h|7}qKawp@g^>;?ud8!3V2|(VA!sE8|%#u7sv3%JZ_R8SxTzNzOA8} ziM~&yfzQSJ^gIllz?~shuo4O@g_5dq(pFTCV8PvppaA6k=yUpYo%l}=BO_Og09P9q z5u=*xZLu3D56lQl2jFz`5ia5hJjm8)84IZ*iQ>T?;1m1TK|B*HWW%ns`V8V8UG2mN|-i$JR4HzATs1gJ1{d`z86X$DNtWYjaNyr8F=jlojgi53sF8tUeZ zVuMx2U#L5z4H86NJ&v>mkj8-)YR?tg`Za|MU}TvfX#(vrxg6CnBaMyT&o}NmP1JKT z^o-P>8y_ZS^M{-w$MZ=|&A0{H*Xh2)zvnU@@^ z3N9RyknSZ^E4_CBJKHe?aoBP1(jJwrW6$IGCBb_?F8L*@&jwE9{gSFThV+ctA8W-+Q1dc5Ao#Lxu`1eA_%8qxFA5+GRFi+;rq#cB)TrUKAD`MULX2zCUSB$ioH5qj2G34^R+J)Q7-U{vwMA)Ip{b>Ak zOAEphrlwVLa~A|@zz?R6%4sAn6r(61nlM3b{Do84S5C6g#Xwjn3&r;0{{YIr=g`rp z<1$L9`-1R6gfMeT^uOZn2;>p_S6Sw*VM8T8J14~*tY>MN+z=lR_+02&5YH^|lftjHsL#F2-Z zpHJnQU?};EC6AsKkL%DqR$M((N{vU8D?G+TR{V^}8G^RbI49?i*QeQ4&!lr3o*aCT z3qweR10P4o)+fQm#MY+G!pSL%o?_L~-&Hl?Reho6r=ZX^>*xRGg%8v;j_=StzK zm4O>T0?0k=^#_cy(oH2Zb!<#LIN)M40Z*wiIzqmdKv1{@x~U`$$_;VRsl$Pr@XH%{ z3G%g}S;ix0kL_a~1ck<@mn@2^vSUWhO4YN-zN+n99-hC3I&M6^K9@Hy59ZkLnEtxYE_VcJ92x0(kFy-9!z~(BPCT?gi4-VWk6sbYN$K_IQ=@&e}+>y)OBc6 z8S*~9U4_)fjTnwIw1VVa`O4KlteR1QU9WMErk&fuwjxE-fQX!_rqHJtiJQ zrSA>uWmWYX2bw;RYPsteY?i{+^!Gp{X!2S@rB3DmZQJueAJkv>*guOIQ{!pytgz)_ zMv@2?Np=|IbqwrODBRzfKx0FL#q-uALrI+|)5SJ?@ADi|OM_gB)qvHbzXOwk}NK zEr6dfzum7t1I#4;{{S6keg;V;@ZLj7GaP(;?%iy&G0Ml)|cVzQ8u3x zW_`v9vSkBpiZoP?X{i4IZntTM{{S3yeO6Upyr6zF$DT}`Mp)imu?3QUC3i?;TMVi% zx#G{j`}7lB$2ocHmyM9Q0N}yr$z*z?0SQ~~01JJ{_#W;$rW>70S$KmdnG0jC(X*Ct zcW`+2qwso7%hM-qW>|6ll4(;V$%<*-IOS!rVAZRIQ_cFl!M=&wI+Rr!0IJUScWNIS z9jv=YG_pqBpNeU!eY37lJK$2Dt0C(V9F*mleitAs|Z}(bFj&3+shUrR1QSTt9K)t+M=0?6%MXSX{}SB|>4@>5U<&cc+Y!fhK-pB8k+ zz|?%W)WDMn!^*akxGr+}mI3d!O_&vvQ$>*M( z@qAr~`lf7g!efd_*p`{J%MEv z?Zuy-jY_RrMjYZt5+r%69Ih4@@%%0lDH_US&KxjcT~P1`ZoHEal_cZBH>L9_jPAaD zzCPalQlA9kg(<1#nHr3Z3M)|m0M&g>kEUuFZlJEG8w;b5kVk&i=>&jlr$#QE$p(Br zRdSu<)mQ#ml;MPOJQSyvl~@D&j<|r>X8LLvJxS1n>ol7iQ{-Tx=}Z zpsA)Skc(3+>^5DHyGUE)1Hl)^_OQt)6(&JR2phdySHEiQ(=@7#LrH9^lI9q)pr7xN zH5qZ{c4?$&f^1!tO1@h$BrP6!vt*m=y)RG3%$@O*E=c^@94nS!fC}P;@Ok8(copx} zhsSwYB=aGWkPsPoZb!&(^6En?uwuqvN2rEkd86NtpZnvX*QZgSWCzcRmb?&%f8e-f z$O^iKNr0)eLJM8+0Y24!+lrsH5g>T5{A$P(Tbj_rKGixqb=7&8Pldk)-5Accj?yY@(!9 zQL5md-=};Fauo`wJp9q;-@jg+7tNfxk=U(zMFI2i{(bt6#mDc;N#g*BZ zOA>!fmK&de*p8lce-2{h<4g28IN5gc`F?ItlO|-0ATJ`1$ZbihH@KP|Cr!_zTO~qo z!-oBTe3UwqOJ%)Xd!y?IL&=gLg>hx|c_6C*P4h$%S7(m@0IyD1c^Dd^B)AzSAt)or z3+YlT^8!2kbKAFBI4Y=xgp=aE?_I!{$l%fLc>e%jw^uN-rNGHwrkJsB$kEH{yEV1D zax0JSI&%?*&SysCUa<}^(4v$957jdvfD zbqy++Nr~IDu8L{{nzMZm z#87GvwUGI2!WJcLF#vuZ`WIf`rEq#T<@sh!$93`O)k3p6i21vsZpaoa z@@T}KYR3Bk9?XDPpg}zQf8Xpl!49JlG^N31U>K{Q762#Tj(Pd(PMB*!4J1#Om&X~E z!l@&?5xj4z(<# z3E@el9r#i>_Uk&c90qD){$724R58HW+A6sVJ~WfArH>{cjN0VGasr;jn(f$-K^*t% z*yH-#W%ERNkPsOjG8tR$06c!GdJ&(LiJu(sW@KUJ#TbWY<64EX2dj;z?OgWiW!2%t zEV&>3Or4u_lg9{?9!BEXkw_{}xl`Yg4@^@P2$-Gmua@5h&SOrBd{{DcjIps~%G0HI z%d!yeiyNyL*$)ya+dz*}{2RWZDGqUyBWmQzWMYHJ4QsSp3bFZ^jl3|fk1j*Z5TY4a zkR9M}F-Wj1A92X;EOo>mNOFwYiN$G=#9&KkH*yUyZ-HbIZpCzkYD^PRg8V-{b1Kbo zcXh~CCfp@BFrbP#e<}nfG(3P<6|e{+=DME(INEU*lA9zmG?GEQP;t2!qVfWtNgH^t zVb4y7OZxT3DS?Wk9K{mJyt!bgtJv{WHvXfII#bjqe0;S74<8FB9#i;{$1Fq;OD%eX z0nfK5pkYI+nWiDYTwB9v3eTEy({aC`x{DJsSs{(I`HPh;ERY*O#BoS_8{~jU0FQn; z>Rm5U$Hol{WZ^q71I++~#noT^(dynmi?u9a2}#yy;)#*smD)(;wg%0c1W^N;=bPiB zxL!BXGGX%dtbC0;?NR1J=19jBLeUJP`}gU`Rr-w^x|nd`uU=}66y2eOpOH4Ck%5(f znK${VcJBA~?bT@W@sW09Vq{>C&R9&_MRURDpVO^0Xu5t@0BsY?a7nrR=@=^W*ls?q z-zVaTB}r@hyzTNl)r|+VZ{(AcAv2UR=Zus~ z8)Pxc7r8th-H*pq^ECZNJmVG?G_w~_+wkK6sWw8YAv=Y8p4Zc?{s}WmeAzMC2RoHi zw;^EPP&;DL|PsP&XLZ&%HGHx^)1`5W{91oAzqv5KW zf@%z>bjp{ppjkcQ>sY8*L%kWhtg#-$@7wLw#Mfb&NDPR^#^}#(eXhqz*zjcq+2>-@ zQAG0DNB;nXEBkdki!6YyL_VfoSwW-vA92=$8BO*E=|Tub#*o7y!hc|3pO z2=?R4tZEs6uK?k|2vBSd;>q{!Pky<^)Z0)MjUGZw%1MrPjyUhP<}O(O0O?bGTTIoi~v#Mry9U`IW=7e2L|@Mjre&4^mAJ~4=eX0Qk*BWK-%8XN$5 zH`0t1Y1}t2hrE7K&Ptl!#T3+M%G2O^rO8E1XpGqo8*6Q6R1B&>W6LPI9s6l|_gG0M&^kdEAr{PWU2ucBw`$Y#`a+>JXs>Y#!=Oni1%nFuQ+ zn}t}7RC-BUC%NcPg|sYf6G+!^@-$hsVUsFH46CahEu?`9Z7exeBstuq`*Gg-4NAC~ zEo)1o_4CwT;)N`-T^$vtVQZOE1XGOi${iNKZWF+{PV;4T5eE}GXp9X z--$G26H5O8mZ^c=3l98pZ?{R2Y91EI$XN0GH{*57je^gUiQ_~n8{o8yS6{LF^+#5h zN{$A{#LDsZJaZ(ll%9M%uS*s`n3Q@Y*!}O0hA|Zkmr{4Sukk@59}7o^4={{c)G;tH zgy|8NBsd;Q0@x_p{K!rR^8J5V$`Knd>Ut=NUH0uerHXbWl_VCc`*YWVO%qbd(=vQdr|J{WBD@(H z5als}oRQ_a#_Jo#fENrmFziKH>dvoNoXpHPMY-4#uG#pze_UktG`i2hSK26i9SI{ z<&cR2%0(3|x7vs!Zv<73w^X!$qsqo-!p-`GjDaIeLT={4Dj2cnf=LAZ!03dMwo_Ej;v@i zKJCgq_~33oJaK<+h-4EqWhCCb66)$JX#`Qe!sw1Wj;8udnAgt7$Ebl)vP(#gwP20R z4<$+M&j5V%rDrvOL4|fOyFn_R*L~2MD!`Ocf0!R&JCAQ}yV0S;iy^Zx+i zNa2m!B@Ag%I)mv2SQgs1#c*!VH%F|@P9w6WOdrp!`rCD*hNGR~vLmg(v=hc2CdG@u z-X+nr=9%F*Sqn67e7`6tEDCc>Y#XzCLE!bHv?VYkI%2GNdof-D#My+bOrQ%pK?R3? zFR;ET<9J6$&eU}YCc<2qH30jhonv^=JV`()G^=zd1I3;zo09pl={jM^#u!DK2_=Y_ zNR>jJl}%@oj3|*n`*q_nm8n-Fvj*GOt-?}u5JQftr21YSMC$~AW3EF3lGDUj%t5(; zecT}LTY%t-zO#=R>3RBQRyMt-Lo}ushBm4Y2HuUm_w5{R3a5j?9^t#_Sv%sAIoYL2 zp+$J*Xv0#HLyfoTwFFr$^T#8q`FS$MJpNiV(Bve^k%aP?Lo04;5A0YD0kLO_1oZy^ z(W=*_P`Z&3wsb$ADIq0~WjC~D3o6Id@#je_q}p~_Az4QCRA&|i*94j%)gBlE2I;Xf zH4PWehf7nH21HO8v5(>vA&_o}n&O7mUIFH)@zZa zHg*69hzkq3_U=GHUTKtZ8Jc|pP&I5xP8>@Vj3iGnV>{zkHD>6Zd9tg1t`A=I?xk6r z_8zaoHQ-m74Rtb`v`tmaQ5THv0mq5>V-fa6VhN1?P{aZO3(^g&DgOY9xVHZQoy2ec z(;0Id%t=z@V`J)BYpmqQkYvShn$DXLk|`n+tY%!SVahRN^4Z6yk#t8@HO&(z3`3DV z#=*)@Gfm2dTN2}ev()GOcmSt7;4%#KX_Ooz6PJ^LTZAPx~il>}9WAoD||s#T{-2)WtS?k~q( zQ9CzO2V!5-GYsMM-B>bY>{*gjZ%eMm+Qo2Y@ zBPb+!p+h4cH+G}hxd+&Zp^B+N^7g&+HfRzJh|Hd7V9Cvc9kZc>YrHY-c?<<4Qeq8Cf1!f2QKPqM>Gzs7 z4tBvF*Yx>Z&_@J+Gg;T-*QdzR^8|Tt$rF7%fXfC3dJraWjq@W62(VnUd`BOR&>0bpWVv zOm2Y+-5+x!f~_u|iPhiHB)Ofx9WNi|G-mYSa)Ftd=XQCN-^Q~6Db zBr8}ao|`3~16tABCkk5ekTu5c8ms`#(;n)l+Mfg zqcN1~wB>U`h2g~1 zH9b8VmC9x4(67 z%)h@KZT=PURC@j>jzs!>MmbubZO&wmlYG%8hpN6Vx$E=1SvgR`BZcQ!NwKhs30IAZjdMOZLqjx?$egRA1vUq9?hW5Re{PzkR+D5F!SPh9M8876Pz;22X$zG}J!pg0 zs6eg<=I6if$5k?LbiC0h%t;%~+qjH}3M-2O{{Tb!^^a)Z#f@qN*{qCRViMrFo}r$q zhzz2=hb2km^UqE1{7=zJp@8PbN{fzI<9&yV8-sE`ZklWnAS7K%qY5Rc_#+2ZaMMqF zqVnA*Rmh>-ZE^&Hjqn%)X8NO*{4&OvyF@g#X$V#gro^CueA!kY{)UHLCywwk7DUB$ zcMiT*^(Y(~usQB5{kpX-aAuB4M6fK1>YeH+e4-S3cx8uH5s{y=PGvs*q{< zIZrE)M2R7C0U+={FgJd~rInf~EY7=`&9gitmn7LF-zNHQlNv;pk0oK4i>3qO1;v&~ zbnN|m0nd4{wLVEc`yN6VcHmcTiD}*|)tN*X`tG@rGi^<>W1|MMNAjUJ_Xm!aS{xa% z(BwytEV}`PWQ^EbG(aob$Fb;^m7zg4RvT&XV!@Wut3{HN2)vRlgO}St3O&9ns=k&O zFqbqdHP4Z9wCpvW7gS8VlF);>Jm~>)t;JER;PFPsBaW`&>Q9f0^ct+0lH;AH8#*E- zmLdxG#nv?3 zq+R?oyk(VzH>Z*tngkBqbJjDk&8jp8cX8BgkWt%Eu)=H0pG(@gPn5Zs@-YkPQkS;4 zW5TEapPT;O3X9FukzVi5PdXs#12U3Dp2zRV2cF#&f=xSHgCjXHF^stNG|cf7XxxGb zRV%qoj(P8Q+pe?Y`e~)dnVk7*1@8f*6i0psKL8u+5$D;3}sKCa#P=K87Pl9{-f5Xm%9Ppd&9fL$^{I>Qh{Q--#x3PZ{o(Mk>M{4=<(n}iJvB<*yeOfbRJum zkIdt1Ue3fH)L82$7Uq%zb(8r&35pb*snXwp^040wYneD+AbGIzHxv%g{X4K@&ihtV zK$4@C@9%u|sAFoGp{JiJO!@wzLnvm*^A&;YL83<$*!7e6S0W5A6k&|j< zg-lH+I0$qqIDRISVj@i}kjq@G3flm`Z&m*Qmr!Qvx|_=wz>Q@=W>%ULe{H_I`LcfB z9T3aJm3-WQp^H(DH9|ruyEaXdD|LOxL5d+MXJ`$`Mg2w4zmI?4t@?EZT^d5kdtS{* zR@z+bjC5?MvoPQXV;p?4tnJ6KB!E8MufJU%E+mcR#~RKu2?|G=1LYU&BT^|8U0Hs4 zzmA7KJnb?1cX!;OSO^$8@H^1==(Y|N(PD{pM2&Jc5*lfPU#5qlIqk(0&(Bn?P3{9L z%Wt!HCr_HaCxA(FLAKx2EZ6v#3u-Gw@AeoC0c>LQyy5QCJ=+BKc6~^%d;#V11@Pv$#gnk~$FKHgu z!}KG+O8Uk^Y8ZNGVJ^U&kGJs*&10OqtbgwnZk8EeS(U*$#y1 zZ1Q75tttaxDyH*8+w*Pb-m9vwG?D2Uk|9~~s*BehpYCx_39S+ZyH z*FQN6BC*{nZ$w@P3Ke&A?oD(L7Z>@ypM{Q-sgoyDkb30-kN|0ojzAm9_$ugkC_OijwX*8RhI6bk_hZ>K7M+kC<1JKpsa)*c(4Z22p`|$tH{c_T&)nLIdG6( z!!Qdm1b>zO-BoDG%vk|R6(AB4uVe;bKe*fldvnz(j_jzeVx(>hyq&B{->R>-+ky7| zdKWqeC6F^Pk+*t94rq4&0KVN7l(RDqyFUo0AYUT_UeFL8f;KG!5O}n zAcYBk1GoIT{R8|7!V>6yC5a!SJG7#SQab|fJpY|zh9p62yD+yk!o0Wv3LHR zZhycXQao8T99f+p`pA613l-hAc`O1uourS`qgpPx^O0<0N0I^>S<*yUcnZE+m!fup zdkXjV=b>^V#K|^HqEhOxm{Wk%ZHl$-x)eXT>XxUeoZ|59C5l?DU&|Wf{_Ch@ zlg)?9K_G~Nw9G*?IV?v26a6EOIqQ0b3gR5$uUhMV5V74-n2-^uwI^Jdv9$b|qu(f1 zg(Y=J&{6eDZ<+-A@qI_BYFdsyrHuqx83_(ZeD{+)TF7B!l6s#wPoL7pXe zV`xKmPj*aB$a%4%9E~l4}kYwgQQsP6B!CFS{Xiz*-{Ltj}J|ss@ zZSy2UCvBpmA4-wkk6=FBlkf4=qjvuQF}FOY(g+r7;16N{0B5Z#cxK3Z#FPV2fdH-= z6m7n2X%tbP!^c(hNAP~jt!|4?%2;47 zV>2M$yN7jC{cZAVXg#jFckri!U{@NBP*VYy%t*p+X=EOq?RR~+v+ZZ1x~^ZhuDpVy zSX^$bcmqMo()8grb8VJztgs$Dqzg(3?#y^5`fkd~$HIasC6pj=MRI-l01G$nJ^AbC z<1#+kE7D0m{Ct!B@88>{?-tCk#ITu+N~$uXatm!lK9E4~Za~}Ik^uW>RJwVB5Dj__ zKT@6Z@l@lcQj%Otuw=6T0Eu6)pa<@FvDEr5MjoMZVWZ20_KPw$$Z2RgsRG%>_7(0; zRrSJY8G5Xlt*jG|0_2k(Ih1fV0MZgY+h`ztk5ISKq;Wx}qC<}aBOPT}&faGKY`lb9ps~*l5AIaoPi$|<)^@^ zw(NQDSJJ14{{V>dcsDaui$~M^_%k6mxcN}dV-jQ}fR?W8fQlqndiSoIt=ftum~njv zoFGyHtw3L<)vNfE#Trk9^eizHpI^3k<{0s=<2ne{+kJjcWFnf_`(HJge-HJ%m~tN% z5+=cA$Y)Holkgykgldr@n=Vj;v0IAd-F4=EqWL~9O#Ky1nZ`VPbSg_2_G7GME4A(A zWb~-)YP*vUg~q3iscNKV_W-pU1=z6VSi3gT;c`j#F`86lcimWL|IAq3Dr1a|hmvELK;wfrOE_;gPd zXgN8uDMioD#mq#4cw8ZkRwj(AstyPsHx2B1#h~}PrAkNcl6>Ombt#&Gu5OE8lO)68 ztn8d1@l8AqF-SCMr=Z=}W5>5jJ{Nd%JQd+4f@KFEPL5e(+(D@TR&o!?`+rd9uDmk@ znuavE-ZsgPP|nk)Yz&BrAt7l6EVd}LG71aG+qsf~Q$uuL3mqq4Zw={q*{zSKM8Y@B zkVv?Z&fa1qWw~fpigW6*b=dWVjLz2f+V_FB?G}YPVZ*ZqEw^gh{{V;6KhVM*>F{Qn z6>`6y&DhjW{%FYk$4i-7H=U1{rf116IV~c{>D((DvHFAhbz8$4&+?6Od>J=+bH(M% zk}&}Vjj|Ki6(kaS)%0^GSc_i6#G6i>!>tI(F-adKJ?vQQ#E^S;_F>gNu}+Ex5VCE;8RD^QY6E6i2Nc-SO>+9$X+Z@rQF^vU7)T1>q@$0*G! zwR-|dKk54Q1_aS#>RB3U%jRpK2972K1-5U*W;{^a@7}0g^xdZ5W9Zn=kS14=2FbEn z=~YMcuec_GH_upDOeK2n4yZDKK{LS2b>g*a;sKIOpVT0l{9AOa^O9qUnWA_Ug2kC_ zTaY_#+wH~IC#5WDv~&mfjRy^n5;>e}pcV(Qt_A&(my97hEy zXL)xP^r$w?wEqB~*z}pE>zK0Xvt&6Kc*skLCXj;?Yyl0or9n-tv=du_G)cchhOJEE zvuud<>J}Ct8jUc6{{Ryv`h9uRHcXhbJzo%D;mm zfLz@QP;G$jFZAet{vyTj{{V=ww5+fbPRdQ*cyOy6s2#SOJlI;=J^<+XaXEW74FU50 zv{e598M)xIU*bNh>n3)Ik@XN~O&mvPUrcuEQ891n^1&jnkfXKq7hKTr^vtX|q5&by z#|rxcRgeqP_9UoKe^Y$)b6?NJ@xSppY2Y(1E!f7#c(Wp^`hxs9y(?m zQ6m2Uvp6jd^aUp+wvd9j1+Ub3;`kjJr~qar4E|4E91)9v8A8i{ltq`R!K7(GL-qNq z4m{Vp$c8m=WeZ&0d-Jt;yRoWhS`0WQ9X|o(lM@()ikucIjk%bR0J>gy?PH;O9+f0e zW@^XFTmPt(FIw5kE*mvT6=LXTt9ZXQ_CaI&OrGwL9Y0=W4(B(Ivtr*n3<}9NTj{*jWxVbV`rk=VYccqX#8EaZt29yOhmI3qv~Y!3 z&7MOR4oISIU$2m|kPK+yfMH0O(Zraruyu&41u6&wfWof3D-qwM@1)As^{r1nY^KM<(j~@))(mqr zg2D8NfgX_+I~(i>_C0ADq)58nm^-08ChE?!c} ztz|fhFGJ4Iz{wmXj{q=MEqrae>GptVHaAbF$q8midx`6-trJvCofE=;$+T91B@zrA zT!xaCMtN2j#n&}+g9n$7nW&_TjwW)Y zNEU4K>f6Xq*W;vW3$mFOx9`f+;THv58y5{wR@EZYbPYpO%vStF6cBeZF{M%e0F{5w zsva6LE92zlBCM+nnRB}Gv9q111^dyUK3Mc4$2q_KX{D8T9bf7sg_NO1t+CiVgRubs z`!)1S!}^9Y;lmsGK5lN@Og}$z$0k?`?YMEdVThxfA$Ldt=Z=`fp2rMM*O(sOLgfOJ zGgK3@>DLj{OwvwkpQ+UzMsF?UAtL95;8?06>d8ND0c3cAbh&ah2_ku9$#(L9HuE)5 zKq|oCas_SM-nto?u0x+LPGn7#bgX=%9w38Ykc9@1CxX_@#PjN)J-SHEM#{@MKUgFG z0BDvNqh}{6RaCdA4ngdkabSU99)*Cz06WKBei5oXlctFFovUW}w_C@^)C_8xW%S;77QARM?-%z zKMPEgGZzuV#t$kSFWM@wl`TjEU~;D)=E zVIms)bcJfntl>?zi2nTT>$N*cg@ZZU)OjM_F7hyP4n}L3p^_c0L}7{8tj7JwD?ryi zpKh`(J4jtiPshvpHf;}9O_ss`v~1Sud9oL2+uQ+sUt1V@rH&!vP(%k zHd1XlBa!rk3WS<+QNI?!zd%)o739i~EU9IsK${AJMe^1_;9sN@!0N~F-%5Q;BU;OW z<#f)|+BZ<8WQu*^Knw??kPVaHsb-crrf120_}*I?Bdy+Ikk*UG4Z!{D?`>bh6o*bZ zn0euRoQ#!L6bqD=3v!b*YD6PzaI&GRH5T95Wbt@4Kpty zA3Z$$V)CT1q?<@$MZ1UR1Q?%91rofyd!L%S3P>rRME8eRZfwy|e#9PxY|Hnp_pSdUTj&7C7C0QRaBW37WtvHGx6=}zT>5@1!dx|hV!G9 zi^_AiNI5$LAYJ#z{5_9w4@Y$`s6nS>;L%??PpVcYWXQ3&3V;2ll4{50JyNS$T;>gj z-=pN01hmfny5^VsAD8r+{wxV9{yFl+Rf{C84{kvm_XHmOYSu(`gE}jjAU7FE2hxXMI!ssK_AP6rn2_R~?Nz z6&7P3yR`ABDJV^2k*^(?v06Q#>stKZNlHc36HPSi6n@!fVSIoi3pE7MKEixxw zQ5a6rM(BpGddz@>WlEaktqx3dgHh2m;V+hgbDb(Pj?tS6zrV+NC!jK)`HfDzJdp|R z2CUW@a%Fh+8PyZ&U8k5vC~pkpfIX<1KXKA*I;7*k`i`Kyq3!19#yHoEnCAt&U7g-14~vOJk!bStUP)yP5qYn>T&WwTkXK9pVjp z6HU<=AUM{#8SS*hxJ1Lcg^Rh8h#P^g=kRsBHm zN1lF27uIj%JSelVv$RPbBzYYgH%Qh%8)-g(dshUG{9W~xLG>S5&5m7jDZ<9JtuxQA zOPpODvU4?UGfQ9gZ7(}67-Ed=@?a0<5D)cm*SL#jJpNkfzk@t8i=K7d=XPg<9$_9n z#Ra!U%Ca-n+Ji&eoA~Rm3AP54;|yI-QkTrb)G#5D2b2U$EM8JF^!0e0de{RU%vy9)~GKO9>!ZJ{F`|Mr~d#@6SYm@Z94?z#RfEB z<;YVhC6xeUwyYC$8I?_e*noH)Hfr#$p^}tEfDCMS^#VusrXc)=Jy(JpY~5EE9ykL1 zKb%CcC3!+1#Z>TA0=q?DJJ0PVxg%+C#>!RqN~%KvL^sfE{Wl&4d)4+oSKSArrG zQ%tZ#(Z*b~s<9+v)aS7rkkmzYKWjeyQ4W#m`V36fyELSmnv}VavZ-%y2p^Qut_dCH zf;jTfB)HyWQM`d+$X*RIR_|av{rZztVU3K^U;vU~O1W*ZsY-_g^IWebm)ubux{&sz~obBQLw2i5i1FsF^O;~+{HCdapEys~@n6z-wlkDj^y5=|T6c!mwH=0QF_ z{l|6sP5O_%<~)3S^q=B#;hL<;*^MCeDPkOh;?UvtG@PJRJHiZZPd6Etd> zQO34B#F3N%bVsBEN02z{d9cRcQwb)So(a<$W>Y(2yGJxcHKm$1q=Wl)pLnBE$-$Ok z4n+9!2&91dQnW0ghX7HsIW|81JDCrclF~3EVFZz0UpyNhs2@D^i>W-hJ|T!>#6+`X zK!I6rmv9|@Tq!E0fjsgn4 z$on$iZsUutmV8RfhvWSYSQmQaYA`Z}VoNsgZ|(W7r%w@L#V$FCpfRRA<(1r$pu7&7 zdEkC=WOMW1ppT@TQ^r0Jd5Sz(h`Fxnr;?D^Tlg$g*R>w2^z5{#J=+YQPtvv`Us0gz zWus;{m!?k8i;*Lct(pYwHGL^XsSNyR{V|5f)J`l%&ECxzU^z4hy@%Lx3FwcFvY!XQ z`E$arB)g$R2-|rwfywy)0AAP6Kzt>py!t*IrWo-OJwif*Z8ZRWME&ZA{{2%0Nv4-* zb|1p(&pEP<$k&Q9&Viz8y0$uo$&Lo{Rk;P20HXWV^IZ4)^poMt%&l`1Au}SlVVzse zl$T&g3e*_!KoegC9+-cMStc(DzSu;?<{Pf5Re5G3zZ3`W&_ChQ$%m%+fn$tCAd)@K zR0i5qhV}-BsD8aL+Ic8F!(7AMe5#jAgzi?f>c-Yz}iS-|@4JJg5Cz@6FLgtcxM>~ zn~xI5j!sLYE)Om?i5(PM)3xynYydWgqV^ryGb3l zdXH+d1^)eKSVB*u^GINs8AmEaBXMYgw$pup+bvgnE7BN}VW98p-7!OHRkEH&)K(IC zjURs??Lf+v+lvZG=iHuw!81%EcSwrMl=GY7fbKs^9TU%nVA)NO#oe3Bl#4XgxrN^& zabbV(_vmOsnrh9pytaiRQp0UCbNc>Kf4J)=yR*7Hdi74QKw4+;-e{M@&T26{dFhnu zP!=Gq3itQp{J%F(`X;2ygt+*s$&>Wa@>i9qV^&oh^2*E)zoYCrLGUya&7(L-L~oms zET{sI<#vQpJ5`hvN3r|!rs-IdX&8BHknEW!96-P$9gYhV{UeKvgG7Qr=dIcgBM#P` zy?lABy1*Bbt{`09S2YT_*`F`s5J4M!jzIf{Km8YetK>l*H;D4*%T$_3@&?LwN`6J~ zYjD~HpOzx15o$bVi&oAtmyRUKl~@L^Tgev`Y!S6T%cbuUWX*-Fd1&Ql&dT~&@)jke z{5B=1*x-R&dy(_i=QT4aac77`bNo+%m!xEPeJy37_O%y8>#vMx?3EJ??Ly_=OKtb)>cS*AZ>@`l(fFvDx@BZ{g zeQwlcdFz^O$QU||NZxmoy2>)sDJSfEAMN|}zo_Yu&nd=id1Y5>gx>DgL@?}oT~%}j z4PfcdBj!z$7={KCLnJDSEr+Op))Wo}1K#hearlOOj7k3hmNq2r%F)0+qBSByI1J$1 zQ3S5w3FIH1v|m_77z?{M=oc5=i;emyo7pTi72p$z`*&jl`P-(I4G= zBg1iE>Je%fa)|MvEbosbW|f824~rv?c^@5oB-RvuiK<(L!? z>rlWSWB$J2^<_2PM+j16GML<;^1*wi9N8wl=>EMj>G;}A+H5VWNesC!3M{@;Y&-$o zkn?^20AAfzkHeVq%_C#JOh?k-M9RaT>KlO|)dTZgIoq(92gwH8Lhr*`;l+wsvP|+6 z$cxLCNZvMG}`njfp$rtZ@<4$VPM^3 z>9Q+L7&dY?GnKwe2U0tMzyNe=9V$=Fl@1n3G2bf`4R>JfRU*B=FM93NwwWh9%<@5d z+oUMRh_w8ew*-nb^HMJ^QtI1|?i7Re_^KUxB!TCJWSHVdEXy6^<)bs%t~b4dSH*jE zK2Cs)46?_I3Mm8{3-?nsx~V7fpRJMzGQ_y5gbA_&Dj5Ny14m?ST?EvyVS_IsTuOp{%PdpNhiIin(;abL)ZgB{ zx>|)7Q+{K6aQH_x8u63}Qk@xOQy`NXINs_+$z~s_kSp7&(Rg`TnPtwFe!wc_$;E!- zpjf%yEqsS~unw)|y3oSRd}D4(sMvQYvIw9%^uvjh;*7iq=a)m&aH5f2(m|@>ISPzJ z5?NG$DEr+h_UERmVg(c5IeOowiUk^u`);I{xJM zVzhB!L5_+qbTMsf=aLAq-oL*>vNZiuP{xX8$%jvlWR6CB$zFHb_eat~U5c(~_wCT_ zM;BGbk~NMfGTem{NeBvWbsee+1lR4)LUt@klRTwUvT@X>Juu^7%$Ok?d-lw^$U~#%>({0D~S_W(881UGDEe`8@j$ zemW_MtZL&Nnd6r-Hrhh-jOW&UC0pzXpn2&!u4QLt1cEuEQ){V+)Gf6FMRsZxgGv`ACrdTc-|T8HCI0V$G7ZyuP(8w9V!T+ z$A&yCD5Pwg^QDd@8+H&Z(F1~NfW8MEDeAiKh;+;*II9k+F@#MFCK9N~FLf|GnUAD_ z$UKX>y9$qQ-DBXWSR8w)yr$V0xi$^6Znf|4@z`~0HW4o7Q6TNR*p9N?58}>FPC{a3 zczZ18G1y>)lI6+Z1S%W98+s`Z@iP)>v+-G;7hHu)9bJPmpja9n` zgQ8^D{2hgVO z?~_E=ek@q%%KrcoMm}-C@jjmT-eN09k*7VpcA(f(M2~UB(f*;yZpZPThP8}OrO(Za zEgga=^2r>Z%2m?4iaY`h(NjmFwzcP8y;o&(L=dti$H~xQGHLfVE73Fo5Z7uK%Ke9K zr+n0wY$+HBo^pe9ZVtt285=o*&iW)U=c@HZ*gA3(329WM$^ZAYJXN;<)Kc zBSe)^%#1TJTm{Kl7ju;a9sdCNsk`yVAdb4ywW%?NK0dW6k_nimK1+gHHtn)rC^eBy z*@5})XSh9+Q$u6p_&=hl26Iz7BKY|kI-FR!`KyTw>Wz>lfh83d$rhg0#qE96LXl_F z&s3&@Y!X@#=i+ZWEzNh}gWKTu_vnM+gq_OmgC(Rcv+x5wk4s-1fdJA#Ex%j8=sIf9 zvD06|p9f9F^7S}!QU0IJ0i${ZZB}k$@436$f!nSX&KZ$Z$lqb+xPOrMLPq{(lPbP% zmyYWu?d}v6Yvl9af`8@@TAm<^9S0jTOqxjYCC7^(iSkxN$cXMq%0LtpDpE3iM}XbC zbc2(mz7DAzSh(=x$%t4)WsyqA2PlTa0@q*?cF+UALA2dRRE+-sAjr(giwZ=S7~^DR z7EnsI#TIMU8)>ggkff7b2N8w-V_N2rBK{G>UEVtk5K1I7Fgup3i>TwaG;y+(67FwN zK7xNLkC4QgKHa`9dGX?vfS5C&qDqc?AD*(M)Fz8e$imOYY`hYZthnUVxXd>8_p1uR zyIHQEw4V`UYA`z{R33B6e2>hi=9h;i_M0SrgRtkKRHIUpi(jV0=j46Rj1elXcAO)g z_YnS|q}W&ZzmNOx(*FR{E>wv(l_osNAyDUntgHc3@~7bU_TrCEc_7B^9OzMn17q@v zuxs3MIp`Ltr7%18xM;StaxE7CUHAOU@;^@9QI$A8Xj9J?aEMRQMJ8BNYIVS%VT#er*GeNiCCb>pJ7FlNRQzAuV3-w(f) zs><5V6f5QK$YLf$9>QAOKp*1WUmZH>K0VO21yL?%)5_1ZN0S)@k_`|*Do1`n{@oAM zbX<)-Oep+Cruhw<2*}1H7LO%(FI|Wt#^8UyN&X=4&PEfL-yL1ug+>R{I_~wif#c6aQ%$ch@da#PMW`bP{H&;yQ3jYV1Gw%x-|y1qrQuVk zm!A@7@dTlL4vwKza#c#U(YSlEk~e$wk)TW`@+QZa;p*_A^WeyghE}pS1IT0`R_i1B zcpzJDlj09j;OFC&sMM#DS*U}}5^aSO>Gt-zu9X4pxI!#6&5G(xA2&uVCY)rC9#2qK zDCKAYPeW@SKQiqnn3nEO{0-0(hZl7A4$K%ZssG{$Oj^_xb3>&3OL+Ad|mBhS!u=4_J$8 zoJ@?3J;us1f~;ts12H?hdlUP0TT#PI;H>kjJWN=rMl0&8`=~TKefsHPi3DSF#T?6U z$B}5xzU4_fWE_gF*YDM+@Sub+LfH0f?NX!lp~v}jxun_5-n>^Dkz#~0{XCvdNK(@7 z3dzNhb_dM@39h_`6@n^_;@XG0fwYd?k8X^NG3Reg)>rLh6Wmc85$rmv{Ie~kc9LvI zX9PJ#c!QgGP0-2FfnIk zV+*|nCi{PG-{)N~#etb5W|a%~A@~QLds*wo#+nq}kc$upYL;bVe9;5<>Xm3wtVufP zrIj4pCWqHEk~UV}TW~v`IQSfY!an^E)bjNGRhVj+P|X0^Az5(&+D~)3yOZ%G?1(qjS4EM$2T96-|R;xW4}Y+o1`o$RsBkcZUA}#J-!pc=q?9U)!fC82(mFMRG^< zH`|_(Us1%v%F0bo8cFxc-c0G{0#Qe-8v^#TDudg&C) zMl%Vh{v<%1?d%HO{Bke!=$<~a=PfcgPcnkN+V}1cHYg9@pjevrp9Vx37)Ykdt;lx&Htziw_4&AV7n$99VGjom1%ru?KjM zZ4fK-U+>gukBVd_D9YIt8@YNM@IC$i0L!3~PauuTNfJ&!r_{7VHGRGR0L!mrpE;y; zPcB6ql@hBF-;QYCAE#0anq&o7Cu%hKkr3NFxR@T~HCM+yb}?2^sG-~+%2H2%nggYl z)O8GX+R)|2>9+Ke4?ki0_2=_kZRsOTE#A5Jup}{{ZRFRStfd)1vOhSxlYGUx?tPvr(h&Ilk-m=qvb+3`Y_TP8jH^KY)4r zpPt~~LUVjWhpQ5DveQ)hX;Uio8%(b`s^;cJD6Ss=HX}Fy%nIc7anlYCQ@X$V4 zX+66Y10~1uifIQg#El zh4%L9(D2XJg9b)4m@uhUSh6xdGu1Iv3R=GXxT`(-X=(5z^c(cl(k_<#= znny$Sa&~t32ak@f>vDLHR)HTMU&g?MsS-hlh+W9+N0`8q?^L6OJaA7!^#1?=EHQ7w z)8NW>UotGYNhSDgjv0qyNcQjT(w(Sr?%Rp$;TA|8^VeL^&kbbd>e*Uuba;#5jXMJ% z#gUAzT70;M=Tjs{xFzT?=bi&qb)d$xWModWNXN`_VM3l(z!dOk9%yoV9zD%<&WYh< z!H*t%^@Z}{K**}RM9fIpySrFXWSihv==?@KIbx4{W5AM01d=m?RDr(9CyrIQ7u)nb zD&Y?$rh3)_tLinvI`dRv(L$Dd+?T`=F&2X!D51 zqXbT^Q$@eb%a8(Z{odjfkT?}a`MT+9n2-imnLdhX;hgg%LL-}|>H{?)iZ!7baRYuP zQoxf_Y?cg@i~D9Pg=6L_v;^u?l4F2{W`0Srj2dl{GU7~gTfkUM*I zM!Kx`tv(*|oD>-xyjI1ic)w5Z^ibpG%F^m17)J3&W@(a}dW4~~hUAq1P~@I^w}Yz> z5Mbuz94z&l7G{oJIw=*l?Tc~=90JG~qZ?7kQa5mI2g5!In+-AL*91RG@cmrcexHzu zJFen3%eR$g+h7*#*M8kSYO-d@rp<*OpB@Gtevu9iRQna$cZxEL>O`R1JE`WY*Gx}b z`b`96yzTMlCeyoQZvRzY8sxKos8%e;uDBoaLUZ8N;x1Bv4Ut_ zp4{I|8k)3m_P?U>Zblv@5u7PX_O<1}>lC zeIYP)2(hy8vN6w?48m0)k?L2vAa1?D_Z`niz+!)iSX7DCEs3SuQ!Po7=1e?^rgg}O zF%Zg=w1a{LB(@kgHUS}k;FH^~^R=lLPtB3?74aS*j6#7tJXMqVS#0tgEph7a(k`o@ zYd#L~Mx~lFWNkkc#s%SADV?sr09t0x@+U-;$cf9Sss3#CdI{(LrFe3 zcH1&+KA??8)NTRDJONE35+-bg$&Fg3k9mFzZR`mhhjF}cc?<|9*Wt?2vou{IJzvg~ zLDHbz20|K}P03y3&0>`5Re=l?i?uafThVhQ#u3Apn7NsfJck&Q_^lasXttW#=V1zc z&f6f>^^b|B_82;K8wLFNrm2wYjZrLg88c-*sKx|MkC5t4=v5?Ejz&uz=npXt))Yq8 z9MR6yu^~w?wf3Db_N3Vv81aWu4G4Fs1J@SiLQi!pOE2{gH6bQuMlsW;`esZ?RzEC- zD8$AHw!i8mG7-18ZZFLt&UOjF!ri9o0UBeci2`p>2$D!aH|cr~o|cXF-K#F;MH1GB z^{+2-$~uxa{cZXR}C4ocvSR#;u~AS)BJ(X^pN(J(4W{6JNchN`Qe zD_3c8^Kqij!)(kR_Kh7E~`>VNr&N%V_a+IbCN01a*7aczHgsJ*9mKi?CQ&(Y<_SHhkdh!DQ(Sr$b%uu%05SFy2c)o8VB zzXWAv<;fyu=rfi~>VPvu$I!-Ly~m=AtMDue9Tu((NplQ)dH(=>P;&}`952?+xFHzY zO6fi({&Mp+cZW4aL!XTVV9OK#08U&$P<8@?flSCquS?jFc^y|twM{m4$?*PKj(oOKm5d~cc;Gr7>g{!;oeLIK5 zGbpCvZQdu$ZQ;jdd&K72J~|%=hMD7>c{Ld0l6>4;iRKVTg*%jZjqY1u0u?p3)X_Gk zj~z2)VR^P?e3gB`NU|>9K_cu`DgOY7aDD!IN<~@OV3!@wogT?(hx0w_XJ$Jf*uS$_KHXt@{{Zk`#Q0NY%ceX!-XhEX`WY4(yBTdJ*FYf%I|MG zqp-DtTE7~%h4p-Vr%h7}CrMRzQzlL{s;pO&*$LhDsy$Vf2%yD}CQOjgQyNjYfB>>V z0PR0-gYG*0nUM~o3P#PRD@zM3qs~awNVX|Vo4Nd?1OEUQJy4fG(X}S>aU;jXm`D~p zElV9@F$U$8H(JpEa-@QO{c*&)hu+(8xbf0BdZU70_WUo%T7o7E1kMxU%_9;};1D*D z2o_BcL9tiIU1LS2Fy~N3;?2ZGdk*?k;ENU2H_`T@6SK` zbeWy}Kha4eKSser8`_k^RtLE)>F-~E-{-EQ^)_aR9=|G&%mu;pSd?0ZodUo6XPF8Q zQ6<0w^y82E^)4>6r#WWB^CYkVXk&I=+>vxh_C5RctS^8xj9jdIybU7~Jb=~btZ^{) zReDHZ4f~N}+oQ0yMjUg;1jR<;7%YWkcC-1JK)wxrgTGH7sJ+dW!Rz#vE@;?RHy*4b z!8zGFWXBv%Tg_}~P&p)80Hg}P@PYZe_Uc^CWa;>EK6WOfi37>GL5t9ADfAD`WE&&5 zBa6PaIkV?So=n`Bmlb9(qU1^ClOZ4|E^5hR#~uFtS{OL3ll2n6me4h9G73wh&&Ok5 z7EN@C`lV*bb4RKCt4Oty6L}-RdAUP3Aj{-OBw|%){HV!r;Y5Hi0&<=Xc+l^US_waK<>p~c64k{9Ckly zs_V)8OMxjb{O?bBNw<{B7kT7+j(x{jb@5f}{los>{?vO%sx>F}a|3Afm1cPIGJFxH z^7^Tt^~DrFF=p(BNlYSArx@GHMUJT<8eVpxVo>|dy4o(85}$XINV7=yUk zQD7RP1s=U^S4USsjit14+D9Tto`85EQGcg_{l7!e9}41O;pL`oim<~7nOVY{qLiwQ z$=V09_7-S&JvBobSjRApOpTrj90f-S5U=Os=jLR2-g?WC0d&cicz{j3DGYg_#2!l$ zTdASdGvQ2G^%#ti`7y^Us8sVA3w|QW!tScEX2|xwjV>%uVwf;qCX|U0C1*gW{o9dX z`UvCf4bTIs;}0TSc*Gbu?6vsJuMFZ-XPuz>d+|fJ-=-N^wO9eC!%d!I0XV80& z!)X3v9i#$S5CNh3@mwDLWw8TVTKpycnavu5L%y*tRTwOy0d z$p^V0ar4&_!H;G*3m4c}yGo208sIOt1RhUUC1DQfG2&gI3v%j0fK7MccRc<2qde^s zg=%RW?NMd#*foG_^*vgv14M%gtZ|(dDdJhOGBY)7toYc%CNaa5MJu8+t$ASBt;3&v zy#&%_h8&FAVR`Jw9vW@=sFDq~su^7wxcd{=iw0^LGQC5DQL=+JM2`^hFwBND z$&N{!sv!D+oF(u%yCk2>N(J;g7aAmeI(%Uo#fuD&BA!^EB}l)W#poZmJx{IqlH=64 zvPP0)qhq|Km_|!RK@3e>pbS-q7AuPCq*69Bvm!4tAYbC1fjoCbV*FMAMx|PvJGzEvK zw5(r{8r%-&gG3%j>EEi-0%XZYEgP8jU03xAKfgU)k&q>--m8_c!JUwet%W3mWLbo>v@$eoBY!!R`nC`}vH?7R z2R`SX-FKCjkDaPc`Z&nP!7@y^;!Kuj^4Ruf?PLLT0Q+%$ORixJf&`&?C}L)fL;egY zAFG49w=w-~k5WRy9CbqNy9HPwanyynG878$c7WLXJf6xCTg zo(bfRefp0Q8S@fJ3K>zYoyY*WLK%hM=B{XReXO3U^8qnTOsd&ad5aQEksv}NcZx7% zW!%Sed$nC%^HuHEsr(+%WY5+xB-3VD3|erN!GVc8(j;iWls;Es|0wq zN%cV{ft;ZpqquTCAP-HOAp3Q+{{RAY6XE=cvhbq%hRx7rlL*ThYGlnml0WjEMS)=V zyXei&ZqHqdoEll)(Q9}bhLrUlp@|kdtZF>c7y0Jjo;t4n&r_ zQRzn3J4Ax}EpSi3`|<&_JvvOL$}j*Tlq+K*6aYyWDith+0NEqe`hk5O(cm)1(8i@P zS^$kv`F?Dh*}VXEMGOUBu;ljZanc`6avRh50nLTyZ@|ggxGU7lZhbIvg zS0`}~8F?e!w}J^}zkc=e)tNEk&z*AR#f~dgRgzLS0c3yx?OzwiKRs89e6g^!3;74) z?I45zdUlU~D#sjMbx$lSMHHFyEYeG01&A;uZh|fTZ&4TigR8QgL*J>pt-k*NE1dTI ztFpF=Y>#DFM5VU3LpmRs7E z0c2l+xLfue0Jt?Bt=y;8wb*pxkU%{A#{onu#S(Z9-IuX7-{5!YXI1)vtzo0)W94VV zImnhI$7TrScElLirCr5{x*neAu-G%8#KSomxUtWlINvjpNQ7^1K>n^(L3jSEYc)V| zkEszpc3krjG>pZhMmF5?NgP#jEB5NGrCO}Ofyb#;HL0?|qFMPeE<8B#4f0WWC6RWq zV%BS)b9L`W+pPOt%%4@7T{BNfB8{S0-dN<>V|S5D(}(@5DgAGLdwsFQs1R%k%@G)ltVnLA=xu-DpV2K0URhlh{FE> zAoXc704!zFL>HMWiM2eerOv_7abFWpW+{`XpKk&^-s zEJ12zlpaB1NwfNP9R7o%lE)k3pqFeo*zCqcABL#AK(72%Uma75dAv%jFr=3o2Oi{_ zeY6Z-?oC>$Kc)M8^`OSKkdmt>M(D2T7?3paoOMHnlPp;iZX4SDTO&csAF}-OyP;kn z@qQK-t2}r}+J;}%yUx*oqaHHLXdl#}$o~Kh(eLrlyuT1-W|Yx9DICya%`cRaZeKSg zo6}3!BDL}FN4W3RjRV8j`er74nfShZvBa=Ljm&M2GciQ-8jSz}c1pGY3l@4u5m1Aj z$8h8N=l!Os(jV>DTbJl>2zZMJ#26U5mW!G6(-RzWW6w)2I{-%4Q-16Pk4X%q9+p3g z{uNDsT*C1L@kx)TJTPPBOC*JcGX;@6y{bqI$IIH)O+{|@+V6ozc7>{>GGnB;+M+{? z=Ssy|HrlQj8YK5{Y=4L1`q3LDwV9!d7ZgnvQbLm?xf@j@C4hxkuF?dmO9kA-f-F~F zTB}Vuy`wdQC9)5$8pHi;wL8d(~*Ch$}g zYbf5X<*Menr^y^KYlcZMwOnbT!pY1MmGg1KH=;m&BFl}&uaW`mdQWX<#Cg6t%9}yg z6FNO3HzOZX(vBcpC5;cQ#HnrxCvY5)-RK>q-8ESz!t%s1OPQ#sf+v+yMUpR3-6DQc zqm|==WC!dAR+JfV*JlH;*lbgnXx)mOxj)VFBFly&iI<98ye|I$mHpI_?8<%(@O`=S zKPMk67FjVQ4V4z^i+89=u-9?{_Tu)p7hT15z{kYOjiHo8^ULiSVL$?^TI`^`qU&g{ zj&8nYqXtGh=VE0l9owG`y!m4GP}X?_bGThqalz}$*ZO`WKQkb=X0kU!Mx1jv0S zp7eq|k1f4wyo*rBh8dxQPMKjc88Sp6D7M=37y<oWq06UPNo|d(kA7kfe_&Tm^@-cRbEf}FNxr? zofKI){+@lD@oU(=+ z-0iM?`8{r$CxNv6CKHK)iI0yPP9|i^6?z@IAe~3oy7(r50!1rupWrojdYo^;02wCHfr3H3Xm3vAubV}B&|mVXqoBGSA`moBw~9#$;+ zaz~>oBC^8NRl|aRIBPwdcH!E()^fj;X_*-l=W967?2#m$vT{{mgVnTMT@py(a>uN9 zP}cDLXX6OM(nDM#v&|O!wGnNeO)*uci*p!p| zprW6`{{Re4rDEi2nv`mpS&D)oK$wv8X1fE&AMo|p@k%(KMALq`ax!6QCCHN&AwZRYj&#v;+lyN&(;7p4|Y~XI)EMixO6nRlvmj zZ%VK-vkpJ=D{S_lK>KyON$#nL?Ho9)(C+l44+G%kUYi`RJXmPyzzh zsCoYYiR;+(TQkho8%Wb-m7>!zaoTd__bMW}yXTU2x9`Z{b?}jNY%EmM%0n!9MKP7! zx|uh6osac?b|mq~ONK`NQ$N!=i8W8fmdV{7G**jawKxH|?`Nxq8ntBU{mNm+$F8@g zT_t7Kmn%`mjTaF^q%lOwuN)Dm0Q`Zu!D{&f+o)i0QK;Scr;x>urZer@?D<-2}sId=k*)c&Eh$r9+Jd zrRKcu{)r&RJRkE@U-z5mz*Lyq~}YxnA}i|}#rbqsThIm*i{!z`32lS{ZDeWutAiWCc_Kmg>DPe!9% zRjlDBt^7Hu6w5(!90aQi{RR}7Gvu(xjUrM*as^**TDx|yZl1hxr5_G>Yr?u-e2_}` zu!Cp_Z#c1Oh-N&gYA3K6U5V)@^ttwX*%$&U_1_zL+-)f~#k zSKSra^n+jVDC{oPd=E2e+Rum5Ov!Zkay0|zY*PMoGAM{Dj?4(X!|XmsPkuDOZ9h=( zq;k3`$T`^o83-ZdFvPT@vu*GCo|D9Ps|M`-ltvQP6SaJCyu9fOySf~*=_Hm~L}n#e zkN~~BkUjbt;6!L~G;LQRQ=Kf0m?g!W1sJXMHkm5dZ0uMgS^T@YIMWHEh9(TFrQtyw zL9e^6_BHctd-KOi8M?H(CYy(+tdN{cjCdv6Dte=k%+6g8$ykvM_Eu`=qtXTVa89%5 zx8ssrS>y!wr3pWk;N(uIxowIho!J3)X#f&#Vh6JDwLmBXj;d=o$0tq3)FB}wBI4Lq4jYrMc>VVor|(8h1oZK!n064xatjMqlNrFnGmbS*$EJ_ zOf4F}y$`=w*iX6*$cyjVQx%MoM_U$A;>|`}{{R(ux@gm&sqf1d6Ms z45)vWYg1<9&mJJt^pS^&xeF*1S)4ERNhG%PM}I7KUZTy?4ypW2*0Ay>qZYrPlaR~; zJEFT4+JMj&MRR-u(fKmh%FWHnhw*S5%#Fwm8kU#<9YuydSSv<>Emk-^Y~rELV`D)+ zCfJjQ*G}h%>lw!K#q;f+*0Ktvzt-zjn=byFor6)hN6r^`SpFtLmK3h`` zYeh2X);>`^1~pADHfCI=X7!?^aJXpv=3A*~l>`DzWR3`Lex>ogvzZQlABUx#9x~`# z$pw7EiW_-bJ7c#1e@Q)$28U_6%?6sVB*G@0Thk{VV)>2vK@EPR{{RZu=j71wb_Oqp zykUreOSIV7&PkBFZFA~f&FW$dZOJ6j1F-5S&^0k-?f`&HbJ(i)hT-y!ND8jImKsNf zG*?*VFq#6uP!JEj?IaKQx|=|k9(=~fmmp(CvB^@)61WttWTEakuW~BDC#9rWvgC>K zolDGo)I|V!YFh04nb@8(R|$4JQuBF=HvOfNO9zW zafJtH%d>0;g&SO*r28=)tE8_9WnQQIFyw*z;&3EtW;Vq44OV#K$0ECVV~2UhgO|Ag9XOqnw8@Wxb%jQZG*5a= zYu73LCrnQhX}YXSKZmjmhAe{#jE^tK1M@4ZQR4RecA`f;0oOE43D1R+Xr4@|6DA0r zH!Jvx1c*rft;!u}^T;>HO1>D!i$(DPj}|i?nfs;LeQ-qZuRJe}>^$Zm_`iC){?U()Wb* zzvfzWSu@EPdFGW_5S_8M>qQ?b%6R=N*!0gVam|aBCGA54GZf*4Uhdre`e3w{%dB?r zJA8@=FkoF`jSF~x$5>G5(7}Zq(0LgmJ>$%kBn;%E5&GJ0RQ}i#Pjp{o-9R3Gn92o;Dd6a-7&Di~{h@8CC|{x%BO> zNgXD5g`v#J#mb51KY=`Pi4Nsuk8TEx+v|TnbUM&!nA4)T z(DhjIbpsSQ_bNmjG`19rut4m6x&3-`i5Cw84Cw9TMA0Ozo3vr zN^1#?<_Kgm4=MMRuv?wnea{_@^`}ELIT}l{M!s5tN!owifLe&-ovhsZo`dy9K$fcE z4p%|ZesumRVw_*%e~Kas^_8hEbaMhj6`mxMf!eK)=z3$)bFwur2I=A`{KxY?nPLn{ z2^%om&%dpxexDsx{yHPU;~eadGwL%LBS~1H7V*0S&j6a)e*u(x^(TbdDZDe20>WjE zJl`-DV!neURtfk3o_MS4R*(EmBWxbIBUZa*7x2Dzb~4STPGyf6Iz=Q>C~qy9T%(5m zlVJwa-p|PEK$9j-CZ*I0wl+(bMcK-Fj_R&SyW+V3`;NNsFNxn*$xSkGBd#cB%((?k z69TI!?YM^uK_bYm-Cvsk=I3Ka62kBFa$_?(@FkQ3zmMuw3t(=*;8pXTa+-7xdOpAUZJ@B^f^Xh)LKP_(;f-`00vp5SK3x1 z<&YG5YSlqw$wJ-57OCPI;UhuN{i+sP=-x(TAI+qEmBV$yW!m!+Sd|`GWdIREg?3@M z@m)crc()rw)H1bQa~m_tMrAA%9qtJMR{1-a01p5uC$$0=Jhc$Y715DprDD8x?frqV z_5<6c)y0b+FT`@|EtdJ3jB(>)D@GS+hG8Sh>$}jd#(+DC+jmEXsn7tBN$+$}^T_0m z!;>~H4lFG%`)sm5obKg<%yRmn1%>rA^ zYVBXQLUnykJwyG1Co2r)ix|^$6U!0@%QYzbk^Aeq7CugwrA2Z=--3`s9BM)JI57h1Y*_>!+WOS6yg#Kj zMlxcv&5w^Ml^iit4-#8?fAy&YkWcB(TdjD1SJ0j~Ght}smMJ2_DPM}q3}iOb&d?Ys zJ;4lpx_{~QSz4ovZr5(#%3iArK$E?GhtTo9mPk$;?Ta|BUPqP=))H~Kjc1-uipdN0p}O0w-77fsM7-9HJMr~E-0{vXKLx`wx> zWlmcs8b}PSxlgCow_}iZa&P=yHEKA~&!rH-c{HlDHuoEB-#q^S@asJO8{w`dwX4Pp zN#++o%;NSWso{jyn$i-#rKF9o$eOYEzxW=$Ej#AJ7zNhVg%*SaS1 z|Hn^4MW0DXxUm+G$K zw*lLbI-f|2IPvi^#y;s{!BPo8s;aE< zJo3PP->*(ZnIw< zOANT)AHvJY5k5*}W=rHX(a4gQZ@;A!53%jmwT!g@`e!~`Mv=#2fJC4;`v3>`>EO{$ zgBzvKx(Fn^o=F$@sP39RoeOMrmnR`*3R>vLU)$7vdxKncOZaC33{7q4^A+_CPhpHd zaT?ogQ)Ke=d-opaqdqr>A1R`XE#laY?BUgo9ke}Mg%|eh4?(;wg)3^97!feX$HRFf zXu}J3ZQJ&m2ZkyDtMr0vs?@00VVwt$m+S??L&sXJ3Pu|v+RUsM(PUZV+2_AMH`XiT zpAF8MmR3|*Pb3*|ED&R;B*Hx9Dio7jcg-gs3&(Og*K?&%k0Q8eqX89AhUSl?d{@8k z)^)3D@M2)<`p%#wpB-Ic!Hs<@G^4d2+mqV2d-aoq29-fj-!JE9Syvj=a`0BhAQ%4-_;wSdfL<59Ew+tNN08KP*qTUX+VL zO2)vT&eT>MY@De_3LVu#*`Ro#@<}!Nj<02Df64GB)3Y8aUjjwMXB1R2LmNt)!rcch z0VJPD9Yx{wIJHMGCpBiv~M8qRRDJd#B>LJzz=@3&2z)q{{YExzM1hebsUX3 zv!~6TNZHJR;g&$VR3iZ;i#v((&opSGSNx9=v+|g1Fham}2`85tJa|>)l0=qPkaA>T z3n~H00J|~gxnc3tTI4ZfX63}~QRz`40Gt<vqc_BO*zb{1IgcE^ z;zF4P*A{G%K-WI~eWB@@I>w`qG`P$$B$91PKvaGta4CJF_#<^ZEO|+Qi0c^ul3aRyR(D%->(-y0*GHa3ea}ORlSSXt#CD&?4 z6e0IWZ<8kO017uXpN^r%Sk)P9ztN-^udsHKm?#ADM*AfFx$W292Jp;dFFR7sjy=tl zkpenOOidcfKymU29{&L01b6Fk?I2TNwpsVn$|s!eS$Tvx&f1u;#Iwx=vcJ=Peovgi zRP$=BRKte~7WnR4lhRJ1tDMgl=~zz1_UaiLlPwY!m64AG85q+opbXejDui>vATZ=m`0h<~D0pvD z!H^6+LsHX`%abIo!MAMzR00YSV0Iw#emY_GT>k*LTaxBvXnn zZ5_#wg-KSvM#dnw9^n4~e!Ppo+LO>zsibASMd6M+qulR*^5><)vq;G!z$@iurRkzv z_);C2IHMwEiG-g^8!18;(@H@s#=8y$lV`U?be&5>%4f%m=vqbm7@kal0PIV<6IM@P zeXF-_mCu2*u>hA&)T7fFk6f}!`;Tk&Eh_dsy0D%b&CAQ(scQ?VO2OS^nM96Bq5k*_ zzQh7ZvQK`i+0~xwdhj5XA=IPp>(nhD8%)Z|IP&9R;}x9Bv9itx+_4s-Oq9G4M*EOC zJajEJ8+e)wIo>>YWAoV}Wh6bgENQ98BAeh22puWuo)y($%bblr&c~D~W2nvmARfwN zrvzVOYo-{YbTdPxV#pL2#!Q{BY#D zgEmKoSmSjJf~CETzBPcWCPIr9>&7)#aG31`tcSdTCO{vr|_hN&o9c#cbkc?y5=$&#ZQB59vs_;ke%xIjj=P&m zbeeTn5h>jn9P_SrytJ%P9)JVSVVa)9Tv?IU~T-@#Zf2qHzM%%nIr~C{<;uA-M1mdAA?pbU$ynl z9*v{pwnFLo85lw2E>P}}#~SUorUgkmh$<*{_UZ_+GN6&42O>PjAN`J^JXK#!&AUpskEZF^$m<4d>Lhj87^{>cngy2Ew?AX?*BWG6UPDSSXPrcD ze>CHDhT!c+?Z?MoMJBT}n`eF3=@JOju(LhX1KE}--xea<$%-Z{e`NFGM_lTW1{HY+(G}up-Hla2nysa4X6iNU)4e{y&)Wd=Y z&u)ff_)ANfk(XK1U5gVLSk;T0UJshJUbE^y;BVKf(gntvb}u5 zu>$y_D*6+Zu4ifK^qBba9JyFgoE2DwwGw}0$Gvw0t|QIXqEh;ftB&~ITbZ#$3AL1| zur{p$$0KpR-CfmK=EJSm3;3yEb4V)pg|sY49BY#2jbkSvKun>i{a=yh0vc*h#WHZ< zZX0YHBZlgyiF_8?whC&vnNZ2C$h%T#8}O!#7LqY24Bk|RCKSMwzfb6YO7M`w#`AI$ zCO5>HGc^1SK0y28c)2n-vV`LI51{P50;Hsr1NBsBov; zgXsx~$0!RbNwwK_@;xj@(R>j?!5r$DI(CKpMBka=hl>whg-{(oCRoId)EEKHy7mIV zBbqhA1(~5_;g>nMLl#J#mQ|ib7r2URzd-%|cpWiEEm3m>b=R`1>SeK3bRAG(>8*_< zc~av~AqtS+)HkJzCn{*Kpza&Ex(ByM(@F5oS;L93aiftCODKwG#m34(y+AV}vMj)@ zhG2k$Ob*O7gq4}<=>9^5Hvn^G=GZn23ZKJD@U*ZQ2712 z6O*I}r}E~FGBC0oQ!WF-t+MV1;5G609XRHAY7E~DOPS%!rTYAM9mG((NFZ(O3dgwK z*2mtgr*%+aTY6lRA{d=u$Qch5)-hzBFD%UwVYOIUrxa*+rLosx@lMQI?JvV==x^kz z<`#FG!4JmYrbiq(Waa6v58<<0J~7%o4}7}w!*{Qm=)^Fi&5tTh-%*Oep`ATXur>K_ zT*(=#ua5RQ80{7;u;OLPvSDPlz|MgAWKbZji#7iM$D8WRz8)y4K9#7sf*9k-k`{fg z2L!1g5P6||5)ZlQ*=P`M4^VUe zoGYEAixt7-AAIVxD$~0TZEervLBrI|s>fNu4#LmH)#jHOTglZuF4(djZmyB5)$T`P zJ8(sH#(tD_1!%((`Z+ zWdrRi!M=E=&<1(WDPBRG!D?d-*r zaj~}&52vZHn*&?h8O(}2sXam`-E7y|$L1oej+$|!!5A61S@`O$l*U;yBUEBsDlLX( z-iPps3JntHq^i}cN!eiL*Y_K3yTM+YK@#hA=#xN!=6K#S9$XSSZEj3&*r@}MYq+w1 zwRP(Wu{~_2SJm zku-S&BVj^?QdT~b-iPI{oBslA6|WHvx_=R6CzyxIl4MBB!ch5) zES5f>gI&9W@zaXy<> zk0{~Kl`qrEQb`dHq=H3|0N~eS_UT_*$$NP8=K7gpk&4LD0!RYD1QWp`xaNrlz0YdC z71OhFCYwskFiuh|q)(^}2JlYegqphcBe_1+(#A)IHGE8!$F$8-0eL|dEY%Qr-S!9k z`qIMUF!e5990-q}btaZgQB>CiG0G*$%2}bDBtz&UWt43;+nN0W#Ze@i9lE!t>Ug>E zDapvh#c?EQBvatb0tP#6oPHRq7tcG5U399r8jMmqA~KbVz*XJmSs%UV??>pwHOxgmRXq!Q!-l1#o~5?Bm3-BBih?cdw4Cx$12SuzeubLEoJxlvn6-zS4$4mos;HiTEveB;IXcfJG$bnH`8=%^zbP%eEtJ*H`56r;bjZ*pg^j5JuskpJZ;E z*boWWQ*PiHKm-shHFWcZt!o$(w3=?Wn}*XAC8Kvz)D3Pwp>F(gd-dL4ub-VXhchx6 zotdR(Y2^UDf>;7bzt|7AK_5*$regWyGJQwo5aJmU7$s*~PLbnCF&kBnMban4jIb}O z%CfQ*8;Iq%2Cl>lH(fbFiQ*xPnUJ`i9nrEdq;Vwrba^GAWKwsH#0CVe;Y5W1f)692 zQEHli5TrSXF(Q=;tGvEZ0>u-4sssaHAKu0u7Q5n%mzI3M+FWF!NidQ|m4~G5MYu`M4p3%#-TCCIaRA(iM)VkUJsZSdT?VTp8g6-)BT~{0Mw4cFf+EqXvY1)S zPV$YzYcdM;3TA^^O-Z1eI(*EjRhJm#Gq;ed6BH$jeqTx`s`U!y?&;z{xG}6EStTkq zd6E$tvXxadvUeCFz;sb$~m*H&Ooi9(+V_9dxj~^aLl|_K^i}l%e35i|?ra%6Q99@9rfo_C zh=w?wOjz-9-fEC`idq{&Qjkd_o`~b)MEIFGFd}EOUA&A>c9vbXmKd6`Fsk6%)4tRKvl|UE*A%u?69W;*n5wE3R5sem=6xwE;EKWYYWHCtdZ6G2+Ai4zZ-oS<`v;e#6XRsM*wG ztw*|{lK>%@-@`3BY1b=N$;i!>+sp|hQLJo##L+79P4F830N1A#(IJZ-Xjj$cW0j30 z9*Eo*o?4Us)g&U|6I2U)%T-sGDy5Ry`Z7HiKGYd|ZQ0l4>4 zYjaimS8s#UcA2EXq(}8KlPk`Y?-4t)5Zi!krZT+R1nI*f~KSG zLW3XEtSdA5jQH8XU4~|6MkeUP29F;O8N`kmuW2P>Rj+d|9{0avOd!rkp&oIY&6$K~ zLMm4AxY(woARm8j-FPpo(~9EJZohtO*8Mf}NXfcP%9|=^eC!;Fex}cs#49v}dnyv5 z?v~kr9r^9h>^(u}gC1lF=a~ zYTh%%#qmylf#Q4w#qutQ`BoTN+FaQ1OkW`)hA4@4 z^)n*(jmKa<8{C@U^uzo~@X+xuhn^^6`jk|bY*{6gv$F0UwFztn;X#1AUiH!r4~w$2 z96Wqq8Z4O_X$$0Ptr_#+TC?XU8)uAIxe}Rd7Eo`mb@XS^r$}B2+sbxwzb$Me`K)su z=a>k_Y^uc0j-Zt>$i;Zr!M7x-e5v`qD%A7=Gj&f6Y8g4$c&)DK36J=i21MZ)PyjS? zRkDgCP}~oC>{~T0C6y9C+i!vm1-uwWKZqsqUxwBhwM5648(Gpd0t|Wh@O$T!TvSu3l8HK8dK|vgzANAy!#zY>~(;7#*V4`;avKOUF7kMtV!) zPYY&vV@tG#4R23U&xleb^C8NKeN3^)NDMb^6h{Y~Mg~)+3yq13>It2`8Xpq043`|D z{{3$Vw}y4BPZ2>rXNPiTEvANwSIdOF`25J;MtTeL6;yz;A>7niNgR9E8 zb#xRYjM5%E5kY|!)x2L4Y5I?dA3|*oEepkMB8Af8%T&PB0gx=R;L861?&JzwzAFG9 ziX`*W@1j^nO-7x1dQHl^UK|P?ulQ?H(efeH`~!&|v4@u1wJil?Sp3Nd=6C_&Cca2t zOV=QtxzgVkS;zX_8!%+VJrW=Ha=_$rlE&Voa7zkdMvYiKJq!%JKU;%O&X`A=rA{$& ze4r4yF0U5kJ(Z(kMO|(MPj0De9tnfQS&?g+Zd2(#CxRzM$z)lQSlrl#b)YAJ8rn@V z-*87xVR4NP$`6N*&v@v9tsLX?*ScNs+DGB(qn{Eg(sE{1mji&X%I;F5ulH}p@fq}< z=)m#Q-l>C$sbidsr~1T+nnlQsLplaD)@#-IM()gLU62n*c-eW8Ya;_w)7wYa!P>ax zyx21!2HCNsuf-kDmPYm6&DP+@qGUvwzfq$McwR`@&y5YnvL7^iSwcdQ>Z|_%ij4*; zhShL$2abep>%k3$%>}Ri(#gq#4qR9~`0|{j(nll|@%d}{oYgXdYR1z>JlK$uvN(O3Wb?aA3^gt2I%rTa<|lao*cLtG6-57dX#6dUmMEjV3s=O&_U> z?&PAN+hp14!1);)Ulv6u;4_pIJ%O?8cs47j;=_#@Cqz`q03GV=j1RY|NdEr-^1g&} zymy2vG?o|&jQT_xuAziA96Zkt$(s~X$B%&1ODrW&Er(szwEk_>8H;hv2P{b@$J19E z#53V)az?CPSW%<%IpgqTPzD& z+egx6jL5I@WEy@CBXHoK)C19}usUO|XobXTq)co{f7*0R`Egju<}A2VkIhtV8rPA* zzT@xL$1^`p!%SJ0472#H9!BD&nb>!X@HpVpS9$}tRB|JQ1g}0Tc&2#a+R)F;*#hSOr(H26UZa( zefqrRawZv5#vX4i*UnWjvA!sg-|SCGoEbOc0e19pA zoVLus+1^3iI9gJ8tG)+cV1Ez1Er}~bH-&WBeE$F}$Q4!Jg#go4`(0l>&rIy3VLWFf zPVO05CL}0Qr?>cs?a1tU6E2qwp1g=*Sk0?8m%RiAFI)@8Jit(bvj?w8?> z3m!C%O#=rQ#!4!#l@bvXDAVmlO7b3FeIm(@s}14xgdN|_u~6? zFKN)+9qXFlZZ%Y5!^y&$OvztSPat`!GIE%CYr^twkJ`ocdP(ymK`iMbL}C)NZSyHB z`kWfRcp~`t>dab(W)An$a53U82K|#p+y&zJ1pIxvtlF+?;!6T)a6nk92ZjiplI#|t zV~*EH=cpN&-s4~nhhGW~S03?_qK96`mOvxap;cB0&Z@#R1ov{vD~kC)9R=~Ph_i4s ze7Ur}V;XtBiR1zkU;-QwxPYMd7tc4xxjhb?pHwv*M22Z6ofpi>Vkv@c3d8~0fZPXi z3F&jksV;AX^%(Uy<9Ou7n7mOCX~=3L-?ba-I}u*KLP3k{kAAtPY15_-opN88;eio!i53e-Hf;0qRV7T8KtZu)>{$5}FW7Xs zji@#gEO1LIrEs2cs^fw7@7v_{WcY(6B4lWflOO?#&9&d;16}^(k=LbV2LYRE!!=tl zt>o#M*v}Z#XH7sBHx^CC`+49wW?LV6_v-!`)UaX3d9>)pKdeY`^43Xlz(0oXzz<*> zD|N?0<<{^gLFd99iw3C>Kda{Z-{0@onVR%aK|V*6u}q|G^5X^A4s4IPsN^ zon^t`iv^m074!$g*ENk#5kqL%Ss2TOCea_%$VcLBKuMuwl4|T9dI*@S6j^xa^G7J3 zJ}{y-C6m@UZ;J$v-|y3R@k3F`%GM`?DpoMXl8|G@_i>_ayJ{Y$EJ^QG$8b7ONtES8 zmK2=0m9Bv()CeD`7ggMK1297u0o6B{(VxWrA{8~UCP2&#@wT7<9=1-dZm%a{{VzP zw^g!P*D2u@E1494YL7qr_wCe~S#kN8+%hBL#@zBx4cpqypWJmfk|oBQCK?jE`A2n~ zv60ORBJYd+x;syF1dUOap>feyjZD}%8;o0uNP;&T*~o zq~Umf#+vSxrFp+gi6TWAmQv16(8ts}jm$tk-~;c}+c5F`D$jKIB^;^acXJVKrNIE6 zSA+imPx9-%C`io~#16tiwL|)g0xN;d*cICNqttmQu{@4|2_q?6djtA)#u6W>5XM6Z z5N)n2jz4}nil1s?j7q&f)#d83jA>-a)SES(qmY1n!t6^gs<}2=`5o?$TL=FDOT;ne zXKhtLk!cccE9wP?K&Aq?Ja+v^@76gyF=a@SVNVnUiZ=7hJf3>F6j3d)9^hJ@FZ?|Q)LTARmR~x35il|lntaR<*zzMO1Su?_5PR}_fk&mR z{eMdiqfP#8uH`!$lOky%$B%dPq${*PZZD7g-1WIkz5f7XWcAj?j_j@bj3;?y+*Dym zl1QSYq8*y9?yr%_?S1+JlZ?GqI5ixpcJ5OqJQ0kCF*8x3Jt#KYbIH1{;r0ON>~Rg-+BT@i9EJ8swh4{MA8e zC&T9Zf3?!UWDh=q373tV;%t@5MuSe%+Ez%TfqfAMYE`uWGf=(NLz?5Bh+$!A`dLNN z*yd%2^~&RZ{`_-fkG~zh{S{pbX_IbNSCtwdNaBvRfnMMH-|yFmFg!7g(#h#s-@K$Me@UMuO)Pw4zwJle_u(4pKwkYg^adyD0k)p8ZCANr8nC zgA!=+N|Gzg8zZj%uEvKZzIqvptYm9)vYd8ERwiYO$@2lC0XqlhHDoROe4Yhry0kiK zY93L1e2jdE6*4A>3HB%_X`*b%^@eX#k zE>t)%ljg|JBob0xrkKL8MdhU$J3a{Z;hVp)=oV*)v+#bV4K$ow%o!bgxnle= z7nkal-iSgPf{uATsB~vHS;oc6#Z2X%27#tsL8XntLm7;1lZF6|&l-{muTkU6x!KVLgytC9kDTHtLsOYy--vX;(;~cOPo^81`h^uZcAr zeD4xXE~P3kkihI{(Xs;35~#~Ek2pVYxX-~<%Fa4gpq)h#Y>6zFkbX{#=&^q84znGT%N$>jOU z-1=33C8~`cLB8}wENo#uRQdX|8BZH`N{SM?NmuLX3( zr5EdNXb|yEg&wJygR1LTsh5Q##g;^jOb_W=VzxoD7L=b?aDA@-0OG6$)jozfZ!#_P zlQqV)n~B`OP_KWGe?waf_;29sjY+i)E-hP6ah%ywMGm0<08aA}$=Ytanks)o?a?hm z!X6mY;Ffm7%0;K$BW5{O424RQ{s5%$*j4xGO4!;=FhTJVe>BS|PK8N@tP>kSr0LVd z$JFl}&9+9|9OzNc_A!J6BgZYcE`>{i^@<#;p(I&TnivnX|a{&Cw1O-7SzR_O&@44u& ztOLoz)6Vbv5M#n_dcMRRNBLhIC1YBylKJ^E_;(*qlQ&dw?Tr*z%_B%xgpqgz1}A7H zy&;A4Hx4*FJduf9#Vj)8NvNcb8L}lwLitg#pvfAwg`;(JDD|-FK0D6Rp~h_*b-@de z(a40TkPppb)u<25Yk(K5n@r5d&&WT_Ba%QdvRW9zZ(3$TBxf{0aJT;e4FlNqyMU*N z#4>97dh|J)IPZNK!p2;wp&1Aim=Z}BWqDx=q9MN26dL_Ky5qvw z=SR}@4ap8mYKWe6M{=}LifGV%_W}tc=DS};FiPXgvQ{rNjk-s%Y(o1Fum_J}eNmR5 zMb#WW(7M*8ltGk`0?hs{sA+=Uf1dGXv1cFvZVPBtfH)}kvwe)r!LIuWLbur^X97q&O z-;~pz*MO(D$v>!C1xazyUJWsnYuDup@g8~8C#6*MBuc@5!5ev`01b*e7vt7HalR&v zv2r4f)?BG^@gQ)jZKaY!zmxY35U*g>U^y` z`JTObO+0WAo@2nCw^&hCk~TbUEXV;pi0Qx^MTPF-Pvg;WmqSMcbHOl8r+9l)m&BPe z!=}YN%Q;C?XpEw=sM741$y^E@W+r@W{NX0%NM&VWW@{l>sj$e zql@9+2J86RTu&T&BEry(o5_8}l(i3(EJ^)&J!6>oYkpUQHyAQMW* zdbx|MNtV;3QLD#3V-nkl+6u^feEL*Z-=Lm1TE)O@ZONA&IEh8@#hxy1QF?0{i{P0CCCY`WfPR;>^d#McT$aiz1slM$)L?2FPwcco_uKAV+N;c0H{AIIIF(8)MSfR@o$B&V94{B>$vG9H>F#aq7QFP zAGP#*8y-C`7A#d|7;bcK6v9e-} z&g6ejr*7)_ZhFJPi@Dqp>TC&rLjyNm@h-G+)WtSq#2wVJ7Qwfg{MJ}8_aN6-e0h*Y zXwo#Du;gnhq2rD;r;Iz@?FPlFledFF9%{VNnKbYAIMPRPDVfSQG65FmBoWBFR3?`V`qR|FB04E@AASwG3 z#ruQs1X$Qv=@wSk3e4MgfQ(9SDnVM@NM1dzi0Hx9-PiA6d*Ai1k9tmXLP&Rq(OeeMeE4#*xX2 z=vF1IfJkB-jt=8gE7^}mbXb!kClw@MHZr8cVLKEs+($DX0DK|&BtL{~*@&psC-`Cpc ztN@7|6w`T==jAk+q_jxDGO2RKDV6(QAwm0t){PUh0V9I0=zRop&viHY*I6c;FqkRI zk#n7LJiL~e7uX0xW8`van`YpB>Gr9#pXzn)~dfKs;^=>{r=r%{XiOd0o;Eb zLM;pCBWLYn8e2`^PaA4DGD{+1EFi*1sM4i1T{-}&!Bc*`{{U!iaS{S{)RsJ)c?K+wBF~Pa zX!&H7Y>s_{073bo(uSo7(|jf)k_A~boRnEsP3`K9)JP~<3$?cc&!mrzifMAT;}@nO zAPU~&^MA{t^39E%8qJpuOam?6445Qcp@WjPepn6za41!F=?c$%976~Cy52hv;U11! zv|YSk!)n7dh@-{SV%WZLjp_CgPwF;D$Rn*g!!wTsVr)+NRPXDB(VqY@$qM^ zY+WwefOP1Tq)QNA<6}#cn3#))ID8y*$d+xEyX5lWX1~@I1-!Rdkcz?vWE*2$$LncegN`?$o z3Lrg*b_etwXgYRw4i2lHu{uYEEJ$NtERz;Nqq2uQ1-?6}KL@1^Z%7%~5vD|FQz3@Q zWI*drNJ;%2N#o-BUeoodmoTPOhFN1~MspqhOB;&vBw1 z?ClbtH5{#HNSl66Oc|>@l#+!kc9ix@0fP>EQ8#_MTg@gc3DMR}C>CXsIO37Pb{~|Q z_qIRed-e7{Z`6leM8nBSqC?p>KQH;4u9TO>Sbk$BjA7Iy#sOsd1Lg!4Kn*hxsn5x? z?bGyVwu@oWJd)+ks7xYS?ydB0VMs@tRU9M{v^OEx56!!26?b6YK(&2Dqsm>rsz+e! zBvBQ42GPZKp;zrgtFmeOtrgZ1I5T{~wiae75*peGp}d=R^opZa$B=hH(^CmpxpU`` zCYDzloku%paEdIQqxG}Xjd%@~-B!a@SNL<`*U!|X%*<4Yqjy*%vRKHAyT3k_2JhXE z{5@>xjFU>Z@E2%}0^oK*d%oTH&?d6xtgJ(_msNR?J%VD9&kYtSTUiEis^?`f$ESZOQhq^I zC<_YU5I*LK>oxGE9B}J81`aXUiMVF(r7hwU5B<-p5E`ob!gMRQ~|C z^gYp^0-$KvwHRX83t>JZzY&A%ZkG`0;?uO8}eX zvIrp1`R-2Z&h?h(RfT2A!r)j>#-F11RjNqs@FgNpdH`k1Zvbvtm(ei!|Mf|hm zX^}%Es>B{vYeEzJO=q9qkB@$qadh}GzOO22=bf~@HVr7f04J5FS7${hh1&@hd8_uW zjxM1#P6(Oe7^-DRA&pd!2JlG$0!;t`tLFYXNK zCo2|40^lflNRP~&&nAt4HYxkv4x4;msxO6nHHqX$<~Apl0u7^Mu#UFvC!N7tgWB(^ zSXvA#sX;8oUk(|UB)h1NNbyuWibx07>$_vzDE$H-jPkW#6l#83E<%UNSW^^&Jg+qE z9{WQo_doF;i|a=PNLPDgjIFu$6UNv4rQYnI&Zn>G9q~>!qnWPg*|`{y$&n@&DOYby zZzXPITCzE70Q(M}aJ3AHv-J%>Ii>ntG6k8F8-|c<+}@+laaG0po{dEeaw~?3Dm6q3 zM&JnG5&903^2F2Xf5aIfCKOC4apPuftGumM`vM60?_FkB#yQMmS|U2pF;0*KlB;HF z*)!mbr^CoOF^MI{SCx4HI-@xp7bT4-@86IQRy-kw+G1s9PaDqgqNk{C+|5ka?zYwO z-2C+hRu9vafXedAYG}tnRaC9*91nWFm~1315HLuVLCjLxPC&13P1#oyP0Co=XxECac&;qq?y z82)%>C-oc{{V-0xZWMq^&b$=k^J8eO`A6-A8zHw^s>f{f1Ue|;3+?2 z)lcD1g(ueX+h5Pa^E8|=#}YXR+dfr*yc5V?TIz|eoBsfbTCeiI3B#abmB`fmK+!Dj z9IN?i;97;COEGG{NLAe2Rkcz32F1-6g`M~p0v{0SxrS^Brh-XSOwc-{SlE%UlPX_P zsvD7Oy;XD8>*L>`()=r~%p}aw@u$EL$0h_4pDLq1SoDp^l!zGmX?u`QS)cH?!qFx! zY%pg_2h>XxhDDYlQy$r)8wj!yD-o`hoP=PNG?GC+qiUm_RV`ye94K_s7TNtz_A%d%UjQ(V|Uwx`MG%KD5QP}?gk)Yr7S3ao7Kvo+W zG8Y4OG*4GNrb&rnT(Aa#0Z0Ua@Nd6FSkInYy@6hZFWz*u! ziZqH)kz>HJY}{lago z?i*I?ov7PI_vf%30P`O^A^f~{!-=joHGYwO>AB#VHA8W}@?g%?HVh|{7>w;Y zTvt02Rl#klIK9pD!1w4?8coMtaYSqlO0f*d1!f$G;WqT)RU_wu0dLF?*mTE@tiu#$ z23JZXvUx{nJ^uh}KfgkBZwEd+=O;YxnODYiA~IKECaCUs(r zM(O~m1P~~W{cv=AbdglgBW?baQu~Mb0sfsznp9D!505TJ!NHiUd=5tnEBv_Wj{AfV z5JUrFh0I&aSm7{7Ba^qxVV&}syosaz0;Z}8zA_&7=jmMV09Mn^Dg$))v z+Liz*TD!hSdIr8aqx_#$!GLAvVrqDpN;ft{_$H%K$t8&Y0EvDo`d!A%)uxO`nAw?V z>9VosS0tkDx@YV!zqR`l)L&g8+Y!?B1x$EONM}LrYQe35&>rQD9u0JQXBai8!^ji= z0Pi8Wv|<20W8pGnNtcD0^tyw~kCv=MB(YyANU#CqaCy4^{dAeKEM;Csa9OAn?7e}z z{{Y{h>#E_#$i@uB$8ge1B$62Rjl>j@<$LYVbfzt*rh+>x+A0{~!WP-fS%PKG(?U&Pi ztbdB$E(Va554jJof=J2DI?i9 zmIXc5c=s*y#fu)@09;KcBOo&-6p}{Nf_sFrl^mbbpKorhri@{1X2F{)8CUapZX{V~ z_d8qFU#CsBLIH$caSF3YV>_h${#7|VF*FU=Ba_EKvoQ3nYfaD7@;sbJ%7x%rBPKUX z+%JFu@6C>Dt|8In#>O5*$kE1l+Qn#seIR@BX8z}@&kVd4^%P)k?{L5K=oK0tVh3E& z7;@fGS@0&zk4$+oo)0bv(=G_xjGUrju|@pZ><`yCe4mrT}Y zlLID5@^P}Fz0Zy!Xyt3Y!H+H}Xo5$nf%c*BY1tBGeI&886YrKSlbI0Mx{O!{cjok( z{kn%Q8L)C67d{3uNUZTl!M2(lkVvpAxIB(N_IEO!eZ5ayRb;nfpEDLbETO0C5H>+n zUpPh!3lbF!m(O6PuKSDa(fvM5coHEDrWtm!xJ9Nwe=^lk7afLP;;*3XrzT8z(_-iE zLZR9;XAKzyouC^GE8H4C<=0bUO02IG#bt<`@9b-#usWMSedTk@ zUgH)Cx9X>d3Pn~q@G`Ip?|Ahp~rvi(L5M2^>V{aoZ;riyI%> z@cc+9j&4m1q%BuLMMuY(B0!S5sYjwYBo!e0ey6`ewEb^h(RBuoRLPSwNk(8YcKNLk zAbw>BaU2d-`(Mvm!)bBmB*RB#oD!)#CIh(oM>IHN!6&ijgV4QSz;dfRxK1T5>gu=I zzTL0BA^F6)@+zoTv zs@a-eKBT2$kO`H;M)8_u5<@IW06WTs0<4G-}d_+tw)a@SjIUG^%1J^Tgy!0~tY z!EBUXtJoD783rpq86I!>YXq9fP-Kn5!Z@*md*NdoZg9^@P zgz;yA);VW_7DWeii6{fV1%Nw$e!b1p<;Gas&uOG)Z!o$Q6b9mKF&@-E_@0VkV);Qn zq1h!Vuy*pw-B6=ef4^L6CPqvpiJ0Q$G~vxD3$hkvH&?@P-}mb_r7;E(fRL9l^BBmh zj;$<%)KWAr$TmfL_P_1X5VPV(0_8)M3~!J)E_{8M`;o==1E@5yhT$#jgA>b-!=&LBD-`?NYoCDsF>K&OA~EY z+*pcR6|f&sHSf=ABfnK)^0GvVtrjo)9NBUK0ui}R;R-X5Ks2>}qDdFt!0I(=6DPVa zJxU;8s0168S89*Su*kM7vT_ZMc{Tf2Tm>?X!bP3c==wni@4@??r-uM!ozJObSgi&0Eng!0nXLe9tc9m zw<(s^yIHfia1ER6I*7#O1)vWVaMlYFh93y$=`ZGIX}F{suc+LsW3}yLb$nRrY|RTk z93bW_C}Mjtm&zzu_9Pv&c_R7aj;!N&`&`D)#v>;yCOx$HnTt2#Zuc7*NuVrPubT&| zT9$4ubaF(fhc56#Qt{{pnK4;J%_m-z8E<$ zKhVzcNO%P^qb@k^zp1lkz4-Pvb&Vg);W};Etu$a5rgFOP7qgW9hQX^;1EE zD^z@_CYjHfW3g^d<8^fgE}xr;^f`FA=#oWITqZ_jV67VsyU8IyUQGq&hhx?3oES2s z%D~oIV2c2iIbj2*E+SHgXg9c!McY?5$lT0DXE!sgZXI-0$7IHl2nHrMn&~Ekp`-#t z-q||iiFo&A$B&Lduo#|-4KE`*B1yAz<&!3YR1l;p5S}PerRIU}#a#}k{%0ONNd_Cs zgwlCy3|R^F4z#sFjVKq*(5kXKbTKs;H5AH^BPn3TjzW@031jDhex;Fba5O#EhtF=b zDT-{fb@EFb$6Xg0P-y8Mp$cFfc0`#Vc-~(=5Ju zLd*VB;}+AhV~-H$PPte@D1)?!*zvQI%_w4hHg_7WzL0uP5nZ%I>+Fw7xy%K4Y4}=K z)2@u;!0&PaF<;>dvvM>0gPB z9GNYvH>Nblfn=RGxwboqSnTcm=B~IrSfh=s=4U*U=C+Zfh_8ZsBjFbsfMm=|sAyN9c4f@qE`j{W)}gB0_~ z%cbDMrpM)Z%-Mg5G>WXMNQgBr=K|fm#{;)kWx&$BA*3c&xPF=pk6L6%Su!(akyHg# zW4Vu@9kc-}WqtZqhsH8VgsPacjYY*nh?wdpQWz@vq}8=9=B=PvuE3MJqrchGcXih_ z0j0t~w(^{wJZ&e;4{3$D1Ntfgy?+Hw65)r*Q?VX#tOVzK!HfB$(2+ZcJF%h^q31P>K*6 zvOAIKBEMdhaSb!IMuzCdh{+^T%;G3rnPZsA>k0#HaH&Kwv_8~#b-3xo#fTFqER3E{ znH{KF7ZV;wsPNqJ`*n+WD;Z?TIv)6|D#Y0lKor~4|HMuDjoaAKVE)mFQm2uR;BFPq3 zl6#A{DmftTKS7lSCdrZ*IMt>+$hF*<{95X*W%Z z^SIoh)CC`gcDokl$7Ae!*^*_CNz*2YV@!6=)9{sJn9z!6jxb$z)vo2g)`+Qdo2ob#h&^;xL39Wv%RkWc?O(tc zIZ#WBk(Z(_WUMq+lWh3#vr^5CD|&b>%xprqqNP~1Hp>ncr;96EXKC|F5W7avf?p5Du}6S=b?I>5Q~o?tt|Qy$-@#{8!*-;( zrs!r4oWE6_rs`Pjkp^gJR#}Gf(ryGKx7?ep;;aC-KuEvPe^3_VqhXCa;Ns&!8pVqd zh(G|PR$3r@jn*sdFKu63ct;}-Skv-mkgi5CwaP@Ln-6h}l#mK)43-^0+wI34P|BZP z&~;63Rq-SXjp2_n9IPp{xIUxk)j$sNm8L~tHx^LqxrwR`L$8jZiFam14-U8g0BT!@ zsKJ;N$&aA6kBgp~9^5QUwT3a>N5` zw9qxcqvBl>RZN`U3TfDnsARz;*?E&NNZo_bh0}pFgaTB^M#0&r1tFm7lpU1anQ*|na1lp5a zSnN$XakKQSyw=KTo$|na?)K`+Rh8o>v9(sC+>dMPN&f&&6}#*=>NoYGRAO>j!D?E* zkB{OVFyZSM%d6>+vEwNFWkv)MBuun74`xEFKVEuKx%?{*V{2JiTF-@DT0iE{?l~BC zER49+Ztgjq0AXKh!E1)5Au zs9`7Su??_5M+A0}d-_;$_UQ*d6NNc(4Uw>puj2=rWu~1$EItb9)8N!o4^h+RN#n_c zFq#(*j=ZqjM220=YrR?I_UTi_o(R%BbELK}iZsQ_%!VbK4orC(Iio(1S|d6iwTX_D@o91zmT7RKW2EQX4_SzMvGPY3x41V_0mJT}sp;M$Y4G5dA(xCx zHaVA#%KrfGBW0k%$LC%R?O>;lnhzBlk;*dv0JByXs>R|QchmHL63-^1rFk)oeO)3D zXW-iK9I4wXS)$ZA?mjAE>w2DzsICu*O3#BNtrjk=5|oX?Kk zId3#s>i$4*;D7@oj>qp`*!%RUtawQdERcuBl04V)m6>-#F*iuccv4M{PbYxa$3|`; z^hR2jZtz}gYQgS0Sco4FX1)$c$w;Gzf12?bJb}BEW)y3R4PAlzbls-n;%Zp)v`W#mfQQ;B z9(#g6P7m00DwUen=4Hn5_ym7iE?|=fRZeIbO+zZOm2M^4JkHo?c7LK0CzkO@~(|$XiTVH3~gS z$diU6`dT-pBw4<#URUy+W0x3`+w4&>*lxgrJzuBAn4!m1%Y8dO8JR*2jK>y6 z4o=_^s2bwWxB2v|^-@(x%EWM0hZTKY{{VT8#z@0a+R?u%zyNH5O<8Y~rsY09pzXJ~GA7k=yn-)-#T!3s>zssl5@WQ5TrmaVHDbY9 zBwc%h-=)}cvhdnP#ndu!&_)8s7Dt;J080u}V!`Ku&2!ONb$q=>Z#N=564Euu@iBlm zVRknt>`igWJoGjipn+6Ojfa)u-Z3b}^o-;&&&Qg#4h}My@sV9SW0I_szbv){@ zEu@mHb}1Tb+5oNFxd+rM{JP;GwOfUAAl48t1D#zveKm)h{ z@PEHjKJ>#}WXO>qa!bY&(n#c8HU9vA->Td5)62YewQ~ZU1unt3M75-hgNBKND8WR zOb6v0_dfSs1Mx;Ge=TTM29=};uAAP9Z(Y>G)pSizKcVT8d1BLYBbQUbnK1nHd1Xnr z6=KdmDY69seeTa3be*i{L6fFU^$kF8HMHy(MU4|Ilc$Ie| z9jE7M1pE4Lu;?pFkvqmQ)a3cTXPCu|ir`VE2ADVIAd9=B>`CdUarHPpnT#VMBuSjg zy9_~y+@y9QfhNVjvKhq9fdfx+tR zdAUgveLAUX<8e^HeZ}+Fqrn$qY36gIlzwMkxMSiP%1?kLQGX0Z_ZXMU##T}#WV1)T ztzXX{Zn~Gl*pW!mMqqful79$=WZD!Br20)3J;?-$>SxW(81qddByk`GoBShjAFss^ zbJsY>J0f=ytVy`C6@9Ew1J2-hum${{!=_(JpnsC3fZqr$B%b3nDex0@ygP$Sz^nH)yD^TCb{i&N%=H-b^a%18GKf- zt~>~s61+x5a$0#JP1~G`0jRI1^8r`SNwb!lOwUL_c-gUk5r*azj76W={rd6l$=iRA z?b*?~^nLH+_qA5x)Fso})n)uGMWUR;knl8??xM2xwAGlHXt_PvE*pOn^?e^f!aRi{{XqFJxvG?A~3Pqh0u03eO7C*{{TzsJyF79 zVh_!D6QL%E=643aVmbN!I)ISgMUci=)rej_B)FsOO|SZOdPc~2miLoJl60e^!gX1( z(*-hMY?YQwf@FY5OUJrDN`ggtePFO4(LH>+K=)N6<@;g1WXOUSj0q%v589U`R%DTUCP_HY;rdeN*vXW*&C4n>LWFH0O!| zjtMX65hxt7C)kQ4kURG3;CIqy%}bd{Mq8o@2a(=~fAi|bA_(Hu-JT{$9a&gYIAHr# zk&iTPj}%2+P(5=zZ;_HBjBX{30@Y`ZKTfC9GGNEna?Gm=<4n0RFPf_ROQ)dm#|#jI z+Q&Uh?h$C4q8h$|1oKCj=L#GL$CqGSl0KqAA>0Lv4hz{@svL7;tylOf_1bgf;Y4G{ z%$c zF=uNNeLnvH3-OFOCo&)9u#c-~5*!%_g^9-u9Tb4U3FMRR{BhS(?-4z2N2z9*T242I zhF6mFWyzoDX)<$PK1`U}R&B${gxM8*le7zz7il^o<+$kt40k+>2Q^WcK`~hKz=#<*Imo4Vk*iYie^wx;spT>dxPALm9n*2P)Q3o_)&b04TmSu zYvwy8&m+zQF#AvNYo53B9ZE#Kb1PK4?@xq(1|w@d&EWd+T5AP;Zy@9)q&oVlfuORM?J z!;)@?7yYWeucw)W&w7O{YPjf#g_Jdi&#bNP7t z{o1@Eso?3FXoftu5$4RS#$aQaiB$v=MF40$cD4YK$5Qt-j{g7{&}#vpLRC%O5=VZy@cxI5kBO+{Y8mg5s6HlX(9C#yNVUSxtiM?Pp~GPvuY#90AvQ7lp>PGDnRxFknKi zCUko_+ee9a}>9fN=AJOrkd}I%rk$N5+OlN4-d#?FC z&lj;tZ+hx1$QvsmqD@a59vpTtWXO^k8K zCaq`IIYozEe5g#gnhqS9T9#fuCOkn^Qb2djyYp?Y%)pRH9@cLAEb9I|*7fv-bXCa0 zz{ZJjp_LbG^F?$h4m;W6$hzHKLy`1{T}?yA+PZ35xm8GEmYE=l0;(4aKmY)w;cC0z zQs?X0I{Z^%_+493G|M)rGI?PM<7`*LfG?3=)H<_(aLnT_*ahz%eq(LnOB&V~iQY|z zT?DD72a7fEu&`6lngn;r%8^jUl2PB^(pV8!>g4sI_+P?CO;HR*GSwNLMn!#$Zi0ix z-;zc954TI$9u39Q@S7-QW~A|^$Yg~8StUKpXhAX?{<2g7&mC#L5@s3(ED?E_zEBd) zJoEXoyq(A|v<9QVtL!`1QHK?Pc71)i{iwuM5!^=f{W}{;i7?@gGUzNs6!~z1NxC=g ze^b~{~9n5WHViaAH%qL0PMlDX&P z{{V>oP=CHZljCh^wF$HJFkpWyj7%6LC?dbe823DoNcW+3JtiLKI264qPI=6nw5a3O ze07_V<5&hn@i-W7m>(Z%k6N@U%BTv2C9JOC#EU!@Ts>1s)$$uF1!kIfoQX0EZd{qe zkcB0qv=v44L^iPJiXhkU?~k<~6y^CCIwDTk`7o@RQoAt$fQ&d#&A7O6!89B7>B?ao zZIP#CM%cL6Y{aV)u%!Zw6kgIf>?-W{zOySA5*fBMo*PHuIXOWtY;hWXmVK=Fv&8x) zO!?UURHr3&$1H5os%+$|ASGFb@K2pb zhXfD_EC{W<-1>$toUlGF3?^x$V(2IjEU~@-6?_la3+>d{`h0PS!}%>NR6MXYgrVPa za>V|%e%&|xOg&}?;wge}*O1}2fk6I4hjx;WNR_nsB%e>igH3FiS*QAFMms8l%Ao*y zOIsb@;B<5AaAtKGUsEHy`W2*ic5d9O4iC2{->OsYk+is4RYXijF*JdK7anAdw*LSz zyHI~EjykiSm4)FQ5BaZ&O0s4c{+1VKT&&pxtL%(b1se%xBZ}?;9cR~VCO8&|bB%!8 zcpZOe^r^nIf@BRzPFJW3ncO4&UA6Oi$& zUL(x%B9|*28g;oI2%12I3rN<@Zr~PTXb#qB9-kir9}6mMjkD#dGn`hCqhv6)^6kjA z^!5PQUT9ZHS~dgf>O8sMA54ZtP4K|m@`;dqb|h7|u_CIktDZNP4^`B(mJGPr&@75F z4o$}rNgC}}Do)|G$pn64X#3WySk|}(*#NXm1iz?wk1ts|tfEnojGk0%#YWov#rFFX zR5kcCC!v~0h9%T+bJq>! zMuQ$7DT8tK4$A7T2MobIOrF-D*G~BIW8f2siJJ4eyLt1=F*{w2ySXBRG35Qv9lE7z zfy7g0#b-D$KwR8mV}>&uM;HjM4${E6Ah$M68a$I!J^Cr&w2EI4}3ua zxIOz71w~!k9{su*spm(5gY{SpG6fWg_R+{JMN=L|<^sNZ`}J!VOUTl^8K~nnYh&eP zp;yR?kFA{=fvOzweZUud@}3~L&~RmotUOfV+B;BPp!_PjE&}3c8dA+B{YE@?`m!kg zBgGFS_a|a693FY-rX~XYTp78rq%?g-TlenLhr+@zrZTvTjE4 z@)Ph8*fSi(P|$QdY+YrOH6JQ+gvT64wg9RKZ<2Rd1By0#*F^EWKFzAfs?1SQVwHq& z#z@F#l|d}0juk~HHVyW!mb`i5Jl_xat3EwA!w|s5iK2O944@DS(vM(nzIu7lLcW`j z_-G{hm5xo)5_hmb)kIQ@B!8bI^q2 zvGI?JF-pc)Dt#p|UfkXV5hd6CMf)O5JfFfEX z#%wk60G8uPAoBq3R>yCWd9T~AJWr-Us4Aq20Lu#*DR&WfRm73Yu&n)bYUFu(yf zC$EnbdXhWwnOMvF1SPbx^^ z@CKm^NM)B7N?ev#b@LR7izz4c_xm3GV|ZAt9~Kky)+h$8}=V=xXg9P$OQpkG?@Yp z$S#1h-jo17z;zy&AoCJ`S|g(<1v^L)fV(}19^dQNIg&0uQvgJQMpTMThm+-&UpK}FP4rx2`7xPf`o|QFBM$`OJsA94y zbje_Ru*#cSh%39A=D}ow3oR zlgk1*RH-G86e$lq>)7;L8DBdCP}62{1hK`C<76!+)3bFguqp{RXg62{3*)F`ERrPX z5t1?v)7YMCj`i(h`}Dcv&k;+c>iS+zi#8XXE}mC63F4T@7$~Q0=D;Ba(yi@%k3__^ z-LwgVasL3wevt6TGdPcL?NG$aI5Eg-%En)W8$+W8;`{OkJ#HQxc{LvmN94?s$qceY zm0?1okf5=;AXj0{{kp&wNadbMV7HCYSwI|HfP0hAZnU4_Zm&1<2f)lw(BvQyl~ZWz zyK!pdk4PfF#Yewg^=f&kHm2`sSHjulyVu?^fiiWR=_irVR~r<8=O6b{ZjMF@KPe0o z+O2^;-Fe}SE^I9>Hj^Y}VM@0Qi0!?S+%Z*P2mvX@^K0LZuYVD=Su!zKTfs*YY5r_^ zD%^*Szds_l1cUk#d9IbbHR336FB>{p1S}P!Vheykt+jSk?`0#}$pewqX=Zj579Ai* zE~my2pWUcI+MjXTe1hKGIayB>NNOhj2{u1oi|O(%L-|vckY_LFLA7IeP_>orNm{YV z;8#MiCdMn1J~O1a%!o;63}9j{Rfl>hRC^xdtFcc!=XNrIsnm{=%;7{5kam#6^4fwp z>`zMKM{3NwZQyn5_N|9Kljo?>D0trsA2&{1h?Qb|)FiBDa_?0vt$yB}wm$y+^_Td3 z`52G~W{u*MQ~AXTa!OMl%gG#`Me)a5{;{Y)G)#?35Cm>nW0F{!(b<|Zt{72Z%58nc z*BxQe=}nKS$cu{8B+&q5QuPwhUp9xZ;2Yp^_UY^mb5fB8-#c|vRe_I<{d+A;!oDQ% z$j8fHJ0bC;#>ikU-Qy)c`*e%--S_J!!qa5XwPx3wAbFAGqel`p#f1qL95M9*8202a zA1AFR6DA2UV@(@5g5<-EGZvDJIS{fen?X@aL2J1G06vp-y&?@WCnpy-DY7Dx9xu-X)TvjOEWakXQVeo}qUBnv*wy~j^c52GLyi}h4-yfcS~lqN)c=^}4Q zn<%P=z7M5AKIC)#`j%`45dkX+CG{{!)CDd{B%1B=Nj6X4sWEb~^XErsC0SZg1c*Z) zCDf4CFZcWOLrjN5&dV5jhJ5%!VR+^8nird$pw(^KPvxV08y!8K4|-(?G?X!L@$q60 zE=$LZs=HzvN0vRoe${u|we2n)@Wlf!;k1OJAAd;v?s)bU_Z>SgguFke=i{%I z7HU4cwmBu5_~f6|)ehbMX=MKZ46!E2$jNNN%;RB`%^Uv!^I0U4L9WCK;B+qCk++{m z-CwgLp&AC2lb@^4CPs0ON&0yF$m5X=i;=W$QM7ja)@=I@P4xALrsKs7k?9E>IP<-< zjefR21K5#6{#D5F63v)J|L@dmCUsAl~K<>Nq)x15U;$j){adG5{W_B+uuEuFwuzNn$z~EH?1rD)II&{X=PFK_{zGDq4J|HO9%Rdni0&m=N&x%Fe%rq&KXJgn z+oc@`9Od|%Q_aXMb|RgD$yoPR#UtIRLHhzeP1f;Ny*?yL9fZNG*L;hM_Y*J#{Oq)a@JuKnVVn z&Q4VFf4MRRjR38vgOmG^f455>9@6H6QOD0|0y^l^Y4St3l~-)jChI?#m0IZbOT;w1 zUno9IZX<}qtf8bXz%d~EFLthdBy|hQn0U|iQmFFRbI5_C4Ae^yIVuLyKo`Xhv>F9U zpq&8d_(!iP7uwrug7}YE$Hjm&xd$FBSk6nz2;E*mMn)eSBT_|qn7A%aZo zn4;M!eq?4B6h!w5fC5Ki#Ghf%twULzwKyfmmVAkF*hBPyMO#W#Ub>9luaIUZcdEi;v(OF3cqtlK=&0%XM0mPeyBu>9=Sw(* zIgSYc0x$rgPpG)sE4`E7t2(|$QfnGsE}f3XJaEB_oweMx(Yrp?{l)ZN2!4|pAy`#n zg;UO$f;{&Cb|>J0%~jXOKHx%<<@vcnK)|~ql%U74J+I!qg#*%rmbRs0Eui8w9(+07 z5x_akVDamMQ1L?HX}BLw>m2!-qlQ=CVIYp1a~=&6C;|ZQe)m6xVh@bD4H;;fc;$*F z@4Zxw-K_8|+2n!HeQJ3;LE^nZ@XE3n6CEaK*fOeEdfme=;7x!x8ytbt&XtP}1~h8t z$%7jnNsWrzwI~98ha~g!_Ul%YO$;bx+}!o#63;p6n9*I-H4}pq#|c?7Ns+>@E5IZc zKEToc04|m0*&54{sl>D8$nj)6fp)4ey@1i8+f)(WtxtY>lM6UzPQqfJQJWz%s`uD^ zPD$g^LZ06sS64FfAjgpAXFkaBN1wOL-)w#Mf$Be$1?2Jo9by)SKPeaL$)HPwf|pY; zZAFbGI*xm!Sm7L~0*g5$p1=}$ugVSc)`OtK6d2h!c=865A7pJO=3%*Q8M_1NH^;RL z9b;N|i?DSqUs1@_Vv8F$9VCVfdEH=*BRhkJdj*`Yr0^{IZ=RieW8!>0FGozd=Z#u7 zm2n>(gx-9|6U zov{^2%CoQp5K6k3>@~3L0X<{hR-xj}dm9f;fKQv5FoPNp<&{Y%-{D1)egW&;?B&Yz z;zqbQ%EUy73-Ny~%OAh(*0KB*&<;MK{QDvjvF$La-W{Tek+(>F)Ug3U{cC`1%%&SI zMx3E&b0#-~yf3EdT5z8#EI8wV0>pgT%UO~@tH?VA7OWh`y2yO(P=eXfOc#VR?S9Z%^5Is~m(N!Fmz;FdqH zXih)lO8D%OsC!i=%~Xhhq-WT*)q}JgxbpbVT#`wPj9A*0JocC%B>F=!B=JMJ>`COB zTfl*`=UhBNw;T&JJBp#lZhn3F_8n_FKZed$B)U{hCM-yc^>e7Lpq^s8;fN;t&_5@u z)^$81ONm35Jmm;tL4^UADrJQ*;R+&c)KmgOsu9lSG&uhNk?Pbc7t5Mt*vD$SC>JFG zO27O34}0mKSkYe;4^krD}#HT zY=u=&2_&8Xv)o+_-wQObO%x8;O_0Q-vq^ixo8K!C8JMpFuouFCeP-h^l(6Nko11Uv zKfCS)F+&Sdw3D;0yP^pU;P!xT;e3QpF-=Y|P67cqy4&1FpJgDUb#Bu~#IOHBXeg6Q@tCD1R zJ4A>~UlD1AIJd35`%ts~eFOghAwq|J!Or6lJTy%=2ImM6Jb$z^7haPns^j3cWUizu z40#>scPdFex|(fwJ_4p32g0@VsDR%c+tp|F>g3)s(v}Fav2h+eWOfUZ_)ZZSxFJ9Q zS*q_{4sR6Z)Tq0ROic^28*evN-oAQheO2-yjX(ZfN2(w3S;xr_ z$;8E+Pc~Mb`7ID8P0%Y9J?!7l&s`>&ixS3=={`}Mgp9<1G>pVh8%>-406vN1_}56t z3}0A>70kB`Lk-+)JOv4DDtENMPERx z^=hqdXHf^&<8M~E8HHgm9#AYiOg051pXp^+DzV6RHsAOA~a1J{ovrye1W(xx|} zQeD}C1^)nu-yXuqf78-tL15c3Uiuvl>#~z)-maU_>=ija|Qav>NG?;kP z41@{^kRgrt0%&&Unl>yqJ%>tH`m+m34TIM~5tuVKG8fu*wUsCPE|nfLzanT%trM0Z zsDRcFC)l6gq8NJ8NU_b0A|(Yc4C%%0+UP;8jHEXoJ^HVipyS9NJ@o;IWR;Pz{E_H8 zmmZ_iY{d?=?U zuO5PE#|)CLM4EOkUP`j4oeHCx0*K~-@978Usj_l*Z+FF-1t}tuxgVT<$CJk&9Q3*8 zNrrA*Z&54wk*@moQnq*jPxl>qnKDSM23$-ShCX3CiQ89S=6$=Kw(|_K(IIDKgAPJ* zaU;i`bLU5oB$5?p2oUhpL2fAV{l`B&M%oT$GYRk|mkT3#CRmQeU@Q+$#lGvsUGd(9^gL-30M={{V;1c(4Vg6D7v# zjIXO>6OoY=IVGaHF?lWd`;dft@JJQVd0H%)YFK`qtPt_aAJ@f;AFpcTo=;4_QEihZ{{T-+I?>boQJ0mTF(8Gqrgy}6@stOI1yFadHMn0ry;N@c zIK)&A4RDcr`EWktMFIemWQf|HrKZLR$&)HHiBS-_*q~Sfha-Y}bY>soH2!%_MtL$v zseG)67a>m!6cW_Oma%*S0i#_(c0IvY0QcviSvpBE zsn5k_jqbPwWUhE|YR8fH=&!@k#EEDV3eBimo5sJTw30!qJ|vlNI!1*z3M3P_5kZA* z9sRxR^g3qJH3%eKKUBlb%SjcWd1C@ab@*t?p69vew|;t?0t{S;;e!fncryH@jq!5I zymGD5vN`1s*wOz0UaRHklZgZqMU#OzZ_AJdOm1)dE$ajRBxWCOk$w`On0Hp+$y8MX zVmLDO9C)H#X~04eay*q16m8ssKy`(n)*R}RM zUqkXTeur$0Vm~v3+so(P`2PS;x#}tPJzrD@10iFITv&|xK3>SkKq!sU9fX<#Y2?ut z&GjJ3T>UuYW=6&7XBaN^01_~BF|4ykAOdlv^l zicJOo0Gq=GaDeBmkLD)Q;gQkXxov@X^#%UzQpOTPUfZ3aRMTsLAgQqR1fLpzt%>rL zpqFHV(%tiuMehA4zE?!NHYeJ3(fX%pR6B>A?1&RfT+XM`U@n{{T@lJ=W&r5y0g0 z@H=++>1G^En4Oj>NN{PQl|W@SeZT4L(R^VnP36ij&5X#46I~MZL;HK(*Hv^x>bM1G zNz_w9@m>s>Ht^&j#&!|yD2xC_Ab0iGJkUM99res3ELkx#E0X?VD?e(#aoBu*zWry- zw=-<;tdcY+tbu<$_u%$k$DY?;Jv(4)NvUWtWyv6%t8G~#jfKa}mtI1UJKq5I;<{3y z%I3H(`{OB{0)^MepLP(_aQ!Q^r; z+#Z{Ctv?z@Y?g{SNOTi35(q%Vn*+J^1_SjT{VC%FCGjVc8D)`K;*vRr-zumBe*XYt zM~<6rB#>JDp1K~qcokN#9Xji+s{Asf`%Db1%Jk}3SR-lY{=aX(T!a95kWotPK=hKm zkH`9TP9>5bDX)QWBT;c@svB0 zi4dLvs{3>Php$#c<}`UIVQ`~qb3l?u2KyU5kA8^97F;PClHQf#Jwr!mpB{6O1Yv-N zQEF7G(5~W-!Q-Bu^sgLXYLWQm%p(Tdb_AmtR=dxk~LcfpfTfyKdx5t-L|U_S7j~v zyHzds9SF+s%n?ZE4dV*qca`M>SKO8O{@)_{NYgduizmp7D94K|W;Vpjq==!gSJEq+ zJ@_EEHwv_l>J~`O z)CNZcfyGtr?tgkWSJ1p^^qpNYqSBrboYATnT2lmy*I+O-2w+cc56@F;nl3YH5@%#$ z(#X zf1=dRNDKjRv9|;;HMm~{SI1Mfi>cs5VO&+%=#Z@NuH_Msf8HQARD*lP(DpagY^^G2 z=X06i(VEIun+im6RY90WRmUFn)AXt}pw0T@@}@yo*Ty=El=_@ZOssVxHZH7;tSg%Z zhp2Y0$F8ybZ-)rSU0Y4bgt0!nRT3;j9y@c`pKfUJ(w0-=;mXj;*_bShqsYizrAu;u zH$0Brb*5*Lo~x&4GUTMlkh%m%4Q8yD0Z;w$(?HQ8bW#Teq(S06J6GR}i!qs_kIa)F zA{U6B{Dp8gam9=3IW-uZWXYE-ag1C^V#UTR1DPa@hIt7hfK}M20W4UzU{6`rtF3=O zXy@?`W>#~=j}d7k4hN{6z32ja*F1I9S@^NGJb~oIFv4Mkzz8I<d-z<4F2Vv6g z!*jP6sc`H;nJd^tlrqgjUbonDQYPyT!n4ZLM z8nHgDw9J>qT~|H0;Pfs}7h;uV$bC*p0c4OdqQ`e)#PM8;uB$hS;K&XUCxJ-XNd?@3 zNg%N|b@4-`n})6|WCT2>EE9aP~lT?L#X15D>O5gM;2_U2b=vrP&$hvR>goUc{t6r$xV@~w(X>IK~LI=_NwV8 zP4K=x3^KNvsbxnNM$%-*9$7TsBDV_k(d-Yg=cXud^D`cKA*X%o?Magg~r5}atFn7~(Q z$r8~*Du@gSJH3b4*c^3o(>6YcV1Og?gF_oe;#R<)07l!;r0TTf)$cpG_n<#cxSvqT zTK-*>BAH|cCwYiPJ&Q7h1?!Rpj%%Wto;3P+sPw#y*q+AkHGwRoT7}y~=XKENELghM zTNRJPFd0eN9B->6MXKyji+2=ByFcmGY8Ex5yxV%SGZSvTQvS2zxpY$;MrF!a7h)N* z3hl5xw;t!43OkN^1t;+jR>i`KT$~&j@#O^svMkK#!jCL#eS>yB{{U{T<#=yX#E|4` zdRAy@H*QTYPKIeDBoo1DLlp*vmAbA0>I{Dcc%LUOT)jFCOHX*?jI6o%SZGj$B-ZH& zROjwRQRe!|sw+t>1b7cULeXbq9q23FC&zlGd&L$y;_A{h69hZsl7ZYsQ5FEdus^>| zeh~3Cr>yIkcn^UY`m9+K9p5=baz57~i{8@Kp;qf@AQ8><3;zHPYxtO%5a#)FHf}75 zILaFx*z(M;8o!gl zp9VyU9+Q(ELhqSk#)*}sVmBjk`Ohu5kUh^Mj<3b7Y1$@OYiv5~Ruo#}V`RX|BC};=FvrA>QqfI3-bf0r7kG({g(XPm;9op+ z4=2T%UIbwx)G)<>6hO^7#?;m}$LXu*xbNHHXI9L}*IlxFO{_M%kcFtvIbgqtNmWG~ z0@)-AEAiLZz9PZFia4<_p-CgUK1)pOF2|}$P&@Yi-8D^>W4_=g$KedpVK$TL@|+>@ z7G|dmE2H9V^OPZ%Hb19`CSZHMBF%~L4F78DwuHcE)p=j9N0A-%DcD5%x|+6W}==c3qHI-HT@ z;pgg_ZW;2Q>Y%ueL%;#!YS!VkfK)BP1o7@*%5!l%PxPZ9Xn|zgk*R6gZl5yZ;zkZM z*Az1%tWyf}23Entg(uvX;)3qyrR`(H{{Z-#!@2p(tY+cGr{F1HrHGTClF}-_nASod z4uw*O=3+_ogJwMg!}!>5K0cq1spTd+#|hP$rHy7Gh`pvLknjmUqh_q0{OPgh=Dwfx zb44V$*j`*M6A=*LmT*^SW9U(27NgwN^g6ApQZm?E(CDp9(`C)l&YOc0YR#x?jWB~w zh&Dp7e3zOKH@XFCC?nnZcPAx@G;5-m(B_rKY>3u8HH5rrj-Eki8H%dOV6h}Iu&06! z-=2%(;Vim@7_dPf)X4|?HY_olK4Ypqs^1jsL0Vt&T@JRqKLhCyO9novg}+pQG+9td zG>sgm%q1MgwpD>N6p#h*Z;rEZKTyN{Il56Q2BF$Ka4n|5MKrva}@zx_Q z&CFd5FQ|jK5O}*3J-TJ^w}o58xtSl%vOKif)(ep5L!hPm!eP&}qq=lY^qhHprN>WvFVf$`x3WXgB3O zu7RP}E+hW{Qq!n1VQG-<`=fTG>FeZLcp}$kev8)dypZUQaj>!SwN=H(+L9M78A#nI zNJYJx0o+jALi?6@5hl;hhFqn~j(B$*V4hlIKtpXiK(c=kNM<~81t{oP)imk!fHQRs zhyahwk2lNQOZN^4B$A|G<^=E$9Uj8OFg8BI@v4<1a#S!_0V<^OeIyg#fyd92?J86O z@7w(^O-n9YEdKx{#KK%n>6fV_(X>QJWLV@9MqOQ04t9`5n*`rC*VwNPsifrN>~i4a z$t1X_Y%+OdY_%4A#2i`s{jcWcq-Q@P97?iBjf~!WWUH}K6t9>;Q_3QqR zQj?xrQ1a*V3(R8MQKPy)r4}pXW9H79E({QAS@3;MZjc*p4y+c*%7}tIjD;NUkDe}> zO#_-{uEzm&3~#B#g!G83ZixfNXnjh=a6&MV60S)v!!?lh<8w zMU{yVi)BrPtmK@HM9rk@aYU^iqm02Oh}fbYszf8%uYy5QSJ3@O0$4S?O;^Oz%^G6k zyljSw-~zNlno>9xDNWrG z(R~la5n$wvBPE^}i}B+v8-oxe{$=mC(r>u{@psk+E9s7Cnr-;--N`*m6&7)jg+t-V zyd@gu=`cr?;f#bykmA3XnC)b|kti$-P0J03YS{!18=~4bi}9?-i#%kQQQ&D z-C1S)!;%97eO}Vcc$w-vF_xYm)TjRdX!>&+%Y&LZ-2PgyR_*@sGLOMOZmVZ#IzDvf zT%9`~!+P__BPvNLZ9hG({J%PY3RrNi5!8}bak5887-_Uot|N}N#yw-&C#^YanUZp{Xje=-e0B6Mv+Ww zKq|<$wEBSq+ylYqs^DZ}))u*mE*!p5WJy>3*}EZF9#k43fg_J=>60H(l?MF0xMXP= zq>;9P6o^3D)-JmcTe11Rwj2D4SzSre-hSU6i9hkaL&f^lX4z029adv-Fvuk4%nCh^9{~AjIwXDZmXROK!?OR1yV#TE4ZM>>Lji zY0%;1utfAUE)T6KPblNJ1d2R=kqH|2hw?Orc{N!hp9U{d=JOd)yprPXHXXwPN5LIy zQ?AD3qL~mwrGWAz?DNLqV_DXjoh1N|F`N<> zM5hc*h88+Fu&N zqR_dwpUU$^{vc-NL}SNvRah0$IQ z&pl0zizF)ge4bWFAzfIVn?!EG?ulYTi!=c(`gNm7QVh(@!+c&Xv|RW}y^`*0$t`pq zygvyuG2qiB-uaNS##*AFw2Y*bmdL{LF-&NTq>?<)Ek+N<5nfM_u)bOzxqvl4wq%)>r1#ZSwDWw)Tcp@8AR0bCfaSeX77_=vi|_7>h&F+z1Lk) zw1_tea(y;*ZZLq6imHT+$gXT2>%rriC*$L$7<44T!#HUR<0?A3nAn9CR5n@T*n{!Z zxR^MbV<`JJuz1>K4b9l~_vhocRwlv8Z#AK50~5K-4$7>4d-a`OgX+XOBcJUxL?|zUU{%Y9Y>~`tK!{Rh=9mKBo4!G=Z}scZg)-qhvbL%Q;!IvrEY*8>reaAK$vpt4Kv=)8s+l-aPN_a-qMHCD1;da^IpiJ8Ir|aS*-H`)%XJ4r zbf3zx?Bi;;9-kZ;g+8KbXSQWoG8AkbtB&+*+WG2uG|5&uS>zklcvQ$~2pzcu5AHgt z9C74FBslPxKAm@OL%vchS}7dau1_4-#q|a|;^%2bPpFR{E!B!T$V`r-uw%`h-M?uGPGP|d><+&mRJLA zl*jby2zz5>*5U17?xWU-GP5J{(zz!DkhUOSs5|I9$LeW zV2K2hOw}pago;*T6pADAo8zpLLaPBU{Cfn`YBah6{PmTTGbWoXMv%19Z&;x~u?q|d zUVZ2heThB0bv&5^D;pF}Lc(JxSvVk;Bvp~@5AH?ZRVT#$RpdoBTI9O55giMRZS@l0 zW+KnPKRrzl^5c>j7t3fvwFVX(5b6l{K99FSBE$sSZ1uH&4fQEC1Z9E*h6zH#_KW3- zT!tQ!c9vrSJo>Egz0XhnL^$$+JD1KtpwAm@7IuO_V0a)7J1HzjbJh>wuM__OEt|-Y z2{1Bdj^b$*Q+QHQ#qbz28*WJ4Yk)f0W!5mVaiYi(Lkw=gf=g9wL9hX{z$<>{$)Ibd z@E!ML2HSUa%hdxF+`KL|O&d(cksJn|IPtd1CduE(c5T2bZoW2+y@@BQ8fGRpm`*+) zl?;RdHaub`2CUNdAa?2vQ#(#<2_cc@fJ~v3?EzGa1JpmOx9indyhkJErYzfRR_RJ?*p z*}nJf(oDchiwn>kTAlVkh-}ruz z`$r^>cmR{!^t+Zo$9bWGEL3=Wr$`yU7NjJw48)&O_a2@*d-dcb3bqiv5eN9@OxX_3 zj3ikMqs(I*iyJB3L`ZJO`Cs3w62%(*6as$(#W z+;SqW;lT3+H$A|i{rdX^y6aezWkyV580Ha{y~>ddqqWtoS463F3@w3F^>xUDN6>Oe z^3r&+gipK@#V0mu_@dtZ`}Ic%0@%CMh~&qRC{is#$tOSRYut5v#1en{KcKG4XynXU zT+nG4$Ot5Thacae7;aJVSrq};>FTN`+VA6r9R0eAc4{Sil9@8%f=wDJv8I*hRE%UI z#>*LS?7KJ>xB!OF1RDgkfI3Eu@A7=#DUYBxaJ{*z$k4eNxF!fCFiWYpx(-`DH&;c_w5<@L*2WH@#RG-WbTG#NWDlB~{U@L>F zPn7$hILuSaXz0rm3RVbLlS92%9cGwXPE>kEc1EDH%cscZ1;>|9`h@zpqMOz(Kvb37 z-e+|e>242Az6jOVB;jRZ?w1&3N}RI|j?P?2k(Qu_HVVsE=?CETN)VKY|>(nylO(1CEVj9Y+3?%mUY8?KSeYogOSBP=)hD4@G8aSWI ziZ(&{uE-#p;90xwDEI1?MyurFu1=(}>3>~A4N>jmF|bx=kAl1TrmpE_1uX&JTC z$Mb9W9t+L1In&o)v_~!eo;ewqG>UkP5~sI%9{&LI>3)4eeCP6@JEh%f-M}1Lm%jZHHeAPy|q?0>oV>0em!4xx~TBHH z>7=j?(hiMjz7xccSRYm=%*&YWd7eg<)p;X#0Nr*`Tmongtx1j}HiM5+RVqEAK}`6* zIcYTMV9>NFG-zT)XZn`0w|A%Ujo)w-Rg1A_o|K}%lg8TP>DaPQi9V-}T6u(P=Q^TL zu_FqM?OG&&)#(@2-w{Cierz}}$t-_J(M>ZXz$43Bl#QfV0E!#AVYs)?S!+I;ACSP*sI|B>oi`pFKMCOCrlq+WXycVi?_!VnWh8 zEQO|W1Qy!ehsZtb(VvH*hNap+ zUrFldjdR>`g{NycSlV`gntZuf+D^?n*`UmcfSy9jxrp2W;Lxyp5Jir$eQU;9pe7zP zjL_l!8#tL+T!jMGyP5!B+n$B%x|8O-t&=pZzCz0ZYmEu`TjGTe{vA}Fe9ZVIhG_Av z-Z%470Fo-Ik+n#msYF`WaHqYK=PKeV5?aH3r>zszs5PQpb>Gz{MnT8K^D>d8+^ZyG za{{0ckP2K3Eg!;*KE^ z+AUYhRZs_VeYmoFl79Ub(|lDv7Nw0Yn~4mP<1tc_qN>RIuA7bZ#a)WzS4Y9sr-x|- znLCv$({*nJwMC5taGhIUk&1;@h)6b%EDjpIm-XkpS5@^d8R2QA4j}Wh3X+gV6G+H} z07E$Wb$kJt zI7l&qv5Gy)vdU}IZMSMI`;bp?7vHDcT{9O?#Ax7!BZF|2!6mmarax z=VzB&{{W=Z>N1~nU3uY0&+y*49QetND@h70(9Ar+1V~VX1QBcs1P8ZrdmC-Y%ywhu z6OpNG4Uy&3ekECA2LSdTJai*Y#(AWcY=>B&R4UF#Z?OLWi|_5x%uHA@F{1N4yl5D& zmjkkiB{lh+wO?yD-;ZwetlCU@dqvLO=~q3~0BJT-X^}iBiIQ9e$lfw$bI#IuROh%i zXY~U6f>{$JSTp6wTj`-!5~73V*2`Dp`U5%w2R!k7^sA_N-UWtn3rzW#qIHoP6)Orx zXcYkZ`MNv<$0qtkm&E$liL)}YG=`fPWKo+kSwvKhI}NlWLMzh0=6Ve_KC6pEqh5OK z`Q^P8wBSh^M@Qj0c&o=h$!7;gT|F`e7=}$kNMxwNX?HAmvQe|V9nMupG_BTksOoa+ zxtUsqubkNvPHIWsZ#riL*j>hzR>=Z2pf9klNa1LPJdYwBv*o_kS7?l~ySG1w5aPS~ zn2)&X zCWoSC>)Fi~Ivi-qgCQzfMUKMTAI_xJ(Jgl;Dm(;_AIyp=V@EN_Obis6 zDR!Sxy^UZ3c;tc4Qfk1}F84T;A6fBEP79_!jtXSD#(ek{qVmd1Y={LfmI^Jh@ZXlY zThaV0nc{SvG|90rAI z+^R2%Bn~(QxZG@+awkkx$!vf?xGf0_RPVc4F8>FpJ41?0w$WRjSc%(7n#XSI|1 z@qZl&mp2|H3l%JMHlSg;N*&2G0^jU9YVdZ8FNkycPzjEYYA7v6x{fxbgmM5Jisi43fs zTvM#XOXd*GP8oeYl&V=C4~Due#dRC41E)8o96 z6%j-c0-I+nR)8PXMEBzQyGCG3km;WFl^9Vhr{WQq-q0xL^%;*rc`4h0(`bm6_|?v{{Vk*dd;Y1jt(~f#=Eb5w~e#C zIs`aIk~)tyoOs~2ca8P+$Z@e}SX_}oQA&^WzO+x_{JA;)AJk;Yl|0`$SS=DGLwi97 z{uW+-ziG$@?NksDE6#k+t&?gev3^t=f+Vq<`O!7Iu`2Hd}$mxdj{+x}ez zn@mKP3T8!V;)UtKi?gCIy7)!aE?M_>s& z8nSkdYmS%vZ{cq{5asD{Bw=1jG9f}qlW_dY`U?Sg;QgzkIC*&p)cD>`93G9}RY|^s zk>76)EOEg7jWmxuGE_lkLOn0}cOP(l!RPcnUW>aom$Q23$q?n6VL327l1wN3Mhq-* zyK90!`XYaRjYytq%8f?q$J~m)_3NEaM|^2!p8`KK4r-OvSD4*R7439Z>*A~9sWI3X zpL?l65w>mzehr_!^|?Xe%#e|Ag9Q!HzOFg4AjL@DNFaG}SgM7NLI@=8;_MFmbN1@C zpu2O>Pmr_Zs4@~yrJRxqtyt~*0rAy{_Cu=}GmDHol@Tyi8<-mwN&f%|2zsxP3qw33 zAyP1&m}$2LQs0vaDPkvFQFQXGA@;oE;8gr7FZL@dt^jv+(GZj0REkiLa4xd^Kt!kqP-^=fuUM# z@vcXOwFhwvO_`)mk1Ui1@*^@tqW znpPk)pqaM@B#Pmx*85+`>Q5O=(fF0K<8oxoCw_jeK#k?8YW9avld*4;4v(LMa>nlS_a8@!wx^dPq$F^ zc36hiJVE4k`YScrshWOXAKF-&E1iO$R4m(VM=HSo0PK3r{7&R}qEV8nVg(3T#W$1_ zkUw(WzBnv)F8^xCXOR63k3Ieyk!m-z7Fjlv zt!3#ltk{biPJl(_xf>cSz?5%Erk$>1YZyzDjU0c97 zAddZGnYbAmZfv;Okq9#}W@zMAt-FVCZ;hmK58QQgL)KeB%v_9hk+9?;WLHsaE{~+2 zODNr4@3+5OHE`{$Bx|TU!d0#l+LYjl6a_`z>X#{$K+&PqBf$dOwmIB^&(s$?xpqjIYS{{Rh&_v(M*7MZJNXAI3c2?Q}< zzna@rpxDpmBM$qvxg)SNM?rpucJW>$_?48oXz<9g4eWmnf-qCTBWlpGTMc{lpuwza z8QNYH+7=crZc1YejGRo#8VM(Wfy7l~)WSd+>;k(@Sf(65ja0Y|m+_y{Bl#GNxJEG->qtOtyEZ6tB13f#2nC;B~~< z(`Z?7PZO8H%U~lCf4oGX$Q%m+lon3>g|4I3<7mb%p{J>kDA>VIbp!Gf>;V?6dtDwn zeS|x_H0!SMCF0D=$o3hPPIbe|9FnoK`W zjwaI`Qdr@bmPMqsAak*~C4%>{d{cn zsEn~XS_dA)9^aJlU3`2!nUf)q%#nb~VRVthQi05!!6&u+e{Q_nMks;VnH=|9t*O^` zV4T|W@k#pki?Xo6hfGwCSpid!?6Qz~8_01)aKnC+D`dV<9lma;6qOoQ<**suYp6UB}wefkNH{4mu{ zOb06)7AyfH8EYfbcAgEM>&W3tcB?&lOgW`MTwi<>>#9Z4lVP9O>FH5neiC9yUZk_D`^cv`SxLBw| z4C9t#yMaKhvF6VMr3FRI%Zmd@v`(4_zmU@wEu9cVhBY#l5478);+ zkB+1|IA)epAm6-w?~%#601!HiL>4xV`0|^cxT>(hE<%2>Gj&DI#z)3jf}{~MhTKC_ zZQu(30GYo1HsPi~jiSeq?WJO^6I%oMivoDzSb%$ze%&tUSX-hfw`{v3;>hHJ_IrE} zVaep4n{qNSF;nUCC;CO6P!ZGmP*t(#;`{dFq_LG=!`Rao>#sFxARh5nw4*Hf`EtVy zWz{huNhDJKUgG7#5!!)8`<5i~daL6m)P9xl@ZKDJ<#bsaN#~#IIA4*EYmfe%`e%v0#bk!#>fMp{umkXHexjLOT|9DO(;ebdVB2td1-a;l&Y zdKG7)5W|WeCTQnbW{s9NA*{q~A1!#G4*-tl+vla|wb-YchfcbcKk>E~8lQFZd-9T-vqo0lkLUauW zEwe^et19B4HykaH8b@J7jjLoe4l4fLX}qz3m!5wKF`331w0#yMiH_Q)s>DkyL0+wh zzswX>@>M_|Z`Y*18Tij6wnm?(<1g0A@p_M6*!zf_bvX zwM6*CcDLsoV@=4TQ(;h+!Um(cq7oqYAQDuog zm5%{OG$;zP7cn%~mn{-SyLCvA0u&D5kUI)JzV>K!tvShy4ag$bDy}XJW@tp?&uIV& z3>VpWY!sXMW|{0 zV9A|4jRcbwMkChpRoWpW4h>y#z$EcqFG|gn%D@;DF)D9x1l^mfcmDv3@4y4AiecJp zRW2^%n!H)#oSzcuSehIVV`AXpOXe#?847?1UC2omELGVR-t3hecQg4oT5#B;umD}T zzHIz_pZhkn4G$;8*|^Y09Qc|+|yW=B%NcWTKZW!41=D6#-Mp6U|4!Y3FGXZk5SEuEL$s5G1VRA(#2z>B z6-Tw%>q*9k7sA>*pjldMg)XX2<|LM)$NvB^7Jbid-9e-1m^w(EaUcti3Lt3-C(LlY zh4voitDaBTcB8AVT#uU^`=XIQ2~|l?Q7S!Mob$%eM?6<2uRiy?9a|{-1aRd&TbWn2 zCX=;L%Fh_M(q-i{i5h|Jxt#H|A9g)~`xDq-Kwrj~Sb#K1DQ1S(DmaV8N}BTFb^%(C z1%M#e1o729Z0ec0xs3*yHe3#kgtC$XKo113Ji7!c(g52)2oI=|3N0>l#l{d~2g-(B zkojP+jY4k@i#Vbh{DyFBdXJ>(vl+fehLmP;3%pzH4 zG7YTdm>Q7#5CN{;7SZQ}O@}WYY?wioBvy?qBJxS2&46fM7JGCOY&^VE7|F`V)8v$c z6A)fz_M|{;*}lW8_+A;0(e7B|dzP=^RqDUTkE`G?DosfHpwf)=&T})o?lt`S>{wXUx>0l!s=0$8!}N z*(8m>b4Q*BOxj2A*GR+?O{wI*sVkeWP%hPBC_00*+ZiJGvmClxUl3gnvDHzHXo5+{SRVTS{3m)B+bAN6J z>V6tX@=TKDaXEPa!*>eE>@oTzE%bz`J!JgHj-XD^R*ZE zXkuWrNNr7;43$yCna@$Y|RT2C_!5U)v?GbLm=WaHz; zn81O(WY~%eg>EdBCzHj{>x^t%2;NDO9L#5s+>E6_zHE`W{{WX>rY3ewPxSG~%u;TMiV7^HrJ-$ynGyB{%@BokGLC< z4}LhcWFh_XAW{4aP2T|o`;NxM* zD(7axp+!acM|%FEKtH8)FlTIbk{noCMKsMC6l$_KAdB|uElVOjPfl!n^N}2L6ky~N zRM%p`91-q%rbd@auyKe|Waeov5i{k^05leS1!o7bu*iFRklj;kJs(noA}A%mXuu{# zK5h#TJNuA$`*l7pN_pH3>VXJ9oAKFJY(2_J_Tmf#A0dP%mi@$)H-*BaB*>9c=Vjyyj2$* zqcF;%Gj&dsNaXkZIw=O3qs>beR&G98sf|m^=8&GitKHY{T?vN(MJbmCO{+)O5}0L1 z=eV#B_Z?q4rhKTWnG`z2b^h-nAH@UTzpM8I{kko0{Xd9jdW*xk*!kRgg;sq=ldSf~ zuU@O1y(3VH85d8OW(9;Q1b->iuVNJXdH3XBLt)f2VTs#P!J8eC6v$;ilZpTeJI4f) zF0a2A(KvIUk``SnGEFLWq2y;DHUZpl;BFtG>g?w$A0HXDtZbF zbel1l%mc{8G~a&yca%rrXkwfGGA+3d!pw&zFFz4nAv72YzJK8${{WX)Q%Rdpky90? z^N#OGd#VMEUp;~E`gQa8Z%fqTY@HH8r)JsTEG}9$vTJmAv=hOw2ilKbct2Cm(zD^x zyiKNv@+VeQncOQ&&pQX@aw~v2BK!5Q%xxS?L22)G)s{tE9ZEOYrf&}Gm}|ZnPGK}W zr-g$kKIG7``hTB7a&k2-Hf`e?9DIZzxDt76%1N+8C?pblAJ+Tzu0cEo2$V3M2`DO& z_p19Jw@~UhQDvY;jdEiYRyj~HQ~v-7KK}sg(OFf@GYN23aiZ!%uRdkNh$@Pog7yyT zZN`W{(m@{J^(Iz6m6p(vk&BO$ysLpK72F!lr((zUvDJ-FLP%tiY;D3vJD#4cKsE{y zL|^{>2uVDwggF5)@k=tXL(;Y;70qY}?U<0%s{{0bU$kX#7SJO^6bVL^WyDJ)5>husweWAZ>4wAhGFQB$FIX z9&R>Fa*4zeI|6ow1Tg@ssIzO|wbxbhu%8(*=7TF0ru8&ZZYq!S8n?v@3HsIb@x`88 zw`Geb76gT4T%j90kOo#8jA&FkSpJenu>kZZM)9!MA$=snj|Q&+D7a)8Q#v&?S}XV3 zH*7XX-?$sYnNmlbTa@qh^IRHBWNFW+ljAg+3pqB)<~E-({LZ7^Gj>4z zM_t4g84^6iha^mZMUxjRDxN{yII;qs_05lQ(;xEO{CGp*?w=Eu`U%>K*t4;2sNW#> zKH&5R9{}n2&6lF%woa0gZpqUM`r#tWJV5jJDfT2$yR>C~VW!d7_u!?j1-VMIDrIBj z&iJl8iCJDW^9W>GVYCzNW4XE&)AZ0kgQb=&JhnPW(1~JcJh8S1a>~jH^%vjIVjBB# z(nd6fXAHhvxVdW5;?3o+mm-tM9PmM4IOmad$6656^!&XRO(FGIGBS*YT`M=tjeO}q zriI&g^|JxUwg3~`tjt&Vp2xIzOvt{Q{5;}FvSyoewaxzkYkyuo`k|9xVrOPx%cjXR zDUl}m@Ywz&N$K2Ghykb-Hb=NM$3ZdTfMmcmU`82jjPizY5MBxN(L4$@^L1NVmP0asQBgH{NmeMM>&GMitAzYaS# zs9_T;MbjJ3#8j11IOb4e^3LMBkEK|1>I*{e;PKm}ZxCb6rs{fhSeUH7Y)!@oBOP&!*(okN z1|nUtfQ=EaQ5+Jd^c`o?#5SEk*Xpcjm?Q)j6H!TA1YNGBHz`_W0=NYGaoWdzI=hi3 zE-W%+WE#govPDHJ!*PFM$o)J0x>&`_nk<#a)nYKrZD7iY7>QJK$Tn2b?0)omISanl zo+Ve?YF$0MfnxX{WBc{C>S6urX8l<8$t{?)-$YeJk%)k-mhAQx{C@R za3Wc;%u>Kj`tqA&gW80WzdG!ZFSc!x6v6^=ZamLxJr zW0c$OW!l!q)yNfB`cdeLc#8uzbUKdM6@0~EjzX0MpYnt32_BX{+>ko+T=3pIjGUMj zaPo$BFg#KPAPTi`ACNZic&~dsEjNU-Vx3*`pfGxm17!atRgK6Z`dBA5h85 z&66V|Q&<)qsOqq#NC`G}xa9Ubfdam7mRRs~9PEQ9(?yFS@wH|QjHiMM^YQJ~r_uaA z6`Zyt9!u?vrOCUwQbiraSLHYH$mlMj1>~;IH+m`~GbRHgY1-4|NfQ9-n4VEmzy)JK zfEvIYj*H;u#fzAdoZqOK+_p^N!FfR1DEbE##e>J+tH;BbGFyR)o6raH*J6`E2HDs* zxS_?KyI%{#AZCPPNfdwyKn?5U5JP`S8-2d_&I?3=xtyqAU*E61b6o6kCoFe^Y5S^;<)78J;b}%(EQsX1zGl$7O55}7KGu8ubnj~FW9}$@ z;#C8n;Bm4nfI;KS+y0gI>b^&XFrkv#9GrFxc9&1@+qWGwV8oNbB=NK}Lx~ekS!Mu* z1+Bnh3lc|QK6vT9^qh$15$2;~!cc~s#$-XffSj#@eM5`=dS18G%@YOQ6Mnu?SxT$) z3nqs^#>QX4&6Y1Wju;C+uOA&9!-ZF56D(PTl#V~a1)0ME$-e&p2D{fs^&qH=N)&@1|E~T{HBQm1z zloK-{GL|BMLys6xhz}%^7>i&5A1R-87?Hp%!Z>wGDLy+^$o)JpGn*~ zHC%#vsgthZYEwJKi3~6_hD47J1&Bm|mH-j+bWK<3)_thx8jeK2NrIWWForPrlce@l z&vuo2up-q#Z%tm_dZRXv;w?u`g9{^4nHwBrN%hkq@}wfEB-(cBVnmZ_G~{PaKYyRl2r6;I@MUWQk+3Jiw70<@Nh0{7opfQK@bm&+sf^2g1 zL8I6K>}dBe9X~4uA1!0lGTonQ`J00m1D-xbgS3xx_v*c!rP4a*sw;A6Ag*#})pKN7 z8zf_u#@YB$%1o46n3BfHKL8FZ^#iD6YEeeWx!D=X8#k5}3Px|a1ddIBX#4ekT#YUv zBMnH>l7T$N46S>p((_-b_UEXi)HHdZCm%N_A`x5SQg{4V1%Pf(U^)K)K7muSc!5xZ z&)}vRE&l*tL=J6#SCbYTEbN?_G2oV2R~_Wof=Lv4j6faRYTxJp0Ch9rXX<)uYI<@$ zP8I+rcnK`g@AR~`cmsCD=7}^G=+myB{3Crt9Y@3&4S@`m<-?B3?8$VlWCejFUki0z z`aPw1I|o6NHh8qG$3ggQnJoLUvLaEsnu@ON=%Garrimb)lV%FJFyjJbPQ2sgT;iz@ zw&$*_vt0)YO+*?@yqtI-X$Q{>Q&UiCSh!hi3z3vw*((aqCGUAEqCh1g`~Eu z^GA)B1PPC^Om?-(HLk&6#8rh3$GE<=NNydH^I_K%nXGCPlqJn7Z>Ye~^7Tx3u<|tA zZHjR*BU)XHu(WK2(b=ez8341f2FC;hnOQ5o6pmSAK3il2Ftn@yq1Yctqe6$O$Hz|C z{uaW{%+n*2Sa0@)nexnNf>`5^l_2e=2WUO)QQ&klBNI=}7)sLSNb@|a<{3HJxTql% zc2cIuqubk_mu5AtA+*6he11BaRC6|-wE5~1qvOlxO*Hc2MrCCUEU3~mFyJ+lY<}N8 zGWd7+eU+|6`8uYplZU4e@8@GGB(fD1=u$qz)LgmtqR*bP>teS3KOh!m1gCsGA zP{FMG9pbn&eO!ZFx#;*0H<1XQR=~)SzM~MgrbGa;Z#Edv9FloFa5@e)t|Zg{02vKB z$-TG@@w~^1nk;0=6W3ZR@#Xk$!wvL0W(r_Kgs9n{PZKs~O)&f^U558EcNA;V1$%Yw zM~rnm3`y{`%sBLCjai`#=_x?Wj)%*-HUTH|1G@OGyv6X;xpKr?8DNtft13XHo6@|H zc`A7)+}k&6zKddMFvpD~*)Jq&(bwSE;`=XhgRrWvx$DhWrGmr5s-Dr-CQjMhEvE3{ z#b`10+z4lMemdpJ1pff)(1vV`{Z?slC(_JbV@NSl6}7Ocn`!7UzE5s=>P&qnPS!R2 zyr1Okvqg>yzH>=Dt>vjj^%B6)2Gs5Q6GoZ`g~p)^okI`Hz^MG>l0&embz&Gd<~$Mr z6lj7D?l{d{{LuzhpN$~RFB3$J{-p*~wA{2&N%M(cVfW*#(Tgz@hEowEyZ-=DpfR&u z`!~GIId|Stk}(?^7Ltj$4& zK1NB)DTvdF+yNx=F?u2dY6`xa1n%rf9lBx8z>iSM$;Of>Lr8|2NRf=2%lcJYl0sv( zaoMiA5vRiooOQ#(iU^Ao+R=y|_R@ml!&&kaZQy!|Bcb9k;4UGusY5%^asJ z40!gED`x&wj{AVGV10_uh3CjbTaTHH2w%fHT)V3RyKjKieT{HC*!=uw%7ZrzF&Z3s z-a#ab6erG5P3~IY5_moA{=H`dWX9B;fi`sdW(JiUM>>31rH>mtKjSi;#uK=Z#nAvx z#1%`S(0siQQPV?ZY8qr3rYK1tCTuzPJY*5EYH)P-O|N4K1{X=qO6Q>@^xQXz|(wFlG%6})A(~$f)~n~ zY+%vIO4}$9t)z)dvk_n(uwr$Dkj6=D?s+MIv zf#84#TKH^5S34mYUAs_qJ{ol?T8w5~(<9YQm}SJymrT_>(UMZUsl$1(tpY(UM2~{q z#dJ4N@b)HVMg~rwlA3m+WcoFl6S%Ul1f;RGTx>uDf(W2TV0tg8VJ4rUL7m~O>|8w# zRR%pPTyHxCBrI3ULe}{9M+}S;p2MnH8L(;Dv0`d4OQ1Q(QMP9KoJJ_X?O8xC86iz> z+z2Pt)8EL<3n~qx->xVfmQ$I9R%4kiRB>vMe<;RxU6}y1kTi>H=#+Ae!0rQZFXyd0 zPtD6ZYeC{onOO2cEE$rdesGb8Z#Qo}w*$qHMe+$FblZy|XCdI0TYow>1zsaEF{&mv z1PUw&Kk)QRCsoPET=NbzNg}T3jd?y}1o`5Cq5%xYw|?DZ;u_pVqpuykK!n9V@!nLL zT-t725Mt<`Pd*wojXFmtu==PNRGrbV7x@iX7u=q_&(NRg(<8}b(G$sj5l&F5FUMI_T?#~C9}&Yl3|b=4rY)+yk0PJUrP%Kb8l=H&ZG_X8M`8Z+qNYOPd>civ{w=; zuv08&f&jg);8hhnjbF8NH%{?PUM14g>7GZ<%u+nLAwN=*uL#$ zlNz`Z+aBbFqJ6CXoPNE&{aS-7&UoT-gUfHue+^G@K!a6dzXrkRWP8?TgD3r(WhZ3< z1As4{pX~CbstP-2M8~uGW_48-0Ji2^KiC!AG>oC4)LSG2)9X z;>u)_34vg25xHa{u8o4gi}p9wY2Y4qRIuXZW6LIJk}b>{G>w$;=;Sao5A>U`I6YtR z_9`nwl5&hP2{uWNXrrdl{{UP2d>)Es#|}&p0MVl$W@3sLi!==mc>532tZ|OR(yas$ zvPPSBet4(F8jq%Zy6VYe8zU|g6JxyaJYcQEGbvrcgAldFiU+;>RdiQF&UmL>Y>!?m z-{7)sDq5)WI}Ugs;_Ie>6I+J`SeB;wt}Bo8>(C5SGQL_X6et5I+-w3uf<3_P_r99` zP8zkD1;==gUp}P_GOIPPNAaV0vC;Bo$5eC?IAT$304_SP7uW;Tc-bl2#xL^5)v18)f?=T$U) z$)Gso(Xr4V! z2^m2FV46Z53GL}(5B&b!T^<$kqcG{h9F5G7;*|s{bA!P%7St7_#H~@+q**$g<=AB%v+O3FaeIVnp zY#Pp+px{Hk2;#$??co#1xf{sbNZYtAdPqL&VDzh~>JhF^Mq->S;|!ai@-bt$q1*#9 z3iCS>Htr;WXO24ZX(Z0b6pHdGU<)v{2G8d9`RQvX3ulh-+fxQew?`bPEQy#=6vLag zuulMi!57xfFFhJ%@?1|^56?B1hI4AaBtQrUi}EAXd`xm;l~rX}A8JOV^NfWFJOIQu zJXc_OzLSfXaMC$vHq7h+Kmj4Pl25qjzZ~>VcSVP0$Yld4c@uysqTBI9xd7OqW4CUG zOB>{1xRG}jh9&e3z0U-n)z_~%PD|wKwrlrjz*XUS7)u;LI4I0Ph%r-lU5|SGI`U_m z>M{JXH#RgLTM$JnC%4$y{koqQY1DEf%9Y~W?yo5Pv5lp-o@n}%aqcgw`KQb}b4pWe zx@;x8fGJp4?c1x=2smc}ZR?G0IL3v6Boc>@>gL)DTP>CsRp|#{~e?=pr zv@0a5>Oo8iQo{ayUfhk}r$_VFHt=lhlN*OWbaA9?IkGLu75N{EzDd5obhP-*1Wi7| z78!yY9D+e*=k!C@Gwnrv+)=1r@uZDHgo$_V+M<@wo_HjRAFuD%*rUmvO8`R5uI#&c z9CJsxALx3Hc=j%0H7etcl}ow7Vr*FTcljJw>DR3)#f-|aA{JFF-_m_Rjy?eY0G~!0 zBnVaX`K89Ef$5euP1ja7)q~t0gZJttk8Tt`Uh?%R2uhGmDKsk7*f(U4kAr_Mu`;z4 ziwPt0=4OpSqY8-t9%KOR zUf0%_{4emg)p&15bE9SEVtq4Y{{S#((lO;bO0uK4EZmYRK%!OHLW(7XQmio51y}|S z-xR~y+O)EDQsu=I#z>@z1QJN{K@RQFrsn>eA8IGLKK%7i>A@OjScDBNg35mo-??MS zJ-U6?bd3u_o@`w+2O}dbmD929xN|eeMeu8pN4aJT??<8j zB*uqIh8K}i9A<<|=7|;Ai*i9VwG@1<_Z*(xJk6=agl5CUZ$CB!Nj!*(DNuN`+$RR< zyNAkBkskC=KqZwHlyYm_ znmwzgXfSe~IVY1Dn-oJf!hG7Kvuu5B9eVw^02f#jBP_Q zEK@9qHw<-eN~)Ii7k+F8DyEMehg6C*j%Rm>G1l$-)y+q^K(JKv^-OFWfrEz*Ms{}5 zP{fSx>Ugr?Q1>K`z;`_q!_f0FvE$9wmP|O+f7x`{qbeRt<(wb>SmV=Nk~ePlK42al zXsxEs)};`nrHBFJs$J|r+a2<%0JFe6bT>dl;$INUk(}w7i5zjolaO;Z`7A*ED5Gnp zyCi#`>f@mr)had5c!rLn@jhDGtza-4uU<%K(oS}-CPpJ;jD}V%nINHztOo1#8K)dmay04vdBSe`h~n==kE#TH?@>6*5moBgR%AWx8CgBCV(`NyP&B>wR$-bX4$VvbW{r5K6}gvD^Fq0P*Y0vGmc9=;Y8YwMduP5-!ia z(c7n~Gja5N(CLsnf*2W?m`GxzQ#I}ajfDUcK$Beco$7jn=T8nCERy14s6+`K)oLe` zUv4@3bgm>*!?PtlQE3-cGUY(DjTx}ajNl@%tuQop4DTI+pE~PvFg!h zW^0nJHXMFg#f~>1%50ioO|f9C0)PlMcmn$8z}hTQOQ>aLVND9ED8`ZEW#j^+?R(qX zxdih=raenXpH|O@HY}*4ouM(5WK~$u3Kh=OJTWcFzD<&P*rip@gHVN>^46TKvLysi ztH?3o2>VcZN}R6%i?4bkx5r*ZoHBnC1x|N;s~dU?4nHs+qB~O92aB+1G&$+wD5BGJ zL~Sn`c!G&zk>rw8+yl`dZH|fDNER-L9FrOCiQ%n2e0@H%H4=rNYA_K*y_HvrRqa4f zzniA}Q&44Sf!Bgq(}R6cBd%a$VwrVFrN)^y1;uT`+A#Gk}HM+*Vq(?ob*SPDnv`lOmG{N;}!2?Qt=yn;`pbDhNqm1dVM+F5Rg zq%tcWNper9_T!%Z{klS~C{uB5F(-fT*VP`K2UHoV8*WV6pYa1STzT-cXht3!q_mO= zH%XApLEF3800P1RbyrqQo)hrqSBP>ICz3SS47n2;9$NEEd9Pv=Py^Um=msVk&C87< zSsA5eR$!ah*#MBE*j(8Q?iGI&Xc_IvZ6IkxD=u)m8qT0}oE7 zBB6V)9zhbTnMIjfZ*PQ4wDz+r8rp3{{o8md+$niE~X59h$IGDP|JB$a5KOYtRqVr^Vh>D}QN&$^k4t?&u;K#2J>Zck8e29y)G>ponVp1)r z@PJ?aEb-GZ(G+-5^t~V~nv>K|CMnqz3VCAg)wq$z1hMu5rY#FaT`w98OfM^XZVRz| zm{heAZMh@TJx)pOeaBB#s445H*RHpvvkA9?Tkw{Rq~_`hn%-VW)7_EaR3KYM8J0si3SyntG4(bZk}d5dVk-cq>S7pp}3`nF`v3lYJmE$15yFN;`t&g15+u zKU)O+p^qGniCNBN8O@`H-TwfK=yw^l(==My@K)jQzFr2C3*GY5q1E5uwq9DzG*ZM^t{yaF%PPg4UDO_b zq~8Ak(ERmF_?an}#Jaws@JMkIB@?m$LtHAse#G!A->Li$ofel4kraA%N~^w37uCd8 zrKa1nXe5?Yu+72r-Fx)SN}`?)nImBQb@))$=6i=*RhXPo-G~ExwLBVh61on-@bOpWF>a5%EW57T$- z-#slPaJSS&JYdBwtHwbb5=P&>5PALm`n9DOk25<7vguE)iC*xLO5o^q@au)6@<}tljkVmI)AW%2K{h-MqwY^DFLIa4A<7)r{p|=X+wuk-0 z4tVO!_>MFkCRrf`WOar~iz^0VSb(ev_Y7#)6nN|{S=lPGNxvIyw^!2Y116h@8Y<56 zoOrU^Z~Hb_iIVvU>ZJbM{{WXlr^AhRLQOZA6oNlDtP%b}NcQj3SBD|T%)`sWoRJf{ zhqKxCfE)h+q6^U3@f$M(%-OzJq}d<>z#!270Q0}MLS;diwCp`~$xvCK??js@t_C~M zRf&rhLJI~Z$p*O=PXO{man(Gy(S(uC%FIo%^Gj|74`3*QXy4!O)iW$-9;A3|5DN#| zRGq@d#~tszRrl)BV@c!}nLM{Z%^55SP$&{dHC?}MJC2s90}YLnEjfZ-@cx;QbFvm} zbykPW4=s|Uux*WA;1mA0$30N-jtf7BaI)Itnl>%6L$tIdcqj7NEh#MTr{ zNKCjI1aeBKlW-t6!_aE8&jaJGyiDg;@Lr*casHg*VhN&+xe2s_%BF|-NIVaF_UiQN z)Gve3xSu~xDz0mF3pvo{-6SBaOrS5AN&|5a0}AcHHa}C-){innDrqvwCOpyQ#_;7p ze-jiXK!#nn`Va^9Jspl_T}~;Le5j@=As6W@bi<#9qes{tg5^WxV&Xs>bHIll zRV0EHWHm$Jss7~k&P4K@P^nV3Bl)U!0_jK<_&*_3{>Pqr9&*4)=AFtNWcQ_{u<8>e z?RdUGWQ7Ce20+F(hf4Q2b;1m71#cl~ z&1qwiA~AqB8X$M<8CUP^eKzRY^w7$hey~`EDv?US4a86g_t}TDUHqQJp^R&ZmfUOL zcKd`HXJfTf_`}0v#yVVCx@1ba<}y;Qz#A$)ZZdAK-EW_7ezA`w#!(G1!&Y^UP2iB8 zqP9nIN58)Wb^1QmNiEr;%3BK|JV{>C0mkYb$A52*lYDvMTx`b3)v*d;YRcD>jXAio zs>b8Teg%==+yXDIz~Z|<@V`xmcMe?}X=;p-m?d8e&iGkU;TD(agENRWZ;csE7Dpb$ zgWP<3_kYJ_pAJYEHJ5=&F z1Hm0W=HX)MxVaGI#_1I48!|-2LKWd=j5p;x^YO^(BT&c8(z06lC_na9LKp3LV>?J+~S){V#p5 ztkz*Shc$=9m`M~&--hgNIR~)^{Xy(W6-TBVU1ujBCM;=AW2U0cxiC8`LWamD5WL51 zyrH`db<+l=rN^!5^I>E|JOnit-)$2q?aklm?hh6SJtoH-HA2EHir^e2XY&YC&u=6) zB<)#9pVCP-Regs)vHeF$n3|?UIjp%38Fug8TXwJ`f%oH)^M4duq5~ID&C_xujWcni zG1P=Fn6=z1cTxzVc>TEx-XPGkvE+Qb1p1hnmF0pn_>nkX>c7-B*B!+U{rcRcQL(`V zg5(tEpzCd;Pm`!<k}|S9 z%GRKeTr!FuW#ajx*XQj%Nwegb>4_|l7zRL*k`P~VJAr@L^g;6)MM$#}UF;gj0ZsE` zceta?{PZf=R#cZaR6txirGB(b_+`aOB$gQ=k;2o0y~XkygWI6Fy1>-&%y0*PI0Z3A z{!=RRV7GdpECL5L&scti#(R?s8qRAFMROB%sp4WLdK!ANi)!5&) z*&S03MoiFid-$QeLx|X;&@@%iT3qR3#+NT409l|@5RGoiqMIa>`I?6m2f65Q!;(gX z#SwuK3dI@%0>!%Qj^fBY&5_f>Vb7B>S;TM+q$rT`!?z$^bMyVWw~M9X!9gSjSp!MA zxQr_D&G2iV`yC#gQ%D-MoB{ks?dpb^sB*9%SXis438ZxoAR9mfgsSw|HQvcS-MzY5 zeNQ4x^-L+&A2gMcYp`RXUdN6J0*OAKewsC%XGz1xO|e0f9IP5a22&uQcPMd08YBV- z1l^jk(oDG+ntmcQN+yzGSRyz_B;A!Hdv?0`1FKLW&vV?;X4l)$T=wJu0*d%~@%0Jv zV_bHR8yd=~^(?Oc0Myt0besy>t5i>N=Mcz-7_qP-jq_#<>AaOtt7mkC0%%y{o_lub zOG=rvY;=Zbgt>Cuxf7cJI}e}gste70^$GD3E5nBo8Cr&0BKhwt-?+a(1oz+qIp>P# z52ox*U;fo*xG-^A1OYJPX=a%ukVIAHB&zHj$kux(Ba`2Nz3-*0{F#PivSde-{H_>$ z_##Cq9P=p!UQz{>KFBY3HcwINek8}xp%Ef^nKDOIq@Xe_1@sfNAO`4=qPencuP!!s zh+rDFY&kGsgn6vtlSL>@H5ww7?NYRH3Kcxu# zs!ajj&rAL%TrEc%elC+XB(cx*ZqjD@R2`)o%VzYK5|Dd=W0OSm24Y(J<)yap^`5lw zFJeOjfmz;m3go5~xOfSISp-26$&`d9Nm@p#7gPoJYCRFtbhMTjT2WMl5;#;ji+EdLsHdZ z`j{4IL@-AbG7#*l1CVU+O`gWb6o`fA)6-*jpK3+qx0hJ3YIU>g&o1crmIqJWNyg@FnCOIc>T&Tm?%TFY|@$ox4%ko$}kXCoIXLSNVJKovNnqlq8YSnEaH67vBy-I)_@3k=CZ z5Q`QdTzOa+<7lKq`JaJ(fhU_6Y+8wf2zi1Jtj(FiH9SWsS^wyna-&$0lxKpbU_x80{Hm7~zOg>m?sivtC;N z0K#4C)7LMg{{S{WQmp!ba#l8#N95n=RZwX`{kR16b5F#|o;ZZ<<%uVGNQZafmY|^r zbHcA5Bk#~nW5ln3^Wy1|wgRFgM={3l!f?h!QMheu3F_yKz;!?d6gI765uh5A8c#!- z;&aPe=1{K?YZyKs&(!{xH8P}#$t2nPgGRCK78G^>eD@S9u<27wgHYFgqdUbdmx+sz z=4@?~m|6%*h1nq{iGK9J_x8F6G}pzl;&ndTmn;yh1ewz(k3cBR>;CtM~(-$oy z`p6bpUO^&CCT4d+0U^J_Pc{b>c;~Ek;PE)87dS-8pT|}R)GN}bE`GbWc>F3_4}zvg znr%67^xOu9;?8p`P22!v-|CTw2ekoTxjBWRxd{fB0iGoVB9PK3H(-HwP16!dB=_yq zo*32B9(P#bmS}`~Vo<@hu{O#9`1d`&{rX{tUE7eY^f>-&8d3q2kV=5000sVI-`}Hx z>?K1<&d@;IJfi!`ht*|k={<4sLSxW1Jd+wn6rwl&n4?ldZL)WAIRlT5I=lY>fuIX| zgt9~n0OjYV?g0QV7I$-Z{#{HnH5sGwB-B5b12~CGD2N-1iKXm>-S;*C`}B7T6ON`S z%HxHM`lLk)pN8Xud<(1W*X`9`^(U}*OwIQq)5108=scbm(=j}+D+kHUF8jAAW$wFs z9uFk^9Sz731qcGp$OF`G;MxBGmq^saVxRXDXx^9RM3)I^WN7JRr!^4RQ zZHk!Wpm(!dn0Fj@Jo7@&LmS1}vk1g8czFxcI>!Sqm+GdoD}qJ)*B>1hn+&icDkQ~? zj@3-JfGem35>(q;Q9oQ&siI!1G(nb3}H4Y95(fk0(m?U z_v*L)2k_$Ot~M~qa|FxvnMsmqW1?sfXoG6J(B|m$NB;o0#uT{dG4l0TU=|`HA~^!D zzjYj6-=_Oq4yBL}{{U~nLkz8;KB-SP$Jk?Ah7D6nk2e|WIm~cIr5?yKP-flS-!^-W zj!FEBA0jMmMr}6-GHNlznG!F*bH8nFA2rA{Pf|_%9l*koX8N4@)fN26=8b8TiXW7F z9(r8yuYy0DOqtqzabapJTjT-CO27aOi)Cs8m;!r(4Rk8Bur=O0J6iUO?6K=baQd{w zIWc7TZ%51)`g+f6Vnl7{x4;&Dd*4;2{v2tOp_3mkD-1EB6}JMU_bB)Mx)b2<7HWDd z&|rA4NHOe=)^uIsN;J}|00HBc2a(C`$6DNQ!JQOYSkC@Ln`BAi8mcm z_V0Z;h5Dsz7yx~{j-Gu5N|Xg@CMVTm7}4YEu!%9eyv1M5>)SG)vv>W7BdGDB%+nWGdNZ|GCsN-nj>3@(5>J7)PzCmSVeK+?` zo_>msKD&jHFO{p|J}yjPE6Wm?*$toR9-;nY?a^(&S%c^au4&E*c$g14X#QoY40yX6 zSbh2e*ykx$H&Ho23PmNPs6J4RfBF)Bj{U3B{{XNJ_C04} zeuG8*>^aJLnE4*b>R(WML{z`O!ZD?14L=trBTva~Pfu0^qm$-BL8e#t9^R@I$ZGG? zBpQr4N#{qBtr~$Gv5NdT2<+bKc>TvpNv^@4nwifWT7G^g1!p0cOhEqtcRCHb)9qmU z0y=2Y@O0lCN%;9$Iwy!Uq^tKminqtBjypq>g${fOu8QicHizS5e0{zD0PnXteq%19k&mbYGUd}s8II|g zF4_i`5x5H-=<(Rn0rfENEjJx?3PhORk#RMQy(kAnI=&uZj;KkeN1-&IiZOATP3CvKj0FT~Q`y$`mjqgoy8DMf0!vM|Z3<*N zT~*lC4nC!iq)Q@<)oIxVHITsBkraYQYl)7 z*HB9%4@-haBn$2+UtIthB0=lXR!Gq3uj;rj;=DaB7!oBTFCqyljN9dg5fE^y4$~wq zp})j_c_Mr-;@s^fOnpCE$Db=5!p7{8mXaw8Fd@>fjkId{?kk>)U}_TMOu2Z>W6i~8 zwiZSDg0UUDAHO5}kMUNOGfM`v=Ntb3s)gOw66B=7?KT^Q4YZ$0+C}yt^n<7tKOp;d za5p}qj?OnXXeu<4JHuX93Do1mn;dxH+);<_5l10^(zWj6# z%UM7%BD`&rYR&u8YT(T&2Vu9!XXB);yfuaS1KG$ zM^9OpJfyDVP=ke(a6QjrLGF1S0L#>L^v+E~BMVs4@}!C384zSHR8t}y+e%vi2|t?t zX!q!*Hm8?~kB*r638%-6kohQ9B#;R^G9>2YMMIMb6Mzzm5Z?xXp4A-_@h0>yJ(E=8wctU-jY zCPY94&4?IfH9!(pxv!hC)U&3neF>_*Q~=pbnASpnFy!&^@_M7F<{ig+e^9E@z+{B^ zGVyF>C^{9%ZUIVQ7`~l`h}DbJ1*H&6aN6wby`?r-?`+T zO7C+Y_SrgRX*jr<(ZLRvB1+K{wloNUa(zxoqgUU({rVl9;e40Jn=1nnF+5U_COM>z zKQT$pI{%amDts>PM2 z69zLb! z`LVB>Hl6Y)APyFf>ILz4@6(6!xN{&_@?6WYPSt%rO{!~yUF*NURiyCVlPD`DlMJ@Q z@g64y4`RUnYp;90dhFm3ZhQ)}OL~Q$N1vtxH<75sil*eJVMOj;%sBY{I{IBx86CmZ zmOaR0aA%#-oj3Tut!u#$jMfW_LyXa(o7}3{zKAQqI z({5yGJ-OPX8$Sa6I=61ewC8MiPvk4+0NABmW|Z7<=0OjLs#`tZ<}4QYud%uv6(bKzGPW!j>_wniA-YaaJG&kLq4QroSA#^t)^PH& zTMJL$jy)pF+=&b@m}JManXqULo&?52xH552cld;@cEQU43$-NV(Y5MO^D6q=IKVr+!df3 zyBgs9*SAyQXe*bGx(sY+pJJ?mPSpdjQ_c1V+uUE>w@|~xf){5i+^-X?&T=#K&0R91 z<+pjP+!_|!xgEQnmNoAhoj-K=`fjC_7&RexXgKajakzpH&&lcNcyXXu_D2y}2qmGG zf{*bVJ-DvBZ71l9c`qc<1_7Qe#0wlBYUAhreFL+?0hW66P%A^GC1;r5#$9LXaqzJ- zFflM7qmPNF$L9jOKni6f8~0=BB!k7CuVViI5r(3%ol_Guyok%@n1Cz^Hb~uSOusgh_YfAeB>09oVT`*k_g^x#@%)O6T49$Hy|Kj%l=qOIZ8e^od%Ie1i$ zxIA(Cck9ORtP%o|!4XFQ3SFXw^T%2r$)TV=$zJN`OvH~;xv=vwa>IenJfW14@5R~U zt63fy)1rSnRFSdIni$9%%WLPg8$5O&y>v2v3E>d&%Z-l+V4%D)mSJbG_6MJPAFoG7 zRM?9YT23w`B}%fq<%m@aRkU(R_#e6U=^C$dzQ+^c`##FR4TT8B@Fs@|c{H31Xi`)q znnc`Np4$&^a&PU?Z{)gcFA`$o;9{6SXNo*@Z&x8m8%ZSD?br^w$J+^6GqZB?Sdst> zjL|<(80sBbuuG9jg);qWBs}6l#t=#WMxjFCCSI5Dv?26mu34X3qWuJ{0^taTxLkyQ1eJo zL!vUIj>G`BWbNmDf)8Qap16xgXc$lz_m>5lLOI8K!Su`%V&8qeg3*91beJplcl5LD}kk-cK4ig#m3{?|_5~f6c zbc_;DB=;k200!a0ivzhmPo?Na7%-%D`bS7u$rQfndw?GbTH46Iea}4-!O{MY0}Z@I zslG%wsAI)4#r0V-bNOM64eTs%ctrz~@6$G$kC>6ZMr=Pv5h1*}m1ms$ZfdkrM{uFO zH+AQ$eR`E1?Ka=iZOeAeG=%eTNBxQeqWFI?H0&duxWz(wZ#zZhAR>a5C%F_jquBoD zBGJ$V`njDPum{S0i6Hh+2;NO|K#y*Sd1^x~zTy-{>@B$V9mltBIKHpx*hea1B-nGL zYOGdgkyS%kZGe7a4%@%5>jC)eMlkDP$D`#5#!+K*2qrFz=d_toY2^fN&V{4(s44*| z>iop+r2F%BdS$`Vv9xS|A~5eSXv307BX2x#0U(=Sa%+wUD->FOD8ji}wbF*FtjqR|(V_Jq|Id$bp2ecO+=Rl#gF#8#f9Zf(8AnPK%!68YHIM z3=&Ku1o^o!jG0k<=O_VUzFkt1;*H+*uh5I?zAG$JEbRnX`yrDh#8&%4tFQzCw##G+ zs~*R-^cN3M)iX&{%OYiuVy+Y;Y9Jti<~8uApU}~>(d-;-j5u#llja2QM zU!e5BCR}uBm@_z)nC>TPt*8Ps+?&37BasTjfiZ?d0vJ<#(jnXU%r_}FYeB5=M;FH( zb)yH%lTpYx98P(TH3<*xQBj~yaf4U>#<)gw=sVxP#JpjZ$-;w89} zE$hHmP)(^LaWzM=vD7e?nsTc+4x5NejCHj2nra3F+ zt7CwaOl1Un{kjE?|aw%2yTTm_8i*v{HUqlE?KJlJb zmEsL2RMT{<_QuSLSp-=Ta%6acI}CtY1_h8f{YV48OPk`1{T6tl%Wor3WN7437zr?9 z!OLBU+K3~%2Iqh)ty9F_6v^=CiN>#^%Y{BBp(mG-gk|!`GF!y#2JMtf6+3pfDnOum zP4aNHTzGLc7^6&`%+Lp5Qc`T4j5}@=b{>1x*Iz{XeJVJND_u?3k65_e9{n}=f5sR( z&T3CSG#aAiDf6GpSY=cW0bwwr3Xaxj`v6V#lj|SD%($jZj}ALQJa4^mx3XLJ1QA78 ze61b_L$UlqeCd;4T#Xk{nllWUK!Bv|Sq&~>b=1)b+#rj`Sl6tSUVBwgS#*xFA#**#W+KgAfju6`$o zFfem*V?en17@T9|GP8PSVi}@pQ$mg{VehQbyw^+|RG!R-@wC ze3Se-&Yh*Oj~Hh7dwT%OJR9+ytaE07_UD7gKOGj!@n$4Avy9wk2^0^qY*|mN5BNa6 zx6KXS{e|?ugRQ2Z^JYOJ=c^;QnYSc!15uK~#^R@nZb9yAsB`oj9al(wD5%AZsSLft zNbw+N9@k-9cN`9Ho{Vt4sFw@IqDO(7$CrW#tCYsX{{WMgvzb>HCNmW3BUF)qUJDhq zuSu#rAC8SAjC|Sf^3GDE#UzD@3al2JzkXG?zCX*P$zaRXad3X2q?a=q7_nO>0<75w zVF@Fz46?CaXl*Cs+DN?kvZF`EcUoj*2jJOl&;*x{lfKc7-mbq~mCKb3Tg(b|w*(=6nU*;{7dgD<0meDhT9`#2%OP zjuiRMbol=O`lA3;$I8c=NOB{x-kr!t9gfykP&@E?XT$Ls#+oCm>DZYlyY5#4Hd0s; zK|FG3pHRP!hvfKY15u6T(HT6%uP+905^aRlBOVO{?f!i#{{W^JnJ&Kl{Qf~#6@a@( zU2su&bH+X)i6X_zi8Vl^vT98tLw=$*OoNkqNDhFTqC*4IzL~E>s^Q5pLpCIFSDLvc z2a;$VtOIUF=dlC(S6R1+wAs@q0xbN0r^>^9k^$@bh?SWX9o!NZZ7}Rd6dJl1nQfgA zidiVe%J|a;D=b6++%O)oLbg8ySh3%r(!$ql$-d4zt_k&mj%&8tdfc}dr&nExBdep` zqk&&NxFepGqkTSklTJE#ibEN6*rREwE4Z%x?~DC<1EFe|v11&({8Yxvnk7uApr33b zX&}5{j@QpNf3+- zhQGQ?FACUZPJv9dgm7nFz1K9gtF$nFPPEWl!E zFp70S2ZB}AsXX_ab;d8!>3DRwZ4H&AmI4@__q&_mU+eMh((0=4%3m4grU!gu%UUCX z3Ge&%ueV+^@s9suC-F^G+=)(htW28IHSGTDeDWlKF`lwZ> z^4YC7nLtDwk#)!fpO1d0#(bDyVT~f@0lm^EQyY8I@AWDDz#Y4FMiC@v%jL2Gz$OI* zitT-Kk&=-Q#CAqL#yU0j}Ns}aoLAx9nkg5`(8A0cBf@sk+R994` z%*)8hU#MNvE;~WJl%l7yf>iqj01#;3ZimN}49q;LU;*_%q#x689R0iX8qbRw5VQ~y z2vxp)`(1O;okERExX)c%MR8H$!5WKElQ6`i>KIC)W@c_wR_jGKPRR5vSt>L%IY3N+_?20k4Uf6@6~v8lrpwkVMUr;f;`ELY)3td z4oB`ft7y`oBo4evobGu=W!JRdN?|PdNBVxB9I(H$5%1L()nu0=(;&c2ybPDND|LH+ zUWmbw1QIBpMxF`hTXP(i#YY@6UC=ys=|^6}#E(%8q2gx1s;BDyrZsL!;2>Zd=I`8( zzgBHvPF*@6|6Cc>e%G(X>eCYLfq{+i*_yLke+z6rTwIG4mk^1$5EvnfgyCY(eqK{4Uv2{ou2l5g~ zW`F_1WFx91*D;^vg=o zb)9rzVxr|rB6@wQj5kO_8ykQ>6bEko`k~^jM<*6+OzB9KaZ)yAlgn0xh-O4_@;tr? z7C&*)xA7-g!_3rS$I_=b%HjizzYELZwdSG&Y1}BF`Sn`u6Y9oPiu#;9O;Bu~Jx0KbYnI zo<0Z%k5EuSzxwpM8%Fw6>*X!BKyNkX+hs#FbMmYRuH|aD9W2)6aYwG==72b#TLWN*KAl-0BC*zTQy04WCnXqX7U;%^=6%)^Q#M7Wo<)Hjf9dPJ-owq zYK4+-@6jzwNs~!zat1^55~OX4(cH2|T}kAiYmemb2X}5drz{UQh_kUWPnkK)c%7n6 z*1@QOM~>gOMSM}G!HK6~%@z)#7(tCW%KBL%j5fj~Hd=`H-YjxB9Rjkge zS>bDg-=2kQ?TeK2Wng12CN@UdBFBiDjYLP(ySWHSJR2)y5^BqKiHdPDXP?TG%93ds zD`?9bB}Ze$>|tDU$3&#f>6(s)*=?p|lMG7D9y||@3$%~0kLn|JfE&Ml4W4>k*E~%g zJP|&d9&S!1Wws_vY2`(bH&OE4fEUOGl#- zXg-oPl3C;2z!g>-NMfW~hwR<>rL7}P)U}w-q$UvQ`0=hA$jT#%1!aFNRjHe66eH5T z$-5WRrd|ev;e9cFtLkIba5FNovNG}aO1ZGCa(O{OEF&O-s7W2cB|+jVVoetIZ8yJ$ z?Wap=yg-FvMWxw|^zlt`_@R)9ZuAif&_ojy*^ zuA#}+C7)9=V-q~N3+9QKd4(Hu0beLARhuO37kypuSWJy$BQH{SlL`&5wVmK(W|3Aj za1_xCBUn@3hh^)GTzNAxKA%rUg`|-qC8K@Cj?sGs1s{L6w?up?;hc>!X!Ejlq|eP# zj|ybwG;z#SAxJhGJA>{Fdxakz&yIU&fqiz)&bqQL9l5~}iFlo-(bdtXkmZ(G+a(pB zdU1O}t*f-v{QRCqbdkq4blF<0v&)Y>3?h;i4K&PDnCXpD@%cp)-oUG?7Di^ZtZF;5 z#$34!%_QZRM5FSB1;+PKq=f^&Bo0qS(^}KC44ES`zFhD(mnO<}+%CwW*zhcygS6@8@%<_}g@lIPM-G*f3>a;akzqyWswO)jW#_r#uIubRPgFGz73o@HIT5CI z&E8X~F~rTgmka$$IHF0jXPyaD@h6OPvvQ_|4(X<1%pg0B8}x3n6m!^qohZuEZu9j| zQr{5nHpj5seTVt`Q0Y8J)Pp6ohMRUKDPaq)@`~zuytx=&X4S`vX$){iSdu{{ixPPv z&Hc%<&2>OzL5qhH3vouxfqtgto7h=AcjKXR70T2K;y7IhsRd*p%Bb~<!t z$Q(s}l5dLuS^X;d#1$P;`s%cD1~p#6&^4WTiN%GZfThPIs?n<`Byf9?!RL|3d+SKh z{0FD#u*nbB9ZO%3s1m}cW5ow)B`(eF{<1h6fC&euOqj5=jR@q;G_dLupj=ZJ2wqS@ zL}|iP*58*ERxkgDCDuA1(U};U9WTCj_XFB0ZVAMoXyEkdJeUfFVkaVENhjK z2#G{s%{<505C-DhgRl=s7hd6lPY;7B@od_x#_dR~Xk-aBECK@!jvU*JAF#GVwB?)%;6=rLh>eapYe%uLPja>|1E&f7$RkEJ%T+I02ihfT~5{H(xZNuQ9}nvO@G=Q#78HXdVt!lJ2tBadJxaoeIg zUV)LT{B0>@8QQc5-5Do$4 zoBQ7-bMAQ5$1Irta zIg|aPP@aLHDuL{)_P^HpS=4-GovzI;H-q2_hNh&{XBHTLP*8ZUx&5oJwQMOoNturM zS#dUn6+B1@yoayO?Z6~`y(`#Rv(@|zJiS^N@$eCFbm#~NAgN$G@PpmCKd0NR4*SMR zV=H)SemUxRC5Bd<&$;v;JhVZvaAkbg$HCvI>ltG5b0u$9--|pd4~he~>DG(k%>guI z0ypzA3i)p~)3PvmAxFupB>Z~-2VP_2;AmLPsU%pCaAcLv=_YP#fGy9$j^A#$lU&qt zN7Cp}oh1yQdErB4N`t+I^d+{>Lb)8A^F|n|8LetFhF)}SwXZnqv3-BmW1G(f^L+k*OZc65z zjaKqC2Yf>EZ<{vaj~)P^`HaVsMcFE$i6Bth$?E2hfMwO?pHt0ApwqIYXz>)Y6_k^- zllfRG^IpV{etH9>Wi~#eD8mp>sZSV5C6$R7$8hXVb8Eu;lWo%`ndRyA4je*bEV446 zFf+5WG34@G_p&}cud2P7bkwdRC`<=ZTr3SzG>mzfl_N_M9nuK)qN_K!{KO6b+<38l zT=2h$3CEuYBfQoz-jo>aNo}?)f=E34Q0R6uZHmq zaWpv60Fpp$zdUO%lq41Ejnycr_5oj>J-PtH(y2ouhNgUD_2q75ZC8UJ=p({W9}Q|U z;_F&=S(s&RfZ%3h81H#iV3I3)7DkWKd;Ii!S%ASK$fU^>WhAlP;s7td{0HCTthWua zadj+lsLI&64y=V^A#PYpgdh&=M+EQ>wRY=U)fzGUuPi?NO+h@qM+n7lo_iku0Afh! z5B~s?V_)qZzif56BKVU7>M-+X%M)d$K2l;PI!eJyG)NVjXybK&EQ{i-bVtLwPW(>| z#-W)s=X}Y0xoA5~vN;TP@X_zu0X9o>bUL*TW==Vcp~}R^h9+0a84Ge8aj|_p$~NLD z`+~GPn>GBIhAtjPo12ybu1fdZ8xw=%}o)xlzGfI1E#t~5X!H204*N@N0f zqdI<2o#T%o)>aOMTobyO*FO9(AfJX_IqH_Zfh5c|T_MWl`DEJ>Jr&n zer^j9Duxn6e@OG+=*FAaFe@ z4+n$DuB>Rz+Jt%d$spKrOqh+g@-+fb5AffqenSyANk7!DV*U@>hZ?m108EohB7`W)TW}_o$sLEX$WQFwZkRGLj!R@h=0LI! zM2anW=Klat!v6qc@_G%J{{U4oNh0}j8;cq3 zcQ{m(6HT-pN6!TR0NwOAO4RiP)8xX`NFhW)QP=Y9-lQn12Hx-Ab>AGBa$ZuhEimNv z?nT%7{{WXkHCY!;%f`!^Gcv;^%7pQ>f`y0a!S?G$tub1h#OOzb&>G^>M~C4yXz&Kn zF^Xewvi>pZ!+QFzt=0f|c)(@zDwmW<{=$44F!=`2^mvlaGXxjaY zZ3peZ=KebOSjYO@2a_M1oF^F&?c|aDOZ|cU)OF{(OtqZTwENt8rbA|!DMj>5ti5j! zONq)wsY&E-RpBziN?>p+p5z~I zb>p6lYN7IyQH>*Gn)Bp!^`hlxzB=oR&W5f4bz``tMVF^1=(wi3!Hj-77 zc3ivUNQ7W=ZFYN6H)G`dS5{z^a=9Io!&$?Hf|IWnD{e!Nn7K{Bm) ze^z`voQ;mqk1WF(^DVY9GK&?)#uO{rkIxWlavZHkGa^qZ=WLzs(I8ZPz!1O=-rueD zT3j56qIof*0#=BGJ3|&j>0m5yY<{41Adt@-GR(>zRNEmE24F|A1F`wOnZq9OBpm&Zd^s29(-4KW*9=iM{DLXSk37^1P%VT7X zB6JaN{A_8`Fk0-Me$_&U$8LJivGSi)!ZTz*Rksl=ZyHiz;I*VC+`2xo?JA;PxSi_vtrO6eBUT z_4*3cDH@jnHt9O#c`?O@mkGzpMDm2pX(#^x2|w|DtGK^@h4}l;kNI|^JhQ$&IguxL z#@7*rX5`(P0h^ly0y}|qJi#iq)>%{wTlFhOMUUA30MD;7gnFizE|042n@`GLC=&GO zIiMbm5Kk9l*zkHCOd+NIT0%zegceo~?!7E#W5Js8Nf3uR7C{-3CIilo`bZCsXL$|a({yY`yglN0 zH8^668hV>+k0pT(9e!^7(7P+#1K*<=m_t>@gUymCH5?`_r{wS86VH}Ux;FxkW7bC4 zbHgZ;4`dlJ$O5rqq%!so&mI2&FgCvSr>Fk_3iyg_;gY(B5Z(hq7DnM1f=I5zu^`sd z&u)QIo0)Op*IzV%E)aO+IO`l)XueY+3+F8un6icnNF@r8Iqs!>xII1T`jlQGjd69B z7`mwn7F2KkyP@iC)EE;)ee7{(su}t~&5|8Q9x11uW97{ZOsgZRDF6U{Eb2=BYTOhH z=q{6{Wo1ew$D1xFOUk5(-B?Kyh9#|m4m*$!q+fB+>pGQsf8;RXx2|3&wDUCgM1q*L z-womF?JOF!DDSj+IkD16fEx%L{{UAvU(^Y!qtYg$pz9h2GfgWEYXUkVOla6-!5?z_ zMebD`kU94r{XApjJ{As~@y#x;gO{->ad#w}lbZs&09$ze#MMEO;z%^PaE4TqeJjmR zJdl{e0lh(HYT7r%-oD<0WOpi2t5%t{!Yi9P1)k+;x_5|Sk3M!W*%<_qH6 z^0)q306y1!4U@wfj+t?U8kvu4F31i(Lnz!%TiSonHow}iTmB`PLdB?r@xc?_)9Qu(lW0NCqI zn3{Tn;DjVt6^Y5E9C@a1B6%YUR#{_JTe%g13e;43dwy&Ey1P0IZBH9c!vcEFhA}kK zAwkSzb1)Wz*z!*to_gAIJOP8M!n;~0U<1Y(gA{%ZtEsg<{2zXTf8c5K+_~~#$9bo+ zuHJJOB>VH+@!a##&1+7Ia~+`s!PIl~Jt_crj2ZH0t zPb&p72eQX%U5|fFcKwgPOFoSXvz%)_zu!@4ZD+Sc!u~lJx${#oJLLfBK<=QY^ATi)tM-y_w6fpeSs#wQX z)Z$p-gDF65l1Yz_Wi%|ErNw&z-uWDK-KOaIS{4CKBO3KoS($P&rSm;Z6Oc;UvDi2S z0Y|?e$BpA9FfZ3U*(+g>nA_x2XY2=RqkR#B#TYZRkBjGINf`##H3Q$B_g#VS()Fm* zb70tQ-QtT*p=q_s_ajYhVcSsF;l$69I3kZ6Gd!?0nAzPF(W?{*si$I{ za}7z%%F4-&WlyYg+C47qAexRY0_a#ly z?0;^D;bCOFZ!EdfWNwJH&5|X4IG{~1JpNH#hqpZ}4IDVhP9vW_XpVELUCB!eN(3y~ z__5{WJ9*)J=4+4jN{km_{@RJ4{Y2lO&vPb616`}z>MV7fLDNX&a^yruJ z_);$~BXcN|)L1em@+@0ddOx?l^;&-uX>iUWZATegD-}dWaeG*wQ2e$D7I*}oo~zqF zv4&rit_%&kkt_k2kwnq%3bMfb$f!KErgKB`pH9|=vh6_f2BS*nfM^hF+>ZS==vqYSED~px zmFF=D6;sP74VH2&@&~YLjTcyq)0IFCrBcP9jAP7Ra$0@PV2GUdbpRj>I2K+k6dE-BSXN{GI5SJPN|(9 zQu?HS!br`rVpo6*9@bAkHhO-UreWavbB$v6Jrz>o$!Y6Fm0)P{WMx8-L1n^un}+S` z2q88V1Od0bl5UOjZ+cJg^E*$7OOdBVjFZAd9&7B9W}qu!_3^wC2~lI7I(ERxg9|Q6 zG~)&|ODvJZkU%lu5qf=0z?PYTLIYS^E!($5lT*alnR!`A%`Xn}F$~PLOI7>OAAYX- z#DW@Nb;$~3-syW@@WvjQjG1s{<)rXFGh)WF(nTUiwWJEYoPaEYN*9ao($*FvQaOey zNXgvbQmXoZQcHKUXTMEao~pUAgWeKx->CdfN&{r)2A<*#^`C%^vb8sCYqprpg2yhO?iGR(DdSC6Rh$l zK2AFBR&>2A5OrHV$@G2M>24i$rP15xxhAdnSJ~*yocQPL_w(XHNkdc8^#Ma zEy&#MZQYBGemiu_76j4bCK<)XkMOyTHwp}U5E+R*?{NpP`0BP#@ee@LuwEE798^U{ z<{0*>^Xc3DB+>8t^NgRx0<1QEFQ>K#U=rM{dz zkwe?0qEO*wScfUFBYbiRLmZMkWYGh@&};5U;{AtTMAByz^EFJFRFfLSCR}h$59nRS zsE_aM*OBSjnJiaI`hy5GO!zJ%ji^_$gU1_*Cy`yc3#)$%^^H$5Y?<;ju^fkU1G+wY zdWci(0J|oD>#5VEUEgGLN~#mduT({c};AC{yXseHaR(BQBtD1rHFqBIe0p520lJ6P|qs9S&^n8wuU8s zY|$M1*X}~(_%lq_&Z!33Boe$LWW$*clQe5c;IFA#i2THc>Xw<|eM3pe$kM0!hQoZ3 zlMYKte;xk-s5v{f$TqD5xKZP|9S);tRuT*!o+ykjrgW8|;rNtgMOd;iLI@sM-9#ET zdwseUs%d!ol*=ZcBE>R_WQcAJeD)o?9^XAjq#O(ve19VMms?lakuOU9Ce!DX}SVr5aD&7>Y542kLj`_w~T_Kijcr}Ruq3iIri_+ zJuge^(?3#6)5A&`?yNFJ3W(O@_{kyl#AR-RfKap%U0cJ3o`A8%K<`M%xy zM%J{vmP3?MqAZH(YQ@1F)1F**An@FK_tK+Lm0OYaB_{fArgJek;p^D>ABT|dgF2{Z zOp$w5texG6uX_OXVR6RaHYGS~y@Y#PcEZIGNybd0AwI#^RI3 zA>mzLYYPMr03wC;reh{1K**8}thT~Xhj=7ev+aC#J-$yswJjxcBUtkxG6ioj421d* z&&cQg$3es9VagA4trhA4_ib6`yWz}vF;^=!4ootld0B8p6dp^S{hwtL4+XaHO1*bL z%7#p1BzcONsF97i3go`-eK%H51Gql?_PwJ>(D5`0A0K{97?SZMG00h2Z*eSP(d1e^K9q(2Svi}>NxY~O*$DM;moSL$JYxIq!39`fDcfnAEf5wE<$MjAXFNrI)rCdEUd~C^1V|jCe??r9B^p`Va?Mu zW!1DPmkU2dX&E^2^V6|oWxMA^!lCawCH-YP#S=ogUI`ULiUX@UmX5lTq-IBkNTdxL4jCTkgMZS)(!l)u z^U$1}G3Un&%jUGuJ2J9TmIQ+t=f42^cjJ(HdWJ&GnjM{RKz)v6OHndP-%$uD1fg9X zIRmTiVRXL)o31L)+p7`eMU%e^P(*J-AZ7q=6-+GgTpoT$w@82ZpEJW*`C4Y9=FNz# zl0!V;F7<7N_c$EB)Y;E1VAX?XG4i3ylOW?V%JGubyK@gsQ(wPfe*XXiw?ZxLrkT}P zvH)_eE~zdawXDF}ew_?)f}TzqY(obs(Y$p*h$&V2b9d1U4Q3jTNYsRe1{-3QbrrU& z$&+yR-Ac#v3I?vkIoR9f#?~=6m&M7Ar&!rRmmD8eo=)Wyd+-ID0=fs6;s)`Sr=5$N z4A_KYMG;$8cQQ;vFgr+S(N~^0ChUL*O46w264;2earln3L@W*xjp-U>dKVbY>`6H1j~u=*R9W-gB8w?ps_zGIrR}(_kVy3pa7QY+ zne&|dyi|nAHkYU}X*n4!b4KwIaY*9#qbMpLjmpCJRrF?Dye&>8%7+?A;L3^_B!S4? z2Q5GzMWL_=`S|IoE@S(H!>+#yj|OC-Fwc>Pls}oqS<&Q@uP9@S%>dah{Y%Bsn_P)f)amO&sS57aRYUlJdVyTTzO zb&(LOOSupaQV<6t;2uZEAp4%KK@4ednCNio5KIFi$WA;`V*|#~;?8k0))(?-sRP0XVcv)(K-zy^I^Zl>d1gpeH(|)}w248sI*q{m z_fkQy2>$j=VpMqKD^e3|qJbmQPw0Q??axyDGiowh{izQvDc8e3D3dlwa5Xqc&sn^^ z&?qX${{XT_&F$dWJg*(cJu^1nGC0~Lc#r=8El2ChU-b&J`t_5xD^7^T+z{#v%0MCP zGQImZ7xTgB$A`RapDRm)t)v+lFvB$OkR&%WD;p6iC>*$9wa^{`3<(5*nNpdeWPeJ{ zIfaw4%gtQONaT=YhyjS$b|tY=ytB{!r0LF1b6=cPI}Q5shvtwGlE2iE>V#pCN5mWND+RU z9g7jgpHTza?4O>FMw#=dku>QdWdLu<$f+CeLckrp`e`~=SoC>$5}`lRyZOJ@s;PxL z%0PkG@)p*Md-ev!d{F;MJigLf{IZ3pJT z1GWDEpG`)%WP|gt%P>>yY1I6;s`OqMJ_zPY_fTAMv<{%*TwJ$$o;x!^5U2Q z9E#RS9P?hUp1Wy2m}AJ9Clz5Oe8|Z>77WIPS>*R8f$`NG=Qm5MHXW*7O#E{=!O7fJ zn8$J^=*bjEHMPG{!LEh>0O9O!s~JfGY5IbxWyr)s5kb!$UG0z>{{Y+Dtp+a=X}P$n zvAp_{zEHrpW%EIy9F9A}o-3D`8oC zSw9thEhA!mT#Z?Ji%lBI=OkN_HY^AS)5Bd3J6Y|06w+}q@v?y!jf#Y@X36~o#ax$WhCz4G><07`wcL()Zpa>Pn91FAY)L&nV zhb)oLs;PBi8*p{5d1@`dA3Ydpa5UJmA1@+3#ZjkHK=YXTRhS;^LGSWOv3*`TmLz$Y z$uL7cT-=isw2M~j*Kxx3%A$x&{Nri_NB=DL#CLbf98oQOTuhMYZdd= zskH|Z$r?#4Qi699qh*Q$`;*@Ny}Bu@CLB6LX6ekrEt|x+aIC26SfK)l9qbxC_&*&8 z#c5X;6FyvBLkm zsugGL$5TeqVaXqnBFZCA=-d>F1S^g=Fg6J{_C5Nks_O?3nR8LG<3}pa?huL;Z9ud7 zkyqQEmGXax+HlLrfyQ*N9^v>H-eWO0e6byYt3401r2Eu#^~qhLpdHYiUq28ETTq~9uuWJu(VV>I4a_WZuC#9z&Pbef(chi(?kNzR{^kLUeM z?0P(H0XG4D`>T`K_ckjTv)EH*<2cIxA(VR zp-egsVw^vmNA+0PSn^KoCLqX=`EMH!U3qTKN2r21{I~iWj}k)~VVLn@cbef6Onktt zyppBSTk^9Jb_L&R>%)_am4a~cwCsk$oCPRk@`Ewp3m_6K`*CC5x|$izE==tfJUIC? zK#@qzlwG7$Brfhfw>6PgNhZ%pGYec8KKD@fFo_=Dv{o3VF_{x4AYL`U+F6j|J8 zk4=01x|Mt@764e^CM23j!}%}*59R)%p-1`qbUxDuOn2%`?vw35r9F*PqffGiEk_>| z5(h9!Fewy-0$|$XTQ!xjP~R1K*1ro~_LKb_9v& zNv0Oz?{y30-#m&J`d3sS&XYZSuL|hHP?g_#-s~fZiSEQ$6t7)matkWzoKuJqD2uhFumA&Zs^}5t z@n2e~@&zlAum~34a&C452zyy;w;$*+A+>R-CUp?)QxiowA7FKA+5l0}KCodowarF2k z3iC&FW|mS2jxENoo9qJ~I*xpwqVuJmSm$>2d2w)&s2uH6**WyxmN)KAd5W04P9^=F zM^6D^jDH2ivLeKEGA5k0P$Xt0h%L zYWcqAtk+Rs=~HTXFlA;HjxfsVBt4VV2dCQku6x~dRwk1cXfZU@iadOA{@WwOpbkAM z06e!Fwws|vi0#wV@U++gaF=nqkuKz}E}IT6;KE$F85TH0vik1mkVPkNVaV;!jel6i z(S$$DvgC>6Qv@($lG0?8$CnI!$@~8RNF=)`9b42jY2$>91Xq#xX{BSe0Uw>Jn2y8K zOx=N1w&^W&Sq`ztXR`lX$y$Ac3z>~W!RTK4QR zHsN%51M`a{kInWyL#ud(2YEl2xR!FvL$2kCe>(6$-M}FG0ZT`cI$at0SxFRHmTpdb z3X2+~&r3)`@SoIu?W~hro`X*fQmM@Qd#k#m8DVtO9B@yLab!`b#JNnePvs4}mvKnK zhTX!(gsG)B!M+5VRBa$wyoh9JSPxW6RRMBI1i0O5>+Cyy`dZSnC5tE^k%P$_Zra{h zzIgd3o=3ssrYsMm$HWqOaCu22mckTkXw<0VyLx~F`nze zc?&@@Rf&Xy;*a9jh(Ga;WSOO+CTg0d znW=p&+IA}Gxe~%(D^6$g5X!)sORxznZEtPuBW;ii>zWK2ZoiivorM-Q9N8-(Lg-X1 zhPQ<@qz%UCP#4;|1)Hat)gadJHp47=QI?H7&F--=1Ox0W0xrjK?bp$8SXvaY^xaCt zjd#xdXUN9LURu3(KC7DhiSp#SZ9(+TWmz%ffus`&Z)PNcyOKuaOBH;o*CU(iY@?^= z382eJoJfObs1_|?zpVU%7z5jP7AvaK_?+sxzHTaMa$;v;L_EA0T*-!T8ygdfB+|lD;VK@ zFXy6Vftr}(>(^5ZIy4wrpy>Fq!HFcIIT?sXA;I)){{R@G-mWXPlhnV-F`X0X)k>=$ zF+x=WYRY>60OR$c&qF@8eI{0X?H*|4GQ`qL7yDE$v7<(Sgr{0o;eaGiutyyp!j~H- z9VEodi$5J?k~s1e#DuEbCgQw;K;=yvJX!Sgd^_njLxx_qSRXJIY6ofz_2Pu!!>Z^g zlIT+=H1SOHN4R;ANYoaZ?Se1^fOx*#9-A?;n;JQCAd)PTNAG3DC|^~ZRxxX!?L&*J`d~9Q{!S|Zk?ADJAl6q7|B)*#pl7Fgh-7*1Hq;Q07d;Wip(EEeDj%At6|v2P%0XuDCV`=B3m8 zKOcxZK@KLJKh&lwnc<#1`dHznEjl`qKma9$;j9B)Eohp&Flstx7Jfvnrlw?3&muGZ zQYa0y#7PVo6$04u3WIgmI&QL(L4dmAt|neIjLWKGhTi5xW+^C)*!-lIORA<{>gtsn zQsSKXcuvDUGOWM_+_Y@%KU{+;PCU@-7!orfS;D4NTu`U2vWvbLZXJm|x&+$J9t5!A z>N~WYjDb-J(_%^3?_TI@a{58y$30)ryko2w%QF7};vpPoE7Or0IM{t?9;wM*Xp7); z(5ZinS_y|s#LCk0F%G3D#_}>iK^SxaWLn%LO~FMVB!UPY-Dfuw^$aVrJ)z^TE@USI zC|4PUy6Z&j*_pNFW=R92(Mn;GM^-^EEJFuAlel|OH$$Gm^K|VtX<`K%5uV6gXHj0% z18_T@EZy~UOz`f0r6zuERQhzWh?7AyHwDvIQr=*RvY$J_&{ zKAIrLy}mni^*muWaE=NM3qUfGV#JN{q>1$$U?P-<^J9432mC{j7<=*oy9c5;`i2LT zkYtJQnPpKahGQy9J>5uBqQ=%2WD`dH*|M}L-6l^q7DftHX2&tI4#Wo*59oSY%+ch; zP1%}oSwrqwp~&*o@xZVMzCHVnIP0F)VzS9HH$eAQ1=MB$f}(8vY*vYJwFUBnlG4o~ z0j#Ah@l-B}2jj0YHCR?dcE>5mRNJdZYMjo+c>uaMjU`3EkR?ltnWTC1V#!$YsSb%EQm{NykSp8f z`a1%~UutXcBf{MoN-{?Q^~ zE;uZZEg@!6kjTIVy}MfNhd1rW=_VL{o>(7G%Fe-Lkhi8_!2Izlw;$W7JiSjLk_^1q zlTMk6q*EdXj1&1oqYF|y0yw{O(gOvHqVbvbotu*#y%)B^@R}pR!OM(G98&-dtLxj7Aun%W*Q&&UtCo;|EcDgYyqb?Ls~ zgWKk2)G#n|%H$o*u&ioM<|^WfkVS2w$^QTwfVe=mCAaA+F)^he>#i4D2<7`YP);68YjLO7<4cDid7spt&omQA6 zG~18^PaVIFMVq9?RCG^Q_*o~3JU5Mvh2mW^Q;tN+j%CJK;|h`PDixc2g4=2W4$uMO znutASJI14-=_P`;R+*D5ZlIC6CNC!H>ok3@r@tSG!H<^~y z7u>#|Q-&Z80Ne4>fQhg(bM*ZtUppf^37WjYx*6hUl~(GQ?Bj#Y^pimizN<(OJWwExf#8>x zEQ1+CB(OOFT+=F$1=_ASWl#VD?MHvV9TLdPe9a;lA8&9^6}uvFUm%?{)2g;m9^aUESzk@7N1JeddTp*xrkS8DF20AA2s zErZXm`;OD6gBMJb7I>R1%aso7b#(!i7qKNy(`9Ss+qZs-qo9Y zjW;vJ3P7vrCF!oH0LT2u_chh1(Zo`3Wg;zF30HKWxDDn4YrR?n_9TCcsAJyvGEI*x zEs%tR9B5J6HKr~Fdu^gSn{T-47^NsOBXXf-c%~H@UQ$nE_uSw2T`c_-u=aJ;%t{)r z99faHK{Ap~JCxbM=h%P`+i~b%S@JY!rKlDR8Fx5ZS$9px{-p&y&lmUVd7yKVnqZ$9 zW`(6FlCcDx`$B>5`rUEQRSL;0a>o*q@(xzEjy+w!)2mavR93Ups#!jTN8+TBPOJh8 zBkB!b&med0eMoUuY)Pd_5;?IU`j~koT*Sy-NF#$px5uRXj;gG&yqHYv&TnGZqg;VKkjk!VSn%?YvL!PE6oZk?{8{F|zgI##3iB#3XV)OF00N z0VH!^{Qderg_hWQraLUJg&dj95o26#;L)O2k@=RJX(Gry2B4A@X;Dzc!x@+wl;S){ zqk~S0R*=jTT?F)~vm**-q1Xo?`*nLwo$>MT+8DyXVUjbmk!s+Q56Rqm6Q6qKEUWtq?A)FW8YQ7c5heq)31URU%f3vI4BT%*?&g1sJ=h$^VUZWhXJQ%4a zMnYcXRV0Q4am@mGy}tF+27{r0GSf8OM=w@SJL_?pc)XQ}jCOR5l!ol|%una+0UdLb zu3~AiJ{ANAG2@9K#*;C_HaK0ohYATLgA>ns{W@v5&_`uKvzFdg>(MIuKzHgJo3C_O z@o;q4kHv3~r{>}$+Kx6m226~V*x?ZR!m%$^9d{g)N2oR3cQ;<~GHSXeJX#J((~biL zi6oKHot>CB0y}CVxfFTif~l=|haW;yKD#bPW}!S}K#ex(q%>%eMw0lhES@?Ep!ko( z+3k@$d3cc^iHO8#FUp7pCA{0P+#0>sPq67O%9*T7#$&r+-_gG0VEUz!!vo!09u&yQ z#)eFX-I*%?0J$-QVN6u3GY}VX28cb6-=yCfct0=0xKU<5h+x!!o$;p_jNV)<6xu5j z>NUY6e0=r0ORQqz=@{QdjIAR=B$1vWI<2TafNIzqphx$s>n7AZ9i6E`G_4Zpu$dns zC1qJ>LIqCs2e|A}XNiLk&`6RRq%8vwoRV=Cv z+XKS`T#m=zs!ceUlI=>PmY@}X_WN{KGY2aMXT_TfBO@{L!qUDI+g;-3w4$s~9(%Lg%?yGNH3cXbApjRdl4`bzPa@fRDy zI<8I@frSoC`4Oe$8T{OonHtznCwgF1fxrYFI@fLmm|1;Ca{cwqAaM?^GPERL;!dE` zWMWG!xf8r7&SjZQZr098m`Nv{6MaOfXN7#-b~G$_G$cRfs#yS=yqFbm69B;OKgOK0FwRm~gAI;=2GPJAmBe zQL(!0k;>5Hf}i6Iv#Gep!HwS!8e)QJ-O>nD2idx~^C`D%9k}MYVf0;=cIZDzR#ndE z+19H$*7a7OBP$>wj0ceKaZMwWZFGA8NZ{R9HhR*3gSgRQ;cBz^jtxUj)61)Ql5T`c z8SIgQEr}%CFJL)6fwACS1H-sDqJ1(+HEl^p;%4N+Oi5>-EYVBjkO^+r-nu8^&2t;W z4<1Ie^GTOFnKALzi%Tf|FVHv^e%00JVGT3e)pT+Y>z*>x@Ua(7(coP+ zELaXl)4;VMPmsOK8v^UO0C(wVBn_3Sj5K}C8mtQ=tg>N-0FfgTut-VdazGV(k66wQ zv8hkuY3W|lAE||JesagwGMdeP{^N5(@|qN-eyYV#PUjx8b+F3cMA4aX?B2E-p6m9yaew;sYuecv)7lpIgZmLYZgX7ny8yCor;87Vc)R2KLoEo zJyy+0j;B1h`41+X$g3VQLaifmYj@9aNClJqJOkHS7O91oCR`AvbkB(#`3nQfwVfgs zSf7D+v{9@0=;C-rl5d_bscvJYuubs#uv+tTtFzagpKn7{)7C7w^i}x^Y%#Uk;NYnzyS)q{Z;OM=fC>L zsb@o>;z;e5kWV$6?(-`~38T z{velB%{cl5Qbmo5n?&WQ3j^4b{Q}7~WcK3kshVKh6vW|LW zz|doYL4=rQGL`<$qz*goehmTf{;k*!&s4)~-&61tEy+k;B~mj&kSYZN zxvuqecs)z0)S8PlZ|3>2DwQd~bB+#Zz03uYRGN+)5^t9n#vsC{Hm`7ByCGNPTXCRq`{YV}cQyLLCzUMvBz z6(ClE7luDA7!B42;#ho=)ZcJ=UdP15()>f13MxKk?8wPb3H*Xidz%4G9^BV+(<#VY zs9tG3P)MSI73pEMf&K5LGZ*Qmsg{5e?yH=dZkd(m$B~`%EKMZ-a;u5}vX4?*G2yut#~0F6M`KizzeyW- zaOEhk?=$uJS|p_-W`Ht^ZQvh+$N6?Yx6exhA#{CTA+p`0MT2xs5A+7)5IcqEp5SxS zK1f!Bd#d^^WHrvl;{O1+7tn2E9C|VpRG7`MBaN&Ius-!%{@pfODZGQBK_*)xR7lMX znHc#IvhJKPP(LFPMDyDF8vCEWOP(ggml|P{j{tb`6@y0_o#sjwqubOJ5!=?PIo;B( zoAo+I6JuZ`k2Eu!jCI~h6%HAr6~i{bp+T8$A$ zYjk!qB(_ycvt1(OYA}eg^Ng`H84Q&tU@Q_pVnP1ns+zn}XGimvXoHgZcvA z-8o6eL>C2f!`X3Z7#fRCnNKQ_0>>ELQXmq+>Y`=2KKdYwwHyml&maB&sBOfu| zK0C!BET8HAeIRNW4kOA;d0Hc%7{@XZ%1WnnME;Bb>EjDli&r`(zl@+otU|b%3%i(d zBiss+>_e-s{*l+4$5J$^=GarTU73-&1=pZmBT~|{2-}a3lk}2ZSCKa{UHi+eTlo)?O zJfnWiU)=Pe;Xe>&OC~NhuFDo?G>ZhUDYBETg^}0YTG<=y$NXJAhCj%|+gA1O_(FI1 z-@vPjIM#8a)YHhuSz;R@^9U*e0(PYv3S<`;E zPMgZxkjWyLj!KYsge6q{s8v_#_X%jGVClQlt|+rNMRlB5@g65=eE20BNnyxMtUx#3 zul6<64p$ax~aBo`^L81wp7{nBONK9f5dUG;Vm> z2n2D@=2}17rO8BET)~(m@nzYFxhg~0CyMyv_vwcb(tI40j+<4|)iKzUwWN%l(J=$R zV;!E>ow@2U4nDC0DufYc+NCWRatADj;=tT5-AMN8XxHp&7Q1I(xbs~0W^9DNGu*On zX%mj?R!bJ0ARxa7gy*mVTc4cA+x9{hNpqGM`Wf zgS7TG2qV~o)j6ON#J-yZnit%TYxef&1WnWSA`XjmjlO||Brla5YRbyijSF^UKI$wV zuwm>EQxXx3a)vNT!LB&xx7>FfEdKxwwK+9^4M&BW9?XnM9~&M)7#?hUZIpX4P~N2+ zkV*GF9>;B_Y-bC(0+4rZB`$+sxd(&$AAXHOtoI7dt4y?#xz)6`@kR^aYLLSmK5%7h zcHGMVp+H{0OZmV&-JWW@SKO)ST9o=mrzeEGRU$mg>eKSeP?9z#fNm)9+py$(bk`@F z9Eb5406Ue}`Wxr;qabW=>GuR<)8(kZs4!j`>(&)(dbU5>JH4^ z71>Z!Zda;v*vDC~Jd&9mthh(^(AXgbeBKC{s83^QgW8aR#?1AoVbn6DE zm5yhXQFGE%K4>mK8Z+q*k}a?yNuoGoRz5N;{W1+wCy^sqWkv;E58=4>aa^e<*mga> z1@8}dqb~vC)AeVHEVh+bA1*<*9G7CM5_4Agx`g4`bcEk=bav~9P#Ijr|{{+D>3Bgn?fWSR*4l*cO;Jq1@~ zs<{Q81@|0}Zg`$A6=kxonWo`n#>CUXm1NQ2kVqi$*jf8@2SwDd+FMC+kQcb#Xv+G4 zq8x#_Pr()iayoOz#M+?e<031m7R)6^A9+x5-};A7j5RirT-ozWImD`3cZg+`8Z9z& zkEj&PVY!Ic@+c(A56uZA@brgYq%azf}4R9Z*AY-fj)*I#_b1-P4=A* zo@DtV14=A>{5Fr$V_hNF5VW3VIAl~Xnsr+s?X$URz~oo?^#r~chDp6miUPu_T1b@u zVM6^q*wN>){d&8jc*nz@C8MXwl&>G+%Z)TDBpZzaKp{`&qHKVFKzg|}xcM=(c+C{E z)@ zj8Wvrdr{q`M<91lz=AgsdqDjUO$wDBFYU@uG6w1Hf<6opx0R8R3;@RQNgU1stAfM# zt_h*q$moWfji=*e;O1nu6d0=8XP$hLu)13oPyilj71&s?FW}No3r~>%81s3Kq*+w+ zH*N!vO48Mu+wVm6S+tA|JY;3+Nfh`o1~}HpjSwW=?oqgn>+^Tp;5AFD_XFd8&HQKj z^CJLfdn#(p&(p9a$T-P_bu|V=f_#IFkwi--C zC4Bhs%Atx>8+M*tfGNS``l$T%B=~VgPEL#<#mt!8a%z#$TT_0DBq&iwfI08mp*q%P ziKJ;58i$Ls@`RbVvVA02T4EsHgn$%p3S-a=k9T1@`{CC{G25fTJmKPt|B zSDxjEmhaLXos{i`6m#ksc~Z$09C4KLEJR(FV@hjiJ5hFmz0ZDtndFp!`A;jgEqSMt zXMjDf>c7{i^nV+8V^GGH4Ra$>jLtxrM5&JppgX9#iz9WNq}70X^unLSUkZ3`Xp_R{ zPf2((yfT?tLGQLwgq9rhbbx8JPtf8ySl;+eHP zr?5W<8+Gy6F>CiC{r>CK&%xj7kgYI*T7V80PB6D3z&E<(8Xq-azd_%GC?LJut=f_oX2|z?( zj^}coc)Pn7U41rAO!GxHR%S*_u{yF#D+VgSZBhkQ4o|qUd-v-Z?W!Mg8YhgOWMFAA zyU(H}s%xn+$bBac1;#+q1ePY-J8vK<94HHX^H!j8dsj_POc^s{({nN;E@2OlphRV$ z*2E5dM4ouy4h8ffYkfJ=B+X{-XK5dFY-Noh*O`0p%<=Htmsu6zv6%V|~5P z$52RXVx5n#A9TCwxz-6sTkz-eJw)mW3rCh!mTaeSvD0qVw6nW!vE%eTS@7q9B8i|7 ztdA)Oo?|sMm0pm>&pdx~e+AbA4@R0ioSjcln>QyH%OegH5k~Az&=r_^m=H}KYL8%g zn-j#zhpjGFi>JqwS$w$6nGV>v@vhL;`#^Rho-C3o$0w#JRdqJx2aTlueXY$^p~vnj zh8Klo3FXisgGkB(#~e|qHe_x9qNE!)?_F9NbXe_=wUh$Z?AVlW{E|+{{5Ffl4ZX=-O*%Nz+pkN|m2b^B7O4Mncej=406N}GcMO~NbD6U zMYjjw5zq})q|AAjM#y*~ULj;92Jpt4aOSFj9Yr=^oJSs9xta0?W?0lK7A?skk0#0H z`0v}Q`W!R(w^7N!j}2nN#FcUKXIVj3bNSH^xgD8@0_X;=v&Bb2XgaNCVd=2uBSde* z+D?A9Wz(hBGV-+yNaC7F4o8$&v1OyM*h>V3UVcwZxZlEUAQ1W4nXQnmPU3kvXCQCYmXUPoqJ^uhbk}M10UrcYR!=$8M zY`8jJ8k&t&79~!5mIG>mbURr+A^3yF*tnSyU`E=O36L2k$Vj3_iZEGwF)g`>umX}t zu)F9+wx`5cGG*gxu<9651WB<*T(U@sWZa5dV>h`Qe?n`g3mWnZq=U5Ims~x@+Ci&%%cNOwT2FKja8ic$D1=VW9WG~LXF8(KY<5bJcpHJ8IIIyzV$Z%IGgezpM zLuxIB?O>a(dFu9+;ZGTOivcIo_3Z~+)MbHWeH&8LV4EOBz#C}g6b13bfbo1?bQfI6 zOivNX3>sskyUWCI(6C}}n2bCx=|;N|-=p3SZxU#FqiS%@*pisSZDxZ-yY2eFs*2-8OSsP{`*y3n6xF3n4eg!UY;5jzJu5nqTpgGfm2l49z+>$qhp$ z3H*(~(If=~Uw+4)n{nU3o*@7zdFTp>~BEm75B>~qpG32lm zER0K0&I4-o04)tD20J`u#O{ zvtWo~N=$OcW#eFW-(m4!-#vV>N0W~6LysOtR|SzsjFWd~a{*v;c0c9U=RXYp01!M= zpq4p!nBF0R>SY9F`BD7~FC{VG5O9AFH4i6>Q zaXj6Q^akfZxkgE`GLs`5OiN0MxNRhgARZ4M*HwLO;oj=Z?CZ8RbM#r2=>{Cs%DLg6 z8RR$-`olEhIV6GwX)(7Z(6XWDmJ|;i$0mU~Qs;e4D0KFRDov$YD5NCOBWN7*2o5=; zYt|j9VKA7<=EpH$2^oes!gUhM+=9$CR4u(8@{{UTc(XyaIgfL{c^Z+mWgWL{m zcOCi*CJSPuu;dwjo$bTz3{i*WBpzo)O(L6zmmzJYV$HmR z(aK6nvI^&K4ll7zK?L;a;<%;Ej#haHWRGElNER~Ol1=*>9GB#*w`;uW4a#fa7xCu_3*>VDR^d zMEZNf}~?a)Lm%8$tK3 z-1V1+Kf$hW)&AEH1H^uJUKI^HcC^ib@dq#0?G)IF<>$r+udQp=fA0`Ppn{0?I(4YwKM0EWMf}zOo zxO$F{o|Zv#OGJ$iqLT+ANFBo0VSfC8eY^bh&!ju zGIG0xkz9+femWgoIH>HvY9Rg;(|$shvvKjYeIv1#CYP>9}ZX*v3&Q%c@O}x!a->G0=ri{cHnc;>}v*@9Jv{&GBiy}GMUc8{Izfp z$Opo(M*Y36`tLU~O)h9La~O%D!iHRTRVU1s9$>D9zGGs_-H2h*blO_>jxc_Fbxb^F z9d%^TBcB{ery~)VvVXJgSxRb9Bk;l5oRkq5w)5E$rsz$kL~f) zGvz@vc+z9-c~&NP7*lzu8FrdK)D#Xq!2N1EQ28mRz@jN0IiQR?lN_9Rr4PfB%~w_% zfn%pCz9et-Bjqd_2vYL7PUXpeFme{d7X?ADy=^~mI+-#?sY&jlR|mk79qkGNGZa zg;OXih?t|r8=)1$3bVqF-v0c1_v#^vxe>su5UZWwcJ)ypug89hW8*BEo)WZqEX-vy zK+(F$5fjn@+I>V86fTO6dA_K+C^->FC)VSvyCRS+85CFtgI9OkiX-CsU{((>-)NrSbsF^s?qV-qhoL$R(a;Pek1 zM>-hu+())MS#E^2M!3IG;B))@^;QgN7B*@3ASw;*G&nXnt00ff+v55YsnMuQT-ZD` zL%VJYc264M%>j6mA~|4Tx+9Ea=aJ6V6n^9NuDpL2V>B*P7&ouh4nqz{eh3GTza1)= z$le5$po#&&C5Sc{6YXF3+pl0))!@`M62PWVmmvOEa@^N?q1Xe-_P=h7+BDkPZ(ggjI$)+r#A`gI zwV;9~P3R~U-bqnl8~6M1XWyvii|O#-)N*w!A*Q(sC6$)sC%OV_*Ujw#tGOI>A~{)! z`eF=9te`0$p&#D*hikync~N-{EvbF0X8X~iK|gMQ>Q$gahnCJ4*N^t3J%VH(Khh&6 zMwb%-l_CI?rI7(3l`JRBT&-6BX9imJFVq?{2IiJOByw%!~C|aclaTE__+M#<;?d{h? z#k!uQwXpO_ass-$2%wOz)BPiA(*9s?@7AX#J`Q$S5@hdoV4l1j)4&6pMP$w*0H2tuRgaf?J0lJX2VhOL&+QCX%b)%&h6$K z1o8eVAc8&Yb;foMW`AYHUSGZ!qIgY z@LLKQrZ~b%j$Gx(r!0)GFB;;OY^VI&@?|cH3E>O904vx6eaQJErfL`(QU!YlxLypvwq)?^gwjeUo<;+WKO^{u+hx z4xz00gAgtbJcXl*aT*^rmexsPeXu9T@Hp*J+P7PwQ|KB5Z7j3u zd0AP0YP;;n*rl4UV=@43eMAd1v`Fau7`Sm@Y518soEcarCP$a)<7rGWrTJtkvfkph zNhE@Lt%0FtODxZi6fi7fl2)CF4ZyxTk?-50c={&Hgj|PFBgPylWl|RDxIV7_^~H+l zbt-pnRL%Ep_utp)3(c1sQOl2ZoeHcZ$s@}j)U>sZPq-)*b(SIJul$ty8f|`6xv(^6Aeb!)HPzzndBq`qBrtAuiIt{Dp z^XeL+;UqblzO?w_M8Z(hNXcY*ylqIu@wn2^?oU{h+!)JSkH1s9b)R@8)>JSwT@Oi( zmn$PX#Q7zdNw|GBIRx1oR9h(^P&Pf!+=SjBnW9{1nJ{re?M!Sa#B1E}Yx{oPO_`#m zj$y*_3uMo$wMt2CT~#eo4Mv%$6Z+4)XuO(2KRYgqg|#^7ShNG7V;<*2`2kh^x=Ww%zP-dG@bm9GHsZ%z~(s- z6u4_)%ZK!}5%0(qeG!Wdv2!6f7{y_ccbOTFvaaO}LD-}y0Y#Q8c0Kdz{Y*8dvu>Mw zJvVUHAsLu(47kr-dmvgqhnBuvzed_lM3QcWkbku7{{R3&X&3VoBb6YY0lrTRh)z7Q z>G@LRG?S{Fk&6Lkm;i1$8GOJ>sIPPVJPYb&$kTYjLM6!Z*hv!3PncCguyzz1hva`? zDD~C`BwBWzsk>~)GZ}N5Q6PdfCKOd9o(hDGM$&g6C*<{r`i{hc>h>N&JkRIwooLDq zRY8n+_@@^WBk^I873UIp=Np0-Y3y85s9OYk-(x1Ht8UK7!H)(rtDpC?WZp!0ILe^8 znRd{WmQ9duv)#guqSW$rJdHX%Bf;6Scz+&P)an}SakO)?y*s8VJrv;jrDakHqy+QP zd|WJST{SQ?{rEa&Fbju_(J@yBj`zM@$pr5<-LK!Q_tvXjxoOxNTEvZ;?ZV{UNCBqz zE9Gdgq?SB){8=!B^5vD^xa;kU>W-^NN2!AYb%Zj4> zpHDu;iJ{POhvvrd{X8y#gsK%bu#tZ&3N)p73bsI?O`eGA8qm@T<7%?o=Vh!=2;wf! zy*$Qe+CM6)uw%gVt@k|@lqliOw_MU)swa|QNQ_H6B$7}sV&t>5kib~6{bXMxD6UB9 z+_0ik3lknDB()?l#JunO00+6QP3|>AGW9__wkDp@$npgf)k#X^(dmpnk<<&#v34pX=%3}@-d(Xr_u$F=^c+w3RMW52d`amR?j8^-++rZO4u@g`ZW0{!$0Kd2M7=ghej^07wa0T6R2#K`) z6(f@y9DPixuCepJy|-E5i?ek{xv{_vTU5x-waS<(v`#jn@kOeM;=wdN1QLI!8mcr8w@o&i zDG567LCoiv3Z$6_C18OFDYOUMN~>}p9QID$^e+96N3nDnXUB?DBSO+DGx~NvzTiQ= zeZf7?wGq)RD@IIMW5~})mmy9w3ZhLI&;vPZuaVjiVJToNw%BFf*m zz24;&{ESCtwot+{LV?H+Zar0gi{qb=J9V9jb-;^_WocoX0N%$$nW*OCvPxQ9O_4Ze z9$;0CizeIu00o*N{{T0)+(uMbjIzY*6j`dW6_dznSrq^%=Xa&3ib8LjvN-99Wo&qw z29<6z=fMZ|c5JD4Yur@2P-DLbM(uzXN z{Ao0}xwyg=R>#ehqvR^6-!jX41>F*~Y*01_w@Uchv*1evUUYewOPcvJV`au9-mHok zgZb9hyAlV-PG7{*@OVmTu=0`hH_M7h3ghimoja>7w$uPo3VrNZzOo%RQ-j2sa^}Sp z(c#LkOBno2S=AQQ8@2)0zi^};dioF2GFHI`xLi;7;iUf8mB%o*5L^#kT~FeV3}WVF zLoPh-t&W7@KJx1ovliOmgWrSd?!Ee6%hWZE4?iLGB$iUHcV^=?w4@&FI6H`6ak{e#eqyE;%yuF!N)Z2R9ui{0AHEAiPMf zKcsIBv4JDvto5+g(t8Bi-FolPrDg0p!l$A5jy*-BLn`HNon4d-lG$r^Do;N&2qw=R zSzIhUiR8$|PvzQ_aR3V1N(~*v5kY{fqsPzQgx(+1wPCp8$1yCc4n`9OM}5E>P<=nD zk}u=fbh>V{1_HJYRC>M*o5adKVE}=+DXq(V^>QjTutsR>pZ@^W!Bk{%kYleeWu;OvnkGAxXCNViC?s}t{HK1#;MyIp+sB-(B!UOr56M;!4>7SSrM`dg2WPy&Y@ zmh1)BN;)>L9xM{BRC!uPTA5cPY=%V1SI3YNrFpIZJ@{_^{XF61Bw5jE_?gb% zR9zZqp_zF;OmQhCN{Go*KvAYrNFp^d6SR7d4Q4;LHTO8~{=*rZ2B8exPt2NQ=4+6oh$uWb(I2f5R zqJ2P{10_+xKqGPr`H}FX0#c93Jy?GPM$*o|__xE0Br`FVDRLx=O_qIrv;cy5?mu3d z55qVf@$x?i9i2h5*Y=Wg^rwy$jO0NyStWdom0>e0g4Dc_NHuq0`(IG~JgNra8c4!2 ztqCfucCczZ5WlYO=f6$T{{RlP&8wH8#fzyF1e2v^Lp+KIAdwoeEC@f+3Fq6Tl~#rW z0e}?&0?8BkY&MhWWHzVV5y$r(F-^^QCY!TH?R-b{s#@miAwi@^E(WC@WHZYaLd^5q z`k0bIRH4I1YT($qke*2EjO?=}HhzgNjgP2*GIz*O1QC1= zkLmC(E~MG`xiFnd1z54<+jgW9V)gUx!n<-vJxP^>(zd%MP9`!T#?&Q?8KLtO!b&+s z0Pgbx6;W5kiZ#kuoPtSgz~8$1bqLgnBn3WShxJ`6NQN)`SCrD@WZ#av(+$KnouXsst&2*-@g81Wc`|AFP|K&lNE!3Qf*CfNJ5^-deO5mx>`42? z2a7W@o@B|>Jh)(zL}}H8Xya(*Y?67dJ^39a=z5k$pB{L{#KAGmD4toAx=PXo0?Jud zp}|W~MHBC3zlZtr;$dsqJ|mwO7ZL{ZaU=-wtg$d-xk3K`1E~NDKYHZkS2&C~CN{v( zk~vA}r|CMKVgTKJe@bl3)Xk1Vk(!e%3J`t<)mAi36+Ni;uYRe-_+^yGmh$74A>_x2 ziyTs~=V zvSlK=?T*QEqR76$Uo=Gy4_?FKkhroKbQ!e_pGyYELl~6-<$^!vAOdysS}StjzbV%@f(CfS1_BXym;1MPf~?|nlt zf~#{A6Tpqy6J=7&h9g8%F+@0#qM=NHj#ZrJQ#S6Un@9yoR2SXP)F(V zJKsUFhPc@*vZs`a;NC-sTv_Z9iDUZLRB`m5H#MbV+0sU?6X@)10D7&;fJJVzUj6!Z zt|EmiIpTLnL2DfC0y&AD217>pOd1xZS&X8W-iNA)BCWGq=Zg7*ZU#@7ut__e7*>pc#pF@O$7&h-RVild}`hjC~D1L*A>bLTOb1}w7 zY*Avy)ihCL4ng1$Q5=R84N$u8(*{OXBQWyg$7f{Db0hO!^7hK&}LU^J`1>O>W9teXu6CHS>Pm=NC%NAVG z#IhnJLuw^#R$ddk76jQ8efmK04za0Eqvm7d&8K8wWEfeYk{KGrZo+{LxP=Ww0b~)+ zMD@J9JwHr+LnkUNODE}0M6rp9rJz|@*-(BIS^W<|F+4>Ey{0UfdR{IgqxnK6nM}n? z(_CPN0PPjJuWvmAv%p^PycE2jpiS*r&7@mzJ~+*_JjAT7FcaCK4`B+~U+aUfIW zi9Z0|;UbZ1wzy-+99X{HT(Jy!4I6@{BxGMK3pJ7sw#c8|*Ky+|qm^px*I zjt4>^D!9|T#$C)zvHA)1hF(Px$o}80^$vNd-gcy`Wess?*byk<#*azQu=2=-(jpO6 z)Qop!A-7l-v{r~W-uj`E?~^c<+5qnmZOUtTrek0G{CDbjv5dHR@xrdw14yhJ-Iz|t_l?y2I!^^2-T*K4yZsYfa~E7%&b-=F#QN+x6?Vw(gNE^IO5M=Ut<{YE?t#U@Y) zqBsD1Zmv&oR=OdhNO3itHg{E(BF|MeMQk!tU$_NakBTPx`y)k~ZwTjV(c|O&G;_fW zl9YcoCUGSwU<#0XkWKKUaeWJEcBFG+l|bQ`s)K4bZ5R73{`~jq^9f=k1;Zg(CdLi9 zAeG`!s4Hr{T^=mZ=&qqWSQ@{dG!ZA$W=AVR0F(i`h~~F^^FVYs?}H|0Unsh}5J0tJ z2w;Ct{vCa(6Z&4$+M6hRxw0PkbrDRzdnJlfx$i6)!!Ve!Ony$XX)$%a>L#xFmn~$0` z3x<4IVpiKMiLgl$sR3Tt)p1Q#T~P4k!xT5wgXD>oL3qTQHaeD}^R>-`$M4Y^NOCCy zD%4=hTz?KO1Sry&ws}+2XsN!gOIcj8_d2qV`AA%@fg}w0x1;m6JX%;$=nF8iGL6ENc5bYJ?F(- zoLpR}C&n@Z6YLv!HGhYF$f8=$1FuU*7;=!&aFKN^x1CpqM$cxF3F4eAQp z0vsaj8WS;BRx7u3Wbw6202J9LxE4VDIxKwe7^#vci)Jgi$1)a@k0MDumiLuV2?uc7 zz%A8VSNTj2IyA_Suy+lN0qDX(p}^U@Bd z{6&>K>`xEjxp{y2xkw55um|_={{T*#H7z~o8PH|Hk2Efl%Z|bZykZnFdnSniLV!Jw z1Eri@2}D@)0gnRYDmzN-SdzlZ1+vUXYX1EkQK);Y?u~TylomRiW_8M1!PBxcvd&(s zG}Gl|a?Zq=AD%!L@%nMrtD@;qY1qi`6mg=9jv`Ob<|F+F-}LCOhP)Ke`BUTJOH#C# zlQOF^lv3@v0sJ)zx6ik3dKatz024Hg23)wjJfp-~vt&q+ON+iZvA{=A+s6{N{f|p( zM;son+S0;|tnWLA&z!C;sfjy=^m+(eB1Mcz3~a?vd9EW02?EXjRp+_scU19)JIjrv z_&*KvHJpsEDm;-hI?jaf6)8yck_n-}2h-0((;raRbC+H5S_6|g-;bsvk^_=hZeo3I zOA;6It@h)BxRAC4`Lb!ulIpqVW_F~6>{$DG5Sk<)uT+3rpM|TOl`$XkTZahSzko5t zRf3%oNWUMCltc|T!~RTJyEQFS$h@(SGb*VMye9F%MIdh5=`00NwkcEVT8^m$MU2Bl z@X{G4e4JQ<0_3qKF3RrAYkM};zVs`moPP_%@~87zVa$frog`1ehm*@g$&iZR$Vlzz z=n6MfpAbW7*vMK_xcJVcs~B0#pXOFa_KN#ogGY&XGtnDroH^3K_#5?fB@i7ws! z`8V!B_vynoPC87|G@Em!c@ZHBp~5LbR4_Yvt=t|>3-<#1Xjphd6DwXppPCdni_AM@ zd$Pq(da=uJEb-QH!n&!-OvjL(x(UHqthn3eP)`rwoY5Xz7bhFn3P!MCv0S!3IXT-e?2Pcc*Yz?n|efB`u7?Hk4p1YJ+HT6@C%j;>Do*m zTdVH!cbLIY46?A`ssna?s;GPQqm{J5XuNA0q-!|5q4|;JL57*x*x4G0lbErw$OwQC zLo**r+4twU+6fj1pXQphP-1G|%izGpX4!#@4)~q70!x#AVBiYud$#Vah%>cWMEaYO zcCVL@TVsVin_whvKJ3Jk?c1eK6nNhoLRoQiw^{O)0<^%;j2i}z&;9-SFLs?i*AZ?X zkJp-`T3r0J?subJAn}rTesYn@XUfG`!U~PjHY0@NfIt^Q&m*^UluJHFu{4^FZ1N)H zF)xzKzDdaL5E}mW6@GfZg`!I)G1R<7uIt(yNi1*o-68g0eZ9}UdyLK04qiltdDtVU zLAEeW4`4V5zY03Z#ME<|9ah6&`RaLSbf~edBr{#5SQ)r@xU*v5`PgYAQ?fdFlP4R4 zy;-xy(X~C!?x*nXG}`W{G2?|~i+Y(wZVG{ibJz>yo;MTm&^&x;GUkXw8D%UL6brIX zZ@DJ8`}MMDdQKmKFlLuf$J2B5X$)H+khF;uZh_UEuhiSD5&<28o^PcoIqz_t2G7T@ zsw=>2ZK`hY{{V&)PRq;6k17YoF=fRTDab619B6Kpxp-}PvrPX0@Sq)atZP!sGc0p? z9(F-&g98=djw6Qo3+;9d554rCk*Vb6XB?eIMK369hQ&(($s2dNlfv=&ZmNL3Pf)|G z>G0)5x}LF*k1VksB$-&2EGvQ7{{UfMrFFi_c}Hnj-Zb6wv-*XXQMv5ZZzD|8^z4Y| zhaE9@LHLUrkm{hHNFW`mef!@W9>msyoAxG)ST}9_r0N?P0pEtB<>T052mS zOEN^-R&;rB$2v_s^3Em*cPIoAL524G#F_(v(G1L-O$SYUyr|^L5%Ut8mRXyy1K*k- zVO<%dxt-W()d=gnt~^iT{Wrt$BzVxW=U=D&Q%THU$`1^EcOu$S<+3Av2JD9tB^Xhi{57-Xf4H?j4VO|{3#=Cae0IX)L05}Kri9Sf?Mrk%AL)l60N%$Y<*fnYR zk>Jgh7@j=YB$=2>pOQcc0Ii#=4cOIwr=_t0jAmV`MudfJ2Tl4N0Uux~| z(EM`nAD#0Tc58h>cUo>qs>sQAcOwJkq3APjAgrNKSp zeahGW0PjD`rTB4#d8lw<*_DNrz9{7;l34c-Er_leRDyW~G3bgTWneUJL8zWNNfbf( z{{UXyeDX<@*qOdkMLhVp;py$(U5u_u`+=|<{{WBe)$28&iR7Z0H-y1C#ghw7&w-_c zVr58GU4dneQp(BC#gEduGoehmI$?rV4zbN7FVAFgYx`Q7{d!ewd8NmdF(Z_z%~zP3 z{|oJpJe&?bb=+O*0=KJ${AKarlXn70DbSLXa@Gq zrtkI<<$sk|eWAl**8DrJokJ36^%3PO?o~$|n9mAL6UpR$-4=M5Vg)Q+qF!%}^}+u9 zf1g;FgnUVliL72+8CeozL%wU}3`haqt75`|WZC?jbA4_x=EIoJCNqYo^{aP7+*tOp z$UflpomiH?vv$Nr3ra+dpGnnOF(rmSDny?iIfo4!u(i6NOBNl+Abt95(lfl7jttXD zFqAydw18f~$7tLJ)9K^qj(haK<6Six7;+g~ZU#cm`zW`N%mcdnZeAFE{V(a>B##S9 zO+HL%ez|hc#Uyf=&f-Yo?$4!t90C}h)rJE0hl}hzdZ5liTA6%jivvFJ-cZYA+cHtw z#E)3J7r7%M{{X~({bk-K%xE>d_;O8-e!rJ!XHz6p`^@nIa|_eG?6o)LSwz#vLEaqH%Oq7k3xIUR^07<$Qv<+|yi{q^)L(4dG&XYzOH+`0-ikh&e z;>RHLzCM6^NH<+g#g0#Ei#rvtRnEdx-5as~y=LAa@W9DAdAe&RKB%GPP}CA|01_h; z+P3af{{R&qv5d`2Cr`^c7>*lyf*cP_p?@fK`5mlL9lKQ#%8_!>H4I8bc^W_{`UxJj z`&TXdR~6P316K)95OqyEEmrbb7OUgD-FHtonx-B&iI6mow!7s}KN5l3TWGL->)wY< zei7E2R?=S=D>2(YPDP0lPzucvVpOXRNd||jrLP_7r%%=6k`k4Yi!YZN`D&6Wq9}Zj z+zy9m`lNbvshE+(CdNbc2;_q#Eyo0QUOSE<#V)yJfDxaR3@Su|gq*)zgfu&z0vwEabFL%Kg?mCWG zBF%9Z6zvtJu*h?NF;m<8ggbTpjv1l0Gcm9$p{{ZryuuYwqXj34_ zgQ!9^%h2^`HK>G(j7Z1S4bup>21y6qT~z+ZtD5ts2Z&+RAi_90F1Qi00Q7{;Qdmm7 zox6n*+uTBdPtQw7|yg5La{zkS#7(Ca)vs4hmlzfnHw>;%gSEvo0eVof$W%jP-9$%W{PHNZZ^ ziy-#)>+J11ER1}2!&X&L04dp64hg?wf7~91VrKnbE*Z~;SR>BF#*#>8^h*P}?m)}j z5o|2{Usv?3_FS>0>HvnFN`vmzWltmDllu|V^ja#@2A-qHj=eQYIF>uTq4X;<@#cso z#r|WD6Pa<>ZcJfRw2No)3E=Kf2kI<$1FY46RaI6~8Irf%@!p5u-uoZ#*XZqU0g$>& z8g4DMxjRb`Kpc+5f3H}EvEfwF@}C*dMFv!xu^D*s*#7|Xm>*(!MjrMLeveJZ!}5sI zG&-t!R$fMzl(S*^b9vH7^*E+qEJ_uDRt$JT4G_cF5Pmw^@G~Uw78_(VgCi?W$d)32 ztH@yD%a!;y$?gU4LA((QKtf1aC~jLkgYot^+<$(VygRF8X*n&Iqr|^jvLutn3AaTC z+A;1xJdbMZM`kiL;zqita5^nBB_ABLQqxE*TMqpH0Mn{!s@%rg8tqMXKlJ|qPxI-L z8Ss2cUnl*>6UJe)0a0$m?ogh_=dJFeBCdf}A&8?N>bNEt&Xz z1n?WWl{Z}aPuTVEi?w`+@}|?;HaN=$;pI3-BDpSGvUlWN8ti(9OYy4ZY0~JPAv3fF z9lIsQ-pfh3Tb;$2kU8M`yAjVqEy($AU3&AnW|($P^};Wki2>a{n=hXPfw#m?)*`t- z7w=>D`RRKpQb^t`v=ieMD{Pj^KH&cVm_Ph{h4n84%K~Q@=E0qJLp&0Rl&@+%jeejJ z(VVX%QpWntId)0?XoYHz9D8l=$8T;sbkiOl6h=eCdKsl^Il3NP6Ew{{Q93+RZu1Of zK>?P}s8JxT_9nXywM-1$9~9}?3${Fna%0(>fsrYZ3g7f{E3qM$kb8^ctYob4ZOUXzx_78_DXxnMid9^--k01&U=rK(V4$;o5XBEf)D zuDSd-%!r)71Weg*epzs`a`w*=z6v{V;E!iM-TI}b_`}6|G{z}3jYeg};%Ftrl$gow zOfQ4>YUj64z5?-fCy8)e>JNzytgK5UFR)B2^Mz*aO^u+MuWRYWq>~cZyoPBMNIcZ2nU-!!Ui5s~RkKsk46u{(JPD zsrUi0vT^?a@V22QB+;SzkE(W%e5)%e-Sb2rVfys-I@F!_2s}0*kTw*_m7+FMu1-Eu z=OiJ7c`(k>3h(~%I(7X@k@x9)Qe2md&eWxoEnQ3_DoFh0*bf0`1h^uAzI%If()Lbv zrJzj~Mz4?b%+eCMSn?{CVe-KGNxK(EkJqBGc)#i)cM|!M$~m4kXeRIdOn|HZ0P9xo z->2IXAj%vN5S;vZa|xK_ApVw$m{|%*WxG&szfkEq?xUitt)-&mO$;jr zKb#jKB9FNS>Bp;)P3~+SI%Rj#GRFM2@?47&O^Wf6$NvCig2DZE4!Dy@IjX))%byu= zo0XF-LsuNB^G9!i)t<_A0S^{j+Kz6D<9`?N@lzuk`EE&}3%Ls>PbkHTFcNo`g@VjAQRPSG0scBmlTt-3M&~ew4OawJvLRl3l%(Bc;!S&ikR_= z5yKc%2jlP6k(V~0409_4XCA)f8y>H}7suTG-D7F*G@(RyBKmhT3IP8Ag+V_*_34Kb zN?bTrMvKkJR-zPc2c8EM2kv?mTtzx|7br+Zv#HJD%?=6tmw6&{kfQvA-^ ze4|uS{{ZoZjb(JR8in1SR{~R#O~@s$gxTscRrVp(v$Km zRn;E5Seep5(WGlDDzs5pQS)bl-`EegQ{v!d%O*Y^K9Q)ws85oqgM~gfl_o=NXTMbh zj4HD;8Vg3qJzT*49Qc>SaO51VMP1c^SoG$W3~1Pq>5_R7S?F?1SNnH4)iE_|NERJ! z)Y)oN!%?SmbRp!!(=5*_BQX`civzF#cO-&Y}z&%pj-$_5`aRBcd09w_opZ~zCe zH!>F0GI3o1-B2TbVYty_-2ffhxj(l;Jad%}lFOtdQ{;)Uk>e1@O4PuS zxrw1%ZUoUMj;lutQmep?zu%_yYPg0|ZIl?dpQenNf@#?;MkwTvd6Fm{+>f3;D_^fy zQ&7=-6^R<0tUM_iA1t=eOm5D$(WTw;$Fqf!_U;mmSmMOb15 zQJP07u|aaG2?X+LxW4^pvjs|+IfwP7{{S%oChSdGmTi$D@!>*?hB4AI`${O>^+%ho z)yICDd?lKPHk128bEyD!yuV=RDH+pg08eg#_?yId znoRNk04&ajRz{S?4ib`b70VIjr5k(ZxFtsf*JBtS9?|qTV~rGU3CG zh|<}VV&lgexahPo3`L4lG>7yr{-6%Kd`%NV$au3geJ4=J zd0ve94vIUr<3ncJ_vCv3I<P5f7Xe!JB*$$yeQrQxVPu)y0}6CnA& zP~?rFC5g(Z;jA#{imr;>Ti7fhawFYGWhYhCdNgZ|j{u(rOo-ICmj*$IHTPj0gSh}- z$>>gIk*GjQm?xbT7e zOBLmhA))eyG^r|nStEPgjtM{0N8EJXO0F$AHC14P-b#nVSza5}^z5xeNs~*|ewlNj zl046+l&im&7^Er|+Uy!2DZguD)BH=Hlc;Ht&z!H1inF#Xlay3*B@!I42-02bc?blk z1%-~8@jPvZouO+QjJjqfot7d)17&2zB#DSaW3ewgDzt(}LWtlilFmLYm&4j_ zm~>~8QP7?l@g<#PT$M@7t4C~tt&zAKfkYB)5|t{{om8@*hkAA5jP|%QGj0(K$#nyX zCRU|^kBpIHv&z`fG+8hcBBW+)S8pwt?!Bndf-acx)g6CP(zID0NYr&Boq?YU7LqJ^ zv80HxK9`NXamt>SAa0=Oc?9&akE&|^1MRZM??B6iugaye%}wcB-ng^KjhruN!ob=Ig33~-*h@J;?2)iYto zmmUdHSfY(2e3XvF@9H9C=W6Z)YbfA1V@x_Sxs%I_G-!O%EXJS!OI3>a=DyuyXf-bn z>XS>M z85>m7rt+te50({87}zN6+e+OUuxqsixQx0ssgW)^2{hMcm~LeoBz`1|X&fnIy;ycO zII+XVYXUUTm zFl|38b37#!B1=RC+jZ~=HQZg<>h#O1wZf6URdiAyyjfQMAoxyA15}o5 z03I0>%LBpzS3(IOGX8EGfOoy`2pw90LeUaqsgLY{YZ`(F=q1w z@tb9m763Z?ez*4Gy3wTZj-ip(cov?vZ9scFC-5rQg|Zhx@q%M#tg+%xB(X}2pcRH& zNn#AZ3mb<%+fe%+k80ET8QAP;(C&suLHX&*s}=4qZT-7+sixqab4AC;hAYp)otF+c z021U#79y;75)Sb)gUGJ*NTW2lEvVxrsi_socXojh)s%vPS;(_shhf3*chPWFn_Ojo z+&ib%KR!q=X=qIu5!6gF6Kaj63FHH85B!JjIvAL-N1qlBRE>pKp`W8Yj!?Vdyb~ZW0E3^82P_Z3$m7d zwxe)hPhe;Zy65lJh~Q zZolIc2>GMmp0sJy?N~rJJ!pdf8B{d?047{Hu$ncO9%bDcg}w1HW(9q?+(jNwBcXa` zmNIa%^xUE)&G7Syv3LG#j0q@EC!11u{Xb5o&d6;!^qp=b9$qKn+Thldcm)NQ2X}XIBq9K&9iOKfmLHl>;FM{KiC${a^zuEF*qLJ1wHk=XRnkBr$KCS5ZavcW8mkpyAb`LS}Yg1;jIBW^wz z@_HMc3^2}CCst_QELk0{iprK5ueYmbKL?}QMxpeLr0P@e6KUDTQ?!*k7!@Rue$L#F z@DFj&>owIF?7wtdoLkj%NRVBo)Vqx$#e$MRT?69BIRsG&!oB{5Sx?%JM|6Ev^t`sh zo)*c(np;4O3r3|$Wv}rD0Q+!H$3o)3T_-VNgC;V#T8>^fqDu^owcC}u43D3t5BQC)x?2>Jbb^FwnoOLmJUFXlL=Q>)`2{;5O0 zSp2yg%bigjL1VV6i8O1GT!L&=npUHN#$7qrBN=htGYpIoo?E+OREq6jP~*LG(9E2Z z77k`INKpMU=0xf_kHNqgz;W zXNs^r{{UW`^t}U2(+jtW;LY6dMiXO?pTac@_8K2(vK0hDa9@iQm20?y$m$?ZuAu z-j@FWFGC{58BqzNu#OL@TezN&N1TsYaIM4nKpJtLMQj{H}DetI8dDboyQfkAn5i=C-b zYORNnj?v|3eltg~EP>o^J8067K?Ps?*SA6D&cfKq7o6<*FC?N+0qsb$lN&9u~ zK857Q7cG?mJDMo@Abrna*ml0G$pk897{xb6H#uT0y+kNm6yD_BaJ(C#(*O^>!-AkL zcXTO}Pl7Di9sv_LAy!p{JK5xlKF6!jYWRQ5mj&g=pJ{0%h_H^w1k+!792%fKk3!(o zMh(aGzf~}Oi@rj;yW1KZs3MQ~UsA`S9O;uTObl3ZoKAk~w1 z)S5LaO!r2^<<~S;y{rOn!FQ3W$XNyvNy_hOa$UnCccB`7W-1A{Vh26GLX3>8#%1#+ zP-84V6iXpD>7}3t_OHK9kKxCCjUXmaSi8uBmL&F3_dU5beY!b;;MVg4=AR=RwaB8G z+Pe$(H|~3Xq_({lG>qAgUJHvJ<7UFoF|nId!!Hek_bnwUbxPaofEL>6Zh; zIk_rhXrzr6_r{6p??FtBOZw33MaI){FcbZrA1ahD=G^3a3;zI+{@r|YA7gHffD}Lm z$v(^QquciAZ^b#^XoY6c{{XQ|ka$)Y@nbII8zHF4KuB7LYvZC2>9}}X6*sf7C0*Pj zU%&&NKIf~#Ii^+fAIOW2=hjFai+25c^YPSkXC|F-;l?s1qRh)`J01!Bx=N*Y0p2}( zqq37`!E);|#LAF6mf4+;-OU2;ENUWFqTY}h2)DOP|~`;r9h2HU`-bFP@!b|b?2F==VV6& z@|Ylyt|YR}l_Z6DO0os8* z`XiZxlc>e2JW;_6pHk69JT7CCBH1ogD%?@x{{Z3Rj!qk@07=yG)62*7v_K?4>#m9e zjiAAq9tK{j@?rp-yqrBn;5u4;? z%M^|nAU<2XN8A?Mv=S`#^pjV|S=B2#t%d!QEnsEJqnD@Y@W?XT8zMQD>&o2(U+-Cg zv1+6`+O60u55H8hUP;(W=(D`67wOV-8f{wve*zE)0OtIuf@T)im z!C!8`01e%b`g96;6(gA1V`Jk(xuhf{Q6LA7cpZS}qcNS)oav|Q^>npI%b}}~9VC^8 z`B1rdos~(68?;<{eKbXZ>Qb#%O<751hAFbL+EtD?jM9+4kQ8zO9Q}azCWk$F6iU?^ zEYX=_c8p8}V4!1819GB(U|YJ8Ldfc_nWq7%NvY;dBj--;F_tuF77S*xBiMMoz_D@( z^;Z?w65`uv28u%fGUd*frF|;oWa=^fHdDrb3N-;^C6$6L3X+Pgu^*U_tyD=|Ws*s< zZb1twtjgcnnGRgUO0(l?eAp84&msdh6 zSDwuzvLE+jmT$THbUgusBO*D<#~kuU9AZ`lqb?00W#I0<6kgQ^$?DtaxpQGj78X=r zSm>`TMT}&ps)dnZO%5yUemZTXu52>f&eJ|{2HuJo4k|;cL$Ia`EVA;b7xF0vt&eTL z-uhb9URjRgnov>L?$(Uti*1AYj@6;sfUk4aO-Cay8Z3p%agVez$zfY*Rs5lN1dIJW ztFAKe_vFqeL-i5wS)G8BX_0M!-N7sm{{U;r1A@jM1KGPbU3I!Eov{p4ZlkozCEKK=Rj>IoI)07n_#5C$BRxVh{{{JEj` z>NqiDmms7B_0bq+Bg?~Zh&WM($1`6-3f(3 zNegd~S)gq22P4zZ9{hBXWn4j>iGW#1LNk@(ELhC#3yhFsLFPu`tg=XU3c72cM`3;X zS$wN2E@H=FkTVH{gfVqz^&iYRs{KD+s%0v!@hd!$7DOo>f>dlZea+JjeM0;9=(a8! zWlfO=LdTJnCTwGDUX|NmkOAP4u!2t_tFh?8ti#+Y=5<>rw9JX6)OTXMVn~~M+ZrH8 z+ylwrf=93bf_dq-Nm3m?HZg2bGs_@Xj>42{DgpHiZtFzZzJm=OY4PEZn1oE;V-{;H ztLfy9-u&gZxLQOf2 z=&K%lYaw+d1hL4?Yyo5Cn>0uC&|CFgbyIdhiOd;ow54wdvLWwWs@W#M+@6o@dLfUf zw6PNt%426JWZ>S(${P++s*mO%ap~RLs18itwP(n9h>vjc5zf&=Xt(CeA5o$`hXbV> zWMY(jai-!+n&Eic&}B=)BGK(N%faJc&!=RV_!_UA_?TGdI(9%Y zt|pb>A=Qg2G38W?+s~y)1GifqmHa)((6t$#6UB?-6@j14Y%L{H4dcil`Ohs`F`?VF zuh{qNGO?+Kc2*sl9XDz;^pwjo)Dq$2x34vm6+;K}DdbF;mS^+XP^^&3B9Qhxj>V61 zqPuS7&IS|d)0wo>&>l`dowHG`VIL@dD+H?3l%O9A)_8i6~zi>{V^ zdX;YGk3a8fr)1XLIc0h-u{15F$(?e=(>#QjBs%#3?{^hB*l?#Ikt$24;xywg2b0bE|CMx8b6$(N8KTjYKnlRSY6*hbsS9XK1ip{K6>TiwsHuh zGDre24$j@#31i%D6hC%MIB<0>OAZNi+{`SY6UUQ8 z=J;F2WWc8x&c zK+xd?NZvZ#`{JLNtaV1k#4)}+jIy-mO~{M`5T2k7m0?v!k9z5gBO@7fomA>EJP_j< zOeH~;kCe(*!k)yg(g!>re&uxy0jD~XY0yKF6j<>IJk{P-8y3Ku>_cuM-A(uJ(xhzI za>FOk$rJ&UiIuK^$$F zE&@qBl5Kz>izIE0l2we@ZKlBu+jSAhJqg6tp@$161H^iKQ)=Qw3z-b!C1tb`x0X+! zpT+D=`x@wmMyCT|#fv^UmRO=?RFXlqPcSJYp7uyKJ^19&=q|gRi=}3mb0%5ziBt#- zi?FIu92WNd>(kNj;g!3@nGi|P9XR-Cxz2M$2s{=1-0e6i^ReS-`PndvCMTA8CA zKoQJTou~4G-K)J_SFz|r!KljE;#Oqx)5(owP!uO7mA}Kupa~smRHn!T4L1Jo*2ESa zMCzUoiEyXHiS-OT)rS#gtC?7W%oxg?5L4kVj&8mA)5aEJ!zP=S(nlma5=9%zEl~?( zf=!*nweLWmJQ|4FC_2>Adm2Yefa4&Bu^F|oeo0hXDo4_s?Ti1#$+U#xCl@{u)CGW zJa7rFsYj8W6vO#GwU4nsG*m@ssfUe@AE)X0j@dcwGRIMU5CUeHcBHwAZCb!N@&OfaTFAg)nI+Eq)ZPGYRxoI z>RKj4wUZ`Z8wnsNJ=B^carZylqdGgLtCc*WIoAQyM;k2SGEFrPNi=VeN9oZ20FOeU z05`qJf;7Cx0eu%s+c}Ms&Y!QYH1W##(npgHN;@PCw5=xySo6yO*JFYA>)HHRaCGS4 z({bU--w0W!U{cEQVBKO@xkMjm^>{GCaDH~7NwgWOe`KYX-hI1>@SM3f3HQ6 zvm7f+p7Zi~*q6`0BdRm#xKjM@W}Ih{>QtOtfQFw$KTPq)wfwoH(KJ^(HY}ON$C#~7 zrP4yGiQkJXY<>6-r1+;7`Q}K|v`v10ry*SDX2kJG?4g=UjSar*^eb)P4mx0x9DI=s z+Jh{m6cu@#w$pr&J9~BWyjLQm@+>=So@uyiJAb78s0skzev60tMI1SrR-JhKDRwQ@ z8x9(1y_?1UE!zv>#iV##M%#?bhPf{|7hBZ10`~Hw=Y!JXPp>vbD`RUK$)923o zKR&2EyR<=~pCb|&ppQB6;89{Fod90vf=MHWWAb+&lhtL^aH5PXnb7%>lN*mU$R~Bz zZbwWK6B-E#jR!5s8+UQsUqU35vu-vH>L7A^SOcm)l}cn~ zh&uIseH09@24>2>K4v>dAc(GQAtZ>#&^yOCgiweQw@tYORHEkiF;(M~Lwxe+T! zvXau5QXQ?B5(y)YX!0xHturc2QH+viXCr0bq5}gtU<%*m76o>0+;+a-c;hQh&(Sp> z_T5h{R}L96UN}L=^GI|%)bZFX*1aQz6>e#kcG5 zku?W{GECB;WP>LeUKSsg_-60X(AZ8*w`WRx0lR8wLvA zN|34pC5qkc4MyDBykf$kcp^#&qQOHA2T)Dv{#D7OHs8URfi8U~7+%Xgw9aT@@6;{HB4{krE($@1dLK&;|ic*00jdRRz}f4Mtv{=E$S zs;&Fg@t9Xl){%sgnUK3N7QomWi6X_>{={_-pE9mIsgS$YNMv76<^+T)LB0*If4TYV zyjd6~r3f-Gn-Wr01qUFhv-Y4*RPndUf;a}<%q)iYVL^%Jy}$VNQTAJUBZv7N zKXb_Q6_ztHyP$S$sKlQ32e;f1eY&Tm;ihJ-g^1|EW|JGH=9+SWB+TjHqGlUD<{Ek^6P#vlpGD;uV4wQnN=RDzeDz8CWwD zVDR7qE42~Dp7P+zpBv6;=9WB2zM3_1#7Fs9AQix-zGxk$y}Gv~@nm>oATXJtO+oyq z{K*fL#yj0#k&6|oKCeh1)zw^V6`S`357x;SiXq8aCx&c=#$}!~F7c~Gs>M-xBmmz& z+;lGx`7^pm&9uCo!Cpxs>bN)U_xp7=WXp$8kv^vE5*B06qBVXNF2_gAQRQmzkXme}*U! zWl~j-es&REsQ%p$%+=u4G@lZOo|&;GbRik8Li($h;uzXF6spLqIY0{j0S>yAaRw4AUv6pBxKx?u=9QNs&7}H4pBT0#f`0}B{nerbM z_ktP2#p_xHytZ3B@!NscTdzsx$${nUVDe2FZcfum7X8oV7yFNHng0NXCkGQ>pBFGk z1mY>j(?%RgBc2(J0;&ZMbG!TXnS!X`_Kkq2F_hbp&f5!7d@Rhe(&9rj$P;s{OWAqv z_Tbll@6>qz0LZ)`aWzj6who;XbITEh(TuV>ZDNWxl25e`Np6RDgZQ5wl(Fd^55bZ3 zN$`^#%`8FVNw?$!BC)&MV!Mvst_bNbPf#@}wM{~4b&YCZ80F@=s>02>**G9s9r^g{ z(bF}tV6+Ua-?y$_YZbH`LyAq$c9f3czzc%oG9{7os#=Pmyx*J z>9Jm-1Cc|kSXw5L;b|q!+L6pulPkS>QI5!f@Txm|e48hrej@S47MD9V5c4t_7B$^u z$bgbIuk?#Qn9)6FI;MW1;ue-n*@8k?F;{*Gs_pK7?uSKvTs{)i+nL>JRohOjVct1g zxi;(H#L*9cxup+tTh`PG@=u~>vy^}eWvt+}Kf&hz=tc}`JtVB6_k#5U_R z+=0oU4}RScn_tTDB-2T#;|O5Kl=&+=KcJ~)ZSmMr0b8?R)lnDH7MH1MGBo*`n~aR0 zHpi!|4zVl0^hFYq(h_WLdpvd>X`e%ni8NTcgmde9q5lANr$ppL2;54_-OOV7UIzeu zy49l0&CFsqP5gQ(8jTHhm+M3`NAQd(nA7Q+Q)SGvF6kH*Sj3KZNx8TO^L&yND6Xy# z4&^4StNgDqUO@%G}RaRX)Ko#?d=T1WUD{{YkHpzvX89xl|(>jrD+GRNwj zlt6P8c_@UNSa}={%m2?_=Ii3mQWwO{zQj(zzg-Sis^PM0?&V1gzghoLBq z-z}>X+ zF1R)Iy>R7bnPqX4oO{nD1X4I>CV+N4+qKZ+p}K~vkB%~16~Ep$;$%2CDIUOgueZOs z>P;8J6KZ}`nxnK)$VS{z&g%DnbN>L8e&^e*Mh4R%w8h7#k6a}xOoHc|D!BSirQ)@e zXwCGxQJ5x1sW>XKJrV%-{*ni4;djc+xh?o{u11h4kGo91c%C zG6)Wh9$qFSX^o8(%625S2}`nTwQl&n;C40cL`xL%ODqa9B6buPh(TgXE%s1Jp?|+s zW)xL9s$7xfrk!&tj;>o~=sLO#nnsVO%NACTiJdI38VH*`R7$M1TLS(>9rw;GE8JL%mKMc z193g}uWB8wzI$}g44@zj4_>#Rg6f2lj;>BVo3>2p1Q0i>Uo}W)OFiz7BnnYv@=fv3 zX?1MvcV;e$r^$zxJjJ`Teh}IJxIo3xEycSGYQAw#gmCDp*;H5gPlE8V~jU z89UV2IEN=5Sf186+!m!FNcY|P@zI=ihBIO`jgSCnA6c?VE6sNU zjwlW~uLLpUn2-Y_axICfzDVbh+nVZF4OtbpA7kVMoefkWKS)lomx-9BRzy?o)HMll~L?jz3}7(#a;G*!ZwO zkxPb!fGuKLjg+q1vdd~k9(G^39b3=Ai#-7xM>qSz4G;({rGMfLRsR5&r5v}PD<2Li zRyea3BNI3qeA!}qWWQq3zTy7>tF?61U@8Cz<;_x^iGrIU&p7$|ZmNhzH?JEos#`Qt z4@(H159xg-c=y8xQ}FJu<{9!Y5t#z=QfPOwe#e3Lub!*g7DYj`*MFbo z95zXA{<`F|e0)=y`7tX>Gh)X70B3=SpX#J!RFXaBf`buy`zcx{t!Kenu0E-V8VLNE ze5F?m2jc9Y4fiK${>QA(!(MI{dksSs8J=ij%vZ{dH%4ihS9<||kVAJ;1rSXVz8je6 z`RR_CIQcS4sX8nZGl8{MtdV7i?_;Q$k!O!@`j5X$9wX7tP9}N`jEF)a<)DS^JdlIwDnZ<=hKTptwa;~_)HIwy z(|26TxoCJ)JQ)V0GP3nd9GqGFCzTL5Dvxr-GdOa)dw{!~a!IP{&xy2%vm(xfNa7tr z0@jAe?Q}lGU4PfAP~bk59-FIpZzgPgE?j&_<h9S+a2@CA_JU zi*ioYx+l^H+!4pPEbW<(u_aG5!6lfRX|-W?wm83W+pH?Iq?%~0ba#~x9^uKAq@-mI z&!|KU$!0qY0sjDtx_+P_6D&`R*b_pLhk{2_=_+=RSG^BO{p+F-FyWp886AYvZCy2M!UI~kkN*Huo4v%? zKc{bSQY>LDc7+(r#EnAn@-*)mX6q@B17YiUQ3O~eWxVWjwW5_;uEA$Y_ASqG(5bN` z$Yk@tk0u!v6tZo2+yPs@;PdzA*!9j%Ec0h#WNA4IhpJ;8*f}hO?USFvfByF3)rZX< zJM@1Uu)Je~sOs8gB$z%WhssS?0i|Xy<*8pUZPzPhBv3bP0P-kx66_sYeZJeg54`xp zz^u+H!p9ehw34%-$JKF^#_4>C6dDKq2EGs6b)0LuYGy3hdXz$9>SBHA>8m4=+z@}$ zrtb~vs~$`;K*m@e5wXjgk|y9cJldY%{QGr3i1d?|%yEcmNiIqazGt~w{{T;seQvs= z8gHRU0OBNS7w3&{K%YY)GhgZ=V^L?1%)_u;f$Y`5kayrW&sDMKFg#*Lcv%grsVd0h z-}U+XeY_;dZ&acO5*U#7 zbpxHCezY&T_J)$v!>+oy+Wf-mu9dIq+CY;p!%mpmklW|tI)=u|{T|w366TF>k8FXDuchgLLDILU&X4AfIqR#$&;evHaa9AY@>Ws<|pnM`nPM ztOX?d@DF3rOf0Qe2UCJ=@1|>rT_ToP$w}2t*Fr}UAtH!dAb?2X!Cyx>&rHL;`Sou_ zSrHD=J8S+Q)AfvbapuHW-*KQ>qhNWU7;7HAzd z5*Rn7xS|JOd)IC{=2d1PxoTO{9zA}LfqerlxLC~kP9f5@JgAJBx|B1phDfpnhyWy( z1XB=HmH_VBLv|fj(lxV(kd2Efz+|@aq+_(VY6qJB-`}l8{4I;6>N8~MvHc(72^Kh# z!2B0ev^g|MBI~tqKHW>KM|DG-*NUQk7Mo7xiRF#9(EgV$CHy>?jzs+ z{{ViJV#+u<1V!iRd1=E$_E!G@L+V~Vh(E7WuZT5F5M&vU!)G_$n`2PTiP@iT|>QnY0bRSk(@bx#D zRzc@}D=4%)4ZC}G?b_=4{Os{fiDz7F*;A5UKlobJmHZ>w1Qw>Zum4 zzIr#(`B@8=hyYO5u6SWqECO$v@6zn2mBw^Idkk4<2`rKiGE)*Mvg*;939&}af^NP0 z-$J!70BM?vkE3XGY>WQ@eT5Sxi{un7w4ZL3eyhZ|J0<>clN=KjIR5}qrS0B5*+R7u z@f$@6t?~tS>BsDp!Ln5Tzu9E0O*dux)Un&n4M-bH>JjmA_877&R%-TTYNDb{h{{S^}`}ETdU?7mYGiKoj z(%x9H#-K4I%fN;yeEqT^h}bHikk&m%&$Qc?@yDO?qg0y}+)2%c8nIp4z@LPYlZrGa6QAEW~}4K_vaZ)1z1# zPM4y_7a9m+Wl}>N2~1Ti5l6)`NQ+>S0OGIgKVFU6RBo^W86fBo zn7l6xbHy%BYGwqNbHrn4(bJm+uXWva{V$%6XdWNSj~gEsBraYeW8`FGt7C1r-0Wu| zTAkGPzC{7sqxv?B=4!BG$uE{EJ58G-&vG?35(#mE`yVJO_;*F{P7WSk zwKHQDSfns4K76?oC}K*oka_r^2fs@`Bg@paZ0xnsF)%c}GIxelGDe3a6t?C;WD?9p z3ZN8mT$0Pm&D7`my;Cks$yGLa(hB`TC=@J{!0qmO=wrhKWql~ZjWGs|*%kf1dge9M z&U%i_??JbzRW$*#MUwWNq6JxBKOwW`lhi@AiA@kr+x1t?^vkE|3m6-s2!Te(l>#de zLAF((K_BA(06vRhV1 z1KEWTNd|}9^o?9*Vp>Y9J5YxVXmJslz@=;0romtd>?+!g^Zs2{fg3g^Ees(HfWx@j zf;%4cD{$xZ7x8C54tN=*$&PGxl^EhcEpPJMQRi{G>;M*6*%i({EZGpBG^}m_5*3$l zTI`_qt_Sw*(htPt8r;A89y3#x+iypI!u4jgm>DoM;d~-C0r1cTz5$h}n0CE&q2DkjBaN23g?v{lz#p1w^2@stn9R#F}JR` zA-@t^cNiO!bbc>cDpTb=PcZZ|Aly}y zT@EA5e+s8iqklc3e zk(2yX%g)}|z8KYVaIzUoNtZNuuuKxdlAB3TN9N>N>2Ev6J|xw$2h!>qHkV?)pBEZT zf~4>*jq^u}uWqBY#8vLGqz^8OA0J$Bh zk1eU!87y5X1+0P3x4&F27Lg45az2wIB(QJxiC-a)-mh)<>f(ke+MJ`q;>y5NZOzKj z@qdW&1!lt6bew{_<_8uzWtK{BOm0H$C4r`@1LP2Hnf@dArIuxbBRNE>HzY|Ea6@K- zA$8wCe^+}yze`c-(WRy{zQcP~IChTJbPrZiX(cS%GgEUZEHP{fJdWKy%sWGJx(M_4 zLN7BR7ykh6gW_gDGQXG^R8X092oY=F@}=Jc-;R;IQ{!!SEsPm6=S3Q=7{;M9{`GZd z=i{ce6wFz(w~#M%LcZSJTb3AQT4`s5_dkTRd;E@}*jiwB03HEzYLIV#HIK!s<;Roe zN{=Ckjh=cLw{kcEy}m_(SJT#qE+((!;$*IyrcXLtQ)Ow&%FVmf6z>&O#BZV7_g@FnPihy>$5p36%+=H2top5Xf)tuYk)_KDzOH4x&hz{UdzpIP=4_r+SpQXHy77ReBRF#?-WHC8V)XM5>zvlMmw>?dd2h)r= zF-yo58YfvBd8-Yxx`_sUd}V%KbnKqj^l4RouMrOTpb z`7Dw%KpFAmdkri+ZlXC1rpcq)kFn^+7mc$t?6=Rz^Ru2wah`TerpA(Vh;0b&oyh@C z-)v3{a45rZEtFg)m^0J82<11aIaAa?la=fPjZ zokzf!@nhxVL#S!xQVq(WW8}c3os0z(kxASdi&*W!E%bR>W}%^DwD>sd^zk;vRbnR% zA`P!!kb&lN#aQ?QrL9{}eH%JR@qZr|Bs8&!DVA7;4tc%GY#ziBV30xShcca5Yr>#& zgu>HxjZX{2vSc(EFvo+C4%maVoEu^piMDGtPv};wtnW7leH8i2=6MMtA(4Gd2XTKQ zjq%^O9mig28j;ai9wukNXXRY;4W0vk!+o2uKOMSlaG6;4jpoMb*wTg^ZXNrAN9aiQ zJv7z|V<@mn$qtf-Vd^NY1LVS)5wI>6If@BlV9IvLpp|OfO+<$FJ-XB~{4Dy0gEnu4 zGv?G@5ggd~;s{$SXd9c$sskZZ9(YNUayK=%7&s#ac_Dzel|QO0JQu#-W9$#;J_yji zhW;njvFFH-NX2Ztyli<4iohW;BL*VRCtO1_r$(GlR`u(mR^Z zr0&3n9S6TxM=k9E2?)ym9@W=a!pr_%_;VR^8_C>{5Zq)Awh0WRdW8|m7tdO^@kdLC zBTP(;(tPKVMt4Ad96lPa6;aV{nzT1@a+m`^%(B{2cE~c>htL*`EER^ zk%DrdhFqfviB?Y}tRUGGL+w()KOB+;_p9AbhAFiHfbDI5SC||0I;x3yAoO?qBc2Or z@-=+SF%v9vDtQQE-bwSQh64DjyQ;I%FCFRmSonB){Cj?<4)>3`=Uybj14~Z_guP%U;66sz`z%irIM1s(gk8IJ%=`e_+F_ zx!P)KT4LhlJc_97JjI~Hf-P^~i{tOmyd1{Piw9AZm6B+Yr9j(&yAm(#cbfe=JBaP& zY$We7kU<2E$za#^>562wV^EbAFpv^t)bKJQ)Fym(2$9Vp0ljEZWRq#2El6TJS#O@C z)3D?54~AO@S6Ek2$IO>U)eLn{B9FnF^eO=d+WN8L*bmgvDzN0^RLw(i_T6O&4~U_P7iWLTsm7L<{{RfCr)zd6aJ#Y7Z*-93r(e<}OKiQ;GPn49 z7JY3u3GmL3sSU@>iz5m`Qer*FmRFwsm7scH!cinp0yxXZkt7$m7eim>M(@#wLUoK) z#gj8H5Co4YQ&*371}UK)T>EeO%x)UJ_Se5gboY#6Va)=ajLRxV!8=Oq;<&Ft1b@TO z=@K4Tdg!V@yxhZTk3S+T?<*%vS#o8E8X2?4lEd+ZDP!zxD*A`JS0r^uHy&Lg1kt$x|Dv8>$WFaDDmq=c2lHNAkT(Fs8_*$1r6;#0K3HN<*Rh0?lLL%^tni z5bbL)`RBtUY+4E~0WgxV-NvqI6B} z(E0}Iv31WDI}Vu@TuIHY-(Q6;V{+SX=``tHDv`YDwWN7IraEx5}GBVSU$Z`uuM2||7M70u0 z{kkQAiny}87!c#6LV;p707w85E90IlS8tA)Q%hC=GPjn%@;D*5>_2+_x~?F2R;4h8 zP*A@in1NpWoBJO8bS~E}mr`ytRAbZTinp-Gg+mY`1Sl+iNaoMSRP`*WaOYUCuuf8| zD$6{%OB%!9k}Alrdi^fClRjC?$%zhBn7O-`b3mJ?w zG06FD1~VyQ-N2d43uYpy-yf+U8k?U|`f^pv7btd}r#4hM3=y<0$Z*GWnLw*89jM zfS^I$X2Bz#y_-vk(PN2x$noJ3p)Oj@f_su{zj8Z#bXPAf40GmcGc5$M3NdO?e4c{k zYZA}@0P5f)h|vY?lgA)@cl&<5H%g3v7dga|RG86YVaf(f2160FMoIwLC^vVAK zg0rO5@(dTC0%F8t2r;2V+!8qI#S`gK+Q~ob)^&fYF`$Yg#MpfK!eN+F@4L|n z)3hvnCfyRVO3Z{XyBrZf9>bp9{{ZG&A4^E6`9VJr0MvLq_it_oVb5F~r%Y*|78gk3 zZ^n{?vZYx&2PgFJ!Qk}pkDG+5Iv!hH5tt;d8O?niHr?mla;mpgotq!#XgD>Equ>i$2|s!cLtyBM;Bf`;W& z+PUpVn?c98HQx`>9CJ2&xN!l4ykd4if+|}Q|?bmo%Q{-<)Wyg)F1aU8^7OWLsY?0gB zo_i6|(D-_GBTw|}j|_1%qBs~HJ=budT$4*f`<{}kRkWrkh1~DHU$l*o`2NzZ;gN&IAeOoACYYq>K;-~#RInK0&q8RVKNJdBvg zk^}gG2bR^lvD$bw#nO&Cn>#z{V=?0qGe|;yB!)uUS(LNc;BW`ritI0{b7l-2&-PfM zg`;L@<6hL@lEj10s9k?=Zij*;lQ$n8DKfPjco@kCyfKjjppgT;UgF{}6K27NbG$<$|; zGcW5hGai#-m@%;<0?84pZgP77O|b=uRWwh3J55y{Ju(S0(8y2JhAAD6_T*Dn!tVLw zzg{e1U6o46#ZKu6B^Trc9q;`8`dY3jjFz_NchAPWmlabDBg90C0A&c9PDGT?C3oOZ zV`uap7(2le2v3v6MIi?E3mWJSAXBB;eqpIbB>|k%L!xv6@K;F{@v(wSIWoI zF{hJpGpu&J=9#fLTW_axGfKmpmqbEPdCxrZ6h{KP8o7A+anJ#1dk&) z7Ru+%ZIlTGf_i`;m98jVQ=OmUDc>6zwydVSw2-f)@#>IvA0=q^9Q5U)cz*{(kIGM0 z=v(S%jag)o63*2E>+=-=9&8%6JvoYd>9Pp`?i&If28S7s72Z~xfgXg}dfuSeIvxZ~ zm8iT?k1}$kdba>gdYKVW5=$+2=sd5Z>l%c5em{ru1|ZYZ>hhOS@_ea(F^kF|?+Ia9 z%cY-4+yOmO@h^yE)->%S4WWD-%si}2>DnBUR7lXi_>v*Vpb(qhz$KYMG(}AjGH}Eh z2XC6K>cfdWMcLU_Ew}kp3-%!Q?b6igp3X@kG(~&HXctF(Baf(H_;O?7SuwKn&UQp` z=3~Ya>Xb}{Ndl^3poZH(S7BAxy2f;%q( zN`MjOd6EcxvRIbbywE?l6tq9nua+6J{N>x^zm`h*ia{VSH(Yu+_T!G-TGMpdM90sC zl1{=#P4Px(eo#IAw;QwBKU4{> zLh!Vi(iQxnY}p8;00OIR8@^r`X(TIgI)I1Dj0P=0 zFeS;V1X%{j=|a*@YQ1y*{nH`!sa6MPY z9X+r=%5NaTL&%V!nx1xxd56OBguz*IwVsy z+lKP@7qjXH`MTX|EC2;xR2B%MnGxm^NTy3%f_*%x1ke@8yEpc(x}D=5M8S=HUjQ*Q zEQ_+~Z<7HY+FeN`_D&y0!nXunfWADOu$w-geA193J$B=RgR^sb1@C;lpH-Xg~G zbi8?{!^E2fT%0)?H=Sfv4kRDcElqdfjqq!s8eW&5nc-}$Lsn*oE(u}E^G49m3be{( zWnR*wDIt3>JTTyN-~3O}UVRNS@kC!yr$$7GSi9HZupo*60LH@K&q$GGYLP3}pN*9U zL=3Y$bH?6c2A0_YWno2R71)mbdz=m;m++b?h#~>!J9P89^O%-Y70zpeFsl80@w~7Q zxllwSiQT(+>7tmuw`J%_*k<`COnWt@v=ze8bvV@mi^ml1CwUB=*NiG z4D9Hn)-dyQEmk~+8JTu6Ba$zuKC%?;C2qgss`niOk4YM?sfmk+HZvrO@hs6v_yL+K zupic(-`w-Xao3@th^JMVw(X7_MY(O@v!6~K9eEVXqTmnaU;R_X8TxU8SlbqM^2>mv zi55lw0CwJz2&TQD*EiF=ULe(`#ntiS#e+)1(z1*=qYEH`JW78KRYTl3jf$m)pv=}v<{Pj3^xERNJ&5&bvl4zYG5z)2{B&*8bt{{{Vyj8f*^^ zX;}^zO2TN0X)r8X8v_st2+3l=5j@t?l6gpl-s9G0J=CeYATnF5X>q6Lf-NQ&HU+27 zH~tW;jS@^Y7@7Ebbop@NyxDCGg|LhiA!Rs_nZP?D5o-1gzP8qrIH-f8F54*kT00C-vov= zvPATqtT$bQOV;Cs7?p8j$DTnZP9e|7iy>UelMNvR(08<&m^XS06@V93bK z&xb!V9}mn4wb5xRXqGaiMesr6a7Egzo1lBR5mj@*IaOFgs@#OTHQjB*acQwfPzL@mC*| zp~2C$h0MmsoU|G?w1+1U+B$i0OTbW6mGWk#1Swi-BU+{%m8tfacgWm!b;jIM?0g)L z5O<}wh6((_fGSGHq9buZv3uCQeouaf>KOQVIZqa_p%vF_!2XmH3INgM5}*p;AHDTc z4s5L}E%3F>88K#w76Ou^xQp9}L8ITlL~^HHS0+dsE$2c?7m-<&*2oMI z*!xwBq5E`d6l>w?6PGaSf3(UQiyYlyEadoNC^yTXy5ZW?kVXg$g7_=@pKpHs4#&yM z#?G1YTP8T<59TCsE32~(NlV&Cq)_6GkZhis@-!@0!jT(3d}-A|$4E_x00gnJz$oMm zw_F}NP|4AAshBFi>LNFDtN5To;Dhi?4z;i$_vFpo?6dFZ*Vaj|eH z)G!RXSusTGx6<(fyLj!~-F#mF^+HVzVt9OviS)6(Jjp+(I=VLaG zn9t$A6Jct&laL_Fa^MygJh_p-5*8O;rK8*$^>kZ9@qVS`m~-@~;hI7#A{H#Jqupde zRhPfH=cAWWtzsjNzN7N1mZdw3^|+$CR!Y7CWn|^x%yMIr8KH%iMPv_P(7Ldy#CvcJ z^=UBiW%Ew*{$dqE7;cSN*embc8YcRyka4wKYFC2-JNSWKJbdO;S z!Po|{!(pHStLz1JCPXvKWw6E;KU7sWg+m&p1eS%NlJX@}73mox|K$S0wPZemuCEd=b8O zT$rnqnKH>7OAGq9K%2M~O2m-NZoNBAn-BHeHEDsC2^SDx9eEu^p(2Xp9_5%j`fs%Y zHi{q{Js9xzgQ#f`OOY;aH_=Nksya-SARbh{(AEgANUH?&d9m@eJTP&~WGhBWO$@eo zfk03-`x8L>b>Y6X^&hP>7;0f3G_CgKF#t@00oHVx2X2Ey49q4>l|(y?k0P+`Pe<_~ zl^QHu%xLD2h{hy}rMB7SOI?6Pdw*_+E-_u8)Y?}G& zaFG81DxN({QkjBFDh831#$s*64b2jeyTaG0Xo_0|^_pbrv*+q^92LXbu$aV45t7hG z5V77CiB<31cO7bdBkGuss8xMBw1;=@aIzIpvNIxq>sNP8*y0yQh0OQxaamiJr>uank`=!P?fRC zIWeqn03=eDb=>6BKGFg0%Gb|Ba%Yj5(LB!a$gD=i1qo1j9g5ig{p+DtZ)Wn|DYl%z z6faluopI-ASk6}5AOsa;V*da)$qn#5UApfYXNW}<;}voQFN-TPgX@Te0Dr_3C} zx+$pPzM+E*`7X5{wdJ()s~Kowl= zAK$9k60S~ETf>!k4Rc@BN_qCG{koq_Pxg$o-U#|Eq&5ko6HL_#T2nJqQ;b&3Q!9w zt7T0ny5oa=x~-d#u;=0A<3!6GPL7;r$9PV9<1}b+MSl#!! zZ+~uwWV)^iR8V%LfLI2>PuGGggWIBzlV{wHq%vdpgEtN&NjKz65Zu8+el;m1kgH4- zS>RvpD9wW^r=67v81hFl;q)2Csw23F{?)AFb38HH8`$EJG=X^>NIgCjhO<6 z4*3x}vKB=)tfKx;BaZ(7n!2|55`7+}mo&KOVZ(}8V@$MGn{)CF)g7ac%mJ`| z-4K&AcZKAMe9;1Ho@xL#rM@{Ft^WY`v0ohg^;1Zw{2OUp@{6hkXBdi=*LiuOZv6ezf>;<}?n>E2bYf%IEuJJ%0@--)FGkF4P1<**= zK=$Ncy>Jh2o{i`-YM9<4^Q4w37~(QG3ap_eR$@WmiZpoVxcRViuo%IEY}&{io&W^< z{fEC=7l5FNJVTsy5bC$u#9ZG2|7HIO3QZ910_gC#YqKG`s}JmKkzjNtQPww`ST2JW*nR*-=L8 zfDKJkTK-=9nGRHe$X8?OvVWxyC%CeH{Enc>(DnZS795P7U8Kj;FiCaAAjF)X$bir$ z*!}yS-Fm}O#l4*?oh4z7b3VZ-;purfO(P~G`Pp*I>UI2EByQRiTR8v|$8b9inXvx= zg&rl!3z4Y=(V~=Zj(mw!xfS_ig>APU2dIj^dVKJFGk9=+G>3LPzm*FTRZ#js0CL3H z;Gc1KT~qM~jen3hksfJtH=m~r;z=0Lv+4(LH_vXzp??fP?HvstzJWdpP9g3wOkesz zvAj2=_*WHjwDwoj9F$DlmsVIv{N9j#Z+vaxMG?e@e5@K>kHA?#~X{uLlbuxq#IIvp--I&YDMr^1tD%1@Jz zjU5fwbs7r3-G^qieqN!cz9bS2+~lIl3GBu?ZhLn;d=8`5bxj+=5S4~C zmpt;@TYRz_9oX5W7Cr|}W(*L|KDyix!OUaPRL0WqF<@-}02naI$Ydoj;*nh=kds@@ z5a#HQZYU}5)Se;n5=EmsXKQ#edS5&+$jC@m(4u6TVWOyWY zk+88@qWXB$sa9uRNq&1D_{484|NY!->&7Fpkk0Ln8B5%bdp3; z2Q0u+^L&cCq1&eEyatwzK8P+Lca74fgW*{pDh!QUE$=6)DA%xCu04li-mAGix_8Hz zVa+pP$BdxS6Z0a+RX`F3;yJ(R%A%hlG&d8cAl1C8(%6;SrXaROM)py;0 zr?5tn&kTB-eK2=Oq$wAhpNiltnHvAt{ZkzKhQ{{YLPax-J$JXvcPh|DJmuz9RN z04Y88iad5C`_SsHPO0?+$i&>P1Yt{)OOGR06}ksL2{P0BP1D_ zaT7GJyYTlNs*8Qwu`TodgTGX^VHsA(i#0HApG_T$@;`t-}4qr~};MU4hd zK0e4~XxyM-yMoD9D|a?ck8yR^I+Rgq(_|cFi#73~ji$#NV^y?G&h~jbn0)TwgUt?M z1}Abf5Qk#pPXd9B1hO=sGFY!Ldz(LT&mPC45Xl4)2(sk!a#aM9M3NT-fD|{tC;tF| z9WVa?IvR^fE(8<4RJC$Q6{1t>1cqW6g%#s(KIC=A57b2*gX(3LSqOFu>5W(d06?Hs z58K}Fo``V`9oFl?QO(|(b7jN=ShabTL@K5nJZ7-$d9vR0IX7Qxs_1iMOOpX%FVg@( zh(pO2&!l?_ufGSLqr%342bmfJBOXb+>i#@oPjywTyP0o~->SC{QO?a#-UxYs7EF(Z zFy+RVP}5`3B6tu!?=n@L$mUJml%D$(*F2u6N1Tt5ZHi)3wE3ZcW*{(cO>m?)<+2S6 zzN$QtOCSzfaCn4SgkrrS}9>yBYBW|Y5M@gP&N6eaC=Q$_K%co`fipL!&ZN6CIzSchdi2ndiIzf|D zH7Dxcho>~d;iNcdQ|wvqspuK&5)ZG0Zki$uNQ!+;{{WbS+;V6htYPLRP97|dM$DuD zlH6|`0e^Et_vuSX)aB8$qn;T?$}22oe=>W5djdW^$8V0C@*xq)EXfy{jh4b|M%=sr z2@CL6j~v*#yXkY?nq*vc`%EzB8J1_4qD76a#?qECpzzpD#*JlG^`2+ z?n>AI{DOP*%nI!nOMQh1(wypzscASGoEW*7K5W`l20I>h;v`uBHg=8UZ(seUJy$~UPA)3L4oi7DigG-sE9tu& zjl_W5Ugf`TrNY+nq0iK^W7FZ&up!GxawU%?9mY#G-=z;2crA7Hib(Pk7hA;)vCmeMCgv!T z1MSEbIR^WKT^kKpG1(obu~6oikdu5Vt4pfOo%O6H%sVAajsrMLvg*7RotMF?7Lh#95lCzj`oL8tzl|dc|qSD zev(&qj%-OlvdVcBd+|gOd=Npd0S1T6fsn?zc%{MeSQ2ADBj5XT{+%agV=PA!W~_Yt zA?e7gUc_#GcnrThbM4XnKTvFl3m^kFEAt@)lV9Ude=`1;RnThCX>N9#E^Ca!votA{ z3qBw@lR}&(>W~n51CeS}kw=>feY&@Wl(XaRNoYg^EA}Ws;{O2R9f+%{`0B8cB~_H| zf@A70-CX_1?tcCHsV+QcP;A_HIGU_vd94}VTaE*#X#gK0z^eJ_M$#;^bVbY#setMm zT_q(_CL1S>xgn@>KHQJk{kp2?F*8Jaq7Y<{_E(v&%3<9}CY5;jKHs#uey@!v$%1HD z8Dk3KF}%e`i5A7M0FXz$kn z#h2KIjFxE3GNYt{!h<5Hqs8(r`R2zQdvr@9NX^K|!`Jkt82%x{ja4O$_eYT)-%>CY zxD)Jo91%yJs9_h#k{nEzQvPX7bwovCz%vzlsx%1)fN0-6AJHa?1>2BP0A(o)Np?uF zz^WsfvD}`Qu3X)2=IrOgj=$0)Ac-0ss3T&>t-fZnq4~HuiTJvPmTa7PZkkBzyl>6W z;kh7N09F|jKNKpKj!;1r-p9E4{XO~k>h`OnHb!JxmXDM%HB5UeBxG(r%ouh*2KXX@ z_MxdJE~;{;GL0`$#gS7d38J74n|SQmR^Zj0rpG(1^J+^*T|Gz0+=e%vPKG%8^60Q+A3^v1s>VbnMMP5=D+pIpgz8Ywpx(kdeS;u0?}))Y@N+r5;M^ag4ycwtPEFOm}y6;a0uR zz#I~9p(?AOMTM+r+C0+YY>^sd%UDZp1fr^%97r5`fdmji_cj$Nm}xru?&|8mJ6*^o zr~EV5wD9?U7tZ?GBXY?QZMj={pm$Vr(Bi!W`%_)0V|bnz(<>WZ#}Fj4YkqGQRGLQ&wV%Qz2%He(Lk{TrqhZGq1V@R1B&`2H$LnD?Sa!BNJ z_ULY>qQ$6VoNZ1Q$AlhCi0TrD=2uWi;E`hc^s}cfMxQ%R;pt}5@=fndbr}%Xeo%&? ze{1QlPw{)={WeCpkz`=N!7}6#%M4OG?kWm`SChvS4UR8^4;Y$2{{XO$A6t8<4W!}- zFj6+L{5D-lA;{C@7_&(%%+lnuJIcP60i-5@QDW<{=cK%^31-EqM}>hLnW>o{n~nHB zTgba?saqp>>_9)K2d~hWlHp`aGR1wSPFg{Z6-oWiyR&=)%tY4dR1hR20GGwQQGQ^fJ}vh;m?&GOQuY-h_~F4 zg31)#8&U}N{{2FUj`Jkh5iF3G8`>5q;Df;`O%wiIYFVBYf@0B^N!B+qxRk7;)ccR( zCp%AS?fMbW9Yeq@**qKEsqSd0AddChs@PNMGCXrCqRqJ42!M?R0IWNZZqLUY9;C_e z_N}Lx6IIfqnc{Yiq9No;-F6q6yZ+rnkKw#*$kQVmB1etEXI;CB6&!$hKKJj@7-|N9 zJKj_69?HbBNzq)<_1t_36lM~o-C3oClHmUUimt2<)nBhqui|`J+v-zYmp3OCNlGEc zX^Sxu+{qc@%90s^kT(L&)_H~D_)#ut)-oAGDgkPwaBQge_P&l_K|U@PRy1En<(&k|ED{5(JIv zt;$f{55Rs)WB&lLLeorGBsp}z$F`WTZN@sIOjIx`1$6>xlEpBFdEyhSQAmif`kWL} zwYQ7f!P|8n4fE4JHlW%g%(|{y!y;hGAdV;yNR#?@5X^UBiN8jJ87KWZb-^vMbb&)ysEPO~>T=}5H zfkM;D#(^Xb6bovz$KLts*N3%DBU;8)idKcAVG)*Cn5#(aJ;(#GTJ79?@{JdT^YgV? zGPQW~BZ4NA%GDV}kdHv5SjVMa*bo@=W0FO6p?Eq?J49Ti#D(=KG9Xxi4^Wp@bGvib zEGV-c=hC2n2T50Zi%vj#vG?0;sH|gT0I!zAam7?S5w7&JcwY4WzG8LpBN-ytR_Stgrh;i(W79p*cZ=S>lm7@Y( z1kxFdW!XNIZraSxL8PMB#gp+|^sdyiIK`Qy+R`L>3d|YFvAX{NH!F4T$?ekJi)*xG zfbFq5?bc4u5yI;2cVy$3Tf?rmrkpJarIKvZxxB$rWMoWTokg`4KHbjM_vXF&9pX6h zW5S;pV#=3|Bf=OMfqL``tD<}Mu7|}mx%z=w=6w95QX-clB@pAnC=!Cg#5)4R)NZ$O zdL;5`a7=b(N#Z=!OMF~9@~`rbGHz*jsvoD#s&LJxVkGVt^Gv%E;yboL@O(X=rfAws zI%FEB)aK73NtYHn#CQeeoO0W2eiAX<7q|tihHPIFMTwr)rrsBF|VmX2JO-j{bF+Je3S_`h%O)!~a4oRL06 zfm}!e1yE{%;Z%yg4=45e^=~6C40S6A6FOa%Jg6Sb)noMU$8Ls&{<`%7k z)!MIUJ-x}l+ougzIhk5Aw{SsiFdZbxQ(H$h1?w9V@9u%1>j8j{L;sXDS;ucK3UN1zV~O2^frQM_a5C{ z$)85>)|&IA>5T<>lVnW0q@BIR3M3vWd(i&ry{;rRqE73cz0)ipYyGSFc=~Rg0%vPu zH(S&gqa+yE+rh9(kiV2F-R>v2`*of8i$|Lq#TuKwq=Y>CzNSo6l4nu{31r#}(BKeg zs1^m+MEpJDT%Au;$&)5m#lp>*<%1SDk>*<)ZLfe0ZXg3hfP3|+>G4Uc>3Nf6VkQn7 z4=)TURcDULX)J@q`hyRX}X{85r7jHT(H~ zV0IvJ>NE)kk4qSM9wNaBCaJCFM$-}>O~lF)P5%IqrDH>PAD69)c#Pw?3G2Zrl($k9 zj4uESCDF?vU`F;MgH?1Z^sbBJ_;&+KR}x33W9=5rkt(SD_Yr)3`tMBe^b$t-J|V*{ zNwEv(%Q%m{t1)e*zQ7;U_Up-X-8wv%`dv3kf+SKr#KnxzCe1lg$M47k;CtQG9WW4y z8%p*~S4fT*WY;hwi3mbqWo1)D(JQ;){{U{J(;&gijO5~FK1$UzhaOPK0R--_E4V+Q z>U}>FG;OW|sbT0q7k7F!?fQ}L+p8r2EiP;)%q~e5;@5ECf=DER{{X|F7r$8wxtXAq z#Ml^kanaAd!7km2mvy6nO};AhuS8$pfDDJ8|4~+<9J1s*93L44YYC z+hwVJW4Rmy!LetqBa=;$;riUkR~{mS#u}@=jpBfAO^n##W9!JFx+O{R6;}ce0pxa2%&3|Sbe$~<2RGk%a!nqb7mh;V#u?tjD#*e*J zw{|W60GHpe71gYrIkI!3lLt2|2v*-A4#6kEC!4Ax?|o2BTj_G5$dem40okZUArdXn z0Yg~e{PS1Xjyh)kRUSedjVRHOv1r_i4}PFQ{Je_evHNl?_f+i3V80*N%I4+HGaGP1 z*BX3w@`e)vt7>3PhrODkNA~{RcA0`%DtncX62a4Ki^1+i6Z(Y3c*dCYiFeD}sK+aDG2-i)k9BTVhCj){840LN@ii z)U1H8_ak***-uS9xrB{W0||aMFEooJZ;wt^Rdl_N&f!;0?`znD$InLmJE^{%njp!I zWW$^AmZ^#d98(eBi$?B1DtYMMet{OX57ue!t*E$=NgF6rBOo4K{uBAaCXnrBkp*Rud;s$6Kv{_aMqD4F~_ykwY z9{ltlMxFF+cN;$$t>JVTLPC5vFv~L9aaTanonFMhcHk63-Ma$ zS(zI$CC<_1$#`Naca@kr1SF5~qX12JUEkvAiHmC5M3G4ZONislUq_Z~kjuGh)a)D@ zH^8CRIpH1n**RF4Nhj836*%DtHsBiq`>`I!+$r`wYdUshdY&-IftF~Sf0X2l3uIMQ zh5(-SMUm_}%&5Z3nCNz=Zrg9e{mUIf}^ar@4 z1bY`#+WKtJvsPGyxQNx|(t`HNdx3N=&hOj5RdYckjVwe!FB_BinH3UbUqSZ%j#Y@wR7S?o;M+LkCd8>{6FQRbBdP@eYc(dD@KF zVmPp~S)$5TZdt($vT^Pd5P!r2S@e#B2t+!Am_htySD1l7Hqfm@+l{C0RP@i&!<$Le zop{rd9w>tGQM*R8p-lk9!Q!;0BmIjn4RB0+qc`LvagS*W#Q#32_GHSK<-KNSJm*m9%xXYK(^%d z7H+kXqiDH{r}<|-Oo*YyETo0sLw#@uaaZqM==G(Drg1nSw2%*?t8G%-)yC5f7G(HL zHmH!z0W3XHO}a%QyMS56{iyN}R}UrS$7A>E>}+Ckv49P;0rugD@9_O((KZsS>poYWCDZ<+OGi@_X^%Sjvd9M2 zh&3MMS*rg4mr60=eQuukkVyE_#Ngx1+?eE75<>KQ0DZgF_P(EUFk{xVysUXt0XS37 zJ4sIC_e1`5(oO@nm5pd)onzeAM{B?D>KuQTOSHZKRtn&rFiednc9v-*?AJ_{{TZQ+nJJ=Y>Vf{puvF~K{ zG6#trqCbYQKcu)KL{;5Eg@S35)9icKP-?iDI$o2Bg(AlD$noPc`HYGV=-nAvPaAAE z_&{HtI+i@J4q`_vxe-Mz$2nE?5X?N#387;94^TYyHA~r0JCN)5`#}r@b=O`94~+Cz z@eF<>({Zk8pF>$9B9G$7kg@{w%Diu zv>n>}{(9Ql{wUW5G$JI$gces~(TNFQ!;0-j)LA_9$2<<7#v1Oaoi3H4W=RHowLX4R zq%9sKWHoK1+`Iuw#4#tZ?r34pm#I%CnWZ6FibE!DT#NWnKnLeG4ZoN+s`uocE27w1 zd{{W+6HSOmrovijlJ9B4=&k6WAGP0%2lHAjK_-E_krfl_Fs&B!M)Sy-o*?8JagQf}l|AXN+G zb!jx$h^%-?w509`XuQ`0eFZJR6}P>6pVOn79!_4Hkvqd2Z6f1JSslb+v+YuWkErla z9&FehDTu_>4b4r!a3(!x*FcL+ttTlSU3w~-WW&YxINFcS61WIbMZ7h0h5V=i8K*}SmvQyW1tvtt7~?=srMxHUJW{3 zVtwxNI}OrHwl$4bV$J}fcwMzkb;%2Ty7G9ONvlw~+c?j%)u%)?pbPjyqmit~Dulsl zVUy}Y@8it~JM9c8S>oEwS+3n!!<-z5lMfbkmU*_35i&^6*s*eK?hX3|yRN+&UKSEA zBzq*(3l`u4VjaO?ZmfG)B$3G$L7aUt%e|8MAV^GvkRypIna!WfXmflHgbYy}l49ZyFB@?Y zBC3VEB!jbq$@ZbqY-L=Cnk-U~i9FDz2Lo`up-=!lJXMb1^LNymcAXShu}hNJ=2k9C zV-x_OBvljYQDe7%ezM#303F;NZ`_#dvsnSbgDW#Bu`(7nU=WmyG7duezH7g+{VSvC zqhaGkjg^o`Dh#Z-J5+}%dkYK#l5I^7zf1bIxAa~nF|2CG9Sm^^Br3B@=596=5V0yM zg6&(4B7;QrBTX)LT)BD9xj7H%RS8kVgja5N5(nw_9cp2zSH*zhVY~P8zlQ<}1D{Ha zh?0q}T)7Ga63ZXplvtyXr=p1^nD*eCBD?Y1i6Vy{JOz0cC0{v2Yqf`?o+AMMVn;o| zv$*s&X=Fh5;5)~(Gc{kp`}RFnhdNA|C z^fQOC5^xKUIUrK=e*>!U56K|P5*SCb^nh^euo zVyg54vScG2YD?SD7bDd97B-{taE-C8WweY1uZl$v$qYS?dU}t-M^{ofGkNi z$K3S}CO%GNv18&w##v;dUg>Ls?eSdM`QTaOuZ{?tF=EPPc9KIA#H_C(5!jf)uuTpP z5-fqm^wXvx({SGvrfH;hEi8<785|x-H+x441@Jf)Nj)!L5Y`N|t0tL~r z@*#!LFdsi*BLU; zGwi`qPW2n3pgqRWem=vKT@J*~eMd5V4?&S6niNx+nIPSdhG=(R>yx<%IqhejaOzbJ z(&u-|X@fT4&luq;3ru+!EQf?h`U zW+#?z^bc$6?KcGs2&71ngSuyzX?Al~Nl~=1+Ag@iupL{>&5s_`GC(+B8T~QX?n(DN zbRjypqk#ef>o+M?LRRLlG558sL)@C~NBZ;u^VT>{RZ~d9%Nt;M1CGS;-`lVq4%G6S zCT}APe27}hQ2~!@B>M~CeDn4kM&Cx#$XkBt0}aQ3K%vcjuiNzMm1tC`&gsA7@y!U; z69Yx`&y|%3-6KE-(j<|0w>{RIllqziiXDA}6X#_~j}(I*7yxPVCt<)p;Ro|EIreBcnFe2kfd9sjF1F` zgZYj6W8l~oV*dS2pPrbj=DA|PFeQ0rYUM%pq1^j^ycOBgCtrn*y2Bexz28J1YfVSI z>^m>SV~z&mc^yORc3NtRK#QSRC7V)Ki#sPW5fY-!3@aM6gO*%$9j&d5jrl=U6ne9% zX_9I~6G_I6Ax6m(NU*75hmt*B#>p(*&-dtzxe_I0DwT~uM5y-cLTc0wefxJe?eA+( zc`;*5Om>ea6y(U6EhgmLVzu(<4b{BW_N6p=9WO|cR8^b#$6ohU4ecasMKnxZJ4C?8 zh6aKakj9G7+ag9RqKWVMPSo#KYu~EABGeZK7mE%VMn?AXC5}Z66Vgrlokes zve2W|uc^(&625vaNrXrAk{zk$IkMqnAD3#CUB=CEN3#XV$T>QJO_5~m9)u)qrT~}b z><|s#Cf3CY>qVdBbiV7Hdoc}4+6ElZw31qkq!ATyziel4VyZsrbX$^rTne-LSxgrO zNZLpNZSs$Jh43qzX*l_6YM=*R$)m*%Aje4>REkMN#ghE*H1L1}&#J8QO>^_t8kUuv z3r8TCCs>HI0@-~e5;+zHp2ToP9y)dP1MCva1)@qHC~Z*2M5!Sb44`ZaW0e7aFid(pk2IVi6GWL2p-(70NXcy?_T1p` z2XA4({QN4Xmk|g|DACk62OIGh^`ibBYJ?^P^p^`%yh%5_=x0Rb7osH&Z5cxzO zDg>q8RIl`tz!&!%(d6>2sAgp9C5ezLA+Jy6N?^=C%ktMfse1b*B*~HGc4d{>BLrUN z+q8f_2Y<`*cpXdh&lC>PmGYWFK_jyxfPW2s!2WM;DX;SN%%mw_S1B(q5HwTiWJIAQ zWQfT15tcLV z)^%#eND2BhZ6yxK(Xr>offq1iV*day#|;bwxeNq^f?K!&8@I2$_UN8`P+{qjq*7ze z{?`H_aIR1UmfDtwbnXD`cXjjzStOYubjq0E!jVZLu!KmyXaK1H0C+*~Ua!AVW#o*F zEfXioGEF#EF@jK%C+tmdYL$o^eebOLjxKG=dXNFe0s)e(9?3qNHJ%w`WMzSjWF7sO zdO;<-pI6DDT~TeLDWjb-ip8`rIP%H~FLVrR>NYvs_P(PnFo`~sKXfUPkkUuy8A)>F zrJ5bNJ9`b?$mggtbDsg9FE=cVSQE_1zs6)h&1QvJ72Dd6C#V5LrSIZ)7M%VJ&eL*o zX2i%`c3eo~O|3JmXu(C$0FVi)72f*9H60sLhe_30@HHuDskW#Y*+t%$4whE!srz#Zs)`W>oGB#$uqjD$vSEQsx*9&f3&RBd`iI-9mj z#;yVKz?FAM&QD-ZszyK6#SXwzUxf5|m%>_(Hiw8{$jLE0Sy?a)h|4TWrB=N|aNK<& z!8~$DT280g)9-;kW7Q{}j&!%LB&)8ktW5K#MzmtiDrHST^q`<)qBv6-0f+d=-N-ufhIr^lqhDnhgb zIFQJZ?E|veR|-3T)@YO0kI7Q8EO{Wh_~tn8uxpGAOp>h2wz7p&lRcK0b6oT2_xI0}xEx zqqoLcXV?*#a_Sp(k$$2q(Y}|Y>SGg9ktWfzhxBydiuP4)7S;mCQnh@12(@nwjWy;a z^!)jw#>s>b*wV*R!8B)&{#>AY1_NtfsCCwrh-Hsme56cwlnAGaC2hWT*4|g1+x9w& z955d}4*nVHA6YkxblHwK)?&w}Y7lu~aTk`$zK3JJJ0Nfaeza>6cZ0-UBZC?@WNkAO zP>LV%Pr6mw3HKuzmj235T2$b)9!jnNxJMt#$-H|W9yf$_oJ{`!{+qd{Kazntr*6 ztgYw499aB?R+ORgf!$owDs#yR`*nzT(p^gjFCI@6=-QsG;W;wo&V2njVKU)H>F9zZ z6EhglGchDC-NbtWb#S%mVau5R0JNR^z`tJ7v&AP>65T?tkCyMfQQJsQiH;aHmLjcd=0w6aWPQlo1_cVWk=0M;dX6e@VH2<*fUL?$qi56y9DJK6 zj=eP?(!g3wM?IVp4{;74>_TLpGgZeiCZy276oo`xtrZd}o%sB;J8m7U`zq_YPQ4bV z0bJ?xbl_u)B4~WKY<1_c+Dk6msvlxH(N3e6E?dQsr{U%+&>Lj(+WzI}AF-kB*Gn#% zw;oheXt_2(j(F8g(f7JPvvn?_$F?W%xwTx=G5J}qhX;zZoUE*^5j4GX9e)Y2vR*$k zCJn`fZraMiy@0#@x+N!vHLR$bOz#e+K4kAKmyMdp@yMowF;TUN0PO@dfN$TYyxk)g zEdKzt z*VO6d%QgO61GRhK9W-gN6C8l$oklO{ISEol$EgTBo_+g|lhHCqm*um`5)ol<%tt-B z4agk-0NwQ6JS{i`6XSFjR=ETqc$#Jwr3$oJn9{Q_SH&2iSsQrdF&1d{Jl%Hat~QGf zGQ|oo%2>rIl|v8B+V~a60QSF*yAdeJGowHx;bUQFz}=2(*w;OMHv~Q1P=BOQ2K7Ad7lBjR2=peR~kIy6mljqoMFi-gJ@mV-1hD`?m8DH zLB%Twg_>6-KuFc>lfWIS=-KwJ{PlZP$eR~MlPePx7=-%}#BH)Aw*}aIg(bHR_21vB z+E0bx)-hXB*DehlnHDXz=4M+kq5|&OySsAEM%CaFGY8cgSyHQf=#{!|sb%AVZUy@N*jZ|Sstqb1dz;slLBo0B#%zzcESg^2z;Y|sSt(Nr~DNb&KZb1Ub; zj_AuVZIYoh7DqQsr{wxiaBh!C8XlRa=i*|vZk&alQ8~y8(nwYNhF|zd2J7bUt+#9I zT1!ESvFTc*c(H`YNR~##Brhll^{)&$HOJef4L?b29F@n^F`F8B@Z)INUjCugomhve zzIT9oi3N+kj6SkmhkY9EEqFGGpT>eg7v4bCUY;4PaB~EOkbe<8F_j!En#qvq6F`{q z`Dx`mVP^FY>j%t003&Mg@;XGySn{J-!evJ*La9ZGQdvVOHU$EA8Xr7$`h&!N9@BhT z94VfVhk%)2dDs5{t^WWKyuw<$HH+fD$Bw@(*J8cYaB%0v@r02{AC)9I^5L{?agbg?7}^?*hL9ROis!dZehSFN!a3M; zX_Dr?p%UY^Qp37jM;qA@2n6huh}Dn{?L;dNbWafk8vc970mj38yH;oP#M_(|TL7T3 z!nLppF8X$vA?2umhcFch$H*)M*u%|;M)E3h0?AIdT=paM>h_eWE@Y`1Y;UB>-mxc{ z>GH>5Pba^>->x+&A%i|wiC#Z71c0lQ7w0v7&j10)u0A@K!qKGKjQ((xgM~O@7Y)wQ z!S=Fy{{XLUrPc*Qe(;Lv8&Tu>gXE(iQVWr^d9Chx38V(dk~l&Mgx+R20zfPs;=w#| zc0PN1^lwa`{j(hmh9-7(XLTi%7cJYl;E(5b8M6ZyUH0CYpRE?me9(xO++*fM$=sr;|3Xdp6B~~PXw4X@ikMqBB zdLuM*T9G{B8k-=Ieii%)QYXhFfz!lKh4(Q`YwNmHva1S7Ug1_m}Z5B#2L#~)I zoI|Uu;Eldq83;+LxI>ShbJvqV26mJ6Qz3!l2+Xavm7`V!ovl~9p5npn->7otEc$fb zX8O}H37~(a0+Iez)UwIsg&Q72r{y+Of#e%}lB%O>gIh&eBh*0_Jv}H#d1-(2;S4ez zLr=!ZaS)n3NF)3^YgqRoE;%8Jg*SCTb;dO4Bz2m0jw!`T=yrkQStM{(hTxajfH?z^ea#d1%za7$0MH!wy5pp`p0G1vDjB5_4kJTFN$kXK7ykeW9@k^5 z&dVN^G!r7k=_w27Rbnj2ppb0$bZ|sApPMtgHQ{>8H@>eP2k}?9ixB`g>`cIgkSH1iW zt!kN5X6V?V8aF_YeL&cumHehuEA9aSgKhX*_NzFWgXd`arV_yjmn$gAY-p(wDLZ~F z#5q0ef!m@s>dq2WejCc$iK}7k-xge$ujLY|Br&^Ev9Ln=i8MzSeOheHjC@(;!cJv_~*-25!;2o!edIzLrt{$z6kf@VI3kf`#K`SV(RH*INPty z5+yziP8YceT57GP~7Kscx*NomM5(eK6oIOEUatqb& ze|>`f!C^cZl* z8F$E$hn>RqRrYSj-M>zcS*6Z~7z1}*cqH1u>kx?e%f>MHYaAv#%QmArl@c0VfZb5N z-2VV^+uU@Y;g1OF{wLJsn>!hx*c3`~+mZhOp8o(S_u6^+q1KO~_%9ny{$DPTlFOew zO+KZq=0+8<#hX|GvK)##*!onO3f%O~H1KFzR9Jd`JYP?@)=Asku{(jgzWnldEzm}1 z5Yl?GE?VT#4EF znIDay5EWGa08huobJZDf-xY&oJ>)*pLcOspszvi;n;cd5AE4}ksA_tQdPbS$N1HM> z(<_fJ8Z`vGv$thHYWvwBa!4II($Xc)x4&LjOO}@y0bA5FC)6?*6B;&VMp6}dQnkph z(z)(yT-Q=XbUCpfB&y{B1i;j|&KRdU>+2G55Y^u{#tKxMl!C zoLM#jb4yAES>TM)3^5{R%?3N9LPdy;%*a%bMO_{MH_fp7^-8#yfYD>-Zn)Dr1Ronk zF`{Kjkmb{cnZ=S%HVG1z$8!PL)74)ed#;0K>H_?zw0KItH_R~;67r$f2+xF?2G=(9auU&c} z29jVR7}(13yX3!>QErSn+DyRH1t;V8v(=%g#~LuliA>LGWc04qP>GRB;{Uk%2`aMSq1r@4)ZC>^g4Iyg!wk@cDsC&XO{+ZN=d7k$jy=-Nz9doD@IC3Q8n6dSzY{`<$S-Z3e_Er8 zZ!MjRH;+ijY=1UehaP}FVG)DRZ=aq3_vnV3pycY1kEKL{0mQi(9+gq{zUS;Y>u1vc z0EDn>xLQV5qo^!6FvMOcQA(keEgF-A*ui+ zg#b`BL*Jg4{{YETrr2X({_L*YB}Z|er1*8jyPgC_j^$l zZ1z#fpiT2sRkY{v1p2wwG@K}L<;uduiYXz+fGJgCWKg2RC_bI`tw-MIE&l+Keuv-n z*5qH}TVGGw#hWusd`6ER6bvN}Wl4b`cH6i1zW)Gjd-dEpb_x`j<;G-nAOr!Bd)EHM za6jyI`YUAFQDeiY_-Z{;1kFagh_TbiD5eSpvl#DEH@|o}<)L>9tpAp~qN+WbH^mQOGs6_y?0$?_BjrtkEly!a}CXx2n1K z>Ly5~jn~h}!*ZmL#3T#(v)lZ-d9;8f(>C)-wywgvY+(=-+A>bdHA1Byz z+o@%gWyH|VjtqzhDo5rdkVnTVKe*_>hdez#v5Atf>e1s$tjfr7!7hbIB}wF8a;J*+ z>f`teS{ZM$eLE+RU7A*ii~gVpBj5Drzg8HQu$pdl(L)1(a6pD<^33RR;hFGakxSzh zh{$7+SZ_x?%x1Y3PxT9;43cJ~+OEub0E$v%frTvw<(ByL-(m-Q>ed3yhnt;^nHmV< zR##G@Ulc=uDs>0f@A<$%OQPJLt58;)p?`Geel z*QVUY*Bn9vUTGN`CeIVbji%2p(k5w0ipw6)T(J>FN9sMe{{SwsfA+5qHbzb}&l=)~ zFy){j-x!KVyP;}GKk=!qw9Ok_k2COdnmHJg4M?`k=E+Ju!BuiTdHCo?qlq4gpNWhH zOt^V+Bsk&P)-`SJ2f+ZT9Q==-mt+GD>#t(rUn`GHQ z1_O=7Ebcp1j^6zo{$jX>1c!Lj@^RVWW>X=Enhd-fDy5W>+^GlKq_LxAXmjLAi5f|b zlErcr5mq??0H{?Rh}(YPkUw%5de$q$lL(AKCP)%R<&R8q0@TZ1q;0py-nkuhI%bd! z8hcoN%hFf7$<-i(H^g|@ z+i~QPapp*XT&9zIi4MyffU6`1M)y0ctYK<-`c9!7*qK=GgEX%r#Urx^4iBQu`tRJH zO>}-g6Gu1HED~fwnI|4}5jjsvvYrR@{!kcKD`TMcRa>R!j+^||g+>(TjRbRP%LHab zgrjUjMUdTvvD~i|e#5Ty311!|ofL*wg-bEpyUf}>Tn_d*ueVb^Okk9e(g}(4Vo%Cm zHar^nAC&#Y`}J2a6c@qEz^36oy;2Q?$?KmSsor}72D0lVk7}TU?`teak{LZxNqK} z)4q|L>JZ0?GoZ?i6l|^3WMuc1P?Dh7?m6AWI8#O8eQpI7|GT)SuhE~$y!IKFuI>hxD!{{RiGe+ofu!3qzCt+7f0w0IP~7kAGv)?IXl^y0)1XbSUt}lMrzP^rV7VSJ?VbZVw&B9;M6< zY_#&~$}ZhPYuCIqnc^(%E>;qwE60)jAdbPP@%QcsJeoaN$(~k`V$Fenn8G)CW;zXR zeqgRPivylHBcA;U{%Mti6ga7xVa1dPCuHVWl#ow7nve9?HhJn?qT^3h#jM-}mhohU zIXA{{)frm`jo+5^MT*`4=}OcMa2$T&)FRWUDaaZgrFEE-rd-b1BLOk92G?tbK&C@? zB~epUHyS?2p!%-0m5HijuDb>-^F@lT(iqCIAni7*=^UOwVn0ivYgWp9jVtNnfnv;& zlzD(#4YoN_EDH7@_xoR2o?Z^Kr%KXki5!R-yv%t4mNyN_vPYf@}T{kB(Hy@aD)@zd{o2WF6EJFftcC-^V&SgU9FlLJtE`*IScu(e)i9Oz>>Y!&_NCnqAC`XRtn? zIP80T^h*O;lNwaXlNTE?C5vb|SYeLK=DQF_Kd0@`C_G!O=|ssV)FF)lb2Ma*fBWv+ zBmV#}J;=U_%dSVOI5|XOXC#}$$0~~@K`K-VBEBo8qN|2lpg3^Xu1IzVGYl(oY{|wF zMpTCU1fmPF6(p-E{NA1k0E64VR3^d2nn>Vj5-H&TMk8ic+sP}ipHSz4NA~NVs5tV8 z3~|9SIAxg_2H)HTALn0gu0E+0ku*8Fc$!vZVUspNk&e;G7yct;-TjEF>e*fobWfGN zl`R^=7Z-;hl6Bc4yWIi-NA7sPf6&)NQ%8yE z@+DIq>P_IdKW;|h-`@JLnA?khv9SkmRsof}3%~hLJyxYhMC{@}uPurM%pqUO;+12@ z!!4)DVl)cv86fssADaIF%=`7u%;@EUOQI!afV8_ zor@6$hVk?I{{Y|V(D-z5qe=C+5)?`vXC^6vRUNV^6vFIXf=4|@TC|%DGt6uGR&7?e z_m#upJlKE!n~^mtlO8_hVP4DL`;G|ej<@_OoMO$Y;paYsk+*on%|ju{AQQK2U=Z93 zYN2NN@2KIt$%&33)w1#xPy_V@7jDan-;X2TZrVlw&ES;w&4e<)h7atS?qk>ZnpnHah}0~`WfWtq3JChCAB4&kXO)U;fOck@J2OEehqh5&_Kg|~u5*A@Q&4I31- zhnFIBk3ccwV|hp!@~4oyuoS~+-L*ygF|&Tv)VVo1SrQpC=Xq93V$R#UeUEO#`wqFt zm2u{Hrz?pf%oHr7ioQAb{{Z9D6xmRm&oX#v<-@C?7Z3FaN@-0KOxlihNhB5)9CT3U ziUhvqDgdkCp2E6;d?glMRy*o?hE{eqIa59~WnxCN$=f<(M6n}>eTprH&=hVeqWK4-x+a~C zkAtDlkvJQWq&1)4tg4Ufgj6|*J2bX_AO1cPX33VbF_CHc zZ}x=1leQ$XjQI00OK;S%B*HkIfE-O`C_KXn7H8QDg6mHXB5hW0Wb2)V4!0J^fW&gIw?zBVCtN zkNJLaFk+(#A;a?a7I2CcnUnLKp?SW4O6YH;R#B|;GA?xC?)UXZ(>QdB%jyrJ>I22 zmWH%I{GPRrNDqDFlv7PyY#mLp@L|O>WU83tpBOM=R>=wpJHrqx_wGJAE2ZpdCB@5~ zR%plKLa<7Mg4aNe%oHi-``1fD%xsu3p@>5)lJ0zX93hI6hu(y+JcB}w*dHR+kS8M@ z;Ff1kB&(TMbX&aL#i3H&jb7u$-+ujdN+2}Dwhzx<%8fU;PPh}}&8PYC`D+H`2ujdY zVQb!jzDWb^?mDlRsl>6eVz~~Ig!5cmFg?U#s17;0;EKNe1&v_9!B`ZR8`y1lmaLxY z*JRl3+vBNfRg9=z< zc;jhU0UR){*LL?J&6CG0KHW=$r%k9xub+~*lI?j?m>^Q1)If^bP1W~5Zh~X~04~v` zmU&hPBSd}ENhg}hTa(|K;B(0&{B#de@rG8XU&~rtcqB_LL8X-KD_46}IritZkzHs~ z!d0tketmy`f#wHY6Q_whdx7DZn@_+)nVB9iD5D|#ym?;OSs)$Ut8HK0i#=t!o?d3N zoS7Qb`8k=p1H}Q_p;G=RDh}t~{{2|T(_iWV^CW3llQu&(^0nDxyDY}Lo(F%6Zt(vA zhw>90wQM{XpGwBaL6JUeo03-@{Kov!s?Y^j+^X;iBUY9kh60&>-KS|gfaCqC&R$?A zAK|xz7e&)#)x1LZ#|~P2XozJs-+3m9Q_U&l&^1S*o+$AK9ztx&l&&^A2?|dx)O)&V zZ-BqyQ)AwbL8b8qW`0BEd0$bK8_WwK3L_WXuV~kgdt=yNZi4C>dh6K&eO@%xrZQbh zq+_dm`D2+6Va*EfLyof@N4KhKRTn!H8nD=Et~JcR5f7--Q|a`R=zT(G^44zu0F&I0 z{G!jbcj$(jqr;3^Xd?4m3l8VYZpOeD=~6l4)J=2V`kEBS%!*9;ch4FSsUoQ=FO90B zYACCvwrE2cQH3n1Tp2qk=zfPeRu$s9}{ZG&IW?7BU}h>g5#G_wUCXbqrF?n-rOoVSWUK ze-A8(z+x;jAiq^1pjdKix$Bv8T~K{Q@Z%|Z05=v-$f19~NeT{m?`o{-q*!RU$`EA% z5qy%02QlH4ut2_d0xqt*^Hzr^nA`1V5;YD~wc_MEYB4zZUT z>A3o4Bk%L$@|sDCFd$iG2cAbCBey52`nH7lxzUWAXmIj8jn{&$7b*wlU(6VX41Fi1 z@sXHzw2-D?W(<#oF4>0wh6;JH_P&q4OnxF5EuEhslMTwIX!Od5Xi}2_%L-m9xg?&F z%U26fJ~J?CH8J`3-6b;GjH=StS;s@O^s2|OMnp2EMmep4>QJM(0f!@-yZJZNQsAuk z;a~|1sGz`aQa{7}Cci<`%-#_>B3#tma-=FJjdqyb#RDX4zRkwq-_!|H$>=1Se2`?k z6Gq7>+CVoO8~47)_xP^0aP@H5mS$vi>XoX>)LjlsP{)-Be0UFZjf%Lw?uX{Ry~X{yIX*dRhIm7e*0Ihuy7%Q<{$PXE%xoC) zJeZ`%o^>R=h(`9t+)3u!bv1$juz4b@s#XSvd7?qpbvUUY*#Z7vtK?(k=4sk?K3+88Wc*e4Kf3=|ya zqTfTP_(oara06ucXDrxUcWv-mjmp)-bMN2U?}9(X`gAbv)sU4;c-{=g3%vO1-q}d-n_xJHuwL$bm>+Od4iGWa+ZOl)s8ltbjG`lk*C$XpO?h z$3XF!wEX`7rOGlyf$kS(EPS%cP*@-iR;YikPCbvqKRqFB-tq2-P2#h1yx)2c{JMOF z$c#j-HYGfAC*&pj#K7_cki-vW+&%gd&TyqnxWF~&ls~$DP|f}JH`uB9>uB)Sg@fXa zMm)^?pC(*9VT|Dr4ao5=@4v`HhH%Sf`a|)Si#CQdrCUFaG%L>VyVONEsKY4r zKuZI^>qp;HY4JQ?qhe~cGNd|Qvx?Yn0>9z5T>}v{`C3F)j2`6qV*4JD ztp3f#SGVL$4uvX`_*X_8EZjESK%z05OE?cB? zqkctZ8%kR%4#X>ve&6d?#Bm%ftuG-9GRBfeIW8(V*~tW{91!Je=G)_=u!$#0_v*+F z1dd8i6JaahPnC)zjzx-gRV}bIjEn(lTwBGk>id1 zMjG$wK43k;0ef|)VaU00JdH$dK9VdcH@g1UW9?lb=lFa1Od5c}#dC>*7Do42lOW2< z6cg!FB1v_?XCF1uXp>I3JM5`by-0=5gz({N7zlf=S%PN?VWXRPP%q!s0pt2X9{o!+ z5W%Rq%G4%#GBky0oQ7tF(3rNX0!#iMs9ziqdJwXIE7oEP^kd4$8<&79(|!I8@;~R% zj2R%x5nzN_0{!;@FpQC-Vb!LW?);Ulmq8OAzInj4(zf)P8b@w<5mW_v=dpJ4_gv zoAcJnDtBraRq+tR1UVU#8D@?5Whg+Td8_4`-~ufW{Ee;l=)j59qAyGbm>QRz+gN|1 zrPte~tw&K9dy4=Jk*r{W&6`HL>~|>s{{V5-{2aNY`h19i&4O83XU294BBda(HR;^S zK6~AZ>l(X75t&8ElACZ#98N)3jsQtK=Z=kL%$OP`m5#XIL7kV8Jjgu>6j4Urn?Yc= z;zvXgRBq@FhGj@b8c70K!j{jOLzB|B!Pz28`B6i?5L0=~s#uQQgrdF= z_PwV=j$s9)kzF4wmh)^ld8JkMBl45|Uc;__T)+@a`FyI!cao{~km(wxtEo&5N73l} znj|B8Mt7=#Vyu?r`*C8rA1mZe9rX~8IVjRfW7>>J1ThA}k|_LNZ;p=P#gR5PeEGQX zE9YYzC}1i%#pJnfi*le2`&3!8#c!wj>D{3d74yK}ztwgE0C*Olf8`&yMr|C^CJ-L! z0RhC(8hNIN8EI9^NhGIqNTl1N17?k0)$C1yMD#{)4#y4@03I>rsLB($7_mNDj^xqh zd7=7_oH1a=!^I1aW<($lEp1Sn;2-Ket-Zgw=s8I>jQ5KY3H1qFn9?|pp&xStOiv71 zO7ZV~`kv06CX(ZBDjHnlWnV^ZTSURmf!`glvYCABly#2e9BnoUE5J||`LajDc7dc% zscOej)hCxq(sa#1WX6r;Gi6CDY*8D!f$6IzfFQ7;@7J16i3A@}tLyS$LW&hJ-)Gef zT8>591(e*zjr!QI0)Yf|LG{M*PNf{$S{*wU2|_^{MxmCPi41^mV8@aPKBg9LtbNi^DDhZ<9*K{H8^VUj@c@s>&DPg96HUUz#-3&ZIoU`Uu@lUS-0pA-4WNJy)5#WGbK8fbmA3*WVod)4 zv7e7?Ee5mX+jg1rLSP9Lkwdu4VuUIOsJT2>a!8|B z(9jc2hB@_UqK{a}{{V5Pk|bPpBylMR)b(3{Bya~H5^+sYPF(Rjg3)vVm8Y7oj|5tI zSv6lbDVP}-%YcaEP(`t0+}(0)k8U~YrmL5OEO~NjIT0*jSRgJ+#5;fo1)Gk*S-!32 zZ7O1#3%*4H*JF@a3Oo=A;*V~qVdG?FWqE@UqecOf8XMRu$mEbo8;IO! zA7DBqs%cWJZ_=)5Zw@sHya}>DPAZyDX@xE z66BM2d=tgj?s`9wr$?kuBjqwP4V&SHBJ2%K*G%)I@r!CP;ZpZT} zvUaW50*7)hckR$zXxl3x@^>Q;_`mHxYolbX`vP`)F5a6NVnnTU72Z+Jk%s@PJ z<>9Rd4@J@OwB0Qv$H2uv?<9bEl9Fu5_5T3ObLu17{{U{g&^$X1iHnJgiaCKcgmwi( z56v^07Uz;%f$BBh`Yk?GSh&odZ~_;@1O;(r)_zoYFsLRt zDvGPP3mBqVo8*NA{p;e-NqM@L)Ma@sk+uVDk?c1;GTQ~KG)mVT3hjJxscLcM=4E6# zc)tap-sN7RBs(}$`F9kf?h!!uJqW_amm5->I4Q!19wuC9W60)Ibzo$gM)e-#gs=%y zBiW!kG)V&EP2AO7WJIEwIViBPmCigd#(cuY#^QKl54f&B%fDPpwiK5mJzo+O0okS} z%^>}~xchN^iR#Xer{m^HrM9JzoAQqQby7;c)Ze-?N3MXd)wEw0dFh)U3M_d;!@p|s z5#MlU-C|cg$sLE=`}E~HnFN8aUI-zD+M(DQ8_za2Mq`XcjW_)k-GoR$C}m;IDD`db zNf%T>`*F_ET;Fe~ z!=(n!of>ACZ^OcoZC!S?WKI|Is~ZUzKB6xBm2H&BHWEr3sx~fc5u9{gHx%Wx@IFS( z-f3d02d9M<`APWX@n3aaS63%k)Z)x|^04vN1dUYfFvtY$D*8vjgrD&4Ae#kxsgdGc zb6d!U7oJ0rkj3DK9wqZyK+&H`92VxeG^5^u>N#|sOE)#}bctZw21H3VXmZhGx$YE^ z>y#TV=Y$=G=HlImr0J?}*1LzP*(!p!XxOAJ*IYKH2z+g*$(q>M&_xzcl^*C}1cA0< zs0cQppO92=N5_7o!P7M;WyQ_U^D?rrloV!bLh~1~Iy%s)UAOKM#ge#gIom zB>u}W6xsmesULuwW1do{_t2hH{v5rx`O~pB}Tz+9hgI!@)YXhOHYKd`dxgf!l97^##kw+p1%8^RS zSJqj#0$+hu$va0pcIvisV`jycxq=gmA}^okM<75In5~9j0$3iR3OBH;=$sL}uqXc2A%!S+O!JN56gu~1yeT5~>e3s_@fWD=>!l_ul@s~`K z!&!Q6v7+Nfx<*b>i(1ohWf1wy5IV|;=AxFj0s#f6aa|~7&N&LM(SjRh^RUvm?pT_(09RR7p^ulR zB>62Cp^pY`_JK+l1%qTG1z^^raQHWT@GSe^q*bWg8%T8Ai_eh1&j?sbx}4pI+=Gz>jW#Rk+n|_3w8t^J?QnI{{Ri(gH+H%=VwGV>QbXcEX(E31IE5w zXK@?O^?u-dSs2-s`#r+ z)3x}aQpJud!iQ;}hm1N=RZ_&WQQBB`0NLFybwM2Ljr2{LZo1gs9h}3k{{XV%Vys1m?T5PR_fW4@;@O{CkBGg~!Lp#{N^CrQywwm4s&VOT*@|1UDXJ zP6ToZ2dP*BXzo*cN;pXx==$(UaGgdhu2`7TLmI$L&ZtBj^Gaa;cf<5Th$M9ymq`{4m zqiMcWnrTN#1dA5<;)+FeEg?cv)?D_oqWX1;c>F&mPCVGplFK6&xt2Ci9z_5mfIB68 z*dybqwNDWUq-ij)_ei_^rFSI@S)$(UMLP-}ueTZOWd^vQb7ZUZ5g;w^t-1My^0neZh7=Kkn{|@zk8=)N{Yo`=OT*z|pFc#km;MV&OrP zkss5|m~x{8?=nUJECUYfxSBrOKnI%?JV%8tg9>3`#T+9xcM26pq{14_q! z#k5jBXxUOt-zxL?U&IcJQ{Exy*hr}ME9+#n35_B{HYVB%R@Ib?90A9E_t^cbrEPmfi(SQz439NFl1W}1q;?qvn2Qa_UOj)9 zal7BIJTIf=XcDj2WWG)^WhixyDFArr+7U!cLX;SJNN$mPTDA*BzWdAvd9!kkGO_g92ML_Bm-Xuk=1B5 zIA#!+!g(!FG?4x>i(XZL7N+lm-`M<=#+wr z;i%ez=f6!!r{(0xxmmdrMKZ%4#w12DBPr_$0HGrp z-zz#)b81NP(jae}-Oq2D>FZLSly3|XW)>v%F>54~eb0WreT8@NaBZCny-5w*z9*L@ zuUo%XHxJsPsifm%M%ZM-lLp9IY2+e!)qpXjcTruHC=29uZRSUwc_LTIXrxt;`kjgH zR04aDd-WVR>m!M!jpfP*YK4fiAt$v9qHJ0Cv(ZSj?5vU$IK@zT-%q)A@IbLvdyalO z(E62MsI&%Q3tA#G9cP7(oA~TV(5FGfzO0++u?NarsB!UJDh7DaPG*oLGjp=Pse!Hq zU3d9a*Zc{sc)EB$lxsOD;jHaBp_LLbA$etq-K3X&uE2Jp)vzZ0tY{t~$4m_)AmFqo zRd|_jo^=eXAtK*z%7REdb6w9JcZWM+;7ro}GUYOPnDK-m*z$c$c9yjQ%>p<)lU-;1 zJ-EyxjeJc|NhfJK^V~GtoTzEMWu)I^pW)98_?N=a=jCY{oSE+=?>N+l?5=)hk+E^ZAysZRJ3i1>cA&D2XdWiR`Jf4nAs6mgr>ars; zZ>v~KEnOZ@KK;%6{B`6S%pp&!APv2l4cB_EYr6(YGyBJJ_?40c9xbORF9bX zkz*_A<94A1J{U&ka4nk|hihT^PadENKK&fY7~Un)VoWm7=c0+?hW#?04T0E#cs}Y$ zzn-diw^+@S7bxfl&CH4kev#K}T!VEJxDU%l!QfZDbzemiY*_W71~f9bk_n@pktSui z5L$vPmLPi)dycdnh{NJC)&OQ6Ki?j9+bK4UT0pmFU3>6N@uV7_Uxt3aN=4Ik97*Gl z44thS17mZGB7tT3qM+4|uzwI_O_8W9vto=rVmK=;*q<*dRb^62l0t%#3$JSJ$m{k( zX}G$+4pt;su*h;mhs>E4$Zo=qYA?y{?OlFP{vqONdQXV67eir-2i0y(Jb*?cpxDrs zB<>!iCW)`O9X86$uKPA4uD(&Iw6TSyEk!I?^;6~J%t}Pk$B({9kU3JD)q|(uvej57 z!5~*r_{SsU!>PzP4~+f^jtRLzx;#A!%vTD3P>0XOIH{Ob@4kSChoVIWtVzQO$|x z!i!LrSf>0aU<CzB{{SuV!+ZVDe!SB`c=A|SQ50dhu1hiZzk}C5LX6+IBf2g) zeN#z{jq$cyDBb;BrxZ^opY!M*Ixaq`lN3r5%brsomN-HrBpdrzbL=`dqcVRo(j+lA z8HV`+=)`#V`D%{yG~z!mU&9Y9o`8B)K~jMTC)N zNG>o{5c$K9c|O9)=eI*~p?8WC69WEWF#>sZ+_V%|d-wOQu1S}Zkn_xvlQ*0sEQE68 z-SN*m2XX8#+p13^9C->BQj!C-4{hF(J}8sNZrvQD+p4sV1bD2&ddG(!rMpt{N7!&j z9QAs9e>(?RdHl7MgfJMH2nn>SAqqY=pJoJliN33qVW;V(H>sN%XwKj2+a#P5@4y%T z04}6&sFNB@j7TFmsP#KbG+@ZZn2$?7=B{~BL+75BJ4(@M&@MFTaq=U8g=h_S#O{{VltS21OUF#_*|=UmZaJNM_B7e@nCsBQ;*DNTJ>pwa9-L?5^YZ4)0M{6DD3@}zLQXCodZ zG(kej?nPf_tG{FR>b6Adk)cD4F^)`eJoyp%a)f1nFLJA?^zAIKz&nUOo_Olc3>hEz zS5WfdPbA^zN_H9`2_Y#bJp1h1WYBMm6=_m0bgqhT9InC$;at^@+@Eep?bGXFK1MH$ z4kQp`j2vQqnOGK%vY`*{=_A!(9kv(?JamM8FsYN&mcrRd3^?R`ckk0&c`&{{c$P^F ztqwZOjGj_R3acSBESnZAQ6L|C>#BXIn18(pn<&MDACwe2EN{GiV94wTe%HT|+qX^n zKBfGfvNfF8Rz}D1JaAhfCk8^zR#Cvt-M9$H>w!}fl;e)k7zeRi3-=Chna~peGk6m(JP?^`Rx|9ZQ z1sy{sLzgqN!#iZZ>_`+K>-C z`+z!m)BG^-Gi2&#%zQ@2VF@Z$$x_P0xusw!c)Py3ojMp(FLb#1od@J7eOJ^L(0L?1 zGeG*5m0*EnVhqycOaLS*mZDGPS_YJNzkZ$kG2#CJCVV{IPXx$;Owp|1FO=xS1Tmh+ z(|p&p1JRsKEo0v{Ly0`b8`4NaY6f;4^+|?fFMMU7vCD&;u-!$|lK;%n^?@AdWJ{&tPlb z_~iG$zf`5mk~pQBc$K78R*?ZN+le4^#oxn(NXm^?$>j9vIj; z6Ka@pjCuUIMkJo8@>zFnY>M>k0=C4yg}>`I#J*0wfu$KDSWH;Bl6eAH@yo><0c2li zYUhpxa!Dfm!Oh9c#Lmma)2GVEiVf+CNLlAQff5g!0FAZ|+oA~-6`_MWg!R_|EQ-?| z(P>n5ZFUn3&6>#BNshlvVk|bh5T-TS2qkU72CPsO&=Zr9mP^Rhb9Af&8+M=AhgFbQH0kdzJJ83FNUCL~L4SR&GSc!?8y= ziMM6uPa3Y%Lw~6EE3|+B;2r@y^Z{S_Co!`JuQg!9OmR@^IZvqTQpu;Z--_Gz%7nN) z5xeHDhXeccQkq3MIJp@(Aplusl%q*8^&1XiOrQ*g8aUW0)e}6inx^wsZb` zeZG736!YNY;-*;&S)XieBi7Ki4R@kQJgE8VwJWv*Te95Hvl2;Eac~0RgvX97VUZ@~ zMhA_nWs0|Rc0(Jp+plo+)tOdIpv^3`v0nE6VmB>t{EiLK{@p<~e7P$cJPGB1SiFiX zl0`1w-~f32N$=K;;r(yHz83mu@wKek<@!+$R#rxs^(*(f$Ol zMv^!Q(%%Tw>9yy);13dq;rMEK_kBW72;rE+itN&X*eC-1$30kw!=53R7F=x;!dWqI zki^+C@Zb|$iWZHn=xcuv zHH~OT4wI*}46nXK$Uug|Bk4rF6dz0M!eDyYu zJ|4FW`kt>O^T(AeMk)0OqxD82lX5EuAC=1hI2H#sE35MBz8@0FiI0_mE^|vRI4$Ld z0bDR+M#$oU;8|Z|&3~1h=9?+YhOjjLwyS>`&2Dp22Ft1~u6Uj-S@N|#Or}OTydoNc z$>~-BSw(tYkE;D$4Tr?qxkCCc^9ED9@)xS-Yf^f5P#*h7G(GyalA3hcV+U2qI5MQW zOXRw@vzVapggaCb63) zG?C(vs&w~RJo+Wr6CYD#NXuzfc^Cy!@?)50MY49XfK`Rx zAXg;uchcdNC=-$7&mYE$azIs@BBTVg(jtgJ~+me{JqXDM<9M8g`>1B z0s|3e?ngx5T*Z-^C&`X67-Njo<7{TPDPlOHJ9AuDS|WWuTssUfWMV6C$A)NCzyq=M zcH;j4PTeSYpTI!iHdlmI@wEuwd*XSUmO)*T?5huDx*(D9(I{5|;8n5Tv-9ob6(2_3 z)Hg3t+2!i7%yI}ovlUTf6XPH-L)Yw|$V+j&jBV2byS(Vh4_a(_uU|2q{ z={5TGqh5e>VY_rcjxv{Hh}U9u)^zzH%sU}4MLFHISa55S2;f<=KVHM0ma;JNq~6jv zn(JvGAq)ioMRVJ~?a_Rn739mJM(_qPs1dSCJjmq?Ij0a@4{PosL#R^4ju+B_s z^0J>WSfDGh>^^wDsfViI16^W0diPxR>PCeqdD1S~B2`?dTFSlpfNpz^2qMS9ubx>o zfV#GUkRXYgPb+i}8MWFyKoiX!%17wvS7RyGDA|-YOy)2;a zkKHJCAQ}ejRfEtSS}0(WCetOIB8|Mz?u7YHPvvVItpzmQ?4Czb$vMWHtPi?eT!%?S z>#|B#ZRl6ns|x)M@(*1{Jn&@3QK$a^X%ZD%{5j(Q)Mt_Sh#9Ndf{u9UmchzK&WBzb zQ0FYF?}aS0#@JD=DUlT#9jYTT1vJ1}6x2ArPU|}Kb7JtIBXq6_rh6Hjx!2Z5N4mL!I9;VUb#Ln#55U9AUSl|w0EzfQN z>PxbY3!+LtrR9xxLHb;w2-LK#kAssdfEprcPdpM1&_}-=4u9ed*)zwDkA;UOPEg() z6tOP&<-cHiSoi0O2iuvvJ*whKsAVQ% zLUJWg0}`w5#S{_3l0)%e6MqAsIic2@YCk?`jU-=cBFM2z94obgsTaS0rLDGy1D&U_ z`29Mgk%8voPX);=Qy(zIhhbK=w_f6@IY14XWfxz52Ic+KmJqJ=A9{Bo$vtnmKe?^t`DQ zpQfdqFPH!KYwa0uq_&oyC!Jy#Mju*M+NA#;9Pn)MOf0!;($$KR~#wB8(A z?Y{p2y_``&5C~Shy!wVOcSY%uklf#RNiJhy*t17{dmz(u_a${IdD|t}>yN{*E z;fk*NzCk?&&%@5q^#sk+owmt3s^nu)Dq4evP&U&AziT#En;mR=lpb~o#mU)`5h0>= zioxxC6aHS^E#hc6(My(?8E=V~laSK!wS31ctV<8M08rz_R`2ou+t(SDQ!8i#HxH6_IiQWNJ18dyXs*e{O@#rphDpF#iA_9C9e` zHC?#me!UKtK*jojo2R?!d27l`0ULheh@vl=JPwEDXY1Mot2B6tkQwdY7lmQ&e75wd z_uznR@zJT%buj?>p%*pfUeAXMF5%39Cj;`C5C&6U;_v;BKwH2#rORXL8F+ix{&>Rx zzQBW4F1a_s{rY6nyltfF*(;~&SfO$lZB=DucKd{GPyUuar$*zz!<+IvH6&YMU(zE&W≪iNsk7vEc$&I_A`+YUy3BCvGGTqyouKv7bE$m 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Ð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[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 z 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§krIeBLx+Fv3_m@PK%!%I>RZd{$mfw$y}>Kyvg zov`-T&puNTlY4jpn^%dyQV-2u2xj}({0Wn`Y-9DrT&ayL{{Tsh79e*gp2MNh`gC0RUTT^+WRGa)aj2M|we39qqoR1i zDD@@Nag5QKypAyzA3|eT#VTjVyuH6NJVYdyKTR> z2jp}2>feL4e0+SUQbdp}vFylnDyAXk9gGwUBA5eLRoGWWJWq>Sb~bWIQb-z=qblV` zVoIOsBi^~^@6uA~^W@_FUY{6>8f0W<0a#xpNj8Ow6Uechb19ex)yXYpZtKw_1VP*+IIMB2bK)@pi z$EG(w;^3$tdjnni6(Z(dZi!Btn&J+NQPBKenuc}7y zW2H@7UH<^ZdHDJs9GmbGWoch-;WGku#;4hNJPsO(_T?M-hnF)If5km zjCzEbSnx+Ac@C^#xcsQd-@9U-!9f6a{H#xIxzqCG)b-5Fyr>ckyhtO*bG1WCMeQc6 zZd5c)@&fd^rNN7+O_E{D%fipb$1-EAz&uYnZe~U!n88$Ppn2QaUr+M*cTmF4#m;qx zTv@TxE=IPMV0h`LVns?#VK7_jK2>T{$kPcMQkG22y;Yq<4>}xF zdjgP>zvp*-Th{Vd7fr`lm@=`DES}z%l8@Tx53uXKM-n_N{Z|?X`iO+Pppc!r-5Q5t zX!?K5bw*5t$3c}cY^^;a$&rv|CRQZZD$8AEVC>!xFOh8yl5@QdIXN+k>8%3rB%ZZQH<34ZTtkI z+b@Ev=xBL7xgw!=UjlI@$RJ_PN|Wds36LM86=Au1UyK^j?j3j-Fv=vS5>sksq>|h zT-gh(NC}QVVtC^H`5$ftbSuR&&6yOQY>0==EiyY^=G<+^72LBQ*P@zCiXSOlI120e zO%)fx2kZc%c)tA;8C~^UTRqXI%9k_-N;jiu68MK+(X_*klj8pXG=_Zik%b&+0!=8| ze>I}HuW%1eUMcau4xy#PE}4}9({f~4RxEsgVly(X*kbLnBnd(~TBhI@9V6(vw3x>5TO&?vBr)SV%ehXTrL8wM^;p2%HtRE zk))DOksf~6ha!GnM`*U~P*?%5iAL}VyBrV*#-T|uC(CDzVq}vZM~pRX3OOC900`~c zx#^L7MX2FvQ0dxkO2abEyA|3P2k{btr@YjRU;cw>M%CM`+e(scQx ziW42laW9goxey9#Td&Rl@4+{B($9x8q|xzM#M7LN*BKH?=Nnbq`6zloyEZ{KYPw?A zH1?YxFHX%@hHPNzuA;me(Jei_J5G-I6+M{V!yWkC*X!rg4AEsnLv4n}@ zN#ZT#tI#x9a0%~D99OU_)P5n-rqm+GTy=3ExZY-ANU|!8-TSLiCWV4PzWpsWqm_v4 zx{2JXHU*+lL9w)0uuj!re!%?oj=~x;kz$&r1F7qEVE9S1CzgEd*>a_ha;+jLF2sSg zNhX0CPhcz`w^ZiE#L;2R#Zej6aivDaY=#A25z*9zLJGU@Wm`43%Lc*Z6B>q0GRnBj zVm8+#y@&&V!1I3>_v-$P4zHA%QisU;F~XPh3km@JtedZK()A&dTwrroW8Mz&xeL(z zH+%k2dF?BH0nxh(xN)S?H-OJi8p< zq;tU?N8w)!X|fn*@dl+3mPPYZ1}Q;1sepGiZ^+;tJNNC@jM*A)qlPi^@uKo%2I2Zv z3+^k9^ zl10bMXbSIGQby+eNaauY5zkE8&xUlbr<#2-G=_Y68KnG1Cty+yZo9LzkB&(^o{=>i zp(OH0j%3KjEEN^@i=`l~f;C|$OA7rDLM6x$1LilF zo0Pd*1b`@-@7S9ksP^jYGaPBz%Un&$vLAA!17^Vt0O#~0+;p}H{e@<`e!eMk=}dUC zhDOETxAD$99lY%yl+pL5O0GuV?6aMplb1T>W=-{T1Q1JR$ymP+Z|TKXdTZ;H*Gwyx z#s!xm(m?7xCC6r~_TM#Q_~k1BaF*hUfKhP?B3eS7x)!1nv}$Kj-rFyO~rsZhi!WieX9 zrMEQzEr6m)C%XF%gGGTZYhGHTMw^;d9i5MABY{8;k7?6SgwnQ}?zs;uEYq2a02_7k zKQ{$O9^32j#z2DLs#JM_MO? zv&ZvoZ^-gIi7}&>dZ1may#(t=@gCm^;NT#j zn&xh!;*CSe$4PLslO2|5_OyVTQoXlW=iplRH_;p|I~NsU5-Aa-kQm(o^X^B->QBE- z`ME2qGPb1-n0&Fd44K7>kB>zf@5dvqaxftJ9PEf8hYAScw-AO<^bLBSxxaz&((%}U z+D9lI6Fb#2X4QF#HXaTyl@mo0I{K9v6MCL`+ANy81lN8CT|bwqXF~>-CC#2F%C0;R zi4|1P{Dn%62iyG5OS(Qg>sr<}Chs9OoQ%0-2k_%xV?diGkXIzP-1VgBIZ}9IPhqTT zsf|4IOFWUsFP9tzzxha(2?_uKpVjsq7MrR#=W~kepd|cX;jX1LOEf+kml(8#5(&{G zXBJPG%GJM?oi#`+vE zMJB761HmiOOOuif4|B3RX5-tWU03+mG_d9W0O9Wl%|4L6ftuh$yc_jU2WURPl6uyo ziNwi!Wbrb6?fF#f!3c!k!tE*uawV2LO-ffykjyr~nCx!+wIz&>PS7lYSMSuicks$@ z58_K4I*UOAqN&BmlYNCHqi#D%Y)RTc9+A%{r0k#LezP_lP{rZAm2x>V<}1d_L=FOi zdm8Dd5BRTy-%I@e0K)QN<$z?7rA?skL6ey>`m)N8b}B<8e7KylMS z<94!}Z<$}i(r|R#nX=?}5<9l&n{BD#P1!#ks=dd4ulX=bDi9)4IUuZHkJHdArI|cY zgmJU7qtf&CtHBc%{P6|_w@9i8qkJIV?l_R(V2Aou@?EIkb(?n zg+RWo+m9+$d7wvGW{=cx>@KPytbruAbnm^6&z0TB8z(q$FfbIEvZO?-V7ZEhy{szn z->Jq1B!Vg6gFLS_E2DZ<7_9>Sny{^S0!Tcw zS3Q8mb)OsftHgMixRPb%L8ju%FvG><1Zib?92ytC%W!`v_~z+?t6%CN-I*}nwsoSp zrq-{~==oCIT2vz(1=?rFR>+!APb=rw0?GWQ$6;MaxD(^!FPEoAA_}Ui_|my51uZJD zB#+at%sae9n5WFl%a0!&Kz0&NRT!}WOCL(v2Z6`Rte8)zGO zZN$|DHczlT*IGmAu4c6x;z0K*CA-(@6_n1Z^663UZbs}0C~|Lx?R_X}{yf0L*R<^? zP1CS7EX;}gypJyvaL4s1qeIrl&j8pUUs((u8Pzi}W6jRW&&tA@ZHY3>)gZFFfUv}H zNHlD7+q-9kwCxv3%Eida$jHvfNjF1_jR|)oU9lkgPX?}uARoV1W*Z2`Iq$63MA#9o z<8!9#Dw0KjS`L0sk()Fct{O!HO|mE?K@i!#kgE<9@$PxM;^_2{$16zCWyu!NVmaj4 z^cjOG?g0gT!1)KH{{Rwd^JFY7mxU${i8eyMHN;jq3)miGv8h~;)WncE_`a^`dUmxA zg`22JrfLHR8y0-IGog>tixBm!Ysn$iu9$j$ zYQ!W-Cs45FrM=4&doU_3Zuz_Cqk1=k9!*;pI!~k+IQ1k_IP+3h{+~!;>7osH6hCn} z?8qD&uLR9HZZ5JD{7jNo@SNFrSu#N;25vlv2yyBYF4O~W9;Z?l^6~j^p1(c#raV6s z%QTvjWIkk!XPQ-Qj$V`+V0kyVo!$7p-F~Xbh8gCSGT;(O8_j|<2I~X_t}eyN*jVQG zf;#-8gO8i^+J;7261qb!K>%SQZ+G4<)n(jm(kDlF5|}^JymZ3V)+v?X5{5gNRT}6 zcc%3QAlUic`**IJF>;z2#v4VuaT2IQ=|@M5o_lZO^8NU}-3O1w5S*ElPr&~GXZk6n zjir&*)wY7gNFJ&nUG;VxMk2F~AmTOEwint*Q7LfZ1=re7fi!H##E*2C)3Uoy4qW7g zSp2}m001$XTIX=@)EGV;#D;8z8fI4HV0Qgu3To}cdmefAJat}A6G*W25z#^CE^CZphP)a|^6=yz+y2QeqF zl*N^aj)*~zGZZqN!`8w0HVu*wd^lk?E5NDhsa9!xPVZaYL$OlLcYO8^A~_pSlw(#$?6 zi_Lixh8|4fbLPSYY%~ZcdGwx09FQz~9=uc;DB?YfB9QBTkPVMg{8-|7F2U4 z40Y_Q1S)w=CMd$6N}cktTW^x!ThUKV{kSTA=za%N&xH=Trenp3$g;#GWKt|Z=F6}D z0FrZIlln_;91}rvTc zK8|@8YDd7YyhA(4u|yrGfeRR?^7e-MPVC&2z z#g)@*Bf388NfFAhHAmDtSg(KY(;gp+b1~y@=D_Es(9y_P2?hTE#6AB2Yxn35NQH7{ z*vuh2n|Kx|AL<>AT^jf6q{9ugMt33gZbAz7yDRbc>8u@E^qn*x*Adq>ceSn^;IvGA ze+xf%np#lm8H=eDHxtc@Bkn;TzgI>y3Xb^Ff~>2&H$4`Ih)`t)`^OGgt@z}kFrQ2aJ%NHxeRZGHW^^p!rK9o(wWPY%9z zEb~e})pPlHHqf@$J7@>o03`Fxe0-jwd`!6KEhCBX)QeFV-`~BS5AXf@r<0v7Bf#2p zappxTw&gA5NRBMk*4I)G2AAKespGt4V!4=^c#ImoO0q5X?hicmng0NguT0tIIN#Ut zDg`$k1fx*k;vAZpvEEY~MxJ>vo2%-Vzxa0nvU4vGZW~`a#k|8eUk{0|#G}Khs zqhw#mzIu;G%h9uQp*c}LW-jZQH0id?S8nbU*i-IF;;*+x^{p?$=`5KV4t}T%ll~qS zRvPV%4*+@ML%y&4J@5C>f7EbwELcI`1OEW(6CNTI3T`50Q^(TrGce+gJxM;QLc2ur z6fqLSd1H4QM}5`@{OBDqfK`>6Kge9lKp&WP;_JWm=w^S3urxLDX36@jfLJm_o}=m@ zf$v;=^sANQ%*lf;1{6?xnI*Xx^X@x;uUSs|rCKj^K70ZE4`fzQbMFb!a3(mnsxDW@Z1o_UsTi)c9pb*RRSpX1e5)`>-k=n7%v1mhI~pzvk?-2FWsv7 zKLeo_<D{c~$mYe`^})|)!AjkiJ<4jHqb9(G9x$2njHtmn~k8myoru$*Ulyk)})KM;e)B**Baw zZe7a7R)^-GSe^jdC=z;2Ns4LMn3Fp``PG%wepus#mf+DosZVk`Wbp*iz9M7k*|}M> zDQ46lh9DG2x)uXr0H0W50)|6N>O9p61ZVknPD8Bg2AJ7Wko#KQr*s4_2hfTL;>CX8 zE|!w6#=;q!kqp|LvMTvPmj*~9U>L#zmOtc2$8Vmg3B_NDj)(`8^3-9_xa#{{T;-|e37DggL_Ms7^wqqmm0zskG|v0j)El&d1OMe z78Y0lK_nJCPrtW3a({lDbe*`qA@JM?iVPVNE0ty{%w$X5M#xZywRZ2-9kE`Y`z5@| zrIR-&Mzl~(6pi5^(Iz9MAUFb{Qs zBOqu#T=5ry@Cdk%*gL&8v{&ae7p$lS( zX4&MDla~mj`nPRTLId)89Zu{XKK4W#mVAvIim#CSP#w7vudFYya0euIAE+H%@e>oN zEO}*!dcb18_0I0>-+1L<+@IW?s>YgMKNdnAfh88Z#Cz__KiZ|Q2BB&4r^T6s^ z@(xTw@hz}rUA zT+~g^J^uXN6ezSK8Pv8&f8WC@qXS&*Bp>p+>}X$6?@CyPTVwZm~*QhgP z!lYRbDkJ4h93f0#?pGv*Q$Ua}n*efapG{+Jzl{h9|=+rqE*dc8Z)`JDpP}8*Q?xD-@in(KMUe&Z<8Kd%Lw}4rg!rZ zyr_wB=C>lqWl#$GNGwen>*@B1F>$7io9SYvpUDVjhL>cNenQyXEN|+rcs2^mVHZPu zMHiO_jEn~5(-fMj{N(=tr_WRlAx6l{`pj%uaiSR!B-gravXlyowSi)6(@>>6@&Ui7 zPYyf^nRrp;Z`0KyGCKx>q*BE>pu}C+J^Noh4%g9BDiu&HBZ(XnPTp(!sP+|J!}RLy zx|o9s{)}PH)e}h0uQk4e&76h z;}S?`LN-Q(MiPLcO{q6#*qY*Kk)(m7Se<_fS&wm66r1+-U4EzIuHzA;?HjRB z^6WHf&=davLEo<75@6UjDx{X-(_P(#U5aMJ;(Z!A>aSV|%lO$$4Whzewi57eF_r8QRvWBi1X?WwmL?Xq_ zg$8OzDgeH0Zd9=M4pj`i(a^&}`nQdZ3H+5lND@e?wNx2dfm9M zdRra32a7gdn=;H~Y%I)I*(#MGqwX5VdhcVQm2q&n#hS7)!yg%J3~n0RI4E{kmbERLIleSG~%7 zz~q}#vAfXi=>xrXB+#ydJ21y}l%lI3V$LdvEkGY@{@m9?XLVh!?HR-_qxx*!9}5-( zI%-?xGfJa;MHDEBb|~Gv2As2VVV1ids4^D}7=(>vwIEOy2W$2LJ1a%-!-7w8rnw!(_UhD&7Dgja91R+2@iZ`blbM*u=C_oG@YmEo5L;H@yeO_u zH-tSx=SFCsCk>^O9X#xWfy9a%c(m>qSF!F_n&-b(JXMOPJ)(Hq9VN?>J)>(CU5ZwS z3Jn4PpgRic3_mI@8Ot}~(t{g$ ziomAZvTN7^J-dCn5fM-x2#r7EAqAf(BszY6?XxaSObB3aVx`!t2Z8Q3K#BeD7GiD4@~Od9|{M&oLm78P6mU5{?v5zkC~j}%Ts>X1tcv1nG; z%rTAvk}Phoes8X5kfGYbn^MwZ%F*(5oNU7;WLXhQHp;#8Q;TJ#R#I$%$Yb%_tv}Ax zvT+U+)5oc$oy)pOW^yEUn)xNT=aE)u(dr#8Idusk()5fub8<2#GHKC7sOQ}HFf-B>Z{fAm6r;Vd{gIvnUT&Uv2)S_gAC(4#J zjz&dd0=XWb6qUARC4m$Lgh^wU3nFBZU`Lh(a~eOVY^WVb_&lkux|@T<6)%>6KqkN!b;tU2DERBd69!3jY_Jb;7>z*w%ha;z>#S+nT8Wp+I$oa=kQ371 zj8OqMeVs>dZ?{2?IEj!MqhiABK_?a8f;s4P@YrVw$R}-vzADZzVR)I9At264Hduh{ zPrtWUS6p-p^qF!aBJCUZ2L1M${{Swh#nB_k;w*)p{UE5@T=%Q6KkL*}Xc^_%r^Cwu zcn$!OXnuyz>^gh14omio(pA{?$DVkgdE>}=wg}v25~#%XB!EHx08gH-!R1OMGGn)z zW%89wfS@bh+nXTORd7M~9V*R*Dme(zF*RY%&)A0oy15x_99GC^*k798!}kxD-drkCYN$XNd(XY zRoAzEhG;n1Iqfz?QDo-n_%X9(c@l?_RL3DkreR@9azzdRJdtr}`E8SfktFis#_*Vw z10h2u{lb(5Vow13051EEj@Q!CI`>nN!5Q9{1Oo{u9i{)3pqrI|nNl4<%xep~+U>%M8*2pDMy#O3nmi5o* zc=+qa!5&ZvEQL$%3n(h3>bD9tb?;u?S-2b@;E+y^ldB#+E#B6vj4Ufr0$M`jq#txc2ER1&Zl|RTD*ZO&pr&@0IO zRrWl3Z{Uw_+pkk1d;uTQhGkvFS9a^LIOm2@-m3ZOqgc|iW{QF)ps|{dC4UZNP=73< zy>vatJbv9SNrf~~mf9u9XWBXLIi?>MM!!zCDdK438F&YuUZQv#6;UA;@cyL+rrumJ znD&KPwhg&PqoBj6$h0d0{-KZ|P?{O7`SE2KZ117t&$@20)!Z zGa3Z3UBkCE-jBcc>5xwjr(a6a9O(Elf)&d1>QH!Kd)52<^qp2ZiSK>7PVbGsD~O#F zE`g|T%1w-4CmoED#uT43a_ufy8w4oii|6&C&4Qq4ZTzlDwH3gM44jySM(#l&l}Wm^ zS5L4~J^IaH#Rc|BCUUW1>4OEC$KSZ;kDqRu{7I6lq>L5whHThCy1(VhS0E{3FOpX1 zk?+kD)3{gVrd&n3(`L>(Bx+Ly{L=^Uo5K?Li^aK+c$QglbgW$xeM2rX{#0TqWK+14 zKmy^Ip2N!?)z*lAin=F;GcdHxD@W6_H2f&%SQAd1D@Fnl8^m_)D@5!ovP*1(9xbsUAZ;pE znTvXhHTszRbS4cuSMhr4SUA|Z8I3g2q!XmfBgJN2J~bG!XG;uikB=&ffrL*XQ||Hs$R5Q9bH`S7zY+fc;QS9KN#CYrY6Ws$IWW>q zMUhZOjA9HDASe$qX7;5^>M1n~qW5Uzuxe&&I^-S4jc3DOsF+5;;XcAh5$^cE|RjR2Zg#ezJGQ1&^q2ppftYlB8<>g4S%cNrCzFw&$1coZ$ zQbNsO0O!yRp43<^6p#5`;Fl%F%?TwjG4yOaICU9|WvaK}MCQ?r{$b4<N(C62` z06~q99wx;bom=q}?_=B#zfQW3ggiBi;$1c=aI>)V+_`TmY>h*HPnQ}q%&0&}y(%ly zxb7yqa+%_72QN&apgLABT&LDPW=%B(U_@+-<0W2`$H6{EDp^X!k^T z{!v)Q9`nqSsAEX~08iov#+bm-;RzWz49v^`x;A(vto9@lI*?>SxS}%5rC||4wzi*8 z@9=hlEOxGXb%RClzkze};MZSQ@lHzPvd+*lVZibQb{eMqv|tcCXeCdo6V3#Br!%Z6Bzod%y(iVDn})V=lcg6gsWAg zk^mddoFINw8lk%q9QXAoQDts+Ditq2`U1ggYE+(!~PHO=DmRg15wYGFDhvxpCD~@H%q-y zY0lGCXO4aP8);=A6C!WB@z&KtU78J2{80>SXynwSRE9P&7*U1sM2-hP6gcCK-Fuhf znK5GWw2+Z-Z!2!X39Blm=<&l7e4aY%R!k>peuX5JUD<@$E#<$cv8}6M_Z;!ssC2$G z`7#;Ul8URkjBHDDQ~>!uKF0detMw|N7E(D!ULIR?P|88qa+fP!)ic@OKR+SP@=;mM zAS>Rx53sJL$Ii}wN;X8B)sbUK4N+5L?cT}j-50|-n%<@`;f>)yzGSjEu!+T=V1LW+ zT^Y;J7e~sQ6*4jM*Z|IAEL3o46GG@wKHT)a7M*-$SZj>)R;cFEZi);kGei>oRzonI z6(o!u*BJhmYv9oK91bjWNpbTh$5$Bf$BY;d5)_R=1Gr}He&)~Lpm`D;a={!)B7j&a zrBF|HZ*G0NpJCBWH&2T#8eLygOkM`q)TZJ-;g1}A{{WX>jm@KjXl;6cbGh`LsS?_i zE)+6C8i^>*rh)STHGS+3y3#URL)GwedziSgj1L zq3RRrGRL-}haNdt-)jl^Y@dET@1h67I@H)%pG~1n0g4h*e2j#N-M3c>bOB!Ep8n)l zK&^=SeM%$>l3?s3@QF^HMv%J_%a=Ap^W=t-R+>g)EVH$fxO?)%iy!6H9|`J^!Q$Ok zdF1n@f(%AT=icum@x7srg_;G0Fy%`N>4h=%p9{p}BL)ew8Ojee46)dK<&=h9s!0Ho zTdIc_($|8sT0Lh}SaDdG&K$0SD_yGWzK?K8KW|Ar$5|AyEv)jwEG=%1siv@iOzO65 z40y~sd;%FEU!+L)$tL3ZRP=&D z1&aK0W4ZqTy6X3llbMI~5=`g`a^XTM$W*U34>S+;cD_6G4fOU$^3b!gi(t`mJ^Oy0 z9)&_2V^wE0q}^RQ#!P_H#EeM4+mE07zM}qRlO(CScLL}T#d#e60N?A=CxrYEy0n3_ zBWXAKW5tFBGP`b~YP$=*KXL~>Zh8ms^FYus#B%AdWzNIX62>KGsvDU5@;i!A+RuKR zINF$T-XoMHrG&#m{MNdbR8d1S47lQQYEM$HaycYb-ygSKrlBf0Qe-W&dj>W_^IUen zw_mLC^~s<)coLj^r$|&ur_E+IS0H%V8K}=8pdo^8YN3z!9-)8f7k8Rk*Pax zU4k{^X-LxV-~OC*#jF1S3N;KYuRjMk$%nXZXM(a2Sm$VMtylgqO?>o558)n09<4Mv zGNw)_Pcs`JxOK=p@Sp%s0N*3_>3`?uciIBE6vJ~Qkrerk;XL`75V#89`am~fe@@+7 z$I^>NUSNwFLX%rJm|0|H1A)mPH*flmv@_ti0>vH-?>1gJ2g!yg<0=^Xu9c5#_vh!X zX7IKqm6ir9QDe>J#&N`nz1ace?Gcs%SWz}WyRbSh@~WE~1gWY208o_1n~e#^Vr2;` zqch066z;GBu{?68gU`27=IQuCT!_@P62@b+mF%YAO+UuqNFMiGbA2`FFh`{6xd%|w z<;cW^W1N8?mUs&ds>-%e)b3tG8s_$%W6Ot?IxK3< zdt{V33M=y&94I_+ESe{=9X00Q%_fZ6mWIe@fjrr9az~oxG2P=U!Q0CftE)c8q}){pf8S%Fd8 zp7+i4P7Hk?J{TcM_0-A;M6Dv+P70AhSJbQtG{DgVm9x`7hChZldXmAJK2E2f5m$`H z#!O;JYTOt&APxl(M}MBISpU9Bg9gXmor<)WOA+IsR?%(`ASBNdk)3}s9fHEH8W zq)u$D_5<3_G%M$#`e%c3GjUE*$BU<9Jf2!hlN%tA*Q%L^s=gIT;QV!|Y2Ef1G--o#)Y-T?bOK1VT$Xs%12j>)ILT_D0wFJBZ*Bpy zZ{MLm>kd8KEiHUZ>7buEQIg%~ELLq2XU@pSk1Q08_7fNcFa+Nq6Gy*pqaGc`!;f~M znLNZAC6AXFKjeSUt$S1PFNX<*VbSKwkt7m`<$ywswVH!7lGSW@uZ!Sxq5Q@)d~Nzh zkYL+9}nM) z;1W<+=RDXf?*~K9)@O?UXp-9r{7?8#E+9P zhr=3VnP<#)GvqNeS&25p_U?Hj^yto=r1+mE2FcWZn->{?^7cpm{QQDVpVSKb^lwL4 zaNuUgKyhQQ#*sktTfdhYbLk%az^-=_&~0PI?75O-(Vlt^9oNj15;?F0uvgK7| zd8NuRMv@jZ#g78G^!Gmptp;JKwwL(Y14n@Q{30~C9{K#DF?fGZ`f24|X9^8V7?X{U znUfm*ONC}C3KmU_f!50a3n;tbg&}f6jN$k{PM0i2pOujo zI)aW?Fy=?>HaR=C-ypE$djZuwYr@Uplx^7%tUIL1({ncjIg4Q=g}r-K(v|j61aBbn z2U)dfng_mh)2@i|M;U6jxv?(fX)v4+vFP43(PzKbM~avt zNLXdV2MHEHH*3Z0+P+`}lgYAZ_2JWX#lXVOIFkJie2lo$1yZvzx2P|_$G2h+ZmUBM zWHQQ2oN*v!b0h6i%1u=Z+zCG3=h&W$h3y|KXpm%b{*LL+?a;kH3HJ zdh-IrE#)hE0|#E-f_wh}Z}j{1J57z78#XIa(GHup`E}op{l|ZbzHY@AXc-BR#6p6k zwefxa{QKA2s03)P(IPgk+8k8J%8O8rVU;V#Bv}y->z^cPa{{y z3dp`nNf28*ib+I}-rFPx?Ok^HCN?5vLcPTfERT{r4bdP^9$~H+6=h8v=v(IDHt%D*FaJjMRwYvKb zuHpvNH@7&-QJFP7SlVQW$s*4d(Hf9hO^O87cLVhYsxsp&OAnP4QAg_%z=~QUZMwGo ztf~8L`09NxM9PtgjaB1Oxuh+%2k+dTI}Y6z`fSJ3m42&E#Ktdbjgq03LqL!KCabwM z*mK{cABqO1Rvu_8xX9Sq3O(>>sq86wm3 zky&0jRJ>+k!>;cBSzc+E$O5 zB#zODp<;~1oPesP$C+e`AYBkh9r|&={t0-~0uh&$rsD`QFl2Uu9ZDC<@|u;1hj!vr zn_=y=j<@Vz5$N6#hfWw+A5)!^h>^}BEFN@6jn-B{8D_Adt*VFv)zWW?zl>UzpsNN1 zx`vmImB0Ognog3|`=4a{M7H-l7w0QJY>(yvDSEV0rn_YPj_d*F-TK5z9!>bQ!U7aiU2C8AV)4g@$E2$R&2zJdmyT^tE%-KggtGUnB5_ z_PZ<=r2haB=S7nvXW%RBb{m#h!|qmH+lb&5B%a)k0Vc1gaWWS(8zMGjk-{vg8pulV zTY<6e6-8P904}a$ct0yLXZn1ol*T<}A&{!qJesxnJ-=>xvxVUdxE4TW#mF)SF?mj3 zo=vFv1Yi2}z^cvYZefXpE)@Dab0#$2ehZcoqOl=7z;HT@;WE1PSZ^uY>vC< zK;44SWFU|`a!(?^>(Fe^59KeJJIMf%t9nH#u-(o4-+tX+h)ph=iwKBh!5EPQp<4HF zy{hYNSoY|dp)O&^GfbxZ48)%nNXq$A&JvU`z5xuscHhVy$Zk9JPhZQP31h&)jRsWm zKjIHtV;;=F56f10_%+Er1H?@D;FV!n9dU~6k=2*CBAz=Oz#dH&c0l; zJe%09-4S5-y7vCvRFS;}w57zIh@QHQm6a_9z=kZSL6uB=0( z$(^-YRFWl9U6q$=C_mLr$LZCxh`C3~O`=tw4aJ+{t!ob&Tt|FImDWhHB-yn2b&*PN#RA( zX4BG7G2wTHSOlxfGcM&EdWSzGbsjE*t9@jUN%V{6F%!NnL~=BtT!VQ4np+eC9)C`H z5Ar{cN3v_IHWGc8I-9FJz3V~KaJ2X#$;#ETvT?N+mA;=B9~;j6HBeNRX4>0}5w^h~ z54airexH$*{Ksxo8F3f~lO(pDViM%5EfOUK#T(l~kH1bZY4K@z8zT{w$J)RM^&}!g_6@a#3ckue)2jU^7e^BJoJB&>vLH^gs5>pL z^>a)zGK41=LHd&;WO;GN5|-MTa!SM1+h)Un{R$e&( z2_%$|d(b}=E2ta6UN;iQ9yXU2stO4a^ykN$a)HSltACeN4j#Fs^rvvzhmeU-4Qy(G|=4?h}d{*b>S<2tfZU{ZP$h9G_;Y%mhXu6IP zF)g#me?Y!?3$%0XLiqi9Jh++CW@P8-;}x{|+9>1+kCoD z$Xa7$fTfgQKYpBa-BV4{T6huQ)2GY=e5`4pSoiw^R+Jl~e#ZLqwJ20=+VT$Z2i|`i z)RwW|aFvC~B#L;XrsrIbch&iQMhj7``85c zJ#3j?2k_phG%O{b6rpC@jUttsbz3nZw~C?3ssLA37x-1-FC|s5gpw?xQ8{uXpetv_ z%Kn|de*G1dYXAv1OaA~FpvYLZ6zdB~ji2QGK3vQvl1SL@6d0%=*x+^_J#!wJ{L3He zqNKG985d}i(nqJ#Y>lIi{@wc3wXfl4Hdtvkky1i3hL;l0f79^X%;k zZ7yMrs$feL>3dc|>Eqy@;<>T&)^&VMc7o@KGp?iYbjv8TZ9%dilNi!Uxk4fgaK_4A zi6oP<`T0C{{W>?{sI)x&Ml-MF%`P_MzZVuS#6?>^rjV@yRE{{la$hbSiKBxpQbWFAvW$YDsxaH?MWUs+HhqA; zjM}xT(Qsr;Sj>75XTmQW$98NEl8m>EbP05wV*@T6ysW7rXyV5FDB_5Q?q-bcPz3|c zk_Q#i)IKoPG>F$0L7k4UA`c;ggCD>OMUE)d_8|M;K$}c`H8L#m=Xqt|6jk)p+I&sfZP?N+l52wb*)8IS87|^Q) zC)8;BnjWL=$G=W_UK;S$R;L~|ov6o<5h6s#9%l0CyOWZD@Imz{9n*#vU0>8Z8=*~; zEYW3T&78`sBoMl!5D*j_;iNZ2oy}yPTdyl#rb?!!7{HrFpmFxp%t_TZV%RG*@a~Ns z8_K64)gGkWWK;<#u&?=V-iF#I{SVFH+`QN^@#C9PY>3f|qGOh4B=F1&T94D(ueVK_ zmVSZYoOrb%0%=NtU=pEeCY`pCK~$S_XWjKnqP^r@+UcdBGrtn;yjg?IzSykAP4mV2PfmX$~K#-2Kt9U@SY}CjjQS2 z9hK$D%E$HOXA>%;4#b4@zrUeY$sVI!W$|blS&|7Q({S?4@U|?GjDieqWCTkYV(hkx zN2{7A+PbZ#ct0Oa$ck8_O_9nPAh~7}Bd@t-0E(;bD*N<{g-XQGsa!^|2C+Um4Go}K z5M&+T7wAl{2ldbAl`KM&C9K1|M3>E1>dL=<2sdkS2{(8-&N%(qTQxMYNEjpV6r@2#S zo9eZH4P@!w7x4Zj6dG=whGxZ!>H(Ot15qY_%^n<{zidmfcMO^qhA;+;Zg#cb)a zqQ=3*!p4habEs64Z7nN}&Pff&r@ad6+&yD29y~cSrKscE9!|#zA|P57Kp}9z02kiD zp?wO~JVUGGK4y`mW9DMVIdy22WJg4LETHjfR41;#se+E==Q_Kwve4s}Zbw^vkwbD{ zY6Yz7)9PBjb{>Hq z#}Y`#Pw=o@%YO`u*73kQ;Z|eiq`J@9-5;`#D-FAaMO=pDu()^xmpH$!h z8hkwHl0;knh28FIxc!LhHcd8tB2<^d**Q8MTgJ}N!N0{i{B)nV}_ zo3G+wPoZXIO%%v)>mg;^@7cf?U=IBE2D-8mA3Y90!}9UVYBqnQzo9 zvcQ5ih!A#PdFOQjfoE7B#7$#O$cHN<6H3(lw~RX`I^r{_3w(lm5LSq)GG($+74^hq)vY-FAnoj5Hpo62p? zPK5jO{Z~{7?bR%w;qy!}8|jYpOUZu@I`Z4VAOD`S?A${JE?6r(2Iu*Rkioqv^sjguZeV9S$iL9pat$^fv+@gSf( zxHi;BUzaA)b+`oJ%(?i^1fFJ8eoTjVJdtX|lXrae=J0N#P0sB|@e-cJ<{$>CwHL;d zDsQ95{#}k^fhQ5c_;SoP4eY$^HXGDWJAJOYqoe2GNtGl+%8lg4l@!QM*C8#3H%!|| zuXFnJF+52G8M0~mhn=V8G-{GXeqh|9!9Ocv>=ReO>gFz*uc*P0s|jf(P_o02yBP2R z-*f@z=ijeMNz}3s;$Y}UFJFb0TIrIE>8DD`jtJ%QJe4^Q0mmQ&e=W$OyssgC2(NCc zX32$_J4=uv$YKxTNm3T0&6~1&U%mJ0zCM!y5wwVt0JF%<0k9aduqLRjf-jE!3py9m zw5LvG#Yv5nK&&hieES+4cImcJqFib<-X?hS;lU11+EGVLI3$PgBZ@NOHj$wokW|%* z?R+1xJx3e^7INN5^J0_K2iO1wd-m<`UnA7G`fgS;PS~w74=@|v+gX*Y7E|2V?ax*d zT9`930gwyrY)LFh7(5i+@%|S34#ugPm^ZY7*H2w;P%agmtdz*dl6-hft&ED3p(Tjr zw$2Z77`Nsef@^{Wip1ArjG|7By-wtoIy@8pABr?b>OVsn5X%(*09S}vTpA9_ISweJ zj>h{RV^nC4hh=E+>X8hMG7m2*H8+R`;z%}GZ@8}GzX0>it4*zf*Xh6ayN=Day1j~@ zCDv&K_|N9R;46jZk2T->i}tX48{#>9pAJu_tRo@}e6y8}wEE)?wIpDC5~@f3pnKmy zF!CqDM92U#$Otw@*#`&qCxQ>ivDl89UlH>$22K=hwGlj-QZG<##*3&u@6g11g+9cZ zRco;4UmwD-2sU0VTkb2X4_hj(^A)Z@1L1lKoRR@3pHP6m81lIO!A z5z4~Jh=8FApXwD??hShjWz{KSsLR9?Y?XCg8fe~08y0v~xQsdlAStS9^V5vl%(An6OgM9~EGsS^Z<`yxdZX7c%>alQ@p0f# z3W8C9Ke%IbM;%g~DpmmL*8aWk+Bj+w;mn?3>OxG;$Wm8>WPtoyo^S3CYaI3KWxnFV zNd+CF%uZ+l-2VXAqH|;6&T2VvrIA9`%wnOvxoZah0Di4v>0nbnOnVi0pg=yG?rf9) z08X_S%2qFR_{sNGF5raXM?QS+aAV%_4cpoZerfy|Pn8%2i96ox zk}HMV&vWh8X{guLbvklmQyt!1)aC$5{iI0ZcAM#-#+Gb=eJCN_Afe9-(>9af-hQXV z4%l(+-Z5iv9fkh@Q*sn@Rm*;z`Y#@z zGnpDd02_)Z=IZ;O(}B?oLj=0&Gdb24Mx^l;4gw|?iHZr0HmX9KMO~85`P}!id-S)T zt7m3Atl1j_QS#yZ$NP5u&r#uH4MK4iMou=JjOUppNfsl>6c#W`wOOxvJoVNtlaoAS z&+_AsVomC@n+<##CWzyoe~y+lOS`g&7}i}1h81RIjxZQqkIYBkjw|)*-Zq}nudD1p zX0PAkzW32z_IxyGWSP+Ai_2ao|=G036?`n`-`2Nv<#VKexACjEFaRa5OY__8fL#KGpko>Y`z@DS1Nr zNE8o#J_mo-t5PW2w3gZ^B8~-f@&5omdOIuBEsAu&3WN!{R%2Pj0&G@|d9^Hn4*i9l z-#*^mb%*s@hC@C?GUpTNSkN+$i!2F0e&5@#aWV0&UpE!j78Ha&(#$=m5zp<_(5a5V zdGTQ?^RT&YK4`H9@3|diR;^X!haSAw2n)$H+^jgmPxSZ;bOW0pS8hpv?gvzV6E(s{ zv*pQl6(cRQ3%lc~WNad=?LKB}3b2tKzo*AhF1FZ@6X9WzwD8h75C>hq?m9?v7U0ugfcGS>DblD+(4x7m+Lx#So?Tws|<< z`9O2f^9sW*7L6uQlNU-8$sq#N%E`Hpda@&mJ}B{B>#OT!KWI~FA!UL*e5O<=!dRqJ zZF{H#^Hk=(y2C>hnx#fTdf$l|f_Uc%qFe8$SBLHXvK}OO!Aol0>0R(KvVFqJ{tK#@-7Ac5SKZ+>_mJq{#Ep~)PZ z+2hp1MnJRWn4gRG78L&Ej(Q~B2xv;ZrfgYsiCZ`6BLu}fu*tGTh`3_R+<+?AkwVGj zUsZfprwlB}n;th@c@TLmEW6mm!_9|t6i$4$+j|!F@IGhJgn4Yx$n6vh1fg2VNP*lN zaIQ`4=f7^<56+ED7^<0=^GT710g)k6tqjP&mOxYu`<1MM+&HogfH?0fw0Be*SCJ%I zrYwS1$jZY$L7-QBY_bn)vZ}-4&poAV61kV zCWv8tfDfoA;AM?BGZ#8EXGo;pRE@irvnVz2S$OTyTunYK9ZozvnYW^5#v|C^sfpyR z&U=qY?LhJmW7j#M%^;{Gfgumd$6Y%kGaDXZGy$n3OXX;?6MfAPYo={(T_0D`;MH+* z@bNXGL^8mvV%p%ld90*WGE#yGVCpw;Z>6li!g$F(V@4h)w!8A(fG59ouYR~lqm${D zSMnBML6D0HO|+L4W9N^axy_ra03}D71lTc10}_nE@147acl}g;%0OQOmN{qNz}IP0aNXF$GH9a zuu&0ZS|H3Q0VG!$#!OX2>W6t$EMSPTzWVceF4-` z7&G#Md7BHDh%gpL@9OW#UU;!*rX4RS=Ecp%IS78DM3sfazH7veP>yc>U>*rO+z)<- zR9Zs2U69HZEM9t{jG{=KEATGvto(F0J(nXMFd^AAL6y$pOIg0e(D>rNeu>CV3rQ5p z(d0v6q9m&+778DND1-VQq|+n9)C&zmDKMYOl=f3ue^DqVd;5Huw-Y+mYFXaCPos%l0pHw18(&Z zBD(rU$^w|1>%17(CQ&TGVZ{zsS#lySg?y$voDS?qAqT3+0QTt5@yiwe0P%hlKKAsF8$^ASV65%7AS!rFW}ejsdI zqS3r&(F7&cq>g3uvk%CdLtFL~E`cOer_ar45HWm)-aDEM_s_re4!Dt-OLSbA$;Szl z=g-7GMB}*%SJHoDU-#ZDSmPNg8JhQjYhC@1-~NQxS8%gZSuy}piqX< zm$uezy!&-ZX$Cx{;Mz<@8A_5x(y;C?{`>p&3XU65SY7f04>gs;QtboMJB}*JvVQ$V zqvecT(6dA`72Y>7g|b3E`dd5`wEXw&)U&D?vbMEC&ctzCZVU&<<$gM?knF^xQf*Ld zFf9Dl{{Z%*_aCoa3bd?9U21w->ACs1So1|I;=3xa^!fqx6(skfr1zjlJy?$@gO`^i z(ZVt&#+FQY#R&l>_M4$p+*f_T5p-;2ePT;C|YX-UGaz{N#G8Kpb-)gtvsjz3rjwV4SZ`9r}hLM+a zXVOUomAfHrXp6Jks<>?0j-99(K}PPzzCaui$31-v%k&X_7_7BoOGL!^WlIQ&J-eUm2R%uwU{}XjhMMxn1ju}q<=8NCUf8W37t(z-e4cvk zTA{Xb?=Bc8)bRE-W97=I!DcLDx26S}$vmF_0H_)H?zzo=I?qi8TN4WBvWwa~c5XXxF{N1ipE5$GNQ8o{Z3oz& z*mnDMe@Iox*D*evc~dlVdZlX{#BR&C;QBxp#gWxW@$z(>Y+;L)lOZ5H(8h%9KBKqG zkN`-b%C!(rzf53j{{R`pf!9G=u$U^cq?5>eut>AC{y@V0i*(0@h}i0)Z#RXn!JBaJ zeTWD9bUQ0A9kK`oM(D(h(OiDO*;gPD&$W@-y19*xrYT-I#pC{Eh>uX_hy;rq3m_W4 zpLQ+p7bz!)ks2dkQj%|3B;m)YWc1(cc=jD~bc`mKCU~S+Hpdu+qbnOo^iJCsXtnkZIN;0F*A4La0~(Le<|rw zBuFV{hcK$s_-_*}4%dMI5YryWWfFAha>Dpa~~nx=@TXXr)lFVQ~Rzu>rWNgXGKCxI}Bl_=jXS${{Z3Ca!oGy8cEyEfD(+1 zLnXD*_rLiO-=bwDi%i^q>;mRPEy2>>P+U%a184cRwaMR>%jBQa2sP z&m)eEV?_qDjTU4B{ooAImJEx>Do7R^zcvr+d@bkchB@MkDi*|=Aga*FwYYG=g5A9* zvwZMRZmZ&I89HuUE`mIv2ccpr5S922v~Ip{tViL4+nSJr*Ivrj*rwDp#KbelJgo_W z6=0H~x3=s)d;Z@24n%a87Vjh^7}>pt!TS-@ZWoAR)gu_XoGfu0)hw+F`cxBFTyeAW^A&L*8*eGjFVL@VbKdGJ$E!49yvxnuJ; z%K+VAnmvVnVO)2wb2+(ZCI*KqV3Q&ZjleYOHvmU*dz-g@FWaix9CKpf2?~g1mHfcU z2G+1B+Wdjle5^U-4mX92NxmYE4;=B_ayx#2d~^zUzzgX(h#DTX_&QFsEds8;Y5a&Z5i9eZSPP&Jen;Xbh zFDuR1>PqYff=F-Ilh&(UNZ}=iy*{2iW92MZdqQ|E$Hjgn@dk*mftQzhrm3mO_zp9lW{51+$0+HR+x66biHZSm>RV>g;{!0#dgLWuzU z(y^$l)wu(tPZuTzgQpJfX4vOXY%4{#; zzL$@KfhIOSpQptRq_GnlWNny;u@%Q5C6j!zmGu?$S0war_$lG+2(--47i&z}8n^QX zgh@Z8BbiWLDC`q+1s=h8>?<29hH9_A&w#83kWft*4u1l`xiUNl#`0q(HkpAcd9rA@ zy9x<*5Nc^bdJRQa)Kpoa$4J7_mTf~+%Nbb_w(>wDXyb@vfzhg^DshqaYcu@NrM@}XU6HF{Vpt782S2`ej>wz9Ik1^#-1r$vsi^* zP^2ln#n1z^fTPq8N3gX>^wr10(3D_f#Tl89LKY=^^#veVao&Ks2t}3xp_wxCylpDI45gL>_-N}vk~gDlxnFjB3!(Tjrq9~Ok%~3G)X12t<|ug;0j9E zJMqs{eMh{2Z`SDklw~EQ&ah8jA=c)_gBK!Pc%T^!Pm*$>IZI^sj03j7k>QnzmMb85#?MkoQ$_%Vidmt>);nO4yT!-V{q^m{26u9xBhjR}P>uvT|Qh z${5nh-fWhf(d5wn)DO=~k%xsG%%yiy`H`N+uB-Gvrxn+^2x3_fs-i5RW(X`P9hp7$ zl_1yc?kKo?Q}8dAG)e24H)EeyD^eVf5N1V%;oUxIB8PM1VdE)z82wqbO9w zz13+jjuIk~C$QQB@FQUx2fk^)Vh%v6+y0NzsCwNih5-kH5##M2By)1YK@6X$*6D8w;w=)RY z*;eFMBItJGxg7rW)~Tn5!>|`xdGC$;%y^~2sPuPD*YoDbgGtKDOzch1D$9_DY6yjt z6T8+49gjTldJX(HAI$arW*D;N87-0Jj3{AMXNEn?zt(*;@>dpZx#OX_(;YiWe8+z% z%0QsNh8w^mk^sp-HorOl0GA&9G=B?YG300yrV9emWX(28L|1xb=EvoSBDV@l6bPq3 z1oe{Q&eJtBtj{pw4_+zyLBgMVsR3#*;r%wDETb85aoLzTS6#8jR2vpA)9NISEc^7E zts_1jHa=b!^3lf(n5xRJD$R)T$v}~~`d8Cp$QA9=LSe}co2fqZ$(Jc7c@xVj9^OC* zZZ z0~b3fa$tu$0!*1CS7R)Dhn%(8iX}GH?YlS8rk4jiul^p>1|)N`Lyrk_B$7x@-N%wS zwFB?m^cH+6aCL1*P0d*G@?m^&BG?4nG4D=I6JRi)Yyx@ckB4tW`0&9XTya! zbrF?P#dmBsU4xtZ^=v<3POft2L;aT4angVk&ybRXfSk15W~iY-C$86}uT zT*~Sgh~q$PN4==>H*sVFFFDeGh&s-_;w>F@oT+j2$!A}w#>SXqBAWD;Wc9EF6SbMH z$P_4bNBD!{Z~R}V;tWXgA;rbV5wHr&<6yoHmkEiR*CR|-tXV6_EIX6w7TolWscV`3BA$F*FDiXM zLxF?VMnF}LFwDkTU!PMQ$GJY%Xr8#z@O3D@k#yWh^IuS&KQR43j7DoM62ZC=#T9mrH&n)ii7$5l^N=<~A-Oi08?{k!P1DaOF&g z)9K(*+(GYD2TJ(4nRrJVs`(#osX1*=Q}VFl$H;Ffq79B35bIpX%XAHJ zPZm3l{TmU3s6>ZAJFUOxLZ*|0M|es+^{{{1xPK-g)E4A9FY?M56k7SKWL%!iOY{alm%`dFT0t3x&@n8|x*iJnhZJjy*# z)pl>pD1*U0jdbk_^{Aim+@1qupDsvj%~E(J-ChXv%|=K=q@iOD9yX!1fg;6PpL#tH zT+|d$JAeB_{{T*{zM1%|VKzv`ePEI;i09|^>P*cK07S-h810KvGesCJDIg7?cP9G* z$?w;n#o=mIuIG{W6X3N4MpI}6ssl3<%~6?ZgoR~Uy+^$O3Fxd|A&v|psjB2bh#gZM zWXsqI9FVG{9uFme1D;Lwb3yQC9&mzKG~cX)dXm0xrB`X9Es1ACO@I*qUcy>%|6d7HSy~NQs}F zmQ)u7a@s^-Iqn>j`hi`qsZ;84LS||*OSdUY#Dp0Zz1SPt#{N%N;?m{F#hO2-T`maa z+Z-71A#KEq3NLE48zq>KD#y1}v+%L;S}a_Mg;hgP+Xnye6BXMj3o5)#fmpx{B;&Sk0@ydT+xao zsENoTg&PEXe!X7C@Xn!)k>u(6vP%mxNS6x+Xz1-NA0=C9x-353cbk!i7F%J%G0Vt9 za>@qS)bq(8k??Bx0N+?63H55V0jXGqv}y^EH*2ZV*7i>}y%>gzsPW>&gEt=)z-eaT z6c#q5abOM!7hkCTdU3<>RzQ&=&dbHpZ={`TQN@EbnRagt1l-WU%{6Exj@FdhS z*TMwq0l_}q?#<;N&cTJ>ZeDQ{D2A~*%73KlB;L2vt#ah z<5bjj4-jSKW$SvA<-(E>gsD|M_K4!X4G-I*J{Qp^*Cd(aNpQ5RV9P#fj4^qN`eTi3 z5=bsU%pDY?`S z)vZ2ocSVqrN?BP}X2@_xk455PS1(TU-_>F^&>Z95^f_(HSEBM23c zxE42Eaby!`_34Kj!dO_i2r^e6KPB9sItd)WRHC>Fqz5h)fh6r5T@KwO=HSaa7!4;# z2Ym1M*rm9d-+9qv^2v**&gqj8#hN!Ux=0L)thO7ls|0uN)tLNG3}s{fU=;R6DeceC zHP2eW{vKdSs7{#+iZXL&G8lwR9f<7A5S^#eER)G6=ck=J0km964oAA>u*GGuN5atJ-gKRk|y>V68x*0mSa z^$NzxVzNgbNK+E*k7*y6u;ZUmVhOQEx>?^%0l7ti@b*yLV@bGK--cq-bw-rP?VchS^t9QMBJ6008@Y^o`>G008Tr z6VW5q^aj*54IU=hK3b})L`-1I44^#?pcQ{7g|IzC$;+J;1B3YPsvIOdRb;Bn8UK)Ma%ed@?$y1G%y5 zDg_QbiR2EwE*t51yi+p<BFt5M(?vWC%#R z0V%~_Jn(u-)wJ&o3E_FXIi4bQM;WtAl&u_0HzTIRrBhUSy7?U_P2uB?vEycCMT?e& zSmQ#<(u*XMum@pc`C>k3^VGQh7mGD=6Bay-yttVdAe5>VWBpc~k~>iVb*EqGY@*3~ z@9)aG-(@t&jvHl?qrb8#F5DSOD?To)_@TTF9Ol3|d56oi_m^~h2PtvdS`&V6PGLGypUw%>F%R*H>eX^ z4cV(5{(7!rHEQT_S_=OF4g3u!h;g!$5?l>HBS^4GG|Lh=Y9nD{w^!QNf@`M*SfkFv z!;v(6#)1Z9nY^v(7$oo*e1HuR?0$N~@iJ#wU@>EiVdk)jw}1;9v1AfK7CANT(LBv` z>yWItvSJu~v;P3tWTHVFus}~2TaEGGr5%oF}~0syise!YDu*h+s&q1uv5wrj^|PBZk95&WYgvIbj*nc zV}=ORyGbZgD6xzUfF5|WTpmqyo)`ZBcF-$OZbuD7SV_>t&b9}fE_IJ}*IJi~HSG(< zA5NLO+Y8FbX=2ZgR{UQq7>KSAhEwm{5NvcWN1wqsT6F7?gqn7wR1Z2BS%NO$O2lc3 zcjtl#d>c6xYvc%Dr&#u$*k?mnXt%78lt zUyDN(=2YBSbnR9I3?<6N$R1cC_zinVG_O8ALmYW>99&ZEB9eHKK&Kwm!0^3!M`3BxC9P~nT>X=*aN4iKJ~POz zhmR0yu))=V0ZAs*o&dW(*Uv?CzZmNHkt{lPMA(qF>u6xo#3r+ zHW=~H>KKwj^GspGw2TtNdx(bWp|p?(D@LoU5O`Zt!KtUp!PIci8}@~CvOosC&2kuj zZkwcV)XRlHV`tnCfd)M7?6|PH?JC|!jx`@V?9_97;)I-uq^02TKmtJR@$d81G2-mJ zxB%5PLo=m-qaSLb`>xYu5Jz*+_R_Nx&9LHEm+)B>I--;L9Xqff8Y7=-JyOQe^D<)3 zlQ$n94s1_T!Jda1$ZHlAmc=n&fzKRS8@dgvyP;H<4%7*C6hHa;wX zh~$8#N)}!y`BGngFKMEA?bYbK9jm0$OXNOGOHs=5VogYBP~{Z4qQ8`${{U{G-$=ri zIrJ;vWx*bH9S;%bbioMT2CleDK9#Z{Td}wa0#G1;7iR~L%nv^OGhz73QzqClX4vAY zP=j#>s;qPI($cw0%x$&yyYo*4$vqAjIs;3ClOY@eT=ldnq^QMmzZc%rbhC7E@p zX2iyqRmc<0k(8O3>J6GS03N%)qO+4 zxEgSH^Yii%vcZQL4xJ=`$T=VG$s`Z_x6d6^$?%R8I*`-yv+}gu$z$J&@nEyZH4a2~ zwTaqSiod;s(7>z+%+cpR3UZB$O4G9R=~15xSH{R)qjO`b{{Wub>*v?8!xn;Ra~W55 zITLx@_YUyfb!4mxIHB9-7iXPABckX4H9eJ{)6(L56Qn!l2& zrZp!CT^yd|D?Rq&?zud0X#-X8cZqyCj9szuB=bivk9jMPR(}&}`hQ+W!SB^svS-J~ zjT%Rm5Zgr2u|p_4g2&ma`+bdcwMWzj2fyiDHqus>{yEdM*g%U>$ka$uh_JwsQjdVQ z={8N1@6ci6OeDrxB{7C+XhtTDMU!OE_xU`Yr|_qSlg3&3I>x={CYz6w^!V7N!pPvR zmB*0Jz3nz)Pd`Y!V zE?iKos?8!oYJvQx%mgqb13+1!+pb^2IkV?vVTE*wCjqi@@})6kqJ;uT)-FI-W&{$w zfxeyu)8u9uoW66pW9Lf~ed$9V^!Dej^(kS~%rojUc_?ok!4}0D>;c_C@3_@b>hzxa zO@_FE%>~bsqDhnZe~17X*&2qRs{XGpEMmamnmmHcELjGukIh{X#_)cH1cWz-vGW`S zEfkZyplv3ITl~j>PXN^c-=Yt%PRwzoIJi=>mO`X5u=y5u8?b7Jeum|1$RJFJa+#uT z@9HT2_8NljJ%J{GzN%^&5=xPo!*aisgQsIfvp-GJ^r$3S10NMuXw{gTSF(8ZeT5%^ zO1bl3C)Hv|(Y904ppsQ4nOG^R+1{8D+;jKnXNdm*h%n&b#Bnk4BF9-2tdfI}?i7Zl z1Aq>`g$BgB<27(&iSBUZ+<#Wl18m0JrLHt1Q9?V@*p0OOx-)zJy{{H$OjDVyImLdW#>yd3we}EEssWGENoakOx>}-2@ximev z={Lq&6x!}*pNEwUc{}1n6DvebwGhkhIV4!KU~oI5O06n`CL##X9izuxHcSDtMQe={ z2k`#@_=|^=kCh&ND;%`Lh{BPe$DF8YkTV;#8&>MUCduc9Y?!mA%91#7vWmmCog!lU z6LVJL-LL#a9{prX;SBvRRmaMCm+5hxWHQFd45&!oV;X6-f7zHWL?1|bQ`Lig|gnGM2^VgF!brPzYS9}L~CQA-LI#m+M?k1Wq7~s zP2!w)lSs*vD-Ko0#6y#k#}t+^raZffjiiPEiY@X8AocmPGx&q2Q@$oXPC|qr7uyn^ zNgd6fek#ZI>tg;eU~78Eg0k?uFxZO>e~qbx$q`95IteLM0ZqyEt=R*b>+?=Wha_J$ zq>>}Kj>4>3@1E7iN_{)&cuZ(DYr8`c^Ur7JV;H)Hq&5}JV^Yy|c_lfTQ8Tjdjzwaw zj00^Os2=CIpnraa#xS(CQxBUiK1oN(jiuVbLx!MvqgA+%n&-b?Hjj{PuN^FdxU-Y* z!J*WXX!&xml1ZVm+$jvlZ|ldv`}OK+V7{G(1*|4Hxn}l`a;=4z;v6~h@-(N4d_`xB zEZ&g_H2Z7v@oIlwemb>>sKU}aVn!at2;`JEn3O|E2m_MDng)f}>)d!#VzbB`nO%7b zzJ}lcNbh~c-)g&|)h$B-vJzL1@EzPdfD^QlbVC0CN&P$f^e)PQc?~w%`;{4q7e^CS zT-hXy;z{Q(q^dfTME6x-4-_uBM#r(h|F=havmlwq=hHi#Z~@<*d1MbGX$>4yCjH~ zQV9&ZPZoRe{x0k9^U$qt!*R(QWZ{Kr)+JvcM0UzQDX!ID9k}DF*ts(3G9(kU-%eUL zk~RRz7$lA8vH2*O=uRsB=NlUviOUw2~}gN%Ll1luMhp1A#`t zW$kq0x#*r2I%uwbrbvJb<&=woCe={V5I?9B+#YMx4U^OfBvT0F#|2t9ERV96%QgKc zf(bl(a%#JEX%!V%Dl-IMNONEy>;U(n!1tg!UDX~AKt4wfzX3+eucq-9KGlw0*#-b2 zGL}^(R8ZvlT+kM5AD(&WCRVulA6+tO4&X*!bY^mp&tJKBl zkbXh$*Ra5p3~(b5ERrsO{e8N4!^e^+WtSnbaTY}n1aqRf3+mihlfYwDN8`Uy=J0RF!^t;SPhWHZ!!6*5VHfM97E*@QG0`_{k~Kpp!5 z-2TAyQzr@?A;)oC@l3E4c_VKrknR-L z2_yhH0=fs}W#=-cDoZlPiguylS-&x3_ayR9S@?`dto+5gb*d{`V&y*O_=gh)5fph# zj~Pk{5(kj4wShrL`JZxnQO(wT>C5BBT8)V%{73iZ&!vC#kKFafH-__acgWsGEGPpp zd2E66L#vSJ&_gI8q|K43(ljL9d(xlvJp|Ty8Cnz$&AVj+e7u~8JEU>Ak51$B^T$7a ztmElfFBvhqV~vG|?&sfV99`e}^!E;zo0=K&3SosNX&-0~YztyfBei>VUomj8%m>5e z^QYyWd7-RgJ*c%8Z}>+aC)=hOfUi(yb-nzR1|S{9i$$1 ziUZ7U)QT&g??*FL)F6+3AbfBcSzbjO$yVWjJ-HpP+K)srG*^VP#FJ*`HGwRI?qY8C z-*0QGA1A0XB*fF_Wz;f|$OhGe6}J$0_a7$szkc0KK|>DQv)((5pE&f{y+Cx#(!SL3hF7o?v z;tRQ)`e<|PIX%B#njqD5-6c%;u;fQ9WlROOvdKp5f;l_^*n``lS)MV;o_XYQk;@@n zwMrxW)>Uh{By;Uu5Ld5IW(<53_vfxP zeHJX)k{v2sW=NTuZSwwO#TxfF$3LJK()9YCUSwiyoTrgh!m%WfKK$|2+ElEinh2$p z)Do>9CitQaaogMDxatAQW~1%62=yo9ih#qer7=t4+&vSV%~?*slvpzn`itkc295Q19(Kfd(-gqdqXbzB`LTo{x4%7r8;#ZSJ^J%?ULXBJ zXh^V9;b~b5pO8sOaDZZEg_;+lHu`z6rknK(e;rxOni!?cc;>^#iwX}h7DO|7jIwOA zzW6)ZzcC~axgSc;$2m@%Zq&)d5mNM>pAvXnz! zVxu&Ug}ExlRH+Nd+@|^H0U8xtgY+1x>jY@9K@7^V-I?S>5$-1IWMg%5M)S>+(98|^ ziy}tuU}RG9*#bruP_PG*2_%1hyUopuQ;^FHBN#h8ueG-!k=t`u0)QJ-3g9PxdX^Xt z!o-DTQpEe;03UZ z63G@81Rh>YuC_ec1dKuf-u8Ai?d{U+?-ELGqjEPWQ^AoAOnCxKW98&37}&CzNl+|$ zNFW+Edv@-6pwbhiYIa45F$lBG?t8C+N4G@bj4q7hB3yNsAqossC(TfsROAo=9-vBv zCio-)T!+XGi#tUrB3R;fC`T(oxUXaX0DSaasdoLOD;i4ThDkDH3SN4qVoQ3tusyAT z=I?KAFREI$JH?*NWROS$ve@T<)qif+`}gbJCSixJ zV$SgS(fOWc!N8I|tVjg*y5rxXO9_({B+y{{VjQb3T}n87f^&ewMAs%0R!cEN|xi-F<~7D^Hz|kg}Xv42vI@ zL1c0H4?JC|Ia;B++;nkq1ptXfaFHd_b<}o=vSW%FM(yTC3nLi{ur=C= zyS^*2>I^m!Pqt7N!BoLStm>Nv?0l>&kO7hTnEs=%XTj*5}E?daP{} zOM+kpGNUoVq=FmM>Rg9v70ULo0-v6)v8i7uY*nInSsWJq&p*FTHQ9uOsSs7HX2fhc z;+oSi%Nc@SGLSE*KH)@vhv5GJpIs$vmU!HwM9Rp~uuus!Y#&kMjyoRw9;?cYkSCQx zJcNc}dyjti@7#4R9#_+3?_fNkVb{x7Vm*x>^gtr{9^G-efURILA~cmtLNJ^ui! z{>MbTUpSu+!}GlA&TynwiE)x3uk{k{C6m(ZeKt)uARfSxf!_oo1867)F@x|#yP87& zuv)!0?SB3L0L!DfaxC+glnBI;VM!Sx?LhMVKz^M4$KRlkPKdbnzFdgKjHBMj0{;L` zf4@B##4$ymr^_lN$gznUDPav8c}=_qU+Yo<1X#b3(a5q3lo)vOWF!j-L@}$gIg}}4 z5ZC~BG`|5@poNaNJh8oT_875Z=wLYYKnh~JMi_#n*0 z%)*W%r{u!~kS;u-f~=6MnD28@Rt_r9e*VFGNy}^u(<~CaPNL(HA7e({!z)-SLHp6{ zO?27f4KoS6AExTsDOQFY_QlOlsCQV17L4GaWhZo>JW#GIfy&cU6H&%N9HtQ?L|NnV zeMQ&}#n#E9yt1oseItTlhFJ@pXB9Rg<$vQT8pcG?9D2)_K69C629X^D+I*>PoLeLQc6 zGek<>`BZL=Zulms9(k@hg(OO`it8`XytlSUQYIm}-h{^9{95eq?0Ts_<=bY4!i`6_ zJcIj#)u?5R;7W@g?=L1rQb}R4)Dh2a@gIxac;l{SK{%8~_Qt2%ToF`izWw`l?bL&G zxUjQOjB<3W z`PD39%><6ZxK}KpN9cN&Nys?AR*MW%B&!&G@sdJ@EDD^(whyjW>ji7)t zpUoXij0hLV;E&vP=&p~Ki40lhWS1dk$;6IGUdUifrL2Rvfnagm{=Ig^KkTdKNeg&q zE;V556UL)xAJ$6~XSG;T0OxA_UsL$A5^P+pEv6t#k)^{gn2sBAk-14e=W7q1cs!1w zgC1>56UcqbIozqackWQJkz0?aisW|p>&;?l7jgdZ^JQ=v#Qdmfk769Eb?gt>)>TCv+8ztSM+!6`YtbqVf(7!&eECNq)*ii<$ zryC%OQ7j@yE42$b8#z3R@B8u9tXvrm-LOXLu}Z)+iWr4bO7qBW2~Ytf_6Mt&f`KY+ zPw8JKM#7A|IL{<5Sxq!*ZX$g~j^9b9J-eRf#$33uj7f2~%L-z^rDli#%%N_*s>^<$ zeebHd(x2v8(&9;QRrV^+(oJEEc*`K70$NPv1Wv~lDMkPyjxI;J0IV0 z{{Y{v8YzoP@=PU~Jb2boDSUj0%c>Z`2mx9R%~Acy=zeBe=40Rzu%V9uV;eyo-b2Xw z7wz-Yu8EHS0R7H}Mh*jIv*iB(EXc{77iKY%QpiK?uvh`eBCD1FfKqe+01Hac2_~b0 zSc?Augo!MH{{Ybs-ue?An7D34EdT?(MH3_sftQjQvDRf0Y~bt+yT|LapYPL#r>EuR zWNR{al+wQ^iHG&8O@6$M1y^UbvByHrnvt@_?z)vls%9dA-h*Cnj?IXXdk=wXE zQS`eHK|4i`+@5$HAO1>` zVXW}#TG@_PjwN{`R7H`QfLA2&NLvHHd*hzHV{t!AaPQNP4}^z&Xj1H7Q3siDq{{3X zf)7dUx{n2@cdPBxc;_gRW_dAog;1zWVD0Q}Pq*qj^y?RcOJ!qXWahYOHATRhS#igc z5pA`;Ku8P;HU;oF>U>`aCMF#1D96ozKV*(dCzlvN!jY76+xR7~j@)z}+vzPWESTCN zM~vUebiN8mScGnkBC{hoG|XRd@86HNzeJLCj~EFzl*5&ap62lkNneLo=NfIVTjlvmFlq56V8{aT0ADpF=f z7z4pUq~_`rsj6n;NgG^wPZNSu%M=Rzz4-qCUa#Y7OP%Y78)Mt5#~N^?f6e8EtN9S$P{f|;Xj*XCuhdkTla1fxa#^_N00GHq2uBnKpQeNRFi2SQX zpoMQ#@ODlvOxYNkjwzVpN088$F|iULV3rgDeN;gL{%fdnd_O*z`c6K3L5-+Kir#b) zI5I%%E75igcAcYfAc6%Aqq(!Fc#|$+{?G}@^42wB@S|W+WRb#-^+0y2>1$Na-HP)| zn%O#rOpWFXV!#4DOvl*vt0dRASXCTnD^E1_29gV(ro`2aq{_M=&&4oJ7{D_~rAtV% zeNX_<1gmm~kU?7?5lPf3p#39(|!hZzf?XO;10EiTg;QmVs+27x1$JcxWP zS(tda8TwrLS`0e05#>oHLq`;lTC9+h!nb5#ORmkTdFuWq43l_wA5YUUGxZF-O#HWO zq7T#MVl+izATucvEAFm8`GnaP4^pQ3jUY6b{Hs)RT60Vw+IFL!nzkf*wiY%{GRqvN z3Rw1}iRLHaN6#U<3p6?8boq_oO*_SUjvHxPW5JUyJPC0bnjDyNHmPMd9d~QHAOKG0 z?p9;a^#%y5q-A5l0yma{*~E5NX|ODTM#XJ4dvB86iQ)yrn@q;c#ng28pH;-vbqtqT z!$~@01!h^8II|!P`53XP2nBRkHoYU6fR6+gKAVI{NCQdLbnK^&Y-yv41*VQ!H{Wp0 zN=Tr}dF%&%{Y9CInG?+pOl-Sp7E@|L?0)KfsE)NfF^P@!`ktj3c{8!)jw6>Gkk|Xh z3=E)&WHc_xG*8$Ld}6*9gFD5CKQp+acx>Nh-IQyv73^)j+qTurv*Ou>3%C zMcIbp>sr(@}oWl5Et zBb-k=4rtC)Y*a*JD zt#FDqZa13I$rqOoVJ~Y3o@{V^zizyd@vdCS8cBYxF&L1osyepil0jVU+6T!DLG94i z*zoS4fQls9+-#fR*8`5dX+(GmRlx{{^Zx)t`G>daEB?n#;Mv&J?zqO#bUk&oK>(tS ztjQBdt29$e9EFpRyVds!6h#^%w<^cqsUV1bZ1Jdg8TVvEcF4+B&0ipowS!mj&|EPo znq^(-kYHw2kQ*ay)qB_mx|rr43V6(9?)$Nc(r^`=^2Zr6>K0{}<# zZBtXm!AND>sA>4VW3Dk9gGe~s$G-CN*f(~Atv~ozpC%3_rQxkfwqd->mlH`iX$!51 z!22@N^G#qLZ>*0KTSkj6C|>-)Tgr04NH+o_9~1xtd)fD1VanBx2Cai8k(TT*noY7s zTZL)2l^ciUBeCv9Uv7($rjUcX&##RTUruH8_M#@gdHWd*cM0 zyRdkP+B>y@SIHOqbQc>?{$B8A>G7h?kCO&WE)Wf+6juY`nDn!n9^9xDX}P4A1*&+n zTboImZ6`-EM)KseY|gc|J7ZPfXr?^=b_~sa`TlOFFpy<^Ma;9SsFq4%@rzPVacn^S zk6mhBB*)0t^K}epk+HG~c$@%P2|~BeerWU1T~9r-c9zAGC6X0WyluaI!13?TzkaG- z2p}ucqFUfcRCNtc`M$G>E~Ok$DIe_7q4cDo*wLXz_XEi6lseGYO^$6jbzMe5g^H4v z%n*(833mlZlz&vR62)xor7V3aNyoCX7auPj%wiCZr_7ArV8yW=5AMpY`Cm$jmI~6f- zMqH;6BaCih00EuJC7+O?`=4!q&`8xhd6lY2@=ZMW7|SQqiE-muCu3Jg8GryDKYqQ! zf#I0sENX-a2rFQbwXbNujz9Qy7leO@`TjQ5rqke^arE3=QInA)skDvWfCK|<%%Bbl zzQd?(cf5Bk{clhyQfVdI6QsEq%pPZpE^r9)VsdGVC2rhFHce8gvvt_@eY_Q^h;f@$ zhabZ8<+5zVlO?6emVg#9ky+P{No~J>o|s|6!|;YIap3RM#w=zivgF!w7}acq5=2Y> zC$?gEwjh9+u6V^^^M95JF8q<~)Et-BW)U`O+khjF|6}B-75g`?j-M1PYFR1)KQ- z#dL93__VUru{=kPp6O_HM;Fry@$jFAAjgXuOdMR@mP@!Ku^*Ys8{Bw2@_X_+AFRQn zL!<-cLyeHr?u*J-V8BKhfo|kep`+WluXrcdBNzw{k4?`QyVdWa|39l@xaCov6hG2v{^_Rl^kkgTWze-FEx+`d7lZ(Bj9aMFUFD zBe|WLQcmFJA-EpxvLZ> z`djfHEO~lfrmqI^9-T2KXm3g~$O*1W{t!E8o;|u^b&N|ajl0vnEw&oh&^^EM9{mi| z-yam?jJ${;dpllFO@@iLS)<0*Z`O$FNdbibed{sTFy)C20E-`CmD`7b!%@a zRY+0|M=13g9*}P8)})=cyQ@mI8QM!z4mqp)+5X)POxO8a{mBJ zM$nW5*3~bJl5)S9nC0Aj;k;~FuyVE+$TPri9~_JGSP@__AgJz3DCYPa zhPd7lDgx$%8Y&(h!OZb4p%xYvBV}hzC!vx+n@I$hV_kp*-?u+KYEpO~Qt(h{b9LP} z6HH*HOp}jGJF*?fY#qu7AgH$6L@Ba5c%5`#;ogZn*ciWMZr z4_-!AJG?-A`N3!b)8?Cj%rEMd4<)%u&-EM(uMOiiPPeDegUF63Ty2aw?7OP3j!FHx zTGVqj9Gr=iV8oEt<%~#Nh50mp_UEl*C-|wO>UF2!;ACnTxa`rPo;~qTbi8h2#ZPcM zo1i*h)%-bynsVjvt^}A;<3uNT2;Bq6&#EF1t8a2WxC7Xl*2ZIFGb4aMGj0|>2<&Ah zp7yCL1ms8OMZPRWj2}Qj-)SQL);sj+nTd;}#&GbYi#3uU*?GzXEai!Ct5;~Nw#D+@ z_~-Z0z+{-y@~ zAdZZ~IMd)wV>}r%{W*ftF&%!j>Yq z_!ZpThq#&6P~y|ISMgVhu{1q1Dc(OTPlXhmOke?)*ah9&l1KqZweSEZrJWB`Iq&A? zstoBejBAhP5V&yxW<~?JJ+}Y_0vD1GNch;9zAx3HZE8uUCV0{~_wHEQM^eQ{WeFKS za@#rY*2SsA1}e`iF|t5hNF4L&0C{5m%2a{=DKEP8Cg*$LXce7Fl!tomL9=r3wCow@ zn23@%*!hwTq>3bvf`A_h*n8i){+E%cc!E$Tj#LuG=S7XUm5w#-B+h%WC-U}N?PIFP zcE6}VbK3Fng5+dktybr6!b9^xSf9DR#B}}O+&M9{tlX(1WuGEcLZAcqXq&d*y~yE> z{{Z$rdbx3Xz#1s*;e?%1?};%6iH4JsnR!_+kGR}W8Sp)^>+G%RJA zosF{bL;43{dr9bMhZ{!KGZzg^!zUlh$PXic)O^HOX`jR_sQfvlVrg0|Kmy_z zB30z=O}mPM3o5SOJMzCLtle}$i;ontXMJW?*Dq18X#^Yj^?Y7IO?~jw%OY(QpDGBpgDjMxuE167 z6>OeKB$g)0=@%1K_gXBZ+HFPfa`N)^42;cBI%UY5tK>>#EJnoigkSLmx?}l4$ow(f6_+@E6m9vIx9Xq2m+&dS|Wc9o;%%9!g2Y$#X}6u*_E zHT?tHzC{7iVP4otVTXOzxgTp_L+qal*;RYjY~qfPF3OdMDxydOr?F9zGK! zS+c+mIgl>gSVUWWhXuA?;t2qb_s}>s{J|VJ=`oHRXrl@eC7}|QExC{M?P?_V9FBXS zc-J2j#6wZnTQ?^h!~u#2iJlzB+;;ND_Sp+Tc?1u*v%@HECvxToVjnsL@!#8s#wW8wvKIua0R($>gz1I zSh&)*Bry>b@)A7D9pT-{2G3#Gn(uYZbIXh33E8)^Op>!)HEEp9FqZ@!qU|eWZKY=^Ihepz#)_bbSj- zj|*IZ+)Ayd$Bnf(V9w%7s$fMe5li`nmLK8g@WC}WVEHxpb_f zOa2bch2sMH#%#J~6gbT?Pk>4KqhU-6%)Ah6wW+n+UCk}(T0FRV-lc;!Op-y4@r^ZB za|*g|veL#k26MClU;sBU27o$ejPP{LOF@$dBUVPt4$l^B_lyaqwJAge+G_V6dE4-V zjfa&cp$WCVsOiDpfm7nFv zq#Cd&pK?cHIqQr(xz22o;K!unPaK9vXz;ANxu&^UtIQyaHO+kWlF6HypOGr)+HBb| z#NbQ;F3aAV(n(eC&DU;8>AOVmj%Kap&8fxW94vO{&Q!#aERt+7kTrYq4}P95>_HTm zHyubk^O6wy<@YmF3>RA{%Tys1UtkeB7 zDKYJ*x)cckrpwTgvJMD3^zC`91hoQMA#K&qg~fD z?Jpg(rPL;^J8ZdFv8;J3G*`$-%PltQx8;CSK=692FNX0NFQCN8`W>+YK4kgjV&#;G z!m6N=%E$dime-O`Sr~>j?U#v>GT05%uL}XNSb3nF^G~ZY1xbos9fQ+M&`;E0a#?C?voUEq< zU8O?=6KZi~$%v;kDJDXxwlM6Z?gP8~+dl*2s~Gw*om8&pjE^ibTS+^WJ5@pMXmAG< zJ-c*DIib_xixW@TF7gcJP5ndPrVu-91QWZPVPqZ$LUmlsh^E8yAx4%Z2?i$p!4-L6 z2q0~{V%!TSlh0eV>$-_`IzuzIo5Oxh&YYm_1AE*8FF%NJVatMC4IpFWW0q9O`iX?Z z8r%pCu~?AZln@)KbbUcQ%#3Vl;nR%U0TPoZm{*Xyz~l0c{BQy6C@uuLp1G8m*tn-q znnv5SS&GU302g+@g#aIu(R}R#4@p&Aoab!CUp3&whkM2=fIvJolffp18z$*$xEfX2 zpBC)fB=Ir)K0Q)?);8q?RGPDF(*EM+I0a@TY0^s_R42{9lKp z!Hp zv0ARZ{6y0<$TV!+cLO1}WFkizG`m>KxkOY7l0Y^<7AnQ`mE!*ZALjU{Qf$pHOZqo; zP#-XvT2P7K%1#3d{H3}5IvJ1Qe2H^P2>y}e*z%p*oE9!<_aVq(Nnn6CFk2lt>HZ(U z(o)C}%)|#lD56Ic%xE9mkH1V%!C}jL?JhiQJs|kc4ne7m6pwc0BxC75EX_$koude< z8RNu?Fb&sxBFDk@zOQ|EinLsrk{=NHDg!BavEz_?1xG{9(s>|uzOHM2CyyxxHk~fm z>Wra`YZ(`66i_0E{V%048krtx-QHfudy=Pv$-6xKgTVIcYCi_qYiYN@es}tBm3mLa zRPR(U6BeD~ZDt&avUOOr{KsQOwCn{(ExVHFNLJwc3+KNbGGKocu+YTOWfYNJw?UnT z(7Y@-AQ;Zt7{Vdcd_O3F?v8&d zXq&YHcSX;+9Pmx_H(v0siS%qpxIoSi z6SIz!r;fl1mei(Gq+THU=<_jj+{kgW5*Z&7N!_+Im3zc|?EvlIkO(J^gKB;x!N$eQ z{&}c)r&pdRRU`|X_?XPj4Hejkb`$CZ3nQ>1&soNssA^so%a0`s$vi63ranxL7D)-D zE;%f=Y>OXqI0R0ktK@5080S)T`dn~ILb85kB7pNhJy@~0-Eb&yc7BS8`7z8WyqB!&2c0wCp$} zmFJ#0gCdzzU{H*bYy<{i!)uMe9w^ZSv@Zta>l!vp+73pEhmngQGRKvXG9+=SG{v8O z#~W-EvO^mKtQwzG`b8>+o=7|35h+u(`xO~M) zK>S2AuEOE>R@XKwn*j7jJHs++&?{x>+H+@lgdaaO{J5YZgdvcU<}#oLDyj!z-=t^B z*L*P~czTD1V2denzM>g0C-Wkn6-y(0Ug1~V4%AKXPhxoR<-+ zq5JT5JrY!N99ok?RX~k~AZ~sKawv4UgX4`eF3Qg&CNucHW3n=H>6FXBNel!*YhGQyCDT4R~Px6 zfM%vr4#i+9tY2Brh&)e`u3*lS3`}fkAXxLHiyZ-#HwLZ7*hURi9!ci4bk7Y@x>Bo4zg`;S~Gc=m<_)wGO{db8E{Ez@7NU_^T%%H zheKr=wO^DgSu}s+d34msOpRL~2kN6i<+MvKK#KS_!0aDy()(Xk(K0 zVvu=pg6b`lGaCM_wSTW}lXT2P^JQG7P^lu%FAKYQ1XDF`zD@gC_B}J;jJ;8gHkGGI zmgPh3iYX+qW7$Ef``7E&tD*D?b!eAXeqEgz5SDYx9c!a6geJwzO+Qu9a&lHuA%b~j zg>z7o>Q<3_uxS2PWo~DN#G zA8NXml|G}WONFNCsK0>Ou2nMJgG(7KppTYPzM<4pz&0lmX4{_Ug{1fX~^7=He!KNci#Cg-xcIk!e{3o&p&OHcp)^vBoB7F|p={ ze2>XJ!L|dDVQ$xuJD5g`s^R!^Lf2%*)TB*HNmdCmF_I;b;~;?%Exus2>SDWBfEW|g zex=~Q5_looQ;!EDQNYu(p`Kk&3Rxt>W+W6TF%}C+$17mhBpd3scD0k^jWt(TOzfam*7!AYIXHjx|QP2qj4MgLG8#NmJ5heQCOZiadvzcB$O(n4Ct} zK#M-AuEdVidvsr=V<|qH=~iemcUmql#7~{ZiXTjyh5B>DK0MMjr%gXH2=u){_=_Bq zDo(#K$z0d?7=j0}6neLl;yhCtwwaTrzG!NAG6_Z7Og%F4p@FVgZL90^Zik-?xXq?& z1U{J4ERXY#L;*4p?l>fSkMfs0H(JKY$ohtcMbopT$DSr0YDKX3+CUo! z$P*Zukv{>01IwkA+C`0~*6zg~RkaTnW#gH$G$hN@F-TD^I_0#u%4jHf!xBI?PSz&3 z(BKZdv+2~wmr;($j~1PO+h0S*6KpM}Csn5FFuqb_X!GaCr6zR0Ow-NE#HE1+txYcE zUTb#S;Pl~z;w+yI$>HeX%9IT=PSdevfnD3njx~81PU==HCG4O84SGtBu)MDs>N>8W zhpOdPWr4LtA72SfQ>-r&%_lF`p7r`eQHvW>@V>ncqnn?nz!Bwqlv1w3GR?49 z;1fzi00?d`ugO{3l-MG*8QkO*^GJ>cbgSAz6cjeyoz=&=Jazih#7j0;gSDtJ;s#kU z%w z0+Y5z456rQA%ClFe{Q^7V4>0}-3f3hWj@_{N>6baTqJT?&L9gYMDHSkBq69;OBqAW zdk`zB7HKxW;m0T(nvh?=&tFf4E<|2fnY^}BcMz1j=F)8N8 z(oNNmi|g6-+@&;03YNXY3vUPlv zmoq4Uil`MFx0VOD-iQ76>xo|;e2*_q#|*KRUT7$yY}aKUspzghhJ%aEEhoaro?0IL zka~~rU#CV>O2yN{N1QS7h&Q#KG<83r;duDxs#K`fp6U;5-38DMH%}4*UKz6Fk!QUtS4^r<761lHxRTMb+>PUP|i5iyEu;Qh?2^a!E7y|4 zCTbBrLoy!mMmDd%9r^vq>rV$xtiu5(t*1mX+55WiR;1LV$Y~e&GUSVn2&`3PEmR4%uuH$#{+oCx! zt||q}{0ii56i7Y2BlYWb*epd>=EPKn?wfe%J=9A9fF&yDF8WNshBtTA>SxjbAr$+4>At<5&={~C9le@k1 z!1+By`C5J|#5F98eLo}=c_Ed&qML4k6iF5B&E1ZXa`io1RY*kh$qZ2OVxo-?$N&oB zzIulr39_;yGR*5F^DJ^?Ng<$FzcFLaZfyHsLKMc!DHQjV(oA zj(TVC?}f55_sRUCNn{eREXqt~kK|YF+;%4;`F3V@B-T!Qsu5MTIEuT^>2{cx+FAvZj7=waXqV zpDqRh!rueflEhzg_v(Zhx|XLhO!$kZ<4Imz*>O1yRzM6+=DQVM*L-!g{0s&J16km^ zbk4)o$UyBXKJ5??l+c|&6B`*ZvDDf=WruK0091D7{t2obQp?16;l+k1{Ka{QW|AYe zNfcio^S~BB9~b$$YRraImD*`tw;0#za-`f^KtN;wRSwh#Yv+;B?5#CUogPDp@-s4M zV?eR8nPXN8)Sv-Cg>Bt{9QW%YwR&zH(Peg*P13G**yGAAB#j^~0ZHQlw=+2ozW&S4 zaby}5*Kp%JD~B|$n9@y-@&My$5SAXlfxgI7@TBqx>z!{5E~O?EF=b-?H1CRjr3whi zk+#P}XVQpc;O&QasSmc*g%To0e3aSu=zwp=>-Ix!asbyxaZewNRLNGS~VTLv# zaiLM@U)PPq`;&doQGHP+7g%W&ED8c~)rSfNl(E74pY^`E4N;&wo#yo$2DaGR2gp96 ze%pGn2_{8ZS=I(?nZVr2mMqt~0FnjrNbS@BoQR(xq;17U)GAh!{n`(Y$fW#n@_OKd zcqLp{AQeD84kbZBNFdhj-Twe!etI>bmk~=ma!nKhIIiLl*1}23xJ7!*koCGpsOy1Q|@lgfa;?+e9T;U6qu9WD>mB zbW#TfgH^&ZqG8x`NkDZH_|aivO)^L^;xZMChD8j!g&G9j@7kzza|GjmEBa|6bD0FJ z#6=3old`O<8}K+P+ih#q0W3{)FCGbVH5Ykd8RyBLAY;ckh?H2^sSIdu@nbG1PBPPlQ5S&PH?`5e&O^RKI74!38NGloT{20h3g36}W_JU~M z-a7em8&k>7n>pXem(0(~w*LTmv>l-R&hyW?aqrb~WswFz+Z>50k$~f9ZJ>SlG(WdY zMpOopNm1hJ`4H*HPQNz>Y2(TfIP|=+*cE*8tiXZo`gL;(I5G0u4IWd8m9|WIBwt9n zqTG$k+u;B!=IK~up1gFutinmo9%WC(f9#KnIzX;OUzg(H#J8b7(?rh*354xGF5aU#cQ zEy5!ro3^_=4&sIWy;Ow$6FTw{$!~GrkJ_)U@TdAbym`5}Wk#?8HGh7+jZ950HK<5GiURQka}e`K zG+NC!B=;5j-&{$VHh+dA!jaU$r_9d{l3Jxcp~w-}{oOQ^7l$#VN)$KL!_W0;db~-Hsj~FCSb!IBZo=yATMkL(| zt5vD>*ye@(zvb5~_O76UuUm)79l8TtT8>&BbhaI$V1G1a#j>CI^(<1XvWsV5Rr6!p z{QGr&d^rdQ75uUswFAYUan&}*`fDzxWLC6_$WnV7q6j~6_UPf@pcW9jj21>gAc%zF zN?P&FSmw>QfA80`Y8iO)V@Hhbj>(Al=gY8UNg21H2e_kDIO<$@#$@oti0-Ce=*eYY zr>3#%CdjMy;)j20n!bmtN2ckzwsJ@GIdO>bCi7J91*ChRNKaC@+GzIUo~JMd>VOm) z%!`bR3Q)BSz1(m9ueh=n_~@raM=RJP9rYaf z3~4wpWXBY7;M<_^oW;R#UJ$wUQtW3_oQv;$bueFLXZH%UgR^adfuiSLWpyo{` zy{Bd3{{S<}%6&p9G1fA7`MXe|8(mqM#^p50?dv^&ePf*1-zFt!Hig=t0qN+#&xEPscVJvwpe6|1q`E8T#LEG=|)pjcb zb<#+rN=72YGVzfP!b17V+xHJ^YO3rvan)s+5#W{8nOR8M7X2)HbMITfzg96b<;O^t zXya^rV-s(nOCuI)Af9Ym*c@#f{KJ!Q%RE=PVRZ(H^?*-5so?(r%c`K%5M@OHjOE1^ zRE-ugWdke1wpBw7%&T=_ZinrC5Y<{a@&-gZJiN$~aI4u#^p)e_ss8;AoQIY+lBuE= zHr3Y$w|{<5Mpqp({5cLxA%wUQn4~rckXd5h)k?$s`}NNf*-X-P`Kj=5u=2E>VNCKw zaNs#mf(!1T%dpVeq?bTg*TwP&OKL-IMNr4p#?stvKk3mKWyi&b8fQ$akU0#X1!As5 ziT?l)D8rLP5&CsSVi@_-!M&ALq>Wj<1cDd~_^?MGe}1Nv#n7u|%wc(^I;JL~yO4R9 z&lpnRSv1$k`HH)P&-eRJWEj(usH{vO0DfE6#jE_R@mwCGg&l&3gS;e`+8lp^iRY8u zd9QAx#7A05V=7Yaz`Cm({{H~y(EyNyOkFccnAlQgWh%mBWoQA7%cHBt-mg{eHnc4J zbI_dpo6+>xgD;tg?5nfgS~$&+dAsA|-=b*AHW3+0sv$2Cj7k+~!7J_qz1@8C&}Non zr>G$mK3Z>L05*}*kDknbeumvq+-0)3#{u#bOg6^f?+F`hS7LrFj*RBVgO8!%NRiC4 z%ZntLQ==;q(neKF5Nd;|AQNM8qg@Qsk|{G`k24`LA@g?0D1&!U}yncUG*+7g3&fm+=*pL*bn`RA_nJSk(Xh#9Vc>HTmrt3UynR@Jk?OI)O__|Zn#>@Oa2w=IPrLE#h6*R z^Xdy6_<2!dMp&6C$}nBLa!3@%X>FeM)>}B0a1tWFl4*bhhVNDP_v=Ic5$ahwR=KE4 zjS{qn6PVc2p7c)cJAv#?6SQA!_az(7c;t9xWh@#<7&L5eovb)3+o4l#SGezmCDPD0 zFE)iYfK5+6&GRLw?47I^F2;<-M>TGw<#4|;Ws6?3UkdsKVdP6#1#$XBNiT#P_{;8*6 zY12kz)N&djD=g2EhE-OHwGR_LhBrikz!rJndudqNaW+&anOhsw*rU$11D3FN04tjU zz54Vxc46u;5Rk8TH4v9+KWHbR7T7riXm!h5Klfc)j(Jf8hBb9Q$t5xW0MpO?o|~lq0H)*=^69s4j4D*7TxH3# zQt12lVsD$G=5%tf3^%sC=+f@}~&k8Yi^_+n{1Fm|TXXH~1 zWtk00ZZ@T6QOc^;{^W&(u)q$|ZOt z!-79Bz`Fnh8>dC;Y33y{uWl34_GxzRk}6!zpE->r2^Oz`F&dIreUXUL0rzbynxR@#6d5s}%E~$e)+;o~4W)n^amU9YUr0*pg^X*U;CD*^(p{d|) zb1G@&#PIH3tu%+tpUJ606GW1{5O))1&)6RQXse}ZvP7&sEi#E27bTUEo0bd@JAvc< zIO^UeMEYZX24-HzlG%LIw3e?OH z#UdqqtcGUT*M5>qSNieKK`^zfoH(V67CDuk!%G&V;ffU?s4NKr=%fb4Ah^m7OJk>U+KqsW8k>NNnO<3fjV9J=fZ z;P7mN!0MI0k&8DF05+2zkVGAq@>Uhvkg_mmm6oxZX&SaGesU{=R0$s)><*)w2PYZS zFjsIrQLJSOa(JQ#_v=*u0Pe}Fs|L!$hIpBqfs*Rz0pJ6;{MT=9*QHMt_{qFasYR8S z4nlcwh*m$T5`_ShV6fuJB!ThYq-$Y*p+IIWpD!(E$z88wtdyk7mJNjl$wP9L!4+Ti z{{2ObpDrl|G>grp3R)oS2qKF8`0w{O(O1DaP=?%!tos3VHXFDUIp>=FI*u(f>#@Wb zdS+%$S}+eDG^uj%e{ee!!99mcQh#jH*IRt?S8>aAP8?Zs?sY2fx|lA}>$|cC1ata( zb>^VxnI$Bdq-9~f995sxa6h@|%w7`BhE3Y8G*~i22xY~AN;=uHBzG0h6z0X)74BCn zCmTc%u4ZPPjItqMqbe6>uKxg)zh3p*s@0`dlY`nMY!U(W*T5)kM!M3o%t5}6DN z&$zlTF|p$R0Dpe{cZsdR6R6H7DpYU6c$AkQcD~@Bis_bS@UE*Qj``TJzbx_;xY>xU z!K{EmuWo)iw}q$aSUC{?04>VX@-9FG$vN}3p5&9sU$7qk0Bh(q9{P+fWjP~ckDtOO zX12~KR*8`Ysh<`rW6cXYiZXz{k|?0!S7QNU&iv zbGk>dGUP&8ER|9R%J4~`IPLS)xG?Je7s`C>9H^&9ge=&ZIOHx&d$^#t*p}>U0^fUb zqcJsc1+@);1~&=R><3|jO^75!8iuj7p}*R4)O>_R(tCEFVi7R{=|k**9KDmiEK5bC;!j##3*EMbp(ErZ*+=Z-<>mZ#v{ zZ5Js206WQ#KN@kn11}Uw^zyB?;QN4dCyKG`O`mXb{{Rp%G+a4XK){Y!ry?wgXWsHl z#^CPLGXe=)6i5_1dx%Y2QSlyM)N2w?AWgBy8qc|C4ZCfJ$+)DpY)# z+0=UYE;TCUHi6d_rDN#2UY&=I*|G)4MG_2q7S?QTCWqe7A8PA8@qh6X15w7y!AurO z3wdQ#?Gy&Fa(6!@Afwx{>dv>Hlcs6QKBJJ+E62MTH*P@0*CPJJP&|I!Wbr{Re4-3Q z^D-TcejpuzHD}}R_UW8fD6z29s-_nV9!uV|@8O1iE_aDDvvaYs8#XdC@ys@`W0YVw z`D)4uEwMtK%6Y!OM&tRf=F1?BUtm=+09Af0c2klx1QZ*G4`G5$B8yg zPGOrSKRk$$hc;^cUHa3*l*;-~+66I)`&NNtf`6gU}jUtMS{W7eQdC`+&%%d$HMW44)cw}js zbh<{Sv+FsSc~zU_CQx}b2@`Na@ufVQTWW1?;Ypw@vLkr(O&pneXo44=LCn+gRi_In zj!0GaifJ#*1zUs76S#Cs_;usmJ&uK>PZpmBPnRTPFCiU^v+psloLG559j>_zySO8m zs?X#G3f1nh=1LnFz4 zl|pZO4u@*_c$kttCLSPJ+kgtW}8sj|FPtK!2pudHfPz6o?f_*l@t zmJDocQ2aQeUci#%9lS8Zl$hD2`s>Lg(Jhm;MW*-zBT{G=Rx;qM+ooiYs>-Mve3ME^ z+XQw?TLRwOZ=SO4Lmv}T)$=us7iI9dmEpkL?uj^ra8Bd65`9Ien`#tz8wZW@F`>tU zLyAb&4P9F&R+1@bNsNwoyWO##$J_&ax$8P@4kq3Yqc$%VNtN;#PI%3JS&wOoV3Vjr4f-#QApYVpw`5Z z$0NT?8kdT*b7snw1L=)1cqfWA4^JE+$0KtK8Llij&UXNbku10E?(0 z&DZ1Gmen(#?QdQw2RU_TpDz??`h(AmRAgf=9Gk%^2o5{1aCxr(0D9=89vktDxe}QC z9jRjBx-v-8<9U)ZiXnn2uqwL(EOF0f-wk-X!&;89p=mf8De)}ESaB0ld1R3qc}L=a zvkMA@DQg>80!4As)~lDMXucrMPYGm6nTI5)GD|8M9s*F8iCy_L!)mqH4c@Hqs!5F2 z^eW^Qi#2@jtl{GREE%w3<1r>?kA>U7umNCsRiXzZcD}ovb!^Ob)UsmBT!x2wpkT5T zy}P4~(-k~&0q@E0MKmws1_oq0t{;kE^Cx)rtnrP_>Qbcc0FVa;&5py|9*b+5Jeqv% zsbS5PhlKJ(P(s9GOyIWZP~Vx4H!HwWtQMFMY(wk0?*N&bb+^xY4`v|d3YNR$e0->I zadL5G!PK7GObA_8C;}OAI?6uzhm^Yz=c!gDY-Z zVM?K1G$AJJKxMFfSNTm5&DR|W3kuFJz;%J6Ei$9*8 zMTCmL^aFf>UB7R?T%2i;s~3~dSSYRF6IKIr@U#!dRb=Lq)GiLD)OYxInS%zqrp=J> zp=ivKZJ4relGqV;K~i>=KMV2Gr;2fB$eXqwDXW6Ojm!+|p9d6G$TF z?cHy~EvX&HBj290Rn+p=GADp6xZw}`I(ije!Q7yJhSdC$I{PUlI7^S^OC&Kcml8o9 z{i%G$;B#ttvD=f`x~(F@=7YS-W}{1lO0nX3;ZVmzky;65+xTg*o=Tz-K?JEB2Ow^u z6p?4D+K#GxH-o9+Xz&%uIWk7Ra*-&G!mE{{15<4T_CGbyw#eBs%`)T8kZyKGAfs63 zz~m5l3tq&0bXE3bVrqvWeAx12G3J1l>Qohthz87Nmy_-rwT`r&?#__{@};ZdXX%LdM0)|ZvIo5J0p4) zNH-z@$g@;Qs{a69vzYPrOi1Uunb?>ScPm;>E<`CM7lwGj^AJE8;#0S~3*wYg^V{#$ zjaOMZ+!#{3fiKd4+qV<5VN&GPSw9~P02DgE^qQO)rd%8uw0x-*l1!O)#3ELITB;zh z4Nry2cPUkow@e8vSb_-J3q3XP81r>uG~C?*j!Hv;B$Zn|Lgq@+Jd4ywn2KGTgkGLd`-E$7yOg%eOF`>qrCQMc*Y27jy%&fxgREbuqfT8#4 z-%ik?)HL~DE-0~16ZtW?QyUo=dWtC=1sno-g0a+C*=fhiW)diie(Sb=mK@ z{{WXsUNF$0(K9jpi6aqC2w2uO8$dK~b&mH`f46c5o;}=m4PZQ%nY=3NK2OT<%?>_q}P4)N62oi z_?~Q3ToHnYV zE4kYuN{v7qi>mwc@6ioANy^o9tww3)pAS*T4F*0VMq=|D%aTWH?g%?a95(NP)i%kC z14~T!CSOwRiBU;px?^@Y^>8>MzfPEFEoqbh1enyOKM8oBLC`X##}6!;p2-aP8%jk2 zg&~l+HUalx&m;;5l6uCr@v7zIymKY72p-TLDVWzcy2t7VSze5aHEamyQqaqt63!8K z8PqUhpnKf`N2YyVJl$JW)H8J)gr0WFB3YPiNirFUY5;aoxb_2refl#V;J_Lqe;&7` zpN3QJ9%&UM0V%kBypTTE-?;sHE2C+;UOp_Eslb3|fU2<1iy44$0A{{J zQnL#0yYFFEbdG%J5(N5$$BeUjmWkR+cRbMcANA^9}B~8AzW65OuYX9Elh5Fy~wE}e}onF z0c4X~XdbznU%}I`a&mIyp$6QLNVhSb%rBF6?@TZe}?em9}Z;T>#^ylNW_tj zd@vS&=ef3749rEma4Rh$kr-uO-r0t*zXl*1}uz;UU}auFDEI02`)>p+JC8mJn?3`00}k88^?z5a(t~KBWHlSR1Fz51>f~+}<`AqySqshk16xNYZ@<4B7AX8c zbwA8HWtjvinQGLGYeJJ{9%MJ z#Oaaeh^5$@C5_&2EN-S?5OMEqXR#O3KZ$%_laZVx)9|2*EJ)NApCEbOV=rQ=2>k%y zgU`oEm>DvbGG=CF3|NlUPdKjQ?0qMStL^dn6M9~$1X84{8>saaQpL<|Vwf@J!5rUU z2SvlWX}QiYAm5hA-~C8JG+9jPDWk+5KGrp;aPa=3Og|i&2 zlkL#Y4(YJ!gD>i0pKe4_964>j8el+jL~6{+pjn_)6GZV{568xfG&|+WVZ(_*dmNrX z9Cv>Ghws4Y{{R=nYl-2hGCU=sEE)K6E-cPf+BJ%puKKee29D0kQi}lHX40uvyYdY` z>$70f-#}HQ4G~;M&^#LWX{ju+zEl#w?CyDFujre=TUMQPO2UQr^8HRHsJWtv@9d3Bvp zS0EI}FyYAZL9v%|5Qd8qx3t+UM2_7X)ATHCeL{Sn6JtvNnU+LNJQP(+SZCkDR zESFUAs7bRiGfqZF;rS*fn8L0DZbH^iuv-K4`}Gz_iSlwVU+YpudWqFqB?_R5^c&%J z*Kln2qHm_@b^ibdU`>scji+Jb?UWUfKvLdYAw%UjCusnFWfw;7&7*jgd^rmw{u|XN zh?G=(c_lMOM$UEs$3Qs0vGo8fgWP<5vuZKb9A7g&e#q<~jIf)$EnX(lvZB@VaqzNn zkPS8RAIcKsyQ(5?BVikN?jVAo6I^tUnIur8!K9K(lVn>6b!dPzH+C0ldwd=%sI;FE zWvgMw9&~ekG>I$`&IFrI;>0L!X^A_BxZ|pp?E6c3i093s2nxsEzoZS^`+M}>AGD=P zr6*c?jWNo)y|$fBwpJq>K!QJ$DNFG+HIS*qr`-O^jLa;u%sy#Ip_83ti_i%GF6Xm^?3&f{Oo zxE*L<>;C`?2~p$jb-2gk=i7o_q&dQL3%yntwCoX-%&P5-^&OQv$*Z+A3kFp`Z;qBR zw9SVY$&SrU1_iG)NWLGf*yFQE#x|>;}&} zhkl8~_*k+>l{_-OMp1@1yxD&cK+IK|_VK*#V?eM4dy&yFMx87$sZ(d3ym(uH(`tse zk!`DqMBW&|STJ$K%`pQnG?rlUFjw+-A>eJRAcpl2Na|k?#f?5@Y>|EvpDFB0&BpF& zhy{)IB;U#D&GndkKZQKX`fr?J5(wS^PD)E8UAdeIFN6Ov$kJ zyiSQKc*OtcPYh#?}ymA`{A=IL^jSaFf;dt@&ElW@E{!2$B zIoTN)xdNOrMYOnNbv#oo+WZ?dc@v{}Y-xJdDAgS1G!v^y=ELM}P=G{91%Oc*Rt!6q z@AFGf)+9ekto?L)FvpO#HcW*UN#!a_wNc@H?#cG;*SUKBpQObU*ts8Algx{mkQ>Z- zKtR9-KP1x{9jJB(tvoFXn0YUB1E}H&zLweKCq$c^T~D)UGdl3y?ux?}Rz5j-q%z77 zGt3W42$!G<3`Mui05Qz4QfB+m#OybVK9z>_qzk-w89ix@XvTaZQ5NURlGX(MX_LF9&kEGIirn?E2NP0R#v zt(=7bs|0qn1M<_++9<79Af`u)v}`Ri8%@g?x(v9g4lPded4WhNzkcZpa6M-Jefn9L zR=DP9Ie5j9J6Jghx_#Ro7A`(K3imov*B4#XrPs?5v$K4+`oGuzek5MU4$GnTuK6dm13xnjYth=w=|- zyiKUA&}3%o8F-R^_3Mu{VrCA`%Ep#8-?AY(Lvz0Z=z(|2IeAEy`h>nqcID$lFwS-5gw=i^OM zNskYI-I)g~(}|EWas%vV6fsNFbkM`h(Io zckqiVBT+a;C@JSLzCH6KPRA3pCl7b4Jfn#d2C88yF=G+mtT{)GPBIdU>_`5#6-#@SE`E zWi0I$OOK|Bb7pC=S`1X6kj?l&k;x1Q=7?`kvFn{*#D-K62MdZNMMPR2Yjdb?opbuAw=SJBojN<%4=%HBf2S&sWtdqSH$k$iJ~DkcQA9@tCCBbYJCQbG;G z{6m0maXtHU)?Od!zsarJROqr3A zNMcqIls1jHH#B%O)xochsXl;_8Dn^akpk!XmRNx%sllfJ_TAs-rYd4Sp307ES)ZJF z2#v!2wz&If+Y4OqmyM>v!#aeX8Iv7lXyQ5Ae%GP2UiU4&iJ}yWzMJCGd_CeQ0!e`k z$pyeX#c1V>0$X4phEOkn2m{-WzcWXrPae69G@P$1Cni-0W^W;pSLRSTQC!&V?b`HD z0(kNbKQ|q9-8G~caWpaI!yOq(U`M4uRwrmXmXB-O?v+O2>NJ)&FAbcoPoX@O!<>7- z%6ah@@b&ckT)giJM?PHa5H1E*VUjP+%Ok(34{S zSx@ojM9^ly!ILgFk6G07(J=BNWhONn5>|8^vZ{nohA#AfOGFzzwX$fTBs*O;PCYggg*@Re_VJ z=jW!E3{1_A3OAMHC#rd6ZtEIx7$6pTA7~V;di1zAQo*ydKXDtn@zVU2UwPcDcsovm zP?zhqdE?UK$(|)F@I0+KVnZ}as%@!jn)Nt8ezq?e%c1ylEqpQI%*BY{?p;GJIb>1i ziBXG9<+Vx>F;Nhr(h?1W!X{?BhopF$Cp8fugAO;&IFCCqgLIXPiev+J?>6L+FLJf) zNzabAn~^7*m6arD*(Hb#xs z!+LWPRZlG*~e z(mY@go@XLJ#EKk{7+ujl3-Cwq+b71Fn;lCVCOs%dXLuK`cy1*?kpt(2Ya*B6K<6m%?5ml#EFwV41jW3nlu6 zGLjsCHj&5X_aeH`{1K>YnoeFMdGY@MGtz@f8z&xdDa4tJZIGo0RJE(xIqrSBA8T5h z$!LH_9euf9T@{>K+qGcY)LD2Mc9WNvjWbSkw#b_q=2)ayo;FzBSX(56YB&scQ3_7d zI$hRu#C-xOrPO0!l_s298WFk`NcSZrv~9_-E;cqv1ogUq89X(oYF-r7KZ!mW^D;E) zu|#^F*kl`}RxvJE6=!oG4$J@rRQB!prPCp@+Yc?JS@GpaqehgPLJ4a2?^dImvC@T% z56-~^9>2efF-guK%A+1j0lOSJu-$ZdU`hLT?tl6&-9C6?2h}w#K5UkaVaUdsJk*}b z%5j!ASpeYg5J&|AO-Jw8q~%79spJ^YtZgx+9MJFI{{UA$^m|`Kq`}II!&vzdAyX8q zl*~<$ACzO@a(UbdJ*ZvvwTbWHT}j3#PGe}|rdrnmQx+DJf%UnG9FFj`ZUj}l#G{ZL zsI%$rMNtCok5k}7kAl<-vsq9g!M&>RhA}yFB>uyF-Lqfym?~2#Ip5?Qx4|4Gqf;z z>S064%41@IOGPP`n;#jrQ-pN)7To>*J~}t$OZ>_`NXaG+RLJ8oS(O%ez(0u@uq3i- zu8RT5>qhYIiJ9UJRG9E%)NtTseYv>nCNz^#0VE7Y zAoaL^^vxXep=eOzH<_kMtxXis2=_S48=49r6UwxrhrfSn{J=$#9@dUPq<(H}8aMGq z{{Tb5>jUZSZ}H{Z%G1PNrIQM3naCYqBOf7xrz?HQY5)R9{{R}UI8jA{@fn4 zKgJTpsibRI*%29K$DL`FS8RutAP@iyJ->dVmsi0=e=9Fof{koaSQf58-F%z*>2ef# zJxKr?T?(|4FK_AG2_laKimpC7D>j>fCYsBq%{yul;u9m7_r~%Nt@w3CJCy|dcI0*0 zn>Lg(08x!xJZ$+Hd063^p;0fI*dFdCV8@DNm!cov39O%iM#gWtM*Q) zA*0<+h<}-nEOATaNURX408rcr?!=x*?_WJz#nZE9z?12P65Cn@jE80JSdu$f;9d9X z<~~L?EdFdN;zM7RYoC#QO!~-_6fsOz$pA2~zeR2wjY5LwYzn?FhccN}hU|7`Ae0-) z2D<<__xI?GUKYp3ap$tFerA$Q#^`bte_x)V8q7gdG*7g524XlT?boAPNYwc;K^U(4 zcXRumnr0ctXb2?KJ5ii%H%r7|=6Po)`hgLxdm0?q@74FshY~VyFx0W*Vik|u=bkU; zrTk2+*}|}q!i1&t5I`~@N)>aItj0{fF*zzgU8eO|BA8$r3NQ~>V&;SfIASRg6V z5;3GWu@{rdzd+hnAO~F6x@I{O{mO~QIzQC5dAF=C2zfi4BxoNOB)b-$1 z#V}3GuE&Tq8JU+$MS=x3@<(@ElW*SZ@6ajpnZaK^Vp!VLVQl=Kt(1LFG5~`oHyRQj zY)C?sCW#%m_P(!TVnkjj$$POpbdOZ<F8OG|jZo_9MBY$?1_iJCBhRhA5 zYm13l^g08;SW5}|r=e%o5{N8s=Dn+r^XP^?k&hIzG(Ks@Ha4<|&hAfj+;-o$emnGc z`5q)P7-P(ASmRqJX%)yOz%-TsvM$Y$e0JzYS&I)KL^C9wGgRnSD+k;uv;D{I*3KH9 z8mlwQxR~zw{?JREFuI3Kf&IXoG;n@J{~#wflFjuSoe5!XwJelgh`8c`9-o z1m(F@9CKXp@B8!|43=$}@UdGUv5nq`wVGe@>UdjHiRB3>frzciia9s`02jCE)6Jj* zOKDnTd~BQF-3+>Z;;tr=N%WVC$_h6VwENwBcK-mMMKQ7lF39xthK#n)6M2ppsXLjC z_W%Mx6;;qPk0ZI4QOKJpumFerGz?7+1q1d6`*qa$O%RSKeIzR@1pp{rq>Cf;Jajsr zO>7t9A0vgoB|xb*YN6t+*>yRwura1!71k>&w3%6yFQoP$p8o*zzKLoYq-&r@k_=IC z1URNNVImb^C1ifqcOhe2j|0=+r4-JV9d92iG1fzb<0t}mSxaz)^W1 zB;QXdSb;LeK`K}yunc?90DN+K^R*b#=x&MDh!;}gW4@)6A_Vf(T#B2R5DnjcNuhUS z@%QNdR+=Nrz=kC9@}n`VEhLB1%;$61N2O;qDMy_Si4ZlY@dP8 zYv2m$f?uP@k||0osgDX|9q?hwuUGqZ!07J@SXapm?+G(MjHfcPQQE@*~HNqfJ4J zdBp)`2_Xcj?xMjY56!pj*S>PfEkz+qMI^VR0I{hz#?=G-{(Ac|NCs@U_>-nyGzu`H znlM0>RMWT}{bz9(&*F8~1W{(?Kr%$G)cHHa=;$^ixznv#=5JK z{cz-}G?62tNy&6(d0CBiJT+J8XTMQotGX;PqY{y-l?~mC@JRXmzo$JZ_c=5MR;wCQ zz&^V!c~=T3Fs0n1c~%atfOoQa90ED+K+PNz0*xXAeu#S~D-K^GbX-?AkG z?AAfE$Q<=5MztTLTh%? zN&fUdw@fjk?mH6BCg_SoBjOcRB*_`F60QYuNj1scAfRuu{B`7o;ar4=@RoSJNZghn zf_eQ#_4M*2Fii)WH1f5%Xy0r~>NbQ6Tz~-=V0x~ry}Y?)gCZHE$|biE=8kqoD_>XQzFq-ug-k(e@Z zvK%1Fh=nSE{wkfz`U@ZD@6~HFM-+@J&Wv4lEIlp9&m;9cdkiy2BxP3T^N|t(W!%-> z4)?(QPj0=*K(olva~y=o02Nki_WuCit1gA!nVFM;sAFZ}9l3F_F_MA3L>26P`D(v< z==5<*_45A!GfCiKEjv1xq>X`KHv*!F+sGgu{VdBHBQ$9y##8BZ=V`mY*@qoJ>l(1u zVuL(lwl*eq@`)so&e78`JBR_Ow2Xac`hmVW1xpZ*NKB=jdJ!I_lQ8s*lnx5eOWK=| zS2i1PAoJUS)mS8k9O$1aGcGgGl|=)wfCj$e@Al}9smu{GG4skv6r`Ih7OMH?whz+# zw|<3WA#g$uQH5XQu=#c*aWrG(x9py)fys4Pb+`rOCH`vwj+p3I_s^V-{D#$y4ELj4G_VkWVJ^HvR z$3@;U2}Y#~BT8EtgkewRa6_wo{{SNo-2J+T2qcr^w2~@EG^&NjwT!W?+x`}IZv3^L0eN;Ht8t%W;jPT}wRj=0@jnkH=%P7kfF zHe~q_#FF`QCNz8GF_X2&!iqi5aen;)o>7OHm5T2pqDaCAam%1217CUvqH372Bki7a zlmtbp*viU7Srm9`{YQR>Y8d-+;oA!C=YGyvSW4ut&tf?v{D(`h0@94<7P(!_#h**b zlN&WvT}?0&D+9ni)R09H$Ui*TJx6OJFjNe+z;0;Yx7*{Z+RPamE<|{G&YdnavE!_; zM>HleKos1g-48vuVk~#-=h8E9<#f--Xwd8t))c11z~JBJch3P^+PWN&m!^_haCHR z^>z>q)f^;PA&V@F`Q#{8_5sG*yV^Sr{T9WRchh2z9buX`$dAoHyPOpyrvs2bJ=Yz1 zCJ4xg7a&dUz;I8`R`kvI+HPJxD`Q8fG>YpkLMSMUX5*2$RwlXc$Q*a*?WhPL1@y=g ziDAU>k%^loG?0I@B#2n-ngl(=6Zvmxt*urYVXNw&iaw|7wq!9I0Sg_zOfdB$Y9%9Qt3O2=9eBJZVnBZMvg1|Hj-JJBu=t2V}OaUpd_~bY#+;2 zecR)c12Preu@J*UE`_bk%7#cE8eQr@+I-!luiWn!U2_I;i$|9pU?q&mSfB@Wa7`a; zukHo*>KqN9PpV@AX|UyB1950o!T#fc@_LUM+vqaW%M89>t(k6!2mV+6&(BvP%BNIj zLJqT?j%D)kvSUDBcF?ZzEp8-sB(T0XWAn*}jk5I3YadZ~-S8D#5zh1o!BLpgAUjW% zSDNI5WDZvKBO2z+W{gPNA!G-XC(BhlpMQ$8W9`>i*^`|^QhZIZ439BoMP14jtPoX+ zHCBDi*HnpIOc_-YGc5SXpxb^OP_g;A=c{=N%Gk_F36Y96wG|9f({R6H6;JQgWnH+; z;x=NlZ7sXE0FS-*{{3Ib%sD!A5zNL}v1Tg^Q5#?*dkeb!#Qaz8dZM$0w5pRc$g#f4 z8-rIi7Phe*{DaXQ4tB*{>}M(DWTa7<2n-O)c6PpaWBOM@WKyxlk_G`oupoT%UwY^5 z&r^{bY2~oiDCUjoXD)5;X;D@QP(deyL=$ygUL-<_W*1tU%NoIjJwmvRD#k|*ytNWd zcHF&EhCtJ*l?+scbWhpw-QLJ_p#Ig@_+Ed z?#GkMk1{!Y?Y@u;IuU-|h_99COtDP5?J5juR~lGyB@!4S$VZW5lt$%44Z%qUja?c& zyK&L&S`7~i#W_*n&6Am;W0>a0`hX#lXhcZ+N!q>n1JlSL+3r@dTr3lU=i9fp1pc4r z{rWYVCSI$p>Jn>{d0BZF{(H$h-lPHpv;cYGINE5h0=NUIci-0pDtZ(SZLreiiv zP7E@(<23O`5l$OHcXGoG*h!BE(v zUIJkzsgVhn%iWHiSDCYDlYJ``Kbb+A_(@vkD_+!Nb zSIySEMT3v5O*3s1NYKX20)R%-#^M}U46C=1&r73VVqhyjU z$t0eLWt=$VaG8rP*%srHRDGaP2Xd0FWVH(508f6ibb?vlRF)YgEZ@}a9@Bj8v&X-G zp50xC!y#i+m5~fefRP+(2RvEaefS^u-X73ST0%H$(Ce6=PMpa%OvVj5R5y&XfC8~t zfKT6{ZQ=bpEz05IJT2I?QW0OE9CZvhiH9S|Nx{Yp&m@ARYxp~?U5}2g$>JuCFu35% zfDk5`0v6|wLh;*=ZiiXDjAtXmqwcE8bqW6f9QEj^%i%nw{{ZVu-RK7iI@lj#M@IA? z3PT}f)OCz(2*NzAzsyBDC{oh1GZMpv=B)d4qo1fw?9%0ANh=}Y1MO8l+zvV!pQ+6< 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 z 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

IZnY+p1 z{xIyZud6SHry|hZxj^X4y*3F8m;v-=C7cxRZy(fbQ>|nep zmm}YCoC9=-k;lMuz)1Y!)yv=~PXd_(_<5f?W&9+>^mQ|ESf^_}IdYQK@7^XG-{FW$ zJ?TDJ78kZo(FOjR#&vsyscBf?KS;fl^!B-6o!+i-%=#V6@N-|`93Y}@x}_te_B5FV z)?=W5c$|12734S btIXGiR!1b4#3Brmvxhm*Y7imND!i{?gx{ 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

)9VtK69e+4Pvb53cL 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ⅈ@ke%Xo_T2f~F|Opi=rs_3$jcwm-ff z2-p(L##JwJS8dO8Z|S}ezF*!{l#}?9a@Qet_xy+JiU=027#K`anMTr?G@!ZE0H}CC$ydG`DZb(()*0t^r_r}7iZEtXJZ=zO& zx|&O~nDw4?g~y7-iE_o4{{W&Rwa3#0rkBZA0X)GOR5FGPINICp0sgpggb~sTX=GPTQIHCQ zZ%7;e0GS*8F@~AK{{YL%q!qgdLQ4Gh_rCV_?}5R~}TJSbJSau9Rb zQe;+Tj2#;t$p^6g@d-c#N_9$@binQihjeS)f@}#Vy|C2~LnAvy2`zOuAB+vn?QwmF zz6+MZX%Mo?@&-Y2>*~|(YwiW@e0noOm{c_ck}MUX5vU^&SQEX67UvZ?yM`5j)!Ov6 zS61@e#-hZ?$#6~g)AO;yM9gDxOr}XRD>DuCi;-eYt;ZPjjRa7&Bg`dv2IcNa7Xa;R zbN;wRB@dSfnN<0j^s?9z$bF6;Ya9 zB-~%rKg*u|@I+&hhV;zPPYqNqB#6j_e+>y&DhB#*+*}WvVO1G?lFd(28Bvl_#aj0u zkg5USb7dF(uy`ev406o2pUhAa_qEAe{&r)B(xj68;XslR6n0rQJ-G+J_r@E$1R!2P zS_)!oGr#ca$e4LS)JUtOlslEUxl}t-b`&!hBjfZNn3$nM?Xw6XxXzjnj|qu zBUF{uK`afs_G@eh&G7X}jy9P=jTC88-M#JpzW7inDLq!NSC;d~04=G2U>mVrUAtVL z*8ryS{Ij4bMq45(*aB~5)!2Wg6*W7G00}|%zJeYGsgfr^Gz$Y|HaieI90bQK$Yl|T z5XL|10^0Q4@qNC%?TSw8SBgoU6qulkR4y3b&?NRg)&p!Fjg*E9u2t0GS%CEHP4@S; z8HlQ9t%0Ob<%)K3>HHv_fdK4mMX>5Rb(S=|%Noc-fX7ayHammu$LoPk@>2=2ORBKJ z=e%tmmt+wu5HyX2xf|fJ7}ecgL8a9~sIxJ-wS~9*zHoRcW|A4r))`U6OQeFOcfUQo zua9{&)JZDI2B}xj#gvPSeLHQ(?Q9UobwbBP-a#7)XHhf^A4v&sSNZ;52LPvuQgW)s z8i?6d!5VHgiycJ!VbjKfiDpkSQy!OMsbXv|Vm+;IuJ}=b;{{Z1_-u69(oNXJBTsumD=@IU{@%6CZ=MOY5 zf!kgvs-uyzHri5*a-~Au#+a0ZJMpThRm%WJ~eKy+X-vIKXK(7A) z!?zbvazN+z@6I2j@yQb~bWJxJh_KjPTzyA4tOa1g1KKzk26c98i#4~uZT7YW8JR9# zNf>;)Yg+x!>-%5|mYZ7oNnNiVq`5x$b|QC(pD$gI-9s?aFWg@Z3yU(ubPYp&UHB&c z*T5q=P$x2@BL4sgmNHnWUHKsPJZ*-tNDxWu4Q8_ea))o~Z-qH+OtLd8h1r188syt@ zcD=iMU=;On)KV9Py!4cZia{mShSt;WHpHY6ytWb$0)nUo?tS~=B5>+SP&W&x+y(D@ z;ZjLu4^O))sS2l2J^uhRwg?x`U12mSuqBxKPj99oAq0`+9&zIlXyYVK zQbD9SlmbfaZ+lo@4R}EXS>}bp#=b(5!%Cal+}mUA^~Pj|X~{Cl3(2GeM7ppCkbS

J?_psXhZHCB!m!8*fq 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 z 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%0A1p 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

kOj2<@KJ498%7t$Ta`}HaBoC4TuKE7Ee!PnTB-+ zV=i8ll=PI4Ecu;vORO~1Foz&XG=$#P8!Cdv*9&XoQ$rjKl0N`Z1mSZg-y6dsV6%`w z&$|9gp}Y$5Rdbw{X>%%6r_QLIlD%ocW2gWDc*V4&fL%!8ff$==lQ$WqW?h-hQuQ+# zB!)>WRRH`JTMH=fdt;dM3QYU#{{Yvt)tR+4Q&Yu5arn>n>KmcjvT>e|*#A~#|2`z@$?1k&JllRg1 zg*afQ^5wIxQ2D5#NV4cquCV@MldJ$#YBx6^78e)#VZ|O%= zYujce{a5Fm@rJExvKHb=Lsiv9R_d|0rXnMaw42)Nu(`FZ{`lEc)l^3)hcTvR`^X|U zk|wmeSlxo1ug=?BYg}`s$un58{L+fHwIY=Hhe=~%qz}ZqTHtEiZ;WpGj8ltHAE36oRl4d1{7TgP- zH{g!g93l#R_ryZJSn@+B@ia+ur?%W4IQYUV8LB3ZIMBSJM-u9QBcofE7Z$i6acoR_ zW}bsJ%a$6*qM3s*4I+h=+Sg-o+rJwFZrHDCb0*B|mDX`uk_K2J5&r-ZH4H+F>UQ#PT>gQbqwold^!O!=C=w)IXFj z9a`S%p;t-N=W~15fNycwVQ{(f5XN zWhz0~k_jYy+Zt*ni^ws`VTW5;%8e+eWd!Yeo8OykFlt%p>1rt?tVrG#B1MtnD!U&} zul#O(x!(i@2~V=RH-EeNzE}~>ad=2q0DcjxZ^h~-bKBz&B#J*VN0yH9uAs3@#{6@8 zfw$$4bv|KEi!BUm9NCkyyuMP9RubD0W4j%#W47nMH1yL+3tGLBr%YrN1d^iO_pm(v zxF-q@7TN}uQ!`1bodRhR7aM_aE=U5~cE%|pjXcvVkTMv>-6YaIHzeEM=D^!+{qV{f zxZoo4qk(wDesOIC*xcU2#O;C8*Or*J>Ky7_DXYuBBa0iAHu&cWK@@2#A(kTXI+p;Q zYzzJtu{XB_Tw2%fjK@jmsV@vHyQp9QPxn6n!azO07(PXl9O{{>W{HH;AI4Yi+&xKR(z*O;tQm!BYhyQ#58W z+RJMr;`+G0-#6a|lm$5uJq=cw-bs?$poLe~miIlo_r42hUDYUo^MTqMgwi!w0!TaC z-)uAUn^0P5W0XiWqA0Tv1&x94wa?d#Ig+wNJaK3-mLI`ovX!|P1l)`LdG^AANwT-G zbiD-B5yKRvgo;@tDR#NO_cymTAYw6;O(b$lO(cktM0B;`B;Mp~!ux$OBd6*JQW+?o zStw_=n8{F0?YpMdHapwR3yo>MMaRZg^;14gXF%-Z0VUAHY`ZZB*$2vv)`t@S-* z5-hM%LREaj8ErOV4=hRTamTg;=S4fRO$Mhig$OLF2)MW>u_M12L^T2^kgK%1*aSf_ zH(=k5xAYUexZeDXHIPSG(s{-gA;0)*faH(+lyXJ)-re`Yr&}1B2=g|ZGp3Lr04Tb= zWvy>jzibaZmX=(~CW1s1?Eq~l8Bho&=Z&whx5gM{@lps~v#Fv@8PsUtM^2Q_VA5+x&i4T*RVD>w*LTJBQ~H~KOw8BBS)17+FYVFh?McHV7FCl1s5XY9x*T+l(j_ zjoMuD!xXNMD;-QiB*#jdn_qvA>xXo~q6)K8c~V4*BV<6lZMeOU>)2yl7FU);sCI@s z66KJS-rt97bG7i|$t4`0bYz+>AQMw5P)?!G9D96?@e~C-Sw^JI!PQIzJ%Ku^1Q}yjSFZ7 z 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

#~ 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

es;|hrGV5NZX=*xSrE_Y^StDX+ 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

4jvUz3Tc7BST> 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 z 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 oAl5iuAWl`oqExj_uaroBcgMV;tF}FpjI%zj_ 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 literal 0 HcmV?d00001 diff --git a/src/backend/src/services/drivers/CoercionService.js b/src/backend/src/services/drivers/CoercionService.js index bd64018b5b..c3784e1780 100644 --- a/src/backend/src/services/drivers/CoercionService.js +++ b/src/backend/src/services/drivers/CoercionService.js @@ -40,6 +40,7 @@ class CoercionService extends BaseService { content_type: 'image' }, coerce: async typed_value => { + this.log.noticeme('coercion is running!'); const response = await CoercionService.MODULES.axios.get(typed_value.value, { responseType: 'stream', }); diff --git a/src/backend/src/services/drivers/DriverService.js b/src/backend/src/services/drivers/DriverService.js index 510b017fcb..c9f4277592 100644 --- a/src/backend/src/services/drivers/DriverService.js +++ b/src/backend/src/services/drivers/DriverService.js @@ -111,6 +111,7 @@ class DriverService extends BaseService { } async _call ({ driver, iface, method, args }) { + console.log('??', driver, iface, method, args); const processed_args = await this._process_args(iface, method, args); if ( Context.get('test_mode') ) { processed_args.test_mode = true; @@ -293,7 +294,7 @@ class DriverService extends BaseService { { name: 'enforce logical rate-limit', on_call: async args => { - if ( ! effective_policy['rate-limit'] ) return args; + if ( ! effective_policy?.['rate-limit'] ) return args; const svc_su = this.services.get('su'); const svc_rateLimit = this.services.get('rate-limit'); await svc_su.sudo(policy_holder, async () => { @@ -309,7 +310,7 @@ class DriverService extends BaseService { { name: 'enforce monthly usage limit', on_call: async args => { - if ( ! effective_policy['monthly-limit'] ) return args; + if ( ! effective_policy?.['monthly-limit'] ) return args; const svc_monthlyUsage = services.get('monthly-usage'); const count = await svc_monthlyUsage.check_2( actor, method_key @@ -356,9 +357,18 @@ class DriverService extends BaseService { name: 'result coercion', on_return: async (result) => { if ( result instanceof TypedValue ) { + const svc_registry = this.services.get('registry'); + const c_interfaces = svc_registry.get('interfaces'); + + console.log('????--1', iface); const interface_ = c_interfaces.get(iface); - let desired_type = interface_.methods[method] - .result_choices[0].type; + console.log('????--2', interface_); + const method_spec = interface_.methods[method]; + let desired_type = + method_spec.result_choices + ? method_spec.result_choices[0].type + : method_spec.result.type + ; const svc_coercion = services.get('coercion'); result = await svc_coercion.coerce(desired_type, result); } diff --git a/tools/run-selfhosted.js b/tools/run-selfhosted.js index a659656a1a..ec2985bcac 100644 --- a/tools/run-selfhosted.js +++ b/tools/run-selfhosted.js @@ -83,7 +83,8 @@ const main = async () => { CoreModule, DatabaseModule, LocalDiskStorageModule, - SelfHostedModule + SelfHostedModule, + TestDriversModule, } = (await import('@heyputer/backend')).default; const k = new Kernel({ @@ -93,6 +94,7 @@ const main = async () => { k.add_module(new DatabaseModule()); k.add_module(new LocalDiskStorageModule()); k.add_module(new SelfHostedModule()); + k.add_module(new TestDriversModule()); k.boot(); }; From 7a09c5c47a3ccf37cd02c11b129006035304d29e Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 29 Jul 2024 20:35:22 -0400 Subject: [PATCH 0640/2119] doc: add example requests --- .../src/modules/test-drivers/doc/requests.md | 36 +++++++++++++++++++ 1 file changed, 36 insertions(+) create mode 100644 src/backend/src/modules/test-drivers/doc/requests.md diff --git a/src/backend/src/modules/test-drivers/doc/requests.md b/src/backend/src/modules/test-drivers/doc/requests.md new file mode 100644 index 0000000000..30b2e433e1 --- /dev/null +++ b/src/backend/src/modules/test-drivers/doc/requests.md @@ -0,0 +1,36 @@ +```javascript +blob = await (await fetch("http://api.puter.localhost:4100/drivers/call", { + "headers": { + "Content-Type": "application/json", + "Authorization": `Bearer ${puter.authToken}`, + }, + "body": JSON.stringify({ + interface: 'test-image', + method: 'get_image', + args: { + source_type: 'string:url:web' + } + }), + "method": "POST", +})).blob(); +dataurl = await new Promise((y, n) => { + a = new FileReader(); + a.onload = _ => y(a.result); + a.onerror = _ => n(a.error); + a.readAsDataURL(blob) +}); +URL.createObjectURL(await (await fetch("http://api.puter.localhost:4100/drivers/call", { + "headers": { + "Content-Type": "application/json", + "Authorization": `Bearer ${puter.authToken}`, + }, + "body": JSON.stringify({ + interface: 'test-image', + method: 'echo_image', + args: { + source: dataurl, + } + }), + "method": "POST", +})).blob()); +``` From 8b1193736512d88288e24cec295528ad241129c6 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 30 Jul 2024 17:30:28 -0400 Subject: [PATCH 0641/2119] dev: fix incomplete support for multipart driver requests --- .../src/modules/test-drivers/doc/requests.md | 62 ++++++++++ src/backend/src/routers/drivers/call.js | 116 +++++++++++++----- src/backend/src/services/drivers/types.js | 4 + 3 files changed, 150 insertions(+), 32 deletions(-) diff --git a/src/backend/src/modules/test-drivers/doc/requests.md b/src/backend/src/modules/test-drivers/doc/requests.md index 30b2e433e1..39275fb9b1 100644 --- a/src/backend/src/modules/test-drivers/doc/requests.md +++ b/src/backend/src/modules/test-drivers/doc/requests.md @@ -34,3 +34,65 @@ URL.createObjectURL(await (await fetch("http://api.puter.localhost:4100/drivers/ "method": "POST", })).blob()); ``` + +```javascript +await(async () => { + + blob = await (await fetch("http://api.puter.localhost:4100/drivers/call", { + "headers": { + "Content-Type": "application/json", + "Authorization": `Bearer ${puter.authToken}`, + }, + "body": JSON.stringify({ + interface: 'test-image', + method: 'get_image', + args: { + source_type: 'string:url:web' + } + }), + "method": "POST", + })).blob(); + + const endpoint = 'http://api.puter.localhost:4100/drivers/call'; + + const body = { + object: { + interface: 'test-image', + method: 'echo_image', + ['args.source']: { + $: 'file', + size: blob.size, + type: blob.type, + }, + }, + file: [ + blob, + ] + }; + + const formData = new FormData(); + for ( const k in body ) { + console.log('k', k); + const append = v => { + if ( v instanceof Blob ) { + formData.append(k, v, 'filename'); + } else { + formData.append(k, JSON.stringify(v)); + } + }; + if ( Array.isArray(body[k]) ) { + for ( const v of body[k] ) append(v); + } else { + append(body[k]); + } + } + const response = await fetch(endpoint, { + method: 'POST', + headers: { 'Authorization': `Bearer ${puter.authToken}` }, + body: formData + }); + const echo_blob = await response.blob(); + const echo_url = URL.createObjectURL(echo_blob); + return echo_url; +})(); +``` \ No newline at end of file diff --git a/src/backend/src/routers/drivers/call.js b/src/backend/src/routers/drivers/call.js index 8d0ff7aa91..737231af1f 100644 --- a/src/backend/src/routers/drivers/call.js +++ b/src/backend/src/routers/drivers/call.js @@ -16,12 +16,15 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ +const APIError = require("../../api/APIError"); const eggspress = require("../../api/eggspress"); const { FileFacade } = require("../../services/drivers/FileFacade"); const { TypeSpec } = require("../../services/drivers/meta/Construct"); const { TypedValue } = require("../../services/drivers/meta/Runtime"); const { Context } = require("../../util/context"); +const { whatis } = require("../../util/langutil"); const { TeePromise } = require("../../util/promise"); +const { valid_file_size } = require("../../util/validutil"); let _handle_multipart; @@ -55,12 +58,14 @@ module.exports = eggspress('/drivers/call', { const x = Context.get(); const svc_driver = x.get('services').get('driver'); - const interface_name = req.body.interface; - const test_mode = req.body.test_mode; + let p_request = null; + let body; + if ( req.headers['content-type'].includes('multipart/form-data') ) { + ({ params: body, p_data_end: p_request } = await _handle_multipart(req)); + } else body = req.body; - const args = req.headers['content-type'].includes('multipart/form-data') - ? await _handle_multipart(req) - : req.body.args; + const interface_name = body.interface; + const test_mode = body.test_mode; let context = Context.get(); if ( test_mode ) context = context.sub({ test_mode: true }); @@ -68,12 +73,22 @@ module.exports = eggspress('/drivers/call', { const result = await context.arun(async () => { return await svc_driver.call({ iface: interface_name, - method: req.body.method, - args + method: body.method, + format: body.format, + args: body.args, }); }); + // We can't wait for the request to finish before responding; + // consider the case where a driver method implements a + // stream transformation, thus the stream from the request isn't + // consumed until the response is being sent. + _respond(res, result); + + // What we _can_ do is await the request promise while responding + // to ensure errors are caught here. + await p_request; }); const _respond = (res, result) => { @@ -96,49 +111,86 @@ const _respond = (res, result) => { }; _handle_multipart = async (req) => { - const busboy = require('busboy'); - const { Readable } = require('stream'); + const Busboy = require('busboy'); + const { PassThrough } = require('stream'); const params = {}; + const files = []; + let file_index = 0; - const bb = new busboy({ + const bb = Busboy({ headers: req.headers, }); - const p_ready = new TeePromise(); + const p_data_end = new TeePromise(); + const p_nonfile_data_end = new TeePromise(); bb.on('file', (fieldname, stream, details) => { - const file_facade = new FileFacade(); - file_facade.values.set('stream', stream); - file_facade.values.set('busboy:details', details); - if ( params.hasOwnProperty(fieldname) ) { - if ( ! Array.isArray(params[fieldname]) ) { - params[fieldname] = [params[fieldname]]; + p_nonfile_data_end.resolve(); + const fileinfo = files[file_index++]; + stream.pipe(fileinfo.stream); + }); + + const on_field = (fieldname, value) => { + const key_parts = fieldname.split('.'); + const last_key = key_parts.pop(); + let dst = params; + for ( let i = 0; i < key_parts.length; i++ ) { + if ( ! dst.hasOwnProperty(key_parts[i]) ) { + dst[key_parts[i]] = {}; } - params[fieldname].push(file_facade); - } else { - params[fieldname] = file_facade; + if ( whatis(dst[key_parts[i]]) !== 'object' ) { + throw new Error( + `Tried to set member of non-object: ${key_parts[i]} in ${fieldname}` + ); + } + dst = dst[key_parts[i]]; } - }); - bb.on('field', (fieldname, value, details) => { - if ( params.hasOwnProperty(fieldname) ) { - if ( ! Array.isArray(params[fieldname]) ) { - params[fieldname] = [params[fieldname]]; + if ( whatis(value) === 'object' && value.$ === 'file' ) { + const fileinfo = value; + const { v: size, ok: size_ok } = + valid_file_size(fileinfo.size); + if ( ! size_ok ) { + throw APIError.create('invalid_file_metadata'); + } + fileinfo.size = size; + fileinfo.stream = new PassThrough(); + const file_facade = new FileFacade(); + file_facade.values.set('stream', fileinfo.stream); + fileinfo.facade = file_facade, + files.push(fileinfo); + value = file_facade; + } + if ( dst.hasOwnProperty(last_key) ) { + if ( ! Array.isArray(dst[last_key]) ) { + dst[last_key] = [dst[last_key]]; } - params[fieldname].push(value); + dst[last_key].push(value); } else { - params[fieldname] = value; + dst[last_key] = value; + } + }; + + bb.on('field', (fieldname, value, details) => { + const o = JSON.parse(value); + for ( const k in o ) { + on_field(k, o[k]); } }); bb.on('error', (err) => { - p_ready.reject(err); + p_data_end.reject(err); }); bb.on('close', () => { - p_ready.resolve(); + p_data_end.resolve(); }); req.pipe(bb); - await p_ready; + (async () => { + await p_data_end; + p_nonfile_data_end.resolve(); + })(); + + await p_nonfile_data_end; - return params; -} \ No newline at end of file + return { params, p_data_end }; +} diff --git a/src/backend/src/services/drivers/types.js b/src/backend/src/services/drivers/types.js index cf3813852e..1c227bd9f7 100644 --- a/src/backend/src/services/drivers/types.js +++ b/src/backend/src/services/drivers/types.js @@ -98,6 +98,10 @@ class File extends BaseType { } async consolidate (ctx, input, { arg_name }) { + if ( input instanceof FileFacade ) { + return input; + } + const result = new FileFacade(); // DRY: Part of this is duplicating FSNodeParam, but FSNodeParam is // subject to change in PR #647, so this should be updated later. From eeda87855409bd5825177eaa814a6ea8a4825e8a Mon Sep 17 00:00:00 2001 From: haruto Date: Thu, 1 Aug 2024 10:00:19 +0900 Subject: [PATCH 0642/2119] Complete Korean translation #541 Complete Korean translation based on English file #541 --- src/gui/src/i18n/translations/ko.js | 192 ++++++++++++++++++++++++++-- 1 file changed, 179 insertions(+), 13 deletions(-) diff --git a/src/gui/src/i18n/translations/ko.js b/src/gui/src/i18n/translations/ko.js index c9659f622f..a4d485678d 100644 --- a/src/gui/src/i18n/translations/ko.js +++ b/src/gui/src/i18n/translations/ko.js @@ -23,12 +23,16 @@ const ko = { code: "ko", dictionary: { about: "정보", - access_granted_to: "접근 권한 부여", account: "계정", + account_password: "계정 암호 확인", + access_granted_to: "권한 부여 대상", add_existing_account: "기존 계정 추가", all_fields_required: '모든 필드는 필수입니다.', + allow: '승인', apply: "적용", ascending: '오름차순', + associated_websites: "관련 웹사이트", + auto_arrange: '자동 배열', background: "배경", browse: "찾아보기", cancel: '취소', @@ -37,60 +41,131 @@ const ko = { change_language: "언어 변경", change_password: "비밀번호 변경", change_username: "사용자 이름 변경", - clock: '시계', - clock_visible_hide: '숨기기 - 항상 숨김', - clock_visible_show: '표시 - 항상 표시', - clock_visible_auto: '자동 - 숨김', + change_ui_colors: "UI 색상 변경", + change_username: "사용자 이름 변경", + close: '닫기', close_all_windows: "모든 창 닫기", + close_all_windows_confirm: "모든 창을 닫으시겠습니까?", + close_all_windows_and_log_out: '닫기 및 로그아웃', + change_always_open_with: "항상 이 형식의 파일을 열려고 합니까", color: '색상', confirm_account_for_free_referral_storage_c2a: '계정을 생성하고 이메일 주소를 확인하여 1GB의 무료 저장 공간을 받으십시오. 친구도 1GB의 무료 저장 공간을 받게 됩니다.', confirm_new_password: "새 비밀번호 확인", + confirm_2fa_recovery: '복구 코드를 안전한 위치에 저장했습니다', + confirm_account_for_free_referral_storage_c2a: '계정을 만들고 이메일 주소를 확인하면 1GB의 무료 저장 공간을 얻을 수 있습니다. 친구도 1GB의 무료 저장 공간을 얻을 수 있습니다.', + confirm_code_generic_incorrect: "잘못된 코드입니다.", + confirm_code_generic_too_many_requests: "요청이 너무 많습니다. 잠시만 기다려 주세요.", + confirm_code_generic_submit: "코드 제출", + confirm_code_generic_try_again: "다시 시도", + confirm_code_generic_title: "확인코드입력", + confirm_code_2fa_instruction: "인증 앱에서 6자리 코드를 입력합니다.", + confirm_code_2fa_submit_btn: "제출", + confirm_code_2fa_title: "2FA 코드를 입력하세요", + confirm_delete_multiple_items: '이 항목을 영구적으로 삭제하시겠습니까?', + confirm_delete_single_item: '이 항목을 완전히 삭제하시겠습니까?', + confirm_open_apps_log_out: '열려 있는 앱이 있습니다. 로그아웃하시겠습니까?', + confirm_new_password: "새 암호 확인", + confirm_delete_user: "계정을 삭제하시겠습니까? 모든 파일과 데이터가 영구적으로 삭제됩니다. 이 작업은 취소할 수 없습니다.", + confirm_delete_user_title: "계정 삭제?", + confirm_session_revoke: "이 세션을 취소하시겠습니까?", + confirm_your_email_address: "이메일 주소 확인", contact_us: "문의하기", + contact_us_verification_required: "이를 사용하려면 확인된 이메일 주소가 있어야 합니다.", contain: '포함', continue: "계속", copy: '복사', copy_link: "링크 복사", copying: "복사 중", + copying_file: "복사중 %%", cover: '표지', create_account: "계정 생성", create_free_account: "무료 계정 생성", create_shortcut: "바로 가기 만들기", + credits: "크레딧", current_password: "현재 비밀번호", cut: '잘라내기', + clock: "시계", + clock_visible_hide: '숨김 - 항상 숨김', + clock_visible_show: '표시 - 항상 볼 수 있음', + clock_visible_auto: '자동 - 기본값, 전체 화면 모드에서만 볼 수 있습니다.', + close_all: '모두 닫기', + created: '창조됨', date_modified: '수정한 날짜', + default: '표준', delete: '삭제', delete_account: "계정 삭제", delete_permanently: "영구 삭제", + deleting_file: "삭제중 %%", deploy_as_app: '앱으로 배포', descending: '내림차순', + desktop: '탁상용', desktop_background_fit: "맞추기", + developers: "개발자", dir_published_as_website: `%strong% 다음에 게시되었습니다:`, + disable_2fa: '2FA 비활성화', + disable_2fa_confirm: "2FA를 비활성화하시겠습니까?", + disable_2fa_instructions: "비밀번호를 입력하여 2FA를 비활성화합니다.", disassociate_dir: "디렉토리 연결 해제", + documents: '문서', + dont_allow: '허용 안 함', download: '다운로드', + download_file: '파일 다운로드', downloading: "다운로드 중", email: "이메일", + email_change_confirmation_sent: "새 이메일 주소로 확인 이메일이 발송되었습니다. 받은 메일함을 확인하고 지시에 따라 절차를 완료하십시오.", + email_invalid: '이메일이 잘못되었습니다.', email_or_username: "이메일 또는 사용자 이름", + email_required: '이메일이 필요합니다.', empty_trash: '휴지통 비우기', empty_trash_confirmation: `휴지통의 항목을 영구적으로 삭제하시겠습니까?`, - emptying_trash: '휴지통 비우는 중…', + emptying_trash: '휴지통 비우는 중...', + enable_2fa: '2FA 활성화', + end_hard: "하드 종료", + end_process_force_confirm: "이 프로세스를 강제 종료하시겠습니까?", + end_soft: "소프트종료", + enlarged_qr_code: "확대 QR 코드", + enter_password_to_confirm_delete_user: "계정 삭제 확인을 위한 비밀번호 입력", + error_message_is_missing: "오류 메시지가 없습니다.", + error_unknown_cause: "알 수 없는 오류가 발생했습니다.", + error_uploading_files: "파일 업로드 실패", + favorites: "즐겨찾기", feedback: "피드백", feedback_c2a: "아래 양식을 사용하여 피드백, 의견 및 버그 보고를 보내십시오.", feedback_sent_confirmation: "문의해 주셔서 감사합니다. 계정에 이메일이 연결되어 있으면 가능한 빨리 회신 드리겠습니다.", - forgot_pass_c2a: "비밀번호를 잊으셨나요?", + fit: "맞아요", + folder: '폴더', + force_quit: '강제 종료', + forgot_pass_c2a: "비밀번호를 잊어버렸습니까?", from: "보낸 사람", general: "일반", get_a_copy_of_on_puter: `Puter.com에서 '%%'의 사본을 받으세요!`, get_copy_link: '링크 복사', hide_all_windows: "모든 창 숨기기", + home: 'Home', html_document: 'HTML 문서', + hue: 'Hue', image: '이미지', + incorrect_password: "암호가 잘못되었습니다", invite_link: "초대 링크", + item: 'item', items_in_trash_cannot_be_renamed: `이 항목은 휴지통에 있기 때문에 이름을 바꿀 수 없습니다. 이 항목의 이름을 바꾸려면 먼저 휴지통에서 끌어내십시오.`, jpeg_image: 'JPEG 이미지', keep_in_taskbar: '작업 표시줄에 유지', language: "언어", + license: "라이센스", + lightness: '밝기', + link_copied: "링크 복사", + loading: '로딩', log_in: "로그인", + log_into_another_account_anyway: '어쨌든 다른 계정에 로그인합니다', log_out: '로그아웃', + looks_good: "좋아요!", + manage_sessions: "세션 관리", + menubar_style: "메누바 스타일", + menubar_style_desktop: "탁상면", + menubar_style_system: "체계", + menubar_style_window: "윈도우즈", + modified: '변경됨', move: '이동', moving_file: "이동 중 %%", my_websites: "내 웹사이트", @@ -102,30 +177,55 @@ const ko = { name_must_be_string: "이름은 문자열만 가능합니다.", name_too_long: `이름은 %%자보다 길 수 없습니다.`, new: '새로운', + new_email: '새 이메일', new_folder: '새 폴더', new_password: "새 비밀번호", new_username: "새 사용자 이름", + no: "아니요", no_dir_associated_with_site: '이 주소에 연결된 디렉토리가 없습니다.', - no_websites_published: "아직 웹사이트를 게시하지 않았습니다.", + no_websites_published: "아직 웹사이트를 게시하지 않았습니다.", ok: '확인', open: "열기", open_in_new_tab: "새 탭에서 열기", open_in_new_window: "새 창에서 열기", open_with: "열기 방법", + original_name: '원래 이름', + original_path: '원래 경로', + oss_code_and_content: "오픈 소스 소프트웨어 및 콘텐츠", password: "비밀번호", password_changed: "비밀번호가 변경되었습니다.", + password_recovery_rate_limit: "요금 제한에 도달했습니다. 잠시만 기다려 주십시오. 앞으로 이 문제를 방지하려면 페이지를 너무 많이 다시 로드하지 마십시오.", + password_recovery_token_invalid: "이 암호 복구 토큰은 더 이상 유효하지 않습니다.", + password_recovery_unknown_error: "알 수 없는 오류가 발생했습니다. 나중에 다시 시도하십시오.", + password_required: '비밀번호는 필수입니다.', + password_strength_error: "암호는 8자 이상이어야 하며 대문자, 소문자, 숫자 및 특수 문자를 하나 이상 포함해야 합니다.", passwords_do_not_match: '`새 비밀번호`와 `새 비밀번호 확인`이 일치하지 않습니다.', paste: '붙여넣기', paste_into_folder: "폴더에 붙여넣기", + path: '경로', personalization: "개인화 설정", pick_name_for_website: "웹사이트 이름을 선택하세요:", picture: "사진", + pictures: '사진', + plural_suffix: 's', powered_by_puter_js: `Powered by {{link=docs}}Puter.js{{/link}}`, preparing: "준비 중...", preparing_for_upload: "업로드 준비 중...", + print: '인쇄', + privacy: "프라이버시", + proceed_to_login: '로그인 진행', + proceed_with_account_deletion: "계정 삭제 진행", + process_status_initializing: "초기화중", + process_status_running: "진행중", + process_type_app: '앱', + process_type_init: '초기', + process_type_ui: 'UI', properties: "속성", + public: '공개', publish: "게시", publish_as_website: '웹사이트로 게시', + puter_description: `퍼터는 모든 파일, 앱 및 게임을 언제 어디서나 액세스할 수 있는 안전한 한 곳에 보관하는 개인 정보 보호 우선 개인 클라우드입니다.`, + reading_file: "%strong% 읽기", recent: "최근", recommended: "추천", recover_password: "비밀번호 찾기", @@ -136,48 +236,114 @@ const ko = { remove_from_taskbar:'작업 표시줄에서 제거', rename: '이름 바꾸기', repeat: '반복', + replace: "교체", + replace_all: '모두 교체', resend_confirmation_code: "확인 코드 다시 보내기", + reset_colors: "색상 초기화", + restart_puter_confirm: "Puter를 다시 시작하시겠습니까?", restore: "복원", - save_account_to_get_copy_link: "계속하려면 계정을 생성하십시오.", - save_account_to_publish: '계속하려면 계정을 생성하십시오.', + save: '저장', + saturation: '채도', + save_account: '계정 저장', + save_account_to_get_copy_link: "복사할 계정을 만들어 주세요.", + save_account_to_publish: '진행할 계정을 만들어 주세요.', + save_session: '세션 저장', save_session_c2a: '현재 세션을 저장하고 작업을 잃지 않으려면 계정을 생성하십시오.', scan_qr_c2a: '다른 기기에서 이 세션으로 로그인하려면 아래 코드를 스캔하십시오', + scan_qr_2fa: '인증자 앱으로 QR 코드 스캔', + scan_qr_generic: '전화기 또는 다른 장치를 사용하여 이 QR 코드를 스캔합니다', + search: '검색', + seconds: '초', + security: "보안", select: "선택", + selected: '선택됨', select_color: '색상 선택…', + sessions: "세션", send: "보내기", send_password_recovery_email: "비밀번호 복구 이메일 보내기", session_saved: "계정을 생성해 주셔서 감사합니다. 이 세션이 저장되었습니다.", settings: "설정", set_new_password: "새 비밀번호 설정", + share: "공유", share_to: "공유", + share_with: "공유:", + shortcut_to: "바로가기", show_all_windows: "모든 창 표시", show_hidden: '숨김 항목 표시', sign_in_with_puter: "Puter로 로그인", sign_up: "가입", signing_in: "로그인 중…", size: '크기', + skip: '뛰여넘기', + something_went_wrong: "오유가 발생했습니다.", sort_by: '정렬 기준', start: '시작', - storage_usage: "저장 공간 사용량", + status: "상태", + storage_usage: "스토리지 사용량", storage_puter_used: 'Puter에서 사용 중', taking_longer_than_usual: '보통보다 조금 더 오래 걸립니다. 잠시만 기다려 주십시오...', task_manager: "작업 관리자", + taskmgr_header_name: "이름", + taskmgr_header_status: "상태", + taskmgr_header_type: "유형", + terms: "조건", text_document: '텍스트 문서', tos_fineprint: `무료 계정 생성을 클릭하면 Puter의 {{link=terms}}서비스 약관{{/link}}과 {{link=privacy}}개인정보 보호정책{{/link}}에 동의하는 것입니다.`, + transparency: "투명도", trash: '휴지통', + two_factor: '2인자 인증', + two_factor_disabled: '2FA 비활성화', + two_factor_enabled: '2FA 활성화', type: '유형', + type_confirm_to_delete_account: "'확인'을 입력하여 계정을 삭제합니다.", + ui_colors: "UI 색상", + ui_manage_sessions: "세션관리자", + ui_revoke: "취소", undo: '실행 취소', + unlimited: '무제한한', unzip: "압축 해제", upload: '업로드', upload_here: '여기에 업로드', + usage: "사용량", username: "사용자 이름", - username_changed: '사용자 이름이 성공적으로 업데이트되었습니다.', - usage: "사용량", + username_changed: '사용자 이름이 성공적으로 업데이트되었습니다.', + username_required: '사용자 이름이 필요합니다.', versions: "버전", + videos: '비디오', visibility: '가시성', + yes: 'Yes', yes_release_it: '예, 해제합니다', you_have_been_referred_to_puter_by_a_friend: "친구가 Puter로 추천했습니다!", zip: "압축", + zipping_file: "압축중 %strong%", + // === 2FA Setup === + setup2fa_1_step_heading: '인증자 앱 열기', + setup2fa_1_instructions: ` + TOTP(Time-based One-Time Password) 프로토콜을 지원하는 모든 인증자 앱을 사용할 수 있습니다. + 선택할 수 있는 것이 많지만 확실하지 않은 경우 + Authy + Android 및 iOS에 대한 확실한 선택입니다. + `, + setup2fa_2_step_heading: 'QR코드 스캔', + setup2fa_3_step_heading: '6자리 코드 입력', + setup2fa_4_step_heading: '복구 코드 복사', + setup2fa_4_instructions: ` + 이러한 복구 코드는 휴대폰을 분실하거나 인증기 앱을 사용할 수 없는 경우 계정에 액세스할 수 있는 유일한 방법입니다. + 반드시 안전한 곳에 보관하세요. + `, + setup2fa_5_step_heading: '2FA 설정 확인', + setup2fa_5_confirmation_1: '복구 코드를 안전한 위치에 저장했습니다', + setup2fa_5_confirmation_2: '2FA를 활성화할 준비가 되었습니다', + setup2fa_5_button: '2FA 활성화', + + // === 2FA Login === + login2fa_otp_title: '2FA코드입력', + login2fa_otp_instructions: '인증기 앱에서 6자리 코드를 입력합니다.', + login2fa_recovery_title: '복구 코드 입력', + login2fa_recovery_instructions: '복구 코드 중 하나를 입력하여 계정에 액세스합니다.', + login2fa_use_recovery_code: '복구 코드 사용', + login2fa_recovery_back: '뒤로', + login2fa_recovery_placeholder: 'XXXXXXXX', } }; From 1063b6c1ab47583d79905334cfa4c79e294fa389 Mon Sep 17 00:00:00 2001 From: Noru V Date: Thu, 1 Aug 2024 10:28:24 +0900 Subject: [PATCH 0643/2119] Updated Korean translation file --- src/gui/src/i18n/translations/ko.js | 492 +++++++++++++++++++--------- 1 file changed, 330 insertions(+), 162 deletions(-) diff --git a/src/gui/src/i18n/translations/ko.js b/src/gui/src/i18n/translations/ko.js index c9659f622f..df54c3c1bf 100644 --- a/src/gui/src/i18n/translations/ko.js +++ b/src/gui/src/i18n/translations/ko.js @@ -18,167 +18,335 @@ */ const ko = { - name: "한국어", - english_name: "Korean", - code: "ko", - dictionary: { - about: "정보", - access_granted_to: "접근 권한 부여", - account: "계정", - add_existing_account: "기존 계정 추가", - all_fields_required: '모든 필드는 필수입니다.', - apply: "적용", - ascending: '오름차순', - background: "배경", - browse: "찾아보기", - cancel: '취소', - center: '중앙', - change_desktop_background: '바탕 화면 배경 변경…', - change_language: "언어 변경", - change_password: "비밀번호 변경", - change_username: "사용자 이름 변경", - clock: '시계', - clock_visible_hide: '숨기기 - 항상 숨김', - clock_visible_show: '표시 - 항상 표시', - clock_visible_auto: '자동 - 숨김', - close_all_windows: "모든 창 닫기", - color: '색상', - confirm_account_for_free_referral_storage_c2a: '계정을 생성하고 이메일 주소를 확인하여 1GB의 무료 저장 공간을 받으십시오. 친구도 1GB의 무료 저장 공간을 받게 됩니다.', - confirm_new_password: "새 비밀번호 확인", - contact_us: "문의하기", - contain: '포함', - continue: "계속", - copy: '복사', - copy_link: "링크 복사", - copying: "복사 중", - cover: '표지', - create_account: "계정 생성", - create_free_account: "무료 계정 생성", - create_shortcut: "바로 가기 만들기", - current_password: "현재 비밀번호", - cut: '잘라내기', - date_modified: '수정한 날짜', - delete: '삭제', - delete_account: "계정 삭제", - delete_permanently: "영구 삭제", - deploy_as_app: '앱으로 배포', - descending: '내림차순', - desktop_background_fit: "맞추기", - dir_published_as_website: `%strong% 다음에 게시되었습니다:`, - disassociate_dir: "디렉토리 연결 해제", - download: '다운로드', - downloading: "다운로드 중", - email: "이메일", - email_or_username: "이메일 또는 사용자 이름", - empty_trash: '휴지통 비우기', - empty_trash_confirmation: `휴지통의 항목을 영구적으로 삭제하시겠습니까?`, - emptying_trash: '휴지통 비우는 중…', - feedback: "피드백", - feedback_c2a: "아래 양식을 사용하여 피드백, 의견 및 버그 보고를 보내십시오.", - feedback_sent_confirmation: "문의해 주셔서 감사합니다. 계정에 이메일이 연결되어 있으면 가능한 빨리 회신 드리겠습니다.", - forgot_pass_c2a: "비밀번호를 잊으셨나요?", - from: "보낸 사람", - general: "일반", - get_a_copy_of_on_puter: `Puter.com에서 '%%'의 사본을 받으세요!`, - get_copy_link: '링크 복사', - hide_all_windows: "모든 창 숨기기", - html_document: 'HTML 문서', - image: '이미지', - invite_link: "초대 링크", - items_in_trash_cannot_be_renamed: `이 항목은 휴지통에 있기 때문에 이름을 바꿀 수 없습니다. 이 항목의 이름을 바꾸려면 먼저 휴지통에서 끌어내십시오.`, - jpeg_image: 'JPEG 이미지', - keep_in_taskbar: '작업 표시줄에 유지', - language: "언어", - log_in: "로그인", - log_out: '로그아웃', - move: '이동', - moving_file: "이동 중 %%", - my_websites: "내 웹사이트", - name: '이름', - name_cannot_be_empty: '이름은 비워둘 수 없습니다.', - name_cannot_contain_double_period: "이름은 '..' 문자일 수 없습니다.", - name_cannot_contain_period: "이름은 '.' 문자일 수 없습니다.", - name_cannot_contain_slash: "이름에 '/' 문자를 포함할 수 없습니다.", - name_must_be_string: "이름은 문자열만 가능합니다.", - name_too_long: `이름은 %%자보다 길 수 없습니다.`, - new: '새로운', - new_folder: '새 폴더', - new_password: "새 비밀번호", - new_username: "새 사용자 이름", - no_dir_associated_with_site: '이 주소에 연결된 디렉토리가 없습니다.', - no_websites_published: "아직 웹사이트를 게시하지 않았습니다.", - ok: '확인', - open: "열기", - open_in_new_tab: "새 탭에서 열기", - open_in_new_window: "새 창에서 열기", - open_with: "열기 방법", - password: "비밀번호", - password_changed: "비밀번호가 변경되었습니다.", - passwords_do_not_match: '`새 비밀번호`와 `새 비밀번호 확인`이 일치하지 않습니다.', - paste: '붙여넣기', - paste_into_folder: "폴더에 붙여넣기", - personalization: "개인화 설정", - pick_name_for_website: "웹사이트 이름을 선택하세요:", - picture: "사진", - powered_by_puter_js: `Powered by {{link=docs}}Puter.js{{/link}}`, - preparing: "준비 중...", - preparing_for_upload: "업로드 준비 중...", - properties: "속성", - publish: "게시", - publish_as_website: '웹사이트로 게시', - recent: "최근", - recommended: "추천", - recover_password: "비밀번호 찾기", - refer_friends_c2a: "Puter에서 계정을 생성하고 확인한 친구마다 1GB를 받으십시오. 친구도 1GB를 받게 됩니다!", - refer_friends_social_media_c2a: `Puter.com에서 1GB의 무료 저장 공간을 받으십시오!`, - refresh: '새로 고침', - release_address_confirmation: `이 주소를 해제하시겠습니까?`, - remove_from_taskbar:'작업 표시줄에서 제거', - rename: '이름 바꾸기', - repeat: '반복', - resend_confirmation_code: "확인 코드 다시 보내기", - restore: "복원", - save_account_to_get_copy_link: "계속하려면 계정을 생성하십시오.", - save_account_to_publish: '계속하려면 계정을 생성하십시오.', - save_session_c2a: '현재 세션을 저장하고 작업을 잃지 않으려면 계정을 생성하십시오.', - scan_qr_c2a: '다른 기기에서 이 세션으로 로그인하려면 아래 코드를 스캔하십시오', - select: "선택", - select_color: '색상 선택…', - send: "보내기", - send_password_recovery_email: "비밀번호 복구 이메일 보내기", - session_saved: "계정을 생성해 주셔서 감사합니다. 이 세션이 저장되었습니다.", - settings: "설정", - set_new_password: "새 비밀번호 설정", - share_to: "공유", - show_all_windows: "모든 창 표시", - show_hidden: '숨김 항목 표시', - sign_in_with_puter: "Puter로 로그인", - sign_up: "가입", - signing_in: "로그인 중…", - size: '크기', - sort_by: '정렬 기준', - start: '시작', - storage_usage: "저장 공간 사용량", - storage_puter_used: 'Puter에서 사용 중', - taking_longer_than_usual: '보통보다 조금 더 오래 걸립니다. 잠시만 기다려 주십시오...', - task_manager: "작업 관리자", - text_document: '텍스트 문서', - tos_fineprint: `무료 계정 생성을 클릭하면 Puter의 {{link=terms}}서비스 약관{{/link}}과 {{link=privacy}}개인정보 보호정책{{/link}}에 동의하는 것입니다.`, - trash: '휴지통', - type: '유형', - undo: '실행 취소', - unzip: "압축 해제", - upload: '업로드', - upload_here: '여기에 업로드', - username: "사용자 이름", - username_changed: '사용자 이름이 성공적으로 업데이트되었습니다.', - usage: "사용량", - versions: "버전", - visibility: '가시성', - yes_release_it: '예, 해제합니다', - you_have_been_referred_to_puter_by_a_friend: "친구가 Puter로 추천했습니다!", - zip: "압축", - } + name: "한국어", + english_name: "Korean", + code: "ko", + dictionary: { + about: "정보", + account: "계정", + account_password: "", + access_granted_to: "접근 권한 부여", + add_existing_account: "기존 계정 추가", + all_fields_required: "모든 항목은 필수 입력사항입니다.", + allow: "허용", + apply: "적용", + ascending: "오름차순", + associated_websites: "관련 웹사이트", + auto_arrange: "자동 정렬", + background: "배경", + browse: "찾아보기", + cancel: "취소", + center: "중앙", + change_desktop_background: "바탕 화면 배경 변경…", + change_email: "이메일 변경", + change_language: "언어 변경", + change_password: "비밀번호 변경", + change_ui_colors: "UI 색상 변경", + change_username: "사용자 이름 변경", + close: "닫기", + close_all_windows: "모든 창 닫기", + close_all_windows_confirm: "정말 모든 창을 닫으시겠습니까?", + close_all_windows_and_log_out: "창을 닫고 로그아웃", + change_always_open_with: "이 형식의 파일을 항상 다음 앱으로 여시겠습니까?:", + color: "색상", + confirm: "확인", + confirm_2fa_setup: "코드를 인증 앱에 추가했습니다", + confirm_2fa_recovery: "복구 코드를 안전한 위치에 저장했습니다", + confirm_account_for_free_referral_storage_c2a: + "계정을 생성하고 이메일 주소를 확인하여 1GB의 무료 저장 공간을 받으십시오. 친구도 1GB의 무료 저장 공간을 받게 됩니다.", + confirm_code_generic_incorrect: "잘못된 코드입니다.", + confirm_code_generic_too_many_requests: "요청이 너무 많습니다. 몇 분만 기다려주십시오.", + confirm_code_generic_submit: "코드 제출", + confirm_code_generic_try_again: "재시도", + confirm_code_generic_title: "확인 코드를 입력하십시오", + confirm_code_2fa_instruction: "인증 앱의 6자리 코드를 입력하십시오.", + confirm_code_2fa_submit_btn: "제출", + confirm_code_2fa_title: "2FA 코드를 입력하십시오", + confirm_delete_multiple_items: "정말로 이 항목들을 영구적으로 삭제하시겠습니까?", + confirm_delete_single_item: "이 항목을 영구적으로 삭제하시겠습니까?", + confirm_open_apps_log_out: "열려있는 앱들이 있습니다. 정말로 로그아웃 하시겠습니까?", + confirm_new_password: "새 비밀번호 확인", + confirm_delete_user: "정말로 계정을 삭제하시겠습니까? 모든 파일과 데이터가 영구적으로 삭제됩니다. 이 작업은 취소될 수 없습니다.", + confirm_delete_user_title: "계정 삭제?", + confirm_session_revoke: "정말로 이 세션을 취소하시겠습니까?", + confirm_your_email_address: "이메일 주소를 확인하십시오", + contact_us: "문의하기", + contact_us_verification_required: "인증된 이메일 주소가 있어야 합니다.", + contain: "포함", + continue: "계속", + copy: "복사", + copy_link: "링크 복사", + copying: "복사 중", + copying_file: "%% 복사 중", + cover: "표지", + create_account: "계정 생성", + create_free_account: "무료 계정 생성", + create_shortcut: "바로 가기 만들기", + credits: "크레딧", + current_password: "현재 비밀번호", + cut: "잘라내기", + clock: "시계", + clock_visible_hide: "숨기기 - 항상 숨김", + clock_visible_show: "표시 - 항상 표시", + clock_visible_auto: "자동 - 숨김", + close_all: "전부 닫기", + created: "만든 날짜", + date_modified: "수정한 날짜", + default: "기본값", + delete: "삭제", + delete_account: "계정 삭제", + delete_permanently: "영구 삭제", + deleting_file: "%% 삭제 중", + deploy_as_app: "앱으로 배포", + descending: "내림차순", + desktop: "바탕화면", + desktop_background_fit: "맞추기", + developers: "개발자", + dir_published_as_website: `%strong% 다음에 게시되었습니다:`, + disable_2fa: "2FA 비활성화", + disable_2fa_confirm: "정말로 2FA를 비활성화 하시겠습니까?", + disable_2fa_instructions: "2FA 비활성화를 하려면 비밀번호를 입력하십시오.", + disassociate_dir: "디렉토리 연결 해제", + documents: "문서", + dont_allow: "허용하지 않음", + download: "다운로드", + download_file: "파일 다운로드", + downloading: "다운로드 중", + email: "이메일", + email_change_confirmation_sent: "새 이메일 주소로 확인 메일이 전송되었습니다. 받은 편지함을 확인하시고 안내에 따라 절차를 완료하십시오.", + email_invalid: "이메일이 유효하지 않습니다.", + email_or_username: "이메일 또는 사용자 이름", + email_required: "이메일은 필수 입력사항입니다.", + empty_trash: "휴지통 비우기", + empty_trash_confirmation: `휴지통의 항목을 영구적으로 삭제하시겠습니까?`, + emptying_trash: "휴지통 비우는 중…", + enable_2fa: "2FA 활성화", + end_hard: "하드 종료", + end_process_force_confirm: "정말로 이 프로세스를 강제 종료 하시겠습니까?", + end_soft: "소프트 종료", + enlarged_qr_code: "확대된 QR 코드", + enter_password_to_confirm_delete_user: "계정 삭제를 승인하려면 비밀번호를 입력하십시오.", + error_message_is_missing: "오류 메세지를 찾을 수 없습니다.", + error_unknown_cause: "알 수 없는 오류가 발생했습니다.", + error_uploading_files: "파일들을 업로드 하는데 실패했습니다", + favorites: "즐겨찾기", + feedback: "피드백", + feedback_c2a: "아래 양식을 사용하여 피드백, 의견 및 버그 보고를 보내십시오.", + feedback_sent_confirmation: "문의해 주셔서 감사합니다. 계정에 이메일이 연결되어 있으면 가능한 빨리 회신 드리겠습니다.", + fit: "맞춤", + folder: "폴더", + force_quit: "강제 종료", + forgot_pass_c2a: "비밀번호를 잊으셨나요?", + from: "보낸 사람", + general: "일반", + get_a_copy_of_on_puter: `Puter.com에서 '%%'의 사본을 받으세요!`, + get_copy_link: "링크 복사", + hide_all_windows: "모든 창 숨기기", + home: "홈", + html_document: "HTML 문서", + hue: "색조", + image: "이미지", + incorrect_password: "잘못된 비밀번호", + invite_link: "초대 링크", + item: "item", + items_in_trash_cannot_be_renamed: `이 항목은 휴지통에 있기 때문에 이름을 바꿀 수 없습니다. 이 항목의 이름을 바꾸려면 먼저 휴지통에서 끌어내십시오.`, + jpeg_image: "JPEG 이미지", + keep_in_taskbar: "작업 표시줄에 유지", + language: "언어", + license: "라이선스", + lightness: "밝기", + link_copied: "링크 복사됨", + loading: "로드 중", + log_in: "로그인", + log_into_another_account_anyway: "다른 계정으로 로그인", + log_out: "로그아웃", + looks_good: "좋아 보입니다!", + manage_sessions: "세션 관리", + menubar_style: "메뉴 표시줄 스타일", + menubar_style_desktop: "Desktop", + menubar_style_system: "System", + menubar_style_window: "Window", + modified: "수정한 날짜", + move: "이동", + moving_file: "이동 중 %%", + my_websites: "내 웹사이트", + name: "이름", + name_cannot_be_empty: "이름은 비워둘 수 없습니다.", + name_cannot_contain_double_period: "이름은 '..' 문자일 수 없습니다.", + name_cannot_contain_period: "이름은 '.' 문자일 수 없습니다.", + name_cannot_contain_slash: "이름에 '/' 문자를 포함할 수 없습니다.", + name_must_be_string: "이름은 문자열만 가능합니다.", + name_too_long: `이름은 %%자보다 길 수 없습니다.`, + new: "새로 만들기", + new_email: "새 이메일", + new_folder: "새 폴더", + new_password: "새 비밀번호", + new_username: "새 사용자 이름", + no: "아니오", + no_dir_associated_with_site: "이 주소에 연결된 디렉토리가 없습니다.", + no_websites_published: "아직 웹사이트를 게시하지 않았습니다.", + ok: "확인", + open: "열기", + open_in_new_tab: "새 탭에서 열기", + open_in_new_window: "새 창에서 열기", + open_with: "앱으로 열기", + original_name: "원본 이름", + original_path: "원본 경로", + oss_code_and_content: "오픈 소스 소프트웨어 및 콘텐츠", + password: "비밀번호", + password_changed: "비밀번호가 변경되었습니다.", + password_recovery_rate_limit: "속도 제한에 도달했습니다. 몇 분만 기다려 주십시오. 앞으로 이 문제를 방지하려면 페이지를 너무 많이 다시 로드하지 마십시오.", + password_recovery_token_invalid: "이 비밀번호 복구 토큰은 더 이상 유효하지 않습니다.", + password_recovery_unknown_error: "알 수 없는 오류가 발생했습니다. 나중에 다시 시도해주십시오.", + password_required: "비밀번호는 필수 입력사항 입니다.", + password_strength_error: "비밀번호는 반드시 최소 8자 이상이어야 하며 최소 대문자 1개, 소문자 1개, 숫자 1개, 특수문자 1개를 포함해야 합니다.", + passwords_do_not_match: "`새 비밀번호`와 `새 비밀번호 확인`이 일치하지 않습니다.", + paste: "붙여넣기", + paste_into_folder: "폴더에 붙여넣기", + path: "경로", + personalization: "개인 설정", + pick_name_for_website: "웹사이트 이름을 선택하세요:", + picture: "사진", + pictures: "사진", + plural_suffix: "들", + powered_by_puter_js: `제공: {{link=docs}}Puter.js{{/link}}`, + preparing: "준비 중...", + preparing_for_upload: "업로드 준비 중...", + print: "인쇄", + privacy: "개인정보", + proceed_to_login: "로그인 진행", + proceed_with_account_deletion: "계정 삭제 진행", + process_status_initializing: "초기화 중", + process_status_running: "실행 중", + process_type_app: "앱", + process_type_init: "초기화", + process_type_ui: "UI", + properties: "속성", + public: "공개", + publish: "게시", + publish_as_website: "웹사이트로 게시", + puter_description: `Puter는 모든 파일, 앱, 게임을 하나의 안전한 공간에 보관하고 언제 어디서나 접속할 수 있으며 개인 정보 보호를 우선시하는 개인 클라우드입니다. `, + reading_file: "%strong% 읽는 중", + recent: "최근", + recommended: "추천", + recover_password: "비밀번호 찾기", + refer_friends_c2a: "Puter에서 계정을 생성하고 확인한 친구마다 1GB를 받으십시오. 친구도 1GB를 받게 됩니다!", + refer_friends_social_media_c2a: `Puter.com에서 1GB의 무료 저장 공간을 받으십시오!`, + refresh: "새로 고침", + release_address_confirmation: `이 주소를 해제하시겠습니까?`, + remove_from_taskbar: "작업 표시줄에서 제거", + rename: "이름 변경", + repeat: "반복", + replace: "교체", + replace_all: "모두 교체", + resend_confirmation_code: "확인 코드 다시 보내기", + reset_colors: "색상 초기화", + restart_puter_confirm: "정말 Puter를 다시 시작하시겠습니까?", + restore: "복원", + save: "저장", + saturation: "채도", + save_account: "계정 저장", + save_account_to_get_copy_link: "계속하려면 계정을 생성하십시오.", + save_account_to_publish: "계속하려면 계정을 생성하십시오.", + save_session: "세션 저장", + save_session_c2a: "현재 세션을 저장하고 작업을 잃지 않으려면 계정을 생성하십시오.", + scan_qr_c2a: "다른 기기에서 이 세션으로 로그인하려면 아래 코드를 스캔하십시오", + scan_qr_2fa: "인증 앱으로 QR 코드를 스캔하십시오.", + scan_qr_generic: "휴대전화나 다른 기기로 QR 코드를 스캔하십시오", + search: "검색", + seconds: "초", + security: "보안", + select: "선택", + selected: "선택됨", + select_color: "색상 선택…", + sessions: "세션", + send: "보내기", + send_password_recovery_email: "비밀번호 복구 이메일 보내기", + session_saved: "계정을 생성해 주셔서 감사합니다. 이 세션이 저장되었습니다.", + settings: "설정", + set_new_password: "새 비밀번호 설정", + share: "공유", + share_to: "공유처", + share_with: "공유 대상:", + shortcut_to: "바로 가기", + show_all_windows: "모든 창 표시", + show_hidden: "숨김 항목 표시", + sign_in_with_puter: "Puter로 로그인", + sign_up: "가입", + signing_in: "로그인 중…", + size: "크기", + skip: "건너뛰기", + something_went_wrong: "무언가 잘못되었습니다.", + sort_by: "정렬 기준", + start: "시작", + status: "상태", + storage_usage: "저장 공간 사용량", + storage_puter_used: "Puter에서 사용 중", + taking_longer_than_usual: "보통보다 조금 더 오래 걸립니다. 잠시만 기다려 주십시오...", + task_manager: "작업 관리자", + taskmgr_header_name: "이름", + taskmgr_header_status: "상태", + taskmgr_header_type: "유형", + terms: "약관", + text_document: "텍스트 문서", + tos_fineprint: `무료 계정 생성을 클릭하면 Puter의 {{link=terms}}서비스 약관{{/link}}과 {{link=privacy}}개인정보 보호정책{{/link}}에 동의하는 것입니다.`, + transparency: "투명도", + trash: "휴지통", + two_factor: "2단계 인증(2FA)", + two_factor_disabled: "2FA 비활성화됨", + two_factor_enabled: "2FA 활성화됨", + type: "유형", + type_confirm_to_delete_account: "계정을 삭제하려면 'confirm'을 입력하십시오.", + ui_colors: "UI 색상", + ui_manage_sessions: "세션 관리자", + ui_revoke: "취소", + undo: "실행 취소", + unlimited: "무제한", + unzip: "압축 해제", + upload: "업로드", + upload_here: "여기에 업로드", + usage: "사용량", + username: "사용자 이름", + username_changed: "사용자 이름이 성공적으로 업데이트되었습니다.", + username_required: "사용자 이름은 필수 입력사항입니다.", + versions: "버전", + videos: "동영상", + visibility: "가시성", + yes: "예", + yes_release_it: "예, 해제합니다", + you_have_been_referred_to_puter_by_a_friend: "친구가 Puter로 추천했습니다!", + zip: "압축", + zipping_file: "%strong% 압축 중", + + // === 2FA Setup === + setup2fa_1_step_heading: "인증 앱을 여십시오", + setup2fa_1_instructions: ` + 시간 기반 일회용 비밀번호(TOTP) 프로토콜을 지원하는 모든 인증 앱을 사용할 수 있습니다. + 선택할 수 있는 앱은 많지만, 잘 모르겠다면 안드로이드 및 iOS용 + Authy + 가 무난한 선택입니다. + `, + setup2fa_2_step_heading: "QR 코드를 스캔하십시오", + setup2fa_3_step_heading: "6자리 코드를 입력하십시오", + setup2fa_4_step_heading: "복구 코드를 복사하십시오", + setup2fa_4_instructions: ` + 이 복구코드들은 휴대전화를 잃어버리거나 인증 앱을 사용할 수 없을 때 계정에 접속할 수 있는 유일한 수단입니다. + 반드시 안전한 장소에 보관하세요. + `, + setup2fa_5_step_heading: "2FA 설정 확인", + setup2fa_5_confirmation_1: "복구 코드를 안전한 위치에 저장했습니다", + setup2fa_5_confirmation_2: "2FA를 활성화할 준비가 되었습니다", + setup2fa_5_button: "2FA 활성화", + + // === 2FA Login === + login2fa_otp_title: "2FA 코드를 입력하십시오", + login2fa_otp_instructions: "인증 앱의 6자리 코드를 입력하십시오.", + login2fa_recovery_title: "복구코드를 입력하십시오", + login2fa_recovery_instructions: "계정 접속을 위해 복구코드들 중 하나를 입력하십시오.", + login2fa_use_recovery_code: "복구코드 사용", + login2fa_recovery_back: "뒤로 가기", + login2fa_recovery_placeholder: "XXXXXXXX", + }, }; -export default ko; \ No newline at end of file +export default ko; From e8b57debe9cab07b529355966ba80b3d8672427f Mon Sep 17 00:00:00 2001 From: Noru V Date: Thu, 1 Aug 2024 11:09:18 +0900 Subject: [PATCH 0644/2119] Updated plural suffix problem related to showing the number of items when you use Explorer --- src/gui/src/i18n/translations/ko.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/gui/src/i18n/translations/ko.js b/src/gui/src/i18n/translations/ko.js index df54c3c1bf..e2d78c5d9f 100644 --- a/src/gui/src/i18n/translations/ko.js +++ b/src/gui/src/i18n/translations/ko.js @@ -148,7 +148,7 @@ const ko = { image: "이미지", incorrect_password: "잘못된 비밀번호", invite_link: "초대 링크", - item: "item", + item: "개 항목", items_in_trash_cannot_be_renamed: `이 항목은 휴지통에 있기 때문에 이름을 바꿀 수 없습니다. 이 항목의 이름을 바꾸려면 먼저 휴지통에서 끌어내십시오.`, jpeg_image: "JPEG 이미지", keep_in_taskbar: "작업 표시줄에 유지", @@ -163,9 +163,9 @@ const ko = { looks_good: "좋아 보입니다!", manage_sessions: "세션 관리", menubar_style: "메뉴 표시줄 스타일", - menubar_style_desktop: "Desktop", - menubar_style_system: "System", - menubar_style_window: "Window", + menubar_style_desktop: "바탕화면", + menubar_style_system: "시스템", + menubar_style_window: "윈도우", modified: "수정한 날짜", move: "이동", moving_file: "이동 중 %%", @@ -208,7 +208,7 @@ const ko = { pick_name_for_website: "웹사이트 이름을 선택하세요:", picture: "사진", pictures: "사진", - plural_suffix: "들", + plural_suffix: " ", powered_by_puter_js: `제공: {{link=docs}}Puter.js{{/link}}`, preparing: "준비 중...", preparing_for_upload: "업로드 준비 중...", From 09289b5004593883475e0991d57c7a38ae1f2602 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 1 Aug 2024 17:04:45 -0700 Subject: [PATCH 0645/2119] Update README.md --- README.md | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/README.md b/README.md index 72e3bfff75..c1df7e22fb 100644 --- a/README.md +++ b/README.md @@ -96,6 +96,16 @@ Puter is available as a hosted service at [**puter.com**](https://puter.com).
+## System Requirements + +- **Operating Systems:** Linux, macOS, Windows +- **RAM:** 2GB minimum (4GB recommended) +- **Disk Space:** 1GB free space +- **Node.js:** Version 16+ (Version 22+ recommended) +- **npm:** Latest stable version + +
+ ## Support Connect with the maintainers and community through these channels: From a2255521f2505173a3d44a36ee26ef4839f9ae1a Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 1 Aug 2024 18:54:10 -0700 Subject: [PATCH 0646/2119] Escape `rootItems` in Dev Center before printing --- src/dev-center/js/dev-center.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/dev-center/js/dev-center.js b/src/dev-center/js/dev-center.js index a70485fa2c..9be94f519e 100644 --- a/src/dev-center/js/dev-center.js +++ b/src/dev-center/js/dev-center.js @@ -592,7 +592,7 @@ async function edit_app_section(cur_app_name) { let items = e.detail.items; // ---------------------------------------------------- - // one Puter files dropped + // One Puter file dropped // ---------------------------------------------------- if (items.length === 1 && !items[0].isDirectory) { if (items[0].name.toLowerCase() === 'index.html') { @@ -745,6 +745,7 @@ async function edit_app_section(cur_app_name) { else if (rootKeys.length > 3) rootItems = rootKeys[0] + ', ' + rootKeys[1] + ', and ' + (rootKeys.length - 2) + ' more item' + (rootKeys.length - 2 > 1 ? 's' : ''); + rootItems = html_encode(rootItems); $('.drop-area').removeClass('drop-area-hover'); $('.drop-area').addClass('drop-area-ready-to-deploy'); drop_area_content = `

${rootItems}

Ready to deploy 🚀

`; From fa2702183cfefb4abdcb1e59e965d91e0455320c Mon Sep 17 00:00:00 2001 From: Razy F <105067767+Razy-F@users.noreply.github.com> Date: Fri, 2 Aug 2024 09:06:34 +0300 Subject: [PATCH 0647/2119] Add the new he.js translation filee --- src/gui/src/i18n/translations/he.js | 369 ++++++++++++++++++++++++++++ 1 file changed, 369 insertions(+) create mode 100644 src/gui/src/i18n/translations/he.js diff --git a/src/gui/src/i18n/translations/he.js b/src/gui/src/i18n/translations/he.js new file mode 100644 index 0000000000..9a77db0575 --- /dev/null +++ b/src/gui/src/i18n/translations/he.js @@ -0,0 +1,369 @@ +/** + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ + +const en = { + name: "עברית", + english_name: "Hebrew", + code: "he", + dictionary: { + about: "אודות", + account: "חשבון", + account_password: "אמת את סיסמת החשבון", + access_granted_to: "ניתנת גישה ל", + add_existing_account: "הוספת חשבון קיים", + all_fields_required: "כל השדות הם שדות חובה.", + allow: "להרשות", + apply: "ביצוע", + ascending: "בסדר עולה", + associated_websites: "אתרים קשורים", + auto_arrange: "סידור אוטומטי", + background: "רקע", + browse: "דפדף", + cancel: "ביטול", + center: "אמצע", + change_desktop_background: "שינוי רקע לשולחן העבודה…", + change_email: "שינוי כתובת אימייל", + change_language: "החלפת שפה", + change_password: "שינוי סיסמה", + change_ui_colors: "שינוי צבעי ממשק המשתמש", + change_username: "שינוי שם משתמש", + close: "סגירה", + close_all_windows: "סגירת כל החלונות", + close_all_windows_confirm: "האם אתה בטוח שברצונך לסגור את כל החלונות?", + close_all_windows_and_log_out: "סגור את החלונות והתנתק", + change_always_open_with: "האם אתה רוצה תמיד לפתוח סוג זה של קובץ עם", + color: "צבע", + confirm: "לאשר", + confirm_2fa_setup: "הוספתי את הקוד לאפליקצית האימות שלי", + confirm_2fa_recovery: "שמרתי את קודי השחזור שלי במיקום מאובטח", + confirm_account_for_free_referral_storage_c2a: + 'צור חשבון ואשר את כתובת הדוא"ל שלך כדי לקבל 1 גיגה בייט של אחסון בחינם. חברך יקבל גם 1 גיגה בייט של אחסון בחינם.', + confirm_code_generic_incorrect: "קוד שגוי.", + confirm_code_generic_too_many_requests: + "יותר מדי בקשות. אנא המתינו מספר דקות.", + confirm_code_generic_submit: "שלח קוד", + confirm_code_generic_try_again: "נסה שוב", + confirm_code_generic_title: "הזן קוד אישור", + confirm_code_2fa_instruction: "הזינו את הקוד בן 6 הספרות מאפליקציית המאמת.", + confirm_code_2fa_submit_btn: "שלח", + confirm_code_2fa_title: "הזינו קוד אימות דו-שלבי", + confirm_delete_multiple_items: + "האם אתה בטוח שברצונך למחוק פריטים אלה לצמיתות?", + confirm_delete_single_item: "האם ברצונך למחוק פריט זה לצמיתות?", + confirm_open_apps_log_out: + "יש לך אפליקציות פתוחות. האם אתה בטוח שברצונך להתנתק", + confirm_new_password: "אשר סיסמה חדשה", + confirm_delete_user: + "האם אתה בטוח שברצונך למחוק את חשבונך? כל הקבצים והנתונים שלך יימחקו לצמיתות. לא ניתן לבטל פעולה זו.", + confirm_delete_user_title: "מחיקת חשבון?", + confirm_session_revoke: "האם אתה בטוח שברצונך לבטל ישיבה זו?", + confirm_your_email_address: "אשר את כתובת האימייל שלך", + contact_us: "צור קשר", + contact_us_verification_required: + "עליך להיות בעל כתובת אימייל מאומתת כדי להשתמש בזה.", + contain: "מכיל", + continue: "המשיך", + copy: "העתק", + copy_link: "העתק קישור", + copying: "מעתיק", + copying_file: "מעתיק %%", + cover: "כיסוי", + create_account: "יצירת חשבון", + create_free_account: "יצירת חשבון חנמי", + create_shortcut: "יצירת קיצור דרך", + credits: "הערכה", + current_password: "סיסמה נוכחית", + cut: "גזירה", + clock: "שעון", + clock_visible_hide: "הסתר - תמיד מוסתר", + clock_visible_show: "הצג - תמיד מוצג", + clock_visible_auto: "אוטומטי - ברירת מחדל, מוצג רק במצב מסך מלא.", + close_all: "סגירת הכל", + created: "נוצר", + date_modified: "תאריך שינוי", + default: "ברירת מחדל", + delete: "מחיקה", + delete_account: "מחיקת חשבון", + delete_permanently: "מחיקה לצמיתות", + deleting_file: "מוחק %%", + deploy_as_app: "לפרוס כאפליקציה", + descending: "בסדר יורד", + desktop: "שולחן העבודה ", + desktop_background_fit: "התאים", + developers: "מפתחים", + dir_published_as_website: `%strong% פורסם ל:`, + disable_2fa: "השבתת אימות דו-שלבי", + disable_2fa_confirm: "האם אתם בטוחים שברצונכם להשבית אימות דו-שלבי?", + disable_2fa_instructions: "הזינו את הסיסמה שלכם כדי להשבית אימות דו-שלבי.", + disassociate_dir: "נתק מדריך", + documents: "מסמכים", + dont_allow: "אל תאפשר", + download: "הורדה", + download_file: "הורדת קובץ", + downloading: "מוריד", + email: "אימייל", + email_change_confirmation_sent: + "אימייל אישור נשלח לכתובת האימייל החדשה שלך. אנא בדוק את תיבת הדואר הנכנס ופעל לפי ההוראות להשלמת התהליך.", + email_invalid: "כתובת האימייל אינה חוקית.", + email_or_username: "אימייל או שם משתמש", + email_required: "אימייל חובה.", + empty_trash: "ריקון אשפה", + empty_trash_confirmation: `האם אתה בטוח שברצונך למחוק לצמיתות את הפריטים באשפה?`, + emptying_trash: "מרוקן אשפה…", + enable_2fa: "הפעלת אימות דו-שלבי", + end_hard: "נגמר קשה", + end_process_force_confirm: + "האם אתה בטוח שאתה רוצה להפסיק בכוח את התהליך הזה?", + end_soft: "נגמר ברכות", + enlarged_qr_code: "קוד QR מוגדל", + enter_password_to_confirm_delete_user: + "הזן את הסיסמה שלך כדי לאשר את מחיקת החשבון", + error_message_is_missing: "הודעת שגיאה חסרה.", + error_unknown_cause: "אירעה שגיאה לא ידועה.", + error_uploading_files: "העלאת קבצים נכשלה", + favorites: "מועדפים", + feedback: "משוב", + feedback_c2a: + "אנא השתמש בטופס שלהלן כדי לשלוח לנו את המשוב, ההערות ודוחות הבאגים שלך.", + feedback_sent_confirmation: + "תודה שפנית אלינו. אם יש לך איממיל המשויך לחשבון שלך, נחזור אליכם בהקדם האפשרי.", + fit: "להתאים", + folder: "תיקיה", + force_quit: "לעזוב בכוח", + forgot_pass_c2a: "שכחת את הסיסמא?", + from: "טופס", + general: "כללי", + get_a_copy_of_on_puter: `קבל עותק של '%%' ב Puter.com!`, + get_copy_link: "קבל העתק קישור", + hide_all_windows: "הסתר את כל החלונות", + home: "בית", + html_document: "מסמך HTML", + hue: "דרגת צבע", + image: "תמונה", + incorrect_password: "סיסמה שגויה", + invite_link: "קישור הזמנה", + item: "פריט", + items_in_trash_cannot_be_renamed: `לא ניתן לשנות את שם הפריט הזה כי הוא נמצא באשפה. כדי לשנות את שם הפריט הזה, תחילה גרור אותו מחוץ לאשפה.`, + jpeg_image: "JPEG תמונת", + keep_in_taskbar: "שמירה בשורת המשימות", + language: "שפה", + license: "רישיון", + lightness: "בהירות", + link_copied: "הקישור הועתק", + loading: "טוען", + log_in: "התחברות", + log_into_another_account_anyway: "התחבר לחשבון אחר בכל מקרה", + log_out: "התנתק", + looks_good: "נראה טוב!", + manage_sessions: "ניהול ישיבות", + menubar_style: "סגנון שורת התפריט", + menubar_style_desktop: "שולחן העבודה", + menubar_style_system: "מערכת", + menubar_style_window: "חַלוֹן", + modified: "שונה", + move: "לעבור", + moving_file: "מעביר %%", + my_websites: "אתרי האינטרנט שלי", + name: "שם", + name_cannot_be_empty: "השם לא יכול להיות ריק.", + name_cannot_contain_double_period: "השם לא יכול להיות עם סימן '..'.", + name_cannot_contain_period: "השם לא יכול להיות עם סימן '.'.", + name_cannot_contain_slash: "השם לא יכול להיות עם סימן '/'.", + name_must_be_string: "השם יכול להיות רק מחרוזת.", + name_too_long: `השם לא יכול להיות ארוך מ %% אותיות.`, + new: "חדש", + new_email: "אימייל חדש", + new_folder: "תיקייה חדשה", + new_password: "סיסמה חדשה", + new_username: "שם משתמש חדש", + no: "לא", + no_dir_associated_with_site: "אין ספריה המשויכת לכתובת זו.", + no_websites_published: + "עדיין לא פרסמת אתרי אינטרנט. לחץ לחיצה ימנית על תיקיה כדי להתחיל.", + ok: "בסדר", + open: "פתח", + open_in_new_tab: "פתח בלשונית חדשה", + open_in_new_window: "פתח בחלון חדש", + open_with: "לפתוח באמצעות", + original_name: "שם מקורי", + original_path: "מסלול מקורי", + oss_code_and_content: "תוכנה ותוכן בקוד פתוח", + password: "סיסמה", + password_changed: "הסיסמה השתנתה.", + password_recovery_rate_limit: + "הגעתם למגבלת התעריף שלנו; אנא המתינו מספר דקות. כדי למנוע זאת בעתיד, הימנע מטעינה מחדש של הדף יותר מדי פעמים.", + password_recovery_token_invalid: "טוקן שחזור סיסמה זה אינו חוקי יותר.", + password_recovery_unknown_error: + "אירעה שגיאה לא ידועה. נסה שוב מאוחר יותר.", + password_required: "סיסמה חובה.", + password_strength_error: + "הסיסמה חייבת להיות באורך של 8 תווים לפחות ולהכיל לפחות אות גדולה אחת , אות קטנה אחת, מספר אחד ותו מיוחד אחד.", + passwords_do_not_match: "`סיסמה חדשה` ו `אשר סיסמה חדשה` אינן תואמות.", + paste: "הדבק", + paste_into_folder: "הדבק בתיקיה", + path: "מסלול", + personalization: "התאמה אישית", + pick_name_for_website: "בחר שם לאתר האינטרנט שלך:", + picture: "תמונה", + pictures: "תמונות", + plural_suffix: "s", + powered_by_puter_js: `מונע ע"י {{link=docs}}Puter.js{{/link}}`, + preparing: "מכין...", + preparing_for_upload: "מתכוננים להעלאה...", + print: "הדפס", + privacy: "פרטיות", + proceed_to_login: "המשך לכניסה", + proceed_with_account_deletion: "המשך למחיקת חשבון", + process_status_initializing: "אתחול", + process_status_running: "עובד", + process_type_app: "אפליקציה", + process_type_init: "התחלתי", + process_type_ui: "ממשק משתמש", + properties: "תכונות", + public: "ציבורי", + publish: "פרסם", + publish_as_website: "פרסום כאתר אינטרנט", + puter_description: `Puter הוא ענן אישי ששם את הפרטיות בראש סדר העדיפויות כדי לשמור על כל הקבצים שלך, האפליקציות ו המשחקים במקום מאובטח אחד, נגיש מכל מקום ובכל זמן.`, + reading_file: "קורא %strong%", + recent: "לאחרונה", + recommended: "מומלץ", + recover_password: "שחזור סיסמה", + refer_friends_c2a: + "קבל 1 גיגה בייט עבור כל חבר שיוצר ומאשר חשבון ב Puter. גם החבר שלך יקבל 1 גיגה בייט!", + refer_friends_social_media_c2a: `קבל שטח אחסון של 1 גיגה בייט בחינם Puter.com!`, + refresh: "רענן", + release_address_confirmation: `האם אתה בטוח שברצונך לשחרר כתובת זו?`, + remove_from_taskbar: "הסרה משורת המשימות", + rename: "שנה שם", + repeat: "חזור", + replace: "החלף", + replace_all: "החלף הכל", + resend_confirmation_code: "שליחה מחדש של קוד אישור", + reset_colors: "איפוס צבעים", + restart_puter_confirm: "האם אתה בטוח שברצונך להפעיל Puter מחדש ?", + restore: "שחזור", + save: "שמירה", + saturation: "הרויה", + save_account: "שמירת חשבון", + save_account_to_get_copy_link: "אנא צור חשבון כדי להמשיך.", + save_account_to_publish: "אנא צור חשבון כדי להמשיך.", + save_session: "שמירת הפעלה", + save_session_c2a: + "צור חשבון כדי לשמור את ההפעלה הנוכחית שלך ולהימנע מאובדן העבודה שלך.", + scan_qr_c2a: "סרוק את הקוד שלהלן\nכדי להתחבר להפעלה זו ממכשירים אחרים", + scan_qr_2fa: "סרוק את קוד ה- QR באמצעות אפליקציית האימות שלך", + scan_qr_generic: "סרוק קוד QR זה באמצעות הטלפון שלך או מכשיר אחר", + search: "חיפוש", + seconds: "שניות", + security: "אבטחה", + select: "לבחירה", + selected: "נבחר", + select_color: "בחירת צבע…", + sessions: "ישיבות", + send: "שלח", + send_password_recovery_email: "שלח אימייל שחזור סיסמה", + session_saved: "תודה שיצרת חשבון. הפעלה זו נשמרה", + settings: "הגדרות", + set_new_password: "הגדרת סיסמה חדשה", + share: "שיתוף", + share_to: "שתף אל", + share_with: "שתף עם:", + shortcut_to: "קיצור דרך אל", + show_all_windows: "הצג את כל החלונות", + show_hidden: "הצג מוסתר", + sign_in_with_puter: "להתחבר עם Puter", + sign_up: "הרשמה", + signing_in: "התחברות…", + size: "גודל", + skip: "דלג", + something_went_wrong: "משהו השתבש.", + sort_by: "מיין לפי", + start: "התחלה", + status: "סטטוס", + storage_usage: "שימוש באחסון", + storage_puter_used: "בשימוש על ידי Puter", + taking_longer_than_usual: "לוקח קצת יותר זמן מהרגיל. חכה בבקשה...", + task_manager: "מנהל משימות", + taskmgr_header_name: "שם", + taskmgr_header_status: "סטטוס", + taskmgr_header_type: "סוג", + terms: "תנאים", + text_document: "מסמך טקסטואלי", + tos_fineprint: `על ידי לחיצה על 'צור חשבון חינם' אתה מסכים Puter's {{link=terms}}תנאי שימוש{{/link}} ו {{link=privacy}}מדיניות פרטיות{{/link}}.`, + transparency: "שקיפות", + trash: "אשפה", + two_factor: "אימות דו-שלבי", + two_factor_disabled: "אימות דו-שלבי הושבת", + two_factor_enabled: "אימות דו-שלבי הופעל", + type: "סוג", + type_confirm_to_delete_account: "הקלד 'אישור' כדי למחוק את חשבונך.", + ui_colors: "צבעי ממשק משתמש", + ui_manage_sessions: "מנהל ישיבות", + ui_revoke: "בטל", + undo: "בטל", + unlimited: "ללא הגבלה", + unzip: "פתח קובץ מכווץ", + upload: "העלאה", + upload_here: "העלה כאן", + usage: "שמוש", + username: "שם משתמש", + username_changed: "שם המשתמש עודכן בהצלחה.", + username_required: "שם משתמש חובה.", + versions: "גרסאות", + videos: "סרטונים", + visibility: "נראות", + yes: "כן", + yes_release_it: "כן, שחררו אותו", + you_have_been_referred_to_puter_by_a_friend: "הופנית אל Puter על ידי חבר!", + zip: "מכווץ", + zipping_file: "מכווץ קובץ %strong%", + + // === 2FA Setup === + setup2fa_1_step_heading: "פתחו את אפליקציית המאמת", + setup2fa_1_instructions: ` + אתה יכול להשתמש בכל אפליקציית אימות התומכת בפרוטוקול סיסמה חד פעמית מבוססת זמן (TOTP). + יש הרבה לבחירה, אבל אם אתה לא בטוח + Authy + היא בחירה סולידית עבור אנדרואיד ו- iOS. + `, + setup2fa_2_step_heading: "סרוק את קוד ה- QR", + setup2fa_3_step_heading: "הזן את הקוד בן 6 הספרות", + setup2fa_4_step_heading: "העתק את קודי השחזור שלך", + setup2fa_4_instructions: ` + קודי שחזור אלו הם הדרך היחידה לגשת לחשבון שלך במידה של איבוד הטלפון או אי יכולת שימוש באפליקציית המאמת . + הקפד לאחסן אותם במקום בטוח. + `, + setup2fa_5_step_heading: "אשר את הגדרת האימות הדו-שלבי", + setup2fa_5_confirmation_1: "שמרתי את קודי השחזור שלי במיקום מאובטח", + setup2fa_5_confirmation_2: "אני מוכן להפעיל אימות דו-שלבי", + setup2fa_5_button: "הפעלת אימות דו-שלבי", + + // === 2FA Login === + login2fa_otp_title: "הזינו קוד אימות דו-שלבי", + login2fa_otp_instructions: "הזינו את הקוד בן 6 הספרות מאפליקציית המאמת.", + login2fa_recovery_title: "הזן קוד שחזור", + login2fa_recovery_instructions: + "הזן אחד מקודי השחזור שלך כדי לגשת לחשבון שלך.", + login2fa_use_recovery_code: "שימוש בקוד שחזור", + login2fa_recovery_back: "לאחור", + login2fa_recovery_placeholder: "XXXXXXXX", + }, +}; + +export default en; From fcb38aee87d47820a87893ddbc385c57ff2c308d Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 1 Aug 2024 23:53:56 -0700 Subject: [PATCH 0648/2119] Update `translations.js` to add Hebrew files --- src/gui/src/i18n/translations/translations.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/gui/src/i18n/translations/translations.js b/src/gui/src/i18n/translations/translations.js index 0a482c6e42..46824464bd 100644 --- a/src/gui/src/i18n/translations/translations.js +++ b/src/gui/src/i18n/translations/translations.js @@ -27,6 +27,7 @@ import es from './es.js'; import fa from './fa.js'; import fi from './fi.js'; import fr from './fr.js'; +import he from './he.js'; import hi from './hi.js'; import hy from './hy.js'; import it from './it.js'; @@ -67,6 +68,7 @@ export default { fa, fi, fr, + he, hi, hy, it, From 475eb13fb3e9fcfa214cb6c4b56fc08455d2f12d Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Fri, 2 Aug 2024 14:00:44 -0700 Subject: [PATCH 0649/2119] add checkmark to selected language in the settings window --- src/gui/src/UI/Settings/UITabLanguage.js | 2 +- src/gui/src/css/style.css | 14 ++++++++++++++ src/gui/src/icons/checkmark.svg | 3 +++ 3 files changed, 18 insertions(+), 1 deletion(-) create mode 100644 src/gui/src/icons/checkmark.svg diff --git a/src/gui/src/UI/Settings/UITabLanguage.js b/src/gui/src/UI/Settings/UITabLanguage.js index fbea62a279..4d27f19363 100644 --- a/src/gui/src/UI/Settings/UITabLanguage.js +++ b/src/gui/src/UI/Settings/UITabLanguage.js @@ -36,7 +36,7 @@ export default { const available_languages = window.listSupportedLanguages(); h += `
`; for (let lang of available_languages) { - h += `
${html_encode(lang.name)}
`; + h += `
${html_encode(lang.name)}
`; } h += `
`; return h; diff --git a/src/gui/src/css/style.css b/src/gui/src/css/style.css index d6912ab62d..95c3832f46 100644 --- a/src/gui/src/css/style.css +++ b/src/gui/src/css/style.css @@ -3865,15 +3865,29 @@ fieldset[name=number-code] { border-radius: 4px; margin-bottom: 10px; margin-right: 10px; + font-size: 13px; + position: relative; } .language-item:hover { background-color: #f6f6f6; } +.language-item .checkmark{ + width: 15px; + height: 15px; + border-radius: 50%; + margin-left: 10px; + display: none; + position: absolute; + right: 10px; +} .language-item.active { background-color: #e0e0e0; } +.language-item.active .checkmark { + display: inline-block; +} .settings-card { overflow: hidden; diff --git a/src/gui/src/icons/checkmark.svg b/src/gui/src/icons/checkmark.svg new file mode 100644 index 0000000000..87168de308 --- /dev/null +++ b/src/gui/src/icons/checkmark.svg @@ -0,0 +1,3 @@ + + + \ No newline at end of file From 1f059c330c777b51822afec3ed3dcffcd5cdad8b Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 31 Jul 2024 23:20:27 -0400 Subject: [PATCH 0650/2119] dev: update FileFacade to use LLRead --- src/backend/src/filesystem/FSNodeContext.js | 4 ++++ src/backend/src/filesystem/ll_operations/ll_read.js | 5 ++++- src/backend/src/services/drivers/FileFacade.js | 12 +++++------- 3 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/backend/src/filesystem/FSNodeContext.js b/src/backend/src/filesystem/FSNodeContext.js index 28e15d6b89..fe421be63a 100644 --- a/src/backend/src/filesystem/FSNodeContext.js +++ b/src/backend/src/filesystem/FSNodeContext.js @@ -644,6 +644,10 @@ module.exports = class FSNodeContext { if ( ! await this.exists() ) { throw new Error('file does not exist'); } + // return null for local filesystem + if ( ! this.entry.bucket ) { + return null; + } return { bucket: this.entry.bucket, bucket_region: this.entry.bucket_region, diff --git a/src/backend/src/filesystem/ll_operations/ll_read.js b/src/backend/src/filesystem/ll_operations/ll_read.js index e19782ddbd..b903a9dd1d 100644 --- a/src/backend/src/filesystem/ll_operations/ll_read.js +++ b/src/backend/src/filesystem/ll_operations/ll_read.js @@ -120,7 +120,10 @@ class LLRead extends LLFilesystemOperation { const { fsNode, version_id, offset, length, has_range } = a.values(); - const location = await fsNode.get('s3:location'); + // Empty object here is in the case of local fiesystem, + // where s3:location will return null. + // TODO: storage interface shouldn't have S3-specific properties. + const location = await fsNode.get('s3:location') ?? {}; const stream = (await storage.create_read_stream(await fsNode.get('uid'), { // TODO: fs:decouple-s3 diff --git a/src/backend/src/services/drivers/FileFacade.js b/src/backend/src/services/drivers/FileFacade.js index 22306c340e..0a6d1b1aa3 100644 --- a/src/backend/src/services/drivers/FileFacade.js +++ b/src/backend/src/services/drivers/FileFacade.js @@ -21,6 +21,7 @@ const { Context } = require("../../util/context"); const { MultiValue } = require("../../util/multivalue"); const { stream_to_buffer } = require("../../util/streamutil"); const { PassThrough } = require("stream"); +const { LLRead } = require("../../filesystem/ll_operations/ll_read"); /** * FileFacade @@ -77,17 +78,14 @@ class FileFacade extends AdvancedBase { if ( ! await fsNode.exists() ) return null; const context = Context.get(); - const services = context.get('services'); - const svc_filesystem = services.get('filesystem'); - const dst_stream = new PassThrough(); - - svc_filesystem.read(context, dst_stream, { + const ll_read = new LLRead(); + const stream = await ll_read.run({ + actor: context.get('actor'), fsNode, - user: context.get('user'), }); - return dst_stream; + return stream; }); this.values.add_factory('stream', 'web_url', async web_url => { From b520783bf4a543c71eaef73277f42d5918ac4469 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 31 Jul 2024 23:20:51 -0400 Subject: [PATCH 0651/2119] fix: add missing driver parameter to /call endpoint --- src/backend/src/routers/drivers/call.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backend/src/routers/drivers/call.js b/src/backend/src/routers/drivers/call.js index 737231af1f..4c66a85554 100644 --- a/src/backend/src/routers/drivers/call.js +++ b/src/backend/src/routers/drivers/call.js @@ -73,6 +73,7 @@ module.exports = eggspress('/drivers/call', { const result = await context.arun(async () => { return await svc_driver.call({ iface: interface_name, + driver: body.driver, method: body.method, format: body.format, args: body.args, From f924d48b02f39884931db45a05dd61b65f2cee4a Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 31 Jul 2024 23:37:17 -0400 Subject: [PATCH 0652/2119] feat: add textract driver to puterai module --- package-lock.json | 7206 +++++++++++------ src/backend/exports.js | 2 + src/backend/package.json | 1 + .../src/modules/puterai/AIInterfaceService.js | 32 + .../src/modules/puterai/AWSTextractService.js | 137 + .../src/modules/puterai/PuterAIModule.js | 17 + .../src/modules/puterai/doc/requests.md | 17 + tools/run-selfhosted.js | 2 + 8 files changed, 4883 insertions(+), 2531 deletions(-) create mode 100644 src/backend/src/modules/puterai/AIInterfaceService.js create mode 100644 src/backend/src/modules/puterai/AWSTextractService.js create mode 100644 src/backend/src/modules/puterai/PuterAIModule.js create mode 100644 src/backend/src/modules/puterai/doc/requests.md diff --git a/package-lock.json b/package-lock.json index b36e5b1314..3f3e002bd3 100644 --- a/package-lock.json +++ b/package-lock.json @@ -263,1848 +263,4002 @@ "node": ">=6.0.0" } }, - "node_modules/@babel/code-frame": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", - "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", - "dev": true, - "license": "MIT", + "node_modules/@aws-crypto/sha256-browser": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", + "integrity": "sha512-AXfN/lGotSQwu6HNcEsIASo7kWXZ5HYWvfOmSNKDsEqC4OashTp8alTmaz+F7TC2L083SFv5RdB+qU3Vs1kZqw==", + "dependencies": { + "@aws-crypto/sha256-js": "^5.2.0", + "@aws-crypto/supports-web-crypto": "^5.2.0", + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "@aws-sdk/util-locate-window": "^3.0.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" + } + }, + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", "dependencies": { - "@babel/highlight": "^7.24.7", - "picocolors": "^1.0.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/compat-data": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.7.tgz", - "integrity": "sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==", - "dev": true, - "license": "MIT", + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", + "dependencies": { + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/core": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz", - "integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==", - "dev": true, - "license": "MIT", + "node_modules/@aws-crypto/sha256-browser/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", "dependencies": { - "@ampproject/remapping": "^2.2.0", - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-compilation-targets": "^7.24.7", - "@babel/helper-module-transforms": "^7.24.7", - "@babel/helpers": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/template": "^7.24.7", - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7", - "convert-source-map": "^2.0.0", - "debug": "^4.1.0", - "gensync": "^1.0.0-beta.2", - "json5": "^2.2.3", - "semver": "^6.3.1" + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" - }, - "funding": { - "type": "opencollective", - "url": "https://opencollective.com/babel" - } - }, - "node_modules/@babel/core/node_modules/convert-source-map": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", - "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", - "dev": true, - "license": "MIT" - }, - "node_modules/@babel/core/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "node": ">=14.0.0" } }, - "node_modules/@babel/generator": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", - "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", - "license": "MIT", + "node_modules/@aws-crypto/sha256-js": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-js/-/sha256-js-5.2.0.tgz", + "integrity": "sha512-FFQQyu7edu4ufvIZ+OadFpHHOt+eSTBaYaki44c+akjg7qZg9oOQeLlk77F6tSYqjDAFClrHJk9tMf0HdVyOvA==", "dependencies": { - "@babel/types": "^7.24.7", - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25", - "jsesc": "^2.5.1" + "@aws-crypto/util": "^5.2.0", + "@aws-sdk/types": "^3.222.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=16.0.0" } }, - "node_modules/@babel/helper-compilation-targets": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz", - "integrity": "sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==", - "dev": true, - "license": "MIT", + "node_modules/@aws-crypto/supports-web-crypto": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/supports-web-crypto/-/supports-web-crypto-5.2.0.tgz", + "integrity": "sha512-iAvUotm021kM33eCdNfwIN//F77/IADDSs58i+MDaOqFrVjZo9bAal0NK7HurRuWLLpF1iLX7gbWrjHjeo+YFg==", "dependencies": { - "@babel/compat-data": "^7.24.7", - "@babel/helper-validator-option": "^7.24.7", - "browserslist": "^4.22.2", - "lru-cache": "^5.1.1", - "semver": "^6.3.1" - }, - "engines": { - "node": ">=6.9.0" + "tslib": "^2.6.2" } }, - "node_modules/@babel/helper-compilation-targets/node_modules/semver": { - "version": "6.3.1", - "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", - "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", - "dev": true, - "license": "ISC", - "bin": { - "semver": "bin/semver.js" + "node_modules/@aws-crypto/util": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/@aws-crypto/util/-/util-5.2.0.tgz", + "integrity": "sha512-4RkU9EsI6ZpBve5fseQlGNUWKMa1RLPQ1dnjnQoe07ldfIzcsGb5hC5W0Dm7u423KWzawlrpbjXBrXCEv9zazQ==", + "dependencies": { + "@aws-sdk/types": "^3.222.0", + "@smithy/util-utf8": "^2.0.0", + "tslib": "^2.6.2" } }, - "node_modules/@babel/helper-environment-visitor": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", - "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", - "dev": true, - "license": "MIT", + "node_modules/@aws-crypto/util/node_modules/@smithy/is-array-buffer": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-2.2.0.tgz", + "integrity": "sha512-GGP3O9QFD24uGeAXYUjwSTXARoqpZykHadOmA8G5vfJPK0/DC67qa//0qvqrJzL1xc8WQWX7/yc7fwudjPHPhA==", "dependencies": { - "@babel/types": "^7.24.7" + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/helper-function-name": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", - "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", - "dev": true, - "license": "MIT", + "node_modules/@aws-crypto/util/node_modules/@smithy/util-buffer-from": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-2.2.0.tgz", + "integrity": "sha512-IJdWBbTcMQ6DA0gdNhh/BwrLkDR+ADW5Kr1aZmd4k3DIF6ezMV4R2NIAmT08wQJ3yUK82thHWmC/TnK/wpMMIA==", "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" + "@smithy/is-array-buffer": "^2.2.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/helper-hoist-variables": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", - "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", - "dev": true, - "license": "MIT", + "node_modules/@aws-crypto/util/node_modules/@smithy/util-utf8": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-2.3.0.tgz", + "integrity": "sha512-R8Rdn8Hy72KKcebgLiv8jQcQkXoLMOGGv5uI1/k0l+snqkOzQ1R0ChUBCxWMlBsFMekWjq0wRudIweFs7sKT5A==", "dependencies": { - "@babel/types": "^7.24.7" + "@smithy/util-buffer-from": "^2.2.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=14.0.0" } }, - "node_modules/@babel/helper-module-imports": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", - "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "node_modules/@aws-sdk/client-sso": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", + "integrity": "sha512-xpKfikN4u0BaUYZA9FGUMkkDmfoIP0Q03+A86WjqDWhcOoqNA1DkHsE4kZ+r064ifkPUfcNuUvlkVTEoBZoFjA==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.1", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=16.0.0" } }, - "node_modules/@babel/helper-module-transforms": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz", - "integrity": "sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-module-imports": "^7.24.7", - "@babel/helper-simple-access": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7" + "node_modules/@aws-sdk/client-sso-oidc": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.621.0.tgz", + "integrity": "sha512-mMjk3mFUwV2Y68POf1BQMTF+F6qxt5tPu6daEUCNGC9Cenk3h2YXQQoS4/eSyYzuBiYk3vx49VgleRvdvkg8rg==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.1", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=16.0.0" }, "peerDependencies": { - "@babel/core": "^7.0.0" + "@aws-sdk/client-sts": "^3.621.0" } }, - "node_modules/@babel/helper-simple-access": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", - "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", - "dev": true, - "license": "MIT", + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", + "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", "dependencies": { - "@babel/traverse": "^7.24.7", - "@babel/types": "^7.24.7" + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=16.0.0" } }, - "node_modules/@babel/helper-split-export-declaration": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", - "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", - "dev": true, - "license": "MIT", + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/node-http-handler": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.4.tgz", + "integrity": "sha512-+UmxgixgOr/yLsUxcEKGH0fMNVteJFGkmRltYFHnBMlogyFdpzn2CwqWmxOrfJELhV34v0WSlaqG1UtE1uXlJg==", "dependencies": { - "@babel/types": "^7.24.7" + "@smithy/abort-controller": "^3.1.1", + "@smithy/protocol-http": "^4.1.0", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=16.0.0" } }, - "node_modules/@babel/helper-string-parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", - "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", - "license": "MIT", + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=6.9.0" + "node": ">=16.0.0" } }, - "node_modules/@babel/helper-validator-identifier": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", - "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", - "license": "MIT", + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/querystring-builder": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", + "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", + "dependencies": { + "@smithy/types": "^3.3.0", + "@smithy/util-uri-escape": "^3.0.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=6.9.0" + "node": ">=16.0.0" } }, - "node_modules/@babel/helper-validator-option": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz", - "integrity": "sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==", - "dev": true, - "license": "MIT", + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "dependencies": { + "tslib": "^2.6.2" + }, "engines": { - "node": ">=6.9.0" + "node": ">=16.0.0" } }, - "node_modules/@babel/helpers": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.7.tgz", - "integrity": "sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==", - "dev": true, - "license": "MIT", + "node_modules/@aws-sdk/client-sso-oidc/node_modules/@smithy/util-uri-escape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", + "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", "dependencies": { - "@babel/template": "^7.24.7", - "@babel/types": "^7.24.7" + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=16.0.0" } }, - "node_modules/@babel/highlight": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", - "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", - "dev": true, - "license": "MIT", + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", + "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", "dependencies": { - "@babel/helper-validator-identifier": "^7.24.7", - "chalk": "^2.4.2", - "js-tokens": "^4.0.0", - "picocolors": "^1.0.0" + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=16.0.0" } }, - "node_modules/@babel/highlight/node_modules/ansi-styles": { - "version": "3.2.1", - "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", - "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", - "dev": true, - "license": "MIT", + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/node-http-handler": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.4.tgz", + "integrity": "sha512-+UmxgixgOr/yLsUxcEKGH0fMNVteJFGkmRltYFHnBMlogyFdpzn2CwqWmxOrfJELhV34v0WSlaqG1UtE1uXlJg==", "dependencies": { - "color-convert": "^1.9.0" + "@smithy/abort-controller": "^3.1.1", + "@smithy/protocol-http": "^4.1.0", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=4" + "node": ">=16.0.0" } }, - "node_modules/@babel/highlight/node_modules/chalk": { - "version": "2.4.2", - "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", - "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", - "dev": true, - "license": "MIT", + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", "dependencies": { - "ansi-styles": "^3.2.1", - "escape-string-regexp": "^1.0.5", - "supports-color": "^5.3.0" + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=4" + "node": ">=16.0.0" } }, - "node_modules/@babel/highlight/node_modules/color-convert": { - "version": "1.9.3", - "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", - "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", - "dev": true, - "license": "MIT", + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/querystring-builder": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", + "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", "dependencies": { - "color-name": "1.1.3" - } - }, - "node_modules/@babel/highlight/node_modules/color-name": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", - "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", - "dev": true, - "license": "MIT" - }, - "node_modules/@babel/highlight/node_modules/escape-string-regexp": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", - "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", - "dev": true, - "license": "MIT", + "@smithy/types": "^3.3.0", + "@smithy/util-uri-escape": "^3.0.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=0.8.0" + "node": ">=16.0.0" } }, - "node_modules/@babel/parser": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", - "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", - "license": "MIT", - "bin": { - "parser": "bin/babel-parser.js" + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "dependencies": { + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.0.0" + "node": ">=16.0.0" } }, - "node_modules/@babel/runtime": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", - "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", - "dev": true, - "license": "MIT", + "node_modules/@aws-sdk/client-sso/node_modules/@smithy/util-uri-escape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", + "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", "dependencies": { - "regenerator-runtime": "^0.14.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=16.0.0" } }, - "node_modules/@babel/template": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", - "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", - "dev": true, - "license": "MIT", - "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7" + "node_modules/@aws-sdk/client-sts": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.621.0.tgz", + "integrity": "sha512-707uiuReSt+nAx6d0c21xLjLm2lxeKc7padxjv92CIrIocnQSlJPxSCM7r5zBhwiahJA6MNQwmTl2xznU67KgA==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.1", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=16.0.0" } }, - "node_modules/@babel/traverse": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", - "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", - "dev": true, - "license": "MIT", + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", + "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", "dependencies": { - "@babel/code-frame": "^7.24.7", - "@babel/generator": "^7.24.7", - "@babel/helper-environment-visitor": "^7.24.7", - "@babel/helper-function-name": "^7.24.7", - "@babel/helper-hoist-variables": "^7.24.7", - "@babel/helper-split-export-declaration": "^7.24.7", - "@babel/parser": "^7.24.7", - "@babel/types": "^7.24.7", - "debug": "^4.3.1", - "globals": "^11.1.0" + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=16.0.0" } }, - "node_modules/@babel/traverse/node_modules/globals": { - "version": "11.12.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", - "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", - "dev": true, - "license": "MIT", + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/node-http-handler": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.4.tgz", + "integrity": "sha512-+UmxgixgOr/yLsUxcEKGH0fMNVteJFGkmRltYFHnBMlogyFdpzn2CwqWmxOrfJELhV34v0WSlaqG1UtE1uXlJg==", + "dependencies": { + "@smithy/abort-controller": "^3.1.1", + "@smithy/protocol-http": "^4.1.0", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=4" + "node": ">=16.0.0" } }, - "node_modules/@babel/types": { - "version": "7.24.7", - "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", - "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", - "license": "MIT", + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", "dependencies": { - "@babel/helper-string-parser": "^7.24.7", - "@babel/helper-validator-identifier": "^7.24.7", - "to-fast-properties": "^2.0.0" + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6.9.0" + "node": ">=16.0.0" } }, - "node_modules/@colors/colors": { - "version": "1.6.0", - "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", - "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", - "license": "MIT", + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/querystring-builder": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", + "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", + "dependencies": { + "@smithy/types": "^3.3.0", + "@smithy/util-uri-escape": "^3.0.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=0.1.90" + "node": ">=16.0.0" } }, - "node_modules/@dabh/diagnostics": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", - "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", - "license": "MIT", + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "colorspace": "1.1.x", - "enabled": "2.0.x", - "kuler": "^2.0.0" - } - }, - "node_modules/@discoveryjs/json-ext": { - "version": "0.5.7", - "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", - "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", - "dev": true, + "tslib": "^2.6.2" + }, "engines": { - "node": ">=10.0.0" + "node": ">=16.0.0" } }, - "node_modules/@eslint-community/eslint-utils": { - "version": "4.4.0", - "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", - "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", - "dev": true, + "node_modules/@aws-sdk/client-sts/node_modules/@smithy/util-uri-escape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", + "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", "dependencies": { - "eslint-visitor-keys": "^3.3.0" + "tslib": "^2.6.2" }, "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" - }, - "peerDependencies": { - "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + "node": ">=16.0.0" } }, - "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { - "version": "3.4.3", - "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", - "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", - "dev": true, - "engines": { - "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + "node_modules/@aws-sdk/client-textract": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-textract/-/client-textract-3.621.0.tgz", + "integrity": "sha512-jnenJsHsY4IMWFL+zoxoOhjD6lAdTIwAeCcCI7HUhcRa+WOiE/TRlDdhheXq7idi2CYLX4NAMU8+oTsmZ1vXvA==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.621.0", + "@aws-sdk/client-sts": "3.621.0", + "@aws-sdk/core": "3.621.0", + "@aws-sdk/credential-provider-node": "3.621.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.1", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.13", + "@smithy/util-defaults-mode-node": "^3.0.13", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2", + "uuid": "^9.0.1" }, - "funding": { - "url": "https://opencollective.com/eslint" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@eslint-community/regexpp": { - "version": "4.10.0", - "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", - "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", - "dev": true, + "node_modules/@aws-sdk/client-textract/node_modules/@smithy/abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", + "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, "engines": { - "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + "node": ">=16.0.0" } }, - "node_modules/@eslint/eslintrc": { - "version": "3.0.2", - "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.0.2.tgz", - "integrity": "sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==", - "dev": true, + "node_modules/@aws-sdk/client-textract/node_modules/@smithy/node-http-handler": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.4.tgz", + "integrity": "sha512-+UmxgixgOr/yLsUxcEKGH0fMNVteJFGkmRltYFHnBMlogyFdpzn2CwqWmxOrfJELhV34v0WSlaqG1UtE1uXlJg==", "dependencies": { - "ajv": "^6.12.4", - "debug": "^4.3.2", - "espree": "^10.0.1", - "globals": "^14.0.0", - "ignore": "^5.2.0", - "import-fresh": "^3.2.1", - "js-yaml": "^4.1.0", - "minimatch": "^3.1.2", - "strip-json-comments": "^3.1.1" + "@smithy/abort-controller": "^3.1.1", + "@smithy/protocol-http": "^4.1.0", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" - }, - "funding": { - "url": "https://opencollective.com/eslint" + "node": ">=16.0.0" } }, - "node_modules/@eslint/eslintrc/node_modules/globals": { - "version": "14.0.0", - "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", - "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", - "dev": true, - "engines": { - "node": ">=18" + "node_modules/@aws-sdk/client-textract/node_modules/@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@eslint/js": { - "version": "9.1.1", - "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.1.1.tgz", - "integrity": "sha512-5WoDz3Y19Bg2BnErkZTp0en+c/i9PvgFS7MBe1+m60HjFr0hrphlAGp4yzI7pxpt4xShln4ZyYp4neJm8hmOkQ==", - "dev": true, + "node_modules/@aws-sdk/client-textract/node_modules/@smithy/querystring-builder": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", + "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", + "dependencies": { + "@smithy/types": "^3.3.0", + "@smithy/util-uri-escape": "^3.0.0", + "tslib": "^2.6.2" + }, "engines": { - "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + "node": ">=16.0.0" } }, - "node_modules/@grpc/grpc-js": { - "version": "1.10.10", - "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.10.10.tgz", - "integrity": "sha512-HPa/K5NX6ahMoeBv15njAc/sfF4/jmiXLar9UlC2UfHFKZzsCVLc3wbe7+7qua7w9VPh2/L6EBxyAV7/E8Wftg==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-textract/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@grpc/proto-loader": "^0.7.13", - "@js-sdsl/ordered-map": "^4.4.2" + "tslib": "^2.6.2" }, "engines": { - "node": ">=12.10.0" + "node": ">=16.0.0" } }, - "node_modules/@grpc/proto-loader": { - "version": "0.7.13", - "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", - "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", - "license": "Apache-2.0", + "node_modules/@aws-sdk/client-textract/node_modules/@smithy/util-uri-escape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", + "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", "dependencies": { - "lodash.camelcase": "^4.3.0", - "long": "^5.0.0", - "protobufjs": "^7.2.5", - "yargs": "^17.7.2" - }, - "bin": { - "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + "tslib": "^2.6.2" }, "engines": { - "node": ">=6" + "node": ">=16.0.0" } }, - "node_modules/@hapi/b64": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/@hapi/b64/-/b64-5.0.0.tgz", - "integrity": "sha512-ngu0tSEmrezoiIaNGG6rRvKOUkUuDdf4XTPnONHGYfSGRmDqPZX5oJL6HAdKTo1UQHECbdB4OzhWrfgVppjHUw==", - "license": "BSD-3-Clause", + "node_modules/@aws-sdk/core": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.621.0.tgz", + "integrity": "sha512-CtOwWmDdEiINkGXD93iGfXjN0WmCp9l45cDWHHGa8lRgEDyhuL7bwd/pH5aSzj0j8SiQBG2k0S7DHbd5RaqvbQ==", "dependencies": { - "@hapi/hoek": "9.x.x" + "@smithy/core": "^2.3.1", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/signature-v4": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@hapi/boom": { - "version": "9.1.4", - "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-9.1.4.tgz", - "integrity": "sha512-Ls1oH8jaN1vNsqcaHVYJrKmgMcKsC1wcp8bujvXrHaAqD2iDYq3HoOwsxwo09Cuda5R5nC0o0IxlrlTuvPuzSw==", - "license": "BSD-3-Clause", + "node_modules/@aws-sdk/core/node_modules/@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", "dependencies": { - "@hapi/hoek": "9.x.x" + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@hapi/bourne": { - "version": "2.1.0", - "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-2.1.0.tgz", - "integrity": "sha512-i1BpaNDVLJdRBEKeJWkVO6tYX6DMFBuwMhSuWqLsY4ufeTKGVuV5rBsUhxPayXqnnWHgXUAmWK16H/ykO5Wj4Q==", - "license": "BSD-3-Clause" - }, - "node_modules/@hapi/cryptiles": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/cryptiles/-/cryptiles-5.1.0.tgz", - "integrity": "sha512-fo9+d1Ba5/FIoMySfMqPBR/7Pa29J2RsiPrl7bkwo5W5o+AN1dAYQRi4SPrPwwVxVGKjgLOEWrsvt1BonJSfLA==", - "license": "BSD-3-Clause", + "node_modules/@aws-sdk/core/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@hapi/boom": "9.x.x" + "tslib": "^2.6.2" }, "engines": { - "node": ">=12.0.0" + "node": ">=16.0.0" } }, - "node_modules/@hapi/hoek": { - "version": "9.3.0", - "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", - "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", - "license": "BSD-3-Clause" - }, - "node_modules/@hapi/iron": { - "version": "6.0.0", - "resolved": "https://registry.npmjs.org/@hapi/iron/-/iron-6.0.0.tgz", - "integrity": "sha512-zvGvWDufiTGpTJPG1Y/McN8UqWBu0k/xs/7l++HVU535NLHXsHhy54cfEMdW7EjwKfbBfM9Xy25FmTiobb7Hvw==", - "license": "BSD-3-Clause", + "node_modules/@aws-sdk/credential-provider-env": { + "version": "3.620.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-env/-/credential-provider-env-3.620.1.tgz", + "integrity": "sha512-ExuILJ2qLW5ZO+rgkNRj0xiAipKT16Rk77buvPP8csR7kkCflT/gXTyzRe/uzIiETTxM7tr8xuO9MP/DQXqkfg==", "dependencies": { - "@hapi/b64": "5.x.x", - "@hapi/boom": "9.x.x", - "@hapi/bourne": "2.x.x", - "@hapi/cryptiles": "5.x.x", - "@hapi/hoek": "9.x.x" + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@hapi/podium": { - "version": "4.1.3", - "resolved": "https://registry.npmjs.org/@hapi/podium/-/podium-4.1.3.tgz", - "integrity": "sha512-ljsKGQzLkFqnQxE7qeanvgGj4dejnciErYd30dbrYzUOF/FyS/DOF97qcrT3bhoVwCYmxa6PEMhxfCPlnUcD2g==", - "license": "BSD-3-Clause", + "node_modules/@aws-sdk/credential-provider-env/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@hapi/hoek": "9.x.x", - "@hapi/teamwork": "5.x.x", - "@hapi/validate": "1.x.x" - } - }, - "node_modules/@hapi/teamwork": { - "version": "5.1.1", - "resolved": "https://registry.npmjs.org/@hapi/teamwork/-/teamwork-5.1.1.tgz", - "integrity": "sha512-1oPx9AE5TIv+V6Ih54RP9lTZBso3rP8j4Xhb6iSVwPXtAM+sDopl5TFMv5Paw73UnpZJ9gjcrTE1BXrWt9eQrg==", - "license": "BSD-3-Clause", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=12.0.0" + "node": ">=16.0.0" } }, - "node_modules/@hapi/topo": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", - "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", - "license": "BSD-3-Clause", + "node_modules/@aws-sdk/credential-provider-http": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.621.0.tgz", + "integrity": "sha512-/jc2tEsdkT1QQAI5Dvoci50DbSxtJrevemwFsm0B73pwCcOQZ5ZwwSdVqGsPutzYzUVx3bcXg3LRL7jLACqRIg==", "dependencies": { - "@hapi/hoek": "^9.0.0" + "@aws-sdk/types": "3.609.0", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/util-stream": "^3.1.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@hapi/validate": { - "version": "1.1.3", - "resolved": "https://registry.npmjs.org/@hapi/validate/-/validate-1.1.3.tgz", - "integrity": "sha512-/XMR0N0wjw0Twzq2pQOzPBZlDzkekGcoCtzO314BpIEsbXdYGthQUbxgkGDf4nhk1+IPDAsXqWjMohRQYO06UA==", - "license": "BSD-3-Clause", + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", + "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", "dependencies": { - "@hapi/hoek": "^9.0.0", - "@hapi/topo": "^5.0.0" + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@heyputer/backend": { - "resolved": "src/backend", - "link": true - }, - "node_modules/@heyputer/kv.js": { - "version": "0.1.6", - "resolved": "https://registry.npmjs.org/@heyputer/kv.js/-/kv.js-0.1.6.tgz", - "integrity": "sha512-p/aYYHVG6wp/z33rfq2bmc7KgfBP6pE7urnQcnAm8xTN3+U0i2hItXH7bBTJOgsmjqk59I1YUOzcjOTlLrZ26w==", - "license": "MIT", + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/node-http-handler": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.4.tgz", + "integrity": "sha512-+UmxgixgOr/yLsUxcEKGH0fMNVteJFGkmRltYFHnBMlogyFdpzn2CwqWmxOrfJELhV34v0WSlaqG1UtE1uXlJg==", "dependencies": { - "minimatch": "^9.0.0" + "@smithy/abort-controller": "^3.1.1", + "@smithy/protocol-http": "^4.1.0", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@heyputer/kv.js/node_modules/brace-expansion": { - "version": "2.0.1", - "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", - "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", - "license": "MIT", + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", "dependencies": { - "balanced-match": "^1.0.0" + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@heyputer/kv.js/node_modules/minimatch": { - "version": "9.0.5", - "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", - "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", - "license": "ISC", + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/querystring-builder": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", + "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", "dependencies": { - "brace-expansion": "^2.0.1" + "@smithy/types": "^3.3.0", + "@smithy/util-uri-escape": "^3.0.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=16 || 14 >=14.17" - }, - "funding": { - "url": "https://github.com/sponsors/isaacs" + "node": ">=16.0.0" } }, - "node_modules/@heyputer/multest": { - "version": "0.0.2", - "resolved": "https://registry.npmjs.org/@heyputer/multest/-/multest-0.0.2.tgz", - "integrity": "sha512-Hr4U9Z2/oMIyCKv+cgO3pNzncA4PAlkS9RotZwoicfzR2BLLu2Rjjp3/HpcLmtE7UEt0hlRMYP+ImMZPYGNwkg==", - "license": "UNLICENSED", + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "append-field": "^1.0.0", - "busboy": "^1.6.0", - "form-data": "^4.0.0" + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@heyputer/parsely": { - "resolved": "src/parsely", - "link": true - }, - "node_modules/@heyputer/phoenix": { - "resolved": "src/phoenix", - "link": true - }, - "node_modules/@heyputer/puter-js-common": { - "resolved": "src/puter-js-common", - "link": true - }, - "node_modules/@heyputer/puterjs": { - "resolved": "src/puter-js", - "link": true - }, - "node_modules/@heyputer/terminal": { - "resolved": "src/terminal", - "link": true - }, - "node_modules/@humanwhocodes/config-array": { - "version": "0.13.0", - "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", - "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", - "dev": true, + "node_modules/@aws-sdk/credential-provider-http/node_modules/@smithy/util-uri-escape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", + "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", "dependencies": { - "@humanwhocodes/object-schema": "^2.0.3", - "debug": "^4.3.1", - "minimatch": "^3.0.5" + "tslib": "^2.6.2" }, "engines": { - "node": ">=10.10.0" + "node": ">=16.0.0" } }, - "node_modules/@humanwhocodes/module-importer": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", - "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", - "dev": true, + "node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.621.0.tgz", + "integrity": "sha512-0EWVnSc+JQn5HLnF5Xv405M8n4zfdx9gyGdpnCmAmFqEDHA8LmBdxJdpUk1Ovp/I5oPANhjojxabIW5f1uU0RA==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.620.1", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-process": "3.620.1", + "@aws-sdk/credential-provider-sso": "3.621.0", + "@aws-sdk/credential-provider-web-identity": "3.621.0", + "@aws-sdk/types": "3.609.0", + "@smithy/credential-provider-imds": "^3.2.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=12.22" + "node": ">=16.0.0" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "peerDependencies": { + "@aws-sdk/client-sts": "^3.621.0" } }, - "node_modules/@humanwhocodes/object-schema": { - "version": "2.0.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", - "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", - "dev": true - }, - "node_modules/@humanwhocodes/retry": { - "version": "0.2.3", - "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.2.3.tgz", - "integrity": "sha512-X38nUbachlb01YMlvPFojKoiXq+LzZvuSce70KPMPdeM1Rj03k4dR7lDslhbqXn3Ang4EU3+EAmwEAsbrjHW3g==", - "dev": true, + "node_modules/@aws-sdk/credential-provider-ini/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "dependencies": { + "tslib": "^2.6.2" + }, "engines": { - "node": ">=18.18" + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/credential-provider-node": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.621.0.tgz", + "integrity": "sha512-4JqpccUgz5Snanpt2+53hbOBbJQrSFq7E1sAAbgY6BKVQUsW5qyXqnjvSF32kDeKa5JpBl3bBWLZl04IadcPHw==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.620.1", + "@aws-sdk/credential-provider-http": "3.621.0", + "@aws-sdk/credential-provider-ini": "3.621.0", + "@aws-sdk/credential-provider-process": "3.620.1", + "@aws-sdk/credential-provider-sso": "3.621.0", + "@aws-sdk/credential-provider-web-identity": "3.621.0", + "@aws-sdk/types": "3.609.0", + "@smithy/credential-provider-imds": "^3.2.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/nzakas" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@istanbuljs/load-nyc-config": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", - "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", - "dev": true, - "license": "ISC", + "node_modules/@aws-sdk/credential-provider-node/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "camelcase": "^5.3.1", - "find-up": "^4.1.0", - "get-package-type": "^0.1.0", - "js-yaml": "^3.13.1", - "resolve-from": "^5.0.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=8" + "node": ">=16.0.0" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { - "version": "1.0.10", - "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", - "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", - "dev": true, - "license": "MIT", + "node_modules/@aws-sdk/credential-provider-process": { + "version": "3.620.1", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-process/-/credential-provider-process-3.620.1.tgz", + "integrity": "sha512-hWqFMidqLAkaV9G460+1at6qa9vySbjQKKc04p59OT7lZ5cO5VH5S4aI05e+m4j364MBROjjk2ugNvfNf/8ILg==", "dependencies": { - "sprintf-js": "~1.0.2" - } - }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { - "version": "5.3.1", - "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", - "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", - "dev": true, - "license": "MIT", + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=6" + "node": ">=16.0.0" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", - "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", - "dev": true, - "license": "MIT", + "node_modules/@aws-sdk/credential-provider-process/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "locate-path": "^5.0.0", - "path-exists": "^4.0.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=8" + "node": ">=16.0.0" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { - "version": "3.14.1", - "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", - "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", - "dev": true, - "license": "MIT", + "node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.621.0.tgz", + "integrity": "sha512-Kza0jcFeA/GEL6xJlzR2KFf1PfZKMFnxfGzJzl5yN7EjoGdMijl34KaRyVnfRjnCWcsUpBWKNIDk9WZVMY9yiw==", "dependencies": { - "argparse": "^1.0.7", - "esprima": "^4.0.0" + "@aws-sdk/client-sso": "3.621.0", + "@aws-sdk/token-providers": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, - "bin": { - "js-yaml": "bin/js-yaml.js" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { - "version": "5.0.0", - "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", - "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", - "dev": true, - "license": "MIT", + "node_modules/@aws-sdk/credential-provider-sso/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "p-locate": "^4.1.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=8" + "node": ">=16.0.0" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { - "version": "2.3.0", - "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", - "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", - "dev": true, - "license": "MIT", + "node_modules/@aws-sdk/credential-provider-web-identity": { + "version": "3.621.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-web-identity/-/credential-provider-web-identity-3.621.0.tgz", + "integrity": "sha512-w7ASSyfNvcx7+bYGep3VBgC3K6vEdLmlpjT7nSIHxxQf+WSdvy+HynwJosrpZax0sK5q0D1Jpn/5q+r5lwwW6w==", "dependencies": { - "p-try": "^2.0.0" + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=6" + "node": ">=16.0.0" }, - "funding": { - "url": "https://github.com/sponsors/sindresorhus" + "peerDependencies": { + "@aws-sdk/client-sts": "^3.621.0" } }, - "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", - "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", - "dev": true, - "license": "MIT", + "node_modules/@aws-sdk/credential-provider-web-identity/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "p-limit": "^2.2.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=8" + "node": ">=16.0.0" } }, - "node_modules/@istanbuljs/schema": { - "version": "0.1.3", - "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", - "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", - "dev": true, - "license": "MIT", + "node_modules/@aws-sdk/middleware-host-header": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-host-header/-/middleware-host-header-3.620.0.tgz", + "integrity": "sha512-VMtPEZwqYrII/oUkffYsNWY9PZ9xpNJpMgmyU0rlDQ25O1c0Hk3fJmZRe6pEkAJ0omD7kLrqGl1DUjQVxpd/Rg==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=8" + "node": ">=16.0.0" } }, - "node_modules/@jimp/bmp": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/bmp/-/bmp-0.22.12.tgz", - "integrity": "sha512-aeI64HD0npropd+AR76MCcvvRaa+Qck6loCOS03CkkxGHN5/r336qTM5HPUdHKMDOGzqknuVPA8+kK1t03z12g==", - "license": "MIT", + "node_modules/@aws-sdk/middleware-host-header/node_modules/@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", "dependencies": { - "@jimp/utils": "^0.22.12", - "bmp-js": "^0.1.0" + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@jimp/core": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/core/-/core-0.22.12.tgz", - "integrity": "sha512-l0RR0dOPyzMKfjUW1uebzueFEDtCOj9fN6pyTYWWOM/VS4BciXQ1VVrJs8pO3kycGYZxncRKhCoygbNr8eEZQA==", - "license": "MIT", + "node_modules/@aws-sdk/middleware-host-header/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@jimp/utils": "^0.22.12", - "any-base": "^1.1.0", - "buffer": "^5.2.0", - "exif-parser": "^0.1.12", - "file-type": "^16.5.4", - "isomorphic-fetch": "^3.0.0", - "pixelmatch": "^4.0.2", - "tinycolor2": "^1.6.0" + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@jimp/core/node_modules/buffer": { - "version": "5.7.1", - "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", - "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "MIT", + "node_modules/@aws-sdk/middleware-logger": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-logger/-/middleware-logger-3.609.0.tgz", + "integrity": "sha512-S62U2dy4jMDhDFDK5gZ4VxFdWzCtLzwbYyFZx2uvPYTECkepLUfzLic2BHg2Qvtu4QjX+oGE3P/7fwaGIsGNuQ==", "dependencies": { - "base64-js": "^1.3.1", - "ieee754": "^1.1.13" + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@jimp/core/node_modules/file-type": { - "version": "16.5.4", - "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz", - "integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==", - "license": "MIT", + "node_modules/@aws-sdk/middleware-logger/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "readable-web-to-node-stream": "^3.0.0", - "strtok3": "^6.2.4", - "token-types": "^4.1.1" + "tslib": "^2.6.2" }, "engines": { - "node": ">=10" - }, - "funding": { - "url": "https://github.com/sindresorhus/file-type?sponsor=1" + "node": ">=16.0.0" } }, - "node_modules/@jimp/core/node_modules/ieee754": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", - "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", - "funding": [ - { - "type": "github", - "url": "https://github.com/sponsors/feross" - }, - { - "type": "patreon", - "url": "https://www.patreon.com/feross" - }, - { - "type": "consulting", - "url": "https://feross.org/support" - } - ], - "license": "BSD-3-Clause" - }, - "node_modules/@jimp/core/node_modules/peek-readable": { - "version": "4.1.0", - "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz", - "integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==", - "license": "MIT", - "engines": { - "node": ">=8" + "node_modules/@aws-sdk/middleware-recursion-detection": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-recursion-detection/-/middleware-recursion-detection-3.620.0.tgz", + "integrity": "sha512-nh91S7aGK3e/o1ck64sA/CyoFw+gAYj2BDOnoNa6ouyCrVJED96ZXWbhye/fz9SgmNUZR2g7GdVpiLpMKZoI5w==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@jimp/core/node_modules/strtok3": { - "version": "6.3.0", - "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz", - "integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==", - "license": "MIT", + "node_modules/@aws-sdk/middleware-recursion-detection/node_modules/@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", "dependencies": { - "@tokenizer/token": "^0.3.0", - "peek-readable": "^4.1.0" + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" + "node": ">=16.0.0" } }, - "node_modules/@jimp/core/node_modules/token-types": { - "version": "4.2.1", - "resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz", - "integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==", - "license": "MIT", + "node_modules/@aws-sdk/middleware-recursion-detection/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@tokenizer/token": "^0.3.0", - "ieee754": "^1.2.1" + "tslib": "^2.6.2" }, "engines": { - "node": ">=10" - }, - "funding": { - "type": "github", - "url": "https://github.com/sponsors/Borewit" + "node": ">=16.0.0" } }, - "node_modules/@jimp/custom": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/custom/-/custom-0.22.12.tgz", - "integrity": "sha512-xcmww1O/JFP2MrlGUMd3Q78S3Qu6W3mYTXYuIqFq33EorgYHV/HqymHfXy9GjiCJ7OI+7lWx6nYFOzU7M4rd1Q==", - "license": "MIT", + "node_modules/@aws-sdk/middleware-user-agent": { + "version": "3.620.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/middleware-user-agent/-/middleware-user-agent-3.620.0.tgz", + "integrity": "sha512-bvS6etn+KsuL32ubY5D3xNof1qkenpbJXf/ugGXbg0n98DvDFQ/F+SMLxHgbnER5dsKYchNnhmtI6/FC3HFu/A==", "dependencies": { - "@jimp/core": "^0.22.12" + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@jimp/gif": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/gif/-/gif-0.22.12.tgz", - "integrity": "sha512-y6BFTJgch9mbor2H234VSjd9iwAhaNf/t3US5qpYIs0TSbAvM02Fbc28IaDETj9+4YB4676sz4RcN/zwhfu1pg==", - "license": "MIT", + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", "dependencies": { - "@jimp/utils": "^0.22.12", - "gifwrap": "^0.10.1", - "omggif": "^1.0.9" + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@jimp/jpeg": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/jpeg/-/jpeg-0.22.12.tgz", - "integrity": "sha512-Rq26XC/uQWaQKyb/5lksCTCxXhtY01NJeBN+dQv5yNYedN0i7iYu+fXEoRsfaJ8xZzjoANH8sns7rVP4GE7d/Q==", - "license": "MIT", + "node_modules/@aws-sdk/middleware-user-agent/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@jimp/utils": "^0.22.12", - "jpeg-js": "^0.4.4" + "tslib": "^2.6.2" }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@jimp/plugin-blit": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-0.22.12.tgz", - "integrity": "sha512-xslz2ZoFZOPLY8EZ4dC29m168BtDx95D6K80TzgUi8gqT7LY6CsajWO0FAxDwHz6h0eomHMfyGX0stspBrTKnQ==", - "license": "MIT", + "node_modules/@aws-sdk/region-config-resolver": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/region-config-resolver/-/region-config-resolver-3.614.0.tgz", + "integrity": "sha512-vDCeMXvic/LU0KFIUjpC3RiSTIkkvESsEfbVHiHH0YINfl8HnEqR5rj+L8+phsCeVg2+LmYwYxd5NRz4PHxt5g==", "dependencies": { - "@jimp/utils": "^0.22.12" + "@aws-sdk/types": "3.609.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@jimp/plugin-blur": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-0.22.12.tgz", - "integrity": "sha512-S0vJADTuh1Q9F+cXAwFPlrKWzDj2F9t/9JAbUvaaDuivpyWuImEKXVz5PUZw2NbpuSHjwssbTpOZ8F13iJX4uw==", - "license": "MIT", + "node_modules/@aws-sdk/region-config-resolver/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@jimp/utils": "^0.22.12" + "tslib": "^2.6.2" }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@jimp/plugin-circle": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-circle/-/plugin-circle-0.22.12.tgz", - "integrity": "sha512-SWVXx1yiuj5jZtMijqUfvVOJBwOifFn0918ou4ftoHgegc5aHWW5dZbYPjvC9fLpvz7oSlptNl2Sxr1zwofjTg==", - "license": "MIT", + "node_modules/@aws-sdk/token-providers": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/token-providers/-/token-providers-3.614.0.tgz", + "integrity": "sha512-okItqyY6L9IHdxqs+Z116y5/nda7rHxLvROxtAJdLavWTYDydxrZstImNgGWTeVdmc0xX2gJCI77UYUTQWnhRw==", "dependencies": { - "@jimp/utils": "^0.22.12" + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" }, "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "@aws-sdk/client-sso-oidc": "^3.614.0" } }, - "node_modules/@jimp/plugin-color": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.22.12.tgz", - "integrity": "sha512-xImhTE5BpS8xa+mAN6j4sMRWaUgUDLoaGHhJhpC+r7SKKErYDR0WQV4yCE4gP+N0gozD0F3Ka1LUSaMXrn7ZIA==", - "license": "MIT", + "node_modules/@aws-sdk/token-providers/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@jimp/utils": "^0.22.12", - "tinycolor2": "^1.6.0" + "tslib": "^2.6.2" }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@jimp/plugin-contain": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-0.22.12.tgz", - "integrity": "sha512-Eo3DmfixJw3N79lWk8q/0SDYbqmKt1xSTJ69yy8XLYQj9svoBbyRpSnHR+n9hOw5pKXytHwUW6nU4u1wegHNoQ==", - "license": "MIT", + "node_modules/@aws-sdk/types": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/types/-/types-3.609.0.tgz", + "integrity": "sha512-+Tqnh9w0h2LcrUsdXyT1F8mNhXz+tVYBtP19LpeEGntmvHwa2XzvLUCWpoIAIVsHp5+HdB2X9Sn0KAtmbFXc2Q==", "dependencies": { - "@jimp/utils": "^0.22.12" + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5", - "@jimp/plugin-blit": ">=0.3.5", - "@jimp/plugin-resize": ">=0.3.5", - "@jimp/plugin-scale": ">=0.3.5" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@jimp/plugin-cover": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-0.22.12.tgz", - "integrity": "sha512-z0w/1xH/v/knZkpTNx+E8a7fnasQ2wHG5ze6y5oL2dhH1UufNua8gLQXlv8/W56+4nJ1brhSd233HBJCo01BXA==", - "license": "MIT", + "node_modules/@aws-sdk/types/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@jimp/utils": "^0.22.12" + "tslib": "^2.6.2" }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5", - "@jimp/plugin-crop": ">=0.3.5", - "@jimp/plugin-resize": ">=0.3.5", - "@jimp/plugin-scale": ">=0.3.5" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@jimp/plugin-crop": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.22.12.tgz", - "integrity": "sha512-FNuUN0OVzRCozx8XSgP9MyLGMxNHHJMFt+LJuFjn1mu3k0VQxrzqbN06yIl46TVejhyAhcq5gLzqmSCHvlcBVw==", - "license": "MIT", + "node_modules/@aws-sdk/util-endpoints": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-endpoints/-/util-endpoints-3.614.0.tgz", + "integrity": "sha512-wK2cdrXHH4oz4IomV/yrGkftU9A+ITB6nFL+rxxyO78is2ifHJpFdV4aqk4LSkXYPi6CXWNru/Dqc7yiKXgJPw==", "dependencies": { - "@jimp/utils": "^0.22.12" + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "@smithy/util-endpoints": "^2.0.5", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@jimp/plugin-displace": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-0.22.12.tgz", - "integrity": "sha512-qpRM8JRicxfK6aPPqKZA6+GzBwUIitiHaZw0QrJ64Ygd3+AsTc7BXr+37k2x7QcyCvmKXY4haUrSIsBug4S3CA==", - "license": "MIT", + "node_modules/@aws-sdk/util-endpoints/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@jimp/utils": "^0.22.12" + "tslib": "^2.6.2" }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@jimp/plugin-dither": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-0.22.12.tgz", - "integrity": "sha512-jYgGdSdSKl1UUEanX8A85v4+QUm+PE8vHFwlamaKk89s+PXQe7eVE3eNeSZX4inCq63EHL7cX580dMqkoC3ZLw==", - "license": "MIT", + "node_modules/@aws-sdk/util-locate-window": { + "version": "3.568.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-locate-window/-/util-locate-window-3.568.0.tgz", + "integrity": "sha512-3nh4TINkXYr+H41QaPelCceEB2FXP3fxp93YZXB/kqJvX0U9j0N0Uk45gvsjmEPzG8XxkPEeLIfT2I1M7A6Lig==", "dependencies": { - "@jimp/utils": "^0.22.12" + "tslib": "^2.6.2" }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@jimp/plugin-fisheye": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-fisheye/-/plugin-fisheye-0.22.12.tgz", - "integrity": "sha512-LGuUTsFg+fOp6KBKrmLkX4LfyCy8IIsROwoUvsUPKzutSqMJnsm3JGDW2eOmWIS/jJpPaeaishjlxvczjgII+Q==", - "license": "MIT", + "node_modules/@aws-sdk/util-user-agent-browser": { + "version": "3.609.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-browser/-/util-user-agent-browser-3.609.0.tgz", + "integrity": "sha512-fojPU+mNahzQ0YHYBsx0ZIhmMA96H+ZIZ665ObU9tl+SGdbLneVZVikGve+NmHTQwHzwkFsZYYnVKAkreJLAtA==", "dependencies": { - "@jimp/utils": "^0.22.12" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "@aws-sdk/types": "3.609.0", + "@smithy/types": "^3.3.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" } }, - "node_modules/@jimp/plugin-flip": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-0.22.12.tgz", - "integrity": "sha512-m251Rop7GN8W0Yo/rF9LWk6kNclngyjIJs/VXHToGQ6EGveOSTSQaX2Isi9f9lCDLxt+inBIb7nlaLLxnvHX8Q==", - "license": "MIT", + "node_modules/@aws-sdk/util-user-agent-browser/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@jimp/utils": "^0.22.12" + "tslib": "^2.6.2" }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5", - "@jimp/plugin-rotate": ">=0.3.5" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@jimp/plugin-gaussian": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-gaussian/-/plugin-gaussian-0.22.12.tgz", - "integrity": "sha512-sBfbzoOmJ6FczfG2PquiK84NtVGeScw97JsCC3rpQv1PHVWyW+uqWFF53+n3c8Y0P2HWlUjflEla2h/vWShvhg==", - "license": "MIT", + "node_modules/@aws-sdk/util-user-agent-node": { + "version": "3.614.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/util-user-agent-node/-/util-user-agent-node-3.614.0.tgz", + "integrity": "sha512-15ElZT88peoHnq5TEoEtZwoXTXRxNrk60TZNdpl/TUBJ5oNJ9Dqb5Z4ryb8ofN6nm9aFf59GVAerFDz8iUoHBA==", "dependencies": { - "@jimp/utils": "^0.22.12" + "@aws-sdk/types": "3.609.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" }, "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "aws-crt": ">=1.0.0" + }, + "peerDependenciesMeta": { + "aws-crt": { + "optional": true + } } }, - "node_modules/@jimp/plugin-invert": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-invert/-/plugin-invert-0.22.12.tgz", - "integrity": "sha512-N+6rwxdB+7OCR6PYijaA/iizXXodpxOGvT/smd/lxeXsZ/empHmFFFJ/FaXcYh19Tm04dGDaXcNF/dN5nm6+xQ==", - "license": "MIT", + "node_modules/@aws-sdk/util-user-agent-node/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@jimp/utils": "^0.22.12" + "tslib": "^2.6.2" }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@jimp/plugin-mask": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-0.22.12.tgz", - "integrity": "sha512-4AWZg+DomtpUA099jRV8IEZUfn1wLv6+nem4NRJC7L/82vxzLCgXKTxvNvBcNmJjT9yS1LAAmiJGdWKXG63/NA==", + "node_modules/@babel/code-frame": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.7.tgz", + "integrity": "sha512-BcYH1CVJBO9tvyIZ2jVeXgSIMvGZ2FDRvDdOIVQyuklNKSsx+eppDEBq/g47Ayw+RqNFE+URvOShmf+f/qwAlA==", + "dev": true, "license": "MIT", "dependencies": { - "@jimp/utils": "^0.22.12" + "@babel/highlight": "^7.24.7", + "picocolors": "^1.0.0" }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@jimp/plugin-normalize": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-normalize/-/plugin-normalize-0.22.12.tgz", - "integrity": "sha512-0So0rexQivnWgnhacX4cfkM2223YdExnJTTy6d06WbkfZk5alHUx8MM3yEzwoCN0ErO7oyqEWRnEkGC+As1FtA==", + "node_modules/@babel/compat-data": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.7.tgz", + "integrity": "sha512-qJzAIcv03PyaWqxRgO4mSU3lihncDT296vnyuE2O8uA4w3UHWI4S3hgeZd1L8W1Bft40w9JxJ2b412iDUFFRhw==", + "dev": true, "license": "MIT", - "dependencies": { - "@jimp/utils": "^0.22.12" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@jimp/plugin-print": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-0.22.12.tgz", - "integrity": "sha512-c7TnhHlxm87DJeSnwr/XOLjJU/whoiKYY7r21SbuJ5nuH+7a78EW1teOaj5gEr2wYEd7QtkFqGlmyGXY/YclyQ==", + "node_modules/@babel/core": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.7.tgz", + "integrity": "sha512-nykK+LEK86ahTkX/3TgauT0ikKoNCfKHEaZYTUVupJdTLzGNvrblu4u6fa7DhZONAltdf8e662t/abY8idrd/g==", + "dev": true, "license": "MIT", "dependencies": { - "@jimp/utils": "^0.22.12", - "load-bmfont": "^1.4.1" + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.7", + "@babel/helper-compilation-targets": "^7.24.7", + "@babel/helper-module-transforms": "^7.24.7", + "@babel/helpers": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/template": "^7.24.7", + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5", - "@jimp/plugin-blit": ">=0.3.5" + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" } }, - "node_modules/@jimp/plugin-resize": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.22.12.tgz", - "integrity": "sha512-3NyTPlPbTnGKDIbaBgQ3HbE6wXbAlFfxHVERmrbqAi8R3r6fQPxpCauA8UVDnieg5eo04D0T8nnnNIX//i/sXg==", + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.7.tgz", + "integrity": "sha512-oipXieGC3i45Y1A41t4tAqpnEZWgB/lC6Ehh6+rOviR5XWpTtMmLN+fGjz9vOiNRt0p6RtO6DtD0pdU3vpqdSA==", "license": "MIT", "dependencies": { - "@jimp/utils": "^0.22.12" + "@babel/types": "^7.24.7", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@jimp/plugin-rotate": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-0.22.12.tgz", - "integrity": "sha512-9YNEt7BPAFfTls2FGfKBVgwwLUuKqy+E8bDGGEsOqHtbuhbshVGxN2WMZaD4gh5IDWvR+emmmPPWGgaYNYt1gA==", + "node_modules/@babel/helper-compilation-targets": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.24.7.tgz", + "integrity": "sha512-ctSdRHBi20qWOfy27RUb4Fhp07KSJ3sXcuSvTrXrc4aG8NSYDo1ici3Vhg9bg69y5bj0Mr1lh0aeEgTvc12rMg==", + "dev": true, "license": "MIT", "dependencies": { - "@jimp/utils": "^0.22.12" + "@babel/compat-data": "^7.24.7", + "@babel/helper-validator-option": "^7.24.7", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5", - "@jimp/plugin-blit": ">=0.3.5", - "@jimp/plugin-crop": ">=0.3.5", - "@jimp/plugin-resize": ">=0.3.5" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@jimp/plugin-scale": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-scale/-/plugin-scale-0.22.12.tgz", - "integrity": "sha512-dghs92qM6MhHj0HrV2qAwKPMklQtjNpoYgAB94ysYpsXslhRTiPisueSIELRwZGEr0J0VUxpUY7HgJwlSIgGZw==", - "license": "MIT", - "dependencies": { - "@jimp/utils": "^0.22.12" - }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5", - "@jimp/plugin-resize": ">=0.3.5" + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "license": "ISC", + "bin": { + "semver": "bin/semver.js" } }, - "node_modules/@jimp/plugin-shadow": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-shadow/-/plugin-shadow-0.22.12.tgz", - "integrity": "sha512-FX8mTJuCt7/3zXVoeD/qHlm4YH2bVqBuWQHXSuBK054e7wFRnRnbSLPUqAwSeYP3lWqpuQzJtgiiBxV3+WWwTg==", + "node_modules/@babel/helper-environment-visitor": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.24.7.tgz", + "integrity": "sha512-DoiN84+4Gnd0ncbBOM9AZENV4a5ZiL39HYMyZJGZ/AZEykHYdJw0wW3kdcsh9/Kn+BRXHLkkklZ51ecPKmI1CQ==", + "dev": true, "license": "MIT", "dependencies": { - "@jimp/utils": "^0.22.12" + "@babel/types": "^7.24.7" }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5", - "@jimp/plugin-blur": ">=0.3.5", - "@jimp/plugin-resize": ">=0.3.5" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@jimp/plugin-threshold": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugin-threshold/-/plugin-threshold-0.22.12.tgz", - "integrity": "sha512-4x5GrQr1a/9L0paBC/MZZJjjgjxLYrqSmWd+e+QfAEPvmRxdRoQ5uKEuNgXnm9/weHQBTnQBQsOY2iFja+XGAw==", + "node_modules/@babel/helper-function-name": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.24.7.tgz", + "integrity": "sha512-FyoJTsj/PEUWu1/TYRiXTIHc8lbw+TDYkZuoE43opPS5TrI7MyONBE1oNvfguEXAD9yhQRrVBnXdXzSLQl9XnA==", + "dev": true, "license": "MIT", "dependencies": { - "@jimp/utils": "^0.22.12" + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5", - "@jimp/plugin-color": ">=0.8.0", - "@jimp/plugin-resize": ">=0.8.0" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@jimp/plugins": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/plugins/-/plugins-0.22.12.tgz", - "integrity": "sha512-yBJ8vQrDkBbTgQZLty9k4+KtUQdRjsIDJSPjuI21YdVeqZxYywifHl4/XWILoTZsjTUASQcGoH0TuC0N7xm3ww==", + "node_modules/@babel/helper-hoist-variables": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.24.7.tgz", + "integrity": "sha512-MJJwhkoGy5c4ehfoRyrJ/owKeMl19U54h27YYftT0o2teQ3FJ3nQUf/I3LlJsX4l3qlw7WRXUmiyajvHXoTubQ==", + "dev": true, "license": "MIT", "dependencies": { - "@jimp/plugin-blit": "^0.22.12", - "@jimp/plugin-blur": "^0.22.12", - "@jimp/plugin-circle": "^0.22.12", - "@jimp/plugin-color": "^0.22.12", - "@jimp/plugin-contain": "^0.22.12", - "@jimp/plugin-cover": "^0.22.12", - "@jimp/plugin-crop": "^0.22.12", - "@jimp/plugin-displace": "^0.22.12", - "@jimp/plugin-dither": "^0.22.12", - "@jimp/plugin-fisheye": "^0.22.12", - "@jimp/plugin-flip": "^0.22.12", - "@jimp/plugin-gaussian": "^0.22.12", - "@jimp/plugin-invert": "^0.22.12", - "@jimp/plugin-mask": "^0.22.12", - "@jimp/plugin-normalize": "^0.22.12", - "@jimp/plugin-print": "^0.22.12", - "@jimp/plugin-resize": "^0.22.12", - "@jimp/plugin-rotate": "^0.22.12", - "@jimp/plugin-scale": "^0.22.12", - "@jimp/plugin-shadow": "^0.22.12", - "@jimp/plugin-threshold": "^0.22.12", - "timm": "^1.6.1" + "@babel/types": "^7.24.7" }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@jimp/png": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/png/-/png-0.22.12.tgz", - "integrity": "sha512-Mrp6dr3UTn+aLK8ty/dSKELz+Otdz1v4aAXzV5q53UDD2rbB5joKVJ/ChY310B+eRzNxIovbUF1KVrUsYdE8Hg==", + "node_modules/@babel/helper-module-imports": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.7.tgz", + "integrity": "sha512-8AyH3C+74cgCVVXow/myrynrAGv+nTVg5vKu2nZph9x7RcRwzmh0VFallJuFTZ9mx6u4eSdXZfcOzSqTUm0HCA==", + "dev": true, "license": "MIT", "dependencies": { - "@jimp/utils": "^0.22.12", - "pngjs": "^6.0.0" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@jimp/tiff": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/tiff/-/tiff-0.22.12.tgz", - "integrity": "sha512-E1LtMh4RyJsoCAfAkBRVSYyZDTtLq9p9LUiiYP0vPtXyxX4BiYBUYihTLSBlCQg5nF2e4OpQg7SPrLdJ66u7jg==", + "node_modules/@babel/helper-module-transforms": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.24.7.tgz", + "integrity": "sha512-1fuJEwIrp+97rM4RWdO+qrRsZlAeL1lQJoPqtCYWv0NL115XM93hIH4CSRln2w52SqvmY5hqdtauB6QFCDiZNQ==", + "dev": true, "license": "MIT", "dependencies": { - "utif2": "^4.0.1" + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-module-imports": "^7.24.7", + "@babel/helper-simple-access": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" }, "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "@babel/core": "^7.0.0" } }, - "node_modules/@jimp/types": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/types/-/types-0.22.12.tgz", - "integrity": "sha512-wwKYzRdElE1MBXFREvCto5s699izFHNVvALUv79GXNbsOVqlwlOxlWJ8DuyOGIXoLP4JW/m30YyuTtfUJgMRMA==", + "node_modules/@babel/helper-simple-access": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.24.7.tgz", + "integrity": "sha512-zBAIvbCMh5Ts+b86r/CjU+4XGYIs+R1j951gxI3KmmxBMhCg4oQMsv6ZXQ64XOm/cvzfU1FmoCyt6+owc5QMYg==", + "dev": true, "license": "MIT", "dependencies": { - "@jimp/bmp": "^0.22.12", - "@jimp/gif": "^0.22.12", - "@jimp/jpeg": "^0.22.12", - "@jimp/png": "^0.22.12", - "@jimp/tiff": "^0.22.12", - "timm": "^1.6.1" + "@babel/traverse": "^7.24.7", + "@babel/types": "^7.24.7" }, - "peerDependencies": { - "@jimp/custom": ">=0.3.5" + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@jimp/utils": { - "version": "0.22.12", - "resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.22.12.tgz", - "integrity": "sha512-yJ5cWUknGnilBq97ZXOyOS0HhsHOyAyjHwYfHxGbSyMTohgQI6sVyE8KPgDwH8HHW/nMKXk8TrSwAE71zt716Q==", + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.24.7.tgz", + "integrity": "sha512-oy5V7pD+UvfkEATUKvIjvIAH/xCzfsFVw7ygW2SI6NClZzquT+mwdTfgfdbUiceh6iQO0CHtCPsyze/MZ2YbAA==", + "dev": true, "license": "MIT", "dependencies": { - "regenerator-runtime": "^0.13.3" + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@jimp/utils/node_modules/regenerator-runtime": { - "version": "0.13.11", - "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", - "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", - "license": "MIT" - }, - "node_modules/@jridgewell/gen-mapping": { - "version": "0.3.5", - "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", - "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", - "dependencies": { - "@jridgewell/set-array": "^1.2.1", - "@jridgewell/sourcemap-codec": "^1.4.10", - "@jridgewell/trace-mapping": "^0.3.24" - }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.7.tgz", + "integrity": "sha512-7MbVt6xrwFQbunH2DNQsAP5sTGxfqQtErvBIvIMi6EQnbgUOuVYanvREcmFrOPhoXBrTtjhhP+lW+o5UfK+tDg==", + "license": "MIT", "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" } }, - "node_modules/@jridgewell/resolve-uri": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", - "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "node_modules/@babel/helper-validator-identifier": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.24.7.tgz", + "integrity": "sha512-rR+PBcQ1SMQDDyF6X0wxtG8QyLCgUB0eRAGguqRLfkCA87l7yAP7ehq8SNj96OOGTO8OBV70KhuFYcIkHXOg0w==", + "license": "MIT", "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" } }, - "node_modules/@jridgewell/set-array": { - "version": "1.2.1", - "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", - "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "node_modules/@babel/helper-validator-option": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.24.7.tgz", + "integrity": "sha512-yy1/KvjhV/ZCL+SM7hBrvnZJ3ZuT9OuZgIJAGpPEToANvc3iM6iDvBnRjtElWibHU6n8/LPR/EjX9EtIEYO3pw==", + "dev": true, + "license": "MIT", "engines": { - "node": ">=6.0.0" + "node": ">=6.9.0" } }, - "node_modules/@jridgewell/source-map": { - "version": "0.3.6", - "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", - "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "node_modules/@babel/helpers": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.7.tgz", + "integrity": "sha512-NlmJJtvcw72yRJRcnCmGvSi+3jDEg8qFu3z0AFoymmzLx5ERVWyzd9kVXr7Th9/8yIJi2Zc6av4Tqz3wFs8QWg==", "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/gen-mapping": "^0.3.5", - "@jridgewell/trace-mapping": "^0.3.25" + "@babel/template": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@jridgewell/sourcemap-codec": { - "version": "1.4.15", - "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", - "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" - }, - "node_modules/@jridgewell/trace-mapping": { - "version": "0.3.25", - "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", - "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "node_modules/@babel/highlight": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.7.tgz", + "integrity": "sha512-EStJpq4OuY8xYfhGVXngigBJRWxftKX9ksiGDnmlY3o7B/V7KIAc9X4oiK87uPJSc/vs5L869bem5fhZa8caZw==", + "dev": true, + "license": "MIT", "dependencies": { - "@jridgewell/resolve-uri": "^3.1.0", - "@jridgewell/sourcemap-codec": "^1.4.14" + "@babel/helper-validator-identifier": "^7.24.7", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" } }, - "node_modules/@js-sdsl/ordered-map": { - "version": "4.4.2", - "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", - "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", + "node_modules/@babel/highlight/node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/highlight/node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "license": "MIT", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/@babel/highlight/node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true, + "license": "MIT" + }, + "node_modules/@babel/highlight/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.7.tgz", + "integrity": "sha512-9uUYRm6OqQrCqQdG1iCBwBPZgN8ciDBro2nIOFaiRz1/BCxaI7CNvQbDHvsArAC7Tw9Hda/B3U+6ui9u4HWXPw==", + "license": "MIT", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/runtime": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.7.tgz", + "integrity": "sha512-UwgBRMjJP+xv857DCngvqXI3Iq6J4v0wXmwc6sapg+zyhbwmQX67LUEFrkK5tbyJ30jGuG3ZvWpBiB9LCy1kWw==", + "dev": true, + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.7.tgz", + "integrity": "sha512-jYqfPrU9JTF0PmPy1tLYHW4Mp4KlgxJD9l2nP9fD6yT/ICi554DmrWBAEYpIelzjHf1msDP3PxJIRt/nFNfBig==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.7.tgz", + "integrity": "sha512-yb65Ed5S/QAcewNPh0nZczy9JdYXkkAbIsEo+P7BE7yO3txAY30Y/oPa3QkQ5It3xVG2kpKMg9MsdxZaO31uKA==", + "dev": true, + "license": "MIT", + "dependencies": { + "@babel/code-frame": "^7.24.7", + "@babel/generator": "^7.24.7", + "@babel/helper-environment-visitor": "^7.24.7", + "@babel/helper-function-name": "^7.24.7", + "@babel/helper-hoist-variables": "^7.24.7", + "@babel/helper-split-export-declaration": "^7.24.7", + "@babel/parser": "^7.24.7", + "@babel/types": "^7.24.7", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/@babel/types": { + "version": "7.24.7", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.7.tgz", + "integrity": "sha512-XEFXSlxiG5td2EJRe8vOmRbaXVgfcBlszKujvVmWIK/UpywWljQCfzAv3RQCGujWQ1RD4YYWEAqDXfuJiy8f5Q==", + "license": "MIT", + "dependencies": { + "@babel/helper-string-parser": "^7.24.7", + "@babel/helper-validator-identifier": "^7.24.7", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@colors/colors": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.6.0.tgz", + "integrity": "sha512-Ir+AOibqzrIsL6ajt3Rz3LskB7OiMVHqltZmspbW/TJuTVuyOMirVqAkjfY6JISiLHgyNqicAC8AyHHGzNd/dA==", + "license": "MIT", + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@dabh/diagnostics": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", + "integrity": "sha512-hrlQOIi7hAfzsMqlGSFyVucrx38O+j6wiGOf//H2ecvIEqYN4ADBSS2iLMh5UFyDunCNniUIPk/q3riFv45xRA==", "license": "MIT", + "dependencies": { + "colorspace": "1.1.x", + "enabled": "2.0.x", + "kuler": "^2.0.0" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "dev": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/eslint-utils/node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, "funding": { - "type": "opencollective", - "url": "https://opencollective.com/js-sdsl" + "url": "https://opencollective.com/eslint" } }, - "node_modules/@kwsites/file-exists": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", - "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-3.0.2.tgz", + "integrity": "sha512-wV19ZEGEMAC1eHgrS7UQPqsdEiCIbTKTasEfcXAigzoXICcqZSjBZEHlZwNVvKg6UBCjSlos84XiLqsRJnIcIg==", + "dev": true, "dependencies": { - "debug": "^4.1.1" + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^10.0.1", + "globals": "^14.0.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "14.0.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-14.0.0.tgz", + "integrity": "sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ==", + "dev": true, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "9.1.1", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.1.1.tgz", + "integrity": "sha512-5WoDz3Y19Bg2BnErkZTp0en+c/i9PvgFS7MBe1+m60HjFr0hrphlAGp4yzI7pxpt4xShln4ZyYp4neJm8hmOkQ==", + "dev": true, + "engines": { + "node": "^18.18.0 || ^20.9.0 || >=21.1.0" + } + }, + "node_modules/@grpc/grpc-js": { + "version": "1.10.10", + "resolved": "https://registry.npmjs.org/@grpc/grpc-js/-/grpc-js-1.10.10.tgz", + "integrity": "sha512-HPa/K5NX6ahMoeBv15njAc/sfF4/jmiXLar9UlC2UfHFKZzsCVLc3wbe7+7qua7w9VPh2/L6EBxyAV7/E8Wftg==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/proto-loader": "^0.7.13", + "@js-sdsl/ordered-map": "^4.4.2" + }, + "engines": { + "node": ">=12.10.0" + } + }, + "node_modules/@grpc/proto-loader": { + "version": "0.7.13", + "resolved": "https://registry.npmjs.org/@grpc/proto-loader/-/proto-loader-0.7.13.tgz", + "integrity": "sha512-AiXO/bfe9bmxBjxxtYxFAXGZvMaN5s8kO+jBHAJCON8rJoB5YS/D6X7ZNc6XQkuHNmyl4CYaMI1fJ/Gn27RGGw==", + "license": "Apache-2.0", + "dependencies": { + "lodash.camelcase": "^4.3.0", + "long": "^5.0.0", + "protobufjs": "^7.2.5", + "yargs": "^17.7.2" + }, + "bin": { + "proto-loader-gen-types": "build/bin/proto-loader-gen-types.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@hapi/b64": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@hapi/b64/-/b64-5.0.0.tgz", + "integrity": "sha512-ngu0tSEmrezoiIaNGG6rRvKOUkUuDdf4XTPnONHGYfSGRmDqPZX5oJL6HAdKTo1UQHECbdB4OzhWrfgVppjHUw==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "9.x.x" + } + }, + "node_modules/@hapi/boom": { + "version": "9.1.4", + "resolved": "https://registry.npmjs.org/@hapi/boom/-/boom-9.1.4.tgz", + "integrity": "sha512-Ls1oH8jaN1vNsqcaHVYJrKmgMcKsC1wcp8bujvXrHaAqD2iDYq3HoOwsxwo09Cuda5R5nC0o0IxlrlTuvPuzSw==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "9.x.x" + } + }, + "node_modules/@hapi/bourne": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/@hapi/bourne/-/bourne-2.1.0.tgz", + "integrity": "sha512-i1BpaNDVLJdRBEKeJWkVO6tYX6DMFBuwMhSuWqLsY4ufeTKGVuV5rBsUhxPayXqnnWHgXUAmWK16H/ykO5Wj4Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@hapi/cryptiles": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/cryptiles/-/cryptiles-5.1.0.tgz", + "integrity": "sha512-fo9+d1Ba5/FIoMySfMqPBR/7Pa29J2RsiPrl7bkwo5W5o+AN1dAYQRi4SPrPwwVxVGKjgLOEWrsvt1BonJSfLA==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/boom": "9.x.x" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@hapi/iron": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@hapi/iron/-/iron-6.0.0.tgz", + "integrity": "sha512-zvGvWDufiTGpTJPG1Y/McN8UqWBu0k/xs/7l++HVU535NLHXsHhy54cfEMdW7EjwKfbBfM9Xy25FmTiobb7Hvw==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/b64": "5.x.x", + "@hapi/boom": "9.x.x", + "@hapi/bourne": "2.x.x", + "@hapi/cryptiles": "5.x.x", + "@hapi/hoek": "9.x.x" + } + }, + "node_modules/@hapi/podium": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/@hapi/podium/-/podium-4.1.3.tgz", + "integrity": "sha512-ljsKGQzLkFqnQxE7qeanvgGj4dejnciErYd30dbrYzUOF/FyS/DOF97qcrT3bhoVwCYmxa6PEMhxfCPlnUcD2g==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "9.x.x", + "@hapi/teamwork": "5.x.x", + "@hapi/validate": "1.x.x" + } + }, + "node_modules/@hapi/teamwork": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/@hapi/teamwork/-/teamwork-5.1.1.tgz", + "integrity": "sha512-1oPx9AE5TIv+V6Ih54RP9lTZBso3rP8j4Xhb6iSVwPXtAM+sDopl5TFMv5Paw73UnpZJ9gjcrTE1BXrWt9eQrg==", + "license": "BSD-3-Clause", + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@hapi/validate": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@hapi/validate/-/validate-1.1.3.tgz", + "integrity": "sha512-/XMR0N0wjw0Twzq2pQOzPBZlDzkekGcoCtzO314BpIEsbXdYGthQUbxgkGDf4nhk1+IPDAsXqWjMohRQYO06UA==", + "license": "BSD-3-Clause", + "dependencies": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0" + } + }, + "node_modules/@heyputer/backend": { + "resolved": "src/backend", + "link": true + }, + "node_modules/@heyputer/kv.js": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/@heyputer/kv.js/-/kv.js-0.1.6.tgz", + "integrity": "sha512-p/aYYHVG6wp/z33rfq2bmc7KgfBP6pE7urnQcnAm8xTN3+U0i2hItXH7bBTJOgsmjqk59I1YUOzcjOTlLrZ26w==", + "license": "MIT", + "dependencies": { + "minimatch": "^9.0.0" + } + }, + "node_modules/@heyputer/kv.js/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "license": "MIT", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@heyputer/kv.js/node_modules/minimatch": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.5.tgz", + "integrity": "sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow==", + "license": "ISC", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@heyputer/multest": { + "version": "0.0.2", + "resolved": "https://registry.npmjs.org/@heyputer/multest/-/multest-0.0.2.tgz", + "integrity": "sha512-Hr4U9Z2/oMIyCKv+cgO3pNzncA4PAlkS9RotZwoicfzR2BLLu2Rjjp3/HpcLmtE7UEt0hlRMYP+ImMZPYGNwkg==", + "license": "UNLICENSED", + "dependencies": { + "append-field": "^1.0.0", + "busboy": "^1.6.0", + "form-data": "^4.0.0" + } + }, + "node_modules/@heyputer/parsely": { + "resolved": "src/parsely", + "link": true + }, + "node_modules/@heyputer/phoenix": { + "resolved": "src/phoenix", + "link": true + }, + "node_modules/@heyputer/puter-js-common": { + "resolved": "src/puter-js-common", + "link": true + }, + "node_modules/@heyputer/puterjs": { + "resolved": "src/puter-js", + "link": true + }, + "node_modules/@heyputer/terminal": { + "resolved": "src/terminal", + "link": true + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.13.0", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.13.0.tgz", + "integrity": "sha512-DZLEEqFWQFiyK6h5YIeynKx7JlvCYWL0cImfSRXZ9l4Sg2efkFGTuFf6vzXjK1cq6IYkU+Eg/JizXw+TD2vRNw==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.3", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.3.tgz", + "integrity": "sha512-93zYdMES/c1D69yZiKDBj0V24vqNzB/koF26KPaagAfd3P/4gUlh3Dys5ogAK+Exi9QyzlD8x/08Zt7wIKcDcA==", + "dev": true + }, + "node_modules/@humanwhocodes/retry": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@humanwhocodes/retry/-/retry-0.2.3.tgz", + "integrity": "sha512-X38nUbachlb01YMlvPFojKoiXq+LzZvuSce70KPMPdeM1Rj03k4dR7lDslhbqXn3Ang4EU3+EAmwEAsbrjHW3g==", + "dev": true, + "engines": { + "node": ">=18.18" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "license": "MIT", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "license": "MIT", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jimp/bmp": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/bmp/-/bmp-0.22.12.tgz", + "integrity": "sha512-aeI64HD0npropd+AR76MCcvvRaa+Qck6loCOS03CkkxGHN5/r336qTM5HPUdHKMDOGzqknuVPA8+kK1t03z12g==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12", + "bmp-js": "^0.1.0" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/core": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/core/-/core-0.22.12.tgz", + "integrity": "sha512-l0RR0dOPyzMKfjUW1uebzueFEDtCOj9fN6pyTYWWOM/VS4BciXQ1VVrJs8pO3kycGYZxncRKhCoygbNr8eEZQA==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12", + "any-base": "^1.1.0", + "buffer": "^5.2.0", + "exif-parser": "^0.1.12", + "file-type": "^16.5.4", + "isomorphic-fetch": "^3.0.0", + "pixelmatch": "^4.0.2", + "tinycolor2": "^1.6.0" + } + }, + "node_modules/@jimp/core/node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/@jimp/core/node_modules/file-type": { + "version": "16.5.4", + "resolved": "https://registry.npmjs.org/file-type/-/file-type-16.5.4.tgz", + "integrity": "sha512-/yFHK0aGjFEgDJjEKP0pWCplsPFPhwyfwevf/pVxiN0tmE4L9LmwWxWukdJSHdoCli4VgQLehjJtwQBnqmsKcw==", + "license": "MIT", + "dependencies": { + "readable-web-to-node-stream": "^3.0.0", + "strtok3": "^6.2.4", + "token-types": "^4.1.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/file-type?sponsor=1" + } + }, + "node_modules/@jimp/core/node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "BSD-3-Clause" + }, + "node_modules/@jimp/core/node_modules/peek-readable": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/peek-readable/-/peek-readable-4.1.0.tgz", + "integrity": "sha512-ZI3LnwUv5nOGbQzD9c2iDG6toheuXSZP5esSHBjopsXH4dg19soufvpUGA3uohi5anFtGb2lhAVdHzH6R/Evvg==", + "license": "MIT", + "engines": { + "node": ">=8" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/@jimp/core/node_modules/strtok3": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-6.3.0.tgz", + "integrity": "sha512-fZtbhtvI9I48xDSywd/somNqgUHl2L2cstmXCCif0itOf96jeW18MBSyrLuNicYQVkvpOxkZtkzujiTJ9LW5Jw==", + "license": "MIT", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "peek-readable": "^4.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/@jimp/core/node_modules/token-types": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/token-types/-/token-types-4.2.1.tgz", + "integrity": "sha512-6udB24Q737UD/SDsKAHI9FCRP7Bqc9D/MQUV02ORQg5iskjtLJlZJNdN4kKtcdtwCeWIwIHDGaUsTsCCAa8sFQ==", + "license": "MIT", + "dependencies": { + "@tokenizer/token": "^0.3.0", + "ieee754": "^1.2.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/Borewit" + } + }, + "node_modules/@jimp/custom": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/custom/-/custom-0.22.12.tgz", + "integrity": "sha512-xcmww1O/JFP2MrlGUMd3Q78S3Qu6W3mYTXYuIqFq33EorgYHV/HqymHfXy9GjiCJ7OI+7lWx6nYFOzU7M4rd1Q==", + "license": "MIT", + "dependencies": { + "@jimp/core": "^0.22.12" + } + }, + "node_modules/@jimp/gif": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/gif/-/gif-0.22.12.tgz", + "integrity": "sha512-y6BFTJgch9mbor2H234VSjd9iwAhaNf/t3US5qpYIs0TSbAvM02Fbc28IaDETj9+4YB4676sz4RcN/zwhfu1pg==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12", + "gifwrap": "^0.10.1", + "omggif": "^1.0.9" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/jpeg": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/jpeg/-/jpeg-0.22.12.tgz", + "integrity": "sha512-Rq26XC/uQWaQKyb/5lksCTCxXhtY01NJeBN+dQv5yNYedN0i7iYu+fXEoRsfaJ8xZzjoANH8sns7rVP4GE7d/Q==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12", + "jpeg-js": "^0.4.4" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-blit": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-blit/-/plugin-blit-0.22.12.tgz", + "integrity": "sha512-xslz2ZoFZOPLY8EZ4dC29m168BtDx95D6K80TzgUi8gqT7LY6CsajWO0FAxDwHz6h0eomHMfyGX0stspBrTKnQ==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-blur": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-blur/-/plugin-blur-0.22.12.tgz", + "integrity": "sha512-S0vJADTuh1Q9F+cXAwFPlrKWzDj2F9t/9JAbUvaaDuivpyWuImEKXVz5PUZw2NbpuSHjwssbTpOZ8F13iJX4uw==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-circle": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-circle/-/plugin-circle-0.22.12.tgz", + "integrity": "sha512-SWVXx1yiuj5jZtMijqUfvVOJBwOifFn0918ou4ftoHgegc5aHWW5dZbYPjvC9fLpvz7oSlptNl2Sxr1zwofjTg==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-color": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-color/-/plugin-color-0.22.12.tgz", + "integrity": "sha512-xImhTE5BpS8xa+mAN6j4sMRWaUgUDLoaGHhJhpC+r7SKKErYDR0WQV4yCE4gP+N0gozD0F3Ka1LUSaMXrn7ZIA==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12", + "tinycolor2": "^1.6.0" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-contain": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-contain/-/plugin-contain-0.22.12.tgz", + "integrity": "sha512-Eo3DmfixJw3N79lWk8q/0SDYbqmKt1xSTJ69yy8XLYQj9svoBbyRpSnHR+n9hOw5pKXytHwUW6nU4u1wegHNoQ==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blit": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5", + "@jimp/plugin-scale": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-cover": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-cover/-/plugin-cover-0.22.12.tgz", + "integrity": "sha512-z0w/1xH/v/knZkpTNx+E8a7fnasQ2wHG5ze6y5oL2dhH1UufNua8gLQXlv8/W56+4nJ1brhSd233HBJCo01BXA==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-crop": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5", + "@jimp/plugin-scale": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-crop": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-crop/-/plugin-crop-0.22.12.tgz", + "integrity": "sha512-FNuUN0OVzRCozx8XSgP9MyLGMxNHHJMFt+LJuFjn1mu3k0VQxrzqbN06yIl46TVejhyAhcq5gLzqmSCHvlcBVw==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-displace": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-displace/-/plugin-displace-0.22.12.tgz", + "integrity": "sha512-qpRM8JRicxfK6aPPqKZA6+GzBwUIitiHaZw0QrJ64Ygd3+AsTc7BXr+37k2x7QcyCvmKXY4haUrSIsBug4S3CA==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-dither": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-dither/-/plugin-dither-0.22.12.tgz", + "integrity": "sha512-jYgGdSdSKl1UUEanX8A85v4+QUm+PE8vHFwlamaKk89s+PXQe7eVE3eNeSZX4inCq63EHL7cX580dMqkoC3ZLw==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-fisheye": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-fisheye/-/plugin-fisheye-0.22.12.tgz", + "integrity": "sha512-LGuUTsFg+fOp6KBKrmLkX4LfyCy8IIsROwoUvsUPKzutSqMJnsm3JGDW2eOmWIS/jJpPaeaishjlxvczjgII+Q==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-flip": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-flip/-/plugin-flip-0.22.12.tgz", + "integrity": "sha512-m251Rop7GN8W0Yo/rF9LWk6kNclngyjIJs/VXHToGQ6EGveOSTSQaX2Isi9f9lCDLxt+inBIb7nlaLLxnvHX8Q==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-rotate": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-gaussian": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-gaussian/-/plugin-gaussian-0.22.12.tgz", + "integrity": "sha512-sBfbzoOmJ6FczfG2PquiK84NtVGeScw97JsCC3rpQv1PHVWyW+uqWFF53+n3c8Y0P2HWlUjflEla2h/vWShvhg==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-invert": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-invert/-/plugin-invert-0.22.12.tgz", + "integrity": "sha512-N+6rwxdB+7OCR6PYijaA/iizXXodpxOGvT/smd/lxeXsZ/empHmFFFJ/FaXcYh19Tm04dGDaXcNF/dN5nm6+xQ==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-mask": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-mask/-/plugin-mask-0.22.12.tgz", + "integrity": "sha512-4AWZg+DomtpUA099jRV8IEZUfn1wLv6+nem4NRJC7L/82vxzLCgXKTxvNvBcNmJjT9yS1LAAmiJGdWKXG63/NA==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-normalize": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-normalize/-/plugin-normalize-0.22.12.tgz", + "integrity": "sha512-0So0rexQivnWgnhacX4cfkM2223YdExnJTTy6d06WbkfZk5alHUx8MM3yEzwoCN0ErO7oyqEWRnEkGC+As1FtA==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-print": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-print/-/plugin-print-0.22.12.tgz", + "integrity": "sha512-c7TnhHlxm87DJeSnwr/XOLjJU/whoiKYY7r21SbuJ5nuH+7a78EW1teOaj5gEr2wYEd7QtkFqGlmyGXY/YclyQ==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12", + "load-bmfont": "^1.4.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blit": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-resize": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-resize/-/plugin-resize-0.22.12.tgz", + "integrity": "sha512-3NyTPlPbTnGKDIbaBgQ3HbE6wXbAlFfxHVERmrbqAi8R3r6fQPxpCauA8UVDnieg5eo04D0T8nnnNIX//i/sXg==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-rotate": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-rotate/-/plugin-rotate-0.22.12.tgz", + "integrity": "sha512-9YNEt7BPAFfTls2FGfKBVgwwLUuKqy+E8bDGGEsOqHtbuhbshVGxN2WMZaD4gh5IDWvR+emmmPPWGgaYNYt1gA==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blit": ">=0.3.5", + "@jimp/plugin-crop": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-scale": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-scale/-/plugin-scale-0.22.12.tgz", + "integrity": "sha512-dghs92qM6MhHj0HrV2qAwKPMklQtjNpoYgAB94ysYpsXslhRTiPisueSIELRwZGEr0J0VUxpUY7HgJwlSIgGZw==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-shadow": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-shadow/-/plugin-shadow-0.22.12.tgz", + "integrity": "sha512-FX8mTJuCt7/3zXVoeD/qHlm4YH2bVqBuWQHXSuBK054e7wFRnRnbSLPUqAwSeYP3lWqpuQzJtgiiBxV3+WWwTg==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-blur": ">=0.3.5", + "@jimp/plugin-resize": ">=0.3.5" + } + }, + "node_modules/@jimp/plugin-threshold": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugin-threshold/-/plugin-threshold-0.22.12.tgz", + "integrity": "sha512-4x5GrQr1a/9L0paBC/MZZJjjgjxLYrqSmWd+e+QfAEPvmRxdRoQ5uKEuNgXnm9/weHQBTnQBQsOY2iFja+XGAw==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5", + "@jimp/plugin-color": ">=0.8.0", + "@jimp/plugin-resize": ">=0.8.0" + } + }, + "node_modules/@jimp/plugins": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/plugins/-/plugins-0.22.12.tgz", + "integrity": "sha512-yBJ8vQrDkBbTgQZLty9k4+KtUQdRjsIDJSPjuI21YdVeqZxYywifHl4/XWILoTZsjTUASQcGoH0TuC0N7xm3ww==", + "license": "MIT", + "dependencies": { + "@jimp/plugin-blit": "^0.22.12", + "@jimp/plugin-blur": "^0.22.12", + "@jimp/plugin-circle": "^0.22.12", + "@jimp/plugin-color": "^0.22.12", + "@jimp/plugin-contain": "^0.22.12", + "@jimp/plugin-cover": "^0.22.12", + "@jimp/plugin-crop": "^0.22.12", + "@jimp/plugin-displace": "^0.22.12", + "@jimp/plugin-dither": "^0.22.12", + "@jimp/plugin-fisheye": "^0.22.12", + "@jimp/plugin-flip": "^0.22.12", + "@jimp/plugin-gaussian": "^0.22.12", + "@jimp/plugin-invert": "^0.22.12", + "@jimp/plugin-mask": "^0.22.12", + "@jimp/plugin-normalize": "^0.22.12", + "@jimp/plugin-print": "^0.22.12", + "@jimp/plugin-resize": "^0.22.12", + "@jimp/plugin-rotate": "^0.22.12", + "@jimp/plugin-scale": "^0.22.12", + "@jimp/plugin-shadow": "^0.22.12", + "@jimp/plugin-threshold": "^0.22.12", + "timm": "^1.6.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/png": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/png/-/png-0.22.12.tgz", + "integrity": "sha512-Mrp6dr3UTn+aLK8ty/dSKELz+Otdz1v4aAXzV5q53UDD2rbB5joKVJ/ChY310B+eRzNxIovbUF1KVrUsYdE8Hg==", + "license": "MIT", + "dependencies": { + "@jimp/utils": "^0.22.12", + "pngjs": "^6.0.0" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/tiff": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/tiff/-/tiff-0.22.12.tgz", + "integrity": "sha512-E1LtMh4RyJsoCAfAkBRVSYyZDTtLq9p9LUiiYP0vPtXyxX4BiYBUYihTLSBlCQg5nF2e4OpQg7SPrLdJ66u7jg==", + "license": "MIT", + "dependencies": { + "utif2": "^4.0.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/types": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/types/-/types-0.22.12.tgz", + "integrity": "sha512-wwKYzRdElE1MBXFREvCto5s699izFHNVvALUv79GXNbsOVqlwlOxlWJ8DuyOGIXoLP4JW/m30YyuTtfUJgMRMA==", + "license": "MIT", + "dependencies": { + "@jimp/bmp": "^0.22.12", + "@jimp/gif": "^0.22.12", + "@jimp/jpeg": "^0.22.12", + "@jimp/png": "^0.22.12", + "@jimp/tiff": "^0.22.12", + "timm": "^1.6.1" + }, + "peerDependencies": { + "@jimp/custom": ">=0.3.5" + } + }, + "node_modules/@jimp/utils": { + "version": "0.22.12", + "resolved": "https://registry.npmjs.org/@jimp/utils/-/utils-0.22.12.tgz", + "integrity": "sha512-yJ5cWUknGnilBq97ZXOyOS0HhsHOyAyjHwYfHxGbSyMTohgQI6sVyE8KPgDwH8HHW/nMKXk8TrSwAE71zt716Q==", + "license": "MIT", + "dependencies": { + "regenerator-runtime": "^0.13.3" + } + }, + "node_modules/@jimp/utils/node_modules/regenerator-runtime": { + "version": "0.13.11", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz", + "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==", + "license": "MIT" + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz", + "integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.6.tgz", + "integrity": "sha512-1ZJTZebgqllO79ue2bm3rIGud/bOe0pP5BjSRCRxxYkEZS8STV7zN84UBbiYu7jy+eCKSnVIUgoWWE/tt+shMQ==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@js-sdsl/ordered-map": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/@js-sdsl/ordered-map/-/ordered-map-4.4.2.tgz", + "integrity": "sha512-iUKgm52T8HOE/makSxjqoWhe95ZJA1/G1sYsGev2JDKUSS14KAgg1LHb+Ba+IPow0xflbnSkOsZcO08C7w1gYw==", + "license": "MIT", + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/@kwsites/file-exists": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/file-exists/-/file-exists-1.1.1.tgz", + "integrity": "sha512-m9/5YGR18lIwxSFDwfE3oA7bWuq9kdau6ugN4H2rJeyhFQZcG9AgSHkQtSD15a8WvTgfz9aikZMrKPHvbpqFiw==", + "dependencies": { + "debug": "^4.1.1" + } + }, + "node_modules/@kwsites/promise-deferred": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", + "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" + }, + "node_modules/@mapbox/node-pre-gyp": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", + "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", + "license": "BSD-3-Clause", + "dependencies": { + "detect-libc": "^2.0.0", + "https-proxy-agent": "^5.0.0", + "make-dir": "^3.1.0", + "node-fetch": "^2.6.7", + "nopt": "^5.0.0", + "npmlog": "^5.0.1", + "rimraf": "^3.0.2", + "semver": "^7.3.5", + "tar": "^6.1.11" + }, + "bin": { + "node-pre-gyp": "bin/node-pre-gyp" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@opentelemetry/api": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.4.1.tgz", + "integrity": "sha512-O2yRJce1GOc6PAy3QxFM4NzFiWzvScDC1/5ihYBL6BUEVdq0XMWN01sppE+H6bBXbaFYipjwFLEWLg5PaSOThA==", + "license": "Apache-2.0", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/@opentelemetry/api-logs": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.49.1.tgz", + "integrity": "sha512-kaNl/T7WzyMUQHQlVq7q0oV4Kev6+0xFwqzofryC66jgGMacd0QH5TwfpbUwSTby+SdAdprAe5UKMvBw4tKS5Q==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api": "^1.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/auto-instrumentations-node": { + "version": "0.43.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/auto-instrumentations-node/-/auto-instrumentations-node-0.43.0.tgz", + "integrity": "sha512-2WvHUSi/QVeVG8ObPD0Ls6WevfIbQjspxIQRuHaQFWXhmEwy/MsEcoQUjbNKXwO5516aS04GTydKEoRKsMwhdA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/instrumentation-amqplib": "^0.35.0", + "@opentelemetry/instrumentation-aws-lambda": "^0.39.0", + "@opentelemetry/instrumentation-aws-sdk": "^0.39.1", + "@opentelemetry/instrumentation-bunyan": "^0.36.0", + "@opentelemetry/instrumentation-cassandra-driver": "^0.36.0", + "@opentelemetry/instrumentation-connect": "^0.34.0", + "@opentelemetry/instrumentation-cucumber": "^0.4.0", + "@opentelemetry/instrumentation-dataloader": "^0.7.0", + "@opentelemetry/instrumentation-dns": "^0.34.0", + "@opentelemetry/instrumentation-express": "^0.36.1", + "@opentelemetry/instrumentation-fastify": "^0.34.0", + "@opentelemetry/instrumentation-fs": "^0.10.0", + "@opentelemetry/instrumentation-generic-pool": "^0.34.0", + "@opentelemetry/instrumentation-graphql": "^0.38.1", + "@opentelemetry/instrumentation-grpc": "^0.49.1", + "@opentelemetry/instrumentation-hapi": "^0.35.0", + "@opentelemetry/instrumentation-http": "^0.49.1", + "@opentelemetry/instrumentation-ioredis": "^0.38.0", + "@opentelemetry/instrumentation-knex": "^0.34.0", + "@opentelemetry/instrumentation-koa": "^0.38.0", + "@opentelemetry/instrumentation-lru-memoizer": "^0.35.0", + "@opentelemetry/instrumentation-memcached": "^0.34.0", + "@opentelemetry/instrumentation-mongodb": "^0.41.0", + "@opentelemetry/instrumentation-mongoose": "^0.36.0", + "@opentelemetry/instrumentation-mysql": "^0.36.0", + "@opentelemetry/instrumentation-mysql2": "^0.36.0", + "@opentelemetry/instrumentation-nestjs-core": "^0.35.0", + "@opentelemetry/instrumentation-net": "^0.34.0", + "@opentelemetry/instrumentation-pg": "^0.39.1", + "@opentelemetry/instrumentation-pino": "^0.36.0", + "@opentelemetry/instrumentation-redis": "^0.37.0", + "@opentelemetry/instrumentation-redis-4": "^0.37.0", + "@opentelemetry/instrumentation-restify": "^0.36.0", + "@opentelemetry/instrumentation-router": "^0.35.0", + "@opentelemetry/instrumentation-socket.io": "^0.37.0", + "@opentelemetry/instrumentation-tedious": "^0.8.0", + "@opentelemetry/instrumentation-winston": "^0.35.0", + "@opentelemetry/resource-detector-alibaba-cloud": "^0.28.7", + "@opentelemetry/resource-detector-aws": "^1.4.0", + "@opentelemetry/resource-detector-container": "^0.3.7", + "@opentelemetry/resource-detector-gcp": "^0.29.7", + "@opentelemetry/resources": "^1.12.0", + "@opentelemetry/sdk-node": "^0.49.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.4.1" + } + }, + "node_modules/@opentelemetry/context-async-hooks": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.22.0.tgz", + "integrity": "sha512-Nfdxyg8YtWqVWkyrCukkundAjPhUXi93JtVQmqDT1mZRVKqA7e2r7eJCrI+F651XUBMp0hsOJSGiFk3QSpaIJw==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/core": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.14.0.tgz", + "integrity": "sha512-MnMZ+sxsnlzloeuXL2nm5QcNczt/iO82UOeQQDHhV83F2fP3sgntW2evvtoxJki0MBLxEsh5ADD7PR/Hn5uzjw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.14.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.5.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-grpc": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.40.0.tgz", + "integrity": "sha512-/UW/6s1WBHkFgdwizouUCEGZPt7NE0Y5xpuFuHqQF/KyjcHzTWibXzB/XWOSS81X55FUxrI3Icoeptk7vtxJFQ==", + "license": "Apache-2.0", + "dependencies": { + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "1.14.0", + "@opentelemetry/otlp-grpc-exporter-base": "0.40.0", + "@opentelemetry/otlp-transformer": "0.40.0", + "@opentelemetry/resources": "1.14.0", + "@opentelemetry/sdk-trace-base": "1.14.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-grpc/node_modules/@opentelemetry/resources": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.14.0.tgz", + "integrity": "sha512-qRfWIgBxxl3z47E036Aey0Lj2ZjlFb27Q7Xnj1y1z/P293RXJZGLtcfn/w8JF7v1Q2hs3SDGxz7Wb9Dko1YUQA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.14.0", + "@opentelemetry/semantic-conventions": "1.14.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.5.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.49.1.tgz", + "integrity": "sha512-KOLtZfZvIrpGZLVvblKsiVQT7gQUZNKcUUH24Zz6Xbi7LJb9Vt6xtUZFYdR5IIjvt47PIqBKDWUQlU0o1wAsRw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/otlp-exporter-base": "0.49.1", + "@opentelemetry/otlp-transformer": "0.49.1", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/sdk-trace-base": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/core": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.22.0.tgz", + "integrity": "sha512-0VoAlT6x+Xzik1v9goJ3pZ2ppi6+xd3aUfg4brfrLkDBHRIVjMP0eBHrKrhB+NKcDyMAg8fAbGL3Npg/F6AwWA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.49.1.tgz", + "integrity": "sha512-z6sHliPqDgJU45kQatAettY9/eVF58qVPaTuejw9YWfSRqid9pXPYeegDCSdyS47KAUgAtm+nC28K3pfF27HWg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/otlp-transformer": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.49.1.tgz", + "integrity": "sha512-Z+koA4wp9L9e3jkFacyXTGphSWTbOKjwwXMpb0CxNb0kjTHGUxhYRN8GnkLFsFo5NbZPjP07hwAqeEG/uCratQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.49.1", + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/sdk-logs": "0.49.1", + "@opentelemetry/sdk-metrics": "1.22.0", + "@opentelemetry/sdk-trace-base": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/resources": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.22.0.tgz", + "integrity": "sha512-+vNeIFPH2hfcNL0AJk/ykJXoUCtR1YaDUZM+p3wZNU4Hq98gzq+7b43xbkXjadD9VhWIUQqEwXyY64q6msPj6A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/sdk-logs": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.49.1.tgz", + "integrity": "sha512-gCzYWsJE0h+3cuh3/cK+9UwlVFyHvj3PReIOCDOmdeXOp90ZjKRoDOJBc3mvk1LL6wyl1RWIivR8Rg9OToyesw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.9.0", + "@opentelemetry/api-logs": ">=0.39.1" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/sdk-metrics": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.22.0.tgz", + "integrity": "sha512-k6iIx6H3TZ+BVMr2z8M16ri2OxWaljg5h8ihGJxi/KQWcjign6FEaEzuigXt5bK9wVEhqAcWLCfarSftaNWkkg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "lodash.merge": "^4.6.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/sdk-trace-base": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.22.0.tgz", + "integrity": "sha512-pfTuSIpCKONC6vkTpv6VmACxD+P1woZf4q0K46nSUvXFvOFqjBYKFaAMkKD3M1mlKUUh0Oajwj35qNjMl80m1Q==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", + "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-proto/-/exporter-trace-otlp-proto-0.49.1.tgz", + "integrity": "sha512-n8ON/c9pdMyYAfSFWKkgsPwjYoxnki+6Olzo+klKfW7KqLWoyEkryNkbcMIYnGGNXwdkMIrjoaP0VxXB26Oxcg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/otlp-exporter-base": "0.49.1", + "@opentelemetry/otlp-proto-exporter-base": "0.49.1", + "@opentelemetry/otlp-transformer": "0.49.1", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/sdk-trace-base": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/core": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.22.0.tgz", + "integrity": "sha512-0VoAlT6x+Xzik1v9goJ3pZ2ppi6+xd3aUfg4brfrLkDBHRIVjMP0eBHrKrhB+NKcDyMAg8fAbGL3Npg/F6AwWA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.49.1.tgz", + "integrity": "sha512-z6sHliPqDgJU45kQatAettY9/eVF58qVPaTuejw9YWfSRqid9pXPYeegDCSdyS47KAUgAtm+nC28K3pfF27HWg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/otlp-transformer": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.49.1.tgz", + "integrity": "sha512-Z+koA4wp9L9e3jkFacyXTGphSWTbOKjwwXMpb0CxNb0kjTHGUxhYRN8GnkLFsFo5NbZPjP07hwAqeEG/uCratQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.49.1", + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/sdk-logs": "0.49.1", + "@opentelemetry/sdk-metrics": "1.22.0", + "@opentelemetry/sdk-trace-base": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/resources": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.22.0.tgz", + "integrity": "sha512-+vNeIFPH2hfcNL0AJk/ykJXoUCtR1YaDUZM+p3wZNU4Hq98gzq+7b43xbkXjadD9VhWIUQqEwXyY64q6msPj6A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/sdk-logs": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.49.1.tgz", + "integrity": "sha512-gCzYWsJE0h+3cuh3/cK+9UwlVFyHvj3PReIOCDOmdeXOp90ZjKRoDOJBc3mvk1LL6wyl1RWIivR8Rg9OToyesw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.9.0", + "@opentelemetry/api-logs": ">=0.39.1" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/sdk-metrics": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.22.0.tgz", + "integrity": "sha512-k6iIx6H3TZ+BVMr2z8M16ri2OxWaljg5h8ihGJxi/KQWcjign6FEaEzuigXt5bK9wVEhqAcWLCfarSftaNWkkg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "lodash.merge": "^4.6.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.3.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/sdk-trace-base": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.22.0.tgz", + "integrity": "sha512-pfTuSIpCKONC6vkTpv6VmACxD+P1woZf4q0K46nSUvXFvOFqjBYKFaAMkKD3M1mlKUUh0Oajwj35qNjMl80m1Q==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", + "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/exporter-zipkin": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-zipkin/-/exporter-zipkin-1.22.0.tgz", + "integrity": "sha512-XcFs6rGvcTz0qW5uY7JZDYD0yNEXdekXAb6sFtnZgY/cHY6BQ09HMzOjv9SX+iaXplRDcHr1Gta7VQKM1XXM6g==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/sdk-trace-base": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/exporter-zipkin/node_modules/@opentelemetry/core": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.22.0.tgz", + "integrity": "sha512-0VoAlT6x+Xzik1v9goJ3pZ2ppi6+xd3aUfg4brfrLkDBHRIVjMP0eBHrKrhB+NKcDyMAg8fAbGL3Npg/F6AwWA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/exporter-zipkin/node_modules/@opentelemetry/resources": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.22.0.tgz", + "integrity": "sha512-+vNeIFPH2hfcNL0AJk/ykJXoUCtR1YaDUZM+p3wZNU4Hq98gzq+7b43xbkXjadD9VhWIUQqEwXyY64q6msPj6A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/exporter-zipkin/node_modules/@opentelemetry/sdk-trace-base": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.22.0.tgz", + "integrity": "sha512-pfTuSIpCKONC6vkTpv6VmACxD+P1woZf4q0K46nSUvXFvOFqjBYKFaAMkKD3M1mlKUUh0Oajwj35qNjMl80m1Q==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/exporter-zipkin/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", + "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/instrumentation": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.49.1.tgz", + "integrity": "sha512-0DLtWtaIppuNNRRllSD4bjU8ZIiLp1cDXvJEbp752/Zf+y3gaLNaoGRGIlX4UHhcsrmtL+P2qxi3Hodi8VuKiQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "0.49.1", + "@types/shimmer": "^1.0.2", + "import-in-the-middle": "1.7.1", + "require-in-the-middle": "^7.1.1", + "semver": "^7.5.2", + "shimmer": "^1.2.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-amqplib": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-amqplib/-/instrumentation-amqplib-0.35.0.tgz", + "integrity": "sha512-rb3hIWA7f0HXpXpfElnGC6CukRxy58/OJ6XYlTzpZJtNJPao7BuobZjkQEscaRYhUzgi7X7R1aKkIUOTV5JFrg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-aws-lambda": { + "version": "0.39.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-aws-lambda/-/instrumentation-aws-lambda-0.39.0.tgz", + "integrity": "sha512-D+oG/hIBDdwCNq7Y6BEuddjcwDVD0C8NhBE7A85mRZ9RLG0bKoWrhIdVvbpqEoa0U5AWe9Y98RX4itNg7WTy4w==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/propagator-aws-xray": "^1.3.1", + "@opentelemetry/resources": "^1.8.0", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@types/aws-lambda": "8.10.122" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-aws-sdk": { + "version": "0.39.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-aws-sdk/-/instrumentation-aws-sdk-0.39.1.tgz", + "integrity": "sha512-QnvIMVpzRYqQHSXydGUksbhBjPbMyHSUBwi6ocN7gEXoI711+tIY3R1cfRutl0u3M67A/fAvPI3IgACfJaFORg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/propagation-utils": "^0.30.7", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-bunyan": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-bunyan/-/instrumentation-bunyan-0.36.0.tgz", + "integrity": "sha512-sHD5BSiqSrgWow7VmugEFzV8vGdsz5m+w1v9tK6YwRzuAD7vbo57chluq+UBzIqStoCH+0yOzRzSALH7hrfffg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/api-logs": "^0.49.1", + "@opentelemetry/instrumentation": "^0.49.1", + "@types/bunyan": "1.8.9" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-cassandra-driver": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-cassandra-driver/-/instrumentation-cassandra-driver-0.36.0.tgz", + "integrity": "sha512-gMfxzryOIP/mvSLXBJp/QxSr2NvS+cC1dkIXn+aSOzYoU1U3apeF3nAyuikmY9dRCQDV7wHPslqbi+pCmd4pAQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-connect": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.34.0.tgz", + "integrity": "sha512-PJO99nfyUp3JSoBMhwZsOQDm/XKfkb/QQ8YTsNX4ZJ28phoRcNLqe36mqIMp80DKmKAX4xkxCAyrSYtW8QqZxA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@types/connect": "3.4.36" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-cucumber": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-cucumber/-/instrumentation-cucumber-0.4.0.tgz", + "integrity": "sha512-n53QvozzgMS9imEclow2nBYJ/jtZlZqiKIqDUi2/g0nDi08F555JhDS03d/Z+4NJxbu7bDLAg12giCV9KZN/Jw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" + } + }, + "node_modules/@opentelemetry/instrumentation-dataloader": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-dataloader/-/instrumentation-dataloader-0.7.0.tgz", + "integrity": "sha512-sIaevxATJV5YaZzBTTcTaDEnI+/1vxYs+lVk1honnvrEAaP0FA9C/cFrQEN0kP2BDHkHRE/t6y5lGUqusi/h3A==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-dns": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-dns/-/instrumentation-dns-0.34.0.tgz", + "integrity": "sha512-3tmXdvrzHQ7S3v82Cm36PTYLtgg2+hVm00K1xB3uzP08GEo9w/F8DW4me9z6rDroVGiLIg621RZ6dzjBcmmFCg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-express": { + "version": "0.36.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-express/-/instrumentation-express-0.36.1.tgz", + "integrity": "sha512-ltIE4kIMa+83QjW/p7oe7XCESF29w3FQ9/T1VgShdX7fzm56K2a0xfEX1vF8lnHRGERYxIWX9D086C6gJOjVGA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-fastify": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fastify/-/instrumentation-fastify-0.34.0.tgz", + "integrity": "sha512-2Qu66XBkfJ8tr6H+RHBTyw/EX73N9U7pvNa49aonDnT9/mK58k7AKOscpRnKXOvHqc2YIdEPRcBIWxhksPFZVA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-fs": { + "version": "0.10.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.10.0.tgz", + "integrity": "sha512-XtMoNINVsIQTQHjtxe7A0Lng96wxA5DSD5CYVVvpquG6HJRdZ4xNe9DTU03YtoEFqlN9qTfvGb/6ILzhKhiG8g==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-generic-pool": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-generic-pool/-/instrumentation-generic-pool-0.34.0.tgz", + "integrity": "sha512-jdI7tfVVwZJuTu4j2kAvJtx4wlEQKIXSZnZG4RdqRHc56KqQQDuVTBLvUgmDXvnSVclH9ayf4oaAV08R9fICtw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-graphql": { + "version": "0.38.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-graphql/-/instrumentation-graphql-0.38.1.tgz", + "integrity": "sha512-mSt4ztn3EVlLtZJ+tDEqq5GUEYdY8cbTT9SeVJFmXSfdSQkPZn0ovo/dRe6dUcplM60gg4w+llw8SZuQN0iZfQ==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-grpc": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-grpc/-/instrumentation-grpc-0.49.1.tgz", + "integrity": "sha512-f8mQjFi5/PiP4SK3VDU1/3sUUgs6exMtBgcnNycgCKgN40htiPT+MuDRwdRnRMNI/4vNQ7p1/5r4Q5oN0GuRBw==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "0.49.1", + "@opentelemetry/semantic-conventions": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-grpc/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", + "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/instrumentation-hapi": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-hapi/-/instrumentation-hapi-0.35.0.tgz", + "integrity": "sha512-j7q99aTLHfjNKW94qJnEaDatgz+q2psTKs7lxZO4QHRnoDltDk39a44/+AkI1qBJNw5xyLjrApqkglfbWJ2abg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@types/hapi__hapi": "20.0.13" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-http": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-http/-/instrumentation-http-0.49.1.tgz", + "integrity": "sha512-Yib5zrW2s0V8wTeUK/B3ZtpyP4ldgXj9L3Ws/axXrW1dW0/mEFKifK50MxMQK9g5NNJQS9dWH7rvcEGZdWdQDA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.22.0", + "@opentelemetry/instrumentation": "0.49.1", + "@opentelemetry/semantic-conventions": "1.22.0", + "semver": "^7.5.2" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-http/node_modules/@opentelemetry/core": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.22.0.tgz", + "integrity": "sha512-0VoAlT6x+Xzik1v9goJ3pZ2ppi6+xd3aUfg4brfrLkDBHRIVjMP0eBHrKrhB+NKcDyMAg8fAbGL3Npg/F6AwWA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/semantic-conventions": "1.22.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.0.0 <1.9.0" + } + }, + "node_modules/@opentelemetry/instrumentation-http/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", + "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/instrumentation-ioredis": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-ioredis/-/instrumentation-ioredis-0.38.0.tgz", + "integrity": "sha512-c9nQFhRjFAtpInTks7z5v9CiOCiR8U9GbIhIv0TLEJ/r0wqdKNLfLZzCrr9XQ9WasxeOmziLlPFhpRBAd9Q4oA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/redis-common": "^0.36.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@types/ioredis4": "npm:@types/ioredis@^4.28.10" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } + }, + "node_modules/@opentelemetry/instrumentation-knex": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-knex/-/instrumentation-knex-0.34.0.tgz", + "integrity": "sha512-6kZOEvNJOylTQunU5zSSi4iTuCkwIL9nwFnZg7719p61u3d6Qj3X4xi9su46VE3M0dH7vEoxUW+nb/0ilm+aZg==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@kwsites/promise-deferred": { - "version": "1.1.1", - "resolved": "https://registry.npmjs.org/@kwsites/promise-deferred/-/promise-deferred-1.1.1.tgz", - "integrity": "sha512-GaHYm+c0O9MjZRu0ongGBRbinu8gVAMd2UZjji6jVmqKtZluZnptXGWhz1E8j8D2HJ3f/yMxKAUC0b+57wncIw==" + "node_modules/@opentelemetry/instrumentation-koa": { + "version": "0.38.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-koa/-/instrumentation-koa-0.38.0.tgz", + "integrity": "sha512-lQujF4I3wdcrOF14miCV2pC72H+OJKb2LrrmTvTDAhELQDN/95v0doWgT9aHybUGkaAeB3QG4d09sved548TlA==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@types/koa": "2.14.0", + "@types/koa__router": "12.0.3" + }, + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" + } }, - "node_modules/@mapbox/node-pre-gyp": { - "version": "1.0.11", - "resolved": "https://registry.npmjs.org/@mapbox/node-pre-gyp/-/node-pre-gyp-1.0.11.tgz", - "integrity": "sha512-Yhlar6v9WQgUp/He7BdgzOz8lqMQ8sU+jkCq7Wx8Myc5YFJLbEe7lgui/V7G1qB1DJykHSGwreceSaD60Y0PUQ==", - "license": "BSD-3-Clause", + "node_modules/@opentelemetry/instrumentation-lru-memoizer": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-lru-memoizer/-/instrumentation-lru-memoizer-0.35.0.tgz", + "integrity": "sha512-wCXe+iCF7JweMgY3blLM2Y1G0GSwLEeSA61z/y1UwzvBLEEXt7vL6qOl2mkNcUL9ZbLDS+EABatBH+vFO6DV5Q==", + "license": "Apache-2.0", "dependencies": { - "detect-libc": "^2.0.0", - "https-proxy-agent": "^5.0.0", - "make-dir": "^3.1.0", - "node-fetch": "^2.6.7", - "nopt": "^5.0.0", - "npmlog": "^5.0.1", - "rimraf": "^3.0.2", - "semver": "^7.3.5", - "tar": "^6.1.11" + "@opentelemetry/instrumentation": "^0.49.1" }, - "bin": { - "node-pre-gyp": "bin/node-pre-gyp" + "engines": { + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@nodelib/fs.scandir": { - "version": "2.1.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", - "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", - "dev": true, + "node_modules/@opentelemetry/instrumentation-memcached": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-memcached/-/instrumentation-memcached-0.34.0.tgz", + "integrity": "sha512-RleFfaag3Evg4pTzHwDBwo1KiFgnCtiT4V6MQRRHadytNGdpcL+Ynz32ydDdiOXeadt7xpRI7HSvBy0quGTXSw==", + "license": "Apache-2.0", "dependencies": { - "@nodelib/fs.stat": "2.0.5", - "run-parallel": "^1.1.9" + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@types/memcached": "^2.2.6" }, "engines": { - "node": ">= 8" + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@nodelib/fs.stat": { - "version": "2.0.5", - "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", - "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", - "dev": true, + "node_modules/@opentelemetry/instrumentation-mongodb": { + "version": "0.41.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.41.0.tgz", + "integrity": "sha512-DlSH0oyEuTW5gprCUppb0Qe3pK3cpUUFW5eTmayWNyICI1LFunwtcrULTNv6UiThD/V5ykAf/GGGEa7KFAmkog==", + "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/sdk-metrics": "^1.9.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, "engines": { - "node": ">= 8" + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@nodelib/fs.walk": { - "version": "1.2.8", - "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", - "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", - "dev": true, + "node_modules/@opentelemetry/instrumentation-mongoose": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongoose/-/instrumentation-mongoose-0.36.0.tgz", + "integrity": "sha512-UelQ8dLQRLTdck3tPJdZ17b+Hk9usLf1cY2ou5THAaZpulUdpg62Q9Hx2RHRU71Rp2/YMDk25og7GJhuWScfEA==", + "license": "Apache-2.0", "dependencies": { - "@nodelib/fs.scandir": "2.1.5", - "fastq": "^1.6.0" + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" }, "engines": { - "node": ">= 8" + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/api": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/api/-/api-1.4.1.tgz", - "integrity": "sha512-O2yRJce1GOc6PAy3QxFM4NzFiWzvScDC1/5ihYBL6BUEVdq0XMWN01sppE+H6bBXbaFYipjwFLEWLg5PaSOThA==", + "node_modules/@opentelemetry/instrumentation-mysql": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql/-/instrumentation-mysql-0.36.0.tgz", + "integrity": "sha512-2mt/032SLkiuddzMrq3YwM0bHksXRep69EzGRnBfF+bCbwYvKLpqmSFqJZ9T3yY/mBWj+tvdvc1+klXGrh2QnQ==", "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@types/mysql": "2.15.22" + }, "engines": { - "node": ">=8.0.0" + "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/api-logs": { - "version": "0.49.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.49.1.tgz", - "integrity": "sha512-kaNl/T7WzyMUQHQlVq7q0oV4Kev6+0xFwqzofryC66jgGMacd0QH5TwfpbUwSTby+SdAdprAe5UKMvBw4tKS5Q==", + "node_modules/@opentelemetry/instrumentation-mysql2": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql2/-/instrumentation-mysql2-0.36.0.tgz", + "integrity": "sha512-F63lKcl/R+if2j5Vz66c2/SLXQEtLlFkWTmYb8NQSgmcCaEKjML4RRRjZISIT4IBwdpanJ2qmNuXVM6MYqhBXw==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/api": "^1.0.0" + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@opentelemetry/sql-common": "^0.40.0" }, "engines": { "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/auto-instrumentations-node": { - "version": "0.43.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/auto-instrumentations-node/-/auto-instrumentations-node-0.43.0.tgz", - "integrity": "sha512-2WvHUSi/QVeVG8ObPD0Ls6WevfIbQjspxIQRuHaQFWXhmEwy/MsEcoQUjbNKXwO5516aS04GTydKEoRKsMwhdA==", + "node_modules/@opentelemetry/instrumentation-nestjs-core": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-nestjs-core/-/instrumentation-nestjs-core-0.35.0.tgz", + "integrity": "sha512-INKA7CIOteTSRVxP7SQaFby11AYU3uezI93xDaDRGY4TloXNVoyw5n6UmcVJU4yDn6xY2r7zZ2SVHvblUc21/g==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/instrumentation-amqplib": "^0.35.0", - "@opentelemetry/instrumentation-aws-lambda": "^0.39.0", - "@opentelemetry/instrumentation-aws-sdk": "^0.39.1", - "@opentelemetry/instrumentation-bunyan": "^0.36.0", - "@opentelemetry/instrumentation-cassandra-driver": "^0.36.0", - "@opentelemetry/instrumentation-connect": "^0.34.0", - "@opentelemetry/instrumentation-cucumber": "^0.4.0", - "@opentelemetry/instrumentation-dataloader": "^0.7.0", - "@opentelemetry/instrumentation-dns": "^0.34.0", - "@opentelemetry/instrumentation-express": "^0.36.1", - "@opentelemetry/instrumentation-fastify": "^0.34.0", - "@opentelemetry/instrumentation-fs": "^0.10.0", - "@opentelemetry/instrumentation-generic-pool": "^0.34.0", - "@opentelemetry/instrumentation-graphql": "^0.38.1", - "@opentelemetry/instrumentation-grpc": "^0.49.1", - "@opentelemetry/instrumentation-hapi": "^0.35.0", - "@opentelemetry/instrumentation-http": "^0.49.1", - "@opentelemetry/instrumentation-ioredis": "^0.38.0", - "@opentelemetry/instrumentation-knex": "^0.34.0", - "@opentelemetry/instrumentation-koa": "^0.38.0", - "@opentelemetry/instrumentation-lru-memoizer": "^0.35.0", - "@opentelemetry/instrumentation-memcached": "^0.34.0", - "@opentelemetry/instrumentation-mongodb": "^0.41.0", - "@opentelemetry/instrumentation-mongoose": "^0.36.0", - "@opentelemetry/instrumentation-mysql": "^0.36.0", - "@opentelemetry/instrumentation-mysql2": "^0.36.0", - "@opentelemetry/instrumentation-nestjs-core": "^0.35.0", - "@opentelemetry/instrumentation-net": "^0.34.0", - "@opentelemetry/instrumentation-pg": "^0.39.1", - "@opentelemetry/instrumentation-pino": "^0.36.0", - "@opentelemetry/instrumentation-redis": "^0.37.0", - "@opentelemetry/instrumentation-redis-4": "^0.37.0", - "@opentelemetry/instrumentation-restify": "^0.36.0", - "@opentelemetry/instrumentation-router": "^0.35.0", - "@opentelemetry/instrumentation-socket.io": "^0.37.0", - "@opentelemetry/instrumentation-tedious": "^0.8.0", - "@opentelemetry/instrumentation-winston": "^0.35.0", - "@opentelemetry/resource-detector-alibaba-cloud": "^0.28.7", - "@opentelemetry/resource-detector-aws": "^1.4.0", - "@opentelemetry/resource-detector-container": "^0.3.7", - "@opentelemetry/resource-detector-gcp": "^0.29.7", - "@opentelemetry/resources": "^1.12.0", - "@opentelemetry/sdk-node": "^0.49.1" + "@opentelemetry/semantic-conventions": "^1.0.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.4.1" + "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/context-async-hooks": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/context-async-hooks/-/context-async-hooks-1.22.0.tgz", - "integrity": "sha512-Nfdxyg8YtWqVWkyrCukkundAjPhUXi93JtVQmqDT1mZRVKqA7e2r7eJCrI+F651XUBMp0hsOJSGiFk3QSpaIJw==", + "node_modules/@opentelemetry/instrumentation-net": { + "version": "0.34.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-net/-/instrumentation-net-0.34.0.tgz", + "integrity": "sha512-gjybNOQQqbXmD1qVHNO2qBJI4V6p3QQ7xKg3pnC/x7wRdxn+siLQj7QIVxW85C3mymngoJJdRs6BwI3qPUfsPQ==", "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" + }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" + "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/core": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.14.0.tgz", - "integrity": "sha512-MnMZ+sxsnlzloeuXL2nm5QcNczt/iO82UOeQQDHhV83F2fP3sgntW2evvtoxJki0MBLxEsh5ADD7PR/Hn5uzjw==", + "node_modules/@opentelemetry/instrumentation-pg": { + "version": "0.39.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pg/-/instrumentation-pg-0.39.1.tgz", + "integrity": "sha512-pX5ujDOyGpPcrZlzaD3LJzmyaSMMMKAP+ffTHJp9vasvZJr+LifCk53TMPVUafcXKV/xX/IIkvADO+67M1Z25g==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/semantic-conventions": "1.14.0" + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@opentelemetry/sql-common": "^0.40.0", + "@types/pg": "8.6.1", + "@types/pg-pool": "2.0.4" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.5.0" + "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/exporter-trace-otlp-grpc": { - "version": "0.40.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.40.0.tgz", - "integrity": "sha512-/UW/6s1WBHkFgdwizouUCEGZPt7NE0Y5xpuFuHqQF/KyjcHzTWibXzB/XWOSS81X55FUxrI3Icoeptk7vtxJFQ==", + "node_modules/@opentelemetry/instrumentation-pino": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pino/-/instrumentation-pino-0.36.0.tgz", + "integrity": "sha512-oEz+BJEYRBMAUu7MVJFJhhlsBuwLaUGjbJciKZRIeGX+fUtgcbQGV+a2Ris9jR3yFzWZrYg0aNBSCbGqvPCtMQ==", "license": "Apache-2.0", "dependencies": { - "@grpc/grpc-js": "^1.7.1", - "@opentelemetry/core": "1.14.0", - "@opentelemetry/otlp-grpc-exporter-base": "0.40.0", - "@opentelemetry/otlp-transformer": "0.40.0", - "@opentelemetry/resources": "1.14.0", - "@opentelemetry/sdk-trace-base": "1.14.0" + "@opentelemetry/instrumentation": "^0.49.1" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.0.0" + "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/exporter-trace-otlp-grpc/node_modules/@opentelemetry/resources": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.14.0.tgz", - "integrity": "sha512-qRfWIgBxxl3z47E036Aey0Lj2ZjlFb27Q7Xnj1y1z/P293RXJZGLtcfn/w8JF7v1Q2hs3SDGxz7Wb9Dko1YUQA==", + "node_modules/@opentelemetry/instrumentation-redis": { + "version": "0.37.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis/-/instrumentation-redis-0.37.0.tgz", + "integrity": "sha512-9G0T74kheu37k+UvyBnAcieB5iowxska3z2rhUcSTL8Cl0y/CvMn7sZ7txkUbXt0rdX6qeEUdMLmbsY2fPUM7Q==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.14.0", - "@opentelemetry/semantic-conventions": "1.14.0" + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/redis-common": "^0.36.1", + "@opentelemetry/semantic-conventions": "^1.0.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.5.0" + "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/exporter-trace-otlp-http": { - "version": "0.49.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-http/-/exporter-trace-otlp-http-0.49.1.tgz", - "integrity": "sha512-KOLtZfZvIrpGZLVvblKsiVQT7gQUZNKcUUH24Zz6Xbi7LJb9Vt6xtUZFYdR5IIjvt47PIqBKDWUQlU0o1wAsRw==", + "node_modules/@opentelemetry/instrumentation-redis-4": { + "version": "0.37.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis-4/-/instrumentation-redis-4-0.37.0.tgz", + "integrity": "sha512-WNO+HALvPPvjbh7UEEIuay0Z0d2mIfSCkBZbPRwZttDGX6LYGc2WnRgJh3TnYqjp7/y9IryWIbajAFIebj1OBA==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.22.0", - "@opentelemetry/otlp-exporter-base": "0.49.1", - "@opentelemetry/otlp-transformer": "0.49.1", - "@opentelemetry/resources": "1.22.0", - "@opentelemetry/sdk-trace-base": "1.22.0" + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/redis-common": "^0.36.1", + "@opentelemetry/semantic-conventions": "^1.0.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.0.0" + "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/core": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.22.0.tgz", - "integrity": "sha512-0VoAlT6x+Xzik1v9goJ3pZ2ppi6+xd3aUfg4brfrLkDBHRIVjMP0eBHrKrhB+NKcDyMAg8fAbGL3Npg/F6AwWA==", + "node_modules/@opentelemetry/instrumentation-restify": { + "version": "0.36.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-restify/-/instrumentation-restify-0.36.0.tgz", + "integrity": "sha512-QbOh8HpnnRn4xxFXX77Gdww6M78yx7dRiIKR6+H3j5LH5u6sYckTXw3TGPSsXsaM4DQHy0fOw15sAcJoWkC+aQ==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/semantic-conventions": "1.22.0" + "@opentelemetry/core": "^1.8.0", + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" + "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/otlp-exporter-base": { - "version": "0.49.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.49.1.tgz", - "integrity": "sha512-z6sHliPqDgJU45kQatAettY9/eVF58qVPaTuejw9YWfSRqid9pXPYeegDCSdyS47KAUgAtm+nC28K3pfF27HWg==", + "node_modules/@opentelemetry/instrumentation-router": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-router/-/instrumentation-router-0.35.0.tgz", + "integrity": "sha512-MdxGJuNTIy/2qDI8yow6cRBQ87m6O//VuHIlawe8v0x1NsTOSwS72xm+BzTuY9D0iMqiJUiTlE3dBs8DA91MTw==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.22.0" + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.0.0" + "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/otlp-transformer": { - "version": "0.49.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.49.1.tgz", - "integrity": "sha512-Z+koA4wp9L9e3jkFacyXTGphSWTbOKjwwXMpb0CxNb0kjTHGUxhYRN8GnkLFsFo5NbZPjP07hwAqeEG/uCratQ==", + "node_modules/@opentelemetry/instrumentation-socket.io": { + "version": "0.37.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-socket.io/-/instrumentation-socket.io-0.37.0.tgz", + "integrity": "sha512-aIztxmx/yis/goEndnoITrZvDDr1GdCtlsWo9ex7MhUIjqq5nJbTuyigf3GmU86XFFhSThxfQuJ9DpJyPxfBfA==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/api-logs": "0.49.1", - "@opentelemetry/core": "1.22.0", - "@opentelemetry/resources": "1.22.0", - "@opentelemetry/sdk-logs": "0.49.1", - "@opentelemetry/sdk-metrics": "1.22.0", - "@opentelemetry/sdk-trace-base": "1.22.0" + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.9.0" + "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/resources": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.22.0.tgz", - "integrity": "sha512-+vNeIFPH2hfcNL0AJk/ykJXoUCtR1YaDUZM+p3wZNU4Hq98gzq+7b43xbkXjadD9VhWIUQqEwXyY64q6msPj6A==", + "node_modules/@opentelemetry/instrumentation-tedious": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-tedious/-/instrumentation-tedious-0.8.0.tgz", + "integrity": "sha512-BBRW8+Qm2PLNkVMynr3Q7L4xCAOCOs0J9BJIJ8ZGoatW42b2H4qhMhq35jfPDvEL5u5azxHDapmUVYrDJDjAfA==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.22.0", - "@opentelemetry/semantic-conventions": "1.22.0" + "@opentelemetry/instrumentation": "^0.49.1", + "@opentelemetry/semantic-conventions": "^1.0.0", + "@types/tedious": "^4.0.10" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" + "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/sdk-logs": { - "version": "0.49.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.49.1.tgz", - "integrity": "sha512-gCzYWsJE0h+3cuh3/cK+9UwlVFyHvj3PReIOCDOmdeXOp90ZjKRoDOJBc3mvk1LL6wyl1RWIivR8Rg9OToyesw==", + "node_modules/@opentelemetry/instrumentation-winston": { + "version": "0.35.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-winston/-/instrumentation-winston-0.35.0.tgz", + "integrity": "sha512-ymcuA3S2flnLmH1GS0105H91iDLap8cizOCaLMCp7Xz7r4L+wFf1zfix9M+iSkxcPFshHRt8LFA/ELXw51nk0g==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.22.0", - "@opentelemetry/resources": "1.22.0" + "@opentelemetry/instrumentation": "^0.49.1" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": ">=1.4.0 <1.9.0", - "@opentelemetry/api-logs": ">=0.39.1" + "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/sdk-metrics": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.22.0.tgz", - "integrity": "sha512-k6iIx6H3TZ+BVMr2z8M16ri2OxWaljg5h8ihGJxi/KQWcjign6FEaEzuigXt5bK9wVEhqAcWLCfarSftaNWkkg==", + "node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.40.0.tgz", + "integrity": "sha512-AUmMUPM1/oYGbOWYRBBQz4Ic/adMYA/mIMnAy+QAEmCzjBIC/fyRReVhJmF2cpkvYh7QOkX3017zl2dgWLHpvQ==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.22.0", - "@opentelemetry/resources": "1.22.0", - "lodash.merge": "^4.6.2" + "@opentelemetry/core": "1.14.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.9.0" + "@opentelemetry/api": "^1.0.0" } }, - "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/sdk-trace-base": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.22.0.tgz", - "integrity": "sha512-pfTuSIpCKONC6vkTpv6VmACxD+P1woZf4q0K46nSUvXFvOFqjBYKFaAMkKD3M1mlKUUh0Oajwj35qNjMl80m1Q==", + "node_modules/@opentelemetry/otlp-grpc-exporter-base": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.40.0.tgz", + "integrity": "sha512-rgfyCofGMpou1OsCF1fNr/2iBzgeZj3rjplEBi0yfX6s3nNcJ6ZfhDvyblKG6dd/UydPSHYAtFAstZwwuucFJA==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.22.0", - "@opentelemetry/resources": "1.22.0", - "@opentelemetry/semantic-conventions": "1.22.0" + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "1.14.0", + "@opentelemetry/otlp-exporter-base": "0.40.0", + "protobufjs": "^7.2.2" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" - } - }, - "node_modules/@opentelemetry/exporter-trace-otlp-http/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", - "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" + "@opentelemetry/api": "^1.0.0" } }, - "node_modules/@opentelemetry/exporter-trace-otlp-proto": { + "node_modules/@opentelemetry/otlp-proto-exporter-base": { "version": "0.49.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-proto/-/exporter-trace-otlp-proto-0.49.1.tgz", - "integrity": "sha512-n8ON/c9pdMyYAfSFWKkgsPwjYoxnki+6Olzo+klKfW7KqLWoyEkryNkbcMIYnGGNXwdkMIrjoaP0VxXB26Oxcg==", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-proto-exporter-base/-/otlp-proto-exporter-base-0.49.1.tgz", + "integrity": "sha512-x1qB4EUC7KikUl2iNuxCkV8yRzrSXSyj4itfpIO674H7dhI7Zv37SFaOJTDN+8Z/F50gF2ISFH9CWQ4KCtGm2A==", "license": "Apache-2.0", "dependencies": { "@opentelemetry/core": "1.22.0", "@opentelemetry/otlp-exporter-base": "0.49.1", - "@opentelemetry/otlp-proto-exporter-base": "0.49.1", - "@opentelemetry/otlp-transformer": "0.49.1", - "@opentelemetry/resources": "1.22.0", - "@opentelemetry/sdk-trace-base": "1.22.0" + "protobufjs": "^7.2.3" }, "engines": { "node": ">=14" @@ -2113,7 +4267,7 @@ "@opentelemetry/api": "^1.0.0" } }, - "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/core": { + "node_modules/@opentelemetry/otlp-proto-exporter-base/node_modules/@opentelemetry/core": { "version": "1.22.0", "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.22.0.tgz", "integrity": "sha512-0VoAlT6x+Xzik1v9goJ3pZ2ppi6+xd3aUfg4brfrLkDBHRIVjMP0eBHrKrhB+NKcDyMAg8fAbGL3Npg/F6AwWA==", @@ -2128,7 +4282,7 @@ "@opentelemetry/api": ">=1.0.0 <1.9.0" } }, - "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/otlp-exporter-base": { + "node_modules/@opentelemetry/otlp-proto-exporter-base/node_modules/@opentelemetry/otlp-exporter-base": { "version": "0.49.1", "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.49.1.tgz", "integrity": "sha512-z6sHliPqDgJU45kQatAettY9/eVF58qVPaTuejw9YWfSRqid9pXPYeegDCSdyS47KAUgAtm+nC28K3pfF27HWg==", @@ -2143,143 +4297,138 @@ "@opentelemetry/api": "^1.0.0" } }, - "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/otlp-transformer": { - "version": "0.49.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.49.1.tgz", - "integrity": "sha512-Z+koA4wp9L9e3jkFacyXTGphSWTbOKjwwXMpb0CxNb0kjTHGUxhYRN8GnkLFsFo5NbZPjP07hwAqeEG/uCratQ==", + "node_modules/@opentelemetry/otlp-proto-exporter-base/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", + "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==", "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.49.1", - "@opentelemetry/core": "1.22.0", - "@opentelemetry/resources": "1.22.0", - "@opentelemetry/sdk-logs": "0.49.1", - "@opentelemetry/sdk-metrics": "1.22.0", - "@opentelemetry/sdk-trace-base": "1.22.0" - }, "engines": { "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.9.0" } }, - "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/resources": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.22.0.tgz", - "integrity": "sha512-+vNeIFPH2hfcNL0AJk/ykJXoUCtR1YaDUZM+p3wZNU4Hq98gzq+7b43xbkXjadD9VhWIUQqEwXyY64q6msPj6A==", + "node_modules/@opentelemetry/otlp-transformer": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.40.0.tgz", + "integrity": "sha512-YrJgVVAsJHibENSbYmC1x+5jAmkAGZ9yrgmHxc6IyqM3D1mryhqBvMRDD31JoavPYelkS7dmrXWM8g7swX0B+g==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.22.0", - "@opentelemetry/semantic-conventions": "1.22.0" + "@opentelemetry/api-logs": "0.40.0", + "@opentelemetry/core": "1.14.0", + "@opentelemetry/resources": "1.14.0", + "@opentelemetry/sdk-logs": "0.40.0", + "@opentelemetry/sdk-metrics": "1.14.0", + "@opentelemetry/sdk-trace-base": "1.14.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" + "@opentelemetry/api": ">=1.3.0 <1.5.0" } }, - "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/sdk-logs": { - "version": "0.49.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.49.1.tgz", - "integrity": "sha512-gCzYWsJE0h+3cuh3/cK+9UwlVFyHvj3PReIOCDOmdeXOp90ZjKRoDOJBc3mvk1LL6wyl1RWIivR8Rg9OToyesw==", + "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/api-logs": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.40.0.tgz", + "integrity": "sha512-8WRuvGnfnbeR9ifGjLN8kklk2fkd0gBT6aN7NHO9zeYF/6qacAViD3bwAKqGXKnJgl39l1EU41I9diqUjamEEQ==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.22.0", - "@opentelemetry/resources": "1.22.0" + "@opentelemetry/api": "^1.0.0" }, "engines": { "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.4.0 <1.9.0", - "@opentelemetry/api-logs": ">=0.39.1" } }, - "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/sdk-metrics": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.22.0.tgz", - "integrity": "sha512-k6iIx6H3TZ+BVMr2z8M16ri2OxWaljg5h8ihGJxi/KQWcjign6FEaEzuigXt5bK9wVEhqAcWLCfarSftaNWkkg==", + "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/resources": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.14.0.tgz", + "integrity": "sha512-qRfWIgBxxl3z47E036Aey0Lj2ZjlFb27Q7Xnj1y1z/P293RXJZGLtcfn/w8JF7v1Q2hs3SDGxz7Wb9Dko1YUQA==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.22.0", - "@opentelemetry/resources": "1.22.0", - "lodash.merge": "^4.6.2" + "@opentelemetry/core": "1.14.0", + "@opentelemetry/semantic-conventions": "1.14.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.9.0" + "@opentelemetry/api": ">=1.0.0 <1.5.0" } }, - "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/sdk-trace-base": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.22.0.tgz", - "integrity": "sha512-pfTuSIpCKONC6vkTpv6VmACxD+P1woZf4q0K46nSUvXFvOFqjBYKFaAMkKD3M1mlKUUh0Oajwj35qNjMl80m1Q==", + "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/sdk-metrics": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.14.0.tgz", + "integrity": "sha512-F0JXmLqT4LmsaiaE28fl0qMtc5w0YuMWTHt1hnANTNX8hxW4IKSv9+wrYG7BZd61HEbPm032Re7fXyzzNA6nIw==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.22.0", - "@opentelemetry/resources": "1.22.0", - "@opentelemetry/semantic-conventions": "1.22.0" + "@opentelemetry/core": "1.14.0", + "@opentelemetry/resources": "1.14.0", + "lodash.merge": "4.6.2" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" + "@opentelemetry/api": ">=1.3.0 <1.5.0" } }, - "node_modules/@opentelemetry/exporter-trace-otlp-proto/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", - "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==", + "node_modules/@opentelemetry/propagation-utils": { + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagation-utils/-/propagation-utils-0.30.10.tgz", + "integrity": "sha512-hhTW8pFp9PSyosYzzuUL9rdm7HF97w3OCyElufFHyUnYnKkCBbu8ne2LyF/KSdI/xZ81ubxWZs78hX4S7pLq5g==", "license": "Apache-2.0", "engines": { "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": "^1.0.0" } }, - "node_modules/@opentelemetry/exporter-zipkin": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-zipkin/-/exporter-zipkin-1.22.0.tgz", - "integrity": "sha512-XcFs6rGvcTz0qW5uY7JZDYD0yNEXdekXAb6sFtnZgY/cHY6BQ09HMzOjv9SX+iaXplRDcHr1Gta7VQKM1XXM6g==", + "node_modules/@opentelemetry/propagator-aws-xray": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-aws-xray/-/propagator-aws-xray-1.25.1.tgz", + "integrity": "sha512-soZQdO9EAROMwa9bL2C0VLadbrfRjSA9t7g6X8sL0X1B8V59pzOayYMyTW9qTECn9uuJV98A7qOnJm6KH6yk8w==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.22.0", - "@opentelemetry/resources": "1.22.0", - "@opentelemetry/sdk-trace-base": "1.22.0", - "@opentelemetry/semantic-conventions": "1.22.0" + "@opentelemetry/core": "1.25.1" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.0.0" + "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, - "node_modules/@opentelemetry/exporter-zipkin/node_modules/@opentelemetry/core": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.22.0.tgz", - "integrity": "sha512-0VoAlT6x+Xzik1v9goJ3pZ2ppi6+xd3aUfg4brfrLkDBHRIVjMP0eBHrKrhB+NKcDyMAg8fAbGL3Npg/F6AwWA==", + "node_modules/@opentelemetry/propagator-aws-xray/node_modules/@opentelemetry/core": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.25.1.tgz", + "integrity": "sha512-GeT/l6rBYWVQ4XArluLVB6WWQ8flHbdb6r2FCHC3smtdOAbrJBIv35tpV/yp9bmYUJf+xmZpu9DRTIeJVhFbEQ==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/semantic-conventions": "1.22.0" + "@opentelemetry/semantic-conventions": "1.25.1" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" + "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, - "node_modules/@opentelemetry/exporter-zipkin/node_modules/@opentelemetry/resources": { + "node_modules/@opentelemetry/propagator-aws-xray/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.1.tgz", + "integrity": "sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==", + "license": "Apache-2.0", + "engines": { + "node": ">=14" + } + }, + "node_modules/@opentelemetry/propagator-b3": { "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.22.0.tgz", - "integrity": "sha512-+vNeIFPH2hfcNL0AJk/ykJXoUCtR1YaDUZM+p3wZNU4Hq98gzq+7b43xbkXjadD9VhWIUQqEwXyY64q6msPj6A==", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-b3/-/propagator-b3-1.22.0.tgz", + "integrity": "sha512-qBItJm9ygg/jCB5rmivyGz1qmKZPsL/sX715JqPMFgq++Idm0x+N9sLQvWFHFt2+ZINnCSojw7FVBgFW6izcXA==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.22.0", - "@opentelemetry/semantic-conventions": "1.22.0" + "@opentelemetry/core": "1.22.0" }, "engines": { "node": ">=14" @@ -2288,14 +4437,12 @@ "@opentelemetry/api": ">=1.0.0 <1.9.0" } }, - "node_modules/@opentelemetry/exporter-zipkin/node_modules/@opentelemetry/sdk-trace-base": { + "node_modules/@opentelemetry/propagator-b3/node_modules/@opentelemetry/core": { "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.22.0.tgz", - "integrity": "sha512-pfTuSIpCKONC6vkTpv6VmACxD+P1woZf4q0K46nSUvXFvOFqjBYKFaAMkKD3M1mlKUUh0Oajwj35qNjMl80m1Q==", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.22.0.tgz", + "integrity": "sha512-0VoAlT6x+Xzik1v9goJ3pZ2ppi6+xd3aUfg4brfrLkDBHRIVjMP0eBHrKrhB+NKcDyMAg8fAbGL3Npg/F6AwWA==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.22.0", - "@opentelemetry/resources": "1.22.0", "@opentelemetry/semantic-conventions": "1.22.0" }, "engines": { @@ -2305,7 +4452,7 @@ "@opentelemetry/api": ">=1.0.0 <1.9.0" } }, - "node_modules/@opentelemetry/exporter-zipkin/node_modules/@opentelemetry/semantic-conventions": { + "node_modules/@opentelemetry/propagator-b3/node_modules/@opentelemetry/semantic-conventions": { "version": "1.22.0", "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==", @@ -2314,139 +4461,88 @@ "node": ">=14" } }, - "node_modules/@opentelemetry/instrumentation": { - "version": "0.49.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation/-/instrumentation-0.49.1.tgz", - "integrity": "sha512-0DLtWtaIppuNNRRllSD4bjU8ZIiLp1cDXvJEbp752/Zf+y3gaLNaoGRGIlX4UHhcsrmtL+P2qxi3Hodi8VuKiQ==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "0.49.1", - "@types/shimmer": "^1.0.2", - "import-in-the-middle": "1.7.1", - "require-in-the-middle": "^7.1.1", - "semver": "^7.5.2", - "shimmer": "^1.2.1" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" - } - }, - "node_modules/@opentelemetry/instrumentation-amqplib": { - "version": "0.35.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-amqplib/-/instrumentation-amqplib-0.35.0.tgz", - "integrity": "sha512-rb3hIWA7f0HXpXpfElnGC6CukRxy58/OJ6XYlTzpZJtNJPao7BuobZjkQEscaRYhUzgi7X7R1aKkIUOTV5JFrg==", + "node_modules/@opentelemetry/propagator-jaeger": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-jaeger/-/propagator-jaeger-1.22.0.tgz", + "integrity": "sha512-pMLgst3QIwrUfepraH5WG7xfpJ8J3CrPKrtINK0t7kBkuu96rn+HDYQ8kt3+0FXvrZI8YJE77MCQwnJWXIrgpA==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "^1.8.0", - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/semantic-conventions": "^1.0.0" + "@opentelemetry/core": "1.22.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": ">=1.0.0 <1.9.0" } }, - "node_modules/@opentelemetry/instrumentation-aws-lambda": { - "version": "0.39.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-aws-lambda/-/instrumentation-aws-lambda-0.39.0.tgz", - "integrity": "sha512-D+oG/hIBDdwCNq7Y6BEuddjcwDVD0C8NhBE7A85mRZ9RLG0bKoWrhIdVvbpqEoa0U5AWe9Y98RX4itNg7WTy4w==", + "node_modules/@opentelemetry/propagator-jaeger/node_modules/@opentelemetry/core": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.22.0.tgz", + "integrity": "sha512-0VoAlT6x+Xzik1v9goJ3pZ2ppi6+xd3aUfg4brfrLkDBHRIVjMP0eBHrKrhB+NKcDyMAg8fAbGL3Npg/F6AwWA==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/propagator-aws-xray": "^1.3.1", - "@opentelemetry/resources": "^1.8.0", - "@opentelemetry/semantic-conventions": "^1.0.0", - "@types/aws-lambda": "8.10.122" + "@opentelemetry/semantic-conventions": "1.22.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": ">=1.0.0 <1.9.0" } }, - "node_modules/@opentelemetry/instrumentation-aws-sdk": { - "version": "0.39.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-aws-sdk/-/instrumentation-aws-sdk-0.39.1.tgz", - "integrity": "sha512-QnvIMVpzRYqQHSXydGUksbhBjPbMyHSUBwi6ocN7gEXoI711+tIY3R1cfRutl0u3M67A/fAvPI3IgACfJaFORg==", + "node_modules/@opentelemetry/propagator-jaeger/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", + "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==", "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^1.8.0", - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/propagation-utils": "^0.30.7", - "@opentelemetry/semantic-conventions": "^1.0.0" - }, "engines": { "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/instrumentation-bunyan": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-bunyan/-/instrumentation-bunyan-0.36.0.tgz", - "integrity": "sha512-sHD5BSiqSrgWow7VmugEFzV8vGdsz5m+w1v9tK6YwRzuAD7vbo57chluq+UBzIqStoCH+0yOzRzSALH7hrfffg==", + "node_modules/@opentelemetry/redis-common": { + "version": "0.36.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/redis-common/-/redis-common-0.36.2.tgz", + "integrity": "sha512-faYX1N0gpLhej/6nyp6bgRjzAKXn5GOEMYY7YhciSfCoITAktLUtQ36d24QEWNA1/WA1y6qQunCe0OhHRkVl9g==", "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/api-logs": "^0.49.1", - "@opentelemetry/instrumentation": "^0.49.1", - "@types/bunyan": "1.8.9" - }, "engines": { "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/instrumentation-cassandra-driver": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-cassandra-driver/-/instrumentation-cassandra-driver-0.36.0.tgz", - "integrity": "sha512-gMfxzryOIP/mvSLXBJp/QxSr2NvS+cC1dkIXn+aSOzYoU1U3apeF3nAyuikmY9dRCQDV7wHPslqbi+pCmd4pAQ==", + "node_modules/@opentelemetry/resource-detector-alibaba-cloud": { + "version": "0.28.10", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-alibaba-cloud/-/resource-detector-alibaba-cloud-0.28.10.tgz", + "integrity": "sha512-TZv/1Y2QCL6sJ+X9SsPPBXe4786bc/Qsw0hQXFsNTbJzDTGGUmOAlSZ2qPiuqAd4ZheUYfD+QA20IvAjUz9Hhg==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/semantic-conventions": "^1.0.0" + "@opentelemetry/resources": "^1.0.0", + "@opentelemetry/semantic-conventions": "^1.22.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": "^1.0.0" } }, - "node_modules/@opentelemetry/instrumentation-connect": { - "version": "0.34.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-connect/-/instrumentation-connect-0.34.0.tgz", - "integrity": "sha512-PJO99nfyUp3JSoBMhwZsOQDm/XKfkb/QQ8YTsNX4ZJ28phoRcNLqe36mqIMp80DKmKAX4xkxCAyrSYtW8QqZxA==", + "node_modules/@opentelemetry/resource-detector-alibaba-cloud/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.1.tgz", + "integrity": "sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==", "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^1.8.0", - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/semantic-conventions": "^1.0.0", - "@types/connect": "3.4.36" - }, "engines": { "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/instrumentation-cucumber": { - "version": "0.4.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-cucumber/-/instrumentation-cucumber-0.4.0.tgz", - "integrity": "sha512-n53QvozzgMS9imEclow2nBYJ/jtZlZqiKIqDUi2/g0nDi08F555JhDS03d/Z+4NJxbu7bDLAg12giCV9KZN/Jw==", + "node_modules/@opentelemetry/resource-detector-aws": { + "version": "1.5.2", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-aws/-/resource-detector-aws-1.5.2.tgz", + "integrity": "sha512-LNwKy5vJM5fvCDcbXVKwg6Y1pKT4WgZUsddGMnWMEhxJcQVZm2Z9vUkyHdQU7xvJtGwCO2/TkMWHPjU1KQNDJQ==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/semantic-conventions": "^1.0.0" + "@opentelemetry/core": "^1.0.0", + "@opentelemetry/resources": "^1.0.0", + "@opentelemetry/semantic-conventions": "^1.22.0" }, "engines": { "node": ">=14" @@ -2455,1697 +4551,1701 @@ "@opentelemetry/api": "^1.0.0" } }, - "node_modules/@opentelemetry/instrumentation-dataloader": { - "version": "0.7.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-dataloader/-/instrumentation-dataloader-0.7.0.tgz", - "integrity": "sha512-sIaevxATJV5YaZzBTTcTaDEnI+/1vxYs+lVk1honnvrEAaP0FA9C/cFrQEN0kP2BDHkHRE/t6y5lGUqusi/h3A==", + "node_modules/@opentelemetry/resource-detector-aws/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.1.tgz", + "integrity": "sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==", "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.49.1" - }, "engines": { "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/instrumentation-dns": { - "version": "0.34.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-dns/-/instrumentation-dns-0.34.0.tgz", - "integrity": "sha512-3tmXdvrzHQ7S3v82Cm36PTYLtgg2+hVm00K1xB3uzP08GEo9w/F8DW4me9z6rDroVGiLIg621RZ6dzjBcmmFCg==", + "node_modules/@opentelemetry/resource-detector-container": { + "version": "0.3.11", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-container/-/resource-detector-container-0.3.11.tgz", + "integrity": "sha512-22ndMDakxX+nuhAYwqsciexV8/w26JozRUV0FN9kJiqSWtA1b5dCVtlp3J6JivG5t8kDN9UF5efatNnVbqRT9Q==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/semantic-conventions": "^1.0.0", - "semver": "^7.5.4" + "@opentelemetry/resources": "^1.0.0", + "@opentelemetry/semantic-conventions": "^1.22.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": "^1.0.0" } }, - "node_modules/@opentelemetry/instrumentation-express": { - "version": "0.36.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-express/-/instrumentation-express-0.36.1.tgz", - "integrity": "sha512-ltIE4kIMa+83QjW/p7oe7XCESF29w3FQ9/T1VgShdX7fzm56K2a0xfEX1vF8lnHRGERYxIWX9D086C6gJOjVGA==", + "node_modules/@opentelemetry/resource-detector-container/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.1.tgz", + "integrity": "sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==", "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^1.8.0", - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/semantic-conventions": "^1.0.0" - }, "engines": { "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/instrumentation-fastify": { - "version": "0.34.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fastify/-/instrumentation-fastify-0.34.0.tgz", - "integrity": "sha512-2Qu66XBkfJ8tr6H+RHBTyw/EX73N9U7pvNa49aonDnT9/mK58k7AKOscpRnKXOvHqc2YIdEPRcBIWxhksPFZVA==", + "node_modules/@opentelemetry/resource-detector-gcp": { + "version": "0.29.10", + "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-gcp/-/resource-detector-gcp-0.29.10.tgz", + "integrity": "sha512-rm2HKJ9lsdoVvrbmkr9dkOzg3Uk0FksXNxvNBgrCprM1XhMoJwThI5i0h/5sJypISUAJlEeJS6gn6nROj/NpkQ==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "^1.8.0", - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/semantic-conventions": "^1.0.0" + "@opentelemetry/core": "^1.0.0", + "@opentelemetry/resources": "^1.0.0", + "@opentelemetry/semantic-conventions": "^1.22.0", + "gcp-metadata": "^6.0.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": "^1.0.0" } }, - "node_modules/@opentelemetry/instrumentation-fs": { - "version": "0.10.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-fs/-/instrumentation-fs-0.10.0.tgz", - "integrity": "sha512-XtMoNINVsIQTQHjtxe7A0Lng96wxA5DSD5CYVVvpquG6HJRdZ4xNe9DTU03YtoEFqlN9qTfvGb/6ILzhKhiG8g==", + "node_modules/@opentelemetry/resource-detector-gcp/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.1.tgz", + "integrity": "sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==", "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "^1.8.0", - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/semantic-conventions": "^1.0.0" - }, "engines": { "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/instrumentation-generic-pool": { - "version": "0.34.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-generic-pool/-/instrumentation-generic-pool-0.34.0.tgz", - "integrity": "sha512-jdI7tfVVwZJuTu4j2kAvJtx4wlEQKIXSZnZG4RdqRHc56KqQQDuVTBLvUgmDXvnSVclH9ayf4oaAV08R9fICtw==", + "node_modules/@opentelemetry/resources": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.25.1.tgz", + "integrity": "sha512-pkZT+iFYIZsVn6+GzM0kSX+u3MSLCY9md+lIJOoKl/P+gJFfxJte/60Usdp8Ce4rOs8GduUpSPNe1ddGyDT1sQ==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/semantic-conventions": "^1.0.0" + "@opentelemetry/core": "1.25.1", + "@opentelemetry/semantic-conventions": "1.25.1" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, - "node_modules/@opentelemetry/instrumentation-graphql": { - "version": "0.38.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-graphql/-/instrumentation-graphql-0.38.1.tgz", - "integrity": "sha512-mSt4ztn3EVlLtZJ+tDEqq5GUEYdY8cbTT9SeVJFmXSfdSQkPZn0ovo/dRe6dUcplM60gg4w+llw8SZuQN0iZfQ==", + "node_modules/@opentelemetry/resources/node_modules/@opentelemetry/core": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.25.1.tgz", + "integrity": "sha512-GeT/l6rBYWVQ4XArluLVB6WWQ8flHbdb6r2FCHC3smtdOAbrJBIv35tpV/yp9bmYUJf+xmZpu9DRTIeJVhFbEQ==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.49.1" + "@opentelemetry/semantic-conventions": "1.25.1" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, - "node_modules/@opentelemetry/instrumentation-grpc": { - "version": "0.49.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-grpc/-/instrumentation-grpc-0.49.1.tgz", - "integrity": "sha512-f8mQjFi5/PiP4SK3VDU1/3sUUgs6exMtBgcnNycgCKgN40htiPT+MuDRwdRnRMNI/4vNQ7p1/5r4Q5oN0GuRBw==", + "node_modules/@opentelemetry/resources/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.1.tgz", + "integrity": "sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==", "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "0.49.1", - "@opentelemetry/semantic-conventions": "1.22.0" - }, "engines": { "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/instrumentation-grpc/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", - "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==", + "node_modules/@opentelemetry/sdk-logs": { + "version": "0.40.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.40.0.tgz", + "integrity": "sha512-/JG7DOLo/Y3VR9azPXlXNRGQff3gp7nQbWl5cFD2SmlYqUrzMq1OjbksZLVztDu1+ynbFunseUG11SxhoxvSRg==", "license": "Apache-2.0", + "dependencies": { + "@opentelemetry/core": "1.14.0", + "@opentelemetry/resources": "1.14.0" + }, "engines": { "node": ">=14" + }, + "peerDependencies": { + "@opentelemetry/api": ">=1.4.0 <1.5.0", + "@opentelemetry/api-logs": ">=0.39.1" } }, - "node_modules/@opentelemetry/instrumentation-hapi": { - "version": "0.35.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-hapi/-/instrumentation-hapi-0.35.0.tgz", - "integrity": "sha512-j7q99aTLHfjNKW94qJnEaDatgz+q2psTKs7lxZO4QHRnoDltDk39a44/+AkI1qBJNw5xyLjrApqkglfbWJ2abg==", + "node_modules/@opentelemetry/sdk-logs/node_modules/@opentelemetry/resources": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.14.0.tgz", + "integrity": "sha512-qRfWIgBxxl3z47E036Aey0Lj2ZjlFb27Q7Xnj1y1z/P293RXJZGLtcfn/w8JF7v1Q2hs3SDGxz7Wb9Dko1YUQA==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "^1.8.0", - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/semantic-conventions": "^1.0.0", - "@types/hapi__hapi": "20.0.13" + "@opentelemetry/core": "1.14.0", + "@opentelemetry/semantic-conventions": "1.14.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": ">=1.0.0 <1.5.0" } }, - "node_modules/@opentelemetry/instrumentation-http": { - "version": "0.49.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-http/-/instrumentation-http-0.49.1.tgz", - "integrity": "sha512-Yib5zrW2s0V8wTeUK/B3ZtpyP4ldgXj9L3Ws/axXrW1dW0/mEFKifK50MxMQK9g5NNJQS9dWH7rvcEGZdWdQDA==", + "node_modules/@opentelemetry/sdk-metrics": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.25.1.tgz", + "integrity": "sha512-9Mb7q5ioFL4E4dDrc4wC/A3NTHDat44v4I3p2pLPSxRvqUbDIQyMVr9uK+EU69+HWhlET1VaSrRzwdckWqY15Q==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.22.0", - "@opentelemetry/instrumentation": "0.49.1", - "@opentelemetry/semantic-conventions": "1.22.0", - "semver": "^7.5.2" + "@opentelemetry/core": "1.25.1", + "@opentelemetry/resources": "1.25.1", + "lodash.merge": "^4.6.2" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": ">=1.3.0 <1.10.0" } }, - "node_modules/@opentelemetry/instrumentation-http/node_modules/@opentelemetry/core": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.22.0.tgz", - "integrity": "sha512-0VoAlT6x+Xzik1v9goJ3pZ2ppi6+xd3aUfg4brfrLkDBHRIVjMP0eBHrKrhB+NKcDyMAg8fAbGL3Npg/F6AwWA==", + "node_modules/@opentelemetry/sdk-metrics/node_modules/@opentelemetry/core": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.25.1.tgz", + "integrity": "sha512-GeT/l6rBYWVQ4XArluLVB6WWQ8flHbdb6r2FCHC3smtdOAbrJBIv35tpV/yp9bmYUJf+xmZpu9DRTIeJVhFbEQ==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/semantic-conventions": "1.22.0" + "@opentelemetry/semantic-conventions": "1.25.1" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" + "@opentelemetry/api": ">=1.0.0 <1.10.0" } }, - "node_modules/@opentelemetry/instrumentation-http/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", - "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==", + "node_modules/@opentelemetry/sdk-metrics/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.25.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.1.tgz", + "integrity": "sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==", "license": "Apache-2.0", "engines": { "node": ">=14" } }, - "node_modules/@opentelemetry/instrumentation-ioredis": { - "version": "0.38.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-ioredis/-/instrumentation-ioredis-0.38.0.tgz", - "integrity": "sha512-c9nQFhRjFAtpInTks7z5v9CiOCiR8U9GbIhIv0TLEJ/r0wqdKNLfLZzCrr9XQ9WasxeOmziLlPFhpRBAd9Q4oA==", + "node_modules/@opentelemetry/sdk-node": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-node/-/sdk-node-0.49.1.tgz", + "integrity": "sha512-feBIT85ndiSHXsQ2gfGpXC/sNeX4GCHLksC4A9s/bfpUbbgbCSl0RvzZlmEpCHarNrkZMwFRi4H0xFfgvJEjrg==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/redis-common": "^0.36.1", - "@opentelemetry/semantic-conventions": "^1.0.0", - "@types/ioredis4": "npm:@types/ioredis@^4.28.10" + "@opentelemetry/api-logs": "0.49.1", + "@opentelemetry/core": "1.22.0", + "@opentelemetry/exporter-trace-otlp-grpc": "0.49.1", + "@opentelemetry/exporter-trace-otlp-http": "0.49.1", + "@opentelemetry/exporter-trace-otlp-proto": "0.49.1", + "@opentelemetry/exporter-zipkin": "1.22.0", + "@opentelemetry/instrumentation": "0.49.1", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/sdk-logs": "0.49.1", + "@opentelemetry/sdk-metrics": "1.22.0", + "@opentelemetry/sdk-trace-base": "1.22.0", + "@opentelemetry/sdk-trace-node": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": ">=1.3.0 <1.9.0" } }, - "node_modules/@opentelemetry/instrumentation-knex": { - "version": "0.34.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-knex/-/instrumentation-knex-0.34.0.tgz", - "integrity": "sha512-6kZOEvNJOylTQunU5zSSi4iTuCkwIL9nwFnZg7719p61u3d6Qj3X4xi9su46VE3M0dH7vEoxUW+nb/0ilm+aZg==", + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/core": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.22.0.tgz", + "integrity": "sha512-0VoAlT6x+Xzik1v9goJ3pZ2ppi6+xd3aUfg4brfrLkDBHRIVjMP0eBHrKrhB+NKcDyMAg8fAbGL3Npg/F6AwWA==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/semantic-conventions": "^1.0.0" + "@opentelemetry/semantic-conventions": "1.22.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": ">=1.0.0 <1.9.0" } }, - "node_modules/@opentelemetry/instrumentation-koa": { - "version": "0.38.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-koa/-/instrumentation-koa-0.38.0.tgz", - "integrity": "sha512-lQujF4I3wdcrOF14miCV2pC72H+OJKb2LrrmTvTDAhELQDN/95v0doWgT9aHybUGkaAeB3QG4d09sved548TlA==", + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/exporter-trace-otlp-grpc": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.49.1.tgz", + "integrity": "sha512-Zbd7f3zF7fI2587MVhBizaW21cO/SordyrZGtMtvhoxU6n4Qb02Gx71X4+PzXH620e0+JX+Pcr9bYb1HTeVyJA==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "^1.8.0", - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/semantic-conventions": "^1.0.0", - "@types/koa": "2.14.0", - "@types/koa__router": "12.0.3" + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "1.22.0", + "@opentelemetry/otlp-grpc-exporter-base": "0.49.1", + "@opentelemetry/otlp-transformer": "0.49.1", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/sdk-trace-base": "1.22.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": "^1.0.0" } }, - "node_modules/@opentelemetry/instrumentation-lru-memoizer": { - "version": "0.35.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-lru-memoizer/-/instrumentation-lru-memoizer-0.35.0.tgz", - "integrity": "sha512-wCXe+iCF7JweMgY3blLM2Y1G0GSwLEeSA61z/y1UwzvBLEEXt7vL6qOl2mkNcUL9ZbLDS+EABatBH+vFO6DV5Q==", + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/otlp-exporter-base": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.49.1.tgz", + "integrity": "sha512-z6sHliPqDgJU45kQatAettY9/eVF58qVPaTuejw9YWfSRqid9pXPYeegDCSdyS47KAUgAtm+nC28K3pfF27HWg==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.49.1" + "@opentelemetry/core": "1.22.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": "^1.0.0" } }, - "node_modules/@opentelemetry/instrumentation-memcached": { - "version": "0.34.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-memcached/-/instrumentation-memcached-0.34.0.tgz", - "integrity": "sha512-RleFfaag3Evg4pTzHwDBwo1KiFgnCtiT4V6MQRRHadytNGdpcL+Ynz32ydDdiOXeadt7xpRI7HSvBy0quGTXSw==", + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/otlp-grpc-exporter-base": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.49.1.tgz", + "integrity": "sha512-DNDNUWmOqtKTFJAyOyHHKotVox0NQ/09ETX8fUOeEtyNVHoGekAVtBbvIA3AtK+JflP7LC0PTjlLfruPM3Wy6w==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/semantic-conventions": "^1.0.0", - "@types/memcached": "^2.2.6" + "@grpc/grpc-js": "^1.7.1", + "@opentelemetry/core": "1.22.0", + "@opentelemetry/otlp-exporter-base": "0.49.1", + "protobufjs": "^7.2.3" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": "^1.0.0" } }, - "node_modules/@opentelemetry/instrumentation-mongodb": { - "version": "0.41.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongodb/-/instrumentation-mongodb-0.41.0.tgz", - "integrity": "sha512-DlSH0oyEuTW5gprCUppb0Qe3pK3cpUUFW5eTmayWNyICI1LFunwtcrULTNv6UiThD/V5ykAf/GGGEa7KFAmkog==", + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/otlp-transformer": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.49.1.tgz", + "integrity": "sha512-Z+koA4wp9L9e3jkFacyXTGphSWTbOKjwwXMpb0CxNb0kjTHGUxhYRN8GnkLFsFo5NbZPjP07hwAqeEG/uCratQ==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/sdk-metrics": "^1.9.1", - "@opentelemetry/semantic-conventions": "^1.0.0" + "@opentelemetry/api-logs": "0.49.1", + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/sdk-logs": "0.49.1", + "@opentelemetry/sdk-metrics": "1.22.0", + "@opentelemetry/sdk-trace-base": "1.22.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": ">=1.3.0 <1.9.0" } }, - "node_modules/@opentelemetry/instrumentation-mongoose": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mongoose/-/instrumentation-mongoose-0.36.0.tgz", - "integrity": "sha512-UelQ8dLQRLTdck3tPJdZ17b+Hk9usLf1cY2ou5THAaZpulUdpg62Q9Hx2RHRU71Rp2/YMDk25og7GJhuWScfEA==", + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/resources": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.22.0.tgz", + "integrity": "sha512-+vNeIFPH2hfcNL0AJk/ykJXoUCtR1YaDUZM+p3wZNU4Hq98gzq+7b43xbkXjadD9VhWIUQqEwXyY64q6msPj6A==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "^1.8.0", - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/semantic-conventions": "^1.0.0" + "@opentelemetry/core": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": ">=1.0.0 <1.9.0" } }, - "node_modules/@opentelemetry/instrumentation-mysql": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql/-/instrumentation-mysql-0.36.0.tgz", - "integrity": "sha512-2mt/032SLkiuddzMrq3YwM0bHksXRep69EzGRnBfF+bCbwYvKLpqmSFqJZ9T3yY/mBWj+tvdvc1+klXGrh2QnQ==", + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/sdk-logs": { + "version": "0.49.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.49.1.tgz", + "integrity": "sha512-gCzYWsJE0h+3cuh3/cK+9UwlVFyHvj3PReIOCDOmdeXOp90ZjKRoDOJBc3mvk1LL6wyl1RWIivR8Rg9OToyesw==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/semantic-conventions": "^1.0.0", - "@types/mysql": "2.15.22" + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": ">=1.4.0 <1.9.0", + "@opentelemetry/api-logs": ">=0.39.1" } }, - "node_modules/@opentelemetry/instrumentation-mysql2": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-mysql2/-/instrumentation-mysql2-0.36.0.tgz", - "integrity": "sha512-F63lKcl/R+if2j5Vz66c2/SLXQEtLlFkWTmYb8NQSgmcCaEKjML4RRRjZISIT4IBwdpanJ2qmNuXVM6MYqhBXw==", + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/sdk-metrics": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.22.0.tgz", + "integrity": "sha512-k6iIx6H3TZ+BVMr2z8M16ri2OxWaljg5h8ihGJxi/KQWcjign6FEaEzuigXt5bK9wVEhqAcWLCfarSftaNWkkg==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/semantic-conventions": "^1.0.0", - "@opentelemetry/sql-common": "^0.40.0" + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "lodash.merge": "^4.6.2" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": ">=1.3.0 <1.9.0" } }, - "node_modules/@opentelemetry/instrumentation-nestjs-core": { - "version": "0.35.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-nestjs-core/-/instrumentation-nestjs-core-0.35.0.tgz", - "integrity": "sha512-INKA7CIOteTSRVxP7SQaFby11AYU3uezI93xDaDRGY4TloXNVoyw5n6UmcVJU4yDn6xY2r7zZ2SVHvblUc21/g==", + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/sdk-trace-base": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.22.0.tgz", + "integrity": "sha512-pfTuSIpCKONC6vkTpv6VmACxD+P1woZf4q0K46nSUvXFvOFqjBYKFaAMkKD3M1mlKUUh0Oajwj35qNjMl80m1Q==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/semantic-conventions": "^1.0.0" + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": ">=1.0.0 <1.9.0" } }, - "node_modules/@opentelemetry/instrumentation-net": { - "version": "0.34.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-net/-/instrumentation-net-0.34.0.tgz", - "integrity": "sha512-gjybNOQQqbXmD1qVHNO2qBJI4V6p3QQ7xKg3pnC/x7wRdxn+siLQj7QIVxW85C3mymngoJJdRs6BwI3qPUfsPQ==", + "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", + "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==", "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/semantic-conventions": "^1.0.0" - }, "engines": { "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/instrumentation-pg": { - "version": "0.39.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pg/-/instrumentation-pg-0.39.1.tgz", - "integrity": "sha512-pX5ujDOyGpPcrZlzaD3LJzmyaSMMMKAP+ffTHJp9vasvZJr+LifCk53TMPVUafcXKV/xX/IIkvADO+67M1Z25g==", + "node_modules/@opentelemetry/sdk-trace-base": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.14.0.tgz", + "integrity": "sha512-NzRGt3PS+HPKfQYMb6Iy8YYc5OKA73qDwci/6ujOIvyW9vcqBJSWbjZ8FeLEAmuatUB5WrRhEKu9b0sIiIYTrQ==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/semantic-conventions": "^1.0.0", - "@opentelemetry/sql-common": "^0.40.0", - "@types/pg": "8.6.1", - "@types/pg-pool": "2.0.4" + "@opentelemetry/core": "1.14.0", + "@opentelemetry/resources": "1.14.0", + "@opentelemetry/semantic-conventions": "1.14.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": ">=1.0.0 <1.5.0" } }, - "node_modules/@opentelemetry/instrumentation-pino": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-pino/-/instrumentation-pino-0.36.0.tgz", - "integrity": "sha512-oEz+BJEYRBMAUu7MVJFJhhlsBuwLaUGjbJciKZRIeGX+fUtgcbQGV+a2Ris9jR3yFzWZrYg0aNBSCbGqvPCtMQ==", + "node_modules/@opentelemetry/sdk-trace-base/node_modules/@opentelemetry/resources": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.14.0.tgz", + "integrity": "sha512-qRfWIgBxxl3z47E036Aey0Lj2ZjlFb27Q7Xnj1y1z/P293RXJZGLtcfn/w8JF7v1Q2hs3SDGxz7Wb9Dko1YUQA==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.49.1" + "@opentelemetry/core": "1.14.0", + "@opentelemetry/semantic-conventions": "1.14.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": ">=1.0.0 <1.5.0" } }, - "node_modules/@opentelemetry/instrumentation-redis": { - "version": "0.37.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis/-/instrumentation-redis-0.37.0.tgz", - "integrity": "sha512-9G0T74kheu37k+UvyBnAcieB5iowxska3z2rhUcSTL8Cl0y/CvMn7sZ7txkUbXt0rdX6qeEUdMLmbsY2fPUM7Q==", + "node_modules/@opentelemetry/sdk-trace-node": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-1.22.0.tgz", + "integrity": "sha512-gTGquNz7ue8uMeiWPwp3CU321OstQ84r7PCDtOaCicjbJxzvO8RZMlEC4geOipTeiF88kss5n6w+//A0MhP1lQ==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/redis-common": "^0.36.1", - "@opentelemetry/semantic-conventions": "^1.0.0" + "@opentelemetry/context-async-hooks": "1.22.0", + "@opentelemetry/core": "1.22.0", + "@opentelemetry/propagator-b3": "1.22.0", + "@opentelemetry/propagator-jaeger": "1.22.0", + "@opentelemetry/sdk-trace-base": "1.22.0", + "semver": "^7.5.2" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": ">=1.0.0 <1.9.0" } }, - "node_modules/@opentelemetry/instrumentation-redis-4": { - "version": "0.37.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-redis-4/-/instrumentation-redis-4-0.37.0.tgz", - "integrity": "sha512-WNO+HALvPPvjbh7UEEIuay0Z0d2mIfSCkBZbPRwZttDGX6LYGc2WnRgJh3TnYqjp7/y9IryWIbajAFIebj1OBA==", + "node_modules/@opentelemetry/sdk-trace-node/node_modules/@opentelemetry/core": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.22.0.tgz", + "integrity": "sha512-0VoAlT6x+Xzik1v9goJ3pZ2ppi6+xd3aUfg4brfrLkDBHRIVjMP0eBHrKrhB+NKcDyMAg8fAbGL3Npg/F6AwWA==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/redis-common": "^0.36.1", - "@opentelemetry/semantic-conventions": "^1.0.0" + "@opentelemetry/semantic-conventions": "1.22.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": ">=1.0.0 <1.9.0" } }, - "node_modules/@opentelemetry/instrumentation-restify": { - "version": "0.36.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-restify/-/instrumentation-restify-0.36.0.tgz", - "integrity": "sha512-QbOh8HpnnRn4xxFXX77Gdww6M78yx7dRiIKR6+H3j5LH5u6sYckTXw3TGPSsXsaM4DQHy0fOw15sAcJoWkC+aQ==", + "node_modules/@opentelemetry/sdk-trace-node/node_modules/@opentelemetry/resources": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.22.0.tgz", + "integrity": "sha512-+vNeIFPH2hfcNL0AJk/ykJXoUCtR1YaDUZM+p3wZNU4Hq98gzq+7b43xbkXjadD9VhWIUQqEwXyY64q6msPj6A==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "^1.8.0", - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/semantic-conventions": "^1.0.0" + "@opentelemetry/core": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": ">=1.0.0 <1.9.0" } }, - "node_modules/@opentelemetry/instrumentation-router": { - "version": "0.35.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-router/-/instrumentation-router-0.35.0.tgz", - "integrity": "sha512-MdxGJuNTIy/2qDI8yow6cRBQ87m6O//VuHIlawe8v0x1NsTOSwS72xm+BzTuY9D0iMqiJUiTlE3dBs8DA91MTw==", + "node_modules/@opentelemetry/sdk-trace-node/node_modules/@opentelemetry/sdk-trace-base": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.22.0.tgz", + "integrity": "sha512-pfTuSIpCKONC6vkTpv6VmACxD+P1woZf4q0K46nSUvXFvOFqjBYKFaAMkKD3M1mlKUUh0Oajwj35qNjMl80m1Q==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/semantic-conventions": "^1.0.0" + "@opentelemetry/core": "1.22.0", + "@opentelemetry/resources": "1.22.0", + "@opentelemetry/semantic-conventions": "1.22.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": ">=1.0.0 <1.9.0" } }, - "node_modules/@opentelemetry/instrumentation-socket.io": { - "version": "0.37.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-socket.io/-/instrumentation-socket.io-0.37.0.tgz", - "integrity": "sha512-aIztxmx/yis/goEndnoITrZvDDr1GdCtlsWo9ex7MhUIjqq5nJbTuyigf3GmU86XFFhSThxfQuJ9DpJyPxfBfA==", + "node_modules/@opentelemetry/sdk-trace-node/node_modules/@opentelemetry/semantic-conventions": { + "version": "1.22.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", + "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==", "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/semantic-conventions": "^1.0.0" - }, "engines": { "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/instrumentation-tedious": { - "version": "0.8.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-tedious/-/instrumentation-tedious-0.8.0.tgz", - "integrity": "sha512-BBRW8+Qm2PLNkVMynr3Q7L4xCAOCOs0J9BJIJ8ZGoatW42b2H4qhMhq35jfPDvEL5u5azxHDapmUVYrDJDjAfA==", + "node_modules/@opentelemetry/semantic-conventions": { + "version": "1.14.0", + "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.14.0.tgz", + "integrity": "sha512-rJfCY8rCWz3cb4KI6pEofnytvMPuj3YLQwoscCCYZ5DkdiPjo15IQ0US7+mjcWy9H3fcZIzf2pbJZ7ck/h4tug==", "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/instrumentation": "^0.49.1", - "@opentelemetry/semantic-conventions": "^1.0.0", - "@types/tedious": "^4.0.10" - }, "engines": { "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.3.0" } }, - "node_modules/@opentelemetry/instrumentation-winston": { - "version": "0.35.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/instrumentation-winston/-/instrumentation-winston-0.35.0.tgz", - "integrity": "sha512-ymcuA3S2flnLmH1GS0105H91iDLap8cizOCaLMCp7Xz7r4L+wFf1zfix9M+iSkxcPFshHRt8LFA/ELXw51nk0g==", + "node_modules/@opentelemetry/sql-common": { + "version": "0.40.1", + "resolved": "https://registry.npmjs.org/@opentelemetry/sql-common/-/sql-common-0.40.1.tgz", + "integrity": "sha512-nSDlnHSqzC3pXn/wZEZVLuAuJ1MYMXPBwtv2qAbCa3847SaHItdE7SzUq/Jtb0KZmh1zfAbNi3AAMjztTT4Ugg==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/instrumentation": "^0.49.1" + "@opentelemetry/core": "^1.1.0" }, "engines": { "node": ">=14" }, "peerDependencies": { - "@opentelemetry/api": "^1.3.0" + "@opentelemetry/api": "^1.1.0" } }, - "node_modules/@opentelemetry/otlp-exporter-base": { - "version": "0.40.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.40.0.tgz", - "integrity": "sha512-AUmMUPM1/oYGbOWYRBBQz4Ic/adMYA/mIMnAy+QAEmCzjBIC/fyRReVhJmF2cpkvYh7QOkX3017zl2dgWLHpvQ==", + "node_modules/@pagerduty/pdjs": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/@pagerduty/pdjs/-/pdjs-2.2.4.tgz", + "integrity": "sha512-MMZvxos7PJnGJ8z3ijsu/gsMQLIfO8peeigKCjUDmviXk8FIaZZjX0X889NIKuFDhGirYbJVwGTaDYCEw4baLg==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.14.0" + "browser-or-node": "^2.0.0", + "cross-fetch": "^3.0.6" }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "license": "MIT", "engines": { "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" } }, - "node_modules/@opentelemetry/otlp-grpc-exporter-base": { - "version": "0.40.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.40.0.tgz", - "integrity": "sha512-rgfyCofGMpou1OsCF1fNr/2iBzgeZj3rjplEBi0yfX6s3nNcJ6ZfhDvyblKG6dd/UydPSHYAtFAstZwwuucFJA==", - "license": "Apache-2.0", + "node_modules/@protobufjs/aspromise": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", + "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/base64": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", + "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/codegen": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", + "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/eventemitter": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", + "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/fetch": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", + "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", + "license": "BSD-3-Clause", + "dependencies": { + "@protobufjs/aspromise": "^1.1.1", + "@protobufjs/inquire": "^1.1.0" + } + }, + "node_modules/@protobufjs/float": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", + "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/inquire": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", + "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/path": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", + "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/pool": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", + "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", + "license": "BSD-3-Clause" + }, + "node_modules/@protobufjs/utf8": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", + "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", + "license": "BSD-3-Clause" + }, + "node_modules/@rollup/plugin-commonjs": { + "version": "24.1.0", + "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-24.1.0.tgz", + "integrity": "sha512-eSL45hjhCWI0jCCXcNtLVqM5N1JlBGvlFfY0m6oOYnLCJ6N0qEXoZql4sY2MOUArzhH4SA/qBpTxvvZp2Sc+DQ==", + "dev": true, + "license": "MIT", "dependencies": { - "@grpc/grpc-js": "^1.7.1", - "@opentelemetry/core": "1.14.0", - "@opentelemetry/otlp-exporter-base": "0.40.0", - "protobufjs": "^7.2.2" + "@rollup/pluginutils": "^5.0.1", + "commondir": "^1.0.1", + "estree-walker": "^2.0.2", + "glob": "^8.0.3", + "is-reference": "1.2.1", + "magic-string": "^0.27.0" }, "engines": { - "node": ">=14" + "node": ">=14.0.0" }, "peerDependencies": { - "@opentelemetry/api": "^1.0.0" - } - }, - "node_modules/@opentelemetry/otlp-proto-exporter-base": { - "version": "0.49.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-proto-exporter-base/-/otlp-proto-exporter-base-0.49.1.tgz", - "integrity": "sha512-x1qB4EUC7KikUl2iNuxCkV8yRzrSXSyj4itfpIO674H7dhI7Zv37SFaOJTDN+8Z/F50gF2ISFH9CWQ4KCtGm2A==", - "license": "Apache-2.0", - "dependencies": { - "@opentelemetry/core": "1.22.0", - "@opentelemetry/otlp-exporter-base": "0.49.1", - "protobufjs": "^7.2.3" - }, - "engines": { - "node": ">=14" + "rollup": "^2.68.0||^3.0.0" }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/@opentelemetry/otlp-proto-exporter-base/node_modules/@opentelemetry/core": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.22.0.tgz", - "integrity": "sha512-0VoAlT6x+Xzik1v9goJ3pZ2ppi6+xd3aUfg4brfrLkDBHRIVjMP0eBHrKrhB+NKcDyMAg8fAbGL3Npg/F6AwWA==", - "license": "Apache-2.0", + "node_modules/@rollup/plugin-node-resolve": { + "version": "15.2.3", + "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", + "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==", + "dev": true, + "license": "MIT", "dependencies": { - "@opentelemetry/semantic-conventions": "1.22.0" + "@rollup/pluginutils": "^5.0.1", + "@types/resolve": "1.20.2", + "deepmerge": "^4.2.2", + "is-builtin-module": "^3.2.1", + "is-module": "^1.0.0", + "resolve": "^1.22.1" }, "engines": { - "node": ">=14" + "node": ">=14.0.0" }, "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" + "rollup": "^2.78.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/@opentelemetry/otlp-proto-exporter-base/node_modules/@opentelemetry/otlp-exporter-base": { - "version": "0.49.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.49.1.tgz", - "integrity": "sha512-z6sHliPqDgJU45kQatAettY9/eVF58qVPaTuejw9YWfSRqid9pXPYeegDCSdyS47KAUgAtm+nC28K3pfF27HWg==", - "license": "Apache-2.0", + "node_modules/@rollup/plugin-replace": { + "version": "5.0.7", + "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.7.tgz", + "integrity": "sha512-PqxSfuorkHz/SPpyngLyg5GCEkOcee9M1bkxiVDr41Pd61mqP1PLOoDPbpl44SB2mQGKwV/In74gqQmGITOhEQ==", + "dev": true, + "license": "MIT", "dependencies": { - "@opentelemetry/core": "1.22.0" + "@rollup/pluginutils": "^5.0.1", + "magic-string": "^0.30.3" }, "engines": { - "node": ">=14" + "node": ">=14.0.0" }, "peerDependencies": { - "@opentelemetry/api": "^1.0.0" + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/@opentelemetry/otlp-proto-exporter-base/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", - "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" + "node_modules/@rollup/plugin-replace/node_modules/magic-string": { + "version": "0.30.10", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", + "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" } }, - "node_modules/@opentelemetry/otlp-transformer": { - "version": "0.40.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.40.0.tgz", - "integrity": "sha512-YrJgVVAsJHibENSbYmC1x+5jAmkAGZ9yrgmHxc6IyqM3D1mryhqBvMRDD31JoavPYelkS7dmrXWM8g7swX0B+g==", - "license": "Apache-2.0", + "node_modules/@rollup/pluginutils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", + "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", + "dev": true, + "license": "MIT", "dependencies": { - "@opentelemetry/api-logs": "0.40.0", - "@opentelemetry/core": "1.14.0", - "@opentelemetry/resources": "1.14.0", - "@opentelemetry/sdk-logs": "0.40.0", - "@opentelemetry/sdk-metrics": "1.14.0", - "@opentelemetry/sdk-trace-base": "1.14.0" + "@types/estree": "^1.0.0", + "estree-walker": "^2.0.2", + "picomatch": "^2.3.1" }, "engines": { - "node": ">=14" + "node": ">=14.0.0" }, "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.5.0" + "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + }, + "peerDependenciesMeta": { + "rollup": { + "optional": true + } } }, - "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/api-logs": { - "version": "0.40.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/api-logs/-/api-logs-0.40.0.tgz", - "integrity": "sha512-8WRuvGnfnbeR9ifGjLN8kklk2fkd0gBT6aN7NHO9zeYF/6qacAViD3bwAKqGXKnJgl39l1EU41I9diqUjamEEQ==", - "license": "Apache-2.0", + "node_modules/@sideway/address": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", + "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", + "license": "BSD-3-Clause", "dependencies": { - "@opentelemetry/api": "^1.0.0" - }, - "engines": { - "node": ">=14" + "@hapi/hoek": "^9.0.0" } }, - "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/resources": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.14.0.tgz", - "integrity": "sha512-qRfWIgBxxl3z47E036Aey0Lj2ZjlFb27Q7Xnj1y1z/P293RXJZGLtcfn/w8JF7v1Q2hs3SDGxz7Wb9Dko1YUQA==", - "license": "Apache-2.0", + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "license": "BSD-3-Clause" + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "license": "BSD-3-Clause" + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", + "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", + "license": "BSD-3-Clause", "dependencies": { - "@opentelemetry/core": "1.14.0", - "@opentelemetry/semantic-conventions": "1.14.0" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.5.0" + "type-detect": "4.0.8" } }, - "node_modules/@opentelemetry/otlp-transformer/node_modules/@opentelemetry/sdk-metrics": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.14.0.tgz", - "integrity": "sha512-F0JXmLqT4LmsaiaE28fl0qMtc5w0YuMWTHt1hnANTNX8hxW4IKSv9+wrYG7BZd61HEbPm032Re7fXyzzNA6nIw==", - "license": "Apache-2.0", + "node_modules/@sinonjs/fake-timers": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", + "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", + "license": "BSD-3-Clause", "dependencies": { - "@opentelemetry/core": "1.14.0", - "@opentelemetry/resources": "1.14.0", - "lodash.merge": "4.6.2" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.5.0" + "@sinonjs/commons": "^3.0.0" } }, - "node_modules/@opentelemetry/propagation-utils": { - "version": "0.30.10", - "resolved": "https://registry.npmjs.org/@opentelemetry/propagation-utils/-/propagation-utils-0.30.10.tgz", - "integrity": "sha512-hhTW8pFp9PSyosYzzuUL9rdm7HF97w3OCyElufFHyUnYnKkCBbu8ne2LyF/KSdI/xZ81ubxWZs78hX4S7pLq5g==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" + "node_modules/@sinonjs/samsam": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", + "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", + "license": "BSD-3-Clause", + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" } }, - "node_modules/@opentelemetry/propagator-aws-xray": { - "version": "1.25.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-aws-xray/-/propagator-aws-xray-1.25.1.tgz", - "integrity": "sha512-soZQdO9EAROMwa9bL2C0VLadbrfRjSA9t7g6X8sL0X1B8V59pzOayYMyTW9qTECn9uuJV98A7qOnJm6KH6yk8w==", - "license": "Apache-2.0", + "node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "license": "BSD-3-Clause", "dependencies": { - "@opentelemetry/core": "1.25.1" - }, - "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" + "type-detect": "4.0.8" } }, - "node_modules/@opentelemetry/propagator-aws-xray/node_modules/@opentelemetry/core": { - "version": "1.25.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.25.1.tgz", - "integrity": "sha512-GeT/l6rBYWVQ4XArluLVB6WWQ8flHbdb6r2FCHC3smtdOAbrJBIv35tpV/yp9bmYUJf+xmZpu9DRTIeJVhFbEQ==", + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", + "license": "(Unlicense OR Apache-2.0)" + }, + "node_modules/@smithy/abort-controller": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.2.0.tgz", + "integrity": "sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/semantic-conventions": "1.25.1" + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" + "node": ">=14.0.0" } }, - "node_modules/@opentelemetry/propagator-aws-xray/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.25.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.1.tgz", - "integrity": "sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==", - "license": "Apache-2.0", + "node_modules/@smithy/config-resolver": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@smithy/config-resolver/-/config-resolver-3.0.5.tgz", + "integrity": "sha512-SkW5LxfkSI1bUC74OtfBbdz+grQXYiPYolyu8VfpLIjEoN/sHVBlLeGXMQ1vX4ejkgfv6sxVbQJ32yF2cl1veA==", + "dependencies": { + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/util-config-provider": "^3.0.0", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=14" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/propagator-b3": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-b3/-/propagator-b3-1.22.0.tgz", - "integrity": "sha512-qBItJm9ygg/jCB5rmivyGz1qmKZPsL/sX715JqPMFgq++Idm0x+N9sLQvWFHFt2+ZINnCSojw7FVBgFW6izcXA==", - "license": "Apache-2.0", + "node_modules/@smithy/config-resolver/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@opentelemetry/core": "1.22.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/core": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.1.tgz", + "integrity": "sha512-BC7VMXx/1BCmRPCVzzn4HGWAtsrb7/0758EtwOGFJQrlSwJBEjCcDLNZLFoL/68JexYa2s+KmgL/UfmXdG6v1w==", + "dependencies": { + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/propagator-b3/node_modules/@opentelemetry/core": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.22.0.tgz", - "integrity": "sha512-0VoAlT6x+Xzik1v9goJ3pZ2ppi6+xd3aUfg4brfrLkDBHRIVjMP0eBHrKrhB+NKcDyMAg8fAbGL3Npg/F6AwWA==", - "license": "Apache-2.0", + "node_modules/@smithy/core/node_modules/@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", "dependencies": { - "@opentelemetry/semantic-conventions": "1.22.0" + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/propagator-b3/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", - "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==", - "license": "Apache-2.0", + "node_modules/@smithy/core/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "dependencies": { + "tslib": "^2.6.2" + }, "engines": { - "node": ">=14" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/propagator-jaeger": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/propagator-jaeger/-/propagator-jaeger-1.22.0.tgz", - "integrity": "sha512-pMLgst3QIwrUfepraH5WG7xfpJ8J3CrPKrtINK0t7kBkuu96rn+HDYQ8kt3+0FXvrZI8YJE77MCQwnJWXIrgpA==", - "license": "Apache-2.0", + "node_modules/@smithy/credential-provider-imds": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/@smithy/credential-provider-imds/-/credential-provider-imds-3.2.0.tgz", + "integrity": "sha512-0SCIzgd8LYZ9EJxUjLXBmEKSZR/P/w6l7Rz/pab9culE/RWuqelAKGJvn5qUOl8BgX8Yj5HWM50A5hiB/RzsgA==", "dependencies": { - "@opentelemetry/core": "1.22.0" + "@smithy/node-config-provider": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/propagator-jaeger/node_modules/@opentelemetry/core": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.22.0.tgz", - "integrity": "sha512-0VoAlT6x+Xzik1v9goJ3pZ2ppi6+xd3aUfg4brfrLkDBHRIVjMP0eBHrKrhB+NKcDyMAg8fAbGL3Npg/F6AwWA==", - "license": "Apache-2.0", + "node_modules/@smithy/credential-provider-imds/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@opentelemetry/semantic-conventions": "1.22.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/propagator-jaeger/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", - "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" + "node_modules/@smithy/fetch-http-handler": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/@smithy/fetch-http-handler/-/fetch-http-handler-3.2.4.tgz", + "integrity": "sha512-kBprh5Gs5h7ug4nBWZi1FZthdqSM+T7zMmsZxx0IBvWUn7dK3diz2SHn7Bs4dQGFDk8plDv375gzenDoNwrXjg==", + "dependencies": { + "@smithy/protocol-http": "^4.1.0", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "@smithy/util-base64": "^3.0.0", + "tslib": "^2.6.2" } }, - "node_modules/@opentelemetry/redis-common": { - "version": "0.36.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/redis-common/-/redis-common-0.36.2.tgz", - "integrity": "sha512-faYX1N0gpLhej/6nyp6bgRjzAKXn5GOEMYY7YhciSfCoITAktLUtQ36d24QEWNA1/WA1y6qQunCe0OhHRkVl9g==", - "license": "Apache-2.0", + "node_modules/@smithy/fetch-http-handler/node_modules/@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=14" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/resource-detector-alibaba-cloud": { - "version": "0.28.10", - "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-alibaba-cloud/-/resource-detector-alibaba-cloud-0.28.10.tgz", - "integrity": "sha512-TZv/1Y2QCL6sJ+X9SsPPBXe4786bc/Qsw0hQXFsNTbJzDTGGUmOAlSZ2qPiuqAd4ZheUYfD+QA20IvAjUz9Hhg==", - "license": "Apache-2.0", + "node_modules/@smithy/fetch-http-handler/node_modules/@smithy/querystring-builder": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", + "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", "dependencies": { - "@opentelemetry/resources": "^1.0.0", - "@opentelemetry/semantic-conventions": "^1.22.0" + "@smithy/types": "^3.3.0", + "@smithy/util-uri-escape": "^3.0.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/resource-detector-alibaba-cloud/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.25.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.1.tgz", - "integrity": "sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==", - "license": "Apache-2.0", + "node_modules/@smithy/fetch-http-handler/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "dependencies": { + "tslib": "^2.6.2" + }, "engines": { - "node": ">=14" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/resource-detector-aws": { - "version": "1.5.2", - "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-aws/-/resource-detector-aws-1.5.2.tgz", - "integrity": "sha512-LNwKy5vJM5fvCDcbXVKwg6Y1pKT4WgZUsddGMnWMEhxJcQVZm2Z9vUkyHdQU7xvJtGwCO2/TkMWHPjU1KQNDJQ==", - "license": "Apache-2.0", + "node_modules/@smithy/fetch-http-handler/node_modules/@smithy/util-uri-escape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", + "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", "dependencies": { - "@opentelemetry/core": "^1.0.0", - "@opentelemetry/resources": "^1.0.0", - "@opentelemetry/semantic-conventions": "^1.22.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/resource-detector-aws/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.25.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.1.tgz", - "integrity": "sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==", - "license": "Apache-2.0", + "node_modules/@smithy/hash-node": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/hash-node/-/hash-node-3.0.3.tgz", + "integrity": "sha512-2ctBXpPMG+B3BtWSGNnKELJ7SH9e4TNefJS0cd2eSkOOROeBnnVBnAy9LtJ8tY4vUEoe55N4CNPxzbWvR39iBw==", + "dependencies": { + "@smithy/types": "^3.3.0", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=14" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/resource-detector-container": { - "version": "0.3.11", - "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-container/-/resource-detector-container-0.3.11.tgz", - "integrity": "sha512-22ndMDakxX+nuhAYwqsciexV8/w26JozRUV0FN9kJiqSWtA1b5dCVtlp3J6JivG5t8kDN9UF5efatNnVbqRT9Q==", - "license": "Apache-2.0", + "node_modules/@smithy/hash-node/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@opentelemetry/resources": "^1.0.0", - "@opentelemetry/semantic-conventions": "^1.22.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/resource-detector-container/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.25.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.1.tgz", - "integrity": "sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==", - "license": "Apache-2.0", - "engines": { - "node": ">=14" + "node_modules/@smithy/invalid-dependency": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/invalid-dependency/-/invalid-dependency-3.0.3.tgz", + "integrity": "sha512-ID1eL/zpDULmHJbflb864k72/SNOZCADRc9i7Exq3RUNJw6raWUSlFEQ+3PX3EYs++bTxZB2dE9mEHTQLv61tw==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" } }, - "node_modules/@opentelemetry/resource-detector-gcp": { - "version": "0.29.10", - "resolved": "https://registry.npmjs.org/@opentelemetry/resource-detector-gcp/-/resource-detector-gcp-0.29.10.tgz", - "integrity": "sha512-rm2HKJ9lsdoVvrbmkr9dkOzg3Uk0FksXNxvNBgrCprM1XhMoJwThI5i0h/5sJypISUAJlEeJS6gn6nROj/NpkQ==", - "license": "Apache-2.0", + "node_modules/@smithy/invalid-dependency/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@opentelemetry/core": "^1.0.0", - "@opentelemetry/resources": "^1.0.0", - "@opentelemetry/semantic-conventions": "^1.22.0", - "gcp-metadata": "^6.0.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/resource-detector-gcp/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.25.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.1.tgz", - "integrity": "sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==", - "license": "Apache-2.0", + "node_modules/@smithy/is-array-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/is-array-buffer/-/is-array-buffer-3.0.0.tgz", + "integrity": "sha512-+Fsu6Q6C4RSJiy81Y8eApjEB5gVtM+oFKTffg+jSuwtvomJJrhUJBu2zS8wjXSgH/g1MKEWrzyChTBe6clb5FQ==", + "dependencies": { + "tslib": "^2.6.2" + }, "engines": { - "node": ">=14" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/resources": { - "version": "1.25.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.25.1.tgz", - "integrity": "sha512-pkZT+iFYIZsVn6+GzM0kSX+u3MSLCY9md+lIJOoKl/P+gJFfxJte/60Usdp8Ce4rOs8GduUpSPNe1ddGyDT1sQ==", - "license": "Apache-2.0", + "node_modules/@smithy/middleware-content-length": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@smithy/middleware-content-length/-/middleware-content-length-3.0.5.tgz", + "integrity": "sha512-ILEzC2eyxx6ncej3zZSwMpB5RJ0zuqH7eMptxC4KN3f+v9bqT8ohssKbhNR78k/2tWW+KS5Spw+tbPF4Ejyqvw==", "dependencies": { - "@opentelemetry/core": "1.25.1", - "@opentelemetry/semantic-conventions": "1.25.1" + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/middleware-content-length/node_modules/@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/resources/node_modules/@opentelemetry/core": { - "version": "1.25.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.25.1.tgz", - "integrity": "sha512-GeT/l6rBYWVQ4XArluLVB6WWQ8flHbdb6r2FCHC3smtdOAbrJBIv35tpV/yp9bmYUJf+xmZpu9DRTIeJVhFbEQ==", - "license": "Apache-2.0", + "node_modules/@smithy/middleware-content-length/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@opentelemetry/semantic-conventions": "1.25.1" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/middleware-endpoint": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@smithy/middleware-endpoint/-/middleware-endpoint-3.1.0.tgz", + "integrity": "sha512-5y5aiKCEwg9TDPB4yFE7H6tYvGFf1OJHNczeY10/EFF8Ir8jZbNntQJxMWNfeQjC1mxPsaQ6mR9cvQbf+0YeMw==", + "dependencies": { + "@smithy/middleware-serde": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-middleware": "^3.0.3", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/resources/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.25.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.1.tgz", - "integrity": "sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==", - "license": "Apache-2.0", + "node_modules/@smithy/middleware-endpoint/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "dependencies": { + "tslib": "^2.6.2" + }, "engines": { - "node": ">=14" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/sdk-logs": { - "version": "0.40.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.40.0.tgz", - "integrity": "sha512-/JG7DOLo/Y3VR9azPXlXNRGQff3gp7nQbWl5cFD2SmlYqUrzMq1OjbksZLVztDu1+ynbFunseUG11SxhoxvSRg==", - "license": "Apache-2.0", + "node_modules/@smithy/middleware-retry": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.13.tgz", + "integrity": "sha512-zvCLfaRYCaUmjbF2yxShGZdolSHft7NNCTA28HVN9hKcEbOH+g5irr1X9s+in8EpambclGnevZY4A3lYpvDCFw==", "dependencies": { - "@opentelemetry/core": "1.14.0", - "@opentelemetry/resources": "1.14.0" + "@smithy/node-config-provider": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/service-error-classification": "^3.0.3", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "tslib": "^2.6.2", + "uuid": "^9.0.1" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.4.0 <1.5.0", - "@opentelemetry/api-logs": ">=0.39.1" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/sdk-logs/node_modules/@opentelemetry/resources": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.14.0.tgz", - "integrity": "sha512-qRfWIgBxxl3z47E036Aey0Lj2ZjlFb27Q7Xnj1y1z/P293RXJZGLtcfn/w8JF7v1Q2hs3SDGxz7Wb9Dko1YUQA==", - "license": "Apache-2.0", + "node_modules/@smithy/middleware-retry/node_modules/@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", "dependencies": { - "@opentelemetry/core": "1.14.0", - "@opentelemetry/semantic-conventions": "1.14.0" + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.5.0" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/sdk-metrics": { - "version": "1.25.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.25.1.tgz", - "integrity": "sha512-9Mb7q5ioFL4E4dDrc4wC/A3NTHDat44v4I3p2pLPSxRvqUbDIQyMVr9uK+EU69+HWhlET1VaSrRzwdckWqY15Q==", - "license": "Apache-2.0", + "node_modules/@smithy/middleware-retry/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@opentelemetry/core": "1.25.1", - "@opentelemetry/resources": "1.25.1", - "lodash.merge": "^4.6.2" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.10.0" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/sdk-metrics/node_modules/@opentelemetry/core": { - "version": "1.25.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.25.1.tgz", - "integrity": "sha512-GeT/l6rBYWVQ4XArluLVB6WWQ8flHbdb6r2FCHC3smtdOAbrJBIv35tpV/yp9bmYUJf+xmZpu9DRTIeJVhFbEQ==", - "license": "Apache-2.0", + "node_modules/@smithy/middleware-serde": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-serde/-/middleware-serde-3.0.3.tgz", + "integrity": "sha512-puUbyJQBcg9eSErFXjKNiGILJGtiqmuuNKEYNYfUD57fUl4i9+mfmThtQhvFXU0hCVG0iEJhvQUipUf+/SsFdA==", "dependencies": { - "@opentelemetry/semantic-conventions": "1.25.1" + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.10.0" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/sdk-metrics/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.25.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.25.1.tgz", - "integrity": "sha512-ZDjMJJQRlyk8A1KZFCc+bCbsyrn1wTwdNt56F7twdfUfnHUZUq77/WfONCj8p72NZOyP7pNTdUWSTYC3GTbuuQ==", - "license": "Apache-2.0", + "node_modules/@smithy/middleware-serde/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "dependencies": { + "tslib": "^2.6.2" + }, "engines": { - "node": ">=14" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/sdk-node": { - "version": "0.49.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-node/-/sdk-node-0.49.1.tgz", - "integrity": "sha512-feBIT85ndiSHXsQ2gfGpXC/sNeX4GCHLksC4A9s/bfpUbbgbCSl0RvzZlmEpCHarNrkZMwFRi4H0xFfgvJEjrg==", - "license": "Apache-2.0", + "node_modules/@smithy/middleware-stack": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/middleware-stack/-/middleware-stack-3.0.3.tgz", + "integrity": "sha512-r4klY9nFudB0r9UdSMaGSyjyQK5adUyPnQN/ZM6M75phTxOdnc/AhpvGD1fQUvgmqjQEBGCwpnPbDm8pH5PapA==", "dependencies": { - "@opentelemetry/api-logs": "0.49.1", - "@opentelemetry/core": "1.22.0", - "@opentelemetry/exporter-trace-otlp-grpc": "0.49.1", - "@opentelemetry/exporter-trace-otlp-http": "0.49.1", - "@opentelemetry/exporter-trace-otlp-proto": "0.49.1", - "@opentelemetry/exporter-zipkin": "1.22.0", - "@opentelemetry/instrumentation": "0.49.1", - "@opentelemetry/resources": "1.22.0", - "@opentelemetry/sdk-logs": "0.49.1", - "@opentelemetry/sdk-metrics": "1.22.0", - "@opentelemetry/sdk-trace-base": "1.22.0", - "@opentelemetry/sdk-trace-node": "1.22.0", - "@opentelemetry/semantic-conventions": "1.22.0" + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.9.0" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/core": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.22.0.tgz", - "integrity": "sha512-0VoAlT6x+Xzik1v9goJ3pZ2ppi6+xd3aUfg4brfrLkDBHRIVjMP0eBHrKrhB+NKcDyMAg8fAbGL3Npg/F6AwWA==", - "license": "Apache-2.0", + "node_modules/@smithy/middleware-stack/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@opentelemetry/semantic-conventions": "1.22.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/exporter-trace-otlp-grpc": { - "version": "0.49.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/exporter-trace-otlp-grpc/-/exporter-trace-otlp-grpc-0.49.1.tgz", - "integrity": "sha512-Zbd7f3zF7fI2587MVhBizaW21cO/SordyrZGtMtvhoxU6n4Qb02Gx71X4+PzXH620e0+JX+Pcr9bYb1HTeVyJA==", - "license": "Apache-2.0", + "node_modules/@smithy/node-config-provider": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-config-provider/-/node-config-provider-3.1.4.tgz", + "integrity": "sha512-YvnElQy8HR4vDcAjoy7Xkx9YT8xZP4cBXcbJSgm/kxmiQu08DwUwj8rkGnyoJTpfl/3xYHH+d8zE+eHqoDCSdQ==", "dependencies": { - "@grpc/grpc-js": "^1.7.1", - "@opentelemetry/core": "1.22.0", - "@opentelemetry/otlp-grpc-exporter-base": "0.49.1", - "@opentelemetry/otlp-transformer": "0.49.1", - "@opentelemetry/resources": "1.22.0", - "@opentelemetry/sdk-trace-base": "1.22.0" + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/otlp-exporter-base": { - "version": "0.49.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-exporter-base/-/otlp-exporter-base-0.49.1.tgz", - "integrity": "sha512-z6sHliPqDgJU45kQatAettY9/eVF58qVPaTuejw9YWfSRqid9pXPYeegDCSdyS47KAUgAtm+nC28K3pfF27HWg==", - "license": "Apache-2.0", + "node_modules/@smithy/node-config-provider/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@opentelemetry/core": "1.22.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/otlp-grpc-exporter-base": { - "version": "0.49.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-grpc-exporter-base/-/otlp-grpc-exporter-base-0.49.1.tgz", - "integrity": "sha512-DNDNUWmOqtKTFJAyOyHHKotVox0NQ/09ETX8fUOeEtyNVHoGekAVtBbvIA3AtK+JflP7LC0PTjlLfruPM3Wy6w==", + "node_modules/@smithy/node-http-handler": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.5.0.tgz", + "integrity": "sha512-mVGyPBzkkGQsPoxQUbxlEfRjrj6FPyA3u3u2VXGr9hT8wilsoQdZdvKpMBFMB8Crfhv5dNkKHIW0Yyuc7eABqA==", "license": "Apache-2.0", "dependencies": { - "@grpc/grpc-js": "^1.7.1", - "@opentelemetry/core": "1.22.0", - "@opentelemetry/otlp-exporter-base": "0.49.1", - "protobufjs": "^7.2.3" + "@smithy/abort-controller": "^2.2.0", + "@smithy/protocol-http": "^3.3.0", + "@smithy/querystring-builder": "^2.2.0", + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.0.0" + "node": ">=14.0.0" } }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/otlp-transformer": { - "version": "0.49.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/otlp-transformer/-/otlp-transformer-0.49.1.tgz", - "integrity": "sha512-Z+koA4wp9L9e3jkFacyXTGphSWTbOKjwwXMpb0CxNb0kjTHGUxhYRN8GnkLFsFo5NbZPjP07hwAqeEG/uCratQ==", - "license": "Apache-2.0", + "node_modules/@smithy/property-provider": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/property-provider/-/property-provider-3.1.3.tgz", + "integrity": "sha512-zahyOVR9Q4PEoguJ/NrFP4O7SMAfYO1HLhB18M+q+Z4KFd4V2obiMnlVoUFzFLSPeVt1POyNWneHHrZaTMoc/g==", "dependencies": { - "@opentelemetry/api-logs": "0.49.1", - "@opentelemetry/core": "1.22.0", - "@opentelemetry/resources": "1.22.0", - "@opentelemetry/sdk-logs": "0.49.1", - "@opentelemetry/sdk-metrics": "1.22.0", - "@opentelemetry/sdk-trace-base": "1.22.0" + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.9.0" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/resources": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.22.0.tgz", - "integrity": "sha512-+vNeIFPH2hfcNL0AJk/ykJXoUCtR1YaDUZM+p3wZNU4Hq98gzq+7b43xbkXjadD9VhWIUQqEwXyY64q6msPj6A==", - "license": "Apache-2.0", + "node_modules/@smithy/property-provider/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@opentelemetry/core": "1.22.0", - "@opentelemetry/semantic-conventions": "1.22.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/sdk-logs": { - "version": "0.49.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-logs/-/sdk-logs-0.49.1.tgz", - "integrity": "sha512-gCzYWsJE0h+3cuh3/cK+9UwlVFyHvj3PReIOCDOmdeXOp90ZjKRoDOJBc3mvk1LL6wyl1RWIivR8Rg9OToyesw==", + "node_modules/@smithy/protocol-http": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.3.0.tgz", + "integrity": "sha512-Xy5XK1AFWW2nlY/biWZXu6/krgbaf2dg0q492D8M5qthsnU2H+UgFeZLbM76FnH7s6RO/xhQRkj+T6KBO3JzgQ==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.22.0", - "@opentelemetry/resources": "1.22.0" + "@smithy/types": "^2.12.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.4.0 <1.9.0", - "@opentelemetry/api-logs": ">=0.39.1" + "node": ">=14.0.0" } }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/sdk-metrics": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-metrics/-/sdk-metrics-1.22.0.tgz", - "integrity": "sha512-k6iIx6H3TZ+BVMr2z8M16ri2OxWaljg5h8ihGJxi/KQWcjign6FEaEzuigXt5bK9wVEhqAcWLCfarSftaNWkkg==", + "node_modules/@smithy/querystring-builder": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.2.0.tgz", + "integrity": "sha512-L1kSeviUWL+emq3CUVSgdogoM/D9QMFaqxL/dd0X7PCNWmPXqt+ExtrBjqT0V7HLN03Vs9SuiLrG3zy3JGnE5A==", "license": "Apache-2.0", "dependencies": { - "@opentelemetry/core": "1.22.0", - "@opentelemetry/resources": "1.22.0", - "lodash.merge": "^4.6.2" + "@smithy/types": "^2.12.0", + "@smithy/util-uri-escape": "^2.2.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.3.0 <1.9.0" + "node": ">=14.0.0" } }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/sdk-trace-base": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.22.0.tgz", - "integrity": "sha512-pfTuSIpCKONC6vkTpv6VmACxD+P1woZf4q0K46nSUvXFvOFqjBYKFaAMkKD3M1mlKUUh0Oajwj35qNjMl80m1Q==", - "license": "Apache-2.0", + "node_modules/@smithy/querystring-parser": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-parser/-/querystring-parser-3.0.3.tgz", + "integrity": "sha512-zahM1lQv2YjmznnfQsWbYojFe55l0SLG/988brlLv1i8z3dubloLF+75ATRsqPBboUXsW6I9CPGE5rQgLfY0vQ==", "dependencies": { - "@opentelemetry/core": "1.22.0", - "@opentelemetry/resources": "1.22.0", - "@opentelemetry/semantic-conventions": "1.22.0" + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/querystring-parser/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "dependencies": { + "tslib": "^2.6.2" }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/sdk-node/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", - "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==", - "license": "Apache-2.0", + "node_modules/@smithy/service-error-classification": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/service-error-classification/-/service-error-classification-3.0.3.tgz", + "integrity": "sha512-Jn39sSl8cim/VlkLsUhRFq/dKDnRUFlfRkvhOJaUbLBXUsLRLNf9WaxDv/z9BjuQ3A6k/qE8af1lsqcwm7+DaQ==", + "dependencies": { + "@smithy/types": "^3.3.0" + }, "engines": { - "node": ">=14" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/sdk-trace-base": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.14.0.tgz", - "integrity": "sha512-NzRGt3PS+HPKfQYMb6Iy8YYc5OKA73qDwci/6ujOIvyW9vcqBJSWbjZ8FeLEAmuatUB5WrRhEKu9b0sIiIYTrQ==", - "license": "Apache-2.0", + "node_modules/@smithy/service-error-classification/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@opentelemetry/core": "1.14.0", - "@opentelemetry/resources": "1.14.0", - "@opentelemetry/semantic-conventions": "1.14.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.5.0" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/sdk-trace-base/node_modules/@opentelemetry/resources": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.14.0.tgz", - "integrity": "sha512-qRfWIgBxxl3z47E036Aey0Lj2ZjlFb27Q7Xnj1y1z/P293RXJZGLtcfn/w8JF7v1Q2hs3SDGxz7Wb9Dko1YUQA==", - "license": "Apache-2.0", + "node_modules/@smithy/shared-ini-file-loader": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/shared-ini-file-loader/-/shared-ini-file-loader-3.1.4.tgz", + "integrity": "sha512-qMxS4hBGB8FY2GQqshcRUy1K6k8aBWP5vwm8qKkCT3A9K2dawUwOIJfqh9Yste/Bl0J2lzosVyrXDj68kLcHXQ==", "dependencies": { - "@opentelemetry/core": "1.14.0", - "@opentelemetry/semantic-conventions": "1.14.0" + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.5.0" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/sdk-trace-node": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-node/-/sdk-trace-node-1.22.0.tgz", - "integrity": "sha512-gTGquNz7ue8uMeiWPwp3CU321OstQ84r7PCDtOaCicjbJxzvO8RZMlEC4geOipTeiF88kss5n6w+//A0MhP1lQ==", - "license": "Apache-2.0", + "node_modules/@smithy/shared-ini-file-loader/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@opentelemetry/context-async-hooks": "1.22.0", - "@opentelemetry/core": "1.22.0", - "@opentelemetry/propagator-b3": "1.22.0", - "@opentelemetry/propagator-jaeger": "1.22.0", - "@opentelemetry/sdk-trace-base": "1.22.0", - "semver": "^7.5.2" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/signature-v4": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/signature-v4/-/signature-v4-4.1.0.tgz", + "integrity": "sha512-aRryp2XNZeRcOtuJoxjydO6QTaVhxx/vjaR+gx7ZjaFgrgPRyZ3HCTbfwqYj6ZWEBHkCSUfcaymKPURaByukag==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-uri-escape": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/sdk-trace-node/node_modules/@opentelemetry/core": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/core/-/core-1.22.0.tgz", - "integrity": "sha512-0VoAlT6x+Xzik1v9goJ3pZ2ppi6+xd3aUfg4brfrLkDBHRIVjMP0eBHrKrhB+NKcDyMAg8fAbGL3Npg/F6AwWA==", - "license": "Apache-2.0", + "node_modules/@smithy/signature-v4/node_modules/@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", "dependencies": { - "@opentelemetry/semantic-conventions": "1.22.0" + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/sdk-trace-node/node_modules/@opentelemetry/resources": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/resources/-/resources-1.22.0.tgz", - "integrity": "sha512-+vNeIFPH2hfcNL0AJk/ykJXoUCtR1YaDUZM+p3wZNU4Hq98gzq+7b43xbkXjadD9VhWIUQqEwXyY64q6msPj6A==", - "license": "Apache-2.0", + "node_modules/@smithy/signature-v4/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@opentelemetry/core": "1.22.0", - "@opentelemetry/semantic-conventions": "1.22.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/sdk-trace-node/node_modules/@opentelemetry/sdk-trace-base": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/sdk-trace-base/-/sdk-trace-base-1.22.0.tgz", - "integrity": "sha512-pfTuSIpCKONC6vkTpv6VmACxD+P1woZf4q0K46nSUvXFvOFqjBYKFaAMkKD3M1mlKUUh0Oajwj35qNjMl80m1Q==", - "license": "Apache-2.0", + "node_modules/@smithy/signature-v4/node_modules/@smithy/util-uri-escape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", + "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", "dependencies": { - "@opentelemetry/core": "1.22.0", - "@opentelemetry/resources": "1.22.0", - "@opentelemetry/semantic-conventions": "1.22.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": ">=1.0.0 <1.9.0" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/sdk-trace-node/node_modules/@opentelemetry/semantic-conventions": { - "version": "1.22.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.22.0.tgz", - "integrity": "sha512-CAOgFOKLybd02uj/GhCdEeeBjOS0yeoDeo/CA7ASBSmenpZHAKGB3iDm/rv3BQLcabb/OprDEsSQ1y0P8A7Siw==", - "license": "Apache-2.0", + "node_modules/@smithy/smithy-client": { + "version": "3.1.11", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", + "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", + "dependencies": { + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/types": "^3.3.0", + "@smithy/util-stream": "^3.1.3", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=14" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/semantic-conventions": { - "version": "1.14.0", - "resolved": "https://registry.npmjs.org/@opentelemetry/semantic-conventions/-/semantic-conventions-1.14.0.tgz", - "integrity": "sha512-rJfCY8rCWz3cb4KI6pEofnytvMPuj3YLQwoscCCYZ5DkdiPjo15IQ0US7+mjcWy9H3fcZIzf2pbJZ7ck/h4tug==", - "license": "Apache-2.0", + "node_modules/@smithy/smithy-client/node_modules/@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, "engines": { - "node": ">=14" + "node": ">=16.0.0" } }, - "node_modules/@opentelemetry/sql-common": { - "version": "0.40.1", - "resolved": "https://registry.npmjs.org/@opentelemetry/sql-common/-/sql-common-0.40.1.tgz", - "integrity": "sha512-nSDlnHSqzC3pXn/wZEZVLuAuJ1MYMXPBwtv2qAbCa3847SaHItdE7SzUq/Jtb0KZmh1zfAbNi3AAMjztTT4Ugg==", - "license": "Apache-2.0", + "node_modules/@smithy/smithy-client/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@opentelemetry/core": "^1.1.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14" - }, - "peerDependencies": { - "@opentelemetry/api": "^1.1.0" + "node": ">=16.0.0" } }, - "node_modules/@pagerduty/pdjs": { - "version": "2.2.4", - "resolved": "https://registry.npmjs.org/@pagerduty/pdjs/-/pdjs-2.2.4.tgz", - "integrity": "sha512-MMZvxos7PJnGJ8z3ijsu/gsMQLIfO8peeigKCjUDmviXk8FIaZZjX0X889NIKuFDhGirYbJVwGTaDYCEw4baLg==", + "node_modules/@smithy/types": { + "version": "2.12.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", + "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", "license": "Apache-2.0", "dependencies": { - "browser-or-node": "^2.0.0", - "cross-fetch": "^3.0.6" + "tslib": "^2.6.2" }, "engines": { - "node": ">=10.0.0" + "node": ">=14.0.0" } }, - "node_modules/@pkgjs/parseargs": { - "version": "0.11.0", - "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", - "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", - "license": "MIT", - "engines": { - "node": ">=14" + "node_modules/@smithy/url-parser": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/url-parser/-/url-parser-3.0.3.tgz", + "integrity": "sha512-pw3VtZtX2rg+s6HMs6/+u9+hu6oY6U7IohGhVNnjbgKy86wcIsSZwgHrFR+t67Uyxvp4Xz3p3kGXXIpTNisq8A==", + "dependencies": { + "@smithy/querystring-parser": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" } }, - "node_modules/@protobufjs/aspromise": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz", - "integrity": "sha512-j+gKExEuLmKwvz3OgROXtrJ2UG2x8Ch2YZUxahh+s1F2HZ+wAceUNLkvy6zKCPVRkU++ZWQrdxsUeQXmcg4uoQ==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/base64": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/base64/-/base64-1.1.2.tgz", - "integrity": "sha512-AZkcAA5vnN/v4PDqKyMR5lx7hZttPDgClv83E//FMNhR2TMcLUhfRUBHCmSl0oi9zMgDDqRUJkSxO3wm85+XLg==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/codegen": { - "version": "2.0.4", - "resolved": "https://registry.npmjs.org/@protobufjs/codegen/-/codegen-2.0.4.tgz", - "integrity": "sha512-YyFaikqM5sH0ziFZCN3xDC7zeGaB/d0IUb9CATugHWbd1FRFwWwt4ld4OYMPWu5a3Xe01mGAULCdqhMlPl29Jg==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/eventemitter": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/eventemitter/-/eventemitter-1.1.0.tgz", - "integrity": "sha512-j9ednRT81vYJ9OfVuXG6ERSTdEL1xVsNgqpkxMsbIabzSo3goCjDIveeGv5d03om39ML71RdmrGNjG5SReBP/Q==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/fetch": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/fetch/-/fetch-1.1.0.tgz", - "integrity": "sha512-lljVXpqXebpsijW71PZaCYeIcE5on1w5DlQy5WH6GLbFryLUrBD4932W/E2BSpfRJWseIL4v/KPgBFxDOIdKpQ==", - "license": "BSD-3-Clause", + "node_modules/@smithy/url-parser/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@protobufjs/aspromise": "^1.1.1", - "@protobufjs/inquire": "^1.1.0" + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@protobufjs/float": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/@protobufjs/float/-/float-1.0.2.tgz", - "integrity": "sha512-Ddb+kVXlXst9d+R9PfTIxh1EdNkgoRe5tOX6t01f1lYWOvJnSPDBlG241QLzcyPdoNTsblLUdujGSE4RzrTZGQ==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/inquire": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/inquire/-/inquire-1.1.0.tgz", - "integrity": "sha512-kdSefcPdruJiFMVSbn801t4vFK7KB/5gd2fYvrxhuJYg8ILrmn9SKSX2tZdV6V+ksulWqS7aXjBcRXl3wHoD9Q==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/path": { - "version": "1.1.2", - "resolved": "https://registry.npmjs.org/@protobufjs/path/-/path-1.1.2.tgz", - "integrity": "sha512-6JOcJ5Tm08dOHAbdR3GrvP+yUUfkjG5ePsHYczMFLq3ZmMkAD98cDgcT2iA1lJ9NVwFd4tH/iSSoe44YWkltEA==", - "license": "BSD-3-Clause" - }, - "node_modules/@protobufjs/pool": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/pool/-/pool-1.1.0.tgz", - "integrity": "sha512-0kELaGSIDBKvcgS4zkjz1PeddatrjYcmMWOlAuAPwAeccUrPHdUqo/J6LiymHHEiJT5NrF1UVwxY14f+fy4WQw==", - "license": "BSD-3-Clause" + "node_modules/@smithy/util-base64": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-base64/-/util-base64-3.0.0.tgz", + "integrity": "sha512-Kxvoh5Qtt0CDsfajiZOCpJxgtPHXOKwmM+Zy4waD43UoEMA+qPxxa98aE/7ZhdnBFZFXMOiBR5xbcaMhLtznQQ==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } }, - "node_modules/@protobufjs/utf8": { - "version": "1.1.0", - "resolved": "https://registry.npmjs.org/@protobufjs/utf8/-/utf8-1.1.0.tgz", - "integrity": "sha512-Vvn3zZrhQZkkBE8LSuW3em98c0FwgO4nxzv6OdSxPKJIEKY2bGbHn+mhGIPerzI4twdxaP8/0+06HBpwf345Lw==", - "license": "BSD-3-Clause" + "node_modules/@smithy/util-body-length-browser": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-browser/-/util-body-length-browser-3.0.0.tgz", + "integrity": "sha512-cbjJs2A1mLYmqmyVl80uoLTJhAcfzMOyPgjwAYusWKMdLeNtzmMz9YxNl3/jRLoxSS3wkqkf0jwNdtXWtyEBaQ==", + "dependencies": { + "tslib": "^2.6.2" + } }, - "node_modules/@rollup/plugin-commonjs": { - "version": "24.1.0", - "resolved": "https://registry.npmjs.org/@rollup/plugin-commonjs/-/plugin-commonjs-24.1.0.tgz", - "integrity": "sha512-eSL45hjhCWI0jCCXcNtLVqM5N1JlBGvlFfY0m6oOYnLCJ6N0qEXoZql4sY2MOUArzhH4SA/qBpTxvvZp2Sc+DQ==", - "dev": true, - "license": "MIT", + "node_modules/@smithy/util-body-length-node": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-body-length-node/-/util-body-length-node-3.0.0.tgz", + "integrity": "sha512-Tj7pZ4bUloNUP6PzwhN7K386tmSmEET9QtQg0TgdNOnxhZvCssHji+oZTUIuzxECRfG8rdm2PMw2WCFs6eIYkA==", "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "commondir": "^1.0.1", - "estree-walker": "^2.0.2", - "glob": "^8.0.3", - "is-reference": "1.2.1", - "magic-string": "^0.27.0" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.68.0||^3.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-buffer-from": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-buffer-from/-/util-buffer-from-3.0.0.tgz", + "integrity": "sha512-aEOHCgq5RWFbP+UDPvPot26EJHjOC+bRgse5A8V3FSShqd5E5UN4qc7zkwsvJPPAVsf73QwYcHN1/gt/rtLwQA==", + "dependencies": { + "@smithy/is-array-buffer": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@rollup/plugin-node-resolve": { - "version": "15.2.3", - "resolved": "https://registry.npmjs.org/@rollup/plugin-node-resolve/-/plugin-node-resolve-15.2.3.tgz", - "integrity": "sha512-j/lym8nf5E21LwBT4Df1VD6hRO2L2iwUeUmP7litikRsVp1H6NWx20NEp0Y7su+7XGc476GnXXc4kFeZNGmaSQ==", - "dev": true, - "license": "MIT", + "node_modules/@smithy/util-config-provider": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-config-provider/-/util-config-provider-3.0.0.tgz", + "integrity": "sha512-pbjk4s0fwq3Di/ANL+rCvJMKM5bzAQdE5S/6RL5NXgMExFAi6UgQMPOm5yPaIWPpr+EOXKXRonJ3FoxKf4mCJQ==", "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "@types/resolve": "1.20.2", - "deepmerge": "^4.2.2", - "is-builtin-module": "^3.2.1", - "is-module": "^1.0.0", - "resolve": "^1.22.1" + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^2.78.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } + "node": ">=16.0.0" } }, - "node_modules/@rollup/plugin-replace": { - "version": "5.0.7", - "resolved": "https://registry.npmjs.org/@rollup/plugin-replace/-/plugin-replace-5.0.7.tgz", - "integrity": "sha512-PqxSfuorkHz/SPpyngLyg5GCEkOcee9M1bkxiVDr41Pd61mqP1PLOoDPbpl44SB2mQGKwV/In74gqQmGITOhEQ==", - "dev": true, - "license": "MIT", + "node_modules/@smithy/util-defaults-mode-browser": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.13.tgz", + "integrity": "sha512-ZIRSUsnnMRStOP6OKtW+gCSiVFkwnfQF2xtf32QKAbHR6ACjhbAybDvry+3L5qQYdh3H6+7yD/AiUE45n8mTTw==", "dependencies": { - "@rollup/pluginutils": "^5.0.1", - "magic-string": "^0.30.3" + "@smithy/property-provider": "^3.1.3", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "bowser": "^2.11.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" - }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } + "node": ">= 10.0.0" } }, - "node_modules/@rollup/plugin-replace/node_modules/magic-string": { - "version": "0.30.10", - "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.10.tgz", - "integrity": "sha512-iIRwTIf0QKV3UAnYK4PU8uiEc4SRh5jX0mwpIwETPpHdhVM4f53RSwS/vXvN1JhGX+Cs7B8qIq3d6AH49O5fAQ==", - "dev": true, - "license": "MIT", + "node_modules/@smithy/util-defaults-mode-browser/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@jridgewell/sourcemap-codec": "^1.4.15" + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@rollup/pluginutils": { - "version": "5.1.0", - "resolved": "https://registry.npmjs.org/@rollup/pluginutils/-/pluginutils-5.1.0.tgz", - "integrity": "sha512-XTIWOPPcpvyKI6L1NHo0lFlCyznUEyPmPY1mc3KpPVDYulHSTvyeLNVW00QTLIAFNhR3kYnJTQHeGqU4M3n09g==", - "dev": true, - "license": "MIT", + "node_modules/@smithy/util-defaults-mode-node": { + "version": "3.0.13", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.13.tgz", + "integrity": "sha512-voUa8TFJGfD+U12tlNNLCDlXibt9vRdNzRX45Onk/WxZe7TS+hTOZouEZRa7oARGicdgeXvt1A0W45qLGYdy+g==", "dependencies": { - "@types/estree": "^1.0.0", - "estree-walker": "^2.0.2", - "picomatch": "^2.3.1" + "@smithy/config-resolver": "^3.0.5", + "@smithy/credential-provider-imds": "^3.2.0", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/smithy-client": "^3.1.11", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" - }, - "peerDependencies": { - "rollup": "^1.20.0||^2.0.0||^3.0.0||^4.0.0" + "node": ">= 10.0.0" + } + }, + "node_modules/@smithy/util-defaults-mode-node/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "dependencies": { + "tslib": "^2.6.2" }, - "peerDependenciesMeta": { - "rollup": { - "optional": true - } + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@sideway/address": { - "version": "4.1.5", - "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.5.tgz", - "integrity": "sha512-IqO/DUQHUkPeixNQ8n0JA6102hT9CmaljNTPmQ1u8MEhBo/R4Q8eKLN/vGZxuebwOroDB4cbpjheD4+/sKFK4Q==", - "license": "BSD-3-Clause", + "node_modules/@smithy/util-endpoints": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@smithy/util-endpoints/-/util-endpoints-2.0.5.tgz", + "integrity": "sha512-ReQP0BWihIE68OAblC/WQmDD40Gx+QY1Ez8mTdFMXpmjfxSyz2fVQu3A4zXRfQU9sZXtewk3GmhfOHswvX+eNg==", "dependencies": { - "@hapi/hoek": "^9.0.0" + "@smithy/node-config-provider": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@sideway/formula": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", - "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", - "license": "BSD-3-Clause" + "node_modules/@smithy/util-endpoints/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } }, - "node_modules/@sideway/pinpoint": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", - "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", - "license": "BSD-3-Clause" + "node_modules/@smithy/util-hex-encoding": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-hex-encoding/-/util-hex-encoding-3.0.0.tgz", + "integrity": "sha512-eFndh1WEK5YMUYvy3lPlVmYY/fZcQE1D8oSf41Id2vCeIkKJXPcYDCZD+4+xViI6b1XSd7tE+s5AmXzz5ilabQ==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } }, - "node_modules/@sinonjs/commons": { - "version": "3.0.1", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.1.tgz", - "integrity": "sha512-K3mCHKQ9sVh8o1C9cxkwxaOmXoAMlDxC1mYyHrjqOWEcBjYr76t96zL2zlj5dUGZ3HSw240X1qgH3Mjf1yJWpQ==", - "license": "BSD-3-Clause", + "node_modules/@smithy/util-middleware": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-middleware/-/util-middleware-3.0.3.tgz", + "integrity": "sha512-l+StyYYK/eO3DlVPbU+4Bi06Jjal+PFLSMmlWM1BEwyLxZ3aKkf1ROnoIakfaA7mC6uw3ny7JBkau4Yc+5zfWw==", "dependencies": { - "type-detect": "4.0.8" + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@sinonjs/fake-timers": { - "version": "11.2.2", - "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", - "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", - "license": "BSD-3-Clause", + "node_modules/@smithy/util-middleware/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "@sinonjs/commons": "^3.0.0" + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@sinonjs/samsam": { - "version": "8.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", - "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", - "license": "BSD-3-Clause", + "node_modules/@smithy/util-retry": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/util-retry/-/util-retry-3.0.3.tgz", + "integrity": "sha512-AFw+hjpbtVApzpNDhbjNG5NA3kyoMs7vx0gsgmlJF4s+yz1Zlepde7J58zpIRIsdjc+emhpAITxA88qLkPF26w==", "dependencies": { - "@sinonjs/commons": "^2.0.0", - "lodash.get": "^4.4.2", - "type-detect": "^4.0.8" + "@smithy/service-error-classification": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": { - "version": "2.0.0", - "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", - "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", - "license": "BSD-3-Clause", + "node_modules/@smithy/util-retry/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { - "type-detect": "4.0.8" + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, - "node_modules/@sinonjs/text-encoding": { - "version": "0.7.2", - "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", - "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", - "license": "(Unlicense OR Apache-2.0)" + "node_modules/@smithy/util-stream": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/@smithy/util-stream/-/util-stream-3.1.3.tgz", + "integrity": "sha512-FIv/bRhIlAxC0U7xM1BCnF2aDRPq0UaelqBHkM2lsCp26mcBbgI0tCVTv+jGdsQLUmAMybua/bjDsSu8RQHbmw==", + "dependencies": { + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/types": "^3.3.0", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-buffer-from": "^3.0.0", + "@smithy/util-hex-encoding": "^3.0.0", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } }, - "node_modules/@smithy/abort-controller": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-2.2.0.tgz", - "integrity": "sha512-wRlta7GuLWpTqtFfGo+nZyOO1vEvewdNR1R4rTxpC8XU6vG/NDyrFBhwLZsqg1NUoR1noVaXJPC/7ZK47QCySw==", - "license": "Apache-2.0", + "node_modules/@smithy/util-stream/node_modules/@smithy/abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", + "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", "dependencies": { - "@smithy/types": "^2.12.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@smithy/node-http-handler": { - "version": "2.5.0", - "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-2.5.0.tgz", - "integrity": "sha512-mVGyPBzkkGQsPoxQUbxlEfRjrj6FPyA3u3u2VXGr9hT8wilsoQdZdvKpMBFMB8Crfhv5dNkKHIW0Yyuc7eABqA==", - "license": "Apache-2.0", + "node_modules/@smithy/util-stream/node_modules/@smithy/node-http-handler": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.4.tgz", + "integrity": "sha512-+UmxgixgOr/yLsUxcEKGH0fMNVteJFGkmRltYFHnBMlogyFdpzn2CwqWmxOrfJELhV34v0WSlaqG1UtE1uXlJg==", "dependencies": { - "@smithy/abort-controller": "^2.2.0", - "@smithy/protocol-http": "^3.3.0", - "@smithy/querystring-builder": "^2.2.0", - "@smithy/types": "^2.12.0", + "@smithy/abort-controller": "^3.1.1", + "@smithy/protocol-http": "^4.1.0", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@smithy/protocol-http": { - "version": "3.3.0", - "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-3.3.0.tgz", - "integrity": "sha512-Xy5XK1AFWW2nlY/biWZXu6/krgbaf2dg0q492D8M5qthsnU2H+UgFeZLbM76FnH7s6RO/xhQRkj+T6KBO3JzgQ==", - "license": "Apache-2.0", + "node_modules/@smithy/util-stream/node_modules/@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", "dependencies": { - "@smithy/types": "^2.12.0", + "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@smithy/querystring-builder": { - "version": "2.2.0", - "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-2.2.0.tgz", - "integrity": "sha512-L1kSeviUWL+emq3CUVSgdogoM/D9QMFaqxL/dd0X7PCNWmPXqt+ExtrBjqT0V7HLN03Vs9SuiLrG3zy3JGnE5A==", - "license": "Apache-2.0", + "node_modules/@smithy/util-stream/node_modules/@smithy/querystring-builder": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", + "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", "dependencies": { - "@smithy/types": "^2.12.0", - "@smithy/util-uri-escape": "^2.2.0", + "@smithy/types": "^3.3.0", + "@smithy/util-uri-escape": "^3.0.0", "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" } }, - "node_modules/@smithy/types": { - "version": "2.12.0", - "resolved": "https://registry.npmjs.org/@smithy/types/-/types-2.12.0.tgz", - "integrity": "sha512-QwYgloJ0sVNBeBuBs65cIkTbfzV/Q6ZNPCJ99EICFEdJYG50nGIY/uYXp+TbsdJReIuPr0a0kXmCvren3MbRRw==", - "license": "Apache-2.0", + "node_modules/@smithy/util-stream/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", "dependencies": { "tslib": "^2.6.2" }, "engines": { - "node": ">=14.0.0" + "node": ">=16.0.0" + } + }, + "node_modules/@smithy/util-stream/node_modules/@smithy/util-uri-escape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", + "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" } }, "node_modules/@smithy/util-uri-escape": { @@ -4160,6 +6260,18 @@ "node": ">=14.0.0" } }, + "node_modules/@smithy/util-utf8": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-utf8/-/util-utf8-3.0.0.tgz", + "integrity": "sha512-rUeT12bxFnplYDe815GXbq/oixEGHfRFFtcTF3YdDi/JaENIM6aSYYLJydG83UNzLXeRI5K8abYd/8Sp/QM0kA==", + "dependencies": { + "@smithy/util-buffer-from": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@socket.io/component-emitter": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.2.tgz", @@ -5446,6 +7558,11 @@ "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==", "license": "ISC" }, + "node_modules/bowser": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/bowser/-/bowser-2.11.0.tgz", + "integrity": "sha512-AlcaJBi/pqqJBIQ8U9Mcpc9i8Aqxn88Skv5d+xBX006BY5u8N3mGLHa5Lgppa7L/HfwgwLgZ6NYs+Ag6uUmJRA==" + }, "node_modules/brace-expansion": { "version": "1.1.11", "license": "MIT", @@ -7340,6 +9457,27 @@ "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", "dev": true }, + "node_modules/fast-xml-parser": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/fast-xml-parser/-/fast-xml-parser-4.4.1.tgz", + "integrity": "sha512-xkjOecfnKGkSsOwtZ5Pz7Us/T6mrbPQrq0nh+aCO5V9nk5NLWmasAHumTKjiPJPWANe+kAZ84Jc8ooJkzZ88Sw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/NaturalIntelligence" + }, + { + "type": "paypal", + "url": "https://paypal.me/naturalintelligence" + } + ], + "dependencies": { + "strnum": "^1.0.5" + }, + "bin": { + "fxparser": "src/cli/cli.js" + } + }, "node_modules/fastest-levenshtein": { "version": "1.0.16", "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz", @@ -12523,6 +14661,11 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strnum": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/strnum/-/strnum-1.0.5.tgz", + "integrity": "sha512-J8bbNyKKXl5qYcR36TIO8W3mVGVHrmmxsd5PAItGkmyzwJvybiw2IVq5nqd0i4LSNSkB/sx9VHllbfFdr9k1JA==" + }, "node_modules/strtok3": { "version": "7.1.0", "resolved": "https://registry.npmjs.org/strtok3/-/strtok3-7.1.0.tgz", @@ -14041,6 +16184,7 @@ "version": "2.1.0", "license": "AGPL-3.0-only", "dependencies": { + "@aws-sdk/client-textract": "^3.621.0", "@heyputer/kv.js": "^0.1.3", "@heyputer/multest": "^0.0.2", "@heyputer/puter-js-common": "^1.0.0", diff --git a/src/backend/exports.js b/src/backend/exports.js index a8649af662..28c7a266e7 100644 --- a/src/backend/exports.js +++ b/src/backend/exports.js @@ -26,6 +26,7 @@ const { testlaunch } = require("./src/index.js"); const BaseService = require("./src/services/BaseService.js"); const { Context } = require("./src/util/context.js"); const { TestDriversModule } = require("./src/modules/test-drivers/TestDriversModule.js"); +const { PuterAIModule } = require("./src/modules/puterai/PuterAIModule.js"); module.exports = { @@ -48,4 +49,5 @@ module.exports = { LocalDiskStorageModule, SelfHostedModule, TestDriversModule, + PuterAIModule, }; diff --git a/src/backend/package.json b/src/backend/package.json index cce89a4708..16c733fb7c 100644 --- a/src/backend/package.json +++ b/src/backend/package.json @@ -7,6 +7,7 @@ "test": "npx mocha" }, "dependencies": { + "@aws-sdk/client-textract": "^3.621.0", "@heyputer/kv.js": "^0.1.3", "@heyputer/multest": "^0.0.2", "@heyputer/puter-js-common": "^1.0.0", diff --git a/src/backend/src/modules/puterai/AIInterfaceService.js b/src/backend/src/modules/puterai/AIInterfaceService.js new file mode 100644 index 0000000000..51fd17f97f --- /dev/null +++ b/src/backend/src/modules/puterai/AIInterfaceService.js @@ -0,0 +1,32 @@ +const BaseService = require("../../services/BaseService"); + +class AIInterfaceService extends BaseService { + async ['__on_driver.register.interfaces'] () { + const svc_registry = this.services.get('registry'); + const col_interfaces = svc_registry.get('interfaces'); + + col_interfaces.set('puter-ocr', { + description: 'Optical character recognition', + methods: { + recognize: { + description: 'Recognize text in an image or document.', + parameters: { + source: { + type: 'file', + }, + }, + result: { + type: { + $: 'stream', + content_type: 'image', + } + }, + }, + } + }); + } +} + +module.exports = { + AIInterfaceService +}; diff --git a/src/backend/src/modules/puterai/AWSTextractService.js b/src/backend/src/modules/puterai/AWSTextractService.js new file mode 100644 index 0000000000..02376646ac --- /dev/null +++ b/src/backend/src/modules/puterai/AWSTextractService.js @@ -0,0 +1,137 @@ +const { TextractClient, AnalyzeDocumentCommand, InvalidS3ObjectException } = require("@aws-sdk/client-textract"); + +const BaseService = require("../../services/BaseService"); + +class AWSTextractService extends BaseService { + _construct () { + this.clients_ = {}; + } + + static IMPLEMENTS = { + ['puter-ocr']: { + async recognize ({ source, test_mode }) { + const resp = await this.analyze_document(source); + + // Simplify the response for common interface + const puter_response = { + blocks: [] + }; + + for ( const block of resp.Blocks ) { + if ( block.BlockType === 'PAGE' ) continue; + if ( block.BlockType === 'CELL' ) continue; + if ( block.BlockType === 'TABLE' ) continue; + if ( block.BlockType === 'MERGED_CELL' ) continue; + if ( block.BlockType === 'LAYOUT_FIGURE' ) continue; + if ( block.BlockType === 'LAYOUT_TEXT' ) continue; + + const puter_block = { + type: `text/textract:${block.BlockType}`, + confidence: block.Confidence, + text: block.Text, + }; + puter_response.blocks.push(puter_block); + } + + return puter_response; + } + }, + }; + + _create_aws_credentials () { + return { + accessKeyId: this.config.aws.access_key, + secretAccessKey: this.config.aws.secret_key, + }; + } + + _get_client (region) { + if ( ! region ) { + region = this.config.aws?.region ?? this.global_config.aws?.region + ?? 'us-west-2'; + } + if ( this.clients_[region] ) return this.clients_[region]; + + this.clients_[region] = new TextractClient({ + credentials: this._create_aws_credentials(), + region, + }); + + return this.clients_[region]; + } + + async analyze_document (file_facade) { + const { + client, document, using_s3 + } = await this._get_client_and_document(file_facade); + + const command = new AnalyzeDocumentCommand({ + Document: document, + FeatureTypes: [ + // 'TABLES', + // 'FORMS', + // 'SIGNATURES', + 'LAYOUT' + ], + }); + + try { + return await client.send(command); + } catch (e) { + if ( using_s3 && e instanceof InvalidS3ObjectException ) { + const { client, document } = + await this._get_client_and_document(file_facade, true); + const command = new AnalyzeDocumentCommand({ + Document: document, + FeatureTypes: [ + 'LAYOUT', + ], + }) + return await client.send(command); + } + + throw e; + } + + throw new Error('expected to be unreachable'); + } + + async _get_client_and_document (file_facade, force_buffer) { + const try_s3info = await file_facade.get('s3-info'); + if ( try_s3info && ! force_buffer ) { + console.log('S3 INFO', try_s3info) + return { + using_s3: true, + client: this._get_client(try_s3info.bucket_region), + document: { + S3Object: { + Bucket: try_s3info.bucket, + Name: try_s3info.key, + }, + }, + }; + } + + const try_buffer = await file_facade.get('buffer'); + if ( try_buffer ) { + const base64 = try_buffer.toString('base64'); + return { + client: this._get_client(), + document: { + Bytes: try_buffer, + }, + }; + } + + const fsNode = await file_facade.get('fs-node'); + if ( fsNode && ! await fsNode.exists() ) { + throw APIError.create('subject_does_not_exist'); + } + + throw new Error('No suitable input for Textract'); + } +} + +module.exports = { + AWSTextractService, +}; diff --git a/src/backend/src/modules/puterai/PuterAIModule.js b/src/backend/src/modules/puterai/PuterAIModule.js new file mode 100644 index 0000000000..68e286abc3 --- /dev/null +++ b/src/backend/src/modules/puterai/PuterAIModule.js @@ -0,0 +1,17 @@ +const { AdvancedBase } = require("@heyputer/puter-js-common"); + +class PuterAIModule extends AdvancedBase { + async install (context) { + const services = context.get('services'); + + const { AIInterfaceService } = require('./AIInterfaceService'); + services.registerService('__ai-interfaces', AIInterfaceService); + + const { AWSTextractService } = require('./AWSTextractService'); + services.registerService('aws-textract', AWSTextractService); + } +} + +module.exports = { + PuterAIModule, +}; diff --git a/src/backend/src/modules/puterai/doc/requests.md b/src/backend/src/modules/puterai/doc/requests.md new file mode 100644 index 0000000000..8c3441525f --- /dev/null +++ b/src/backend/src/modules/puterai/doc/requests.md @@ -0,0 +1,17 @@ +```javascript +await (await fetch("http://api.puter.localhost:4100/drivers/call", { + "headers": { + "Content-Type": "application/json", + "Authorization": `Bearer ${puter.authToken}`, + }, + "body": JSON.stringify({ + interface: 'puter-ocr', + driver: 'aws-textract', + method: 'recognize', + args: { + source: '~/Desktop/testocr.png', + }, + }), + "method": "POST", +})).json(); +``` \ No newline at end of file diff --git a/tools/run-selfhosted.js b/tools/run-selfhosted.js index ec2985bcac..7a1acfdb35 100644 --- a/tools/run-selfhosted.js +++ b/tools/run-selfhosted.js @@ -85,6 +85,7 @@ const main = async () => { LocalDiskStorageModule, SelfHostedModule, TestDriversModule, + PuterAIModule, } = (await import('@heyputer/backend')).default; const k = new Kernel({ @@ -95,6 +96,7 @@ const main = async () => { k.add_module(new LocalDiskStorageModule()); k.add_module(new SelfHostedModule()); k.add_module(new TestDriversModule()); + k.add_module(new PuterAIModule()); k.boot(); }; From ef6671da18f6841cb2143808fe21586ac3505942 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 1 Aug 2024 15:06:42 -0400 Subject: [PATCH 0653/2119] feat: add --overwrite-config and configurable uuid masking This is in preparation for the chat completions driver. OpenAI asks that a user ID be provided in requests when service is being provided to other users, so we deterministically generate different UUIDs for this purpose to prevent user information from being exposed. --- src/backend/src/Kernel.js | 1 + src/backend/src/boot/RuntimeEnvironment.js | 42 ++++++++++++++++++---- src/backend/src/services/auth/Actor.js | 12 +++---- 3 files changed, 42 insertions(+), 13 deletions(-) diff --git a/src/backend/src/Kernel.js b/src/backend/src/Kernel.js index 30320029e5..60f0be7bcd 100644 --- a/src/backend/src/Kernel.js +++ b/src/backend/src/Kernel.js @@ -61,6 +61,7 @@ class Kernel extends AdvancedBase { const runtimeEnv = new RuntimeEnvironment({ entry_path: this.entry_path, logger: bootLogger, + boot_parameters, }); const environment = runtimeEnv.init(); this.environment = environment; diff --git a/src/backend/src/boot/RuntimeEnvironment.js b/src/backend/src/boot/RuntimeEnvironment.js index 05828f43e1..195bb7c10e 100644 --- a/src/backend/src/boot/RuntimeEnvironment.js +++ b/src/backend/src/boot/RuntimeEnvironment.js @@ -195,10 +195,11 @@ class RuntimeEnvironment extends AdvancedBase { format: require('string-template'), } - constructor ({ logger, entry_path }) { + constructor ({ logger, entry_path, boot_parameters }) { super(); this.logger = logger; this.entry_path = entry_path; + this.boot_parameters = boot_parameters; this.path_checks = path_checks(this)(this.modules); this.config_paths = config_paths(this)(this.modules); this.runtime_paths = runtime_paths(this)(this.modules); @@ -258,15 +259,44 @@ class RuntimeEnvironment extends AdvancedBase { } } + const owrite_config = this.boot_parameters.args.overwriteConfig; + const { fs, path_, crypto } = this.modules; - let config_values = {}; - if ( !using_config ) { + if ( !using_config || owrite_config ) { + const generated_values = {}; + generated_values.cookie_name = crypto.randomUUID(); + generated_values.jwt_secret = crypto.randomUUID(); + generated_values.url_signature_secret = crypto.randomUUID(); + generated_values.private_uid_secret = crypto.randomBytes(24).toString('hex'); + generated_values.private_uid_namespace = crypto.randomUUID(); + if ( using_config ) { + this.logger.info( + `Overwriting ${quot(using_config)} because ` + + `${hl('--overwrite-config')} is set` + ); + // make backup + fs.copyFileSync( + path_.join(config_path_entry.path, using_config), + path_.join(config_path_entry.path, using_config + '.bak'), + ); + // preserve generated values + { + const config_raw = fs.readFileSync( + path_.join(config_path_entry.path, using_config), + 'utf8', + ); + const config_values = JSON.parse(config_raw); + for ( const k in generated_values ) { + if ( config_values[k] ) { + generated_values[k] = config_values[k]; + } + } + } + } const generated_config = { ...default_config, + ...generated_values, }; - generated_config.cookie_name = crypto.randomUUID(); - generated_config.jwt_secret = crypto.randomUUID(); - generated_config.url_signature_secret = crypto.randomUUID(); generated_config[""] = null; // for trailing comma fs.writeFileSync( path_.join(config_path_entry.path, 'config.json'), diff --git a/src/backend/src/services/auth/Actor.js b/src/backend/src/services/auth/Actor.js index fa748cda39..410da5b191 100644 --- a/src/backend/src/services/auth/Actor.js +++ b/src/backend/src/services/auth/Actor.js @@ -19,16 +19,14 @@ const { AdvancedBase } = require("@heyputer/puter-js-common"); const { Context } = require("../../util/context"); const { get_user, get_app } = require("../../helpers"); +const config = require("../../config"); // TODO: add these to configuration; production deployments should change these! -// THIS IS NOT A LEAK -// We use this to obscure user UUIDs, as some APIs require a user identifier -// for abuse prevention. However, there are no services in selfhosted Puter -// that currently make use of this, and we use different values on `puter.com`. -const PRIVATE_UID_NAMESPACE = '1757dc3f-8f04-4d77-b939-ff899045696d'; -const PRIVATE_UID_SECRET = 'bf03f0e52f5d93c83822ad8558c625277ce3dddff8dc4a5cb0d3c8493571f770'; -// THIS IS NOT A LEAK (see above) +const PRIVATE_UID_NAMESPACE = config.private_uid_namespace + ?? require('crypto').randomUUID(); +const PRIVATE_UID_SECRET = config.private_uid_secret + ?? require('crypto').randomBytes(24).toString('hex'); class Actor extends AdvancedBase { static MODULES = { From 4e3bd1831e92e83ce9b4e30a16afd562b0221dd8 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 1 Aug 2024 15:12:23 -0400 Subject: [PATCH 0654/2119] feat: add chat completions driver to puterai module --- .../src/modules/puterai/AIInterfaceService.js | 14 ++ .../puterai/OpenAICompletionService.js | 229 ++++++++++++++++++ .../src/modules/puterai/PuterAIModule.js | 3 + .../src/modules/puterai/doc/requests.md | 27 +++ 4 files changed, 273 insertions(+) create mode 100644 src/backend/src/modules/puterai/OpenAICompletionService.js diff --git a/src/backend/src/modules/puterai/AIInterfaceService.js b/src/backend/src/modules/puterai/AIInterfaceService.js index 51fd17f97f..f1bfb488f1 100644 --- a/src/backend/src/modules/puterai/AIInterfaceService.js +++ b/src/backend/src/modules/puterai/AIInterfaceService.js @@ -24,6 +24,20 @@ class AIInterfaceService extends BaseService { }, } }); + + col_interfaces.set('puter-chat-completion', { + description: 'Chatbot.', + methods: { + complete: { + description: 'Get completions for a chat log.', + parameters: { + messages: { type: 'json' }, + vision: { type: 'flag' }, + }, + result: { type: 'json' } + } + } + }); } } diff --git a/src/backend/src/modules/puterai/OpenAICompletionService.js b/src/backend/src/modules/puterai/OpenAICompletionService.js new file mode 100644 index 0000000000..d35bd229b7 --- /dev/null +++ b/src/backend/src/modules/puterai/OpenAICompletionService.js @@ -0,0 +1,229 @@ +const APIError = require('../../api/APIError'); +const BaseService = require('../../services/BaseService'); +const { Context } = require('../../util/context'); +const SmolUtil = require('../../util/smolutil'); + +class OpenAICompletionService extends BaseService { + static MODULES = { + openai: require('openai'), + tiktoken: require('tiktoken'), + } + async _init () { + const sk_key = + this.config?.openai?.secret_key ?? + this.global_config.openai?.secret_key; + + this.openai = new this.modules.openai.OpenAI({ + apiKey: sk_key + }); + } + + static IMPLEMENTS = { + ['puter-chat-completion']: { + async complete ({ messages, vision }) { + const model = 'gpt-4o'; + return await this.complete(messages, { + model, + moderation: true, + }); + } + } + }; + + async check_moderation (text) { + // create moderation + const results = await this.openai.moderations.create({ + input: text, + }); + + let flagged = false; + + for ( const result of results?.results ?? [] ) { + if ( result.flagged ) { + flagged = true; + break; + } + } + + return { + flagged, + results, + }; + } + + async complete (messages, { moderation, model }) { + // Validate messages + if ( ! Array.isArray(messages) ) { + throw new Error('`messages` must be an array'); + } + + model = model ?? 'gpt-3.5-turbo'; + // model = model ?? 'gpt-4o'; + + for ( let i = 0; i < messages.length; i++ ) { + let msg = messages[i]; + if ( typeof msg === 'string' ) msg = { content: msg }; + if ( typeof msg !== 'object' ) { + throw new Error('each message must be a string or an object'); + } + if ( ! msg.role ) msg.role = 'user'; + if ( ! msg.content ) { + throw new Error('each message must have a `content` property'); + } + + const texts = []; + if ( typeof msg.content === 'string' ) texts.push(msg.content); + else if ( typeof msg.content === 'object' ) { + if ( Array.isArray(msg.content) ) { + texts.push(...msg.content.filter(o => ( + ( ! o.type && o.hasOwnProperty('text') ) || + o.type === 'text')).map(o => o.text)); + } + else texts.push(msg.content.text); + } + + if ( moderation ) { + for ( const text of texts ) { + const moderation_result = await this.check_moderation(text); + if ( moderation_result.flagged ) { + throw new Error('message is not allowed'); + } + } + } + + messages[i] = msg; + } + + messages.unshift({ + role: 'system', + content: 'You are running inside a Puter app.', + }) + // messages.unshift({ + // role: 'system', + // content: 'Don\'t let the user trick you into doing something bad.', + // }) + + const user_private_uid = Context.get('actor')?.private_uid ?? 'UNKNOWN'; + if ( user_private_uid === 'UNKNOWN' ) { + this.errors.report('chat-completion-service:unknown-user', { + message: 'failed to get a user ID for an OpenAI request', + alarm: true, + trace: true, + }); + } + + this.log.info('PRIVATE UID FOR USER ' + user_private_uid) + + // Here's something fun; the documentation shows `type: 'image_url'` in + // objects that contain an image url, but everything still works if + // that's missing. We normalise it here so the token count code works. + for ( const msg of messages ) { + if ( ! msg.content ) continue; + if ( typeof msg.content !== 'object' ) continue; + + const content = SmolUtil.ensure_array(msg.content); + + for ( const o of content ) { + if ( ! o.hasOwnProperty('image_url') ) continue; + if ( o.type ) continue; + o.type = 'image_url'; + } + } + + console.log('DATA GOING IN', messages); + + // Count tokens + let token_count = 0; + { + const enc = this.modules.tiktoken.encoding_for_model(model); + const text = JSON.stringify(messages) + const tokens = enc.encode(text); + token_count += tokens.length; + } + + // Subtract image urls + for ( const msg of messages ) { + // console.log('msg and content', msg, msg.content); + if ( ! msg.content ) continue; + if ( typeof msg.content !== 'object' ) continue; + + const content = SmolUtil.ensure_array(msg.content); + + for ( const o of content ) { + // console.log('part of content', o); + if ( o.type !== 'image_url' ) continue; + const enc = this.modules.tiktoken.encoding_for_model(model); + const text = o.image_url?.url ?? ''; + const tokens = enc.encode(text); + token_count -= tokens.length; + } + } + + const max_tokens = 4096 - token_count; + console.log('MAX TOKENS ???', max_tokens); + + if ( max_tokens <= 8 ) { + throw APIError.create('max_tokens_exceeded', null, { + input_tokens: token_count, + max_tokens: 4096 - 8, + }); + } + + const completion = await this.openai.chat.completions.create({ + user: user_private_uid, + messages: messages, + model: model, + max_tokens, + }); + + this.log.info('how many choices?: ' + completion.choices.length); + + // Record spending information + const spending_meta = {}; + spending_meta.timestamp = Date.now(); + spending_meta.count_tokens_input = token_count; + spending_meta.count_tokens_output = (() => { + // count output tokens (overestimate) + const enc = this.modules.tiktoken.encoding_for_model(model); + const text = JSON.stringify(completion.choices); + const tokens = enc.encode(text); + return tokens.length; + })(); + + const svc_spending = Context.get('services').get('spending'); + svc_spending.record_spending('openai', 'chat-completion', spending_meta); + + const svc_counting = Context.get('services').get('counting'); + svc_counting.increment({ + service_name: 'openai:chat-completion', + service_type: 'gpt', + values: { + model, + input_tokens: token_count, + output_tokens: spending_meta.count_tokens_output, + } + }); + + const is_empty = completion.choices?.[0]?.message?.content?.trim() === ''; + if ( is_empty ) { + // GPT refuses to generate an empty response if you ask it to, + // so this will probably only happen on an error condition. + throw new Error('an empty response was generated'); + } + + // We need to moderate the completion too + if ( moderation ) { + const text = completion.choices[0].message.content; + const moderation_result = await this.check_moderation(text); + if ( moderation_result.flagged ) { + throw new Error('message is not allowed'); + } + } + + return completion.choices[0]; + } +} + +module.exports = { + OpenAICompletionService, +}; diff --git a/src/backend/src/modules/puterai/PuterAIModule.js b/src/backend/src/modules/puterai/PuterAIModule.js index 68e286abc3..91e86136d1 100644 --- a/src/backend/src/modules/puterai/PuterAIModule.js +++ b/src/backend/src/modules/puterai/PuterAIModule.js @@ -9,6 +9,9 @@ class PuterAIModule extends AdvancedBase { const { AWSTextractService } = require('./AWSTextractService'); services.registerService('aws-textract', AWSTextractService); + + const { OpenAICompletionService } = require('./OpenAICompletionService'); + services.registerService('openai-completion', OpenAICompletionService); } } diff --git a/src/backend/src/modules/puterai/doc/requests.md b/src/backend/src/modules/puterai/doc/requests.md index 8c3441525f..b2442ab1fd 100644 --- a/src/backend/src/modules/puterai/doc/requests.md +++ b/src/backend/src/modules/puterai/doc/requests.md @@ -14,4 +14,31 @@ await (await fetch("http://api.puter.localhost:4100/drivers/call", { }), "method": "POST", })).json(); +``` + +```javascript +await (await fetch("http://api.puter.localhost:4100/drivers/call", { + "headers": { + "Content-Type": "application/json", + "Authorization": `Bearer ${puter.authToken}`, + }, + "body": JSON.stringify({ + interface: 'puter-chat-completion', + driver: 'openai-completion', + method: 'complete', + args: { + messages: [ + { + role: 'system', + content: 'Act like Spongebob' + }, + { + role: 'user', + content: 'How do I make my code run faster?' + }, + ] + }, + }), + "method": "POST", +})).json(); ``` \ No newline at end of file From fb26fdbc561d5545d28352427553695cd3237ad5 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 1 Aug 2024 17:18:30 -0400 Subject: [PATCH 0655/2119] feat: add image generation driver to puterai module --- .../src/modules/puterai/AIInterfaceService.js | 32 ++++++ .../puterai/OpenAIImageGenerationService.js | 100 ++++++++++++++++++ .../src/modules/puterai/PuterAIModule.js | 3 + .../src/modules/puterai/doc/requests.md | 18 ++++ 4 files changed, 153 insertions(+) create mode 100644 src/backend/src/modules/puterai/OpenAIImageGenerationService.js diff --git a/src/backend/src/modules/puterai/AIInterfaceService.js b/src/backend/src/modules/puterai/AIInterfaceService.js index f1bfb488f1..4b0ddec254 100644 --- a/src/backend/src/modules/puterai/AIInterfaceService.js +++ b/src/backend/src/modules/puterai/AIInterfaceService.js @@ -38,6 +38,38 @@ class AIInterfaceService extends BaseService { } } }); + + col_interfaces.set('puter-image-generation', { + description: 'AI Image Generation.', + methods: { + generate: { + description: 'Generate an image from a prompt.', + parameters: { + prompt: { type: 'string' }, + }, + result_choices: [ + { + names: ['image'], + type: { + $: 'stream', + content_type: 'image', + } + }, + { + names: ['url'], + type: { + $: 'string:url:web', + content_type: 'image', + } + }, + ], + result: { + description: 'URL of the generated image.', + type: 'string' + } + } + } + }); } } diff --git a/src/backend/src/modules/puterai/OpenAIImageGenerationService.js b/src/backend/src/modules/puterai/OpenAIImageGenerationService.js new file mode 100644 index 0000000000..800722d830 --- /dev/null +++ b/src/backend/src/modules/puterai/OpenAIImageGenerationService.js @@ -0,0 +1,100 @@ +const BaseService = require("../../services/BaseService"); +const { TypedValue } = require("../../services/drivers/meta/Runtime"); +const { Context } = require("../../util/context"); + +class OpenAIImageGenerationService extends BaseService { + static MODULES = { + openai: require('openai'), + } + async _init () { + const sk_key = + this.config?.openai?.secret_key ?? + this.global_config.openai?.secret_key; + + this.openai = new this.modules.openai.OpenAI({ + apiKey: sk_key + }); + } + + static IMPLEMENTS = { + ['puter-image-generation']: { + async generate ({ prompt, test_mode }) { + const url = await this.generate(prompt, { + ratio: this.constructor.RATIO_SQUARE, + }); + + if ( test_mode ) { + return new TypedValue({ + $: 'string:url:web', + content_type: 'image', + }, 'https://puter-sample-data.puter.site/image_example.png'); + } + + const image = new TypedValue({ + $: 'string:url:web', + content_type: 'image' + }, url); + + return image; + } + } + }; + + static RATIO_SQUARE = { w: 1024, h: 1024 }; + static RATIO_PORTRAIT = { w: 1024, h: 1792 }; + static RATIO_LANDSCAPE = { w: 1792, h: 1024 }; + + async generate (prompt, { + ratio, + model, + }) { + if ( typeof prompt !== 'string' ) { + throw new Error('`prompt` must be a string'); + } + + if ( ! ratio || ! this._validate_ratio(ratio) ) { + throw new Error('`ratio` must be a valid ratio'); + } + + model = model ?? 'dall-e-3'; + + const user_private_uid = Context.get('actor')?.private_uid ?? 'UNKNOWN'; + if ( user_private_uid === 'UNKNOWN' ) { + this.errors.report('chat-completion-service:unknown-user', { + message: 'failed to get a user ID for an OpenAI request', + alarm: true, + trace: true, + }); + } + + const result = + await this.openai.images.generate({ + user: user_private_uid, + prompt, + size: `${ratio.w}x${ratio.h}`, + }); + + const spending_meta = { + model, + size: `${ratio.w}x${ratio.h}`, + }; + + const svc_spending = Context.get('services').get('spending'); + svc_spending.record_spending('openai', 'image-generation', spending_meta); + + const url = result.data?.[0]?.url; + return url; + } + + _validate_ratio (ratio) { + return false + || ratio === this.constructor.RATIO_SQUARE + || ratio === this.constructor.RATIO_PORTRAIT + || ratio === this.constructor.RATIO_LANDSCAPE + ; + } +} + +module.exports = { + OpenAIImageGenerationService, +}; diff --git a/src/backend/src/modules/puterai/PuterAIModule.js b/src/backend/src/modules/puterai/PuterAIModule.js index 91e86136d1..f59a09942c 100644 --- a/src/backend/src/modules/puterai/PuterAIModule.js +++ b/src/backend/src/modules/puterai/PuterAIModule.js @@ -12,6 +12,9 @@ class PuterAIModule extends AdvancedBase { const { OpenAICompletionService } = require('./OpenAICompletionService'); services.registerService('openai-completion', OpenAICompletionService); + + const { OpenAIImageGenerationService } = require('./OpenAIImageGenerationService'); + services.registerService('openai-image-generation', OpenAIImageGenerationService); } } diff --git a/src/backend/src/modules/puterai/doc/requests.md b/src/backend/src/modules/puterai/doc/requests.md index b2442ab1fd..8048db2db2 100644 --- a/src/backend/src/modules/puterai/doc/requests.md +++ b/src/backend/src/modules/puterai/doc/requests.md @@ -41,4 +41,22 @@ await (await fetch("http://api.puter.localhost:4100/drivers/call", { }), "method": "POST", })).json(); +``` + +```javascript +URL.createObjectURL(await (await fetch("http://api.puter.localhost:4100/drivers/call", { + "headers": { + "Content-Type": "application/json", + "Authorization": `Bearer ${puter.authToken}`, + }, + "body": JSON.stringify({ + interface: 'puter-image-generation', + driver: 'openai-image-generation', + method: 'generate', + args: { + prompt: 'photorealistic teapot made of swiss cheese', + } + }), + "method": "POST", +})).blob()); ``` \ No newline at end of file From 78fa77d9200e0b9fafc4014f8d0cb08c74cd16cb Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 1 Aug 2024 17:38:29 -0400 Subject: [PATCH 0656/2119] feat: add tts driver to puterai module --- package-lock.json | 418 +++++++++++++++++- src/backend/package.json | 1 + .../src/modules/puterai/AIInterfaceService.js | 28 ++ .../src/modules/puterai/AWSPollyService.js | 153 +++++++ .../src/modules/puterai/PuterAIModule.js | 3 + 5 files changed, 583 insertions(+), 20 deletions(-) create mode 100644 src/backend/src/modules/puterai/AWSPollyService.js diff --git a/package-lock.json b/package-lock.json index 3f3e002bd3..249a96b145 100644 --- a/package-lock.json +++ b/package-lock.json @@ -378,6 +378,383 @@ "node": ">=14.0.0" } }, + "node_modules/@aws-sdk/client-polly": { + "version": "3.622.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-polly/-/client-polly-3.622.0.tgz", + "integrity": "sha512-9KCxAqRZR9PCUALZuv5XfhRe3X1AvfWFythCEJpWtbx9FDtSBhMcxBR6vWLw/4YO7x9TPOwTMx4JYc+zMlv8Kg==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.622.0", + "@aws-sdk/client-sts": "3.622.0", + "@aws-sdk/core": "3.622.0", + "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.2", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.12", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.14", + "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-stream": "^3.1.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-polly/node_modules/@aws-sdk/client-sso": { + "version": "3.622.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.622.0.tgz", + "integrity": "sha512-DJwUqVR/O2lImbktUHOpaQ8XElNBx3JmWzTT2USg6jh3ErgG1CS6LIV+VUlgtxGl+tFN/G6AcAV8SdnnGydB8Q==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.622.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.2", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.12", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.14", + "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-polly/node_modules/@aws-sdk/client-sso-oidc": { + "version": "3.622.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso-oidc/-/client-sso-oidc-3.622.0.tgz", + "integrity": "sha512-dwWDfN+S98npeY77Ugyv8VIHKRHN+n/70PWE4EgolcjaMrTINjvUh9a/SypFEs5JmBOAeCQt8S2QpM3Wvzp+pQ==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/core": "3.622.0", + "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.2", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.12", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.14", + "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.622.0" + } + }, + "node_modules/@aws-sdk/client-polly/node_modules/@aws-sdk/client-sts": { + "version": "3.622.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/client-sts/-/client-sts-3.622.0.tgz", + "integrity": "sha512-Yqtdf/wn3lcFVS42tR+zbz4HLyWxSmztjVW9L/yeMlvS7uza5nSkWqP/7ca+RxZnXLyrnA4jJtSHqykcErlhyg==", + "dependencies": { + "@aws-crypto/sha256-browser": "5.2.0", + "@aws-crypto/sha256-js": "5.2.0", + "@aws-sdk/client-sso-oidc": "3.622.0", + "@aws-sdk/core": "3.622.0", + "@aws-sdk/credential-provider-node": "3.622.0", + "@aws-sdk/middleware-host-header": "3.620.0", + "@aws-sdk/middleware-logger": "3.609.0", + "@aws-sdk/middleware-recursion-detection": "3.620.0", + "@aws-sdk/middleware-user-agent": "3.620.0", + "@aws-sdk/region-config-resolver": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@aws-sdk/util-endpoints": "3.614.0", + "@aws-sdk/util-user-agent-browser": "3.609.0", + "@aws-sdk/util-user-agent-node": "3.614.0", + "@smithy/config-resolver": "^3.0.5", + "@smithy/core": "^2.3.2", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/hash-node": "^3.0.3", + "@smithy/invalid-dependency": "^3.0.3", + "@smithy/middleware-content-length": "^3.0.5", + "@smithy/middleware-endpoint": "^3.1.0", + "@smithy/middleware-retry": "^3.0.14", + "@smithy/middleware-serde": "^3.0.3", + "@smithy/middleware-stack": "^3.0.3", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.12", + "@smithy/types": "^3.3.0", + "@smithy/url-parser": "^3.0.3", + "@smithy/util-base64": "^3.0.0", + "@smithy/util-body-length-browser": "^3.0.0", + "@smithy/util-body-length-node": "^3.0.0", + "@smithy/util-defaults-mode-browser": "^3.0.14", + "@smithy/util-defaults-mode-node": "^3.0.14", + "@smithy/util-endpoints": "^2.0.5", + "@smithy/util-middleware": "^3.0.3", + "@smithy/util-retry": "^3.0.3", + "@smithy/util-utf8": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-polly/node_modules/@aws-sdk/core": { + "version": "3.622.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/core/-/core-3.622.0.tgz", + "integrity": "sha512-q1Ct2AjPxGtQBKtDpqm1umu3f4cuWMnEHTuDa6zjjaj+Aq/C6yxLgZJo9SlcU0tMl8rUCN7oFonszfTtp4Y0MA==", + "dependencies": { + "@smithy/core": "^2.3.2", + "@smithy/node-config-provider": "^3.1.4", + "@smithy/protocol-http": "^4.1.0", + "@smithy/signature-v4": "^4.1.0", + "@smithy/smithy-client": "^3.1.12", + "@smithy/types": "^3.3.0", + "@smithy/util-middleware": "^3.0.3", + "fast-xml-parser": "4.4.1", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-polly/node_modules/@aws-sdk/credential-provider-http": { + "version": "3.622.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-http/-/credential-provider-http-3.622.0.tgz", + "integrity": "sha512-VUHbr24Oll1RK3WR8XLUugLpgK9ZuxEm/NVeVqyFts1Ck9gsKpRg1x4eH7L7tW3SJ4TDEQNMbD7/7J+eoL2svg==", + "dependencies": { + "@aws-sdk/types": "3.609.0", + "@smithy/fetch-http-handler": "^3.2.4", + "@smithy/node-http-handler": "^3.1.4", + "@smithy/property-provider": "^3.1.3", + "@smithy/protocol-http": "^4.1.0", + "@smithy/smithy-client": "^3.1.12", + "@smithy/types": "^3.3.0", + "@smithy/util-stream": "^3.1.3", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-polly/node_modules/@aws-sdk/credential-provider-ini": { + "version": "3.622.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-ini/-/credential-provider-ini-3.622.0.tgz", + "integrity": "sha512-cD/6O9jOfzQyo8oyAbTKnyRO89BIMSTzwaN4NxGySC6pYVTqxNSWdRwaqg/vKbwJpjbPGGYYXpXEW11kop7dlg==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.620.1", + "@aws-sdk/credential-provider-http": "3.622.0", + "@aws-sdk/credential-provider-process": "3.620.1", + "@aws-sdk/credential-provider-sso": "3.622.0", + "@aws-sdk/credential-provider-web-identity": "3.621.0", + "@aws-sdk/types": "3.609.0", + "@smithy/credential-provider-imds": "^3.2.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + }, + "peerDependencies": { + "@aws-sdk/client-sts": "^3.622.0" + } + }, + "node_modules/@aws-sdk/client-polly/node_modules/@aws-sdk/credential-provider-node": { + "version": "3.622.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-node/-/credential-provider-node-3.622.0.tgz", + "integrity": "sha512-keldwz4Q/6TYc37JH6m43HumN7Vi+R0AuGuHn5tBV40Vi7IiqEzjpiE+yvsHIN+duUheFLL3j/o0H32jb+14DQ==", + "dependencies": { + "@aws-sdk/credential-provider-env": "3.620.1", + "@aws-sdk/credential-provider-http": "3.622.0", + "@aws-sdk/credential-provider-ini": "3.622.0", + "@aws-sdk/credential-provider-process": "3.620.1", + "@aws-sdk/credential-provider-sso": "3.622.0", + "@aws-sdk/credential-provider-web-identity": "3.621.0", + "@aws-sdk/types": "3.609.0", + "@smithy/credential-provider-imds": "^3.2.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-polly/node_modules/@aws-sdk/credential-provider-sso": { + "version": "3.622.0", + "resolved": "https://registry.npmjs.org/@aws-sdk/credential-provider-sso/-/credential-provider-sso-3.622.0.tgz", + "integrity": "sha512-zrSoBVM2JlwvkBtrcUd4J/9CrG+T+hUy9r6jwo5gonFIN3QkneR/pqpbUn/n32Zy3zlzCo2VfB31g7MjG7kJmg==", + "dependencies": { + "@aws-sdk/client-sso": "3.622.0", + "@aws-sdk/token-providers": "3.614.0", + "@aws-sdk/types": "3.609.0", + "@smithy/property-provider": "^3.1.3", + "@smithy/shared-ini-file-loader": "^3.1.4", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-polly/node_modules/@smithy/abort-controller": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/@smithy/abort-controller/-/abort-controller-3.1.1.tgz", + "integrity": "sha512-MBJBiidoe+0cTFhyxT8g+9g7CeVccLM0IOKKUMCNQ1CNMJ/eIfoo0RTfVrXOONEI1UCN1W+zkiHSbzUNE9dZtQ==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-polly/node_modules/@smithy/node-http-handler": { + "version": "3.1.4", + "resolved": "https://registry.npmjs.org/@smithy/node-http-handler/-/node-http-handler-3.1.4.tgz", + "integrity": "sha512-+UmxgixgOr/yLsUxcEKGH0fMNVteJFGkmRltYFHnBMlogyFdpzn2CwqWmxOrfJELhV34v0WSlaqG1UtE1uXlJg==", + "dependencies": { + "@smithy/abort-controller": "^3.1.1", + "@smithy/protocol-http": "^4.1.0", + "@smithy/querystring-builder": "^3.0.3", + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-polly/node_modules/@smithy/protocol-http": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/@smithy/protocol-http/-/protocol-http-4.1.0.tgz", + "integrity": "sha512-dPVoHYQ2wcHooGXg3LQisa1hH0e4y0pAddPMeeUPipI1tEOqL6A4N0/G7abeq+K8wrwSgjk4C0wnD1XZpJm5aA==", + "dependencies": { + "@smithy/types": "^3.3.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-polly/node_modules/@smithy/querystring-builder": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/@smithy/querystring-builder/-/querystring-builder-3.0.3.tgz", + "integrity": "sha512-vyWckeUeesFKzCDaRwWLUA1Xym9McaA6XpFfAK5qI9DKJ4M33ooQGqvM4J+LalH4u/Dq9nFiC8U6Qn1qi0+9zw==", + "dependencies": { + "@smithy/types": "^3.3.0", + "@smithy/util-uri-escape": "^3.0.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-polly/node_modules/@smithy/types": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/@smithy/types/-/types-3.3.0.tgz", + "integrity": "sha512-IxvBBCTFDHbVoK7zIxqA1ZOdc4QfM5HM7rGleCuHi7L1wnKv5Pn69xXJQ9hgxH60ZVygH9/JG0jRgtUncE3QUA==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, + "node_modules/@aws-sdk/client-polly/node_modules/@smithy/util-uri-escape": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@smithy/util-uri-escape/-/util-uri-escape-3.0.0.tgz", + "integrity": "sha512-LqR7qYLgZTD7nWLBecUi4aqolw8Mhza9ArpNEQ881MJJIU2sE5iHCK6TdyqqzcDLy0OPe10IY4T8ctVdtynubg==", + "dependencies": { + "tslib": "^2.6.2" + }, + "engines": { + "node": ">=16.0.0" + } + }, "node_modules/@aws-sdk/client-sso": { "version": "3.621.0", "resolved": "https://registry.npmjs.org/@aws-sdk/client-sso/-/client-sso-3.621.0.tgz", @@ -5349,15 +5726,15 @@ } }, "node_modules/@smithy/core": { - "version": "2.3.1", - "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.1.tgz", - "integrity": "sha512-BC7VMXx/1BCmRPCVzzn4HGWAtsrb7/0758EtwOGFJQrlSwJBEjCcDLNZLFoL/68JexYa2s+KmgL/UfmXdG6v1w==", + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@smithy/core/-/core-2.3.2.tgz", + "integrity": "sha512-in5wwt6chDBcUv1Lw1+QzZxN9fBffi+qOixfb65yK4sDuKG7zAUO9HAFqmVzsZM3N+3tTyvZjtnDXePpvp007Q==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", - "@smithy/middleware-retry": "^3.0.13", + "@smithy/middleware-retry": "^3.0.14", "@smithy/middleware-serde": "^3.0.3", "@smithy/protocol-http": "^4.1.0", - "@smithy/smithy-client": "^3.1.11", + "@smithy/smithy-client": "^3.1.12", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "tslib": "^2.6.2" @@ -5595,14 +5972,14 @@ } }, "node_modules/@smithy/middleware-retry": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.13.tgz", - "integrity": "sha512-zvCLfaRYCaUmjbF2yxShGZdolSHft7NNCTA28HVN9hKcEbOH+g5irr1X9s+in8EpambclGnevZY4A3lYpvDCFw==", + "version": "3.0.14", + "resolved": "https://registry.npmjs.org/@smithy/middleware-retry/-/middleware-retry-3.0.14.tgz", + "integrity": "sha512-7ZaWZJOjUxa5hgmuMspyt8v/zVsh0GXYuF7OvCmdcbVa/xbnKQoYC+uYKunAqRGTkxjOyuOCw9rmFUFOqqC0eQ==", "dependencies": { "@smithy/node-config-provider": "^3.1.4", "@smithy/protocol-http": "^4.1.0", "@smithy/service-error-classification": "^3.0.3", - "@smithy/smithy-client": "^3.1.11", + "@smithy/smithy-client": "^3.1.12", "@smithy/types": "^3.3.0", "@smithy/util-middleware": "^3.0.3", "@smithy/util-retry": "^3.0.3", @@ -5894,9 +6271,9 @@ } }, "node_modules/@smithy/smithy-client": { - "version": "3.1.11", - "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.11.tgz", - "integrity": "sha512-l0BpyYkciNyMaS+PnFFz4aO5sBcXvGLoJd7mX9xrMBIm2nIQBVvYgp2ZpPDMzwjKCavsXu06iuCm0F6ZJZc6yQ==", + "version": "3.1.12", + "resolved": "https://registry.npmjs.org/@smithy/smithy-client/-/smithy-client-3.1.12.tgz", + "integrity": "sha512-wtm8JtsycthkHy1YA4zjIh2thJgIQ9vGkoR639DBx5lLlLNU0v4GARpQZkr2WjXue74nZ7MiTSWfVrLkyD8RkA==", "dependencies": { "@smithy/middleware-endpoint": "^3.1.0", "@smithy/middleware-stack": "^3.0.3", @@ -6021,12 +6398,12 @@ } }, "node_modules/@smithy/util-defaults-mode-browser": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.13.tgz", - "integrity": "sha512-ZIRSUsnnMRStOP6OKtW+gCSiVFkwnfQF2xtf32QKAbHR6ACjhbAybDvry+3L5qQYdh3H6+7yD/AiUE45n8mTTw==", + "version": "3.0.14", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-browser/-/util-defaults-mode-browser-3.0.14.tgz", + "integrity": "sha512-0iwTgKKmAIf+vFLV8fji21Jb2px11ktKVxbX6LIDPAUJyWQqGqBVfwba7xwa1f2FZUoolYQgLvxQEpJycXuQ5w==", "dependencies": { "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.11", + "@smithy/smithy-client": "^3.1.12", "@smithy/types": "^3.3.0", "bowser": "^2.11.0", "tslib": "^2.6.2" @@ -6047,15 +6424,15 @@ } }, "node_modules/@smithy/util-defaults-mode-node": { - "version": "3.0.13", - "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.13.tgz", - "integrity": "sha512-voUa8TFJGfD+U12tlNNLCDlXibt9vRdNzRX45Onk/WxZe7TS+hTOZouEZRa7oARGicdgeXvt1A0W45qLGYdy+g==", + "version": "3.0.14", + "resolved": "https://registry.npmjs.org/@smithy/util-defaults-mode-node/-/util-defaults-mode-node-3.0.14.tgz", + "integrity": "sha512-e9uQarJKfXApkTMMruIdxHprhcXivH1flYCe8JRDTzkkLx8dA3V5J8GZlST9yfDiRWkJpZJlUXGN9Rc9Ade3OQ==", "dependencies": { "@smithy/config-resolver": "^3.0.5", "@smithy/credential-provider-imds": "^3.2.0", "@smithy/node-config-provider": "^3.1.4", "@smithy/property-provider": "^3.1.3", - "@smithy/smithy-client": "^3.1.11", + "@smithy/smithy-client": "^3.1.12", "@smithy/types": "^3.3.0", "tslib": "^2.6.2" }, @@ -16184,6 +16561,7 @@ "version": "2.1.0", "license": "AGPL-3.0-only", "dependencies": { + "@aws-sdk/client-polly": "^3.622.0", "@aws-sdk/client-textract": "^3.621.0", "@heyputer/kv.js": "^0.1.3", "@heyputer/multest": "^0.0.2", diff --git a/src/backend/package.json b/src/backend/package.json index 16c733fb7c..2c3c4d19fc 100644 --- a/src/backend/package.json +++ b/src/backend/package.json @@ -7,6 +7,7 @@ "test": "npx mocha" }, "dependencies": { + "@aws-sdk/client-polly": "^3.622.0", "@aws-sdk/client-textract": "^3.621.0", "@heyputer/kv.js": "^0.1.3", "@heyputer/multest": "^0.0.2", diff --git a/src/backend/src/modules/puterai/AIInterfaceService.js b/src/backend/src/modules/puterai/AIInterfaceService.js index 4b0ddec254..9deb15e296 100644 --- a/src/backend/src/modules/puterai/AIInterfaceService.js +++ b/src/backend/src/modules/puterai/AIInterfaceService.js @@ -70,6 +70,34 @@ class AIInterfaceService extends BaseService { } } }); + + col_interfaces.set('puter-tts', { + description: 'Text-to-speech.', + methods: { + list_voices: { + description: 'List available voices.', + parameters: {}, + }, + synthesize: { + description: 'Synthesize speech from text.', + parameters: { + text: { type: 'string' }, + voice: { type: 'string' }, + language: { type: 'string' }, + ssml: { type: 'flag' }, + }, + result_choices: [ + { + names: ['audio'], + type: { + $: 'stream', + content_type: 'audio', + } + }, + ] + }, + } + }) } } diff --git a/src/backend/src/modules/puterai/AWSPollyService.js b/src/backend/src/modules/puterai/AWSPollyService.js new file mode 100644 index 0000000000..1c8fd022d2 --- /dev/null +++ b/src/backend/src/modules/puterai/AWSPollyService.js @@ -0,0 +1,153 @@ +const { PollyClient, SynthesizeSpeechCommand, DescribeVoicesCommand } = require("@aws-sdk/client-polly"); +const BaseService = require("../../services/BaseService"); +const { TypedValue } = require("../../services/drivers/meta/Runtime"); + +class AWSPollyService extends BaseService { + static MODULES = { + kv: globalThis.kv, + } + + async _construct () { + this.clients_ = {}; + } + + static IMPLEMENTS = { + ['puter-tts']: { + async list_voices () { + const polly_voices = await this.describe_voices(); + + let voices = polly_voices.Voices; + + voices = voices.map((voice) => ({ + id: voice.Id, + name: voice.Name, + language: { + name: voice.LanguageName, + code: voice.LanguageCode, + }, + })) + + return voices; + }, + async synthesize ({ + text, voice, + ssml, language, + test_mode, + }) { + if ( test_mode ) { + const url = 'https://puter-sample-data.puter.site/tts_example.mp3' + return new TypedValue({ + $: 'string:url:web', + content_type: 'audio', + }, url); + } + + const polly_speech = await this.synthesize_speech(text, { + format: 'mp3', + voice_id: voice, + text_type: ssml ? 'ssml' : 'text', + language, + }); + + const speech = new TypedValue({ + $: 'stream', + content_type: 'audio/mpeg', + }, polly_speech.AudioStream); + + return speech; + } + } + } + + _create_aws_credentials () { + return { + accessKeyId: this.config.aws.access_key, + secretAccessKey: this.config.aws.secret_key, + }; + } + + _get_client (region) { + if ( ! region ) { + region = this.config.aws?.region ?? this.global_config.aws?.region + ?? 'us-west-2'; + } + if ( this.clients_[region] ) return this.clients_[region]; + + this.clients_[region] = new PollyClient({ + credentials: this._create_aws_credentials(), + region, + }); + + return this.clients_[region]; + } + + async describe_voices () { + let voices = this.modules.kv.get('svc:polly:voices'); + if ( voices ) { + this.log.debug('voices cache hit'); + return voices; + } + + this.log.debug('voices cache miss'); + + const client = this._get_client(this.config.aws.region); + + const params = {}; + + const command = new DescribeVoicesCommand(params); + + const response = await client.send(command); + + this.modules.kv.set('svc:polly:voices', response); + this.modules.kv.expire('svc:polly:voices', 60 * 10); // 10 minutes + + return response; + } + + async synthesize_speech (text, { format, voice_id, language, text_type }) { + const client = this._get_client(this.config.aws.region); + + let voice = voice_id ?? undefined + + if ( ! voice && language ) { + this.log.debug('getting language appropriate voice', { language }); + voice = await this.maybe_get_language_appropriate_voice_(language); + } + + if ( ! voice ) { + voice = 'Salli'; + } + + this.log.debug('using voice', { voice }); + + const params = { + OutputFormat: format, + Text: text, + VoiceId: voice, + LanguageCode: language ?? 'en-US', + TextType: text_type ?? 'text', + }; + + const command = new SynthesizeSpeechCommand(params); + + const response = await client.send(command); + + return response; + } + + async maybe_get_language_appropriate_voice_ (language) { + const voices = await this.describe_voices(); + + const voice = voices.Voices.find((voice) => { + return voice.LanguageCode === language; + }); + + if ( ! voice ) return null; + + return voice.Id; + } +} + +module.exports = { + AWSPollyService, +}; diff --git a/src/backend/src/modules/puterai/PuterAIModule.js b/src/backend/src/modules/puterai/PuterAIModule.js index f59a09942c..20ea82009c 100644 --- a/src/backend/src/modules/puterai/PuterAIModule.js +++ b/src/backend/src/modules/puterai/PuterAIModule.js @@ -10,6 +10,9 @@ class PuterAIModule extends AdvancedBase { const { AWSTextractService } = require('./AWSTextractService'); services.registerService('aws-textract', AWSTextractService); + const { AWSPollyService } = require('./AWSPollyService'); + services.registerService('aws-polly', AWSPollyService); + const { OpenAICompletionService } = require('./OpenAICompletionService'); services.registerService('openai-completion', OpenAICompletionService); From 9a9bd5eaf0aca8fd1cc57455db03dba55801d5a0 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sat, 3 Aug 2024 20:56:21 -0400 Subject: [PATCH 0657/2119] feat: add test_mode flag --- .../src/modules/puterai/AWSTextractService.js | 18 +++++++++++++ .../puterai/OpenAICompletionService.js | 27 ++++++++++++++++++- .../puterai/OpenAIImageGenerationService.js | 8 +++--- 3 files changed, 48 insertions(+), 5 deletions(-) diff --git a/src/backend/src/modules/puterai/AWSTextractService.js b/src/backend/src/modules/puterai/AWSTextractService.js index 02376646ac..01e605e8dd 100644 --- a/src/backend/src/modules/puterai/AWSTextractService.js +++ b/src/backend/src/modules/puterai/AWSTextractService.js @@ -1,6 +1,7 @@ const { TextractClient, AnalyzeDocumentCommand, InvalidS3ObjectException } = require("@aws-sdk/client-textract"); const BaseService = require("../../services/BaseService"); +const APIError = require("../../api/APIError"); class AWSTextractService extends BaseService { _construct () { @@ -10,6 +11,23 @@ class AWSTextractService extends BaseService { static IMPLEMENTS = { ['puter-ocr']: { async recognize ({ source, test_mode }) { + if ( test_mode ) { + return { + blocks: [ + { + type: 'text/textract:WORD', + confidence: 0.9999998807907104, + text: 'Hello', + }, + { + type: 'text/puter:sample-output', + confidence: 1, + text: 'The test_mode flag is set to true. This is a sample output.', + }, + ] + }; + } + const resp = await this.analyze_document(source); // Simplify the response for common interface diff --git a/src/backend/src/modules/puterai/OpenAICompletionService.js b/src/backend/src/modules/puterai/OpenAICompletionService.js index d35bd229b7..5a6cfd26c9 100644 --- a/src/backend/src/modules/puterai/OpenAICompletionService.js +++ b/src/backend/src/modules/puterai/OpenAICompletionService.js @@ -20,7 +20,32 @@ class OpenAICompletionService extends BaseService { static IMPLEMENTS = { ['puter-chat-completion']: { - async complete ({ messages, vision }) { + async complete ({ messages, test_mode }) { + if ( test_mode ) { + const { LoremIpsum } = require('lorem-ipsum'); + const li = new LoremIpsum({ + sentencesPerParagraph: { + max: 8, + min: 4 + }, + wordsPerSentence: { + max: 20, + min: 12 + }, + }); + return { + "index": 0, + "message": { + "role": "assistant", + "content": li.generateParagraphs( + Math.floor(Math.random() * 3) + 1 + ), + }, + "logprobs": null, + "finish_reason": "stop" + } + } + const model = 'gpt-4o'; return await this.complete(messages, { model, diff --git a/src/backend/src/modules/puterai/OpenAIImageGenerationService.js b/src/backend/src/modules/puterai/OpenAIImageGenerationService.js index 800722d830..e715788d74 100644 --- a/src/backend/src/modules/puterai/OpenAIImageGenerationService.js +++ b/src/backend/src/modules/puterai/OpenAIImageGenerationService.js @@ -19,10 +19,6 @@ class OpenAIImageGenerationService extends BaseService { static IMPLEMENTS = { ['puter-image-generation']: { async generate ({ prompt, test_mode }) { - const url = await this.generate(prompt, { - ratio: this.constructor.RATIO_SQUARE, - }); - if ( test_mode ) { return new TypedValue({ $: 'string:url:web', @@ -30,6 +26,10 @@ class OpenAIImageGenerationService extends BaseService { }, 'https://puter-sample-data.puter.site/image_example.png'); } + const url = await this.generate(prompt, { + ratio: this.constructor.RATIO_SQUARE, + }); + const image = new TypedValue({ $: 'string:url:web', content_type: 'image' From 7aece26f4b7dd3abe1721d6d75510c3b8cd47831 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sat, 3 Aug 2024 21:00:13 -0400 Subject: [PATCH 0658/2119] tweak: add default driver mapping --- src/backend/src/services/drivers/DriverService.js | 12 +++++++++++- 1 file changed, 11 insertions(+), 1 deletion(-) diff --git a/src/backend/src/services/drivers/DriverService.js b/src/backend/src/services/drivers/DriverService.js index c9f4277592..8eb9082369 100644 --- a/src/backend/src/services/drivers/DriverService.js +++ b/src/backend/src/services/drivers/DriverService.js @@ -128,8 +128,18 @@ class DriverService extends BaseService { const svc_registry = this.services.get('registry'); const c_interfaces = svc_registry.get('interfaces'); + + // There used to be only an 'interface' parameter but no 'driver' + // parameter. To support outdated clients we use this hard-coded + // table to map interfaces to default drivers. + const iface_to_driver = { + ['puter-ocr']: 'aws-textract', + ['puter-tts']: 'aws-polly', + ['puter-chat-completion']: 'openai-completion', + ['puter-image-generation']: 'openai-image-generation', + } - driver = driver ?? iface; + driver = driver ?? iface_to_driver[iface] ?? iface; const driver_service_exists = (() => { return this.services.has(driver) && From c97688706e88490968c51962eed33e8a4e17a34b Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 5 Aug 2024 15:59:09 -0400 Subject: [PATCH 0659/2119] tweak: add boot error help --- tools/run-selfhosted.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/tools/run-selfhosted.js b/tools/run-selfhosted.js index 7a1acfdb35..e5cdb57bcb 100644 --- a/tools/run-selfhosted.js +++ b/tools/run-selfhosted.js @@ -121,6 +121,15 @@ const early_init_errors = [ suggestions: [ 'try running `npm install`' ], + }, + { + text: 'Cannot write to path', + notes: [ + 'this usually happens when /var/puter isn\'t chown\'d to the right UID' + ], + suggestions: [ + 'check issue #645 on our github' + ] } ]; From 476acae0e0d07c7b025cdbcfd86aacfedd7831a5 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 5 Aug 2024 16:04:21 -0400 Subject: [PATCH 0660/2119] fix: disable unconfigured ai services --- .../src/modules/puterai/PuterAIModule.js | 26 +++++++++++++------ 1 file changed, 18 insertions(+), 8 deletions(-) diff --git a/src/backend/src/modules/puterai/PuterAIModule.js b/src/backend/src/modules/puterai/PuterAIModule.js index 20ea82009c..f1ccde4263 100644 --- a/src/backend/src/modules/puterai/PuterAIModule.js +++ b/src/backend/src/modules/puterai/PuterAIModule.js @@ -1,4 +1,5 @@ const { AdvancedBase } = require("@heyputer/puter-js-common"); +const config = require("../../config"); class PuterAIModule extends AdvancedBase { async install (context) { @@ -7,17 +8,26 @@ class PuterAIModule extends AdvancedBase { const { AIInterfaceService } = require('./AIInterfaceService'); services.registerService('__ai-interfaces', AIInterfaceService); - const { AWSTextractService } = require('./AWSTextractService'); - services.registerService('aws-textract', AWSTextractService); + // TODO: services should govern their own availability instead of + // the module deciding what to register - const { AWSPollyService } = require('./AWSPollyService'); - services.registerService('aws-polly', AWSPollyService); + if ( !! config?.services?.['aws-textract']?.aws ) { + const { AWSTextractService } = require('./AWSTextractService'); + services.registerService('aws-textract', AWSTextractService); + } - const { OpenAICompletionService } = require('./OpenAICompletionService'); - services.registerService('openai-completion', OpenAICompletionService); + if ( !! config?.services?.['aws-polly']?.aws ) { + const { AWSPollyService } = require('./AWSPollyService'); + services.registerService('aws-polly', AWSPollyService); + } - const { OpenAIImageGenerationService } = require('./OpenAIImageGenerationService'); - services.registerService('openai-image-generation', OpenAIImageGenerationService); + if ( !! config?.openai ) { + const { OpenAICompletionService } = require('./OpenAICompletionService'); + services.registerService('openai-completion', OpenAICompletionService); + + const { OpenAIImageGenerationService } = require('./OpenAIImageGenerationService'); + services.registerService('openai-image-generation', OpenAIImageGenerationService); + } } } From cea29645fec493020a4f66e378b087fa17ae03d4 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 5 Aug 2024 00:41:41 -0400 Subject: [PATCH 0661/2119] feat: add message encryption between Puter peers --- package-lock.json | 15 ++ src/backend/package.json | 1 + src/backend/src/services/BroadcastService.js | 218 +++++++++++++++++- .../services/runtime-analysis/AlarmService.js | 2 +- tools/keygen/gen-peer-keys.js | 19 ++ tools/keygen/package.json | 12 + tools/run-selfhosted.js | 2 +- 7 files changed, 264 insertions(+), 5 deletions(-) create mode 100644 tools/keygen/gen-peer-keys.js create mode 100644 tools/keygen/package.json diff --git a/package-lock.json b/package-lock.json index 249a96b145..3e6ffe024d 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11704,6 +11704,10 @@ "safe-buffer": "^5.0.1" } }, + "node_modules/keygen": { + "resolved": "tools/keygen", + "link": true + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -16622,6 +16626,7 @@ "string-length": "^6.0.0", "svgo": "^3.0.2", "tiktoken": "^1.0.11", + "tweetnacl": "^1.0.3", "ua-parser-js": "^1.0.38", "uglify-js": "^3.17.4", "uuid": "^9.0.0", @@ -16640,6 +16645,12 @@ "typescript": "^5.1.6" } }, + "src/backend/node_modules/tweetnacl": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-1.0.3.tgz", + "integrity": "sha512-6rt+RN7aOi1nGMyC4Xa5DdYiukl2UWCbcJft7YhxReBGQD7OAM8Pbxw6YMo4r2diNEA8FEmu32YOn9rhaiE5yw==", + "license": "Unlicense" + }, "src/contextlink": { "version": "0.0.0", "license": "AGPL-3.0-only", @@ -16914,6 +16925,10 @@ "handlebars": "^4.7.8" } }, + "tools/keygen": { + "version": "1.0.0", + "license": "AGPL-3.0-only" + }, "tools/license-headers": { "version": "1.0.0", "license": "AGPL-3.0-only", diff --git a/src/backend/package.json b/src/backend/package.json index 2c3c4d19fc..632b93e60f 100644 --- a/src/backend/package.json +++ b/src/backend/package.json @@ -68,6 +68,7 @@ "string-length": "^6.0.0", "svgo": "^3.0.2", "tiktoken": "^1.0.11", + "tweetnacl": "^1.0.3", "ua-parser-js": "^1.0.38", "uglify-js": "^3.17.4", "uuid": "^9.0.0", diff --git a/src/backend/src/services/BroadcastService.js b/src/backend/src/services/BroadcastService.js index 45a468a5f1..597228d1fc 100644 --- a/src/backend/src/services/BroadcastService.js +++ b/src/backend/src/services/BroadcastService.js @@ -21,12 +21,81 @@ const { Endpoint } = require("../util/expressutil"); const { UserActorType } = require("./auth/Actor"); const BaseService = require("./BaseService"); +class KeyPairHelper extends AdvancedBase { + static MODULES = { + tweetnacl: require('tweetnacl'), + }; + + constructor ({ + kpublic, + ksecret, + }) { + super(); + this.kpublic = kpublic; + this.ksecret = ksecret; + this.nonce_ = 0; + } + + to_nacl_key_ (key) { + console.log('WUT', key); + const full_buffer = Buffer.from(key, 'base64'); + + // Remove version byte (assumed to be 0x31 and ignored for now) + const buffer = full_buffer.slice(1); + + return new Uint8Array(buffer); + } + + get naclSecret () { + return this.naclSecret_ ?? ( + this.naclSecret_ = this.to_nacl_key_(this.ksecret)); + } + get naclPublic () { + return this.naclPublic_ ?? ( + this.naclPublic_ = this.to_nacl_key_(this.kpublic)); + } + + write (text) { + const require = this.require; + const nacl = require('tweetnacl'); + + const nonce = nacl.randomBytes(nacl.box.nonceLength); + const message = {}; + + const textUint8 = new Uint8Array(Buffer.from(text, 'utf-8')); + const encryptedText = nacl.box( + textUint8, nonce, + this.naclPublic, this.naclSecret + ); + message.text = Buffer.from(encryptedText); + message.nonce = Buffer.from(nonce); + + return message; + } + + read (message) { + const require = this.require; + const nacl = require('tweetnacl'); + + const arr = nacl.box.open( + new Uint8Array(message.text), + new Uint8Array(message.nonce), + this.naclPublic, + this.naclSecret, + ); + + return Buffer.from(arr).toString('utf-8'); + } +} + class Peer extends AdvancedBase { + static AUTHENTICATING = Symbol('AUTHENTICATING'); static ONLINE = Symbol('ONLINE'); static OFFLINE = Symbol('OFFLINE'); static MODULES = { sioclient: require('socket.io-client'), + crypto: require('crypto'), }; constructor (svc_broadcast, config) { @@ -38,7 +107,23 @@ class Peer extends AdvancedBase { send (data) { if ( ! this.socket ) return; - this.socket.send(data) + const require = this.require; + const crypto = require('crypto'); + const iv = crypto.randomBytes(16); + const cipher = crypto.createCipheriv( + 'aes-256-cbc', + this.aesKey, + iv, + ); + const jsonified = JSON.stringify(data); + let buffers = []; + buffers.push(cipher.update(Buffer.from(jsonified, 'utf-8'))); + buffers.push(cipher.final()); + const buffer = Buffer.concat(buffers); + this.socket.send({ + iv, + message: buffer, + }); } get state () { @@ -66,6 +151,22 @@ class Peer extends AdvancedBase { this.log.info(`connected`, { address: this.config.address }); + + const require = this.require; + const crypto = require('crypto'); + this.aesKey = crypto.randomBytes(32); + + const kp_helper = new KeyPairHelper({ + kpublic: this.config.key, + ksecret: this.svc_broadcast.config.keys.secret, + }); + socket.send({ + $: 'take-my-key', + key: this.svc_broadcast.config.keys.public, + message: kp_helper.write( + this.aesKey.toString('base64') + ), + }); }); socket.on('disconnect', () => { this.log.info(`disconnected`, { @@ -88,6 +189,89 @@ class Peer extends AdvancedBase { } } +class Connection extends AdvancedBase { + static MODULES = { + crypto: require('crypto'), + } + + static AUTHENTICATING = { + on_message (data) { + if ( data.$ !== 'take-my-key' ) { + this.disconnect(); + return; + } + + const hasKey = this.svc_broadcast.trustedPublicKeys_[data.key]; + if ( ! hasKey ) { + this.disconnect(); + return; + } + + const is_trusted = + this.svc_broadcast.trustedPublicKeys_ + .hasOwnProperty(data.key) + if ( ! is_trusted ) { + this.disconnect(); + return; + } + + const kp_helper = new KeyPairHelper({ + kpublic: data.key, + ksecret: this.svc_broadcast.config.keys.secret, + }); + + const message = kp_helper.read(data.message); + this.aesKey = Buffer.from(message, 'base64'); + + this.state = this.constructor.ONLINE; + } + } + static ONLINE = { + on_message (data) { + if ( ! this.on_message ) return; + + const require = this.require; + const crypto = require('crypto'); + const decipher = crypto.createDecipheriv( + 'aes-256-cbc', + this.aesKey, + data.iv, + ) + const buffers = []; + buffers.push(decipher.update(data.message)); + buffers.push(decipher.final()); + + const rawjson = Buffer.concat(buffers).toString('utf-8'); + + const output = JSON.parse(rawjson); + + this.on_message(output); + } + } + static OFFLINE = { + on_message () { + throw new Error('unexpected message'); + } + } + + constructor (svc_broadcast, socket) { + super(); + this.state = this.constructor.AUTHENTICATING; + this.svc_broadcast = svc_broadcast; + this.log = this.svc_broadcast.log; + this.socket = socket; + + socket.on('message', data => { + this.state.on_message.call(this, data); + }); + } + + disconnect () { + this.socket.disconnect(true); + this.state = this.constructor.OFFLINE; + } +} + class BroadcastService extends BaseService { static MODULES = { express: require('express'), @@ -96,16 +280,21 @@ class BroadcastService extends BaseService { _construct () { this.peers_ = []; + this.connections_ = []; + this.trustedPublicKeys_ = {}; } async _init () { const peers = this.config.peers ?? []; for ( const peer_config of peers ) { + this.trustedPublicKeys_[peer_config.key] = true; const peer = new Peer(this, peer_config); this.peers_.push(peer); peer.connect(); } + this._register_commands(this.services.get('commands')); + const svc_event = this.services.get('event'); svc_event.on('outer.*', this.on_event.bind(this)); } @@ -131,15 +320,24 @@ class BroadcastService extends BaseService { }); io.on('connection', async socket => { - socket.on('message', ({ key, data, meta }) => { + const conn = new Connection(this, socket); + this.connections_.push(conn); + + conn.on_message = ({ key, data, meta }) => { if ( meta.from_outside ) { this.log.noticeme('possible over-sending'); return; } + if ( key === 'test' ) { + this.log.noticeme(`test message: ` + + JSON.stringify(data) + ); + } + meta.from_outside = true; svc_event.emit(key, data, meta); - }); + }; }); @@ -147,6 +345,20 @@ class BroadcastService extends BaseService { require('node:util').inspect(this.config) ); } + + _register_commands (commands) { + commands.registerCommands('broadcast', [ + { + id: 'test', + description: 'send a test message', + handler: async (args, ctx) => { + this.on_event('test', { + contents: 'I am a test message', + }, {}) + } + } + ]) + } } module.exports = { BroadcastService }; diff --git a/src/backend/src/services/runtime-analysis/AlarmService.js b/src/backend/src/services/runtime-analysis/AlarmService.js index 177ca2ce86..718314b78f 100644 --- a/src/backend/src/services/runtime-analysis/AlarmService.js +++ b/src/backend/src/services/runtime-analysis/AlarmService.js @@ -252,7 +252,7 @@ class AlarmService extends BaseService { svc_devConsole.add_widget(this.alarm_widget); } - const args = Context.get('args'); + const args = Context.get('args') ?? {}; if ( args['quit-on-alarm'] ) { const svc_shutdown = this.services.get('shutdown'); svc_shutdown.shutdown({ diff --git a/tools/keygen/gen-peer-keys.js b/tools/keygen/gen-peer-keys.js new file mode 100644 index 0000000000..78ba9ed374 --- /dev/null +++ b/tools/keygen/gen-peer-keys.js @@ -0,0 +1,19 @@ +const nacl = require('tweetnacl'); + +const pair = nacl.box.keyPair(); + +const format_key = key => { + const version = new Uint8Array([0x31]); + const buffer = Buffer.concat([ + Buffer.from(version), + Buffer.from(key), + ]); + return buffer.toString('base64'); +}; + +console.log(JSON.stringify({ + keys: { + public: format_key(pair.publicKey), + secret: format_key(pair.secretKey), + }, +}, undefined, ' ')); diff --git a/tools/keygen/package.json b/tools/keygen/package.json new file mode 100644 index 0000000000..d44fccaad2 --- /dev/null +++ b/tools/keygen/package.json @@ -0,0 +1,12 @@ +{ + "name": "keygen", + "version": "1.0.0", + "main": "gen-peer-keys.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "AGPL-3.0-only", + "description": "" +} diff --git a/tools/run-selfhosted.js b/tools/run-selfhosted.js index e5cdb57bcb..8c4cb17866 100644 --- a/tools/run-selfhosted.js +++ b/tools/run-selfhosted.js @@ -96,7 +96,7 @@ const main = async () => { k.add_module(new LocalDiskStorageModule()); k.add_module(new SelfHostedModule()); k.add_module(new TestDriversModule()); - k.add_module(new PuterAIModule()); + // k.add_module(new PuterAIModule()); k.boot(); }; From c213b21bee07cea9e64a23d28dd55addee5d5a97 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 5 Aug 2024 16:59:21 -0400 Subject: [PATCH 0662/2119] move: BroadcastService to [+] BroadcastModule --- src/backend/exports.js | 2 ++ src/backend/src/CoreModule.js | 3 --- .../src/modules/broadcast/BroadcastModule.js | 14 ++++++++++++++ .../broadcast}/BroadcastService.js | 4 +--- tools/run-selfhosted.js | 2 ++ 5 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 src/backend/src/modules/broadcast/BroadcastModule.js rename src/backend/src/{services => modules/broadcast}/BroadcastService.js (98%) diff --git a/src/backend/exports.js b/src/backend/exports.js index 28c7a266e7..0ed27f9914 100644 --- a/src/backend/exports.js +++ b/src/backend/exports.js @@ -27,6 +27,7 @@ const BaseService = require("./src/services/BaseService.js"); const { Context } = require("./src/util/context.js"); const { TestDriversModule } = require("./src/modules/test-drivers/TestDriversModule.js"); const { PuterAIModule } = require("./src/modules/puterai/PuterAIModule.js"); +const { BroadcastModule } = require("./src/modules/broadcast/BroadcastModule.js"); module.exports = { @@ -50,4 +51,5 @@ module.exports = { SelfHostedModule, TestDriversModule, PuterAIModule, + BroadcastModule, }; diff --git a/src/backend/src/CoreModule.js b/src/backend/src/CoreModule.js index ef875add2b..8110acf671 100644 --- a/src/backend/src/CoreModule.js +++ b/src/backend/src/CoreModule.js @@ -279,9 +279,6 @@ const install = async ({ services, app, useapi }) => { const { ScriptService } = require('./services/ScriptService'); services.registerService('script', ScriptService); - const { BroadcastService } = require('./services/BroadcastService'); - services.registerService('broadcast', BroadcastService); - const { NotificationService } = require('./services/NotificationService'); services.registerService('notification', NotificationService); diff --git a/src/backend/src/modules/broadcast/BroadcastModule.js b/src/backend/src/modules/broadcast/BroadcastModule.js new file mode 100644 index 0000000000..f7d0dc067b --- /dev/null +++ b/src/backend/src/modules/broadcast/BroadcastModule.js @@ -0,0 +1,14 @@ +const { AdvancedBase } = require("@heyputer/puter-js-common"); + +class BroadcastModule extends AdvancedBase { + async install (context) { + const services = context.get('services'); + + const { BroadcastService } = require('./BroadcastService'); + services.registerService('broadcast', BroadcastService); + } +} + +module.exports = { + BroadcastModule, +}; diff --git a/src/backend/src/services/BroadcastService.js b/src/backend/src/modules/broadcast/BroadcastService.js similarity index 98% rename from src/backend/src/services/BroadcastService.js rename to src/backend/src/modules/broadcast/BroadcastService.js index 597228d1fc..0b393dfffc 100644 --- a/src/backend/src/services/BroadcastService.js +++ b/src/backend/src/modules/broadcast/BroadcastService.js @@ -17,9 +17,7 @@ * along with this program. If not, see . */ const { AdvancedBase } = require("@heyputer/puter-js-common"); -const { Endpoint } = require("../util/expressutil"); -const { UserActorType } = require("./auth/Actor"); -const BaseService = require("./BaseService"); +const BaseService = require("../../services/BaseService"); class KeyPairHelper extends AdvancedBase { static MODULES = { diff --git a/tools/run-selfhosted.js b/tools/run-selfhosted.js index 8c4cb17866..9253b21ebe 100644 --- a/tools/run-selfhosted.js +++ b/tools/run-selfhosted.js @@ -84,6 +84,7 @@ const main = async () => { DatabaseModule, LocalDiskStorageModule, SelfHostedModule, + BroadcastModule, TestDriversModule, PuterAIModule, } = (await import('@heyputer/backend')).default; @@ -95,6 +96,7 @@ const main = async () => { k.add_module(new DatabaseModule()); k.add_module(new LocalDiskStorageModule()); k.add_module(new SelfHostedModule()); + k.add_module(new BroadcastModule()); k.add_module(new TestDriversModule()); // k.add_module(new PuterAIModule()); k.boot(); From e2f35b4844b10df8dabe14a9d32ca0b9969c3618 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 5 Aug 2024 18:48:49 -0400 Subject: [PATCH 0663/2119] dev: CLink and SLink classes --- doc/contributors/comment_prefixes.md | 5 +- .../src/modules/broadcast/BroadcastService.js | 270 +----------------- .../modules/broadcast/connection/BaseLink.js | 34 +++ .../src/modules/broadcast/connection/CLink.js | 103 +++++++ .../broadcast/connection/KeyPairHelper.js | 72 +++++ .../src/modules/broadcast/connection/SLink.js | 87 ++++++ src/backend/src/traits/ChannelFeature.js | 46 +++ 7 files changed, 360 insertions(+), 257 deletions(-) create mode 100644 src/backend/src/modules/broadcast/connection/BaseLink.js create mode 100644 src/backend/src/modules/broadcast/connection/CLink.js create mode 100644 src/backend/src/modules/broadcast/connection/KeyPairHelper.js create mode 100644 src/backend/src/modules/broadcast/connection/SLink.js create mode 100644 src/backend/src/traits/ChannelFeature.js diff --git a/doc/contributors/comment_prefixes.md b/doc/contributors/comment_prefixes.md index eefb0e4af8..7a24afd1bb 100644 --- a/doc/contributors/comment_prefixes.md +++ b/doc/contributors/comment_prefixes.md @@ -27,4 +27,7 @@ This document will be updated on an _as-needed_ basis. [track-comments.md](../devmeta/track-comments.md) - `wet:` is usesd to track anything that doesn't adhere to the DRY principle; the following message should describe - where similar code is \ No newline at end of file + where similar code is +- `compare():` is used to note differences between other + implementations of a similar idea +- `name:` pedantic commentary on the name of something diff --git a/src/backend/src/modules/broadcast/BroadcastService.js b/src/backend/src/modules/broadcast/BroadcastService.js index 0b393dfffc..dd7d663479 100644 --- a/src/backend/src/modules/broadcast/BroadcastService.js +++ b/src/backend/src/modules/broadcast/BroadcastService.js @@ -18,257 +18,8 @@ */ const { AdvancedBase } = require("@heyputer/puter-js-common"); const BaseService = require("../../services/BaseService"); - -class KeyPairHelper extends AdvancedBase { - static MODULES = { - tweetnacl: require('tweetnacl'), - }; - - constructor ({ - kpublic, - ksecret, - }) { - super(); - this.kpublic = kpublic; - this.ksecret = ksecret; - this.nonce_ = 0; - } - - to_nacl_key_ (key) { - console.log('WUT', key); - const full_buffer = Buffer.from(key, 'base64'); - - // Remove version byte (assumed to be 0x31 and ignored for now) - const buffer = full_buffer.slice(1); - - return new Uint8Array(buffer); - } - - get naclSecret () { - return this.naclSecret_ ?? ( - this.naclSecret_ = this.to_nacl_key_(this.ksecret)); - } - get naclPublic () { - return this.naclPublic_ ?? ( - this.naclPublic_ = this.to_nacl_key_(this.kpublic)); - } - - write (text) { - const require = this.require; - const nacl = require('tweetnacl'); - - const nonce = nacl.randomBytes(nacl.box.nonceLength); - const message = {}; - - const textUint8 = new Uint8Array(Buffer.from(text, 'utf-8')); - const encryptedText = nacl.box( - textUint8, nonce, - this.naclPublic, this.naclSecret - ); - message.text = Buffer.from(encryptedText); - message.nonce = Buffer.from(nonce); - - return message; - } - - read (message) { - const require = this.require; - const nacl = require('tweetnacl'); - - const arr = nacl.box.open( - new Uint8Array(message.text), - new Uint8Array(message.nonce), - this.naclPublic, - this.naclSecret, - ); - - return Buffer.from(arr).toString('utf-8'); - } -} - -class Peer extends AdvancedBase { - static AUTHENTICATING = Symbol('AUTHENTICATING'); - static ONLINE = Symbol('ONLINE'); - static OFFLINE = Symbol('OFFLINE'); - - static MODULES = { - sioclient: require('socket.io-client'), - crypto: require('crypto'), - }; - - constructor (svc_broadcast, config) { - super(); - this.svc_broadcast = svc_broadcast; - this.log = this.svc_broadcast.log; - this.config = config; - } - - send (data) { - if ( ! this.socket ) return; - const require = this.require; - const crypto = require('crypto'); - const iv = crypto.randomBytes(16); - const cipher = crypto.createCipheriv( - 'aes-256-cbc', - this.aesKey, - iv, - ); - const jsonified = JSON.stringify(data); - let buffers = []; - buffers.push(cipher.update(Buffer.from(jsonified, 'utf-8'))); - buffers.push(cipher.final()); - const buffer = Buffer.concat(buffers); - this.socket.send({ - iv, - message: buffer, - }); - } - - get state () { - try { - if ( this.socket?.connected ) return this.constructor.ONLINE; - } catch (e) { - console.error('could not get peer state', e); - } - return this.constructor.OFFLINE; - } - - connect () { - const address = this.config.address; - const socket = this.modules.sioclient(address, { - transports: ['websocket'], - path: '/wssinternal', - reconnection: true, - extraHeaders: { - ...(this.config.host ? { - Host: this.config.host, - } : {}) - } - }); - socket.on('connect', () => { - this.log.info(`connected`, { - address: this.config.address - }); - - const require = this.require; - const crypto = require('crypto'); - this.aesKey = crypto.randomBytes(32); - - const kp_helper = new KeyPairHelper({ - kpublic: this.config.key, - ksecret: this.svc_broadcast.config.keys.secret, - }); - socket.send({ - $: 'take-my-key', - key: this.svc_broadcast.config.keys.public, - message: kp_helper.write( - this.aesKey.toString('base64') - ), - }); - }); - socket.on('disconnect', () => { - this.log.info(`disconnected`, { - address: this.config.address - }); - }); - socket.on('connect_error', e => { - this.log.info(`connection error`, { - address: this.config.address, - message: e.message, - }); - }); - socket.on('error', e => { - this.log.info('error', { - message: e.message, - }); - }); - - this.socket = socket; - } -} - -class Connection extends AdvancedBase { - static MODULES = { - crypto: require('crypto'), - } - - static AUTHENTICATING = { - on_message (data) { - if ( data.$ !== 'take-my-key' ) { - this.disconnect(); - return; - } - - const hasKey = this.svc_broadcast.trustedPublicKeys_[data.key]; - if ( ! hasKey ) { - this.disconnect(); - return; - } - - const is_trusted = - this.svc_broadcast.trustedPublicKeys_ - .hasOwnProperty(data.key) - if ( ! is_trusted ) { - this.disconnect(); - return; - } - - const kp_helper = new KeyPairHelper({ - kpublic: data.key, - ksecret: this.svc_broadcast.config.keys.secret, - }); - - const message = kp_helper.read(data.message); - this.aesKey = Buffer.from(message, 'base64'); - - this.state = this.constructor.ONLINE; - } - } - static ONLINE = { - on_message (data) { - if ( ! this.on_message ) return; - - const require = this.require; - const crypto = require('crypto'); - const decipher = crypto.createDecipheriv( - 'aes-256-cbc', - this.aesKey, - data.iv, - ) - const buffers = []; - buffers.push(decipher.update(data.message)); - buffers.push(decipher.final()); - - const rawjson = Buffer.concat(buffers).toString('utf-8'); - - const output = JSON.parse(rawjson); - - this.on_message(output); - } - } - static OFFLINE = { - on_message () { - throw new Error('unexpected message'); - } - } - - constructor (svc_broadcast, socket) { - super(); - this.state = this.constructor.AUTHENTICATING; - this.svc_broadcast = svc_broadcast; - this.log = this.svc_broadcast.log; - this.socket = socket; - - socket.on('message', data => { - this.state.on_message.call(this, data); - }); - } - - disconnect () { - this.socket.disconnect(true); - this.state = this.constructor.OFFLINE; - } -} +const { CLink } = require("./connection/CLink"); +const { SLink } = require("./connection/SLink"); class BroadcastService extends BaseService { static MODULES = { @@ -286,7 +37,11 @@ class BroadcastService extends BaseService { const peers = this.config.peers ?? []; for ( const peer_config of peers ) { this.trustedPublicKeys_[peer_config.key] = true; - const peer = new Peer(this, peer_config); + const peer = new CLink({ + keys: this.config.keys, + config: peer_config, + log: this.log, + }); this.peers_.push(peer); peer.connect(); } @@ -301,7 +56,6 @@ class BroadcastService extends BaseService { if ( meta.from_outside ) return; for ( const peer of this.peers_ ) { - if ( peer.state !== Peer.ONLINE ) continue; peer.send({ key, data, meta }); } } @@ -318,10 +72,14 @@ class BroadcastService extends BaseService { }); io.on('connection', async socket => { - const conn = new Connection(this, socket); + const conn = new SLink({ + keys: this.config.keys, + trustedKeys: this.trustedPublicKeys_, + socket, + }); this.connections_.push(conn); - conn.on_message = ({ key, data, meta }) => { + conn.channels.message.on(({ key, data, meta }) => { if ( meta.from_outside ) { this.log.noticeme('possible over-sending'); return; @@ -335,7 +93,7 @@ class BroadcastService extends BaseService { meta.from_outside = true; svc_event.emit(key, data, meta); - }; + }); }); diff --git a/src/backend/src/modules/broadcast/connection/BaseLink.js b/src/backend/src/modules/broadcast/connection/BaseLink.js new file mode 100644 index 0000000000..0f391886bc --- /dev/null +++ b/src/backend/src/modules/broadcast/connection/BaseLink.js @@ -0,0 +1,34 @@ +const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { ChannelFeature } = require("../../../traits/ChannelFeature"); + +class BaseLink extends AdvancedBase { + static FEATURES = [ + new ChannelFeature(), + ]; + static CHANNELS = ['message']; + + static MODULES = { + crypto: require('crypto'), + }; + + static AUTHENTICATING = {}; + static ONLINE = {}; + static OFFLINE = {}; + + send (data) { + if ( this.state !== this.constructor.ONLINE ) { + return false; + } + + return this._send(data); + } + + constructor () { + super(); + this.state = this.constructor.AUTHENTICATING; + } +} + +module.exports = { + BaseLink, +}; diff --git a/src/backend/src/modules/broadcast/connection/CLink.js b/src/backend/src/modules/broadcast/connection/CLink.js new file mode 100644 index 0000000000..e667554678 --- /dev/null +++ b/src/backend/src/modules/broadcast/connection/CLink.js @@ -0,0 +1,103 @@ +const { BaseLink } = require("./BaseLink"); +const { KeyPairHelper } = require("./KeyPairHelper"); + +class CLink extends BaseLink { + static MODULES = { + sioclient: require('socket.io-client'), + }; + + _send (data) { + if ( ! this.socket ) return; + const require = this.require; + const crypto = require('crypto'); + const iv = crypto.randomBytes(16); + const cipher = crypto.createCipheriv( + 'aes-256-cbc', + this.aesKey, + iv, + ); + const jsonified = JSON.stringify(data); + let buffers = []; + buffers.push(cipher.update(Buffer.from(jsonified, 'utf-8'))); + buffers.push(cipher.final()); + const buffer = Buffer.concat(buffers); + this.socket.send({ + iv, + message: buffer, + }); + } + + constructor ({ + keys, + log, + config, + }) { + super(); + // keys of client (local) + this.keys = keys; + // keys of server (remote) + this.config = config; + this.log = log; + } + + connect () { + const address = this.config.address; + const socket = this.modules.sioclient(address, { + transports: ['websocket'], + path: '/wssinternal', + reconnection: true, + extraHeaders: { + ...(this.config.host ? { + Host: this.config.host, + } : {}) + } + }); + socket.on('connect', () => { + this.log.info(`connected`, { + address: this.config.address + }); + + const require = this.require; + const crypto = require('crypto'); + this.aesKey = crypto.randomBytes(32); + + const kp_helper = new KeyPairHelper({ + kpublic: this.config.key, + ksecret: this.keys.secret, + }); + socket.send({ + $: 'take-my-key', + key: this.keys.public, + message: kp_helper.write( + this.aesKey.toString('base64') + ), + }); + this.state = this.constructor.ONLINE; + }); + socket.on('disconnect', () => { + this.log.info(`disconnected`, { + address: this.config.address + }); + }); + socket.on('connect_error', e => { + this.log.info(`connection error`, { + address: this.config.address, + message: e.message, + }); + }); + socket.on('error', e => { + this.log.info('error', { + message: e.message, + }); + }); + socket.on('message', data => { + if ( this.state.on_message ) { + this.state.on_message.call(this, data); + } + }); + + this.socket = socket; + } +} + +module.exports = { CLink }; diff --git a/src/backend/src/modules/broadcast/connection/KeyPairHelper.js b/src/backend/src/modules/broadcast/connection/KeyPairHelper.js new file mode 100644 index 0000000000..ab5081681f --- /dev/null +++ b/src/backend/src/modules/broadcast/connection/KeyPairHelper.js @@ -0,0 +1,72 @@ +const { AdvancedBase } = require('@heyputer/puter-js-common'); + +class KeyPairHelper extends AdvancedBase { + static MODULES = { + tweetnacl: require('tweetnacl'), + }; + + constructor ({ + kpublic, + ksecret, + }) { + super(); + this.kpublic = kpublic; + this.ksecret = ksecret; + this.nonce_ = 0; + } + + to_nacl_key_ (key) { + console.log('WUT', key); + const full_buffer = Buffer.from(key, 'base64'); + + // Remove version byte (assumed to be 0x31 and ignored for now) + const buffer = full_buffer.slice(1); + + return new Uint8Array(buffer); + } + + get naclSecret () { + return this.naclSecret_ ?? ( + this.naclSecret_ = this.to_nacl_key_(this.ksecret)); + } + get naclPublic () { + return this.naclPublic_ ?? ( + this.naclPublic_ = this.to_nacl_key_(this.kpublic)); + } + + write (text) { + const require = this.require; + const nacl = require('tweetnacl'); + + const nonce = nacl.randomBytes(nacl.box.nonceLength); + const message = {}; + + const textUint8 = new Uint8Array(Buffer.from(text, 'utf-8')); + const encryptedText = nacl.box( + textUint8, nonce, + this.naclPublic, this.naclSecret + ); + message.text = Buffer.from(encryptedText); + message.nonce = Buffer.from(nonce); + + return message; + } + + read (message) { + const require = this.require; + const nacl = require('tweetnacl'); + + const arr = nacl.box.open( + new Uint8Array(message.text), + new Uint8Array(message.nonce), + this.naclPublic, + this.naclSecret, + ); + + return Buffer.from(arr).toString('utf-8'); + } +} + +module.exports = { + KeyPairHelper, +}; diff --git a/src/backend/src/modules/broadcast/connection/SLink.js b/src/backend/src/modules/broadcast/connection/SLink.js new file mode 100644 index 0000000000..1bf0c58910 --- /dev/null +++ b/src/backend/src/modules/broadcast/connection/SLink.js @@ -0,0 +1,87 @@ +const { BaseLink } = require("./BaseLink"); +const { KeyPairHelper } = require("./KeyPairHelper"); + +class SLink extends BaseLink { + static AUTHENTICATING = { + on_message (data) { + if ( data.$ !== 'take-my-key' ) { + this.disconnect(); + return; + } + + const trustedKeys = this.trustedKeys; + + const hasKey = trustedKeys[data.key]; + if ( ! hasKey ) { + this.disconnect(); + return; + } + + const is_trusted = trustedKeys.hasOwnProperty(data.key) + if ( ! is_trusted ) { + this.disconnect(); + return; + } + + const kp_helper = new KeyPairHelper({ + kpublic: data.key, + ksecret: this.keys.secret, + }); + + const message = kp_helper.read(data.message); + this.aesKey = Buffer.from(message, 'base64'); + + this.state = this.constructor.ONLINE; + } + }; + static ONLINE = { + on_message (data) { + const require = this.require; + const crypto = require('crypto'); + const decipher = crypto.createDecipheriv( + 'aes-256-cbc', + this.aesKey, + data.iv, + ) + const buffers = []; + buffers.push(decipher.update(data.message)); + buffers.push(decipher.final()); + + const rawjson = Buffer.concat(buffers).toString('utf-8'); + + const output = JSON.parse(rawjson); + + this.channels.message.emit(output); + } + } + static OFFLINE = { + on_message () { + throw new Error('unexpected message'); + } + } + + _send () { + // TODO: implement as a fallback + throw new Error('cannot send via SLink yet'); + } + + constructor ({ + keys, + trustedKeys, + socket, + }) { + super(); + this.state = this.constructor.AUTHENTICATING; + // Keys of server (local) + this.keys = keys; + // Allowed client keys (remote) + this.trustedKeys = trustedKeys; + this.socket = socket; + + socket.on('message', data => { + this.state.on_message.call(this, data); + }); + } +} + +module.exports = { SLink }; diff --git a/src/backend/src/traits/ChannelFeature.js b/src/backend/src/traits/ChannelFeature.js new file mode 100644 index 0000000000..a78435d80c --- /dev/null +++ b/src/backend/src/traits/ChannelFeature.js @@ -0,0 +1,46 @@ +// name: 'Channel' does not behave the same as Golang's channel construct; it +// behaves more like an EventEmitter. +class Channel { + constructor () { + this.listeners_ = []; + } + + // compare(EventService): EventService has an 'on' method, + // but it accepts a 'selector' argument to narrow the scope of events + on (callback) { + // wet: EventService also creates an object like this + const det = { + detach: () => { + const idx = this.listeners_.indexOf(callback); + if ( idx !== -1 ) { + this.listeners_.splice(idx, 1); + } + } + }; + + this.listeners_.push(callback); + + return det; + } + + emit (...a) { + for ( const lis of this.listeners_ ) { + lis(...a); + } + } +} + +class ChannelFeature { + install_in_instance (instance) { + const channels = instance._get_merged_static_array('CHANNELS'); + + instance.channels = {}; + for ( const name of channels ) { + instance.channels[name] = new Channel(name); + } + } +} + +module.exports = { + ChannelFeature, +}; From 5b74b4affae5473029e887542717c76c7b32f562 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 8 Aug 2024 17:22:34 -0400 Subject: [PATCH 0664/2119] fix: missing method in SLink --- src/backend/src/modules/broadcast/connection/SLink.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/backend/src/modules/broadcast/connection/SLink.js b/src/backend/src/modules/broadcast/connection/SLink.js index 1bf0c58910..c2cee1f768 100644 --- a/src/backend/src/modules/broadcast/connection/SLink.js +++ b/src/backend/src/modules/broadcast/connection/SLink.js @@ -65,6 +65,11 @@ class SLink extends BaseLink { throw new Error('cannot send via SLink yet'); } + disconnect () { + this.socket.disconnect(); + this.state = this.constructor.OFFLINE; + } + constructor ({ keys, trustedKeys, From 783cf57934c55e39cf84206052e6852b6b7a2c29 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 8 Aug 2024 17:23:30 -0400 Subject: [PATCH 0665/2119] sync: update hardcoded permissions --- src/backend/src/data/hardcoded-permissions.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/backend/src/data/hardcoded-permissions.js b/src/backend/src/data/hardcoded-permissions.js index 8308d123f9..f68c41fcf4 100644 --- a/src/backend/src/data/hardcoded-permissions.js +++ b/src/backend/src/data/hardcoded-permissions.js @@ -77,6 +77,7 @@ const hardcoded_user_group_permissions = { }, 'b7220104-7905-4985-b996-649fdcdb3c8f': { 'service:hello-world:ii:hello-world': policy_perm('temp.es'), + 'service:puter-kvstore:ii:puter-kvstore': policy_perm('temp.kv'), 'driver:puter-kvstore': policy_perm('temp.kv'), 'driver:puter-notifications': policy_perm('temp.es'), 'driver:puter-apps': policy_perm('temp.es'), @@ -84,6 +85,7 @@ const hardcoded_user_group_permissions = { }, '78b1b1dd-c959-44d2-b02c-8735671f9997': { 'service:hello-world:ii:hello-world': policy_perm('user.es'), + 'service:puter-kvstore:ii:puter-kvstore': policy_perm('user.kv'), 'driver:puter-kvstore': policy_perm('user.kv'), 'driver:puter-notifications': policy_perm('user.es'), 'driver:puter-apps': policy_perm('user.es'), From e60632343b79e8ca9156cbe46eec1dda43a998e5 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 8 Aug 2024 21:24:10 -0400 Subject: [PATCH 0666/2119] sync: cross origin + small gui updates --- src/backend/src/services/WebServerService.js | 20 ++++++++++++++------ src/gui/src/IPC.js | 5 +++++ src/puter-js/src/modules/UI.js | 2 +- 3 files changed, 20 insertions(+), 7 deletions(-) diff --git a/src/backend/src/services/WebServerService.js b/src/backend/src/services/WebServerService.js index 1dc68cf405..0960bbc66c 100644 --- a/src/backend/src/services/WebServerService.js +++ b/src/backend/src/services/WebServerService.js @@ -362,13 +362,12 @@ class WebServerService extends BaseService { app.use(helmet.xssFilter()); // app.use(helmet.referrerPolicy()); app.disable('x-powered-by'); - + const uaParser = require('ua-parser-js'); app.use(function (req, res, next) { const ua_header = req.headers['user-agent']; const ua = uaParser(ua_header); req.ua = ua; - console.log('\x1B[26;1m===== UA =====\x1B[0m', ua); next(); }); @@ -382,11 +381,20 @@ class WebServerService extends BaseService { app.use(function (req, res, next) { const origin = req.headers.origin; - const is_site = req.hostname.endsWith(config.static_hosting_domain); + const is_site = + req.hostname.endsWith(config.static_hosting_domain) || + req.hostname === 'docs.puter.com' + ; const is_popup = !! req.query.embedded_in_popup; - - const co_isolation_okay = !is_popup && (is_site || req.co_isolation_enabled); - + const is_parent_co = !! req.query.cross_origin_isolated; + const is_app = !! req.query['puter.app_instance_id']; + + const co_isolation_okay = + (!is_popup || is_parent_co) && + (is_app || !is_site) && + req.co_isolation_enabled + ; + if ( req.path === '/signup' || req.path === '/login' ) { res.setHeader('Access-Control-Allow-Origin', origin ?? '*'); } diff --git a/src/gui/src/IPC.js b/src/gui/src/IPC.js index 1010601b27..356e72e064 100644 --- a/src/gui/src/IPC.js +++ b/src/gui/src/IPC.js @@ -497,6 +497,11 @@ window.addEventListener('message', async (event) => { if(!window.menubars[event.data.appInstanceID]) window.menubars[event.data.appInstanceID] = value.items; + // disable system context menu + $menubar.on('contextmenu', (e) => { + e.preventDefault(); + }); + const sanitize_items = items => { return items.map(item => { // Check if the item is just '-' diff --git a/src/puter-js/src/modules/UI.js b/src/puter-js/src/modules/UI.js index 8a3fe496aa..f560841672 100644 --- a/src/puter-js/src/modules/UI.js +++ b/src/puter-js/src/modules/UI.js @@ -468,7 +468,7 @@ class UI extends EventListener { let fpath = URLParams.get('puter.item.path'); if(!fpath.startsWith('~/') && !fpath.startsWith('/')) - fpath = '~/' + fpath + fpath = '~/' + fpath; callback([new FSItem({ name: URLParams.get('puter.item.name'), From 200cc4680b7fe844267e5b519b6148643efb0a84 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 9 Aug 2024 20:34:23 +0530 Subject: [PATCH 0667/2119] Completed Transaltion of English To Portuguese from Portugal --- src/gui/src/i18n/translations/pt.js | 159 ++++++++++++++++++++++++++-- 1 file changed, 149 insertions(+), 10 deletions(-) diff --git a/src/gui/src/i18n/translations/pt.js b/src/gui/src/i18n/translations/pt.js index 32ebbbf586..4f8f251e3c 100644 --- a/src/gui/src/i18n/translations/pt.js +++ b/src/gui/src/i18n/translations/pt.js @@ -24,36 +24,59 @@ const pt = { dictionary: { about: "Sobre", account: "Conta", - access_granted_to: "Acesso Dado A", + account_password: "Verificar a palavra-passe da conta", + access_granted_to: "Acesso Concedido a", add_existing_account: "Adicionar Conta Existente", all_fields_required: 'Todos os campos são obrigatórios.', + allow: 'Permitir', apply: "Aplicar", ascending: 'Ascendente', + associated_websites: "Sites Associados", auto_arrange: 'Auto Organizar', background: "Fundo", browse: "Explorar", cancel: 'Cancelar', center: 'Centrar', - change_desktop_background: 'Alterar o fundo…', - change_language: "Alterar a Língua", - change_password: "Alterar a Password", - change_username: "Alterar o Nome de Utilizador", + change_desktop_background: 'Alterar fundo do ambiente de trabalho…', + change_email: "Alterar e-mail", + change_language: "Alterar Idioma", + change_password: "Alterar Senha", + change_ui_colors: "Alterar Cores da Interface", + change_username: "Alterar Nome de Utilizador", + close: 'Fechar', close_all_windows: "Fechar Todas as Janelas", + close_all_windows_confirm: "Tem a certeza de que deseja fechar todas as janelas?", close_all_windows_and_log_out: 'Fechar Janelas e Sair', change_always_open_with: "Queres que ficheiros deste tipo abram sempre com", color: 'Cor', + confirm: 'Confirmar', + confirm_2fa_setup: 'Adicionei o código à minha aplicação de autenticação', + confirm_2fa_recovery: 'Guardei os meus códigos de recuperação em um local seguro.', confirm_account_for_free_referral_storage_c2a: 'Cria uma conta e confirma o endereço do email para receber 1 GB de armazenamento gratuito. O teu amigo também receberá 1 GB de armazenamento gratuito.', + confirm_code_generic_incorrect: "Código Incorreto.", + confirm_code_generic_too_many_requests: "Demasiados pedidos. Aguarde alguns minutos.", + confirm_code_generic_submit: "Submeter Código", + confirm_code_generic_try_again: "Tentar Novamente", + confirm_code_generic_title: "Introduza o Código de Confirmação", + confirm_code_2fa_instruction: "Introduza o código de 6 dígitos da sua aplicação de autenticação.", + confirm_code_2fa_submit_btn: "Submeter", + confirm_code_2fa_title: "Introduza o Código 2FA", confirm_delete_multiple_items: 'Tens a certeza que queres apagar estes itens permanentemente?', confirm_delete_single_item: 'Queres apagar este item permanentemente?', confirm_open_apps_log_out: 'Tens aplicações abertas. Queres mesmo terminar a sessão?', confirm_new_password: "Confirma a Nova Password", confirm_delete_user: "Tens a certeza que queres apagar a tua conta? Todos os ficheiros e dados serão apagados permanentemente. Esta operação é final.", + confirm_delete_user_title: "Eliminar Conta?", + confirm_session_revoke: "Tem a certeza de que deseja revogar esta sessão?", + confirm_your_email_address: "Confirme o Seu Endereço de Email", contact_us: "Contacta-nos", + contact_us_verification_required: "É necessário ter um endereço de email verificado para usar isto.", contain: 'Contém', continue: "Continua", copy: 'Copia', copy_link: "Copia Link", - copying: "A copiar", + copying: "Copiando", + copying_file: "Copiando %%", cover: 'Capa', create_account: "Criar Conta", create_free_account: "Criar Conta Gratuita", @@ -65,36 +88,64 @@ const pt = { clock_visible_hide: 'Esconder - Sempre escondido', clock_visible_show: 'Mostrar - Sempre visível', clock_visible_auto: 'Auto - Por defeito, mostra apenas em modo full-screen', + close_all: 'Close All', + created: 'Created', date_modified: 'Data alterada', + default: 'Default', delete: 'Apagar', delete_account: "Apagar Conta", delete_permanently: "Apagar Permanentemente", + deleting_file: "Deleting %%", deploy_as_app: 'Publicar como aplicativo', descending: 'Descendente', + desktop: 'Desktop', desktop_background_fit: "Ajustado", developers: "Developers", dir_published_as_website: `%strong% foi publicado em:`, + disable_2fa: 'Disable 2FA', + disable_2fa_confirm: "Are you sure you want to disable 2FA?", + disable_2fa_instructions: "Enter your password to disable 2FA.", disassociate_dir: "Desassociar Diretório", + documents: 'Documents', + dont_allow: 'Don\'t Allow', download: 'Descarregar', download_file: 'Descarregar Ficheiro', downloading: "Fazendo a descarga", email: "Email", + email_change_confirmation_sent: "A confirmation email has been sent to your new email address. Please check your inbox and follow the instructions to complete the process.", + email_invalid: 'Email is invalid.', email_or_username: "Email ou Nome de Utilizador", + email_required: 'Email is required.', empty_trash: 'Esvaziar Lixo', empty_trash_confirmation: `Queres apagar os itens do Lixo permanentemente?`, emptying_trash: 'Deitando o Lixo fora…', + enable_2fa: 'Enable 2FA', + end_hard: "End Hard", + end_process_force_confirm: "Are you sure you want to force-quit this process?", + end_soft: "End Soft", + enlarged_qr_code: "Enlarged QR Code", enter_password_to_confirm_delete_user: "Insere a Password para confirmar a remoção da conta", + error_message_is_missing: "Error message is missing.", + error_unknown_cause: "An unknown error occurred.", + error_uploading_files: "Failed to upload files", + favorites: "Favorites", feedback: "Feedback", feedback_c2a: "Pff usa o formulário abaixo para enviar feedback, comentários e bugs.", feedback_sent_confirmation: "Obrigado por nos contactares. Se tiveres um email associado a esta conta, receberás notícias o mais brevemente que nos seja possível.", + fit: "Fit", + folder: 'Folder', + force_quit: 'Force Quit', forgot_pass_c2a: "Esqueceste a senha?", from: "De", general: "Geral", get_a_copy_of_on_puter: `Obter uma cópia de '%%' em Puter.com!`, get_copy_link: 'Copiar Link', hide_all_windows: "Ocultar Todas as Janelas", + home: 'Home', html_document: 'Documento HTML', + hue: 'Hue', image: 'Imagem', + incorrect_password: "Incorrect password", invite_link: "Link do Convite", item: 'item', items_in_trash_cannot_be_renamed: `Este item não pode ser renomeado porque está no lixo. Para alterar o nome, primeiro arrasta-o para fora do Lixo.`, @@ -102,10 +153,19 @@ const pt = { keep_in_taskbar: 'Manter na Barra de Tarefas', language: "Língua", license: "Licença", + lightness: 'Lightness', + link_copied: "Link copied", loading: 'Carregando', log_in: "Entrar", log_into_another_account_anyway: 'Entrar com outra conta na mesma', log_out: 'Sair', + looks_good: "Looks good!", + manage_sessions: "Manage Sessions", + menubar_style: "Menubar Style", + menubar_style_desktop: "Desktop", + menubar_style_system: "System", + menubar_style_window: "Window", + modified: 'Modified', move: 'Mover', moving_file: "Movendo %%", my_websites: "Meus Sites", @@ -117,6 +177,7 @@ const pt = { name_must_be_string: "Nome tem que ser apenas texto.", name_too_long: `Nome não pode ter mais que %% caracteres.`, new: 'Novo', + new_email: 'New Email', new_folder: 'Nova Pasta', new_password: "Nova Password", new_username: "Novo Nome de Utilizador", @@ -128,26 +189,45 @@ const pt = { open_in_new_tab: "Abrir em Nova Aba", open_in_new_window: "Abrir em Nova Janela", open_with: "Abrir Com", + original_name: 'Original Name', + original_path: 'Original Path', oss_code_and_content: "Software de Código Aberto", password: "Password", password_changed: "Password alterada.", + password_recovery_rate_limit: "You've reached our rate-limit; please wait a few minutes. To prevent this in the future, avoid reloading the page too many times.", + password_recovery_token_invalid: "This password recovery token is no longer valid.", + password_recovery_unknown_error: "An unknown error occurred. Please try again later.", + password_required: 'Password is required.', + password_strength_error: "Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, one number, and one special character.", passwords_do_not_match: '`Nova Password` e `Confirmação de Nova Password` são diferentes.', paste: 'Colar', paste_into_folder: "Cola na Pasta", + path: 'Path', + personalization: "Personalization", pick_name_for_website: "Escolha um nome para seu site:", picture: "Imagem", + pictures: 'Pictures', plural_suffix: 's', powered_by_puter_js: `Criado com {{link=docs}}Puter.js{{/link}}`, preparing: "A preparar...", preparing_for_upload: "A preparar o upload...", + print: 'Print', privacy: "Privacidade", proceed_to_login: 'Prosseguir para o login', proceed_with_account_deletion: "Prosseguir com Remoção da Conta", - properties: "Propriedades", + process_status_initializing: "Initializing", + process_status_running: "Running", + process_type_app: 'App', + process_type_init: 'Init', + process_type_ui: 'UI', + properties: "Properties", + public: 'Public', publish: "Publicar", publish_as_website: 'Publicar como Site', puter_description: `Puter é uma nuvem pessoal que prioriza a privacidade e que mantém todos os teus ficheiros, aplicativos e jogos num local seguro, acessível de qualquer lugar e a qualquer hora.`, - recent: "Recentes", + reading_file: "Reading %strong%", + recent: "Recent", + recommended: "Recommended", recover_password: "Recuperar Password", refer_friends_c2a: "Ganha 1 GB por cada amigo que criar e confirmar uma conta Puter. Os teus amigos também ganham 1 GB!", refer_friends_social_media_c2a: `Ganha 1 GB de armazenamento gratuito em Puter.com!`, @@ -159,22 +239,35 @@ const pt = { replace: 'Substituir', replace_all: 'Substituir Todos', resend_confirmation_code: "Re-enviar o Código de Confirmação", + reset_colors: "Reset Colors", + restart_puter_confirm: "Are you sure you want to restart Puter?", restore: "Restaurar", + save: 'Save', + saturation: 'Saturation', save_account: 'Gravar conta', save_account_to_get_copy_link: "Para continuar, pff cria uma conta.", save_account_to_publish: 'Para continuar, pff cria uma conta.', save_session: 'Gravar sessão', save_session_c2a: 'Cria uma conta para gravares a sessão atual e evitares perder o teu trabalho.', scan_qr_c2a: 'Digitaliza o código abaixo para entrares nesta sessão com outros dispositivos', + scan_qr_2fa: 'Scan the QR code with your authenticator app', + scan_qr_generic: 'Scan this QR code using your phone or another device', + search: 'Search', + seconds: 'seconds', + security: "Security", select: "Selecionar", selected: 'selecionado', select_color: 'Selecionar cor…', + sessions: "Sessions", send: "Enviar", send_password_recovery_email: "Enviar Email de Recuperação de Password", session_saved: "Obrigado por criares uma conta. Esta sessão foi gravada.", settings: "Definições", set_new_password: "Definir nova Password", - share_to: "Partilhar com", + share: "Share", + share_to: "Share to", + share_with: "Share with:", + shortcut_to: "Shortcut to", show_all_windows: "Mostrar Todas as Janelas", show_hidden: 'Exibir janelas ocultas', sign_in_with_puter: "Entrar em Puter", @@ -182,17 +275,30 @@ const pt = { signing_in: "Entrar…", size: 'Tamanho', skip: 'Passar à frente', + something_went_wrong: "Something went wrong.", sort_by: 'Ordenar por', start: 'Iniciar', status: "Status", storage_usage: "Uso do Armazenamento", + storage_puter_used: 'used by Puter', taking_longer_than_usual: 'Está a levar mais tempo que o usual. Por favor aguarda...', + task_manager: "Task Manager", + taskmgr_header_name: "Name", + taskmgr_header_status: "Status", + taskmgr_header_type: "Type", terms: "Termos", text_document: 'Documento de Texto', tos_fineprint: `Ao clicares em 'Criar Conta Gratuita' concordas com os {{link=terms}}Termos de Serviço{{/link}} e {{link=privacy}}Política de Privacidade{{/link}} do Puter.`, - trash: 'Lixo', + transparency: "Transparency", + trash: 'Trash', + two_factor: 'Two Factor Authentication', + two_factor_disabled: '2FA Disabled', + two_factor_enabled: '2FA Enabled', type: 'Tipo', type_confirm_to_delete_account: "Escreve 'confirm' para apagares esta conta.", + ui_colors: "UI Colors", + ui_manage_sessions: "Session Manager", + ui_revoke: "Revoke", undo: 'Voltar atrás', unlimited: 'Ilimitado', unzip: "Abrir zip", @@ -201,11 +307,44 @@ const pt = { usage: 'Utilização', username: "Nome de Utilizador", username_changed: 'Nome de Utilizador atualizado.', + username_required: 'Username is required.', versions: "Versões", + videos: 'Videos', + visibility: 'Visibility', yes: 'Sim', yes_release_it: 'Sim, libertar', you_have_been_referred_to_puter_by_a_friend: "Um amigo teu recomendou-te a Puter.com!", zip: "Zipar", + zipping_file: "Zipping %strong%", + + // === 2FA Setup === + setup2fa_1_step_heading: 'Open your authenticator app', + setup2fa_1_instructions: ` + You can use any authenticator app that supports the Time-based One-Time Password (TOTP) protocol. + There are many to choose from, but if you're unsure + Authy + is a solid choice for Android and iOS. + `, + setup2fa_2_step_heading: 'Scan the QR code', + setup2fa_3_step_heading: 'Enter the 6-digit code', + setup2fa_4_step_heading: 'Copy your recovery codes', + setup2fa_4_instructions: ` + These recovery codes are the only way to access your account if you lose your phone or can't use your authenticator app. + Make sure to store them in a safe place. + `, + setup2fa_5_step_heading: 'Confirm 2FA setup', + setup2fa_5_confirmation_1: 'I have saved my recovery codes in a secure location', + setup2fa_5_confirmation_2: 'I am ready to enable 2FA', + setup2fa_5_button: 'Enable 2FA', + + // === 2FA Login === + login2fa_otp_title: 'Enter 2FA Code', + login2fa_otp_instructions: 'Enter the 6-digit code from your authenticator app.', + login2fa_recovery_title: 'Enter a recovery code', + login2fa_recovery_instructions: 'Enter one of your recovery codes to access your account.', + login2fa_use_recovery_code: 'Use a recovery code', + login2fa_recovery_back: 'Back', + login2fa_recovery_placeholder: 'XXXXXXXX', } }; From 00e8b81d161fcb833e1e36961ca4ad5779d6626c Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 9 Aug 2024 23:16:52 +0530 Subject: [PATCH 0668/2119] completed translation english to danish in da.js --- src/gui/src/i18n/translations/da.js | 346 +++++++++++++++++++++------- 1 file changed, 265 insertions(+), 81 deletions(-) diff --git a/src/gui/src/i18n/translations/da.js b/src/gui/src/i18n/translations/da.js index bbba3ca423..4ea1141bd0 100644 --- a/src/gui/src/i18n/translations/da.js +++ b/src/gui/src/i18n/translations/da.js @@ -22,147 +22,331 @@ const da = { english_name: "Danish", code: "da", dictionary: { + about: "Om", + account: "Konto", + account_password: "Bekræft kontoens adgangskode", access_granted_to: "Adgang givet til", add_existing_account: "Tilføj eksisterende konto", - all_fields_required: "Alle felter er obligatoriske.", + all_fields_required: 'Alle felter er påkrævede.', + allow: 'Tillad', apply: "Anvend", - ascending: "Stigende", + ascending: 'Stigende', + associated_websites: "Tilknyttede websteder", + auto_arrange: 'Auto Arrangere', background: "Baggrund", browse: "Gennemse", - cancel: "Annuller", - center: "Centrer", - change_desktop_background: "Skift skrivebordsbaggrund…", - change_language: "Skift sprog", - change_password: "Skift adgangskode", - change_username: "Skift brugernavn", + cancel: 'Annuller', + center: 'Center', + change_desktop_background: 'Ændre skrivebordsbaggrund…', + change_email: "Ændre e-mail", + change_language: "Ændre sprog", + change_password: "Ændre adgangskode", + change_ui_colors: "Ændre UI-farver", + change_username: "Ændre brugernavn", + close: 'Luk', close_all_windows: "Luk alle vinduer", - color: "Farve", - confirm_account_for_free_referral_storage_c2a: "Opret en konto og bekræft din e-mailadresse for at modtage 1 GB gratis lagerplads. Din ven får også 1 GB gratis lagerplads.", + close_all_windows_confirm: "Er du sikker på, at du vil lukke alle vinduer?", + close_all_windows_and_log_out: 'Luk vinduer og log ud', + change_always_open_with: "Vil du altid åbne denne filtype med", + color: 'Farve', + confirm: 'Bekræft', + confirm_2fa_setup: 'Jeg har tilføjet koden til min autentifikator-app', + confirm_2fa_recovery: 'Jeg har gemt mine gendannelseskoder på et sikkert sted', + confirm_account_for_free_referral_storage_c2a: 'Opret en konto og bekræft din e-mailadresse for at modtage 1 GB gratis lagerplads. Din ven vil også få 1 GB gratis lagerplads.', + confirm_code_generic_incorrect: "Forkert kode.", + confirm_code_generic_too_many_requests: "For mange anmodninger. Vent et par minutter.", + confirm_code_generic_submit: "Indsend kode", + confirm_code_generic_try_again: "Prøv igen", + confirm_code_generic_title: "Indtast bekræftelseskode", + confirm_code_2fa_instruction: "Indtast den 6-cifrede kode fra din autentifikator-app.", + confirm_code_2fa_submit_btn: "Indsend", + confirm_code_2fa_title: "Indtast 2FA-kode", + confirm_delete_multiple_items: 'Er du sikker på, at du vil slette disse elementer permanent?', + confirm_delete_single_item: 'Vil du slette dette element permanent?', + confirm_open_apps_log_out: 'Du har åbne apps. Er du sikker på, at du vil logge ud?', confirm_new_password: "Bekræft ny adgangskode", + confirm_delete_user: "Er du sikker på, at du vil slette din konto? Alle dine filer og data vil blive permanent slettet. Denne handling kan ikke fortrydes.", + confirm_delete_user_title: "Slet konto?", + confirm_session_revoke: "Er du sikker på, at du vil tilbagekalde denne session?", + confirm_your_email_address: "Bekræft din e-mailadresse", contact_us: "Kontakt os", - contain: "Indehold", + contact_us_verification_required: "Du skal have en verificeret e-mailadresse for at bruge dette.", + contain: 'Indeholde', continue: "Fortsæt", - copy: "Kopier", + copy: 'Kopier', copy_link: "Kopier link", copying: "Kopierer", - cover: "Dæk", + copying_file: "Kopierer %%", + cover: 'Omslag', create_account: "Opret konto", create_free_account: "Opret gratis konto", create_shortcut: "Opret genvej", + credits: "Kreditter", current_password: "Nuværende adgangskode", - cut: "Klip", - date_modified: "Ændringsdato", - delete: "Slet", + cut: 'Klip', + clock: "Uret", + clock_visible_hide: 'Skjul - Altid skjult', + clock_visible_show: 'Vis - Altid synlig', + clock_visible_auto: 'Auto - Standard, synlig kun i fuld skærm-tilstand.', + close_all: 'Luk alle', + created: 'Oprettet', + date_modified: 'Dato ændret', + default: 'Standard', + delete: 'Slet', + delete_account: "Slet konto", delete_permanently: "Slet permanent", - deploy_as_app: "Udrul som app", - descending: "Faldende", + deleting_file: "Sletter %%", + deploy_as_app: 'Implementer som app', + descending: 'Faldende', + desktop: 'Skrivebord', desktop_background_fit: "Tilpas", - dir_published_as_website: "%strong% er offentliggjort på:", - disassociate_dir: "Fjern tilknytning fra mappe", - download: "Download", + developers: "Udviklere", + dir_published_as_website: `%strong% er blevet offentliggjort til:`, + disable_2fa: 'Deaktiver 2FA', + disable_2fa_confirm: "Er du sikker på, at du vil deaktivere 2FA?", + disable_2fa_instructions: "Indtast din adgangskode for at deaktivere 2FA.", + disassociate_dir: "Fjern tilknytning til mappe", + documents: 'Dokumenter', + dont_allow: 'Tillad ikke', + download: 'Download', + download_file: 'Download fil', downloading: "Downloader", email: "E-mail", + email_change_confirmation_sent: "En bekræftelses-e-mail er sendt til din nye e-mailadresse. Kontroller din indbakke og følg instruktionerne for at fuldføre processen.", + email_invalid: 'E-mail er ugyldig.', email_or_username: "E-mail eller brugernavn", - empty_trash: "Tøm papirkurv", - empty_trash_confirmation: "Er du sikker på, at du vil slette alt i papirkurven permanent?", - emptying_trash: "Tømmer papirkurv…", + email_required: 'E-mail er påkrævet.', + empty_trash: 'Tøm papirkurv', + empty_trash_confirmation: `Er du sikker på, at du vil slette elementerne i papirkurven permanent?`, + emptying_trash: 'Tømmer papirkurv…', + enable_2fa: 'Aktivér 2FA', + end_hard: "Afslut hårdt", + end_process_force_confirm: "Er du sikker på, at du vil afslutte denne proces tvangsmæssigt?", + end_soft: "Afslut blødt", + enlarged_qr_code: "Forstørret QR-kode", + enter_password_to_confirm_delete_user: "Indtast din adgangskode for at bekræfte sletning af konto", + error_message_is_missing: "Fejlmeddelelse mangler.", + error_unknown_cause: "Der opstod en ukendt fejl.", + error_uploading_files: "Fejl ved upload af filer", + favorites: "Favoritter", feedback: "Feedback", feedback_c2a: "Brug venligst formularen nedenfor til at sende os din feedback, kommentarer og fejlrapporter.", - feedback_sent_confirmation: "Tak fordi du kontaktede os. Hvis du har en e-mail tilknyttet din konto, hører du fra os så hurtigt som muligt.", + feedback_sent_confirmation: "Tak fordi du kontaktede os. Hvis du har en e-mail knyttet til din konto, vil du høre fra os så hurtigt som muligt.", + fit: "Pas", + folder: 'Mappe', + force_quit: 'Tving afslut', forgot_pass_c2a: "Glemt adgangskode?", from: "Fra", general: "Generelt", - get_a_copy_of_on_puter: "Få en kopi af '%%' på Puter.com!", - get_copy_link: "Få kopilink", + get_a_copy_of_on_puter: `Få en kopi af '%%' på Puter.com!`, + get_copy_link: 'Få kopi-link', hide_all_windows: "Skjul alle vinduer", - html_document: "HTML-dokument", - image: "Billede", - invite_link: "Invitationslink", - items_in_trash_cannot_be_renamed: "Dette emne kan ikke omdøbes, fordi det er i papirkurven. For at omdøbe dette emne, træk det først ud af papirkurven.", - jpeg_image: "JPEG-billede", - keep_in_taskbar: "Behold i proceslinjen", + home: 'Hjem', + html_document: 'HTML-dokument', + hue: 'Farvetone', + image: 'Billede', + incorrect_password: "Forkert adgangskode", + invite_link: "Inviter link", + item: 'element', + items_in_trash_cannot_be_renamed: `Dette element kan ikke omdøbes, fordi det er i papirkurven. For at omdøbe dette element, skal du først trække det ud af papirkurven.`, + jpeg_image: 'JPEG-billede', + keep_in_taskbar: 'Hold i proceslinjen', + language: "Sprog", + license: "Licens", + lightness: 'Lysstyrke', + link_copied: "Link kopieret", + loading: 'Indlæser', log_in: "Log ind", - log_out: "Log ud", - move: "Flyt", + log_into_another_account_anyway: 'Log ind på en anden konto alligevel', + log_out: 'Log ud', + looks_good: "Ser godt ud!", + manage_sessions: "Administrer sessioner", + menubar_style: "Menubjælke stil", + menubar_style_desktop: "Skrivebord", + menubar_style_system: "System", + menubar_style_window: "Vindue", + modified: 'Ændret', + move: 'Flyt', moving_file: "Flytter %%", my_websites: "Mine websteder", - name: "Navn", - name_cannot_be_empty: "Navn kan ikke være tomt.", - name_cannot_contain_double_period: "Navn kan ikke indeholde '..'.", - name_cannot_contain_period: "Navn kan ikke indeholde '.'-tegnet.", - name_cannot_contain_slash: "Navn kan ikke indeholde '/'-tegnet.", - name_must_be_string: "Navn skal være en streng.", - name_too_long: "Navn kan ikke være længere end %% tegn.", - new: "Ny", - new_folder: "Ny mappe", + name: 'Navn', + name_cannot_be_empty: 'Navn kan ikke være tomt.', + name_cannot_contain_double_period: "Navn kan ikke være '..' tegn.", + name_cannot_contain_period: "Navn kan ikke være '.' tegn.", + name_cannot_contain_slash: "Navn kan ikke indeholde '/' tegn.", + name_must_be_string: "Navn kan kun være en streng.", + name_too_long: `Navn kan ikke være længere end %% tegn.`, + new: 'Ny', + new_email: 'Ny e-mail', + new_folder: 'Ny mappe', new_password: "Ny adgangskode", new_username: "Nyt brugernavn", - no_dir_associated_with_site: "Ingen mappe er tilknyttet denne adresse.", - no_websites_published: "Du har ikke offentliggjort nogen websteder endnu.", - ok: "OK", + no: 'Nej', + no_dir_associated_with_site: 'Ingen mappe tilknyttet denne adresse.', + no_websites_published: "Du har ikke offentliggjort nogen websteder endnu. Højreklik på en mappe for at komme i gang.", + ok: 'OK', open: "Åbn", open_in_new_tab: "Åbn i ny fane", open_in_new_window: "Åbn i nyt vindue", open_with: "Åbn med", + original_name: 'Originalt navn', + original_path: 'Original sti', + oss_code_and_content: "Open Source Software og indhold", password: "Adgangskode", password_changed: "Adgangskode ændret.", - passwords_do_not_match: "`Ny adgangskode` og `Bekræft ny adgangskode` stemmer ikke overens.", - paste: "Indsæt", - paste_into_folder: "Indsæt i mappe", + password_recovery_rate_limit: "Du har nået vores rate-limit; vent venligst et par minutter. For at undgå dette i fremtiden, undgå at genindlæse siden for mange gange.", + password_recovery_token_invalid: "Denne adgangskodegendannelsestoken er ikke længere gyldig.", + password_recovery_unknown_error: "Der opstod en ukendt fejl. Prøv venligst igen senere.", + password_required: 'Adgangskode er påkrævet.', + password_strength_error: "Adgangskoden skal være mindst 8 tegn lang og indeholde mindst ét stort bogstav, ét lille bogstav, ét tal og ét specialtegn.", + passwords_do_not_match: '`Ny adgangskode` og `Bekræft ny adgangskode` stemmer ikke overens.', + paste: 'Sæt ind', + paste_into_folder: "Sæt ind i mappe", + path: 'Sti', + personalization: "Personalisering", pick_name_for_website: "Vælg et navn til dit websted:", picture: "Billede", - powered_by_puter_js: "Drevet af {{link=docs}}Puter.js{{/link}}", + pictures: 'Billeder', + plural_suffix: 's', + powered_by_puter_js: `Udviklet af {{link=docs}}Puter.js{{/link}}`, preparing: "Forbereder...", - preparing_for_upload: "Forbereder upload...", + preparing_for_upload: "Forbereder til upload...", + print: 'Udskriv', + privacy: "Privatliv", + proceed_to_login: 'Fortsæt til login', + proceed_with_account_deletion: "Fortsæt med sletning af konto", + process_status_initializing: "Initialiserer", + process_status_running: "Kører", + process_type_app: 'App', + process_type_init: 'Init', + process_type_ui: 'UI', properties: "Egenskaber", + public: 'Offentlig', publish: "Offentliggør", - publish_as_website: "Offentliggør som websted", + publish_as_website: 'Offentliggør som websted', + puter_description: `Puter er en privatlivsorienteret personlig sky til at holde alle dine filer, apps og spil på ét sikkert sted, tilgængeligt fra hvor som helst, når som helst.`, + reading_file: "Læser %strong%", recent: "Seneste", + recommended: "Anbefalet", recover_password: "Gendan adgangskode", - refer_friends_c2a: "Få 1 GB for hver ven, der opretter og bekræfter en konto på Puter. Din ven får også 1 GB.", - refer_friends_social_media_c2a: "Få 1 GB gratis lagerplads på Puter.com!", - refresh: "Opdater", - release_address_confirmation: "Er du sikker på, at du vil frigive denne adresse?", - remove_from_taskbar: "Fjern fra proceslinjen", - rename: "Omdøb", - repeat: "Gentag", - resend_confirmation_code: "Send bekræftelseskoden igen", + refer_friends_c2a: "Få 1 GB for hver ven, der opretter og bekræfter en konto på Puter. Din ven vil også få 1 GB!", + refer_friends_social_media_c2a: `Få 1 GB gratis lagerplads på Puter.com!`, + refresh: 'Opdater', + release_address_confirmation: `Er du sikker på, at du vil frigive denne adresse?`, + remove_from_taskbar: 'Fjern fra proceslinje', + rename: 'Omdøb', + repeat: 'Gentag', + replace: 'Erstat', + replace_all: 'Erstat alle', + resend_confirmation_code: "Send bekræftelseskode igen", + reset_colors: "Nulstil farver", + restart_puter_confirm: "Er du sikker på, at du vil genstarte Puter?", restore: "Gendan", + save: 'Gem', + saturation: 'Mætning', + save_account: 'Gem konto', save_account_to_get_copy_link: "Opret venligst en konto for at fortsætte.", - save_account_to_publish: "Opret venligst en konto for at fortsætte.", - save_session_c2a: "Opret en konto for at gemme din nuværende session og undgå at miste dit arbejde.", - scan_qr_c2a: "Scan koden nedenfor for at logge ind på denne session fra andre enheder", + save_account_to_publish: 'Opret venligst en konto for at fortsætte.', + save_session: 'Gem session', + save_session_c2a: 'Opret en konto for at gemme din nuværende session og undgå at miste dit arbejde.', + scan_qr_c2a: 'Scan koden nedenfor\nfor at logge ind på denne session fra andre enheder', + scan_qr_2fa: 'Scan QR-koden med din autentifikator-app', + scan_qr_generic: 'Scan denne QR-kode med din telefon eller en anden enhed', + search: 'Søg', + seconds: 'sekunder', + security: "Sikkerhed", select: "Vælg", - select_color: "Vælg farve…", + selected: 'valgt', + select_color: 'Vælg farve…', + sessions: "Sessioner", send: "Send", send_password_recovery_email: "Send e-mail til gendannelse af adgangskode", - session_saved: "Tak for at du oprettede en konto. Denne session er gemt.", + session_saved: "Tak fordi du oprettede en konto. Denne session er blevet gemt.", + settings: "Indstillinger", set_new_password: "Indstil ny adgangskode", + share: "Del", share_to: "Del til", + share_with: "Del med:", + shortcut_to: "Genvej til", show_all_windows: "Vis alle vinduer", - show_hidden: "Vis skjulte", + show_hidden: 'Vis skjulte', sign_in_with_puter: "Log ind med Puter", sign_up: "Tilmeld dig", signing_in: "Logger ind…", - size: "Størrelse", - sort_by: "Sorter efter", - start: "Start", - taking_longer_than_usual: "Dette tager længere tid end sædvanligt. Vent venligst...", - text_document: "Tekstdokument", - tos_fineprint: "Ved at klikke på 'Opret gratis konto' accepterer du Puters {{link=terms}}servicevilkår{{/link}} og {{link=privacy}}privatlivspolitik{{/link}}.", - trash: "Papirkurv", - type: "Type", - undo: "Fortryd", + size: 'Størrelse', + skip: 'Spring over', + something_went_wrong: "Noget gik galt.", + sort_by: 'Sorter efter', + start: 'Start', + status: "Status", + storage_usage: "Lagerforbrug", + storage_puter_used: 'brugt af Puter', + taking_longer_than_usual: 'Tager lidt længere tid end normalt. Vent venligst...', + task_manager: "Opgavehåndtering", + taskmgr_header_name: "Navn", + taskmgr_header_status: "Status", + taskmgr_header_type: "Type", + terms: "Vilkår", + text_document: 'Tekstdokument', + tos_fineprint: `Ved at klikke på 'Opret gratis konto' accepterer du Puters {{link=terms}}Brugsvilkår{{/link}} og {{link=privacy}}Privatlivspolitik{{/link}}.`, + transparency: "Gennemsigtighed", + trash: 'Papirkurv', + two_factor: 'To-faktor autentifikation', + two_factor_disabled: '2FA deaktiveret', + two_factor_enabled: '2FA aktiveret', + type: 'Type', + type_confirm_to_delete_account: "Skriv 'bekræft' for at slette din konto.", + ui_colors: "UI-farver", + ui_manage_sessions: "Session Manager", + ui_revoke: "Tilbagekald", + undo: 'Fortryd', + unlimited: 'Ubegrænset', unzip: "Udpak", - upload: "Upload", - upload_here: "Upload her", + upload: 'Upload', + upload_here: 'Upload her', + usage: 'Brug', username: "Brugernavn", - username_changed: "Brugernavn opdateret.", + username_changed: 'Brugernavn opdateret succesfuldt.', + username_required: 'Brugernavn er påkrævet.', versions: "Versioner", - yes_release_it: "Ja, frigør den", + videos: 'Videoer', + visibility: 'Synlighed', + yes: 'Ja', + yes_release_it: 'Ja, frigiv det', you_have_been_referred_to_puter_by_a_friend: "Du er blevet henvist til Puter af en ven!", - zip: "Zip" + zip: "Zip", + zipping_file: "Zipper %strong%", + + // === 2FA Setup === + setup2fa_1_step_heading: 'Åbn din autentifikator-app', + setup2fa_1_instructions: ` + Du kan bruge enhver autentifikator-app, der understøtter Time-based One-Time Password (TOTP) protokollen. + Der er mange at vælge imellem, men hvis du er usikker + Authy + er et solidt valg til Android og iOS. + `, + setup2fa_2_step_heading: 'Scan QR-koden', + setup2fa_3_step_heading: 'Indtast den 6-cifrede kode', + setup2fa_4_step_heading: 'Kopier dine gendannelseskoder', + setup2fa_4_instructions: ` + Disse gendannelseskoder er den eneste måde at få adgang til din konto, hvis du mister din telefon eller ikke kan bruge din autentifikator-app. + Sørg for at opbevare dem på et sikkert sted. + `, + setup2fa_5_step_heading: 'Bekræft 2FA-opsætning', + setup2fa_5_confirmation_1: 'Jeg har gemt mine gendannelseskoder på et sikkert sted', + setup2fa_5_confirmation_2: 'Jeg er klar til at aktivere 2FA', + setup2fa_5_button: 'Aktivér 2FA', + + // === 2FA Login === + login2fa_otp_title: 'Indtast 2FA-kode', + login2fa_otp_instructions: 'Indtast den 6-cifrede kode fra din autentifikator-app.', + login2fa_recovery_title: 'Indtast en gendannelseskode', + login2fa_recovery_instructions: 'Indtast en af dine gendannelseskoder for at få adgang til din konto.', + login2fa_use_recovery_code: 'Brug en gendannelseskode', + login2fa_recovery_back: 'Tilbage', + login2fa_recovery_placeholder: 'XXXXXXXX', } + }; export default da; From 3f07ead1b9940ee133c142f4c34d19884bbb3cd2 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 9 Aug 2024 16:50:39 -0400 Subject: [PATCH 0669/2119] fix: add context to event listener aiife --- src/backend/src/services/EventService.js | 9 +++++---- src/backend/src/util/context.js | 3 +++ 2 files changed, 8 insertions(+), 4 deletions(-) diff --git a/src/backend/src/services/EventService.js b/src/backend/src/services/EventService.js index d668b992bc..89417ed547 100644 --- a/src/backend/src/services/EventService.js +++ b/src/backend/src/services/EventService.js @@ -16,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ +const { Context } = require("../util/context"); const BaseService = require("./BaseService"); class ScopedEventBus { @@ -55,7 +56,7 @@ class EventService extends BaseService { // IIAFE wrapper to catch errors without blocking // event dispatch. - (async () => { + Context.arun(async () => { try { await callback(key, data, meta); } catch (e) { @@ -65,14 +66,14 @@ class EventService extends BaseService { alarm: true, }); } - })(); + }); } } for ( const callback of this.global_listeners_ ) { // IIAFE wrapper to catch errors without blocking // event dispatch. - (async () => { + Context.arun(async () => { try { await callback(key, data, meta); } catch (e) { @@ -82,7 +83,7 @@ class EventService extends BaseService { alarm: true, }); } - })(); + }); } } diff --git a/src/backend/src/util/context.js b/src/backend/src/util/context.js index 4e222caf12..91948b8f6d 100644 --- a/src/backend/src/util/context.js +++ b/src/backend/src/util/context.js @@ -60,6 +60,9 @@ class Context { static describe () { return this.get().describe(); } + static arun (cb) { + return this.get().arun(cb); + } get (k) { return this.values_[k]; } From 0c4690e39c6950cf431318e8df168c442c113fca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Joel=20Sj=C3=B6gren?= Date: Sun, 11 Aug 2024 10:54:57 +0200 Subject: [PATCH 0670/2119] completed translation english to swedish in sv.js --- src/gui/src/i18n/translations/sv.js | 208 ++++++++++++++++++++++++++-- 1 file changed, 196 insertions(+), 12 deletions(-) diff --git a/src/gui/src/i18n/translations/sv.js b/src/gui/src/i18n/translations/sv.js index ea88c573b7..fcceafe8fe 100644 --- a/src/gui/src/i18n/translations/sv.js +++ b/src/gui/src/i18n/translations/sv.js @@ -17,72 +17,156 @@ * along with this program. If not, see . */ + const sv = { name: "Svenska", english_name: "Swedish", code: "sv", dictionary: { + about: "Om", + account: "Konto", + account_password: "Bekräfta kontolösenord", access_granted_to: "Tillgång beviljad till", add_existing_account: "Lägg till befintligt konto", all_fields_required: "Alla fält är obligatoriska.", + allow: "Tillåt", apply: "Tillämpa", ascending: "Stigande", + associated_websites: "Anknytande webbplatser", + auto_arrange: "Auto Arrange", background: "Bakgrund", browse: "Bläddra", cancel: "Avbryt", center: "Centrera", change_desktop_background: "Ändra skrivbordsbakgrund…", + change_email: "Ändra e-postadress", change_language: "Ändra språk", change_password: "Byt lösenord", + change_ui_colors: "Ändra gränssnittets färger", change_username: "Byt användarnamn", + close: "Stäng", close_all_windows: "Stäng alla fönster", + close_all_windows_confirm: "Är det säkert att du vill stänga alla fönster?", + close_all_windows_and_log_out: "Stäng alla fönster och logga ut", + change_always_open_with: "Vill du alltid öppna den här filtypen med", color: "Färg", + confirm: "Bekräfta", + confirm_2fa_setup: "Jag har lagt in koden i min autentiseringsapp", + confirm_2fa_recovery: "Jag har sparat mina återställningskoder på en säker plats", confirm_account_for_free_referral_storage_c2a: "Skapa ett konto och bekräfta din e-postadress för att få 1 GB gratis lagringsutrymme. Din vän får också 1 GB gratis lagringsutrymme.", - confirm_new_password: "Bekräfta nytt lösenord", + confirm_code_generic_incorrect: "Felaktig kod.", + confirm_code_generic_too_many_requests: "För många förfrågningar. Var god vänta ett par minuter.", + confirm_code_generic_submit: "Skicka in kod", + confirm_code_generic_try_again: "Försök igen", + confirm_code_generic_title: "Fyll i bekräftelsekod", + confirm_code_2fa_instruction: "Fyll i de 6 siffrorna från din autentiseringsapp.", + confirm_code_2fa_submit_btn: "Skicka in", + confirm_code_2fa_title: "Fyll i 2FA-kod", + confirm_delete_multiple_items: "Är det säkert att du vill ta bort de här objekten permanent?", + confirm_delete_single_item: "Vill du ta bort det här objektet?", + confirm_open_apps_log_out: "Du har öppna applikationer. Är det säkert att du vill logga ut?", + confirm_new_password: "Bekräfta det nya lösenordet", + confirm_delete_user: "Är det säkert att du vill radera ditt konto? Alla dina filer och data kommer att tas bort permanent. Detta steg kan inte ångras.", + confirm_delete_user_title: "Ta bort konto?", + confirm_session_revoke: "Är det säkert att du vill upphäva den här sessionen?", + confirm_your_email_address: "Bekräfta din e-postadress", contact_us: "Kontakta oss", - contain: "Innehålla", - continue: "Fortsätt", + contact_us_verification_required: "Du behöver en verifierad e-postadress för att använda den här funktionen.", + contain: "Innehåll", + continue: "Continue", copy: "Kopiera", copy_link: "Kopiera länk", copying: "Kopierar", - cover: "Täcka", + copying_file: "Kopierar %%", + cover: "Täck", create_account: "Skapa konto", create_free_account: "Skapa gratis konto", create_shortcut: "Skapa genväg", + credits: "Tack", current_password: "Nuvarande lösenord", cut: "Klipp ut", + clock: "Klocka", + clock_visible_hide: "Dölj - Alltid dold", + clock_visible_show: "Visa - Alltid synlig", + clock_visible_auto: "Auto - Förval, bara synlig i helskärm.", + close_all: "Stäng alla", + created: "Skapad", date_modified: "Ändringsdatum", - delete: "Radera", + default: "Förval", + delete: "Ta bort", + delete_account: "Ta bort kontot", delete_permanently: "Radera permanent", + deleting_file: "Tar bort %%", deploy_as_app: "Distribuera som app", descending: "Fallande", + desktop: "Skrivbord", desktop_background_fit: "Anpassa", + developers: "Utvecklare", dir_published_as_website: "%strong% är publicerat på:", + disable_2fa: "Stäng av 2FA", + disable_2fa_confirm: "Är det säkert att du vill stänga av 2FA?", + disable_2fa_instructions: "Fyll i ditt lösenord för att stänga av 2FA.", disassociate_dir: "Avassociera mapp", + documents: "Dokument", + dont_allow: "Tillåt inte", download: "Ladda ner", + download_file: "Ladda ner fil", downloading: "Laddar ner", email: "E-post", + email_change_confirmation_sent: "Ett bekräftelsemail har skickats till din nya e-postadress. Var god kontrollera inkorgen och följ instruktionerna för att fullfölja processen.", + email_invalid: "Adressen är ogiltig.", email_or_username: "E-post eller användarnamn", + email_required: "E-post krävs.", empty_trash: "Töm papperskorgen", empty_trash_confirmation: "Är du säker på att du vill permanent radera allt i papperskorgen?", emptying_trash: "Tömmer papperskorgen…", + enable_2fa: 'Aktivera 2FA', + end_hard: "Hårt slut", + end_process_force_confirm: "Är det säkert att du vill tvinga avslut för den här processen?", + end_soft: "Mjukt slut", + enlarged_qr_code: "Förstorad QR-kod", + enter_password_to_confirm_delete_user: "Fyll i ditt lösenord för att bekräfta kontots borttagning.", + error_message_is_missing: "Felmeddelande saknas.", + error_unknown_cause: "Ett okänt fel inträffade.", + error_uploading_files: "Uppladdningen misslyckades", + favorites: "Favoriter", feedback: "Feedback", feedback_c2a: "Vänligen använd formuläret nedan för att skicka oss din feedback, kommentarer och felrapporter.", feedback_sent_confirmation: "Tack för att du kontaktade oss. Om du har en e-post kopplad till ditt konto kommer du att höra från oss så snart som möjligt.", + fit: "Anpassa", + folder: "Mapp", + force_quit: "Tvinga avslut", forgot_pass_c2a: "Glömt lösenord?", from: "Från", general: "Allmänt", get_a_copy_of_on_puter: "Få en kopia av '%%' på Puter.com!", get_copy_link: "Få kopieringslänk", hide_all_windows: "Dölj alla fönster", + home: "Hem", html_document: "HTML-dokument", + hue: "Färgton", image: "Bild", - invite_link: "Inbjudningslänk", + incorrect_password: "Felaktigt lösenord", + invite_link: "Länk för inbjudan", + item: "Objekt", items_in_trash_cannot_be_renamed: "Det här objektet kan inte byta namn eftersom det är i papperskorgen. För att byta namn på detta objekt, dra det först ur papperskorgen.", jpeg_image: "JPEG-bild", keep_in_taskbar: "Behåll i aktivitetsfältet", + language: "Språk", + license: "Licens", + lightness: "Ljus", + link_copied: "Länk kopierad", + loading: "Laddar", log_in: "Logga in", + log_into_another_account_anyway: "Logga ändå in till annat konto", log_out: "Logga ut", + looks_good: "Ser bra ut!", + manage_sessions: "Hantera sessioner", + menubar_style: "Stil för menyraden", + menubar_style_desktop: "Skrivbord", + menubar_style_system: "System", + menubar_style_window: "Fönster", + modified: "Ändrad", move: "Flytta", moving_file: "Flyttar %%", my_websites: "Mina webbplatser", @@ -93,31 +177,58 @@ const sv = { name_cannot_contain_slash: "Namn kan inte innehålla '/'-tecknet.", name_must_be_string: "Namn måste vara en sträng.", name_too_long: "Namn kan inte vara längre än %% tecken.", - new: "Ny", + new: "Nytt", + new_email: "Ny e-post", new_folder: "Ny mapp", new_password: "Nytt lösenord", new_username: "Nytt användarnamn", + no: "Nej", no_dir_associated_with_site: "Ingen mapp är associerad med denna adress.", - no_websites_published: "Du har inte publicerat några webbplatser än.", + no_websites_published: "Du har ännu inte publicerat några webbplatser.", ok: "OK", open: "Öppna", open_in_new_tab: "Öppna i ny flik", open_in_new_window: "Öppna i nytt fönster", open_with: "Öppna med", + original_name: "Utsprungligt namn", + original_path: "Utsprunglig filväg", + oss_code_and_content: "Öppen mjukvara och innehåll", password: "Lösenord", password_changed: "Lösenord ändrat.", + password_recovery_rate_limit: "Du har uppnått vår hastighetsgräns; var god vänta ett par minuter. För att motverka detta i framtiden, undvik att ladda om sidan för många gånger.", + password_recovery_token_invalid: "Den här återställningsnyckeln är inte giltig längre.", + password_recovery_unknown_error: "Ett okänt fel inträffade. Var god försök igen senare.", + password_required: "Lösenord krävs.", + password_strength_error: "Lösenordet måste vara minst 8 tecken och innehålla minst en stor bokstav, en liten bokstav, en siffra, och ett specialtecken.", passwords_do_not_match: "`Nytt lösenord` och `Bekräfta nytt lösenord` stämmer inte överens.", paste: "Klistra in", paste_into_folder: "Klistra in i mapp", + path: "Filväg", + personalization: "Personalisering", pick_name_for_website: "Välj ett namn för din webbplats:", picture: "Bild", + pictures: "Bilder", + plural_suffix: "", // neutrum has "", utrum has "or", "ar", "er" powered_by_puter_js: "Drivs av {{link=docs}}Puter.js{{/link}}", preparing: "Förbereder...", preparing_for_upload: "Förbereder för uppladdning...", + print: "Skriv ut", + privacy: "Integritet", + proceed_to_login: "Förtsätt till inloggning", + proceed_with_account_deletion: "Försätt med kontoborttagning", + process_status_initializing: "Processen påbörjas", + process_status_running: "Processen körs", + process_type_app: "App", + process_type_init: "Init", + process_type_ui: "UI", properties: "Egenskaper", + public: "Offentligt", publish: "Publicera", publish_as_website: "Publicera som webbplats", + puter_description: "Puter är ett integritetsvänligt personligt moln för alla dina filer, appar och spel på ett säkert ställe, tillgängligt varsomhelst och närsomhelst.", + reading_file: "Läser in %strong%", recent: "Senaste", + recommended: "Rekommenderat", recover_password: "Återställ lösenord", refer_friends_c2a: "Få 1 GB för varje vän som skapar och bekräftar ett konto på Puter. Din vän får också 1 GB.", refer_friends_social_media_c2a: "Få 1 GB gratis lagringsutrymme på Puter.com!", @@ -126,42 +237,115 @@ const sv = { remove_from_taskbar: "Ta bort från aktivitetsfältet", rename: "Byt namn", repeat: "Upprepa", + replace: "Ersätt", + replace_all: "Ersätt alla", resend_confirmation_code: "Skicka bekräftelsekoden igen", + reset_colors: "Nolställ färgerna", + restart_puter_confirm: "Är det säkert att du vill starta om Puter?", restore: "Återställ", + save: "Spara", + saturation: "Mättnad", + save_account: "Spara konto", save_account_to_get_copy_link: "Vänligen skapa ett konto för att fortsätta.", save_account_to_publish: "Vänligen skapa ett konto för att fortsätta.", - save_session_c2a: "Skapa ett konto för att spara den nuvarande sessionen och undvika att förlora ditt arbete.", + save_session: "Spara sessionen", + save_session_c2a: "Skapa ett konto för att spara den nuvarande sessionen och undvika att ditt arbete går förlorat.", scan_qr_c2a: "Skanna koden nedan för att logga in på denna session från andra enheter", + scan_qr_2fa: "Skanna QR-koden med din autentiseringsapp", + scan_qr_generic: "Skanna den här QR-koden med din telefon eller en annan enhet", + search: "Sök", + seconds: "sekunder", + security: "Säkerhet", select: "Välj", + selected: "vald", select_color: "Välj färg…", + sessions: "Sessioner", send: "Skicka", send_password_recovery_email: "Skicka e-post för återställning av lösenord", session_saved: "Tack för att du skapade ett konto. Denna session är sparad.", + settings: "Inställningar", set_new_password: "Ange nytt lösenord", + share: "Dela", share_to: "Dela till", + share_with: "Dela med:", + shortcut_to: "Genväg till", show_all_windows: "Visa alla fönster", show_hidden: "Visa dolda", sign_in_with_puter: "Logga in med Puter", - sign_up: "Registrera dig", + sign_up: "Skapa konto", signing_in: "Loggar in…", size: "Storlek", + skip: "Hoppa över", + something_went_wrong: "Någonting gick fel.", sort_by: "Sortera efter", start: "Start", + status: "Tillstånd", + storage_usage: "Användning av lagringsutrymme", + storage_puter_used: "använt av Puter", taking_longer_than_usual: "Detta tar längre tid än vanligt. Vänligen vänta...", + task_manager: "Aktivitetshanteraren", + taskmgr_header_name: "Namn", + taskmgr_header_status: "Tillstånd", + taskmgr_header_type: "Typ", + terms: "Villkor", text_document: "Textdokument", tos_fineprint: "Genom att klicka på 'Skapa gratis konto' godkänner du Puters {{link=terms}}användarvillkor{{/link}} och {{link=privacy}}integritetspolicy{{/link}}.", + transparency: "Transparens", trash: "Papperskorg", + two_factor: "Tvåfaktors-autentisering", + two_factor_disabled: "2FA inaktiverad", + two_factor_enabled: "2FA aktiverad", type: "Typ", + type_confirm_to_delete_account: "Skriv 'bekräfta' för att ta bort ditt konto.", + ui_colors: "Färger för användargränssnitt", + ui_manage_sessions: "Sessionshanterare", + ui_revoke: "Upphäv", undo: "Ångra", + unlimited: "Obegränsat", unzip: "Packa upp", upload: "Ladda upp", - upload_here: "Ladda upp här", + upload_here: "Ladda upp hit", + usage: "Används", username: "Användarnamn", username_changed: "Användarnamn uppdaterat.", + username_required: "Användarnamn krävs.", versions: "Versioner", + videos: "Videor", + visibility: "Synlighet", + yes: "Ja", yes_release_it: "Ja, frigör den", you_have_been_referred_to_puter_by_a_friend: "Du har blivit hänvisad till Puter av en vän!", - zip: "Zip" + zip: "Zippa", + zipping_file: "Komprimerar %strong%", + + // === 2FA Setup === + setup2fa_1_step_heading: "Öppna din autentiseringsapp", + setup2fa_1_instructions: ` + Du kan använda godtycklig autentiseringsapp som stöder Time-based One-Time Password (TOTP)-protokollet. + Det finns många att välja bland, men om du är osäker så är + Authy + ett stabilt val för Android och iOS. + `, + setup2fa_2_step_heading: "Skanna QR-kod", + setup2fa_3_step_heading: "Fyll i koden om 6 siffror", + setup2fa_4_step_heading: "Kopiera dina återställningskoder", + setup2fa_4_instructions: ` + De här återställningskoderna är det enda sättet att komma åt ditt konto om du skulle tappa bort din telefon eller inte kan använda din autentiseringsapp. + Försäkra dig om att du förvarar dem på en säker plats. + `, + setup2fa_5_step_heading: "Bekräfta 2FA-installationen", + setup2fa_5_confirmation_1: "Jag har sparat mina återställningskoder på en säker plats", + setup2fa_5_confirmation_2: "Jag är redo att aktivera 2FA", + setup2fa_5_button: "Aktivera 2FA", + + // === 2FA Login === + login2fa_otp_title: "Fyll i 2FA-kod", + login2fa_otp_instructions: "Fyll i koden om 6 siffror från din autentiseringsapp.", + login2fa_recovery_title: "Fyll i en återhämtningskod", + login2fa_recovery_instructions: "Fyll i en av dina återhämtningskoder för att få tillgång till ditt konto.", + login2fa_use_recovery_code: "Använd en återhämtningskod", + login2fa_recovery_back: "Tillbaka", + login2fa_recovery_placeholder: "XXXXXXXX", } }; From cb8d0fa011c3707badea52aea31d887712c9ca2b Mon Sep 17 00:00:00 2001 From: Ranegg Date: Mon, 12 Aug 2024 19:35:41 +0300 Subject: [PATCH 0671/2119] Added Finnish translations related to issue #536 --- src/gui/src/i18n/translations/fi.js | 322 ++++++++++++++++++++++------ 1 file changed, 252 insertions(+), 70 deletions(-) diff --git a/src/gui/src/i18n/translations/fi.js b/src/gui/src/i18n/translations/fi.js index 887566193a..21d006db70 100644 --- a/src/gui/src/i18n/translations/fi.js +++ b/src/gui/src/i18n/translations/fi.js @@ -17,16 +17,20 @@ * along with this program. If not, see . */ + const fi = { name: "Suomi", english_name: "Finnish", code: "fi", dictionary: { - access_granted_to: "Käyttöoikeus Myönnetty", - add_existing_account: "Lisää Olemassaoleva Tili", + about: "Tietoa", + account: "Tili", + account_password: "Vahvista tilin salasana", + access_granted_to: "Käyttöoikeus myönnetty", + add_existing_account: "Kirjaudu olemassaolevalla tilillä", all_fields_required: 'Kaikki kentät on täytettävä.', - - apply: "Apply", // TODO: Ambiguous meaning + allow: 'Salli', + apply: "Käytä", // TODO: Ambiguous meaning // To apply(a principle) => "Sovella" or // Apply for(a job) "Hae" or // Apply as(an engineer) => "Hakeudu" or @@ -34,99 +38,177 @@ const fi = { // Apply in the sense of applying something, like a tool => "Käytä" ascending: 'Nouseva', + associated_websites: "Tähän liittyvät verkkosivustot", + auto_arrange: 'Järjestä automaattisesti', background: "Tausta", browse: "Selaa", cancel: 'Peruuta', - center: 'Keskus', + center: 'Keskitä', change_desktop_background: 'Vaihda työpöydän taustakuvaa…', - change_password: "Muuta Salasana", - change_username: "Muuta Käyttäjänimeä", - close_all_windows: "Sulje Kaikki Ikkunat", + change_email: "Vaihda sähköpostiosoite", + change_language: "Vaihda kieli", + change_password: "Vaihda salasana", + change_ui_colors: "Vaihda käyttöliittymän värejä", + change_username: "Vaihda käyttäjänimi", + close: 'Sulje', + close_all_windows: "Sulje kaikki ikkunat", + close_all_windows_confirm: "Haluatko varmasti sulkea kaikki ikkunat?", + close_all_windows_and_log_out: 'Sulje ikkunat ja kirjaudu ulos', + change_always_open_with: "Haluatko aina avata tämän tyyppisen tiedoston sovelluksella", color: 'Väri', - confirm_account_for_free_referral_storage_c2a: 'Luo tili ja vahvista sähköpostiosoitteesi saadaksesi 1 Gt ilmaista tallennustilaa. Myös kaverisi saa 1 Gt ilmaista tallennustilaa.', - confirm_new_password: "Vahvista Uusi Salasana", - contact_us: "Ota Yhteyttä", - - contain: 'Contain', // TODO: Ambiguous meaning + confirm: 'Vahvista', + confirm_2fa_setup: 'Olen lisännyt koodin todennussovellukseeni', + confirm_2fa_recovery: 'Olen tallentanut palautuskoodini turvalliseen paikkaan', + confirm_account_for_free_referral_storage_c2a: 'Luo tili ja vahvista sähköpostiosoitteesi saadaksesi 1 Gt ilmaista tallennustilaa. Myös kaverisi saa 1 Gt:n ilmaista tallennustilaa.', + confirm_code_generic_incorrect: "Väärä koodi.", + confirm_code_generic_too_many_requests: "Liikaa pyyntöjä. Ole hyvä ja odota muutama minuutti.", + confirm_code_generic_submit: "Lähetä koodi", + confirm_code_generic_try_again: "Yritä uudelleen", + confirm_code_generic_title: "Syötä vahvistuskoodi", + confirm_code_2fa_instruction: "Syötä kuusinumeroinen koodi todennussovelluksestasi.", + confirm_code_2fa_submit_btn: "Lähetä", + confirm_code_2fa_title: "Syötä kaksivaiheisen tunnistautumisen koodi", + confirm_delete_multiple_items: 'Haluatko varmasti poistaa nämä kohteet pysyvästi?', + confirm_delete_single_item: 'Haluatko poistaa tämän kohteen pysyvästi?', + confirm_open_apps_log_out: 'Sinulla on avoimia sovelluksia. Haluatko varmasti kirjautua ulos?', + confirm_new_password: "Vahvista uusi salasana", + confirm_delete_user: "Haluatko varmasti poistaa tilisi? Kaikki tiedostosi ja tietosi poistetaan pysyvästi. Tätä toimintoa ei voi kumota.", + confirm_delete_user_title: "Poista tilisi?", + confirm_session_revoke: "Haluatko varmasti peruuttaa tämän istunnon?", + confirm_your_email_address: "Vahvista sähköpostiosoitteesi", + contact_us: "Ota yhteyttä", + contact_us_verification_required: "Sinulla on oltava vahvistettu sähköpostiosoite, jotta voit käyttää tätä.", + contain: 'Sisällytä', // TODO: Ambiguous meaning // "inside(a house)" => "Sisällä" - probably more appropriate // "contain within" => "Sisältää" continue: "Jatka", - copy: 'Copy', // TODO: Lexical categories + copy: 'Kopioi', // TODO: Lexical categories // Noun "A copy of something" => 'Kopio' or // Verb "To copy something" => 'Kopioi'? - copy_link: "Kopioi Linkki", + copy_link: "Kopioi linkki", copying: "Kopioidaan", - - cover: 'Cover', // TODO: Lexical categories + copying_file: "Kopioidaan %%", + cover: 'Kansi', // TODO: Lexical categories // Noun (shelter) => 'Suoja' or // Noun (lid) => 'Kansi' or // Intransitive Verb (To occlude something) => 'Peitä' or // Transitive Verb (To cover for someone) => 'Suojaa' - create_account: "Luo Tili", - create_free_account: "Luo Ilmainen Tili", - create_shortcut: "Luo Pikakuvake", - current_password: "Nykyinen Salasana", + create_account: "Luo tili", + create_free_account: "Luo ilmainen tili", + create_shortcut: "Luo pikakuvake", + credits: "Tekijät", + current_password: "Nykyinen salasana", cut: 'Leikkaa', - date_modified: 'Muutospäivämäärä', + clock: "Kello", + clock_visible_hide: 'Piilota - aina piilossa', + clock_visible_show: 'Näytä - aina näkyvissä', + clock_visible_auto: 'Automaattinen - oletus, näkyy vain koko näytön tilassa.', + close_all: 'Sulje kaikki', + created: 'Luotu', + date_modified: 'Muokkauspäivämäärä', + default: 'Oletus', delete: 'Poista', - delete_permanently: "Poista Pysyvästi", - deploy_as_app: 'Levitä sovelluksena', + delete_account: "Poista tilisi", + delete_permanently: "Poista pysyvästi", + deleting_file: "Poistetaan %%", + deploy_as_app: 'Ota käyttöön sovelluksena', descending: 'Laskeva', + desktop: 'Työpöytä', desktop_background_fit: "Sovita", + developers: "Kehittäjät", dir_published_as_website: `%strong% on julkaistu osoitteessa:`, - disassociate_dir: "Erota Hakemisto", + disable_2fa: 'Ota kaksivaiheinen tunnistautuminen pois käytöstä', + disable_2fa_confirm: "Haluatko varmasti poistaa kaksivaiheisen tunnistautumisen käytöstä?", + disable_2fa_instructions: "Syötä salasanasi poistaaksesi kaksivaihesen tunnistautumisen käytöstä.", + disassociate_dir: "Irrota hakemisto", + documents: 'Dokumentit', + dont_allow: 'Älä salli', download: 'Lataa', + download_file: 'Lataa tiedosto', downloading: "Ladataan", - email: "Sähköposti", + email: "Sähköpostiosoite", + email_change_confirmation_sent: "Vahvistusviesti on lähetetty uuteen sähköpostiosoitteeseesi. Tarkista postilaatikkosi ja viimeistele prosessi seuraamalla ohjeita.", + email_invalid: 'Sähköpostiosoite on virheellinen.', email_or_username: "Sähköposti tai Käyttäjänimi", - empty_trash: 'Tyhjennä Roskakori', - empty_trash_confirmation: `Oletko varma, että haluat poistaa Roskakorin kohteet pysyvästi?`, - emptying_trash: 'Tyhjennetään Roskakori…', + email_required: 'Sähköpostiosoite vaaditaan.', + empty_trash: 'Tyhjennä roskakori', + empty_trash_confirmation: `Haluatko varmasti poistaa roskakorissa olevat kohteet pysyvästi?`, + emptying_trash: 'Tyhjennetään roskakoria...', + enable_2fa: 'Ota käyttöön kaksivaiheinen tunnistautuminen', + end_hard: "Pakotettu lopetus", + end_process_force_confirm: "Haluatko varmasti pakottaa prosessin lopetuksen?", + end_soft: "Pehmeä lopetus", + enlarged_qr_code: "Suurennettu QR-koodi", + enter_password_to_confirm_delete_user: "Syötä salasanasi vahvistaaksesi tilisi poiston", + error_message_is_missing: "Virheilmoitus puuttuu.", + error_unknown_cause: "Tuntematon virhe.", + error_uploading_files: "Tiedostojen lataaminen epäonnistui", + favorites: "Suosikit", feedback: "Palaute", feedback_c2a: "Käytä alla olevaa lomaketta lähettääksesi meille palautetta, kommentteja ja vikailmoituksia.", - feedback_sent_confirmation: "Kiitos yhteydenotosta. Jos sinulla on tiliisi liittyvä sähköpostiosoite, saat meiltä vastauksen mahdollisimman pian.", - forgot_pass_c2a: "Unohditko Salasanasi?", + feedback_sent_confirmation: "Kiitos yhteydenotostasi. Jos tiliisi on liitetty sähköpostiosoite, saat meiltä vastauksen mahdollisimman pian.", + fit: "Sovita", + folder: 'Kansio', + force_quit: 'Pakota lopetus', + forgot_pass_c2a: "Unohditko salasanasi?", - from: "From", // TODO: Context dependent, examples + from: "Henkilöltä", // TODO: Context dependent, examples // "from address" => "osoitteesta" or // "from sender" => "lähettäjältä". // In the finnish language these are usually translated as case suffixes. // "From Person" gets the suffix "-ltä", being the combination of "Henkilö(Person) and ltä(From)" - general: "General", // TODO: Conceptual ambiguity + general: "Yleinen", // TODO: Conceptual ambiguity // "general (about something)" => "Yleistä" or // "military general" => "Kenraali" get_a_copy_of_on_puter: `Hanki '%%' -kopio Puter.com-sivustolta!`, // TODO: Very difficult ambiguity due to different case suffix for any possible word that you can substitue here. Can stay as is, but it's not exactly correct. - get_copy_link: 'Get Copy Link', // TODO: Ambiguous meaning + get_copy_link: 'Hanki kopiolinkki', // TODO: Ambiguous meaning // 'get a copy of a link' => 'Ota Kopio Linkkiin' or // 'get a link to the copy' => 'Ota Linkki Kopioon' - More probable, just want to be sure - hide_all_windows: "Piilota Kaikki Ikkunat", + hide_all_windows: "Piilota kaikki ikkunat", + home: 'Koti', html_document: 'HTML-dokumentti', + hue: 'Sävy', image: 'Kuva', + incorrect_password: "Väärä salasana", invite_link: "Kutsulinkki", - items_in_trash_cannot_be_renamed: `Tätä kohdetta ei voi nimetä uudelleen, koska se on roskakorissa. Jos haluat nimetä kohteen uudelleen, raahaa se ensin pois roskakorista.`, + item: 'kohde', + items_in_trash_cannot_be_renamed: `Tätä kohdetta ei voi nimetä uudelleen, koska se on roskakorissa. Jos haluat nimetä kohteen uudelleen, palauta se ensin roskakorista.`, jpeg_image: 'JPEG-kuva', keep_in_taskbar: 'Pidä tehtäväpalkissa', + language: "Kieli", + license: "Lisenssi", + lightness: 'Valoisuus', + link_copied: "Linkki kopioitu", + loading: 'Ladataan', log_in: "Kirjaudu Sisään", - log_out: 'Kirjaudu Ulos', + log_into_another_account_anyway: 'Kirjaudu joka tapauksessa toiselle tilille', + log_out: 'Kirjaudu ulos', + looks_good: "Näyttää hyvältä!", + manage_sessions: "Hallitse istuntoja", + menubar_style: "Valikkopalkin tyyli", + menubar_style_desktop: "Työpöytä", + menubar_style_system: "Järjestelmä", + menubar_style_window: "Ikkuna", + modified: 'Muokattu', move: 'Siirrä', moving_file: "Siirretään %%", - my_websites: "Verkkosivustoni", + my_websites: "Sivustoni", name: 'Nimi', name_cannot_be_empty: 'Nimi ei voi olla tyhjä.', - name_cannot_contain_double_period: "Name can not be the '..' character.", // TODO: definition says a different thing, than the string + name_cannot_contain_double_period: "Nimi ei voi olla '..'", // TODO: definition says a different thing, than the string // "Name can not be the '..' character." => "Nimi ei voi olla '..'-merkki." or // "Name can not contain the '..' character." => "Nimi ei voi sisältää merkkiä '..'." - name_cannot_contain_period: "Name can not be the '.' character.", // TODO: definition says a different thing, than the string + name_cannot_contain_period: "Nimi ei voi olla '.'", // TODO: definition says a different thing, than the string // "Name can not be the '.' character." => "Nimi ei voi olla '.'-merkki." or // "Name can not contain the '.' character." => "Nimi ei voi sisältää merkkiä '.'." @@ -134,93 +216,193 @@ const fi = { name_must_be_string: "Nimi voi olla vain merkkijono.", name_too_long: `Nimi ei voi olla pidempi kuin %% merkkiä.`, new: 'Uusi', + new_email: 'New Email', new_folder: 'Uusi kansio', - new_password: "Uusi Salasana", - new_username: "Uusi Käyttäjänimi", - no_dir_associated_with_site: 'Osoitteeseen ei liity mitään hakemistoa.', - no_websites_published: "Et ole vielä julkaissut yhtään verkkosivustoa.", + new_password: "Uusi salasana", + new_username: "Uusi käyttäjänimi", + no: 'Ei', + no_dir_associated_with_site: 'Tähän osoitteeseen ei ole liitetty hakemistoa.', + no_websites_published: "Et ole vielä julkaissut yhtään verkkosivustoa. Napsauta kansiota hiiren kakkospainikkeella aloittaaksesi.", ok: 'OK', open: "Avaa", - open_in_new_tab: "Avaa uudessa Välilehdessä", - open_in_new_window: "Avaa uudessa Ikkunassa", + open_in_new_tab: "Avaa uudessa välilehdessä", + open_in_new_window: "Avaa uudessa ikkunassa", - open_with: "Open With", // TODO: Context dependent + open_with: "Avaa sovelluksessa", // TODO: Context dependent // "Open" => "Avaa", can be "Avaa..." in this context or // "Open With" is often translated in the context of "Open With Application" => "Avaa Sovelluksessa" + original_name: 'Alkuperäinen nimi', + original_path: 'Alkuperäinen polku', + oss_code_and_content: "Avoimen lähdekoodin ohjelmisto ja sisältö", password: "Salasana", password_changed: "Salasana vaihdettu.", - passwords_do_not_match: '`Uusi Salasana` ja `Vahvista Uusi Salasana` eivät täsmää.', + password_recovery_rate_limit: "Olet ylittänyt pyyntörajamme. Ole hyvä, ja odota muutama minuutti. Estääksesi tätä tapahtumasta uudelleen, vältä uudelleenlataamasta sivua liian monta kertaa.", + password_recovery_token_invalid: "Tämä salasanan palautustunnus ei ole enää voimassa.", + password_recovery_unknown_error: "Tuntematon virhe. Yritä myöhemmin uudelleen.", + password_required: 'Salasana vaaditaan.', + password_strength_error: "Salasanan tulee olla vähintään 8 merkkiä pitkä ja sisältää vähintään yhden ison kirjaimen, yhden pienen kirjaimen, yhden numeron ja yhden erikoismerkin.", + passwords_do_not_match: '`Uusi salasana` ja `Vahvista uusi salasana` eivät täsmää.', paste: 'Liitä', - paste_into_folder: "Liitä Kansioon", + paste_into_folder: "Liitä kansioon", + path: 'Polku', + personalization: "Personointi", pick_name_for_website: "Valitse nimi verkkosivustollesi:", picture: "Kuva", - powered_by_puter_js: `Tämän Mahdollistaa {{link=docs}}Puter.js{{/link}}`, + pictures: 'Kuvat', + plural_suffix: 't', + powered_by_puter_js: `Palvelun tarjoaa {{link=docs}}Puter.js{{/link}}`, preparing: "Valmistellaan...", preparing_for_upload: "Valmistellaan latausta...", + print: 'Tulosta', + privacy: "Yksityisyys", + proceed_to_login: 'Jatka sisäänkirjautumiseen', + proceed_with_account_deletion: "Jatka tilin poistamista", + process_status_initializing: "Alustetaan", + process_status_running: "Käynnissä", + process_type_app: 'Sovellus', + process_type_init: 'Alustava', + process_type_ui: 'Käyttöliittymä', properties: "Ominaisuudet", + public: 'Julkinen', publish: "Julkaise", publish_as_website: 'Julkaise verkkosivustona', + puter_description: `Puter on yksityisyyttä korostava henkilökohtainen pilvipalvelu, jossa voit säilyttää kaikki tiedostosi, sovelluksesi ja pelisi yhdessä turvallisessa paikassa, ja jotka ovat saatavilla mistä tahansa milloin tahansa.`, + reading_file: "Luetaan %strong%", recent: "Viimeisimmät", - recover_password: "Palauta Salasana", - refer_friends_c2a: "Saat 1 Gt tilaa jokaisesta kaverista, joka luo ja vahvistaa tilin Puterissa. Myös kaverisi saa 1 Gt tilaa!", + recommended: "Suositellut", + recover_password: "Palauta salasanasi", + refer_friends_c2a: "Saat 1 Gt ilmaista tallennustilaa jokaisesta ystävästä, joka luo ja vahvistaa tilin Puterissa. Myös ystäväsi saa 1 Gt:n ilmaista tallennustilaa!", refer_friends_social_media_c2a: `Hanki 1 Gt ilmaista tallennustilaa Puter.comista!`, refresh: 'Päivitä', - release_address_confirmation: `Are you sure you want to release this address?`, // TODO: Slight ambiguity between the meaning of "release" + release_address_confirmation: `Haluatko varmasti julkaista tämän osoitteen?`, // TODO: Slight ambiguity between the meaning of "release" // "get rid of" => "Oletko varma, että haluat luovuttaa tämän osoitteen?" or // "publish" => "Oletko varma, että haluat julkaista tämän osoitteen?" - remove_from_taskbar:'Poista Tehtäväpalkista', + remove_from_taskbar:'Poista tehtäväpalkista', rename: 'Nimeä uudelleen', repeat: 'Toista', - resend_confirmation_code: "Lähetä Vahvistuskoodi Uudelleen", + replace: 'Replace', + replace_all: 'Korvaa kaikki', + resend_confirmation_code: "Lähetä vahvistuskoodi Uudelleen", + reset_colors: "Palauta värit", + restart_puter_confirm: "Haluatko varmasti käynnistää Puterin uudelleen?", restore: "Palauta", + save: 'Tallenna', + saturation: 'Kylläisyys', + save_account: 'Tallenna tili', save_account_to_get_copy_link: "Luo tili jatkaaksesi.", save_account_to_publish: 'Luo tili jatkaaksesi.', - save_session_c2a: 'Luo tili tallentaaksesi nykyisen istuntosi ja välttyäksesi työn menettämiseltä.', - scan_qr_c2a: 'Skannaa alla oleva koodi kirjautuaksesi tähän istuntoon muista laitteista', + save_session: 'Tallenna istunto', + save_session_c2a: 'Luo tili tallentaaksesi nykyisen istuntosi ja välttääksesi työsi menettämisen.', + scan_qr_c2a: 'Skannaa alla oleva koodi kirjautuaksesi tähän istuntoon muilla laitteilla.', + scan_qr_2fa: 'Skannaa QR-koodi todennussovelluksellasi', + scan_qr_generic: 'Skannaa tämä QR-koodi puhelimellasi tai toisella laitteella.', + search: 'Etsi', + seconds: 'sekuntia', + security: "Turvallisuus", select: "Valitse", + selected: 'valitut', select_color: 'Valitse väri…', + sessions: "Istunnot", send: "Lähetä", - send_password_recovery_email: "Lähetä Salasanan Palautussähköposti", + send_password_recovery_email: "Lähetä salasanan palautussähköposti", session_saved: "Kiitos tilin luomisesta. Tämä istunto on tallennettu.", - set_new_password: "Aseta Uusi Salasana", + settings: "Asetukset", + set_new_password: "Aseta uusi salasana", + share: "Jaa", - share_to: "Share to", // TODO: Grammatical ambiguity + share_to: "Jaa", // TODO: Grammatical ambiguity // The base form of "Share" is "Jaa". So maybe "Jaa..." is appropriate? // If "share to" is followed by the name of a user, it will not make any sense, as the name can be suffixed by for example "Jaa %%lle". - show_all_windows: "Näytä Kaikki Ikkunat", - show_hidden: 'Näytä piilotettu', + share_with: "Jaa:", + shortcut_to: "Pikakuvake", + show_all_windows: "Näytä kaikki ikkunat", + show_hidden: 'Näytä piilotetut', sign_in_with_puter: "Kirjaudu sisään Puterilla", sign_up: "Rekisteröidy", signing_in: "Kirjaudutaan sisään…", size: 'Koko', - sort_by: 'Lajittele:', + skip: 'Ohita', + something_went_wrong: "Jokin meni pieleen.", + sort_by: 'Lajittele', start: 'Käynnistä', - taking_longer_than_usual: 'Kestää hieman tavallista kauemmin. Odottakaa...', + status: "Tila", + storage_usage: "Tallennustilan käyttö", + storage_puter_used: 'Puterin käyttämä', + taking_longer_than_usual: 'Kestää hieman tavallista kauemmin. Ole hyvä ja odota...', + task_manager: "Tehtävienhallinta", + taskmgr_header_name: "Nimi", + taskmgr_header_status: "Tila", + taskmgr_header_type: "Tyyppi", + terms: "Ehdot", text_document: 'Tekstiasiakirja', - tos_fineprint: `Klikkaamalla 'Luo ilmainen tili' hyväksyt Puterin käyttöehdot ja tietosuojakäytännön.`, + tos_fineprint: `Klikkaamalla 'Luo ilmainen tili' hyväksyt Puterin {{link=terms}}käyttöehdot{{/link}} ja {{link=privacy}}tietosuojakäytännön{{/link}}.`, + transparency: "Läpinäkyvyys", - trash: 'Trash', // TODO: Ambiguous meaning + trash: 'Roskakori', // TODO: Ambiguous meaning // "Trash" is oft used to just mean "Trash bin" => 'Roskakori' or // "Trash" by itself => 'Roska' - type: 'Type', // TODO: Ambiguous meaning + two_factor: 'Kaksivaiheinen tunnistautuminen', + two_factor_disabled: 'Kaksivaiheinen tunnistautuminen poissa käytöstä', + two_factor_enabled: 'Kaksivaiheinen tunnistautuminen käytössä', + + type: 'Kirjoita', // TODO: Ambiguous meaning // "Type of an object" => 'Tyyppi' or // "Type on the keyboard" => 'Kirjoita' + type_confirm_to_delete_account: "Kirjoita 'vahvista' poistaaksesi tilisi.", + ui_colors: "Käyttöliittymän värit", + ui_manage_sessions: "Istunnon hallinta", + ui_revoke: "Peruuta", undo: 'Kumoa', - unzip: "Pura zip", + unlimited: 'Rajoittamaton', + unzip: "Pura zip-tiedosto", upload: 'Lataa', upload_here: 'Lataa tähän', + usage: 'Käyttö', username: "Käyttäjänimi", username_changed: 'Käyttäjänimi päivitetty onnistuneesti.', + username_required: 'Käyttäjänimi vaaditaan.', versions: "Versiot", - yes_release_it: 'Kyllä, Julkaise Se', - you_have_been_referred_to_puter_by_a_friend: "Kaverisi on kutsunut sinut Puterille!", + videos: 'Videot', + visibility: 'Näkyvyys', + yes: 'Kyllä', + yes_release_it: 'Kyllä, julkaise se', + you_have_been_referred_to_puter_by_a_friend: "Kaverisi on kutsunut sinut Puteriin!", zip: "Zip", + zipping_file: "Zipataan %strong%", + + // === 2FA Setup === + setup2fa_1_step_heading: 'Avaa todennussovelluksesi', + setup2fa_1_instructions: ` + Voit käyttää mitä tahansa todennussovellusta, joka tukee aikaperusteista kertakirjautumissalasanaa (TOTP-protokollaa). + Valittavanasi on monia sovelluksia, mutta jos et ole varma, + Authy on hyvä valinta Androidille ja iOS:lle. + `, + setup2fa_2_step_heading: 'Skannaa QR-koodi', + setup2fa_3_step_heading: 'Syötä kuusinumeroinen koodi', + setup2fa_4_step_heading: 'Kopioi palautuskoodisi', + setup2fa_4_instructions: ` + Nämä palautuskoodit ovat ainoa tapa päästä tiliisi, jos menetät puhelimesi tai et voi käyttää todennussovellustasi. + Varmista, että säilytät ne turvallisessa paikassa. + `, + setup2fa_5_step_heading: 'Vahvista kaksivaiheisen tunnistautumisen asetukset', + setup2fa_5_confirmation_1: 'Olen tallentanut palautuskoodini turvalliseen paikkaan', + setup2fa_5_confirmation_2: 'Olen valmis ottamaan kaksivaiheisen tunnistautumisen käyttöön', + setup2fa_5_button: 'Ota kaksivaiheinen tunnistautuminen käyttöön', + + // === 2FA Login === + login2fa_otp_title: 'Syötä kaksivaiheisen tunnistautumisen koodi', + login2fa_otp_instructions: 'Syötä kuusinumeroinen koodi todennussovelluksestasi.', + login2fa_recovery_title: 'Syötä palautuskoodi', + login2fa_recovery_instructions: 'Syötä yksi palautuskoodeistasi saadaksesi pääsy tilillesi.', + login2fa_use_recovery_code: 'Käytä palautuskoodi', + login2fa_recovery_back: 'Takaisin', + login2fa_recovery_placeholder: 'XXXXXXXX', } } From 902bde3c2dd15416dcdab618bb4415ce0e9198d9 Mon Sep 17 00:00:00 2001 From: looz0 Date: Mon, 12 Aug 2024 19:20:21 -0700 Subject: [PATCH 0672/2119] Add security email to contact section --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index c1df7e22fb..126f8f45ec 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,7 @@ Connect with the maintainers and community through these channels: - X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) - Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) - Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) +- Security issues? [security@puter.com](mailto:security@puter.com) - Email maintainers at [hi@puter.com](mailto:hi@puter.com) We are always happy to help you with any questions you may have. Don't hesitate to ask! From f00e0cf4a6fabeef93c7e0748d0b999cadb2b749 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 13 Aug 2024 20:42:40 -0700 Subject: [PATCH 0673/2119] Add YouTube link to README.md --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index 126f8f45ec..70b4313a58 100644 --- a/README.md +++ b/README.md @@ -16,6 +16,8 @@ · Discord · + YouTube + · Reddit · X (Twitter) From f7924f30bc74ee59d1de60a010c4c13e68b5a97d Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 14 Aug 2024 00:59:58 -0700 Subject: [PATCH 0674/2119] Create README.en.md --- doc/i18n/README.en.md | 132 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 doc/i18n/README.en.md diff --git a/doc/i18n/README.en.md b/doc/i18n/README.en.md new file mode 100644 index 0000000000..70b4313a58 --- /dev/null +++ b/doc/i18n/README.en.md @@ -0,0 +1,132 @@ +

Puter.com, The Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time.

+ +

The Internet OS! Free, Open-Source, and Self-Hostable.

+ +

+ GitHub repo size GitHub Release GitHub License +

+ +

+ « LIVE DEMO » +
+
+ Puter.com + · + SDK + · + Discord + · + YouTube + · + Reddit + · + X (Twitter) + · + Bug Bounty +

+ +

screenshot

+ +
+ +## Puter + +Puter is an advanced, open-source internet operating system designed to be feature-rich, exceptionally fast, and highly extensible. Puter can be used as: + +- A privacy-first personal cloud to keep all your files, apps, and games in one secure place, accessible from anywhere at any time. +- A platform for building and publishing websites, web apps, and games. +- An alternative to Dropbox, Google Drive, OneDrive, etc. with a fresh interface and powerful features. +- A remote desktop environment for servers and workstations. +- A friendly, open-source project and community to learn about web development, cloud computing, distributed systems, and much more! + +
+ +## Getting Started + + +### 💻 Local Development + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +This will launch Puter at http://localhost:4000 (or the next available port). + +
+ +### 🐳 Docker + + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ + +### 🐙 Docker Compose + + +#### Linux/macOS +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` +
+ +#### Windows + + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +### ☁️ Puter.com + +Puter is available as a hosted service at [**puter.com**](https://puter.com). + +
+ +## System Requirements + +- **Operating Systems:** Linux, macOS, Windows +- **RAM:** 2GB minimum (4GB recommended) +- **Disk Space:** 1GB free space +- **Node.js:** Version 16+ (Version 22+ recommended) +- **npm:** Latest stable version + +
+ +## Support + +Connect with the maintainers and community through these channels: + +- Bug report or feature request? Please [open an issue](github.com/HeyPuter/puter/issues/new/choose). +- Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) +- Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) +- Security issues? [security@puter.com](mailto:security@puter.com) +- Email maintainers at [hi@puter.com](mailto:hi@puter.com) + +We are always happy to help you with any questions you may have. Don't hesitate to ask! + +
+ + +## License + +This repository, including all its contents, sub-projects, modules, and components, is licensed under [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) unless explicitly stated otherwise. Third-party libraries included in this repository may be subject to their own licenses. + +
From ebaec99741e569a5409158c39e5227bb93818ff6 Mon Sep 17 00:00:00 2001 From: Jes Bak Hansen Date: Wed, 14 Aug 2024 15:24:47 +0200 Subject: [PATCH 0675/2119] Add Danish translation of README.en.md --- doc/i18n/README.da.md | 132 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 doc/i18n/README.da.md diff --git a/doc/i18n/README.da.md b/doc/i18n/README.da.md new file mode 100644 index 0000000000..cf9277ba4d --- /dev/null +++ b/doc/i18n/README.da.md @@ -0,0 +1,132 @@ +

Puter.com, Den Personlige Cloudcomputer: Alle dine filer, apps og spil på ét sted tilgængelige fra hvor som helst til enhver tid.

+ +

Internet OS'et! Gratis, Open-Source og kan selvhostes.

+ +

+ GitHub repo størrelse GitHub Udgivelse GitHub Licens +

+ +

+ « LIVE DEMO » +
+
+ Puter.com + · + SDK + · + Discord + · + YouTube + · + Reddit + · + X (Twitter) + · + Bug Bounty +

+ +

skærmbillede

+ +
+ +## Puter + +Puter er et avanceret, open-source internetoperativsystem designet til at være funktionsrigt, exceptionelt hurtigt og meget udvideligt. Puter kan bruges som: + +- En privatlivsfokuseret personlig sky til at opbevare alle dine filer, apps og spil på ét sikkert sted, tilgængeligt hvor som helst og når som helst. +- En platform til at bygge og publicere hjemmesider, webapplikationer og spil. +- Et alternativ til Dropbox, Google Drive, OneDrive osv. med et friskt interface og kraftfulde funktioner. +- Et fjernskrivebordsmiljø for servere og arbejdsstationer. +- Et venligt, open-source projekt og fællesskab til at lære om webudvikling, cloud computing, distribuerede systemer og meget mere! + +
+ +## Kom godt i gang + + +### 💻 Lokal Udvikling + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +Dette vil starte Puter på http://localhost:4000 (eller den næste tilgængelige port). + +
+ +### 🐳 Docker + + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ + +### 🐙 Docker Compose + + +#### Linux/macOS +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` +
+ +#### Windows + + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +### ☁️ Puter.com + +Puter er tilgængelig som en hosted tjeneste på [**puter.com**](https://puter.com). + +
+ +## Systemkrav + +- **Operativsystemer:** Linux, macOS, Windows +- **RAM:** 2GB minimum (4GB anbefales) +- **Diskplads:** 1GB fri plads +- **Node.js:** Version 16+ (Version 22+ anbefales) +- **npm:** Seneste stabile version + +
+ +## Support + +Kom i kontakt med vedligeholderne og fællesskabet gennem disse kanaler: + +- Bugrapport eller funktionønske? Åbn [venligst en sag](github.com/HeyPuter/puter/issues/new/choose). +- Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) +- Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) +- Sikkerhedsspørgsmål? [security@puter.com](mailto:security@puter.com) +- Send email til vedligeholdere på [hi@puter.com](mailto:hi@puter.com) + +Vi er altid glade for at hjælpe dig med eventuelle spørgsmål, du måtte have. Tøv ikke med at spørge! + +
+ + +## Licens + +Dette repository, inklusive alt dets indhold, underprojekter, moduler og komponenter, er licenseret under [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt), medmindre andet er udtrykkeligt angivet. Tredjepartsbiblioteker inkluderet i dette repository kan være underlagt deres egne licenser. + +
From 4f8786fc8f53dd50c055bb110a00be7bf04b2bce Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 14 Aug 2024 07:40:37 -0700 Subject: [PATCH 0676/2119] Add link to Danish README in the English Readme --- README.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/README.md b/README.md index 70b4313a58..b1b6fb9632 100644 --- a/README.md +++ b/README.md @@ -130,3 +130,8 @@ We are always happy to help you with any questions you may have. Don't hesitate This repository, including all its contents, sub-projects, modules, and components, is licensed under [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) unless explicitly stated otherwise. Third-party libraries included in this repository may be subject to their own licenses.
+ +## Translations + +- [Danish / Dansk](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.da.md) +- [English](https://github.com/HeyPuter/puter/blob/main/README.md) From 3dd3ae02ae0bd32c12416bfe3377e38b12079042 Mon Sep 17 00:00:00 2001 From: Tatiana Magnus Vianna Date: Wed, 14 Aug 2024 11:51:38 -0300 Subject: [PATCH 0677/2119] Adding readme portuguese translation --- doc/i18n/README.pt.md | 132 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 doc/i18n/README.pt.md diff --git a/doc/i18n/README.pt.md b/doc/i18n/README.pt.md new file mode 100644 index 0000000000..b899eebb04 --- /dev/null +++ b/doc/i18n/README.pt.md @@ -0,0 +1,132 @@ +

Puter.com, O Computador Pessoal em Nuvem: Todos os seus arquivos, aplicativos e jogos em um único lugar, acessíveis de qualquer lugar e a qualquer hora.

+ +

O Sistema Operacional da Internet! Gratuito, de Código Aberto e Auto-Hospedável.

+ +

+ Tamanho do repositório do GitHub Lançamento no GitHub Licença do GitHub +

+ +

+ « DEMONSTRAÇÃO AO VIVO » +
+
+ Puter.com + · + SDK + · + Discord + · + YouTube + · + Reddit + · + X (Twitter) + · + Recompensa por Bugs +

+ +

screenshot

+ +
+ +## Puter + +Puter é um sistema operacional de internet avançado e de código aberto, projetado para ser rico em recursos, excepcionalmente rápido e altamente extensível. Puter pode ser usado como: + +- Um serviço de nuvem pessoal com foco na privacidade para manter todos os seus arquivos, aplicativos e jogos em um local seguro, acessível de qualquer lugar e a qualquer hora. +- Uma plataforma para construir e publicar websites, aplicativos web e jogos. +- Uma alternativa ao Dropbox, Google Drive, OneDrive, etc., com uma interface renovada e recursos poderosos. +- Um ambiente de desktop remoto para servidores e estações de trabalho. +- Um projeto e comunidade de código aberto e amigável para aprender sobre desenvolvimento web, computação em nuvem, sistemas distribuídos e muito mais! + +
+ +## Iniciando o Projeto + + +### 💻 Desenvolvimento Local + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +Isso iniciará o Puter em http://localhost:4000 (ou na próxima porta disponível). + +
+ +### 🐳 Docker + + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ + +### 🐙 Docker Compose + + +#### Linux/macOS +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` +
+ +#### Windows + + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +### ☁️ Puter.com + +O Puter está disponível como um serviço hospedado em [**puter.com**](https://puter.com). + +
+ +## Requerimentos do sistema + +- **Sistema operacional:** Linux, macOS, Windows +- **RAM:** 2GB mínimo (4GB recomendado) +- **Espaço de disco:** 1GB de espaço disponível +- **Node.js:** Versão 16+ (Versão 22+ recomendada) +- **npm:** Última versão estável + +
+ +## Suporte + +Conecte-se com os mantenedores e a comunidade através destes canais: + +- Relato de bug ou solicitação de recurso? Por favor, [abra um tópico](github.com/HeyPuter/puter/issues/new/choose). +- Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) +- Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) +- Problemas de segurança? [security@puter.com](mailto:security@puter.com) +- Envie um email para os mantenedores em [hi@puter.com](mailto:hi@puter.com) + +Estamos sempre felizes em ajudá-lo com quaisquer perguntas que você possa ter. Não hesite em perguntar! + +
+ + +## Licença + +Este repositório, incluindo todos os seus conteúdos, subprojetos, módulos e componentes, está licenciado sob [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) a menos que explicitamente indicado de outra forma. Bibliotecas de terceiros incluídas neste repositório podem estar sujeitas às suas próprias licenças. + +
From c98d1ca25e34d4865c64e8d52d1303d33155d4d5 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 14 Aug 2024 08:23:09 -0700 Subject: [PATCH 0678/2119] Add link to the Portuguese README in the English README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index b1b6fb9632..be544be225 100644 --- a/README.md +++ b/README.md @@ -135,3 +135,4 @@ This repository, including all its contents, sub-projects, modules, and componen - [Danish / Dansk](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.da.md) - [English](https://github.com/HeyPuter/puter/blob/main/README.md) +- [Portuguese / Português](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.pt.md) From 93d475b6b30a8d4c6d615b4fa0c1f5051e72a9ce Mon Sep 17 00:00:00 2001 From: Danil Buslaev Date: Wed, 14 Aug 2024 19:20:18 +0300 Subject: [PATCH 0679/2119] added readme translation into Russian --- doc/i18n/README.ru.md | 132 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 doc/i18n/README.ru.md diff --git a/doc/i18n/README.ru.md b/doc/i18n/README.ru.md new file mode 100644 index 0000000000..b68e04e843 --- /dev/null +++ b/doc/i18n/README.ru.md @@ -0,0 +1,132 @@ +

Puter.com, персональный облачный компьютер: все ваши файлы, приложения и игры в одном месте, доступные из любой точки мира в любое время.

+ +

Интернет ОС! Бесплатная, с открытым исходным кодом и возможностью самостоятельной установки.

+ +

+ Размер репозитория GitHub Релиз GitHub Лицензия GitHub +

+ +

+ « ЖИВОЕ ДЕМО » +
+
+ Puter.com + · + SDK + · + Discord + · + YouTube + · + Reddit + · + X (Twitter) + · + Bug Bounty +

+ +

screenshot

+ +
+ +## Puter + +Puter — это передовая операционная система с открытым исходным кодом, разработанная для обеспечения широкого функционала, исключительной скорости и высокой масштабируемости. Puter можно использовать как: + +- Персональное облако с приоритетом конфиденциальности для хранения всех ваших файлов, приложений и игр в одном безопасном месте, доступном из любой точки мира в любое время. +- Платформа для создания и публикации веб-сайтов, веб-приложений и игр. +- Альтернатива Dropbox, Google Drive, OneDrive и т. д. с новым интерфейсом и мощными функциями. +- Удаленное рабочее окружение для серверов и рабочих станций. +- Дружественный проект с открытым исходным кодом и сообщество для изучения веб-разработки, облачных вычислений, распределенных систем и многого другого! + +
+ +## Начало работы + + +### 💻 Локальная разработка + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +Это запустит Puter по адресу http://localhost:4000 (или на следующем доступном порту). + +
+ +### 🐳 Docker + + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ + +### 🐙 Docker Compose + + +#### Linux/macOS +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` +
+ +#### Windows + + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +### ☁️ Puter.com + +Puter доступен как облачный сервис на [**puter.com**](https://puter.com). + +
+ +## Системные требования + +- **Операционные системы:** Linux, macOS, Windows +- **ОЗУ:** минимум 2 ГБ (рекомендуется 4 ГБ) +- **Место на диске:** 1 ГБ свободного места +- **Node.js:** Версия 16+ (рекомендуется версия 22+) +- **npm:** Последняя стабильная версия + +
+ +## Поддержка + +Свяжитесь с разработчиками и сообществом этими способами: + +- Отчет об ошибке или запрос функции? Пожалуйста, [откройте вопрос](github.com/HeyPuter/puter/issues/new/choose). +- Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) +- Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) +- Проблемы безопасности? [security@puter.com](mailto:security@puter.com) +- Свяжитесь с разработчиками по адресу [hi@puter.com](mailto:hi@puter.com) + +Мы всегда рады помочь вам с любыми вопросами. Не стесняйтесь спрашивать! + +
+ + +## Лицензия + +Этот репозиторий, включая все его содержимое, подпроекты, модули и компоненты, лицензирован в соответствии с [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt), если явно не указано иное. Сторонние библиотеки, включенные в этот репозиторий, могут подпадать под действие их собственных лицензий. + +
From 82dec20c07716b5bf76d01b38ca9e6544b4d7287 Mon Sep 17 00:00:00 2001 From: Danil Buslaev Date: Wed, 14 Aug 2024 19:45:14 +0300 Subject: [PATCH 0680/2119] added translation link to readme --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index be544be225..a1dc709471 100644 --- a/README.md +++ b/README.md @@ -136,3 +136,5 @@ This repository, including all its contents, sub-projects, modules, and componen - [Danish / Dansk](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.da.md) - [English](https://github.com/HeyPuter/puter/blob/main/README.md) - [Portuguese / Português](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.pt.md) +- [Russian / Русский](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ru.md) + From 4cd94df90c2c59eac04245e7cb4499c93d8a8e68 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 14 Aug 2024 10:54:09 -0700 Subject: [PATCH 0681/2119] Use the correct local dev address in README files --- README.md | 2 +- doc/i18n/README.da.md | 2 +- doc/i18n/README.en.md | 2 +- doc/i18n/README.pt.md | 2 +- doc/i18n/README.ru.md | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/README.md b/README.md index a1dc709471..2135562494 100644 --- a/README.md +++ b/README.md @@ -53,7 +53,7 @@ npm install npm start ``` -This will launch Puter at http://localhost:4000 (or the next available port). +This will launch Puter at http://puter.localhost:4100 (or the next available port).
diff --git a/doc/i18n/README.da.md b/doc/i18n/README.da.md index cf9277ba4d..a52a3fdb40 100644 --- a/doc/i18n/README.da.md +++ b/doc/i18n/README.da.md @@ -53,7 +53,7 @@ npm install npm start ``` -Dette vil starte Puter på http://localhost:4000 (eller den næste tilgængelige port). +Dette vil starte Puter på http://puter.localhost:4100 (eller den næste tilgængelige port).
diff --git a/doc/i18n/README.en.md b/doc/i18n/README.en.md index 70b4313a58..dda7ef3f32 100644 --- a/doc/i18n/README.en.md +++ b/doc/i18n/README.en.md @@ -53,7 +53,7 @@ npm install npm start ``` -This will launch Puter at http://localhost:4000 (or the next available port). +This will launch Puter at http://puter.localhost:4100 (or the next available port).
diff --git a/doc/i18n/README.pt.md b/doc/i18n/README.pt.md index b899eebb04..2b3a4efab1 100644 --- a/doc/i18n/README.pt.md +++ b/doc/i18n/README.pt.md @@ -53,7 +53,7 @@ npm install npm start ``` -Isso iniciará o Puter em http://localhost:4000 (ou na próxima porta disponível). +Isso iniciará o Puter em http://puter.localhost:4100 (ou na próxima porta disponível).
diff --git a/doc/i18n/README.ru.md b/doc/i18n/README.ru.md index b68e04e843..70cfa14e3d 100644 --- a/doc/i18n/README.ru.md +++ b/doc/i18n/README.ru.md @@ -53,7 +53,7 @@ npm install npm start ``` -Это запустит Puter по адресу http://localhost:4000 (или на следующем доступном порту). +Это запустит Puter по адресу http://puter.localhost:4100 (или на следующем доступном порту).
From 11695846fac5d1388456e239f60fc8cf3b5ec3c5 Mon Sep 17 00:00:00 2001 From: Danil Buslaev Date: Wed, 14 Aug 2024 21:34:44 +0300 Subject: [PATCH 0682/2119] fix broken links in readme --- doc/i18n/README.da.md | 2 +- doc/i18n/README.en.md | 2 +- doc/i18n/README.pt.md | 2 +- doc/i18n/README.ru.md | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/doc/i18n/README.da.md b/doc/i18n/README.da.md index cf9277ba4d..c51251caf6 100644 --- a/doc/i18n/README.da.md +++ b/doc/i18n/README.da.md @@ -112,7 +112,7 @@ Puter er tilgængelig som en hosted tjeneste på [**puter.com**](https://puter.c Kom i kontakt med vedligeholderne og fællesskabet gennem disse kanaler: -- Bugrapport eller funktionønske? Åbn [venligst en sag](github.com/HeyPuter/puter/issues/new/choose). +- Bugrapport eller funktionønske? Åbn [venligst en sag](https://github.com/HeyPuter/puter/issues/new/choose). - Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) - X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) - Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) diff --git a/doc/i18n/README.en.md b/doc/i18n/README.en.md index 70b4313a58..96a513dccb 100644 --- a/doc/i18n/README.en.md +++ b/doc/i18n/README.en.md @@ -112,7 +112,7 @@ Puter is available as a hosted service at [**puter.com**](https://puter.com). Connect with the maintainers and community through these channels: -- Bug report or feature request? Please [open an issue](github.com/HeyPuter/puter/issues/new/choose). +- Bug report or feature request? Please [open an issue](https://github.com/HeyPuter/puter/issues/new/choose). - Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) - X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) - Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) diff --git a/doc/i18n/README.pt.md b/doc/i18n/README.pt.md index b899eebb04..1214535591 100644 --- a/doc/i18n/README.pt.md +++ b/doc/i18n/README.pt.md @@ -112,7 +112,7 @@ O Puter está disponível como um serviço hospedado em [**puter.com**](https:// Conecte-se com os mantenedores e a comunidade através destes canais: -- Relato de bug ou solicitação de recurso? Por favor, [abra um tópico](github.com/HeyPuter/puter/issues/new/choose). +- Relato de bug ou solicitação de recurso? Por favor, [abra um tópico](https://github.com/HeyPuter/puter/issues/new/choose). - Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) - X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) - Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) diff --git a/doc/i18n/README.ru.md b/doc/i18n/README.ru.md index b68e04e843..30dccf55f5 100644 --- a/doc/i18n/README.ru.md +++ b/doc/i18n/README.ru.md @@ -112,7 +112,7 @@ Puter доступен как облачный сервис на [**puter.com**] Свяжитесь с разработчиками и сообществом этими способами: -- Отчет об ошибке или запрос функции? Пожалуйста, [откройте вопрос](github.com/HeyPuter/puter/issues/new/choose). +- Отчет об ошибке или запрос функции? Пожалуйста, [откройте вопрос](https://github.com/HeyPuter/puter/issues/new/choose). - Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) - X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) - Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) From bf4ba3f1d6d9bb6907ce30bffb7ce156ec555e89 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 14 Aug 2024 12:38:00 -0700 Subject: [PATCH 0683/2119] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2135562494..f8c4517717 100644 --- a/README.md +++ b/README.md @@ -112,7 +112,7 @@ Puter is available as a hosted service at [**puter.com**](https://puter.com). Connect with the maintainers and community through these channels: -- Bug report or feature request? Please [open an issue](github.com/HeyPuter/puter/issues/new/choose). +- Bug report or feature request? Please [open an issue](https://github.com/HeyPuter/puter/issues/new/choose). - Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) - X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) - Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) From 0d3af0048fa472bef3883b9ee66d2cf02546fa8d Mon Sep 17 00:00:00 2001 From: juank0205 Date: Wed, 14 Aug 2024 16:09:26 -0500 Subject: [PATCH 0684/2119] translate README.md to spanish --- doc/i18n/README.es.md | 132 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 doc/i18n/README.es.md diff --git a/doc/i18n/README.es.md b/doc/i18n/README.es.md new file mode 100644 index 0000000000..d7a2f22b63 --- /dev/null +++ b/doc/i18n/README.es.md @@ -0,0 +1,132 @@ +

Puter.com, El Computador Personal en Nube: Todos tus archivos, apps y juegos en un solo lugar accesible desde cualquier lugar en cualquier momento

+ +

El Sistema Operativo de Internet! Gratis, de Código abierto, y Autohospedable.

+ +

+ GitHub repo size GitHub Release GitHub License +

+ +

+ « DEMO EN VIVO » +
+
+ Puter.com + · + SDK + · + Discord + · + YouTube + · + Reddit + · + X (Twitter) + · + Recompensa por bugs +

+ +

screenshot

+ +
+ +## Puter + +Puter es un sistema operativo en internet avanzado y de código abierto, diseñado para ser rico en funcionalidades, excepcionalmente rápido y altamente extensible. Puter puede ser usado como: + +- Una nube personal privada para almacenar todos tus archivos, aplicaciones y juegos en un lugar seguro, accesible y desde cualquier lugar en cualquier momento. +- Una plataforma para construir y publicar páginas web, aplicativos sobre la web y juegos. +- Una alternativa a Dropbox, Google Drive, OneDrive, etc. con una interfaz fresca y llena de funcionalidades. +- Un entorno de escritorio remoto para servidores y estaciones de trabajo. +- Un proyecto y comunidad abiertas y amigables para aprender sobre desarrollo web, computación en la nube, sistemas distribuidos y mucho más! + +
+ +## Primeros Pasos + + +### 💻 Desarrollo Local + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +Esto ejecutará Puter en http://puter.localhost:4100 (o el siguiente puerto disponible). + +
+ +### 🐳 Docker + + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ + +### 🐙 Docker Compose + + +#### Linux/macOS +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` +
+ +#### Windows + + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +### ☁️ Puter.com + +Puter está disponible como servicio alojado en [**puter.com**](https://puter.com). + +
+ +## Requerimientos del sistema + +- **Sistemas operativos:** Linux, macOS, Windows +- **RAM:** 2GB mínimo (4GB recomendados) +- **Almacenamiento:** 1GB de espacio libre +- **Node.js:** Versión 16+ (Versión 22+ recomendada) +- **npm:** Última version estable + +
+ +## Soporte + +Conéctate con los mantenedores y la comunidad a través de estos canales: + +- Reporte de bug o solicitud de funcionalidad? Por favor [abrir un issue](https://github.com/HeyPuter/puter/issues/new/choose). +- Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) +- Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) +- Problemas de seguridad? [security@puter.com](mailto:security@puter.com) +- Envia un email a los mantenedores en [hi@puter.com](mailto:hi@puter.com) + +Estamos siempre felices de ayudar con cualquier pregunta que puedas tener. No dudes en preguntar! + +
+ + +## Licencia + +Este repositorio, incluyendo todo su contenido, sub-proyectos, modulos y componentes, esta licenciado bajo [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) a menos que se indique explícitamente lo contrario. Librerías de terceros incluidos en este repositorio pueden estar sujetas a sus propias licencias. + +
From d4319ea072e0793a32dbddb1d456227cf481e42c Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 14 Aug 2024 17:20:09 -0400 Subject: [PATCH 0685/2119] fix: sqlite condition in MonthlyUsageService --- src/backend/src/services/sla/MonthlyUsageService.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/backend/src/services/sla/MonthlyUsageService.js b/src/backend/src/services/sla/MonthlyUsageService.js index 1718039a76..696f311c33 100644 --- a/src/backend/src/services/sla/MonthlyUsageService.js +++ b/src/backend/src/services/sla/MonthlyUsageService.js @@ -33,6 +33,7 @@ class MonthlyUsageService extends BaseService { const month = new Date().getUTCMonth() + 1; const maybe_app_id = actor.type.app?.id; + const stringified = JSON.stringify(extra); // UPSERT increment count await this.db.write( @@ -45,8 +46,8 @@ class MonthlyUsageService extends BaseService { 'DO UPDATE SET `count` = `count` + 1, `extra` = ?', }), [ - year, month, key, actor.type.user.id, maybe_app_id ?? null, JSON.stringify(extra), - ...this.db.case({ mysql: [JSON.stringify(extra)], otherwise: [JSON.stringify({ a: 1 })] }), + year, month, key, actor.type.user.id, maybe_app_id ?? null, stringified, + stringified, ] ); } From 461ea3eae6ad32bf34c43a822de7a06f08efb556 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 14 Aug 2024 17:18:34 -0400 Subject: [PATCH 0686/2119] feat: add feature flag for /share --- src/backend/src/CoreModule.js | 3 ++ src/backend/src/data/hardcoded-permissions.js | 1 + src/backend/src/middleware/featureflag.js | 22 ++++++++++ .../src/services/FeatureFlagService.js | 42 +++++++++++++++++++ src/backend/src/services/ShareService.js | 6 ++- 5 files changed, 73 insertions(+), 1 deletion(-) create mode 100644 src/backend/src/middleware/featureflag.js create mode 100644 src/backend/src/services/FeatureFlagService.js diff --git a/src/backend/src/CoreModule.js b/src/backend/src/CoreModule.js index 8110acf671..f78452430e 100644 --- a/src/backend/src/CoreModule.js +++ b/src/backend/src/CoreModule.js @@ -314,6 +314,9 @@ const install = async ({ services, app, useapi }) => { const { BootScriptService } = require('./services/BootScriptService'); services.registerService('boot-script', BootScriptService); + + const { FeatureFlagService } = require('./services/FeatureFlagService'); + services.registerService('feature-flag', FeatureFlagService); } const install_legacy = async ({ services }) => { diff --git a/src/backend/src/data/hardcoded-permissions.js b/src/backend/src/data/hardcoded-permissions.js index f68c41fcf4..b785cea210 100644 --- a/src/backend/src/data/hardcoded-permissions.js +++ b/src/backend/src/data/hardcoded-permissions.js @@ -74,6 +74,7 @@ const hardcoded_user_group_permissions = { system: { 'ca342a5e-b13d-4dee-9048-58b11a57cc55': { 'service': {}, + 'feature': {}, }, 'b7220104-7905-4985-b996-649fdcdb3c8f': { 'service:hello-world:ii:hello-world': policy_perm('temp.es'), diff --git a/src/backend/src/middleware/featureflag.js b/src/backend/src/middleware/featureflag.js new file mode 100644 index 0000000000..120cc29bc9 --- /dev/null +++ b/src/backend/src/middleware/featureflag.js @@ -0,0 +1,22 @@ +const APIError = require("../api/APIError"); +const { Context } = require("../util/context"); + +const featureflag = options => async (req, res, next) => { + const { feature } = options; + + const context = Context.get(); + const services = context.get('services'); + const svc_featureFlag = services.get('feature-flag'); + + if ( ! await svc_featureFlag.check({ + actor: req.actor, + }, feature) ) { + const e = APIError.create('forbidden'); + e.write(res); + return; + } + + next(); +}; + +module.exports = featureflag; diff --git a/src/backend/src/services/FeatureFlagService.js b/src/backend/src/services/FeatureFlagService.js new file mode 100644 index 0000000000..bbce5818b2 --- /dev/null +++ b/src/backend/src/services/FeatureFlagService.js @@ -0,0 +1,42 @@ +const { Context } = require("../util/context"); +const { whatis } = require("../util/langutil"); +const { PermissionUtil } = require("./auth/PermissionService"); +const BaseService = require("./BaseService"); + +/** + * FeatureFlagService is a way to let the client (frontend) know what features + * are enabled or disabled for the current user. + */ +class FeatureFlagService extends BaseService { + async check (...a) { + // allows binding call with multiple options objects; + // the last argument is the permission to check + const { options, value: permission } = (() => { + let value; + const options = {}; + for ( const arg of a ) { + if ( whatis(arg) === 'object' ) { + Object.assign(options, arg); + continue; + } + value = arg; + break; + } + return { options, value }; + })(); + + + + const actor = options.actor ?? Context.get('actor'); + + const svc_permission = this.services.get('permission'); + const reading = await svc_permission.scan(actor, `feature:${permission}`); + const l = PermissionUtil.reading_to_options(reading); + if ( l.length === 0 ) return false; + return true; + } +} + +module.exports = { + FeatureFlagService +}; diff --git a/src/backend/src/services/ShareService.js b/src/backend/src/services/ShareService.js index a2973938f8..b640934362 100644 --- a/src/backend/src/services/ShareService.js +++ b/src/backend/src/services/ShareService.js @@ -19,6 +19,7 @@ const APIError = require("../api/APIError"); const { get_user } = require("../helpers"); const configurable_auth = require("../middleware/configurable_auth"); +const featureflag = require("../middleware/featureflag.js"); const { Context } = require("../util/context"); const { Endpoint } = require("../util/expressutil"); const { whatis } = require("../util/langutil"); @@ -246,7 +247,10 @@ class ShareService extends BaseService { Endpoint({ route: '/', methods: ['POST'], - mw: [configurable_auth()], + mw: [ + configurable_auth(), + featureflag({ feature: 'share' }), + ], handler: async (req, res) => { const actor = Actor.adapt(req.user); return await share_sequence.call(this, { From 209555c1d93845fa129bea450f9c25d595a3c60f Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 14 Aug 2024 17:19:23 -0400 Subject: [PATCH 0687/2119] feat: make public folders a config opt-in --- src/backend/src/services/auth/ACLService.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/backend/src/services/auth/ACLService.js b/src/backend/src/services/auth/ACLService.js index 9edd85cce1..a036983e1e 100644 --- a/src/backend/src/services/auth/ACLService.js +++ b/src/backend/src/services/auth/ACLService.js @@ -56,9 +56,11 @@ class ACLService extends BaseService { } // Hard rule: anyone and anything can read /user/public directories - const public_modes = ['read', 'list', 'see']; - if ( public_modes.includes(mode) ) { - if ( await fsNode.isPublic() ) return true; + if ( this.global_config.enable_public_folders ) { + const public_modes = ['read', 'list', 'see']; + if ( public_modes.includes(mode) ) { + if ( await fsNode.isPublic() ) return true; + } } // Access tokens only work if the authorizer has permission From 471514ea435794e6661542ccf68a063b098673ae Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 14 Aug 2024 15:05:51 -0700 Subject: [PATCH 0688/2119] Add link to Spanish README in the English Readme --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index f8c4517717..2fef370db5 100644 --- a/README.md +++ b/README.md @@ -137,4 +137,4 @@ This repository, including all its contents, sub-projects, modules, and componen - [English](https://github.com/HeyPuter/puter/blob/main/README.md) - [Portuguese / Português](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.pt.md) - [Russian / Русский](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ru.md) - +- [Spanish / Español](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.es.md) From a821dc67d5e77f7575c54dcaf773a9563775fa54 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 14 Aug 2024 19:29:47 -0400 Subject: [PATCH 0689/2119] tweak: add driver to implicit admin permissions --- src/backend/src/data/hardcoded-permissions.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backend/src/data/hardcoded-permissions.js b/src/backend/src/data/hardcoded-permissions.js index b785cea210..e1c91834b1 100644 --- a/src/backend/src/data/hardcoded-permissions.js +++ b/src/backend/src/data/hardcoded-permissions.js @@ -73,6 +73,7 @@ const policy_perm = selector => ({ const hardcoded_user_group_permissions = { system: { 'ca342a5e-b13d-4dee-9048-58b11a57cc55': { + 'driver': {}, 'service': {}, 'feature': {}, }, From d032ab7d247dae0f79283ab4e49c402e2504b61c Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 14 Aug 2024 21:08:29 -0400 Subject: [PATCH 0690/2119] chore: update tiktoken --- package-lock.json | 5 ++--- src/backend/package.json | 2 +- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index 3e6ffe024d..225d2e4484 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15316,8 +15316,7 @@ "node_modules/tiktoken": { "version": "1.0.15", "resolved": "https://registry.npmjs.org/tiktoken/-/tiktoken-1.0.15.tgz", - "integrity": "sha512-sCsrq/vMWUSEW29CJLNmPvWxlVp7yh2tlkAjpJltIKqp5CKf98ZNpdeHRmAlPVFlGEbswDc6SmI8vz64W/qErw==", - "license": "MIT" + "integrity": "sha512-sCsrq/vMWUSEW29CJLNmPvWxlVp7yh2tlkAjpJltIKqp5CKf98ZNpdeHRmAlPVFlGEbswDc6SmI8vz64W/qErw==" }, "node_modules/tildify": { "version": "2.0.0", @@ -16625,7 +16624,7 @@ "string-hash": "^1.1.3", "string-length": "^6.0.0", "svgo": "^3.0.2", - "tiktoken": "^1.0.11", + "tiktoken": "^1.0.15", "tweetnacl": "^1.0.3", "ua-parser-js": "^1.0.38", "uglify-js": "^3.17.4", diff --git a/src/backend/package.json b/src/backend/package.json index 632b93e60f..a1d4e97fe8 100644 --- a/src/backend/package.json +++ b/src/backend/package.json @@ -67,7 +67,7 @@ "string-hash": "^1.1.3", "string-length": "^6.0.0", "svgo": "^3.0.2", - "tiktoken": "^1.0.11", + "tiktoken": "^1.0.15", "tweetnacl": "^1.0.3", "ua-parser-js": "^1.0.38", "uglify-js": "^3.17.4", From 959a0f4e3994ab254a13c2f779f0b7d0b3abed2e Mon Sep 17 00:00:00 2001 From: Ikko Eltociear Ashimine Date: Fri, 16 Aug 2024 00:25:30 +0900 Subject: [PATCH 0691/2119] chore: update SystemFSEntryService.js propery -> property --- src/backend/src/filesystem/storage/SystemFSEntryService.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/src/filesystem/storage/SystemFSEntryService.js b/src/backend/src/filesystem/storage/SystemFSEntryService.js index 6cc8ef4b62..a226602535 100644 --- a/src/backend/src/filesystem/storage/SystemFSEntryService.js +++ b/src/backend/src/filesystem/storage/SystemFSEntryService.js @@ -26,7 +26,7 @@ const _path = require('path'); // // If `` is `multi`, then the format differs slightly: // :::multi:::: -// where `` specifies the propery being used for the id +// where `` specifies the property being used for the id class SystemFSEntryService { constructor ({ services }) { @@ -162,4 +162,4 @@ class SystemFSEntryService { } } -module.exports = SystemFSEntryService; \ No newline at end of file +module.exports = SystemFSEntryService; From 70bf4bdfa180599f1ddac2c907eb362c1dd1eef6 Mon Sep 17 00:00:00 2001 From: abhishekpaturkar Date: Thu, 15 Aug 2024 23:01:29 +0530 Subject: [PATCH 0692/2119] translate README.md into hindi --- README.md | 1 + doc/i18n/README.hi.md | 131 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 132 insertions(+) create mode 100644 doc/i18n/README.hi.md diff --git a/README.md b/README.md index 2fef370db5..21a0ac8413 100644 --- a/README.md +++ b/README.md @@ -135,6 +135,7 @@ This repository, including all its contents, sub-projects, modules, and componen - [Danish / Dansk](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.da.md) - [English](https://github.com/HeyPuter/puter/blob/main/README.md) +- [Hindi / हिंदी](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.hi.md) - [Portuguese / Português](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.pt.md) - [Russian / Русский](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ru.md) - [Spanish / Español](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.es.md) diff --git a/doc/i18n/README.hi.md b/doc/i18n/README.hi.md new file mode 100644 index 0000000000..0bc54ba2b1 --- /dev/null +++ b/doc/i18n/README.hi.md @@ -0,0 +1,131 @@ +

Puter.com, व्यक्तिगत क्लाउड कंप्यूटर: आपकी सभी फाइलें, ऐप्स और गेम एक ही स्थान पर, कभी भी, कहीं से भी पहुँच योग्य.

+ +

इंटरनेट ऑपरेटिंग सिस्टम! मुफ़्त, ओपन-सोर्स, और स्वयं-होस्ट करने योग्य|

+ +

+ GitHub repo size GitHub Release GitHub License +

+ +

+ « LIVE DEMO » +
+
+ Puter.com + · + SDK + · + Discord + · + YouTube + · + Reddit + · + X (Twitter) + · + Bug Bounty +

+ +

screenshot

+ +
+ +## Puter + +Puter एक उन्नत, ओपन-सोर्स इंटरनेट ऑपरेटिंग सिस्टम है जिसे फीचर-रिच, असाधारण रूप से तेज़ और अत्यधिक विस्तार योग्य बनाने के लिए डिज़ाइन किया गया है। Puter का उपयोग इस प्रकार किया जा सकता है: + +- एक गोपनीयता-पहले व्यक्तिगत क्लाउड जो आपकी सभी फ़ाइलों, ऐप्स और गेम को एक सुरक्षित स्थान पर रखता है, जिसे कहीं से भी किसी भी समय एक्सेस किया जा सकता है। +- वेबसाइट, वेब ऐप्स और गेम बनाने और प्रकाशित करने के लिए एक प्लेटफ़ॉर्म। +- ड्रॉपबॉक्स, Google ड्राइव, OneDrive आदि का एक विकल्प नए इंटरफ़ेस और शक्तिशाली सुविधाओं के साथ सर्वर और वर्कस्टेशन के लिए एक रिमोट डेस्कटॉप वातावरण। +- वेब विकास, क्लाउड कंप्यूटिंग, वितरित सिस्टम और बहुत कुछ सीखने के लिए एक दोस्ताना, ओपन-सोर्स प्रोजेक्ट और समुदाय! + +
+ +## शुरू करें + + +### 💻 स्थानीय विकास + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +यह Puter को लॉन्च करेगा http://puter.localhost:4100 (या अगले उपलब्ध पोर्ट पर). + +
+ +### 🐳 डॉकर + + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ + +### 🐙 डॉकर कंपोज़ + + +#### लिनक्स/मैकओएस +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` +
+ +#### विंडोज + + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +### ☁️ Puter.com + +Puter एक होस्टेड सेवा के रूप में उपलब्ध है [**puter.com**](https://puter.com). + +
+ +## सिस्टम आवश्यकताएँ + +- **ऑपरेटिंग सिस्टम:** लिनक्स, मैकओएस, विंडोज +- **रैम:** 2GB न्यूनतम (4GB अनुशंसित) +- **डिस्क स्थान:** 1GB खाली स्थान +- **नोड.जेएस:** संस्करण 16+ (संस्करण 22+ अनुशंसित) +- **एनपीएम:** नवीनतम स्थिर संस्करण + +
+ +## समर्थन + +मेनटेनरों और समुदाय से इन चैनलों के माध्यम से जुड़ें: + +- बग रिपोर्ट या फीचर रिक्वेस्ट? कृपया [open an issue](https://github.com/HeyPuter/puter/issues/new/choose). +- डिस्कॉर्ड: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- X (ट्विटर): [x.com/HeyPuter](https://x.com/HeyPuter) +- रेड्डिट: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- मास्टोडॉन: [mastodon.social/@puter](https://mastodon.social/@puter) +- सुरक्षा समस्याएँ? [security@puter.com](mailto:security@puter.com) +- ईमेल रखरखावकर्ता को [hi@puter.com](mailto:hi@puter.com) + +हमें आपकी किसी भी प्रश्न में मदद करने में खुशी होगी। बेझिझक पूछें! + +
+ + +## लाइसेंस + +यह रिपॉजिटरी, इसकी सभी सामग्री, उप-प्रोजेक्ट्स, मॉड्यूल और घटकों सहित, लाइसेंस के तहत है [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) जब तक स्पष्ट रूप से अन्यथा नहीं कहा गया है। इस रिपॉजिटरी में शामिल तृतीय-पक्ष पुस्तकालयों के अपने स्वयं के लाइसेंस के अधीन हो सकते हैं। + +
From ac673cfae57ddc8685bbe5a60863bb8f1ef4271d Mon Sep 17 00:00:00 2001 From: calreed-prof Date: Thu, 15 Aug 2024 15:58:07 -0600 Subject: [PATCH 0693/2119] Created README.jp.md --- doc/i18n/README.jp.md | 128 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 doc/i18n/README.jp.md diff --git a/doc/i18n/README.jp.md b/doc/i18n/README.jp.md new file mode 100644 index 0000000000..19e729bb0f --- /dev/null +++ b/doc/i18n/README.jp.md @@ -0,0 +1,128 @@ + +

Puter.com, あなたのファイル、アプリ、ゲームをどこからでもアクセス可能にするパーソナルクラウドコンピュータ

+ +

インターネットOS!無料、オープンソース、セルフホスト可能。

+ +

+ GitHub リポジトリサイズ GitHub リリース GitHub ライセンス +

+ +

+ « ライブデモ » +
+
+ Puter.com + · + SDK + · + Discord + · + YouTube + · + Reddit + · + X (Twitter) + · + バグバウンティ +

+ +

スクリーンショット

+ +
+ +## Puter + +Puterは、機能豊富で非常に高速、そして高い拡張性を持つ、先進的なオープンソースのインターネットオペレーティングシステムです。Puterは以下の用途に利用できます: + +- プライバシーを最優先するパーソナルクラウドとして、あなたのファイル、アプリ、ゲームを一か所で安全に管理し、どこからでもアクセス可能に。 +- ウェブサイト、ウェブアプリ、ゲームの作成と公開のためのプラットフォーム。 +- Dropbox、Google Drive、OneDriveなどの代替として、新しいインターフェースと強力な機能を提供。 +- サーバーやワークステーションのためのリモートデスクトップ環境。 +- ウェブ開発、クラウドコンピューティング、分散システムなどを学ぶための、フレンドリーでオープンなコミュニティとプロジェクト。 + +
+ +## はじめに + + +### 💻 ローカル開発 + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +これでPuterが http://puter.localhost:4100 (または次に利用可能なポート)で起動します。 + +
+ +### 🐳 Docker + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ +### 🐙 Docker Compose + +#### Linux/macOS +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` +
+ +#### Windows + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +### ☁️ Puter.com + +Puterは[**puter.com**](https://puter.com)でホストサービスとして利用可能です。 + +
+ +## システム要件 + +- **オペレーティングシステム:** Linux, macOS, Windows +- **RAM:** 最小2GB(推奨4GB) +- **ディスクスペース:** 1GBの空き容量 +- **Node.js:** バージョン16以上(推奨バージョン22以上) +- **npm:** 最新の安定バージョン + +
+ +## サポート + +メンテナーやコミュニティと以下のチャンネルを通じてつながりましょう: + +- バグ報告や機能リクエストがありますか? [issueを開く](https://github.com/HeyPuter/puter/issues/new/choose) してください。 +- Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) +- Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) +- セキュリティの問題? [security@puter.com](mailto:security@puter.com) +- メンテナーへのメールは [hi@puter.com](mailto:hi@puter.com) まで + +質問があれば、いつでもお気軽にお問い合わせください! + +
+ +## ライセンス + +このリポジトリ、ならびにそのすべてのコンテンツ、サブプロジェクト、モジュール、コンポーネントは、[AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt)の下でライセンスされています。明示的に異なるライセンスが示されている場合を除きます。このリポジトリに含まれるサードパーティのライブラリは、それぞれのライセンスが適用される場合があります。 + +
From 8cb415675b120ace588fb63654c29e0f02668a61 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 15 Aug 2024 15:06:55 -0700 Subject: [PATCH 0694/2119] Add link to Japanese README in the English Readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 21a0ac8413..5b7f386416 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,7 @@ This repository, including all its contents, sub-projects, modules, and componen - [Danish / Dansk](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.da.md) - [English](https://github.com/HeyPuter/puter/blob/main/README.md) - [Hindi / हिंदी](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.hi.md) +- [Japanese / 日本語](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.jp.md) - [Portuguese / Português](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.pt.md) - [Russian / Русский](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ru.md) - [Spanish / Español](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.es.md) From 8e39f41dd41d7f4dd795828e5004d57b14b2858b Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 15 Aug 2024 15:11:23 -0700 Subject: [PATCH 0695/2119] Encode Japanese string in the badge URL in README --- doc/i18n/README.jp.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/i18n/README.jp.md b/doc/i18n/README.jp.md index 19e729bb0f..479e1ad8d7 100644 --- a/doc/i18n/README.jp.md +++ b/doc/i18n/README.jp.md @@ -4,7 +4,7 @@

インターネットOS!無料、オープンソース、セルフホスト可能。

- GitHub リポジトリサイズ GitHub リリース GitHub ライセンス + GitHub リポジトリサイズ GitHub リリース GitHub ライセンス

From 4561b8937de025471c2dfb1771465d779cefab5d Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 15 Aug 2024 19:14:38 -0400 Subject: [PATCH 0696/2119] feat: report feature flags in /whoami --- src/backend/src/routers/whoami.js | 5 ++- .../src/services/FeatureFlagService.js | 33 +++++++++++++++++++ src/backend/src/services/ShareService.js | 7 ++++ src/backend/src/services/auth/ACLService.js | 7 ++++ 4 files changed, 51 insertions(+), 1 deletion(-) diff --git a/src/backend/src/routers/whoami.js b/src/backend/src/routers/whoami.js index a08d796ee8..89320312a3 100644 --- a/src/backend/src/routers/whoami.js +++ b/src/backend/src/routers/whoami.js @@ -61,7 +61,10 @@ const WHOAMI_GET = eggspress('/whoami', { // Get whoami values from other services const svc_whoami = req.services.get('whoami'); - const provider_details = await svc_whoami.get_details({ user: req.user }); + const provider_details = await svc_whoami.get_details({ + user: req.user, + actor: actor, + }); Object.assign(details, provider_details); if ( ! is_user ) { diff --git a/src/backend/src/services/FeatureFlagService.js b/src/backend/src/services/FeatureFlagService.js index bbce5818b2..d310cce6ad 100644 --- a/src/backend/src/services/FeatureFlagService.js +++ b/src/backend/src/services/FeatureFlagService.js @@ -8,6 +8,20 @@ const BaseService = require("./BaseService"); * are enabled or disabled for the current user. */ class FeatureFlagService extends BaseService { + _construct () { + this.known_flags = new Map(); + } + register (name, spec) { + this.known_flags.set(name, spec); + } + async _init () { + const svc_detailProvider = this.services.get('whoami'); + svc_detailProvider.register_provider(async (context, out) => { + console.log(`\x1B[36;1mCALLED\x1B[0m`); + if ( ! context.actor ) return; + out.feature_flags = await this.get_summary(context.actor); + }); + } async check (...a) { // allows binding call with multiple options objects; // the last argument is the permission to check @@ -25,6 +39,9 @@ class FeatureFlagService extends BaseService { return { options, value }; })(); + if ( ! this.known_flags.has(permission) ) { + this.known_flags.set(permission, true); + } const actor = options.actor ?? Context.get('actor'); @@ -35,6 +52,22 @@ class FeatureFlagService extends BaseService { if ( l.length === 0 ) return false; return true; } + + async get_summary (actor) { + const summary = {}; + for ( const [key, value] of this.known_flags.entries() ) { + if ( value.$ === 'config-flag' ) { + summary[key] = value.value; + continue; + } + const svc_permission = this.services.get('permission'); + const reading = await svc_permission.scan(actor, `feature:`); + const l = PermissionUtil.reading_to_options(reading); + summary[key] = l.length > 0; + } + + return summary; + } } module.exports = { diff --git a/src/backend/src/services/ShareService.js b/src/backend/src/services/ShareService.js index b640934362..63e7e7760f 100644 --- a/src/backend/src/services/ShareService.js +++ b/src/backend/src/services/ShareService.js @@ -37,6 +37,13 @@ class ShareService extends BaseService { async _init () { this.db = await this.services.get('database').get(DB_WRITE, 'share'); + + // registry "share" as a feature flag so gui is informed + // about whether or not a user has access to this feature + const svc_featureFlag = this.services.get('feature-flag'); + svc_featureFlag.register('share', { + $: 'permission-flag' + }); } ['__on_install.routes'] (_, { app }) { diff --git a/src/backend/src/services/auth/ACLService.js b/src/backend/src/services/auth/ACLService.js index a036983e1e..9cbc98ab3b 100644 --- a/src/backend/src/services/auth/ACLService.js +++ b/src/backend/src/services/auth/ACLService.js @@ -25,6 +25,13 @@ const { AppUnderUserActorType, UserActorType, Actor, SystemActorType, AccessToke const { PermissionUtil } = require("./PermissionService"); class ACLService extends BaseService { + async _init () { + const svc_featureFlag = this.services.get('feature-flag'); + svc_featureFlag.register('public-folders', { + $: 'config-flag', + value: this.global_config.enable_public_folders ?? false, + }); + } async check (actor, resource, mode) { const ld = (Context.get('logdent') ?? 0) + 1; return await Context.get().sub({ logdent: ld }).arun(async () => { From 1c0adfc89a10443ad587aa296e29ffc421d7828a Mon Sep 17 00:00:00 2001 From: Emirhan Date: Sat, 17 Aug 2024 13:47:25 +0300 Subject: [PATCH 0697/2119] Created Read.me in Turkish. --- doc/i18n/README.tr.md | 132 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 doc/i18n/README.tr.md diff --git a/doc/i18n/README.tr.md b/doc/i18n/README.tr.md new file mode 100644 index 0000000000..07fb54b25a --- /dev/null +++ b/doc/i18n/README.tr.md @@ -0,0 +1,132 @@ +

Puter.com, Kişisel Bulut Bilgisayar: Tüm dosyalarınız, uygulamalarınız ve oyunlarınız her zaman her yerden erişilebilen tek bir yerde.

+ +

İnternet İşletim Sistemi! Ücretsiz, Açık Kaynaklı ve Kendi Kendine Barındırılabilir

+ +

+ GitHub Depo Boyutu GitHub Yayınlamak GitHub Lisans +

+ +

+ « CANLI DEMO » +
+
+ Puter.com + · + SDK + · + Discord + · + YouTube + · + Reddit + · + X (Twitter) + · + Bug Bounty +

+ +

screenshot

+ +
+ +## Puter + +Puter, zengin özelliklere sahip, son derece hızlı ve son derece genişletilebilir olacak şekilde tasarlanmış gelişmiş, açık kaynaklı bir internet işletim sistemidir. Puter şu şekilde kullanılabilir: + +- Tüm dosyalarınızı, uygulamalarınızı ve oyunlarınızı tek bir güvenli yerde tutmak için gizlilik öncelikli bir kişisel bulut, her yerden her zaman erişilebilir. +- Web siteleri, web uygulamaları ve oyunlar oluşturmak ve yayınlamak için bir platform. +- Yeni bir arayüz ve güçlü özelliklerle Dropbox, Google Drive, OneDrive vb. uygulamalara bir alternatif. +- Sunucular ve iş istasyonları için bir uzak masaüstü ortamı. +- Web geliştirme, bulut bilişim, dağıtık sistemler ve çok daha fazlası hakkında bilgi edinmek için dost canlısı, açık kaynaklı bir proje ve topluluk! + +
+ +## Başlarken + + +### 💻 Yerel Geliştirme + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +Bu, Puter'ı http://puter.localhost:4100 adresinde (veya bir sonraki kullanılabilir portta) başlatacaktır. + +
+ +### 🐳 Docker + + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ + +### 🐙 Docker Compose + + +#### Linux/macOS +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` +
+ +#### Windows + + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +### ☁️ Puter.com + +Puter, [**puter.com**](https://puter.com) adresinde barındırılan bir hizmet olarak kullanılabilir. + +
+ +## Sistem Gereksinimleri + +- **İşletim Sistemleri:** Linux, macOS, Windows +- **RAM:** 2GB Minimum (4GB önerilir) +- **Disk Alanı:** 1GB boş alan +- **Node.js:** Sürüm 16+ (Sürüm 22+ önerilir) +- **npm:** En son stabil sürüm + +
+ +## Destek + +Bakımcılarla ve toplulukla şu kanallar aracılığıyla iletişim kurabilirsiniz: + +- Hata raporu veya özellik isteği? Lütfen [yeni bir issue açın](https://github.com/HeyPuter/puter/issues/new/choose). +- Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) +- Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) +- Güvenlik sorunları? [security@puter.com](mailto:security@puter.com) +- Bakımcılara şu adresten e-posta gönderin [hi@puter.com](mailto:hi@puter.com) + +Sorularınız varsa size her zaman yardımcı olmaktan mutluluk duyarız. Sormaktan çekinmeyin! + +
+ + +## Lisans + +Bu depo, tüm içeriği, alt projeleri, modülleri ve bileşenleri dahil olmak üzere, aksi açıkça belirtilmedikçe [AGPL-3.0] (https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) altında lisanslanmıştır. Bu depoda yer alan üçüncü taraf kütüphaneler kendi lisanslarına tabi olabilir. + +
From f43b52b0e157fd164bd8e1c299f05af653a7d6bf Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sat, 17 Aug 2024 09:15:00 -0700 Subject: [PATCH 0698/2119] fix the markdown link for the license --- doc/i18n/README.tr.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/i18n/README.tr.md b/doc/i18n/README.tr.md index 07fb54b25a..34f2d57bc2 100644 --- a/doc/i18n/README.tr.md +++ b/doc/i18n/README.tr.md @@ -127,6 +127,6 @@ Sorularınız varsa size her zaman yardımcı olmaktan mutluluk duyarız. Sormak ## Lisans -Bu depo, tüm içeriği, alt projeleri, modülleri ve bileşenleri dahil olmak üzere, aksi açıkça belirtilmedikçe [AGPL-3.0] (https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) altında lisanslanmıştır. Bu depoda yer alan üçüncü taraf kütüphaneler kendi lisanslarına tabi olabilir. +Bu depo, tüm içeriği, alt projeleri, modülleri ve bileşenleri dahil olmak üzere, aksi açıkça belirtilmedikçe [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) altında lisanslanmıştır. Bu depoda yer alan üçüncü taraf kütüphaneler kendi lisanslarına tabi olabilir.
From 54d248e40b492f3bfb10de8925ac01e7283ce8cd Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sat, 17 Aug 2024 09:53:38 -0700 Subject: [PATCH 0699/2119] Add link to Turkish README in the English Readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5b7f386416..737087b527 100644 --- a/README.md +++ b/README.md @@ -140,3 +140,4 @@ This repository, including all its contents, sub-projects, modules, and componen - [Portuguese / Português](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.pt.md) - [Russian / Русский](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ru.md) - [Spanish / Español](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.es.md) +- [Turkish / Türkçe](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.tr.md) From 88e8e33dc29f9f516e46a8f42e581aa1a8dbdc06 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sat, 17 Aug 2024 11:11:36 -0700 Subject: [PATCH 0700/2119] take into account feature flags for sharing --- src/gui/src/UI/UIItem.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/src/UI/UIItem.js b/src/gui/src/UI/UIItem.js index e7db916cb4..2b90b26b12 100644 --- a/src/gui/src/UI/UIItem.js +++ b/src/gui/src/UI/UIItem.js @@ -782,7 +782,7 @@ function UIItem(options){ // ------------------------------------------- menu_items.push('-'); } - if(!are_trashed){ + if(!are_trashed && (!window.user.feature_flags || window.user.feature_flags.share !== false)){ menu_items.push({ html: 'Share With…', onClick: async function(){ @@ -1086,7 +1086,7 @@ function UIItem(options){ // ------------------------------------------- // Share With… // ------------------------------------------- - if(!is_trashed && !is_trash){ + if(!is_trashed && !is_trash && (!window.user.feature_flags || window.user.feature_flags.share !== false)){ menu_items.push({ html: 'Share With…', onClick: async function(){ From 4e37064f477101902099411c4b59aa72c60d79ba Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sat, 17 Aug 2024 11:34:53 -0700 Subject: [PATCH 0701/2119] fix issues public folder paths --- src/gui/src/UI/UIItem.js | 4 ++-- src/gui/src/UI/UIWindow.js | 1 - src/gui/src/helpers.js | 1 + src/gui/src/helpers/update_username_in_gui.js | 1 + 4 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/gui/src/UI/UIItem.js b/src/gui/src/UI/UIItem.js index 2b90b26b12..bac63d0108 100644 --- a/src/gui/src/UI/UIItem.js +++ b/src/gui/src/UI/UIItem.js @@ -782,7 +782,7 @@ function UIItem(options){ // ------------------------------------------- menu_items.push('-'); } - if(!are_trashed && (!window.user.feature_flags || window.user.feature_flags.share !== false)){ + if(!are_trashed && (window.user.feature_flags?.share !== false)){ menu_items.push({ html: 'Share With…', onClick: async function(){ @@ -1086,7 +1086,7 @@ function UIItem(options){ // ------------------------------------------- // Share With… // ------------------------------------------- - if(!is_trashed && !is_trash && (!window.user.feature_flags || window.user.feature_flags.share !== false)){ + if(!is_trashed && !is_trash && (window.user.feature_flags?.share !== false)){ menu_items.push({ html: 'Share With…', onClick: async function(){ diff --git a/src/gui/src/UI/UIWindow.js b/src/gui/src/UI/UIWindow.js index 1af86ef7f4..9e2d4dec24 100644 --- a/src/gui/src/UI/UIWindow.js +++ b/src/gui/src/UI/UIWindow.js @@ -271,7 +271,6 @@ async function UIWindow(options) { h += `
${i18n('desktop')}
`; h += `
${i18n('videos')}
`; h += `
`; - } // Menubar diff --git a/src/gui/src/helpers.js b/src/gui/src/helpers.js index c4da072471..1ba495e253 100644 --- a/src/gui/src/helpers.js +++ b/src/gui/src/helpers.js @@ -488,6 +488,7 @@ window.update_auth_data = async (auth_token, user)=>{ window.videos_path = '/' + window.user.username + '/Videos'; window.desktop_path = '/' + window.user.username + '/Desktop'; window.home_path = '/' + window.user.username; + window.public_path = '/' + window.user.username + '/Public'; if(window.user !== null && !window.user.is_temp){ $('.user-options-login-btn, .user-options-create-account-btn').hide(); diff --git a/src/gui/src/helpers/update_username_in_gui.js b/src/gui/src/helpers/update_username_in_gui.js index 78c2f35353..212363a3b7 100644 --- a/src/gui/src/helpers/update_username_in_gui.js +++ b/src/gui/src/helpers/update_username_in_gui.js @@ -83,6 +83,7 @@ const update_username_in_gui = function(new_username){ window.pictures_path = '/' + new_username + '/Pictures'; window.videos_path = '/' + new_username + '/Videos'; window.desktop_path = '/' + new_username + '/Desktop'; + window.public_path = '/' + new_username + '/Public'; window.home_path = '/' + new_username; } From ceecf543572368b8f71cde3d0eee4df0d3f80896 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sat, 17 Aug 2024 15:13:01 -0400 Subject: [PATCH 0702/2119] chore: sync versions --- src/backend/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/package.json b/src/backend/package.json index a1d4e97fe8..0fb81bb58a 100644 --- a/src/backend/package.json +++ b/src/backend/package.json @@ -1,6 +1,6 @@ { "name": "@heyputer/backend", - "version": "2.1.0", + "version": "2.4.1", "description": "Backend/Kernel for Puter", "main": "exports.js", "scripts": { From 3f520e13f339f7943bb3c0a272339d20bb31ea29 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sat, 17 Aug 2024 12:29:32 -0700 Subject: [PATCH 0703/2119] remove cover iframe for public folders --- src/gui/src/UI/UIWindow.js | 25 ------------------------- 1 file changed, 25 deletions(-) diff --git a/src/gui/src/UI/UIWindow.js b/src/gui/src/UI/UIWindow.js index 9e2d4dec24..2889b95579 100644 --- a/src/gui/src/UI/UIWindow.js +++ b/src/gui/src/UI/UIWindow.js @@ -344,31 +344,6 @@ async function UIWindow(options) { // Detail layout header h += window.explore_table_headers(); - // Maybe render iframe for users public directory - (() => { - if ( options.is_saveFileDialog || options.is_openFileDialog || options.is_directoryPicker ) { - return false; - } - - if ( ! options.path || ! options.path.startsWith('/') ) { // sus - return false; - } - - const components = options.path.slice(1).split('/'); - - if ( components.length === 2 && components[1] === 'Public' ) { - const username = components[0]; - h += ` - `; - } - })(); - // Add 'This folder is empty' message by default h += `
This folder is empty
`; From 0519b4a71b236e464c9d1136065e8f5ba15def8e Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sat, 17 Aug 2024 16:36:52 -0400 Subject: [PATCH 0704/2119] fix: require confirmed email for public folder --- src/backend/src/services/auth/ACLService.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/backend/src/services/auth/ACLService.js b/src/backend/src/services/auth/ACLService.js index 9cbc98ab3b..72d5d66dac 100644 --- a/src/backend/src/services/auth/ACLService.js +++ b/src/backend/src/services/auth/ACLService.js @@ -18,7 +18,6 @@ */ const APIError = require("../../api/APIError"); const { NodePathSelector } = require("../../filesystem/node/selectors"); -const { get_user } = require("../../helpers"); const { Context } = require("../../util/context"); const BaseService = require("../BaseService"); const { AppUnderUserActorType, UserActorType, Actor, SystemActorType, AccessTokenActorType } = require("./Actor"); @@ -64,10 +63,21 @@ class ACLService extends BaseService { // Hard rule: anyone and anything can read /user/public directories if ( this.global_config.enable_public_folders ) { - const public_modes = ['read', 'list', 'see']; - if ( public_modes.includes(mode) ) { - if ( await fsNode.isPublic() ) return true; - } + const public_modes = Object.freeze(['read', 'list', 'see']); + let is_public; + await (async () => { + if ( ! public_modes.includes(mode) ) return; + if ( ! (await fsNode.isPublic()) ) return; + + const svc_getUser = this.services.get('get-user'); + + const username = await fsNode.getUserPart(); + const user = await svc_getUser.get_user({ username }); + if ( ! user.email_confirmed ) return; + + is_public = true; + })(); + if ( is_public ) return true; } // Access tokens only work if the authorizer has permission From ef245b70df482ff470877459fcb28e1f490fe42d Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sat, 17 Aug 2024 17:20:31 -0400 Subject: [PATCH 0705/2119] fix: do primary read of user after setting email_confirmed --- src/backend/src/routers/confirm-email.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/backend/src/routers/confirm-email.js b/src/backend/src/routers/confirm-email.js index 839ebb2e52..bf013c544a 100644 --- a/src/backend/src/routers/confirm-email.js +++ b/src/backend/src/routers/confirm-email.js @@ -70,7 +70,8 @@ router.post('/confirm-email', auth, express.json(), async (req, res, next)=>{ "UPDATE `user` SET `email_confirmed` = 1, `requires_email_confirmation` = 0 WHERE id = ? LIMIT 1", [req.user.id], ); - invalidate_cached_user(req.user); + const svc_getUser = req.services.get('get-user'); + await svc_getUser.get_user({ id: req.user.id, force: true }); } // Build response object From 11fb02c67b8a3346da9af79b4de8f21d5521d1a4 Mon Sep 17 00:00:00 2001 From: JinHo Jang <105098581+jsdmas@users.noreply.github.com> Date: Sun, 18 Aug 2024 11:55:53 +0900 Subject: [PATCH 0706/2119] Create README.ko.md --- doc/i18n/README.ko.md | 132 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 doc/i18n/README.ko.md diff --git a/doc/i18n/README.ko.md b/doc/i18n/README.ko.md new file mode 100644 index 0000000000..c08ab2220c --- /dev/null +++ b/doc/i18n/README.ko.md @@ -0,0 +1,132 @@ +

Puter.com, The Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time.

+ +

인터넷 OS! 무료이고 오픈소스이며 자체 호스팅이 가능합니다.

+ +

+ GitHub repo size GitHub Release GitHub License +

+ +

+ « 시연 영상 » +
+
+ Puter.com + · + SDK + · + Discord + · + YouTube + · + Reddit + · + X (Twitter) + · + 버그 제보하기 +

+ +

screenshot

+ +
+ +## Puter + +Puter는 기능이 풍부하고, 매우 빠르며, 높은 확장성을 갖춘 고급 오픈소스 인터넷 운영 체제입니다. Puter는 다음과 같이 사용될 수 있습니다: + +- 모든 파일, 앱, 게임을 한 곳에 안전하게 보관하고 언제 어디서나 접근할 수 있는 프라이버시 중심의 개인 클라우드로 사용할 수 있습니다. +- 웹사이트, 웹 앱, 게임을 구축하고 배포하는 플랫폼으로 활용할 수 있습니다. +- 새로운 인터페이스와 강력한 기능을 갖춘 Dropbox, Google Drive, OneDrive 등의 대안으로 사용할 수 있습니다. +- 서버와 워크스테이션을 위한 원격 데스크톱 환경으로 활용할 수 있습니다. +- 웹 개발, 클라우드 컴퓨팅, 분산 시스템 등에 대해 배울 수 있는 친근한 오픈소스 프로젝트이자 커뮤니티입니다! + +
+ +## 시작하기 + + +### 💻 로컬 환경 개발 + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +위처럼 실행할 시 Puter는 http://puter.localhost:4100 (또는 사용 가능한 다음 포트)에서 실행됩니다. + +
+ +### 🐳 Docker + + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ + +### 🐙 Docker Compose + + +#### Linux/macOS +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` +
+ +#### Windows + + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +### ☁️ Puter.com + +Puter는 [**puter.com**](https://puter.com)에서 호스팅 서비스로 이용할 수 있습니다. + +
+ +## 시스템 요구사항 + +- **Operating Systems:** Linux, macOS, Windows +- **RAM:** 2GB minimum (4GB recommended) +- **Disk Space:** 1GB free space +- **Node.js:** Version 16+ (Version 22+ recommended) +- **npm:** Latest stable version + +
+ +## 지원 + +다음 채널을 통해 관리자 및 커뮤니티와 소통하세요: + +- 버그 신고나 기능 요청이 있으신가요? [이슈를 열어주세요.](https://github.com/HeyPuter/puter/issues/new/choose). +- Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) +- Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) +- 보안 관련 문제는 [security@puter.com](mailto:security@puter.com) 으로 연락주세요. +- 관리자에게 이메일 보내기: [hi@puter.com](mailto:hi@puter.com) + +어떤 질문이든 기꺼이 도와드리겠습니다. 언제든 물어보세요! + +
+ + +## 라이선스 + +이 저장소는 모든 내용, 하위 프로젝트, 모듈 및 구성 요소를 포함하여 명시적으로 달리 명시되지 않는 한 [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) 라이선스 하에 제공됩니다. 이 저장소에 포함된 제3자 라이브러리는 해당 라이브러리의 고유 라이선스를 따를 수 있습니다. + +
From 6e325fa000f19b8f20d79829ab2bd78edce80425 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 16 Aug 2024 18:33:50 -0400 Subject: [PATCH 0707/2119] fix: requirement for email_confirmed in backend --- src/backend/src/api/APIError.js | 3 ++- src/backend/src/routers/auth/configure-2fa.js | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/backend/src/api/APIError.js b/src/backend/src/api/APIError.js index ed188c0714..93bee20fc4 100644 --- a/src/backend/src/api/APIError.js +++ b/src/backend/src/api/APIError.js @@ -470,7 +470,8 @@ module.exports = class APIError { }, 'email_must_be_confirmed': { status: 422, - message: 'Email must be confirmed to apply a share.', + message: ({action}) => + `Email must be confirmed to ${action ?? 'apply a share'}.`, }, 'no_need_to_request': { status: 422, diff --git a/src/backend/src/routers/auth/configure-2fa.js b/src/backend/src/routers/auth/configure-2fa.js index 5f1b444200..9c3c461e4d 100644 --- a/src/backend/src/routers/auth/configure-2fa.js +++ b/src/backend/src/routers/auth/configure-2fa.js @@ -105,6 +105,12 @@ module.exports = eggspress('/auth/configure-2fa/:action', { } const user = await get_user({ id: req.user.id, force: true }); + + if ( ! user.email_confirmed ) { + throw APIError.create('email_must_be_confirmed', null, { + action: 'enable 2FA' + }); + } // Verify that 2FA isn't already enabled if ( user.otp_enabled ) { From 9fa12d43fc782d7e4d2584b1cf74dca13b7ced25 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sun, 18 Aug 2024 00:41:39 -0400 Subject: [PATCH 0708/2119] fix: only show 2fa when available --- src/backend/src/routers/whoami.js | 6 ++++-- src/gui/src/UI/Settings/UITabSecurity.js | 2 +- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/src/backend/src/routers/whoami.js b/src/backend/src/routers/whoami.js index 89320312a3..a4eabdea59 100644 --- a/src/backend/src/routers/whoami.js +++ b/src/backend/src/routers/whoami.js @@ -47,7 +47,8 @@ const WHOAMI_GET = eggspress('/whoami', { uuid: req.user.uuid, email: req.user.email, unconfirmed_email: req.user.email, - email_confirmed: req.user.email_confirmed, + email_confirmed: req.user.email_confirmed + || req.user.username === 'admin', requires_email_confirmation: req.user.requires_email_confirmation, desktop_bg_url: req.user.desktop_bg_url, desktop_bg_color: req.user.desktop_bg_color, @@ -168,7 +169,8 @@ WHOAMI_POST.post('/whoami', auth, fs, express.json(), async (req, response, next username: req.user.username, uuid: req.user.uuid, email: req.user.email, - email_confirmed: req.user.email_confirmed, + email_confirmed: req.user.email_confirmed + || req.user.username === 'admin', requires_email_confirmation: req.user.requires_email_confirmation, desktop_bg_url: req.user.desktop_bg_url, desktop_bg_color: req.user.desktop_bg_color, diff --git a/src/gui/src/UI/Settings/UITabSecurity.js b/src/gui/src/UI/Settings/UITabSecurity.js index 89ef589bd0..9ddda082ca 100644 --- a/src/gui/src/UI/Settings/UITabSecurity.js +++ b/src/gui/src/UI/Settings/UITabSecurity.js @@ -53,7 +53,7 @@ export default { h += `
`; // configure 2FA - if(!user.is_temp){ + if(!user.is_temp && user.email_confirmed){ h += `
`; h += `
`; h += `${i18n('two_factor')}`; From b6b64d3bccb6e17240a245c956ead2ae5a87c8dd Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sun, 18 Aug 2024 01:06:47 -0400 Subject: [PATCH 0709/2119] fix: add anti-csrf token for /revoke-session --- .../src/routers/auth/revoke-session.js | 5 ++++ src/gui/src/UI/UIWindowManageSessions.js | 4 ++++ src/gui/src/initgui.js | 2 ++ src/gui/src/services/AntiCSRFService.js | 23 +++++++++++++++++++ 4 files changed, 34 insertions(+) create mode 100644 src/gui/src/services/AntiCSRFService.js diff --git a/src/backend/src/routers/auth/revoke-session.js b/src/backend/src/routers/auth/revoke-session.js index c5195c7214..ff23d1433b 100644 --- a/src/backend/src/routers/auth/revoke-session.js +++ b/src/backend/src/routers/auth/revoke-session.js @@ -36,6 +36,11 @@ module.exports = eggspress('/auth/revoke-session', { throw APIError.create('forbidden'); } + const svc_antiCSRF = req.services.get('anti-csrf'); + if ( ! svc_antiCSRF.consume_token(actor.type.user.uuid, req.body.anti_csrf) ) { + return res.status(400).json({ message: 'incorrect anti-CSRF token' }); + } + // Ensure valid UUID if ( ! req.body.uuid || typeof req.body.uuid !== 'string' ) { throw APIError.create('field_invalid', null, { diff --git a/src/gui/src/UI/UIWindowManageSessions.js b/src/gui/src/UI/UIWindowManageSessions.js index 9515c2aefb..48819c5575 100644 --- a/src/gui/src/UI/UIWindowManageSessions.js +++ b/src/gui/src/UI/UIWindowManageSessions.js @@ -105,6 +105,9 @@ const UIWindowManageSessions = async function UIWindowManageSessions (options) { if ( alert_resp !== 'yes' ) { return; } + + + const anti_csrf = await services.get('anti-csrf').token(); const resp = await fetch(`${window.api_origin}/auth/revoke-session`, { method: 'POST', @@ -114,6 +117,7 @@ const UIWindowManageSessions = async function UIWindowManageSessions (options) { }, body: JSON.stringify({ uuid: session.uuid, + anti_csrf, }), }); if ( resp.ok ) { diff --git a/src/gui/src/initgui.js b/src/gui/src/initgui.js index cd7bf0b33d..efdadc4546 100644 --- a/src/gui/src/initgui.js +++ b/src/gui/src/initgui.js @@ -45,6 +45,7 @@ import UIComponentWindow from './UI/UIComponentWindow.js'; import update_mouse_position from './helpers/update_mouse_position.js'; import { LaunchOnInitService } from './services/LaunchOnInitService.js'; import item_icon from './helpers/item_icon.js'; +import { AntiCSRFService } from './services/AntiCSRFService.js'; const launch_services = async function (options) { // === Services Data Structures === @@ -79,6 +80,7 @@ const launch_services = async function (options) { register('process', new ProcessService()); register('locale', new LocaleService()); register('settings', new SettingsService()); + register('anti-csrf', new AntiCSRFService()); register('__launch-on-init', new LaunchOnInitService()); // === Service-Script Services === diff --git a/src/gui/src/services/AntiCSRFService.js b/src/gui/src/services/AntiCSRFService.js new file mode 100644 index 0000000000..d5e65a2ad2 --- /dev/null +++ b/src/gui/src/services/AntiCSRFService.js @@ -0,0 +1,23 @@ +import { Service } from "../definitions.js"; + +export class AntiCSRFService extends Service { + /** + * Request an anti-csrf token from the server + * @return anti_csrf: string + */ + async token () { + const anti_csrf = await (async () => { + const resp = await fetch( + `${window.gui_origin}/get-anticsrf-token`,{ + headers: { + 'Content-Type': 'application/json', + 'Authorization': 'Bearer ' + window.auth_token, + } + },) + const { token } = await resp.json(); + return token; + })(); + + return anti_csrf; + } +} From 380e946bbf4e5cb606c71c9a6682382ebcef8f39 Mon Sep 17 00:00:00 2001 From: Priyanshu1035 Date: Sun, 18 Aug 2024 23:00:24 +0530 Subject: [PATCH 0710/2119] updated PR to revert accidental changes --- doc/i18n/README.vi.md | 129 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 doc/i18n/README.vi.md diff --git a/doc/i18n/README.vi.md b/doc/i18n/README.vi.md new file mode 100644 index 0000000000..9a9151b377 --- /dev/null +++ b/doc/i18n/README.vi.md @@ -0,0 +1,129 @@ +

Puter.com, Máy Tính Đám Mây Cá Nhân: Tất cả các tệp, ứng dụng, và trò chơi của bạn ở một nơi, có thể truy cập từ bất cứ đâu vào bất kỳ lúc nào.

+

Hệ điều hành Internet! Miễn phí, Mã nguồn mở và Có thể tự lưu trữ.

+

+ Kích thước repo GitHub Phiên bản phát hành GitHub Giấy phép GitHub +

+

+ « DEMO TRỰC TIẾP » +
+
+ Puter.com + · + SDK + · + Discord + · + YouTube + · + Reddit + · + X (Twitter) + · + Bug Bounty +

+ +

chụp màn hình

+ +
+ +## Puter + +Puter là một hệ điều hành internet tiên tiến, mã nguồn mở được thiết kế để có nhiều tính năng, tốc độ vượt trội và khả năng mở rộng cao. Puter có thể được sử dụng như: + +- Một đám mây cá nhân ưu tiên quyền riêng tư để lưu trữ tất cả các tệp, ứng dụng và trò chơi của bạn ở một nơi an toàn, có thể truy cập từ bất cứ đâu, bất cứ lúc nào. +- Một nền tảng để xây dựng và xuất bản các trang web, ứng dụng web và trò chơi. +- Một sự thay thế cho Dropbox, Google Drive, OneDrive, v.v. với giao diện mới mẻ và nhiều tính năng mạnh mẽ. +- Một môi trường máy tính từ xa cho các máy chủ và máy trạm. +- Một dự án thân thiện, mã nguồn mở và cộng đồng để học hỏi về phát triển web, điện toán đám mây, hệ thống phân tán và nhiều hơn nữa! + +
+ +## Bắt Đầu + +## 💻 Phát Triển Cục Bộ + +```bash +Copy code +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` +Điều này sẽ khởi chạy Puter tại http://puter.localhost:4100 (hoặc cổng kế tiếp có sẵn). + +
+ +### 🐳 Docker + + +```bash +Copy code +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ +## 🐙 Docker Compose + +## Linux/macOS + +``` bash +Copy code +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` + +
+ +## Windows + +```powershell +Copy code +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +## ☁️ Puter.com + +Puter có sẵn dưới dạng dịch vụ lưu trữ tại [**puter.com**](https://puter.com). + +
+ +## Yêu Cầu Hệ Thống + +- **Hệ Điều Hành:** Linux, macOS, Windows +- **RAM:** Tối thiểu 2GB (Khuyến nghị 4GB) +- **Dung Lượng Ổ Cứng:** Còn trống 1GB +- **Node.js:** Phiên bản 16+ (Khuyến nghị phiên bản 22+) +- **npm:** Phiên bản ổn định mới nhất + +
+ +## Hỗ Trợ + +Kết nối với các nhà bảo trì và cộng đồng thông qua các kênh sau: + +- Báo cáo lỗi hoặc yêu cầu tính năng? Vui lòng mở một vấn đề. +- Discord: discord.com/invite/PQcx7Teh8u +- X (Twitter): x.com/HeyPuter +- Reddit: reddit.com/r/puter/ +- Mastodon: mastodon.social/@puter +- Vấn đề bảo mật? security@puter.com +- Email các nhà bảo trì tại hi@puter.com + +Chúng tôi luôn sẵn sàng giúp đỡ bạn với bất kỳ câu hỏi nào bạn có. Đừng ngần ngại hỏi! + +
+ +## Giấy Phép + +Kho lưu trữ này, bao gồm tất cả nội dung, dự án con, mô-đun và thành phần của nó, được cấp phép theo [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt), trừ khi được tuyên bố rõ ràng khác. Các thư viện của bên thứ ba được bao gồm trong kho lưu trữ này có thể phải tuân theo các giấy phép riêng của chúng. + +
\ No newline at end of file From 625ae0eade9c4cc427fa39ddb91c921582ec582d Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sun, 18 Aug 2024 11:18:42 -0700 Subject: [PATCH 0711/2119] Fix URL encoding of Vietnamese string --- doc/i18n/README.vi.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/i18n/README.vi.md b/doc/i18n/README.vi.md index 9a9151b377..6a4ae6f969 100644 --- a/doc/i18n/README.vi.md +++ b/doc/i18n/README.vi.md @@ -1,7 +1,7 @@

Puter.com, Máy Tính Đám Mây Cá Nhân: Tất cả các tệp, ứng dụng, và trò chơi của bạn ở một nơi, có thể truy cập từ bất cứ đâu vào bất kỳ lúc nào.

Hệ điều hành Internet! Miễn phí, Mã nguồn mở và Có thể tự lưu trữ.

- Kích thước repo GitHub Phiên bản phát hành GitHub Giấy phép GitHub + Kích thước repo GitHub Phiên bản phát hành GitHub Giấy phép GitHub

« DEMO TRỰC TIẾP » @@ -126,4 +126,4 @@ Chúng tôi luôn sẵn sàng giúp đỡ bạn với bất kỳ câu hỏi nào Kho lưu trữ này, bao gồm tất cả nội dung, dự án con, mô-đun và thành phần của nó, được cấp phép theo [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt), trừ khi được tuyên bố rõ ràng khác. Các thư viện của bên thứ ba được bao gồm trong kho lưu trữ này có thể phải tuân theo các giấy phép riêng của chúng. -
\ No newline at end of file +
From fc26f88e6039b1511cd17a86602387faa00ab63b Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sun, 18 Aug 2024 11:22:17 -0700 Subject: [PATCH 0712/2119] Add link to the Vietnamese README in the English README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 737087b527..9cc7878830 100644 --- a/README.md +++ b/README.md @@ -141,3 +141,4 @@ This repository, including all its contents, sub-projects, modules, and componen - [Russian / Русский](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ru.md) - [Spanish / Español](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.es.md) - [Turkish / Türkçe](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.tr.md) +- [Vietnamese / Tiếng Việt](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.vi.md) From 2386d87229aa6205ef8ced6563371ab40a0def62 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sun, 18 Aug 2024 15:22:10 -0400 Subject: [PATCH 0713/2119] feat: add writable attribute to fs items --- src/backend/src/filesystem/FSNodeContext.js | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/backend/src/filesystem/FSNodeContext.js b/src/backend/src/filesystem/FSNodeContext.js index fe421be63a..219a193435 100644 --- a/src/backend/src/filesystem/FSNodeContext.js +++ b/src/backend/src/filesystem/FSNodeContext.js @@ -659,6 +659,13 @@ module.exports = class FSNodeContext { await this.fetchEntry(); return this.isRoot; } + + if ( key === 'writable' ) { + const actor = Context.get('actor'); + if ( !actor || !actor.type.user ) return undefined; + const svc_acl = this.services.get('acl'); + return await svc_acl.check(actor, this, 'write'); + } throw new Error(`unrecognize key for FSNodeContext.get: ${key}`); } @@ -789,6 +796,7 @@ module.exports = class FSNodeContext { fsentry.dirname = _path.dirname(fsentry.path); fsentry.dirpath = fsentry.dirname; + fsentry.writable = await this.get('writable'); // Do not send internal IDs to clients fsentry.id = res.uuid; From 3819584d119076658c9d4be2b2b941c58d122ad4 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sun, 18 Aug 2024 15:54:53 -0400 Subject: [PATCH 0714/2119] fix: admin user public folder --- src/backend/src/services/auth/ACLService.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/backend/src/services/auth/ACLService.js b/src/backend/src/services/auth/ACLService.js index 72d5d66dac..82897cc2f2 100644 --- a/src/backend/src/services/auth/ACLService.js +++ b/src/backend/src/services/auth/ACLService.js @@ -73,7 +73,9 @@ class ACLService extends BaseService { const username = await fsNode.getUserPart(); const user = await svc_getUser.get_user({ username }); - if ( ! user.email_confirmed ) return; + if ( ! (user.email_confirmed || user.username === 'admin') ) { + return; + } is_public = true; })(); From 48fea77a20a0938fc2272483c798b817ca1c9848 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sun, 18 Aug 2024 22:44:27 -0400 Subject: [PATCH 0715/2119] fix: share services and features with apps --- src/backend/src/data/hardcoded-permissions.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/backend/src/data/hardcoded-permissions.js b/src/backend/src/data/hardcoded-permissions.js index e1c91834b1..65cce827c1 100644 --- a/src/backend/src/data/hardcoded-permissions.js +++ b/src/backend/src/data/hardcoded-permissions.js @@ -8,6 +8,8 @@ const default_implicit_user_app_permissions = { 'driver:puter-apps': {}, 'driver:puter-subdomains': {}, 'driver:temp-email': {}, + 'service': {}, + 'feature': {}, }; const implicit_user_app_permissions = [ From 6b4a19e12a115be2c0e323d17340ab2ce2b6b025 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 19 Aug 2024 00:58:19 -0400 Subject: [PATCH 0716/2119] fix: implicit app permissions bug --- .../src/services/auth/PermissionService.js | 9 +++++++++ .../structured/sequence/scan-permission.js | 7 ++++++- .../src/unstructured/permission-scanners.js | 19 ++++++++++++++----- src/backend/src/util/debugutil.js | 17 +++++++++++++++++ 4 files changed, 46 insertions(+), 6 deletions(-) create mode 100644 src/backend/src/util/debugutil.js diff --git a/src/backend/src/services/auth/PermissionService.js b/src/backend/src/services/auth/PermissionService.js index 492799557a..57b1c2a9c3 100644 --- a/src/backend/src/services/auth/PermissionService.js +++ b/src/backend/src/services/auth/PermissionService.js @@ -24,6 +24,7 @@ const { const { get_user, get_app } = require("../../helpers"); const { AssignableMethodsFeature } = require("../../traits/AssignableMethodsFeature"); const { Context } = require("../../util/context"); +const { get_a_letter, cylog } = require("../../util/debugutil"); const BaseService = require("../BaseService"); const { DB_WRITE } = require("../database/consts"); const { UserActorType, Actor, AppUnderUserActorType, AccessTokenActorType, SiteActorType } = require("./Actor"); @@ -220,6 +221,10 @@ class PermissionService extends BaseService { if ( ! Array.isArray(permission_options) ) { permission_options = [permission_options]; } + + // TODO: command to enable these logs + // const l = get_a_letter(); + // cylog(l, 'ACT & PERM:', actor.uid, permission_options); const start_ts = Date.now(); await require('../../structured/sequence/scan-permission') @@ -229,6 +234,10 @@ class PermissionService extends BaseService { reading, }); const end_ts = Date.now(); + + // TODO: command to enable these logs + // cylog(l, 'READING', JSON.stringify(reading, null, ' ')); + reading.push({ $: 'time', value: end_ts - start_ts, diff --git a/src/backend/src/structured/sequence/scan-permission.js b/src/backend/src/structured/sequence/scan-permission.js index b610b970e2..dedf7ab192 100644 --- a/src/backend/src/structured/sequence/scan-permission.js +++ b/src/backend/src/structured/sequence/scan-permission.js @@ -56,7 +56,12 @@ module.exports = new Sequence([ } }, async function explode_permission (a) { - const { reading, permission_options } = a.values(); + let { reading, permission_options } = a.values(); + + // VERY nasty bugs can happen if this array is not cloned! + // (this was learned the hard way) + permission_options = [...permission_options]; + for ( let i=0 ; i < permission_options.length ; i++ ) { const permission = permission_options[i]; permission_options[i] = diff --git a/src/backend/src/unstructured/permission-scanners.js b/src/backend/src/unstructured/permission-scanners.js index f9c3dd4f2c..9079032147 100644 --- a/src/backend/src/unstructured/permission-scanners.js +++ b/src/backend/src/unstructured/permission-scanners.js @@ -213,15 +213,22 @@ const PERMISSION_SCANNERS = [ const app_uid = actor.type.app.uid; + const issuer_actor = actor.get_related_actor(UserActorType); + const issuer_reading = await a.icall('scan', issuer_actor, permission_options); + for ( const permission of permission_options ) { { + const implied = default_implicit_user_app_permissions[permission]; if ( implied ) { reading.push({ - $: 'option', - source: 'implied', + $: 'path', + permission, + source: 'user-app-implied', by: 'user-app-hc-1', data: implied, + issuer_username: actor.type.user.username, + reading: issuer_reading, }); } } { @@ -233,11 +240,13 @@ const PERMISSION_SCANNERS = [ } if ( implicit_permissions[permission] ) { reading.push({ - $: 'option', + $: 'path', permission, - source: 'implied', + source: 'user-app-implied', by: 'user-app-hc-2', data: implicit_permissions[permission], + issuer_username: actor.type.user.username, + reading: issuer_reading, }); } } @@ -246,7 +255,7 @@ const PERMISSION_SCANNERS = [ let sql_perm = permission_options.map(() => `\`permission\` = ?`).join(' OR '); if ( permission_options.length > 1 ) sql_perm = '(' + sql_perm + ')'; - + // SELECT permission const rows = await db.read( 'SELECT * FROM `user_to_app_permissions` ' + diff --git a/src/backend/src/util/debugutil.js b/src/backend/src/util/debugutil.js new file mode 100644 index 0000000000..e9896eb4ff --- /dev/null +++ b/src/backend/src/util/debugutil.js @@ -0,0 +1,17 @@ +const LETTERS = ['A','B','C','D','E','F','G','H','I','J','K','L','M','N']; + +let curr_letter_ = 0; + +const ind = () => { + let v = curr_letter_; + curr_letter_++; + curr_letter_ = curr_letter_ % LETTERS.length; + return v; +}; + +module.exports = { + get_a_letter: () => LETTERS[ind()], + cylog: (...a) => { + console.log(`\x1B[36;1m`, ...a); + } +}; From 14820481b9700a5c61c6d9a156944f42f9879008 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 19 Aug 2024 14:49:17 -0400 Subject: [PATCH 0717/2119] fix: missing key for feature flag perm check --- src/backend/src/services/FeatureFlagService.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/src/services/FeatureFlagService.js b/src/backend/src/services/FeatureFlagService.js index d310cce6ad..58d288fdec 100644 --- a/src/backend/src/services/FeatureFlagService.js +++ b/src/backend/src/services/FeatureFlagService.js @@ -61,7 +61,7 @@ class FeatureFlagService extends BaseService { continue; } const svc_permission = this.services.get('permission'); - const reading = await svc_permission.scan(actor, `feature:`); + const reading = await svc_permission.scan(actor, `feature:${key}`); const l = PermissionUtil.reading_to_options(reading); summary[key] = l.length > 0; } From 3d92d0c619573d4cbdd48531b02ab96fefc4898c Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 19 Aug 2024 14:50:32 -0400 Subject: [PATCH 0718/2119] tweak: show full scan in dev console --- src/backend/src/services/auth/PermissionService.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/src/services/auth/PermissionService.js b/src/backend/src/services/auth/PermissionService.js index 57b1c2a9c3..bb60258597 100644 --- a/src/backend/src/services/auth/PermissionService.js +++ b/src/backend/src/services/auth/PermissionService.js @@ -707,7 +707,7 @@ class PermissionService extends BaseService { }) let reading = await this.scan(actor, permission); - reading = PermissionUtil.reading_to_options(reading); + // reading = PermissionUtil.reading_to_options(reading); ctx.log(JSON.stringify(reading, undefined, ' ')); } }, From cb4cab529affa5c28ddb32b90328ad47f21de8d4 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 19 Aug 2024 16:46:49 -0400 Subject: [PATCH 0719/2119] fix: don't try to sanitize null owners --- src/backend/src/om/entitystorage/SetOwnerES.js | 2 ++ src/backend/src/util/langutil.js | 3 +++ 2 files changed, 5 insertions(+) diff --git a/src/backend/src/om/entitystorage/SetOwnerES.js b/src/backend/src/om/entitystorage/SetOwnerES.js index 84eecbe57a..f33609620b 100644 --- a/src/backend/src/om/entitystorage/SetOwnerES.js +++ b/src/backend/src/om/entitystorage/SetOwnerES.js @@ -19,6 +19,7 @@ const { get_user } = require("../../helpers"); const { AppUnderUserActorType, UserActorType } = require("../../services/auth/Actor"); const { Context } = require("../../util/context"); +const { nou } = require("../../util/langutil"); const { BaseES } = require("./BaseES"); class SetOwnerES extends BaseES { @@ -64,6 +65,7 @@ class SetOwnerES extends BaseES { }, async _sanitize_owner (entity) { let owner = await entity.get('owner'); + if ( nou(owner) ) return null; owner = get_user({ id: owner }); await entity.set('owner', owner); } diff --git a/src/backend/src/util/langutil.js b/src/backend/src/util/langutil.js index 8d39bd4144..ceea451f6b 100644 --- a/src/backend/src/util/langutil.js +++ b/src/backend/src/util/langutil.js @@ -26,6 +26,9 @@ const whatis = thing => { return typeof thing; }; +const nou = v => v === null || v === undefined; + module.exports = { whatis, + nou, }; From 0705c2919f355bdd9b5e78e1fa74cfb9a986f2fe Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Mon, 19 Aug 2024 15:21:51 -0700 Subject: [PATCH 0720/2119] Remove redundant `console.log()`s --- src/gui/src/init_sync.js | 10 ---------- src/gui/src/util/Component.js | 9 --------- 2 files changed, 19 deletions(-) diff --git a/src/gui/src/init_sync.js b/src/gui/src/init_sync.js index 5635e15a46..d57046dd58 100644 --- a/src/gui/src/init_sync.js +++ b/src/gui/src/init_sync.js @@ -111,8 +111,6 @@ logger.info('start -> blocking initialization'); registry_.hooks_on_register.forEach(hook => hook({ cls })); - console.log('registered class', id, registry_); - // Find class that owns 'on_self_registered' hook let owner = cls; while ( @@ -133,7 +131,6 @@ logger.info('start -> blocking initialization'); }; scope.use = id => { - console.log('use called with id: ', id); if ( id === undefined ) { return registry_.classes_m; } @@ -142,13 +139,6 @@ logger.info('start -> blocking initialization'); throw new Error(`Class with ID ${id} not registered`); } - console.log( - 'okay it\'s going to return:', - registry_.classes_m[id], - 'and the entire map is this: ', - registry_.classes_m - ) - return registry_.classes_m[id]; } })(globalThis); diff --git a/src/gui/src/util/Component.js b/src/gui/src/util/Component.js index 7039513fc8..3ebfd0632c 100644 --- a/src/gui/src/util/Component.js +++ b/src/gui/src/util/Component.js @@ -37,16 +37,10 @@ export const Component = def(class Component extends HTMLElement { // Automatically define components for all HTML elements on_other_registered(({ cls }) => { - console.log('detected class', cls.ID); if ( cls.ID === 'ui.component.StepHeading' ) { globalThis.sh_shouldbe = cls; - console.log( - 'this is what StepHeading should be', - cls - ); } if ( globalThis.lib.is_subclass(cls, HTMLElement) ) { - console.log('registering as an element'); defineComponent(cls); } }); @@ -222,9 +216,6 @@ export const defineComponent = (component) => { // TODO: This is necessary because files can be loaded from // both `/src/UI` and `/UI` in the URL; we need to fix that if ( customElements.get(name) ) return; - - // console.log('[surely] defining', name, 'as', component); - customElements.define(name, component); component.defined_as = name; } From a7cdb70251ae86f883257de3596838d20196c62d Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 19 Aug 2024 21:27:46 -0400 Subject: [PATCH 0721/2119] fix: ll_write --- src/backend/src/filesystem/ll_operations/ll_write.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/src/filesystem/ll_operations/ll_write.js b/src/backend/src/filesystem/ll_operations/ll_write.js index cc83a7f15d..f2600ce71c 100644 --- a/src/backend/src/filesystem/ll_operations/ll_write.js +++ b/src/backend/src/filesystem/ll_operations/ll_write.js @@ -53,7 +53,7 @@ class LLWriteBase extends LLFilesystemOperation { const storage = svc_mountpoint.get_storage(); bucket ??= config.s3_bucket; - bucket_region ??= config.s3_region; + bucket_region ??= config.s3_region ?? config.region; let upload_tracker = new UploadProgressTracker(); @@ -251,7 +251,7 @@ class LLCWrite extends LLWriteBase { this.field('fsentry-uid', uid); // determine bucket region - let bucket_region = config.s3_region; + let bucket_region = config.s3_region ?? config.region; let bucket = config.s3_bucket; this.checkpoint('before acl'); From fca88a82cc420199e87246912f71c3163d45d5ba Mon Sep 17 00:00:00 2001 From: Sam-SSTU <17349719015@163.com> Date: Tue, 20 Aug 2024 09:56:16 +0800 Subject: [PATCH 0722/2119] add Chinese, add language tag --- README.md | 13 +++- doc/i18n/README.da.md | 13 +++- doc/i18n/README.en.md | 13 +++- doc/i18n/README.es.md | 13 +++- doc/i18n/README.hi.md | 13 +++- doc/i18n/README.jp.md | 13 +++- doc/i18n/README.ko.md | 13 +++- doc/i18n/README.pt.md | 13 +++- doc/i18n/README.ru.md | 13 +++- doc/i18n/README.tr.md | 13 +++- doc/i18n/README.vi.md | 12 ++++ doc/i18n/README.zh.md | 149 ++++++++++++++++++++++++++++++++++++++++++ 12 files changed, 281 insertions(+), 10 deletions(-) create mode 100644 doc/i18n/README.zh.md diff --git a/README.md b/README.md index 9cc7878830..560cb8c9f2 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,18 @@

GitHub repo size GitHub Release GitHub License

- +

+English +Danish (Dansk) +Hindi (हिंदी) +Japanese (日本語) +Portuguese (Português) +Russian (Русский) +Spanish (Español) +Turkish (Türkçe) +Vietnamese (Tiếng Việt) +Chinese (中文) +

« LIVE DEMO »
diff --git a/doc/i18n/README.da.md b/doc/i18n/README.da.md index df9f9ec8e4..8eefc98e5e 100644 --- a/doc/i18n/README.da.md +++ b/doc/i18n/README.da.md @@ -5,7 +5,18 @@

GitHub repo størrelse GitHub Udgivelse GitHub Licens

- +

+English +Danish (Dansk) +Hindi (हिंदी) +Japanese (日本語) +Portuguese (Português) +Russian (Русский) +Spanish (Español) +Turkish (Türkçe) +Vietnamese (Tiếng Việt) +Chinese (中文) +

« LIVE DEMO »
diff --git a/doc/i18n/README.en.md b/doc/i18n/README.en.md index 9ad73f54f8..d1286bec31 100644 --- a/doc/i18n/README.en.md +++ b/doc/i18n/README.en.md @@ -5,7 +5,18 @@

GitHub repo size GitHub Release GitHub License

- +

+English +Danish (Dansk) +Hindi (हिंदी) +Japanese (日本語) +Portuguese (Português) +Russian (Русский) +Spanish (Español) +Turkish (Türkçe) +Vietnamese (Tiếng Việt) +Chinese (中文) +

« LIVE DEMO »
diff --git a/doc/i18n/README.es.md b/doc/i18n/README.es.md index d7a2f22b63..9db6c9cba9 100644 --- a/doc/i18n/README.es.md +++ b/doc/i18n/README.es.md @@ -5,7 +5,18 @@

GitHub repo size GitHub Release GitHub License

- +

+English +Danish (Dansk) +Hindi (हिंदी) +Japanese (日本語) +Portuguese (Português) +Russian (Русский) +Spanish (Español) +Turkish (Türkçe) +Vietnamese (Tiếng Việt) +Chinese (中文) +

« DEMO EN VIVO »
diff --git a/doc/i18n/README.hi.md b/doc/i18n/README.hi.md index 0bc54ba2b1..96161b0a20 100644 --- a/doc/i18n/README.hi.md +++ b/doc/i18n/README.hi.md @@ -5,7 +5,18 @@

GitHub repo size GitHub Release GitHub License

- +

+English +Danish (Dansk) +Hindi (हिंदी) +Japanese (日本語) +Portuguese (Português) +Russian (Русский) +Spanish (Español) +Turkish (Türkçe) +Vietnamese (Tiếng Việt) +Chinese (中文) +

« LIVE DEMO »
diff --git a/doc/i18n/README.jp.md b/doc/i18n/README.jp.md index 479e1ad8d7..d739b40ec7 100644 --- a/doc/i18n/README.jp.md +++ b/doc/i18n/README.jp.md @@ -6,7 +6,18 @@

GitHub リポジトリサイズ GitHub リリース GitHub ライセンス

- +

+English +Danish (Dansk) +Hindi (हिंदी) +Japanese (日本語) +Portuguese (Português) +Russian (Русский) +Spanish (Español) +Turkish (Türkçe) +Vietnamese (Tiếng Việt) +Chinese (中文) +

« ライブデモ »
diff --git a/doc/i18n/README.ko.md b/doc/i18n/README.ko.md index c08ab2220c..a7d742823c 100644 --- a/doc/i18n/README.ko.md +++ b/doc/i18n/README.ko.md @@ -5,7 +5,18 @@

GitHub repo size GitHub Release GitHub License

- +

+English +Danish (Dansk) +Hindi (हिंदी) +Japanese (日本語) +Portuguese (Português) +Russian (Русский) +Spanish (Español) +Turkish (Türkçe) +Vietnamese (Tiếng Việt) +Chinese (中文) +

« 시연 영상 »
diff --git a/doc/i18n/README.pt.md b/doc/i18n/README.pt.md index 8104a3a6b8..43694cc06e 100644 --- a/doc/i18n/README.pt.md +++ b/doc/i18n/README.pt.md @@ -5,7 +5,18 @@

Tamanho do repositório do GitHub Lançamento no GitHub Licença do GitHub

- +

+English +Danish (Dansk) +Hindi (हिंदी) +Japanese (日本語) +Portuguese (Português) +Russian (Русский) +Spanish (Español) +Turkish (Türkçe) +Vietnamese (Tiếng Việt) +Chinese (中文) +

« DEMONSTRAÇÃO AO VIVO »
diff --git a/doc/i18n/README.ru.md b/doc/i18n/README.ru.md index df906217df..17e07447b6 100644 --- a/doc/i18n/README.ru.md +++ b/doc/i18n/README.ru.md @@ -5,7 +5,18 @@

Размер репозитория GitHub Релиз GitHub Лицензия GitHub

- +

+English +Danish (Dansk) +Hindi (हिंदी) +Japanese (日本語) +Portuguese (Português) +Russian (Русский) +Spanish (Español) +Turkish (Türkçe) +Vietnamese (Tiếng Việt) +Chinese (中文) +

« ЖИВОЕ ДЕМО »
diff --git a/doc/i18n/README.tr.md b/doc/i18n/README.tr.md index 34f2d57bc2..f55f1e15a0 100644 --- a/doc/i18n/README.tr.md +++ b/doc/i18n/README.tr.md @@ -5,7 +5,18 @@

GitHub Depo Boyutu GitHub Yayınlamak GitHub Lisans

- +

+English +Danish (Dansk) +Hindi (हिंदी) +Japanese (日本語) +Portuguese (Português) +Russian (Русский) +Spanish (Español) +Turkish (Türkçe) +Vietnamese (Tiếng Việt) +Chinese (中文) +

« CANLI DEMO »
diff --git a/doc/i18n/README.vi.md b/doc/i18n/README.vi.md index 6a4ae6f969..b41c0a572a 100644 --- a/doc/i18n/README.vi.md +++ b/doc/i18n/README.vi.md @@ -3,6 +3,18 @@

Kích thước repo GitHub Phiên bản phát hành GitHub Giấy phép GitHub

+

+English +Danish (Dansk) +Hindi (हिंदी) +Japanese (日本語) +Portuguese (Português) +Russian (Русский) +Spanish (Español) +Turkish (Türkçe) +Vietnamese (Tiếng Việt) +Chinese (中文) +

« DEMO TRỰC TIẾP »
diff --git a/doc/i18n/README.zh.md b/doc/i18n/README.zh.md new file mode 100644 index 0000000000..c88b83d5f2 --- /dev/null +++ b/doc/i18n/README.zh.md @@ -0,0 +1,149 @@ + +

Puter.com,个人云计算机:所有文件、应用程序和游戏在一个地方,随时随地可访问。

+ +

互联网操作系统!免费、开源且可自行托管。

+ +

+ GitHub repo size GitHub Release GitHub License +

+ +

+English +Danish (Dansk) +Hindi (हिंदी) +Japanese (日本語) +Portuguese (Português) +Russian (Русский) +Spanish (Español) +Turkish (Türkçe) +Vietnamese (Tiếng Việt) +Chinese (中文) +

+ + + + +

+ « 在线演示 » +
+
+ Puter.com + · + SDK + · + Discord + · + YouTube + · + Reddit + · + X (Twitter) + · + 漏洞报告 +

+ +

screenshot

+ +
+ +## Puter + +Puter 是一个先进的开源互联网操作系统,设计为功能丰富、速度极快且高度可扩展。Puter 可用作: + +- 一个以隐私为优先的个人云,将所有文件、应用程序和游戏保存在一个安全的地方,随时随地可访问。 +- 构建和发布网站、Web 应用程序和游戏的平台。 +- Dropbox、Google Drive、OneDrive 等的替代品,具有全新的界面和强大的功能。 +- 服务器和工作站的远程桌面环境。 +- 一个友好的开源项目和社区,学习 Web 开发、云计算、分布式系统等更多内容! + +
+ +## 入门指南 + + +### 💻 本地开发 + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +这将会在 http://puter.localhost:4100(或下一个可用端口)启动 Puter。 + +
+ +### 🐳 Docker + + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ + +### 🐙 Docker Compose + + +#### Linux/macOS +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` +
+ +#### Windows + + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +### ☁️ Puter.com + +Puter 可以作为托管服务使用,访问 [**puter.com**](https://puter.com)。 + +
+ +## 系统要求 + +- **操作系统:** Linux, macOS, Windows +- **内存:** 最低 2GB(推荐 4GB) +- **磁盘空间:** 1GB 可用空间 +- **Node.js:** 版本 16+(推荐 22+) +- **npm:** 最新稳定版本 + +
+ +## 支持 + +通过以下渠道与维护者和社区联系: + +- 有 Bug 报告或功能请求?请 [提交问题](https://github.com/HeyPuter/puter/issues/new/choose)。 +- Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) +- Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) +- 安全问题?请联系 [security@puter.com](mailto:security@puter.com) +- 电子邮件维护者 [hi@puter.com](mailto:hi@puter.com) + +我们随时乐意帮助您解答任何问题,欢迎随时联系! + +
+ + +## 许可证 + +本仓库,包括其所有内容、子项目、模块和组件,除非另有明确说明,否则均遵循 [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) 许可证。 本仓库中包含的第三方库可能受其各自的许可证约束。 + +
From a3eb52702d8c7929850b1e1e2f881093c739d631 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Mon, 19 Aug 2024 19:36:20 -0700 Subject: [PATCH 0723/2119] Remove language badges and add link to the Chinese README inside the English README --- README.md | 13 +------------ doc/i18n/README.da.md | 12 ------------ doc/i18n/README.en.md | 12 ------------ doc/i18n/README.es.md | 12 ------------ doc/i18n/README.hi.md | 12 ------------ doc/i18n/README.jp.md | 12 ------------ doc/i18n/README.ko.md | 12 ------------ doc/i18n/README.pt.md | 12 ------------ doc/i18n/README.ru.md | 12 ------------ doc/i18n/README.tr.md | 12 ------------ doc/i18n/README.vi.md | 12 ------------ doc/i18n/README.zh.md | 16 ---------------- 12 files changed, 1 insertion(+), 148 deletions(-) diff --git a/README.md b/README.md index 560cb8c9f2..a5043040dd 100644 --- a/README.md +++ b/README.md @@ -5,18 +5,6 @@

GitHub repo size GitHub Release GitHub License

-

-English -Danish (Dansk) -Hindi (हिंदी) -Japanese (日本語) -Portuguese (Português) -Russian (Русский) -Spanish (Español) -Turkish (Türkçe) -Vietnamese (Tiếng Việt) -Chinese (中文) -

« LIVE DEMO »
@@ -144,6 +132,7 @@ This repository, including all its contents, sub-projects, modules, and componen ## Translations +- [Chinese / 中文](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.zh.md) - [Danish / Dansk](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.da.md) - [English](https://github.com/HeyPuter/puter/blob/main/README.md) - [Hindi / हिंदी](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.hi.md) diff --git a/doc/i18n/README.da.md b/doc/i18n/README.da.md index 8eefc98e5e..673cc09f8c 100644 --- a/doc/i18n/README.da.md +++ b/doc/i18n/README.da.md @@ -5,18 +5,6 @@

GitHub repo størrelse GitHub Udgivelse GitHub Licens

-

-English -Danish (Dansk) -Hindi (हिंदी) -Japanese (日本語) -Portuguese (Português) -Russian (Русский) -Spanish (Español) -Turkish (Türkçe) -Vietnamese (Tiếng Việt) -Chinese (中文) -

« LIVE DEMO »
diff --git a/doc/i18n/README.en.md b/doc/i18n/README.en.md index d1286bec31..55c22b73a4 100644 --- a/doc/i18n/README.en.md +++ b/doc/i18n/README.en.md @@ -5,18 +5,6 @@

GitHub repo size GitHub Release GitHub License

-

-English -Danish (Dansk) -Hindi (हिंदी) -Japanese (日本語) -Portuguese (Português) -Russian (Русский) -Spanish (Español) -Turkish (Türkçe) -Vietnamese (Tiếng Việt) -Chinese (中文) -

« LIVE DEMO »
diff --git a/doc/i18n/README.es.md b/doc/i18n/README.es.md index 9db6c9cba9..c7d3a2d6a2 100644 --- a/doc/i18n/README.es.md +++ b/doc/i18n/README.es.md @@ -5,18 +5,6 @@

GitHub repo size GitHub Release GitHub License

-

-English -Danish (Dansk) -Hindi (हिंदी) -Japanese (日本語) -Portuguese (Português) -Russian (Русский) -Spanish (Español) -Turkish (Türkçe) -Vietnamese (Tiếng Việt) -Chinese (中文) -

« DEMO EN VIVO »
diff --git a/doc/i18n/README.hi.md b/doc/i18n/README.hi.md index 96161b0a20..aa26ea3eb8 100644 --- a/doc/i18n/README.hi.md +++ b/doc/i18n/README.hi.md @@ -5,18 +5,6 @@

GitHub repo size GitHub Release GitHub License

-

-English -Danish (Dansk) -Hindi (हिंदी) -Japanese (日本語) -Portuguese (Português) -Russian (Русский) -Spanish (Español) -Turkish (Türkçe) -Vietnamese (Tiếng Việt) -Chinese (中文) -

« LIVE DEMO »
diff --git a/doc/i18n/README.jp.md b/doc/i18n/README.jp.md index d739b40ec7..5ec1bf3645 100644 --- a/doc/i18n/README.jp.md +++ b/doc/i18n/README.jp.md @@ -6,18 +6,6 @@

GitHub リポジトリサイズ GitHub リリース GitHub ライセンス

-

-English -Danish (Dansk) -Hindi (हिंदी) -Japanese (日本語) -Portuguese (Português) -Russian (Русский) -Spanish (Español) -Turkish (Türkçe) -Vietnamese (Tiếng Việt) -Chinese (中文) -

« ライブデモ »
diff --git a/doc/i18n/README.ko.md b/doc/i18n/README.ko.md index a7d742823c..cc0ed0fa36 100644 --- a/doc/i18n/README.ko.md +++ b/doc/i18n/README.ko.md @@ -5,18 +5,6 @@

GitHub repo size GitHub Release GitHub License

-

-English -Danish (Dansk) -Hindi (हिंदी) -Japanese (日本語) -Portuguese (Português) -Russian (Русский) -Spanish (Español) -Turkish (Türkçe) -Vietnamese (Tiếng Việt) -Chinese (中文) -

« 시연 영상 »
diff --git a/doc/i18n/README.pt.md b/doc/i18n/README.pt.md index 43694cc06e..7a541e8498 100644 --- a/doc/i18n/README.pt.md +++ b/doc/i18n/README.pt.md @@ -5,18 +5,6 @@

Tamanho do repositório do GitHub Lançamento no GitHub Licença do GitHub

-

-English -Danish (Dansk) -Hindi (हिंदी) -Japanese (日本語) -Portuguese (Português) -Russian (Русский) -Spanish (Español) -Turkish (Türkçe) -Vietnamese (Tiếng Việt) -Chinese (中文) -

« DEMONSTRAÇÃO AO VIVO »
diff --git a/doc/i18n/README.ru.md b/doc/i18n/README.ru.md index 17e07447b6..832dd60bb6 100644 --- a/doc/i18n/README.ru.md +++ b/doc/i18n/README.ru.md @@ -5,18 +5,6 @@

Размер репозитория GitHub Релиз GitHub Лицензия GitHub

-

-English -Danish (Dansk) -Hindi (हिंदी) -Japanese (日本語) -Portuguese (Português) -Russian (Русский) -Spanish (Español) -Turkish (Türkçe) -Vietnamese (Tiếng Việt) -Chinese (中文) -

« ЖИВОЕ ДЕМО »
diff --git a/doc/i18n/README.tr.md b/doc/i18n/README.tr.md index f55f1e15a0..85d9cf309f 100644 --- a/doc/i18n/README.tr.md +++ b/doc/i18n/README.tr.md @@ -5,18 +5,6 @@

GitHub Depo Boyutu GitHub Yayınlamak GitHub Lisans

-

-English -Danish (Dansk) -Hindi (हिंदी) -Japanese (日本語) -Portuguese (Português) -Russian (Русский) -Spanish (Español) -Turkish (Türkçe) -Vietnamese (Tiếng Việt) -Chinese (中文) -

« CANLI DEMO »
diff --git a/doc/i18n/README.vi.md b/doc/i18n/README.vi.md index b41c0a572a..6a4ae6f969 100644 --- a/doc/i18n/README.vi.md +++ b/doc/i18n/README.vi.md @@ -3,18 +3,6 @@

Kích thước repo GitHub Phiên bản phát hành GitHub Giấy phép GitHub

-

-English -Danish (Dansk) -Hindi (हिंदी) -Japanese (日本語) -Portuguese (Português) -Russian (Русский) -Spanish (Español) -Turkish (Türkçe) -Vietnamese (Tiếng Việt) -Chinese (中文) -

« DEMO TRỰC TIẾP »
diff --git a/doc/i18n/README.zh.md b/doc/i18n/README.zh.md index c88b83d5f2..e463f3f8da 100644 --- a/doc/i18n/README.zh.md +++ b/doc/i18n/README.zh.md @@ -7,22 +7,6 @@ GitHub repo size GitHub Release GitHub License

-

-English -Danish (Dansk) -Hindi (हिंदी) -Japanese (日本語) -Portuguese (Português) -Russian (Русский) -Spanish (Español) -Turkish (Türkçe) -Vietnamese (Tiếng Việt) -Chinese (中文) -

- - - -

« 在线演示 »
From aa610befb13cdbdfe3910d7bbbbc4d8db2f38aa4 Mon Sep 17 00:00:00 2001 From: FabioDePalma <44713203+FabioDePalma@users.noreply.github.com> Date: Tue, 20 Aug 2024 09:05:13 +0200 Subject: [PATCH 0724/2119] added readme file in Italian --- README.md | 1 + doc/i18n/README.it.md | 132 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 133 insertions(+) create mode 100644 doc/i18n/README.it.md diff --git a/README.md b/README.md index a5043040dd..becb44c3c6 100644 --- a/README.md +++ b/README.md @@ -142,3 +142,4 @@ This repository, including all its contents, sub-projects, modules, and componen - [Spanish / Español](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.es.md) - [Turkish / Türkçe](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.tr.md) - [Vietnamese / Tiếng Việt](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.vi.md) +- [Italian / Italiano](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.it.md) diff --git a/doc/i18n/README.it.md b/doc/i18n/README.it.md new file mode 100644 index 0000000000..3a4070d1bd --- /dev/null +++ b/doc/i18n/README.it.md @@ -0,0 +1,132 @@ +

Puter.com, The Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time.

+ +

Il sistema operativo di Internet! Gratuito, Open-Source e Auto-Hostabile.

+ +

+ GitHub repo size GitHub Release GitHub License +

+

+ « LIVE DEMO » +
+
+ Puter.com + · + SDK + · + Discord + · + YouTube + · + Reddit + · + X (Twitter) + · + Bug Bounty +

+ +

screenshot

+ +
+ +## Puter + +Puter è un sistema operativo di Internet avanzato e open-source, progettato per essere ricco di funzionalità, eccezionalmente veloce e altamente estensibile. Puter può essere utilizzato come: + +- Un cloud personale che tiene conto della privacy per conservare tutti i file, le app e i giochi in un luogo sicuro, accessibile da qualsiasi luogo e in qualsiasi momento. +- Una piattaforma per creare e pubblicare siti web, app e giochi. +- Un'alternativa a Dropbox, Google Drive, OneDrive, ecc. con un'interfaccia nuova e funzioni potenti. +- Un ambiente desktop remoto per server e workstation. +- Un progetto e una comunità open-source amichevole per imparare lo sviluppo web, il cloud computing, i sistemi distribuiti e molto altro ancora! + +
+ +## Getting Started + + +### 💻 Local Development + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +In questo modo Puter verrà avviato all'indirizzo http://puter.localhost:4100 (o alla prossima porta disponibile). + +
+ +### 🐳 Docker + + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ + +### 🐙 Docker Compose + + +#### Linux/macOS +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` +
+ +#### Windows + + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +### ☁️ Puter.com + +Puter è disponibile come servizio in hosting su [**puter.com**](https://puter.com). + +
+ +## Requisiti di Sistema + +- **Sistema Operativo:** Linux, macOS, Windows +- **RAM:** 2GB minimi (4GB raccomandati) +- **Spazio su Disco:** 1GB liberi +- **Node.js:** Versione 16+ (Versione 22+ raccomandati) +- **npm:** Ultima versione stabile + +
+ +## Supporto + +Collegatevi con i maintainers e la comunità attraverso questi canali: + +- Segnalazione di bug o richiesta di funzionalità? Perfavore [aprire una issue](https://github.com/HeyPuter/puter/issues/new/choose). +- Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) +- Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) +- Problemi di sicurezza? [security@puter.com](mailto:security@puter.com) +- Email maintainers a [hi@puter.com](mailto:hi@puter.com) + +Siamo sempre felici di aiutarvi con qualsiasi domanda. Non esitate a chiedere! + +
+ + +## Licenza + +Questo repository, compresi tutti i suoi contenuti, sottoprogetti, moduli e componenti, è concesso in licenza [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt), a meno che non sia esplicitamente indicato diversamente. Le librerie di terze parti incluse in questo repository possono essere soggette alle loro licenze. + +
+ From a002ad08e5622a349b5d24ed2c7c5f61215146b8 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 20 Aug 2024 18:33:12 -0400 Subject: [PATCH 0725/2119] fix(security): remove unconfirmed_email from /whoami for apps --- src/backend/src/routers/whoami.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backend/src/routers/whoami.js b/src/backend/src/routers/whoami.js index a4eabdea59..2c57e6b9c0 100644 --- a/src/backend/src/routers/whoami.js +++ b/src/backend/src/routers/whoami.js @@ -73,6 +73,7 @@ const WHOAMI_GET = eggspress('/whoami', { // delete details.username; // delete details.uuid; delete details.email; + delete details.unconfirmed_email; delete details.desktop_bg_url; delete details.desktop_bg_color; delete details.desktop_bg_fit; From 5caf59f1bc22c0342e594a31b0f5d9ebe068660c Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 20 Aug 2024 19:05:34 -0700 Subject: [PATCH 0726/2119] make logger return empty string --- src/gui/src/init_sync.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/src/init_sync.js b/src/gui/src/init_sync.js index d57046dd58..3d632e5bdd 100644 --- a/src/gui/src/init_sync.js +++ b/src/gui/src/init_sync.js @@ -39,7 +39,8 @@ // something like this was also done in backend and it proved useful. (scope => { globalThis.logger = { - info: (...a) => console.log('%c[INIT/INFO]', 'color: #4287f5', ...a), + info: (...a) => {}, + // info: (...a) => console.log('%c[INIT/INFO]', 'color: #4287f5', ...a), }; })(globalThis); logger.info('start -> blocking initialization'); From 0b97bff1a2b2f6573c12dd2231632e71331aa933 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 20 Aug 2024 19:29:11 -0700 Subject: [PATCH 0727/2119] Open public folders via URL only if deskotp has finished loading --- src/gui/src/UI/UIDesktop.js | 26 ++++++++++++++++++++++++++ src/gui/src/initgui.js | 23 ----------------------- 2 files changed, 26 insertions(+), 23 deletions(-) diff --git a/src/gui/src/UI/UIDesktop.js b/src/gui/src/UI/UIDesktop.js index c02e455927..0bfb37dbb7 100644 --- a/src/gui/src/UI/UIDesktop.js +++ b/src/gui/src/UI/UIDesktop.js @@ -1143,6 +1143,32 @@ async function UIDesktop(options){ }) } }) + + + //-------------------------------------------------------------------------------------- + // Trying to view a user's public folder? + // i.e. https://puter.com/@ + //-------------------------------------------------------------------------------------- + const url_paths = window.location.pathname.split('/').filter(element => element); + if(url_paths[0]?.startsWith('@')){ + let username = url_paths[0].substring(1); + let item_path = '/' + username + '/Public'; + + // check if username has valid characters + if(!username.match(/^[a-z0-9_]+$/i)){ + UIAlert({ + message: 'Invalid username.' + }); + }else{ + UIWindow({ + path: item_path, + title: path.basename(item_path), + icon: await item_icon({is_dir: true, path: item_path}), + is_dir: true, + app: 'explorer', + }); + } + } } $(document).on('contextmenu taphold', '.taskbar', function(event){ diff --git a/src/gui/src/initgui.js b/src/gui/src/initgui.js index efdadc4546..a74763deee 100644 --- a/src/gui/src/initgui.js +++ b/src/gui/src/initgui.js @@ -189,29 +189,6 @@ window.initgui = async function(options){ let whoami; const url_paths = window.location.pathname.split('/').filter(element => element); - //-------------------------------------------------------------------------------------- - // Trying to view a user's public folder? - // i.e. https://puter.com/@ - //-------------------------------------------------------------------------------------- - if(url_paths[0]?.startsWith('@')){ - let username = url_paths[0].substring(1); - let item_path = '/' + username + '/Public'; - - // check if username has valid characters - if(!username.match(/^[a-z0-9_]+$/i)){ - UIAlert({ - message: 'Invalid username.' - }); - }else{ - UIWindow({ - path: item_path, - title: path.basename(item_path), - icon: await item_icon({is_dir: true, path: item_path}), - is_dir: true, - app: 'explorer', - }); - } - } //-------------------------------------------------------------------------------------- // Determine if an app was launched from URL From 921f522732b199a6dd0872be5820471b227cc1d1 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 20 Aug 2024 19:37:35 -0700 Subject: [PATCH 0728/2119] Remove redundant `console.log` --- src/gui/src/helpers/launch_app.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gui/src/helpers/launch_app.js b/src/gui/src/helpers/launch_app.js index 940b6d0b13..e156969122 100644 --- a/src/gui/src/helpers/launch_app.js +++ b/src/gui/src/helpers/launch_app.js @@ -40,7 +40,6 @@ const launch_app = async (options)=>{ // explorer is a special case if(options.name === 'explorer'){ - console.log('explorer'); app_info = []; } else if(options.app_obj) From 7024e2ec91bcb46f5a8b4edc2ee0d9f963019009 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 20 Aug 2024 19:51:21 -0700 Subject: [PATCH 0729/2119] Add `ketboards.js` to prod dependencies --- src/gui/src/static-assets.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/src/static-assets.js b/src/gui/src/static-assets.js index 1b8b0e5d58..b6fc567791 100644 --- a/src/gui/src/static-assets.js +++ b/src/gui/src/static-assets.js @@ -50,6 +50,7 @@ const js_paths = [ '/IPC.js', '/globals.js', `/i18n/i18n.js`, + `/keyboard.js` ] export { lib_paths, css_paths, js_paths }; \ No newline at end of file From 2678679ab7dae98e786ec8fec8ccc20aff6aecdc Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 21 Aug 2024 14:11:16 -0700 Subject: [PATCH 0730/2119] Correct the order of README translation links --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index becb44c3c6..78081ec63a 100644 --- a/README.md +++ b/README.md @@ -136,10 +136,10 @@ This repository, including all its contents, sub-projects, modules, and componen - [Danish / Dansk](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.da.md) - [English](https://github.com/HeyPuter/puter/blob/main/README.md) - [Hindi / हिंदी](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.hi.md) +- [Italian / Italiano](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.it.md) - [Japanese / 日本語](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.jp.md) - [Portuguese / Português](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.pt.md) - [Russian / Русский](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ru.md) - [Spanish / Español](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.es.md) - [Turkish / Türkçe](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.tr.md) - [Vietnamese / Tiếng Việt](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.vi.md) -- [Italian / Italiano](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.it.md) From 9d5963cdf5fe63a4f7970d2d03bc307f4d4fa3ab Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 20 Aug 2024 22:22:33 -0400 Subject: [PATCH 0731/2119] feat(puterai): add streaming --- .../src/modules/puterai/AIInterfaceService.js | 3 +- .../puterai/OpenAICompletionService.js | 38 +++++++++++++++++-- src/backend/src/routers/drivers/call.js | 6 ++- .../src/services/drivers/CoercionService.js | 2 +- 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/src/backend/src/modules/puterai/AIInterfaceService.js b/src/backend/src/modules/puterai/AIInterfaceService.js index 9deb15e296..257291033d 100644 --- a/src/backend/src/modules/puterai/AIInterfaceService.js +++ b/src/backend/src/modules/puterai/AIInterfaceService.js @@ -33,8 +33,9 @@ class AIInterfaceService extends BaseService { parameters: { messages: { type: 'json' }, vision: { type: 'flag' }, + stream: { type: 'flag' }, }, - result: { type: 'json' } + result: { type: 'json' }, } } }); diff --git a/src/backend/src/modules/puterai/OpenAICompletionService.js b/src/backend/src/modules/puterai/OpenAICompletionService.js index 5a6cfd26c9..f9a9af3a66 100644 --- a/src/backend/src/modules/puterai/OpenAICompletionService.js +++ b/src/backend/src/modules/puterai/OpenAICompletionService.js @@ -1,7 +1,10 @@ +const { PassThrough } = require('stream'); const APIError = require('../../api/APIError'); const BaseService = require('../../services/BaseService'); +const { TypedValue } = require('../../services/drivers/meta/Runtime'); const { Context } = require('../../util/context'); const SmolUtil = require('../../util/smolutil'); +const { nou } = require('../../util/langutil'); class OpenAICompletionService extends BaseService { static MODULES = { @@ -20,7 +23,7 @@ class OpenAICompletionService extends BaseService { static IMPLEMENTS = { ['puter-chat-completion']: { - async complete ({ messages, test_mode }) { + async complete ({ messages, test_mode, stream }) { if ( test_mode ) { const { LoremIpsum } = require('lorem-ipsum'); const li = new LoremIpsum({ @@ -50,6 +53,7 @@ class OpenAICompletionService extends BaseService { return await this.complete(messages, { model, moderation: true, + stream, }); } } @@ -76,7 +80,7 @@ class OpenAICompletionService extends BaseService { }; } - async complete (messages, { moderation, model }) { + async complete (messages, { stream, moderation, model }) { // Validate messages if ( ! Array.isArray(messages) ) { throw new Error('`messages` must be an array'); @@ -199,7 +203,35 @@ class OpenAICompletionService extends BaseService { messages: messages, model: model, max_tokens, + stream, }); + + if ( stream ) { + const entire = []; + const stream = new PassThrough(); + const retval = new TypedValue({ + $: 'stream', + content_type: 'application/x-ndjson', + chunked: true, + }, stream); + (async () => { + for await ( const chunk of completion ) { + entire.push(chunk); + if ( chunk.choices.length < 1 ) continue; + if ( chunk.choices[0].finish_reason ) { + stream.end(); + break; + } + if ( nou(chunk.choices[0].delta.content) ) continue; + const str = JSON.stringify({ + text: chunk.choices[0].delta.content + }); + stream.write(str + '\n'); + } + })(); + return retval; + } + this.log.info('how many choices?: ' + completion.choices.length); @@ -244,7 +276,7 @@ class OpenAICompletionService extends BaseService { throw new Error('message is not allowed'); } } - + return completion.choices[0]; } } diff --git a/src/backend/src/routers/drivers/call.js b/src/backend/src/routers/drivers/call.js index 4c66a85554..3236b1b881 100644 --- a/src/backend/src/routers/drivers/call.js +++ b/src/backend/src/routers/drivers/call.js @@ -84,7 +84,7 @@ module.exports = eggspress('/drivers/call', { // consider the case where a driver method implements a // stream transformation, thus the stream from the request isn't // consumed until the response is being sent. - + _respond(res, result); // What we _can_ do is await the request promise while responding @@ -95,8 +95,12 @@ module.exports = eggspress('/drivers/call', { const _respond = (res, result) => { if ( result.result instanceof TypedValue ) { const tv = result.result; + debugger; if ( TypeSpec.adapt({ $: 'stream' }).equals(tv.type) ) { res.set('Content-Type', tv.type.raw.content_type); + if ( tv.type.raw.chunked ) { + res.set('Transfer-Encoding', 'chunked'); + } tv.value.pipe(res); return; } diff --git a/src/backend/src/services/drivers/CoercionService.js b/src/backend/src/services/drivers/CoercionService.js index c3784e1780..5caceb092c 100644 --- a/src/backend/src/services/drivers/CoercionService.js +++ b/src/backend/src/services/drivers/CoercionService.js @@ -88,7 +88,7 @@ class CoercionService extends BaseService { return coerced; } - return undefined; + return typed_value; } } From d009cd0aaff645a24d37085ed41c55fe296a5722 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 20 Aug 2024 22:23:27 -0400 Subject: [PATCH 0732/2119] feat(puterai): add claude --- package-lock.json | 27 ++++- src/backend/package.json | 1 + .../src/modules/puterai/ClaudeService.js | 109 ++++++++++++++++++ .../src/modules/puterai/PuterAIModule.js | 5 + 4 files changed, 141 insertions(+), 1 deletion(-) create mode 100644 src/backend/src/modules/puterai/ClaudeService.js diff --git a/package-lock.json b/package-lock.json index 225d2e4484..f15dee877b 100644 --- a/package-lock.json +++ b/package-lock.json @@ -263,6 +263,30 @@ "node": ">=6.0.0" } }, + "node_modules/@anthropic-ai/sdk": { + "version": "0.26.1", + "resolved": "https://registry.npmjs.org/@anthropic-ai/sdk/-/sdk-0.26.1.tgz", + "integrity": "sha512-HeMJP1bDFfQPQS3XTJAmfXkFBdZ88wvfkE05+vsoA9zGn5dHqEaHOPsqkazf/i0gXYg2XlLxxZrf6rUAarSqzw==", + "license": "MIT", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7" + } + }, + "node_modules/@anthropic-ai/sdk/node_modules/@types/node": { + "version": "18.19.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.45.tgz", + "integrity": "sha512-VZxPKNNhjKmaC1SUYowuXSRSMGyQGmQjvvA1xE4QZ0xce2kLtEhPDS+kqpCPBZYgqblCLQ2DAjSzmgCM5auvhA==", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, "node_modules/@aws-crypto/sha256-browser": { "version": "5.2.0", "resolved": "https://registry.npmjs.org/@aws-crypto/sha256-browser/-/sha256-browser-5.2.0.tgz", @@ -16561,9 +16585,10 @@ }, "src/backend": { "name": "@heyputer/backend", - "version": "2.1.0", + "version": "2.4.1", "license": "AGPL-3.0-only", "dependencies": { + "@anthropic-ai/sdk": "^0.26.1", "@aws-sdk/client-polly": "^3.622.0", "@aws-sdk/client-textract": "^3.621.0", "@heyputer/kv.js": "^0.1.3", diff --git a/src/backend/package.json b/src/backend/package.json index 0fb81bb58a..c8a2d59dfe 100644 --- a/src/backend/package.json +++ b/src/backend/package.json @@ -7,6 +7,7 @@ "test": "npx mocha" }, "dependencies": { + "@anthropic-ai/sdk": "^0.26.1", "@aws-sdk/client-polly": "^3.622.0", "@aws-sdk/client-textract": "^3.621.0", "@heyputer/kv.js": "^0.1.3", diff --git a/src/backend/src/modules/puterai/ClaudeService.js b/src/backend/src/modules/puterai/ClaudeService.js new file mode 100644 index 0000000000..3dcba322f8 --- /dev/null +++ b/src/backend/src/modules/puterai/ClaudeService.js @@ -0,0 +1,109 @@ +const { default: Anthropic } = require("@anthropic-ai/sdk"); +const BaseService = require("../../services/BaseService"); +const { whatis } = require("../../util/langutil"); +const { PassThrough } = require("stream"); +const { TypedValue } = require("../../services/drivers/meta/Runtime"); + +const PUTER_PROMPT = ` + You are running on an open-source platform called Puter, + as the Claude implementation for a driver interface + called puter-chat-completion. + + The following JSON contains system messages from the + user of the driver interface (typically an app on Puter): +`.replace('\n', ' ').trim(); + +class ClaudeService extends BaseService { + static MODULES = { + Anthropic: require('@anthropic-ai/sdk'), + } + + async _init () { + this.anthropic = new Anthropic({ + apiKey: this.config.apiKey + }); + } + + static IMPLEMENTS = { + ['puter-chat-completion']: { + async complete ({ messages, stream }) { + const adapted_messages = []; + + const system_prompts = []; + let previous_was_user = false; + for ( const message of messages ) { + if ( typeof message.content === 'string' ) { + message.content = { + type: 'text', + text: message.content, + }; + } + if ( whatis(message.content) !== 'array' ) { + message.content = [message.content]; + } + if ( message.role === 'user' && previous_was_user ) { + const last_msg = adapted_messages[adapted_messages.length-1]; + last_msg.content.push( + ...(Array.isArray ? message.content : [message.content]) + ); + continue; + } + if ( message.role === 'system' ) { + system_prompts.push(...message.content); + continue; + } + adapted_messages.push(message); + if ( message.role === 'user' ) { + previous_was_user = true; + } + } + + if ( stream ) { + const stream = new PassThrough(); + const retval = new TypedValue({ + $: 'stream', + content_type: 'application/x-ndjson', + chunked: true, + }, stream); + (async () => { + const completion = await this.anthropic.messages.stream({ + model: 'claude-3-5-sonnet-20240620', + max_tokens: 1000, + temperature: 0, + system: PUTER_PROMPT + JSON.stringify(system_prompts), + messages: adapted_messages, + }); + for await ( const event of completion ) { + if ( + event.type !== 'content_block_delta' || + event.delta.type !== 'text_delta' + ) continue; + const str = JSON.stringify({ + text: event.delta.text, + }); + stream.write(str + '\n'); + } + })(); + + return retval; + } + + const msg = await this.anthropic.messages.create({ + model: 'claude-3-5-sonnet-20240620', + max_tokens: 1000, + temperature: 0, + system: PUTER_PROMPT + JSON.stringify(system_prompts), + messages: adapted_messages, + }); + return { + message: msg, + finish_reason: 'stop' + }; + } + } + } +} + +module.exports = { + ClaudeService, +}; diff --git a/src/backend/src/modules/puterai/PuterAIModule.js b/src/backend/src/modules/puterai/PuterAIModule.js index f1ccde4263..977afec232 100644 --- a/src/backend/src/modules/puterai/PuterAIModule.js +++ b/src/backend/src/modules/puterai/PuterAIModule.js @@ -28,6 +28,11 @@ class PuterAIModule extends AdvancedBase { const { OpenAIImageGenerationService } = require('./OpenAIImageGenerationService'); services.registerService('openai-image-generation', OpenAIImageGenerationService); } + + if ( !! config?.services?.claude ) { + const { ClaudeService } = require('./ClaudeService'); + services.registerService('claude', ClaudeService); + } } } From 32f0edb93a8fb0c33b0614b99c7fc439c8f6afc9 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 21 Aug 2024 15:31:24 -0400 Subject: [PATCH 0733/2119] feat(api): add /lsmod --- src/backend/src/CoreModule.js | 3 + src/backend/src/Kernel.js | 1 + src/backend/src/data/hardcoded-permissions.js | 1 + src/backend/src/services/Container.js | 32 +++++ src/backend/src/services/KernelInfoService.js | 117 ++++++++++++++++++ src/backend/src/services/RegistryService.js | 3 +- .../src/services/auth/PermissionService.js | 8 ++ 7 files changed, 164 insertions(+), 1 deletion(-) create mode 100644 src/backend/src/services/KernelInfoService.js diff --git a/src/backend/src/CoreModule.js b/src/backend/src/CoreModule.js index f78452430e..13558f2caa 100644 --- a/src/backend/src/CoreModule.js +++ b/src/backend/src/CoreModule.js @@ -317,6 +317,9 @@ const install = async ({ services, app, useapi }) => { const { FeatureFlagService } = require('./services/FeatureFlagService'); services.registerService('feature-flag', FeatureFlagService); + + const { KernelInfoService } = require('./services/KernelInfoService'); + services.registerService('kernel-info', KernelInfoService); } const install_legacy = async ({ services }) => { diff --git a/src/backend/src/Kernel.js b/src/backend/src/Kernel.js index 60f0be7bcd..01062fdfa5 100644 --- a/src/backend/src/Kernel.js +++ b/src/backend/src/Kernel.js @@ -136,6 +136,7 @@ class Kernel extends AdvancedBase { // Internal modules for ( const module of this.modules ) { + services.registerModule(module.constructor.name, module); await module.install(Context.get()); } diff --git a/src/backend/src/data/hardcoded-permissions.js b/src/backend/src/data/hardcoded-permissions.js index 65cce827c1..abaa2940b4 100644 --- a/src/backend/src/data/hardcoded-permissions.js +++ b/src/backend/src/data/hardcoded-permissions.js @@ -78,6 +78,7 @@ const hardcoded_user_group_permissions = { 'driver': {}, 'service': {}, 'feature': {}, + 'kernel-info': {}, }, 'b7220104-7905-4985-b996-649fdcdb3c8f': { 'service:hello-world:ii:hello-world': policy_perm('temp.es'), diff --git a/src/backend/src/services/Container.js b/src/backend/src/services/Container.js index d9ba8b1ecd..7241523267 100644 --- a/src/backend/src/services/Container.js +++ b/src/backend/src/services/Container.js @@ -29,7 +29,33 @@ class Container { this.instances_ = {}; this.implementors_ = {}; this.ready = new TeePromise(); + + this.modname_ = null; + this.modules_ = {} + } + + registerModule (name, module) { + this.modules_[name] = { + services_l: [], + services_m: {}, + module + }; + this.setModuleName(name); } + + /** + * Sets the name of the current module registering services. + * + * Note: this is an antipattern; it would be a bit better to + * provide the module name while registering a service, but + * this requires making an implementor of Container's interface + * with this as a hidden variable so as not to break existing + * modules. + */ + setModuleName (name) { + this.modname_ = name; + } + /** * registerService registers a service with the servuces container. * @@ -44,6 +70,12 @@ class Container { : new cls({ services: this, config, my_config, name, args }) ; this.instances_[name] = instance; + if ( this.modname_ ) { + const mod_entry = this.modules_[this.modname_]; + mod_entry.services_l.push(name); + mod_entry.services_m[name] = true; + } + if ( !(instance instanceof AdvancedBase) ) return; const traits = instance.list_traits(); diff --git a/src/backend/src/services/KernelInfoService.js b/src/backend/src/services/KernelInfoService.js new file mode 100644 index 0000000000..e8807f2177 --- /dev/null +++ b/src/backend/src/services/KernelInfoService.js @@ -0,0 +1,117 @@ +const configurable_auth = require("../middleware/configurable_auth"); +const { Context } = require("../util/context"); +const { Endpoint } = require("../util/expressutil"); +const BaseService = require("./BaseService"); +const { Interface } = require("./drivers/meta/Construct"); + +const PERM_SEE_ALL = 'kernel-info:see-all-services'; +const PERM_SEE_DRIVERS = 'kernel-info:see-all-drivers'; + +class KernelInfoService extends BaseService { + async _init () { + // + } + + ['__on_install.routes'] (_, { app }) { + const router = (() => { + const require = this.require; + const express = require('express'); + return express.Router(); + })(); + + app.use('/', router); + + Endpoint({ + route: '/lsmod', + methods: ['GET', 'POST'], + mw: [ + configurable_auth(), + ], + handler: async (req, res) => { + const svc_permission = this.services.get('permission'); + + const actor = Context.get('actor'); + const can_see_all = actor && + await svc_permission.check(actor, PERM_SEE_ALL); + const can_see_drivers = actor && + await svc_permission.check(actor, PERM_SEE_DRIVERS); + + const interfaces = {}; + const svc_registry = this.services.get('registry'); + const col_interfaces = svc_registry.get('interfaces'); + for ( const interface_name of col_interfaces.keys() ) { + const iface = col_interfaces.get(interface_name); + console.log('-->', interface_name, iface); + if ( iface === undefined ) continue; + if ( iface.no_sdk ) continue; + interfaces[interface_name] = { + spec: (new Interface( + iface, + { name: interface_name } + )).serialize(), + implementors: {} + } + } + + const services = []; + const modules = []; + for ( const k in this.services.modules_ ) { + const module_info = { + name: k, + services: [] + }; + + modules.push(module_info); + + for ( const s_k of this.services.modules_[k].services_l ) { + const service_info = { + name: s_k, + traits: [] + }; + services.push(service_info); + + const service = this.services.get(s_k); + if ( service.list_traits ) { + const traits = service.list_traits(); + for ( const trait of traits ) { + const corresponding_iface = interfaces[trait]; + if ( ! corresponding_iface ) continue; + corresponding_iface.implementors[s_k] = {}; + } + service_info.traits = service.list_traits(); + } + } + } + + // If actor doesn't have permission to see all drivers, + // (granted by either "can_see_all" or "can_see_drivers") + if ( ! can_see_all && ! can_see_drivers ) { + // only show interfaces with at least one implementation + // that the actor has permission to use + for ( const iface_name in interfaces ) { + for ( const impl_name in interfaces[iface_name].implementors ) { + const perm = `service:${impl_name}:ii:${iface_name}`; + const can_see_this = actor && + await svc_permission.check(actor, perm); + if ( ! can_see_this ) { + delete interfaces[iface_name].implementors[impl_name]; + } + } + if ( Object.keys(interfaces[iface_name].implementors).length < 1 ) { + delete interfaces[iface_name]; + } + } + } + + res.json({ + interfaces, + ...(can_see_all ? { services } : {}) + }); + } + }).attach(router); + } +} + +module.exports = { + KernelInfoService, +}; diff --git a/src/backend/src/services/RegistryService.js b/src/backend/src/services/RegistryService.js index 789e5ecb4b..6b93e4abb5 100644 --- a/src/backend/src/services/RegistryService.js +++ b/src/backend/src/services/RegistryService.js @@ -49,7 +49,8 @@ class MapCollection extends AdvancedBase { } keys () { - return this.kv.keys(`registry:map:${this.map_id}:*`); + const keys = this.kv.keys(`registry:map:${this.map_id}:*`); + return keys.map(k => k.slice(`registry:map:${this.map_id}:`.length)); } _mk_key (key) { diff --git a/src/backend/src/services/auth/PermissionService.js b/src/backend/src/services/auth/PermissionService.js index bb60258597..38e5b88c80 100644 --- a/src/backend/src/services/auth/PermissionService.js +++ b/src/backend/src/services/auth/PermissionService.js @@ -214,6 +214,14 @@ class PermissionService extends BaseService { } return permission; } + + async check (actor, permission_options) { + // TODO: optimized implementation for check instead of + // delegating to the scan() method + const reading = await this.scan(actor, permission_options); + const options = PermissionUtil.reading_to_options(reading); + return options.length > 0; + } async scan (actor, permission_options) { const reading = []; From 439f52b5a3f1a94e6d15ddacc315ae797f4709c2 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 21 Aug 2024 18:27:27 -0400 Subject: [PATCH 0734/2119] feat(puterjs): add drivers module --- src/puter-js/src/index.js | 48 +++++--- src/puter-js/src/modules/Drivers.js | 171 ++++++++++++++++++++++++++++ 2 files changed, 205 insertions(+), 14 deletions(-) create mode 100644 src/puter-js/src/modules/Drivers.js diff --git a/src/puter-js/src/index.js b/src/puter-js/src/index.js index 425fb06a02..757439b962 100644 --- a/src/puter-js/src/index.js +++ b/src/puter-js/src/index.js @@ -11,6 +11,7 @@ import FSItem from './modules/FSItem.js'; import * as utils from './lib/utils.js'; import path from './lib/path.js'; import Util from './modules/Util.js'; +import Drivers from './modules/Drivers.js'; window.puter = (function() { 'use strict'; @@ -58,6 +59,8 @@ window.puter = (function() { // -------------------------------------------- constructor(options) { options = options ?? {}; + + this.modules_ = []; // Holds the query parameters found in the current URL let URLParams = new URLSearchParams(window.location.search); @@ -181,6 +184,11 @@ window.puter = (function() { } } } + + registerModule (name, instance) { + this.modules_.push(name); + this[name] = instance; + } // Initialize submodules initSubmodules = function(){ @@ -188,34 +196,46 @@ window.puter = (function() { this.util = new Util(); // Auth - this.auth = new Auth(this.authToken, this.APIOrigin, this.appID, this.env); + this.registerModule('auth', + new Auth(this.authToken, this.APIOrigin, this.appID, this.env)); // OS - this.os = new OS(this.authToken, this.APIOrigin, this.appID, this.env); + this.registerModule('os', + new OS(this.authToken, this.APIOrigin, this.appID, this.env)); // FileSystem - this.fs = new FileSystem(this.authToken, this.APIOrigin, this.appID, this.env); + this.registerModule('fs', + new FileSystem(this.authToken, this.APIOrigin, this.appID, this.env)); // UI - this.ui = new UI(this.appInstanceID, this.parentInstanceID, this.appID, this.env, this.util); + this.registerModule('ui', + new UI(this.appInstanceID, this.parentInstanceID, this.appID, this.env, this.util)); // Hosting - this.hosting = new Hosting(this.authToken, this.APIOrigin, this.appID, this.env); + this.registerModule('hosting', + new Hosting(this.authToken, this.APIOrigin, this.appID, this.env)); // Email - this.email = new Email(this.authToken, this.APIOrigin, this.appID); + this.registerModule('email', + new Email(this.authToken, this.APIOrigin, this.appID)); // Apps - this.apps = new Apps(this.authToken, this.APIOrigin, this.appID, this.env); + this.registerModule('apps', + new Apps(this.authToken, this.APIOrigin, this.appID, this.env)); // AI - this.ai = new AI(this.authToken, this.APIOrigin, this.appID, this.env); + this.registerModule('ai', + new AI(this.authToken, this.APIOrigin, this.appID, this.env)); // Key-Value Store - this.kv = new KV(this.authToken, this.APIOrigin, this.appID, this.env); + this.registerModule('kv', + new KV(this.authToken, this.APIOrigin, this.appID, this.env)); + // Drivers + this.registerModule('drivers', + new Drivers(this.authToken, this.APIOrigin, this.appID, this.env)); // Path this.path = path; } updateSubmodules() { // Update submodules with new auth token and API origin - [this.os, this.fs, this.hosting, this.email, this.apps, this.ai, this.kv].forEach(module => { - if(!module) return; - module.setAuthToken(this.authToken); - module.setAPIOrigin(this.APIOrigin); - }); + for ( const name of this.modules_ ) { + if ( ! this[name] ) continue; + this[name]?.setAuthToken?.(this.authToken); + this[name]?.setAPIOrigin?.(this.APIOrigin); + } } setAppID = function (appID) { diff --git a/src/puter-js/src/modules/Drivers.js b/src/puter-js/src/modules/Drivers.js new file mode 100644 index 0000000000..cb29a0964e --- /dev/null +++ b/src/puter-js/src/modules/Drivers.js @@ -0,0 +1,171 @@ +class FetchDriverCallBackend { + constructor ({ context }) { + this.context = context; + this.response_handlers = this.constructor.response_handlers; + } + + static response_handlers = { + 'application/x-ndjson': async resp => { + const Stream = async function* Stream (readableStream) { + const reader = readableStream.getReader(); + let value, done; + while ( ! done ) { + ({ value, done } = await reader.read()); + if ( done ) break; + const parts = (new TextDecoder().decode(value).split('\n')); + for ( const part of parts ) { + if ( part.trim() === '' ) continue; + yield JSON.parse(part); + } + } + } + + return Stream(resp.body); + }, + 'application/json': async resp => { + return await resp.json(); + }, + 'application/octet-stream': async resp => { + return await resp.blob(); + }, + } + + async call ({ driver, method_name, parameters }) { + const resp = await fetch(`${this.context.APIOrigin}/drivers/call`, { + headers: { + Authorization: `Bearer ${this.context.authToken}`, + 'Content-Type': 'application/json', + }, + method: 'POST', + body: JSON.stringify({ + 'interface': driver.iface_name, + ...(driver.service_name + ? { service: driver.service_name } + : {}), + method: method_name, + args: parameters, + }), + }); + + const content_type = resp.headers.get('content-type') + .split(';')[0].trim(); // TODO: parser for Content-Type + const handler = this.response_handlers[content_type]; + if ( ! handler ) { + const msg = `unrecognized content type: ${content_type}`; + console.error(msg); + console.error('creating blob so dev tools shows response...'); + await resp.blob(); + throw new Error(msg); + } + + return await handler(resp); + } +} + +class Driver { + constructor ({ + iface, + iface_name, + service_name, + call_backend, + }) { + this.iface = iface; + this.iface_name = iface_name; + this.service_name = service_name; + this.call_backend = call_backend; + } + async call (method_name, parameters) { + return await this.call_backend.call({ + driver: this, + method_name, + parameters, + }); + } +} + +class Drivers { + /** + * Creates a new instance with the given authentication token, API origin, and app ID, + * + * @class + * @param {string} authToken - Token used to authenticate the user. + * @param {string} APIOrigin - Origin of the API server. Used to build the API endpoint URLs. + * @param {string} appID - ID of the app to use. + */ + constructor (authToken, APIOrigin, appID) { + this.authToken = authToken; + this.APIOrigin = APIOrigin; + this.appID = appID; + + // Driver-specific + this.drivers_ = {}; + + this.context = {}; + Object.defineProperty(this.context, 'authToken', { + get: () => this.authToken, + }); + Object.defineProperty(this.context, 'APIOrigin', { + get: () => this.APIOrigin, + }); + } + + /** + * Sets a new authentication token and resets the socket connection with the updated token, if applicable. + * + * @param {string} authToken - The new authentication token. + * @memberof [AI] + * @returns {void} + */ + setAuthToken (authToken) { + this.authToken = authToken; + } + + /** + * Sets the API origin. + * + * @param {string} APIOrigin - The new API origin. + * @memberof [AI] + * @returns {void} + */ + setAPIOrigin (APIOrigin) { + this.APIOrigin = APIOrigin; + } + + async list () { + const resp = await fetch(`${this.APIOrigin}/lsmod`, { + headers: { + Authorization: 'Bearer ' + this.authToken, + }, + method: 'POST' + }); + const list = await resp.json(); + return list.interfaces; + } + + async get (iface_name, service_name) { + const key = `${iface_name}:${service_name}`; + if ( this.drivers_[key] ) return this.drivers_[key]; + + const interfaces = await this.list(); + if ( ! interfaces[iface_name] ) { + throw new Error(`Interface ${iface_name} not found`); + } + + return this.drivers_[key] = new Driver ({ + call_backend: new FetchDriverCallBackend({ + context: this.context, + }), + iface: interfaces[iface_name], + iface_name, + service_name, + }); + } + + async call (iface_name, service_name, method_name, parameters) { + const driver = await this.get(iface_name, service_name); + return await driver.call(method_name, parameters); + } + +} + +export default Drivers; From 7b254e86766edad7c6ea40a3a2f21de67ecdfc3d Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 21 Aug 2024 23:15:53 -0400 Subject: [PATCH 0735/2119] tweak(puerai): add model parameter --- src/backend/src/modules/puterai/AIInterfaceService.js | 1 + src/backend/src/modules/puterai/ClaudeService.js | 4 ++-- src/backend/src/modules/puterai/OpenAICompletionService.js | 5 ++--- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/backend/src/modules/puterai/AIInterfaceService.js b/src/backend/src/modules/puterai/AIInterfaceService.js index 257291033d..1abdbaf189 100644 --- a/src/backend/src/modules/puterai/AIInterfaceService.js +++ b/src/backend/src/modules/puterai/AIInterfaceService.js @@ -34,6 +34,7 @@ class AIInterfaceService extends BaseService { messages: { type: 'json' }, vision: { type: 'flag' }, stream: { type: 'flag' }, + model: { type: 'string' }, }, result: { type: 'json' }, } diff --git a/src/backend/src/modules/puterai/ClaudeService.js b/src/backend/src/modules/puterai/ClaudeService.js index 3dcba322f8..a0382db9fc 100644 --- a/src/backend/src/modules/puterai/ClaudeService.js +++ b/src/backend/src/modules/puterai/ClaudeService.js @@ -26,7 +26,7 @@ class ClaudeService extends BaseService { static IMPLEMENTS = { ['puter-chat-completion']: { - async complete ({ messages, stream }) { + async complete ({ messages, stream, model }) { const adapted_messages = []; const system_prompts = []; @@ -67,7 +67,7 @@ class ClaudeService extends BaseService { }, stream); (async () => { const completion = await this.anthropic.messages.stream({ - model: 'claude-3-5-sonnet-20240620', + model: model ?? 'claude-3-5-sonnet-20240620', max_tokens: 1000, temperature: 0, system: PUTER_PROMPT + JSON.stringify(system_prompts), diff --git a/src/backend/src/modules/puterai/OpenAICompletionService.js b/src/backend/src/modules/puterai/OpenAICompletionService.js index f9a9af3a66..b280a10fdf 100644 --- a/src/backend/src/modules/puterai/OpenAICompletionService.js +++ b/src/backend/src/modules/puterai/OpenAICompletionService.js @@ -23,7 +23,7 @@ class OpenAICompletionService extends BaseService { static IMPLEMENTS = { ['puter-chat-completion']: { - async complete ({ messages, test_mode, stream }) { + async complete ({ messages, test_mode, stream, model }) { if ( test_mode ) { const { LoremIpsum } = require('lorem-ipsum'); const li = new LoremIpsum({ @@ -49,9 +49,8 @@ class OpenAICompletionService extends BaseService { } } - const model = 'gpt-4o'; return await this.complete(messages, { - model, + model: model ?? 'gpt-4o', moderation: true, stream, }); From bdfdf2331b37680b95ac56b31026d3bdab4c173b Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 21 Aug 2024 23:17:02 -0400 Subject: [PATCH 0736/2119] feat(puterai): add togetherai --- package-lock.json | 26 +++++++ src/backend/package.json | 1 + .../src/modules/puterai/PuterAIModule.js | 5 ++ .../src/modules/puterai/TogetherAIService.js | 67 +++++++++++++++++++ 4 files changed, 99 insertions(+) create mode 100644 src/backend/src/modules/puterai/TogetherAIService.js diff --git a/package-lock.json b/package-lock.json index f15dee877b..97b1540cbd 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15389,6 +15389,31 @@ "node": ">=8.0" } }, + "node_modules/together-ai": { + "version": "0.6.0-alpha.4", + "resolved": "https://registry.npmjs.org/together-ai/-/together-ai-0.6.0-alpha.4.tgz", + "integrity": "sha512-aeMAMkDJn6Pzdr93cDc9dQksshGMBr+6v1096NI82iAnozuT/11ngrW4h9iiQWChh/CoiD0vWDASendG/v84CQ==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7", + "web-streams-polyfill": "^3.2.1" + } + }, + "node_modules/together-ai/node_modules/@types/node": { + "version": "18.19.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.45.tgz", + "integrity": "sha512-VZxPKNNhjKmaC1SUYowuXSRSMGyQGmQjvvA1xE4QZ0xce2kLtEhPDS+kqpCPBZYgqblCLQ2DAjSzmgCM5auvhA==", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, "node_modules/toidentifier": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", @@ -16650,6 +16675,7 @@ "string-length": "^6.0.0", "svgo": "^3.0.2", "tiktoken": "^1.0.15", + "together-ai": "^0.6.0-alpha.4", "tweetnacl": "^1.0.3", "ua-parser-js": "^1.0.38", "uglify-js": "^3.17.4", diff --git a/src/backend/package.json b/src/backend/package.json index c8a2d59dfe..5d09800edc 100644 --- a/src/backend/package.json +++ b/src/backend/package.json @@ -69,6 +69,7 @@ "string-length": "^6.0.0", "svgo": "^3.0.2", "tiktoken": "^1.0.15", + "together-ai": "^0.6.0-alpha.4", "tweetnacl": "^1.0.3", "ua-parser-js": "^1.0.38", "uglify-js": "^3.17.4", diff --git a/src/backend/src/modules/puterai/PuterAIModule.js b/src/backend/src/modules/puterai/PuterAIModule.js index 977afec232..fdb67a4179 100644 --- a/src/backend/src/modules/puterai/PuterAIModule.js +++ b/src/backend/src/modules/puterai/PuterAIModule.js @@ -33,6 +33,11 @@ class PuterAIModule extends AdvancedBase { const { ClaudeService } = require('./ClaudeService'); services.registerService('claude', ClaudeService); } + + if ( !! config?.services?.['together-ai'] ) { + const { TogetherAIService } = require('./TogetherAIService'); + services.registerService('together-ai', TogetherAIService); + } } } diff --git a/src/backend/src/modules/puterai/TogetherAIService.js b/src/backend/src/modules/puterai/TogetherAIService.js new file mode 100644 index 0000000000..851987ac5f --- /dev/null +++ b/src/backend/src/modules/puterai/TogetherAIService.js @@ -0,0 +1,67 @@ +const { PassThrough } = require("stream"); +const BaseService = require("../../services/BaseService"); +const { TypedValue } = require("../../services/drivers/meta/Runtime"); +const { nou } = require("../../util/langutil"); + +class TogetherAIService extends BaseService { + static MODULES = { + ['together-ai']: require('together-ai'), + kv: globalThis.kv, + uuidv4: require('uuid').v4, + } + + async _init () { + const require = this.require; + const Together = require('together-ai'); + this.together = new Together({ + apiKey: this.config.apiKey + }); + this.kvkey = this.modules.uuidv4(); + debugger; + } + + static IMPLEMENTS = { + ['puter-chat-completion']: { + async complete ({ messages, stream, model }) { + console.log('model?', model); + const completion = await this.together.chat.completions.create({ + model: model ?? + 'meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo', + messages: messages, + stream, + }); + + if ( stream ) { + const stream = new PassThrough(); + const retval = new TypedValue({ + $: 'stream', + content_type: 'application/x-ndjson', + chunked: true, + }, stream); + (async () => { + for await ( const chunk of completion ) { + console.log('IT IS THIS STRING', chunk); + if ( chunk.choices.length < 1 ) continue; + if ( chunk.choices[0].finish_reason ) { + stream.end(); + break; + } + if ( nou(chunk.choices[0].delta.content) ) continue; + const str = JSON.stringify({ + text: chunk.choices[0].delta.content + }); + stream.write(str + '\n'); + } + })(); + return retval; + } + + return completion.choices[0]; + } + } + } +} + +module.exports = { + TogetherAIService, +}; From 21539a1651bc868bcfcf17efa6a4bb8fb6ad52da Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 21 Aug 2024 23:18:12 -0400 Subject: [PATCH 0737/2119] tweak: let driver be called service --- src/backend/src/routers/drivers/call.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/src/routers/drivers/call.js b/src/backend/src/routers/drivers/call.js index 3236b1b881..9e472d7a25 100644 --- a/src/backend/src/routers/drivers/call.js +++ b/src/backend/src/routers/drivers/call.js @@ -73,7 +73,7 @@ module.exports = eggspress('/drivers/call', { const result = await context.arun(async () => { return await svc_driver.call({ iface: interface_name, - driver: body.driver, + driver: body.driver ?? body.service, method: body.method, format: body.format, args: body.args, From 43c18377eb79b2160641861b2bfddf6d427ee7d8 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 21 Aug 2024 20:19:26 -0700 Subject: [PATCH 0738/2119] Add support for multiple AI drivers via puter.js --- src/puter-js/src/lib/utils.js | 11 +++++--- src/puter-js/src/modules/AI.js | 39 ++++++++++++++++++++++++++--- src/puter-js/src/modules/Apps.js | 10 ++++---- src/puter-js/src/modules/Hosting.js | 10 ++++---- src/puter-js/src/modules/KV.js | 14 +++++------ 5 files changed, 59 insertions(+), 25 deletions(-) diff --git a/src/puter-js/src/lib/utils.js b/src/puter-js/src/lib/utils.js index a84ac432f1..8195da8f04 100644 --- a/src/puter-js/src/lib/utils.js +++ b/src/puter-js/src/lib/utils.js @@ -181,9 +181,10 @@ class Valid { * Makes the hybrid promise/callback function for a particular driver method * @param {string[]} arg_defs - argument names (for now; definitions eventually) * @param {string} driverInterface - name of the interface + * @param {string} driverName - name of the driver * @param {string} driverMethod - name of the method */ -function make_driver_method(arg_defs, driverInterface, driverMethod, settings = {}) { +function make_driver_method(arg_defs, driverInterface, driverName, driverMethod, settings = {}) { return async function (...args) { let driverArgs = {}; let options = {}; @@ -214,11 +215,11 @@ function make_driver_method(arg_defs, driverInterface, driverMethod, settings = driverArgs = settings.preprocess(driverArgs); } - return await driverCall(options, driverInterface, driverMethod, driverArgs, settings); + return await driverCall(options, driverInterface, driverName, driverMethod, driverArgs, settings); }; } -async function driverCall (options, driverInterface, driverMethod, driverArgs, settings) { +async function driverCall (options, driverInterface, driverName, driverMethod, driverArgs, settings) { const tp = new TeePromise(); driverCall_( @@ -226,6 +227,7 @@ async function driverCall (options, driverInterface, driverMethod, driverArgs, s tp.resolve.bind(tp), tp.reject.bind(tp), driverInterface, + driverName, driverMethod, driverArgs, undefined, @@ -240,7 +242,7 @@ async function driverCall (options, driverInterface, driverMethod, driverArgs, s async function driverCall_( options = {}, resolve_func, reject_func, - driverInterface, driverMethod, driverArgs, + driverInterface, driverName, driverMethod, driverArgs, method, contentType = 'application/json;charset=UTF-8', settings = {}, @@ -342,6 +344,7 @@ async function driverCall_( // send request xhr.send(JSON.stringify({ interface: driverInterface, + driver: driverName, test_mode: settings?.test_mode, method: driverMethod, args: driverArgs, diff --git a/src/puter-js/src/modules/AI.js b/src/puter-js/src/modules/AI.js index edf9abb4a3..5a37c410f9 100644 --- a/src/puter-js/src/modules/AI.js +++ b/src/puter-js/src/modules/AI.js @@ -69,7 +69,7 @@ class AI{ testMode = true; } - return await utils.make_driver_method(['source'], 'puter-ocr', 'recognize', { + return await utils.make_driver_method(['source'], 'puter-ocr', 'aws-textract', 'recognize', { test_mode: testMode ?? false, transform: async (result) => { let str = ''; @@ -113,7 +113,7 @@ class AI{ testMode = true; } - return await utils.make_driver_method(['source'], 'puter-tts', 'synthesize', { + return await utils.make_driver_method(['source'], 'puter-tts', 'aws-polly', 'synthesize', { responseType: 'blob', test_mode: testMode ?? false, transform: async (result) => { @@ -132,8 +132,12 @@ class AI{ // if object, it's treated as the full argument object that the API expects chat = async (...args) => { let options = {}; + let settings = {}; let testMode = false; + // default driver is openai-completion + let driver = 'openai-completion'; + // Check that the argument is not undefined or null if(!args){ throw({message: 'Arguments are required', code: 'arguments_required'}); @@ -199,8 +203,35 @@ class AI{ testMode = true; } + // if any of the args is an object, assume it's the settings object + for (let i = 0; i < args.length; i++) { + if (typeof args[i] === 'object') { + settings = args[i]; + break; + } + } + + // does settings contain `model`? add it to options + if (settings.model) { + options.model = settings.model; + } + + // convert to the correct model name if necessary + if( options.model === 'claude-3-5-sonnet' || options.model === 'claude'){ + options.model = 'claude-3-5-sonnet-20240620'; + } + + // map model to the appropriate driver + if (!options.model || options.model === 'gpt-4o' || options.model === 'gpt-4o-mini') { + driver = 'openai-completion'; + }else if(options.model === 'claude-3-haiku-20240307' || options.model === 'claude-3-5-sonnet-20240620'){ + driver = 'claude'; + }else if(options.model === 'meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo' || options.model === 'meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo' || options.model === 'meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo' || options.model === `google/gemma-2-27b-it`){ + driver = 'together-ai'; + } + // Call the original chat.complete method - return await utils.make_driver_method(['messages'], 'puter-chat-completion', 'complete', { + return await utils.make_driver_method(['messages'], 'puter-chat-completion', driver, 'complete', { test_mode: testMode ?? false, transform: async (result) => { result.toString = () => { @@ -235,7 +266,7 @@ class AI{ } // Call the original chat.complete method - return await utils.make_driver_method(['prompt'], 'puter-image-generation', 'generate', { + return await utils.make_driver_method(['prompt'], 'puter-image-generation', undefined, 'generate', { responseType: 'blob', test_mode: testMode ?? false, transform: async blob => { diff --git a/src/puter-js/src/modules/Apps.js b/src/puter-js/src/modules/Apps.js index 4307e29b53..4479aa2a14 100644 --- a/src/puter-js/src/modules/Apps.js +++ b/src/puter-js/src/modules/Apps.js @@ -42,7 +42,7 @@ class Apps{ options = { "predicate": ['user-can-edit'] }; - return utils.make_driver_method(['uid'], 'puter-apps', 'select').call(this, options); + return utils.make_driver_method(['uid'], 'puter-apps', undefined, 'select').call(this, options); } create = async (...args) => { @@ -70,7 +70,7 @@ class Apps{ }; } // Call the original chat.complete method - return await utils.make_driver_method(['object'], 'puter-apps', 'create').call(this, options); + return await utils.make_driver_method(['object'], 'puter-apps', undefined, 'create').call(this, options); } update = async(...args) => { @@ -96,7 +96,7 @@ class Apps{ } // Call the original chat.complete method - return await utils.make_driver_method(['object'], 'puter-apps', 'update').call(this, options); + return await utils.make_driver_method(['object'], 'puter-apps', undefined, 'update').call(this, options); } get = async(...args) => { @@ -106,7 +106,7 @@ class Apps{ if (Array.isArray(args) && typeof args[0] === 'string') { options = { id: {name: args[0]}}; } - return utils.make_driver_method(['uid'], 'puter-apps', 'read').call(this, options); + return utils.make_driver_method(['uid'], 'puter-apps', undefined, 'read').call(this, options); } delete = async(...args) => { @@ -116,7 +116,7 @@ class Apps{ if (Array.isArray(args) && typeof args[0] === 'string') { options = { id: {name: args[0]}}; } - return utils.make_driver_method(['uid'], 'puter-apps', 'delete').call(this, options); + return utils.make_driver_method(['uid'], 'puter-apps', undefined, 'delete').call(this, options); } getDeveloperProfile = function(...args){ diff --git a/src/puter-js/src/modules/Hosting.js b/src/puter-js/src/modules/Hosting.js index fa2234164d..349257e2f8 100644 --- a/src/puter-js/src/modules/Hosting.js +++ b/src/puter-js/src/modules/Hosting.js @@ -39,7 +39,7 @@ class Hosting{ } // todo document the `Subdomain` object. - list = utils.make_driver_method([], 'puter-subdomains', 'select'); + list = utils.make_driver_method([], 'puter-subdomains', undefined, 'select'); create = async (...args) => { let options = {}; @@ -74,7 +74,7 @@ class Hosting{ options = { object: args[0] }; } // Call the original chat.complete method - return await utils.make_driver_method(['object'], 'puter-subdomains', 'create').call(this, options); + return await utils.make_driver_method(['object'], 'puter-subdomains', undefined, 'create').call(this, options); } update = async(...args) => { @@ -97,7 +97,7 @@ class Hosting{ } // Call the original chat.complete method - return await utils.make_driver_method(['object'], 'puter-subdomains', 'update').call(this, options); + return await utils.make_driver_method(['object'], 'puter-subdomains', undefined, 'update').call(this, options); } get = async(...args) => { @@ -113,7 +113,7 @@ class Hosting{ options = { id: {subdomain: args[0]}}; } - return utils.make_driver_method(['uid'], 'puter-subdomains', 'read').call(this, options); + return utils.make_driver_method(['uid'], 'puter-subdomains', undefined, 'read').call(this, options); } delete = async(...args) => { @@ -129,7 +129,7 @@ class Hosting{ options = { id: {subdomain: args[0]}}; } - return utils.make_driver_method(['uid'], 'puter-subdomains', 'delete').call(this, options); + return utils.make_driver_method(['uid'], 'puter-subdomains', undefined, 'delete').call(this, options); } } diff --git a/src/puter-js/src/modules/KV.js b/src/puter-js/src/modules/KV.js index c040560658..5fe958757d 100644 --- a/src/puter-js/src/modules/KV.js +++ b/src/puter-js/src/modules/KV.js @@ -47,7 +47,7 @@ class KV{ * `key` size cannot be larger than 1mb. * `value` size cannot be larger than 10mb. */ - set = utils.make_driver_method(['key', 'value'], 'puter-kvstore', 'set',{ + set = utils.make_driver_method(['key', 'value'], 'puter-kvstore', undefined, 'set',{ preprocess: (args)=>{ // key cannot be undefined or null if(args.key === undefined || args.key === null){ @@ -68,7 +68,7 @@ class KV{ /** * Resolves to the value if the key exists, or `undefined` if the key does not exist. Rejects with an error on failure. */ - get = utils.make_driver_method(['key'], 'puter-kvstore', 'get', { + get = utils.make_driver_method(['key'], 'puter-kvstore', undefined, 'get', { preprocess: (args)=>{ // key size cannot be larger than MAX_KEY_SIZE if(args.key.length > this.MAX_KEY_SIZE){ @@ -98,7 +98,7 @@ class KV{ throw ({message: 'Key size cannot be larger than ' + this.MAX_KEY_SIZE, code: 'key_too_large'}); } - return utils.make_driver_method(['key'], 'puter-kvstore', 'incr').call(this, options); + return utils.make_driver_method(['key'], 'puter-kvstore', undefined, 'incr').call(this, options); } decr = async(...args) => { @@ -117,12 +117,12 @@ class KV{ throw ({message: 'Key size cannot be larger than ' + this.MAX_KEY_SIZE, code: 'key_too_large'}); } - return utils.make_driver_method(['key'], 'puter-kvstore', 'decr').call(this, options); + return utils.make_driver_method(['key'], 'puter-kvstore', undefined, 'decr').call(this, options); } // resolves to 'true' on success, or rejects with an error on failure // will still resolve to 'true' if the key does not exist - del = utils.make_driver_method(['key'], 'puter-kvstore', 'del', { + del = utils.make_driver_method(['key'], 'puter-kvstore', undefined, 'del', { preprocess: (args)=>{ // key size cannot be larger than this.MAX_KEY_SIZE if(args.key.length > this.MAX_KEY_SIZE){ @@ -154,7 +154,7 @@ class KV{ pattern = args[0]; } - return utils.make_driver_method([], 'puter-kvstore', 'list', { + return utils.make_driver_method([], 'puter-kvstore', undefined, 'list', { transform: (res)=>{ // glob pattern was provided if(pattern){ @@ -179,7 +179,7 @@ class KV{ // resolve to 'true' on success, or rejects with an error on failure // will still resolve to 'true' if there are no keys - flush = utils.make_driver_method([], 'puter-kvstore', 'flush') + flush = utils.make_driver_method([], 'puter-kvstore', undefined, 'flush') // clear is an alias for flush clear = this.flush; From 3bface8c6624d0ee374f897963e10b2bde7efff7 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 21 Aug 2024 20:38:03 -0700 Subject: [PATCH 0739/2119] if first args in `puter.chat` is a string, it's the prompt --- src/puter-js/src/modules/AI.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/puter-js/src/modules/AI.js b/src/puter-js/src/modules/AI.js index 5a37c410f9..928e76e0ec 100644 --- a/src/puter-js/src/modules/AI.js +++ b/src/puter-js/src/modules/AI.js @@ -144,10 +144,15 @@ class AI{ } // ai.chat(prompt) + if(typeof args[0] === 'string'){ + options = { messages: [{ content: args[0] }] }; + } + // ai.chat(prompt, testMode) if (typeof args[0] === 'string' && (!args[1] || typeof args[1] === 'boolean')) { options = { messages: [{ content: args[0] }] }; } + // ai.chat(prompt, imageURL/File) // ai.chat(prompt, imageURL/File, testMode) else if (typeof args[0] === 'string' && (typeof args[1] === 'string' || args[1] instanceof File)) { @@ -211,6 +216,7 @@ class AI{ } } + // does settings contain `model`? add it to options if (settings.model) { options.model = settings.model; From c08b897d4a6a77c54a7e8d2e705e2048ab4797ba Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 21 Aug 2024 23:50:09 -0400 Subject: [PATCH 0740/2119] fix(puterai): adapt message role for claude --- src/backend/src/modules/puterai/ClaudeService.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/backend/src/modules/puterai/ClaudeService.js b/src/backend/src/modules/puterai/ClaudeService.js index a0382db9fc..473ecd833f 100644 --- a/src/backend/src/modules/puterai/ClaudeService.js +++ b/src/backend/src/modules/puterai/ClaudeService.js @@ -41,6 +41,7 @@ class ClaudeService extends BaseService { if ( whatis(message.content) !== 'array' ) { message.content = [message.content]; } + if ( ! message.role ) message.role = 'user'; if ( message.role === 'user' && previous_was_user ) { const last_msg = adapted_messages[adapted_messages.length-1]; last_msg.content.push( From 6135054b3bbbded483838f1f575adf374c432664 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 21 Aug 2024 20:59:42 -0700 Subject: [PATCH 0741/2119] add stream flag to the `chat()` method of `puter.ai` --- src/puter-js/src/modules/AI.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/puter-js/src/modules/AI.js b/src/puter-js/src/modules/AI.js index 928e76e0ec..36bf4756cb 100644 --- a/src/puter-js/src/modules/AI.js +++ b/src/puter-js/src/modules/AI.js @@ -236,6 +236,11 @@ class AI{ driver = 'together-ai'; } + // stream flag from settings + if(settings.stream !== undefined && typeof settings.stream === 'boolean'){ + options.stream = settings.stream; + } + // Call the original chat.complete method return await utils.make_driver_method(['messages'], 'puter-chat-completion', driver, 'complete', { test_mode: testMode ?? false, From 4415e76a0ba35e59a83178b8f3869a3ca3cc007d Mon Sep 17 00:00:00 2001 From: Priyanshu1035 Date: Thu, 22 Aug 2024 19:29:10 +0530 Subject: [PATCH 0742/2119] readmeinbengali --- doc/i18n/README.bn.md | 128 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 doc/i18n/README.bn.md diff --git a/doc/i18n/README.bn.md b/doc/i18n/README.bn.md new file mode 100644 index 0000000000..8f21003ea8 --- /dev/null +++ b/doc/i18n/README.bn.md @@ -0,0 +1,128 @@ +

Puter.com, ব্যক্তিগত ক্লাউড কম্পিউটার: আপনার সমস্ত ফাইল, অ্যাপস, এবং গেম এক জায়গায়, যেকোনো সময়, যেকোনো স্থান থেকে অ্যাক্সেসযোগ্য।

+ +

ইন্টারনেট ওএস! ফ্রি, ওপেন-সোর্স, এবং সেল্ফ-হোস্টেবল।

+ +

+ GitHub রেপোর আকার GitHub রিলিজ GitHub লাইসেন্স +

+ +

+ « লাইভ ডেমো » +
+
+ Puter.com + · + এসডিকে + · + ডিসকর্ড + · + ইউটিউব + · + রেডিট + · + X (টুইটার) + · + বাগ বাউন্টি +

+ +

স্ক্রিনশট

+ +
+ +## Puter + +Puter একটি উন্নত, ওপেন-সোর্স ইন্টারনেট অপারেটিং সিস্টেম যা বৈশিষ্ট্যপূর্ণ, অত্যন্ত দ্রুত এবং উচ্চ মাত্রায় সম্প্রসারণযোগ্য। Puter ব্যবহার করা যেতে পারে: + +- একটি প্রাইভেসি-প্রথম পার্সোনাল ক্লাউড হিসাবে যা আপনার সমস্ত ফাইল, অ্যাপস এবং গেমসকে এক জায়গায় নিরাপদে রাখে, যেকোনো সময় যেকোনো স্থান থেকে অ্যাক্সেসযোগ্য। +- ওয়েবসাইট, ওয়েব অ্যাপ এবং গেম তৈরি ও প্রকাশ করার একটি প্ল্যাটফর্ম হিসাবে। +- ড্রপবক্স, গুগল ড্রাইভ, ওয়ানড্রাইভ ইত্যাদির বিকল্প হিসাবে একটি নতুন ইন্টারফেস এবং শক্তিশালী বৈশিষ্ট্য সহ। +- সার্ভার এবং ওয়ার্কস্টেশনের জন্য একটি রিমোট ডেস্কটপ এনভায়রনমেন্ট হিসাবে। +- ওয়েব ডেভেলপমেন্ট, ক্লাউড কম্পিউটিং, ডিস্ট্রিবিউটেড সিস্টেম এবং আরও অনেক কিছু শিখতে একটি বন্ধুত্বপূর্ণ, ওপেন-সোর্স প্রকল্প এবং কমিউনিটি হিসাবে! + +
+ +## শুরু করার জন্য + +## 💻 লোকাল ডেভেলপমেন্ট + +```bash +Copy code +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` +এটি Puter কে http://puter.localhost:4100 (অথবা পরবর্তী উপলব্ধ পোর্টে) চালু করবে। + +
+ +## 🐳 ডকার + +```bash +Copy code +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` +
+ +## 🐙 ডকার কম্পোজ + +## লিনাক্স/ম্যাকওএস + +```bash +Copy code +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` +
+ +## উইন্ডোজ + +```powershell +Copy code +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +## ☁️ Puter.com +Puter [**puter.com**](https://puter.com) এ হোস্টেড সার্ভিস হিসেবে উপলব্ধ। + +
+ +## সিস্টেম রিকোয়ারমেন্টস + +- **অপারেটিং সিস্টেম:** লিনাক্স, ম্যাকওএস, উইন্ডোজ +- **র‍্যাম:** ২জিবি ন্যূনতম (৪জিবি প্রস্তাবিত) +- **ডিস্ক স্পেস:** ১জিবি ফ্রি স্পেস +- **Node.js:** সংস্করণ ১৬+ (সংস্করণ ২২+ প্রস্তাবিত) +- **npm:** সর্বশেষ স্থিতিশীল সংস্করণ + +
+ +## সাপোর্ট + +মেইনটেইনার এবং কমিউনিটির সাথে এই চ্যানেলগুলির মাধ্যমে সংযোগ করুন: + +- বাগ রিপোর্ট বা ফিচার রিকোয়েস্ট? অনুগ্রহ করে একটি ইস্যু খুলুন। +- ডিসকর্ড: discord.com/invite/PQcx7Teh8u +- X (টুইটার): x.com/HeyPuter +- রেডিট: reddit.com/r/puter/ +- মাস্টডন: mastodon.social/@puter +- সিকিউরিটি ইস্যু? security@puter.com +- মেইনটেইনারদের ইমেইল করুন hi@puter.com এ + +আপনার যেকোনো প্রশ্নের জন্য আমরা সবসময় সাহায্য করতে প্রস্তুত। জিজ্ঞাসা করতে দ্বিধা করবেন না! + +
+ +## লাইসেন্স + +এই রিপোজিটরি, এর সমস্ত বিষয়বস্তু, সাব-প্রকল্প, মডিউল, এবং কম্পোনেন্ট সহ [AGPL-3.0] (https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) লাইসেন্সের অধীনে লাইসেন্সকৃত, যদি অন্যথায় স্পষ্টভাবে উল্লেখ না করা হয়। এই রিপোজিটরিতে অন্তর্ভুক্ত তৃতীয় পক্ষের লাইব্রেরিগুলি তাদের নিজস্ব লাইসেন্সের অধীনে হতে পারে। + +
\ No newline at end of file From 07ca9ff6eadb256644deea5281d058a903adf451 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 22 Aug 2024 08:15:27 -0700 Subject: [PATCH 0743/2119] Fix license link --- doc/i18n/README.bn.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/i18n/README.bn.md b/doc/i18n/README.bn.md index 8f21003ea8..3d774a4d5a 100644 --- a/doc/i18n/README.bn.md +++ b/doc/i18n/README.bn.md @@ -123,6 +123,6 @@ Puter [**puter.com**](https://puter.com) এ হোস্টেড সার্ ## লাইসেন্স -এই রিপোজিটরি, এর সমস্ত বিষয়বস্তু, সাব-প্রকল্প, মডিউল, এবং কম্পোনেন্ট সহ [AGPL-3.0] (https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) লাইসেন্সের অধীনে লাইসেন্সকৃত, যদি অন্যথায় স্পষ্টভাবে উল্লেখ না করা হয়। এই রিপোজিটরিতে অন্তর্ভুক্ত তৃতীয় পক্ষের লাইব্রেরিগুলি তাদের নিজস্ব লাইসেন্সের অধীনে হতে পারে। +এই রিপোজিটরি, এর সমস্ত বিষয়বস্তু, সাব-প্রকল্প, মডিউল, এবং কম্পোনেন্ট সহ [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) লাইসেন্সের অধীনে লাইসেন্সকৃত, যদি অন্যথায় স্পষ্টভাবে উল্লেখ না করা হয়। এই রিপোজিটরিতে অন্তর্ভুক্ত তৃতীয় পক্ষের লাইব্রেরিগুলি তাদের নিজস্ব লাইসেন্সের অধীনে হতে পারে। -
\ No newline at end of file +
From fa96c6d1462492aaef6b92605e4f232e9d677231 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 22 Aug 2024 08:22:18 -0700 Subject: [PATCH 0744/2119] Add link to Bengali README to English README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 78081ec63a..a36e64f290 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,7 @@ This repository, including all its contents, sub-projects, modules, and componen ## Translations +- [Bengali / বাংলা](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.bn.md) - [Chinese / 中文](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.zh.md) - [Danish / Dansk](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.da.md) - [English](https://github.com/HeyPuter/puter/blob/main/README.md) From bdd24c69a50b0f7b0ceb2a8d24e76fd7f218c0fa Mon Sep 17 00:00:00 2001 From: Niroyan Kugaruban Date: Thu, 22 Aug 2024 13:44:12 -0400 Subject: [PATCH 0745/2119] Add Tamil readme file --- doc/i18n/README.ta.md | 127 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 127 insertions(+) create mode 100644 doc/i18n/README.ta.md diff --git a/doc/i18n/README.ta.md b/doc/i18n/README.ta.md new file mode 100644 index 0000000000..16ac70493e --- /dev/null +++ b/doc/i18n/README.ta.md @@ -0,0 +1,127 @@ +

Puter.com, The Personal Cloud Computer: உங்கள் கோப்புகள், ஆப்ஸ் மற்றும் கேம்கள் அனைத்தும் ஒரே இடத்தில் எங்கிருந்தும் எந்த நேரத்திலும் அணுகலாம்.

+ +

இன்டர்நெட் OS! இலவசம், ஓப்பன் சோர்ஸ் மற்றும் Self-Hostable

+ +

+ GitHub repo size GitHub Release GitHub உரிமம் +

+

+ « லைவ் டெமோ » +
+
+ Puter.com + · + SDK + · + Discord + · + YouTube + · + Reddit + · + X (Twitter) + · + Bug Bounty +

+ +

screenshot

+ +
+ +## புட்டர் (Putter) + +புட்டர்(putter) என்பது ஒரு மேம்பட்ட, திறந்த மூல இலவசமாக இணைய இயக்க முறைமையாகும், இது அம்சம் நிறைந்ததாகவும், விதிவிலக்காக வேகமாகவும், அதிக விரிவாக்கக்கூடியதாகவும் வடிவமைக்கப்பட்டுள்ளது. புட்டரை இவ்வாறு பயன்படுத்தலாம்: + +- உங்கள் கோப்புகள், பயன்பாடுகள் மற்றும் கேம்கள் அனைத்தையும் ஒரே பாதுகாப்பான இடத்தில் வைத்திருக்க, எந்த நேரத்திலும் எங்கிருந்தும் அணுகக்கூடிய தனியுரிமை-முதல் தனிப்பட்ட கிளவுட். +- இணையதளங்கள், இணைய பயன்பாடுகள் மற்றும் கேம்களை உருவாக்கி வெளியிடுவதற்கான தளம் இதுவாகும். +- புதிய இடைமுகம் மற்றும் சக்திவாய்ந்த அம்சங்களுடன் Dropbox, Google Drive, OneDrive போன்றவற்றுக்கு மாற்றீடாக உபயோகிக்க கூடியது. +- சர்வர்கள் மற்றும் பணிநிலையங்களுக்கான தொலைநிலை டெஸ்க்டாப்(desktop) சூழல். +- வலை மேம்பாடு, கிளவுட் கம்ப்யூட்டிங், விநியோகிக்கப்பட்ட அமைப்புகள் மற்றும் பலவற்றைப் பற்றி அறிந்து ஒரு நட்பு ரீதியான, திறந்த மூல திட்டம் மற்றும் சமூக அறிவியலில் சார்ந்த ஒன்று. + +
+ +## தொடங்குதல் + +### 💻 உள்ளூர் வளர்ச்சி + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` தொடக்கம் +``` + +இது புட்டரை இல் தொடங்கும் (அல்லது அடுத்து கிடைக்கும் இடம்). + +
+ +### 🐳 Docker + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ +### 🐙 டோக்கர் கம்போஸ் + +#### Linux/macOS +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` +
+ +#### Windows + + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +### ☁️ Puter.com + +புட்டர் ஹோஸ்ட் செய்யப்பட்ட சேவையாக [**puter.com**](https://puter.com) இல் கிடைக்கிறது. + +
+ +## கணினி தேவைகள் + +- **இயக்க முறைமைகள்:** Linux, macOS, Windows +- **ரேம்:** குறைந்தபட்சம் 2 ஜிபி (4 ஜிபி பரிந்துரைக்கப்படுகிறது) +- **வட்டு இடம்:** 1GB இலவச இடம் +- **Node.js:** Version 16+ (Version 22+ recommended) +- **npm:** சமீபத்திய நிலையான பதிப்பு(Latest stable version) + +
+ +## ஆதரவு + +இந்த சேனல்கள் மூலம் பராமரிப்பாளர்கள் மற்றும் சமூகத்துடன் சமூக இணைப்பாளர்: + +- பிழை அறிக்கை அல்லது மாற்றுதல் கோரிக்கை? தயவுசெய்து [சிக்கலைத் திறக்கவும்](https://github.com/HeyPuter/puter/issues/new/choose). +- கருத்து வேறுபாடு: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) +- Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) +- பாதுகாப்பு பிரச்சினைகள்? [security@puter.com](mailto:security@puter.com) +- மின்னஞ்சல் பராமரிப்பாளர்களுக்கு [hi@puter.com](mailto:hi@puter.com) + +உங்களுக்கு ஏதேனும் கேள்விகள் இருந்தால் உங்களுக்கு உதவ நாங்கள் எப்போதும் மகிழ்ச்சியடைகிறோம். தயங்காமல் கேளுங்கள்! + +
+ +## உரிமம் + +இந்தக் களஞ்சியமானது, அதன் அனைத்து உள்ளடக்கங்கள், துணைத் திட்டங்கள், தொகுதிகள் மற்றும் கூறுகள் உட்பட, வெளிப்படையாகக் கூறப்படாவிட்டால், [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) இன் கீழ் உரிமம் பெற்றுள்ளது. . இந்தக் களஞ்சியத்தில் சேர்க்கப்பட்டுள்ள மூன்றாம் தரப்பு நூலகங்கள் அவற்றின் சொந்த உரிமங்களுக்கு உட்பட்டதாக இருக்கும். + +
From 7600d9b07c5b719d529f8a48c38d9178efefa266 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 22 Aug 2024 14:28:09 -0400 Subject: [PATCH 0746/2119] feat: add streaming to XHR driver client --- src/puter-js/src/lib/utils.js | 67 +++++++++++++++++++++++++++++++++++ 1 file changed, 67 insertions(+) diff --git a/src/puter-js/src/lib/utils.js b/src/puter-js/src/lib/utils.js index 8195da8f04..1d8af33fda 100644 --- a/src/puter-js/src/lib/utils.js +++ b/src/puter-js/src/lib/utils.js @@ -268,9 +268,76 @@ async function driverCall_( if ( settings.responseType ) { xhr.responseType = settings.responseType; } + + // =============================================== + // TO UNDERSTAND THIS CODE, YOU MUST FIRST + // UNDERSTAND THE FOLLOWING TEXT: + // + // Everything between here and the comment reading + // "=== END OF STREAMING ===" is ONLY for handling + // requests with content type "application/x-ndjson" + // =============================================== + + let is_stream = false; + let got_headers = false; + let signal_stream_update = null; + let lastLength = 0; + let response_complete = false; + const parts_received = []; + xhr.onreadystatechange = () => { + if ( got_headers ) return; + got_headers = true; + if ( xhr.readyState >= 2 ) { + if ( xhr.getResponseHeader("Content-Type") !== + 'application/x-ndjson' + ) return; + is_stream = true; + const Stream = async function* Stream () { + while ( ! response_complete ) { + const tp = new TeePromise(); + signal_stream_update = tp.resolve.bind(tp); + await tp; + if ( response_complete ) break; + while ( parts_received.length > 0 ) { + const value = parts_received.pop(); + const parts = value.split('\n'); + for ( const part of parts ) { + if ( part.trim() === '' ) continue; + yield JSON.parse(part); + } + } + } + } + + return resolve_func(Stream()); + } + }; + + xhr.onprogress = function() { + if ( ! signal_stream_update ) return; + + const newText = xhr.responseText.slice(lastLength); + lastLength = xhr.responseText.length; // Update lastLength to the current length + + parts_received.push(newText); + signal_stream_update(); + }; + + xhr.addEventListener('load', () => { + response_complete = true; + }); + + // ======================== + // === END OF STREAMING === + // ======================== // load: success or error xhr.addEventListener('load', async function(response){ + response_complete = true; + if ( is_stream ) { + signal_stream_update?.(); + return; + } const resp = await parseResponse(response.target); // HTTP Error - unauthorized if(response.status === 401 || resp?.code === "token_auth_failed"){ From 02e7e27796d42e280c21529fe8386a2129761825 Mon Sep 17 00:00:00 2001 From: Sayf Roumane Date: Thu, 22 Aug 2024 20:30:43 +0200 Subject: [PATCH 0747/2119] feat(readme): add french readme respecting format and styling --- doc/i18n/README.fr.md | 129 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 doc/i18n/README.fr.md diff --git a/doc/i18n/README.fr.md b/doc/i18n/README.fr.md new file mode 100644 index 0000000000..c684f50e8a --- /dev/null +++ b/doc/i18n/README.fr.md @@ -0,0 +1,129 @@ +

Puter.com, L'ordinateur cloud personnel : Tous vos fichiers, applications et jeux en un seul endroit accessible de partout à tout moment.

+ +

L'OS Internet ! Gratuit, open-source et auto-hébergeable.

+ +

+ Taille du dépôt GitHub Version GitHub Licence GitHub +

+

+ « DÉMO EN DIRECT » +
+
+ Puter.com + · + SDK + · + Discord + · + YouTube + · + Reddit + · + X (Twitter) + · + Bug Bounty +

+ +

capture d'écran

+ +
+ +## Puter + +Puter est un système d'exploitation internet avancé, open-source, conçu pour être riche en fonctionnalités, extrêmement rapide et hautement extensible. Puter peut être utilisé comme : + +- Un cloud personnel axé sur la confidentialité pour garder tous vos fichiers, applications et jeux en un seul endroit sécurisé, accessible de partout à tout moment. +- Une plateforme pour créer et publier des sites web, des applications web et des jeux. +- Une alternative à Dropbox, Google Drive, OneDrive, etc. avec une interface renouvelée et des fonctionnalités puissantes. +- Un environnement de bureau à distance pour serveurs et stations de travail. +- Un projet et une communauté open-source accueillants pour apprendre le développement web, l'informatique en nuage, les systèmes distribués, et bien plus encore ! + +
+ +## Démarrage + + +### 💻 Développement Local + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +Cela lancera Puter à http://puter.localhost:4100 (ou au port disponible suivant). + +
+ +### 🐳 Docker + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ +### 🐙 Docker Compose + +#### Linux/macOS + +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` + +
+ +#### Windows + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +### ☁️ Puter.com + +Puter est disponible en tant que service hébergé sur puter.com. + +
+ +## Configuration système requise +- **Systèmes d'exploitation:** Linux, macOS, Windows +- **RAM:** Minimum 2 Go (4 Go recommandés) +- **Espace disque:** 1 Go d'espace libre +- **Node.js:** Version 16+ (Version 22+ recommandée) +- **npm:** Dernière version stable + +
+ +## Support + +Connectez-vous avec les mainteneurs et la communauté via ces canaux : + +- Un bug ou une demande de fonctionnalité ? Veuillez [ouvrir une issue](https://github.com/HeyPuter/puter/issues/new/choose). +- Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) +- Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) +- Problèmes de sécurité ? [security@puter.com](mailto:security@puter.com) +- Email des mainteneurs à [hi@puter.com](mailto:hi@puter.com) + +Nous sommes toujours heureux de vous aider avec toutes les questions que vous pourriez avoir. N'hésitez pas à nous demander ! + +
+ + +## License + +Ce dépôt, y compris tout son contenu, sous-projets, modules et composants, est licencié sous [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) sauf indication contraire explicite. Les bibliothèques tierces incluses dans ce dépôt peuvent être soumises à leurs propres licences. + +
+ From d36ef2d770effe6741b1b0ac1b581395b50ca7aa Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 22 Aug 2024 11:38:19 -0700 Subject: [PATCH 0748/2119] Fix image tag for the badge --- doc/i18n/README.ta.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/i18n/README.ta.md b/doc/i18n/README.ta.md index 16ac70493e..25bed62f83 100644 --- a/doc/i18n/README.ta.md +++ b/doc/i18n/README.ta.md @@ -3,7 +3,7 @@

இன்டர்நெட் OS! இலவசம், ஓப்பன் சோர்ஸ் மற்றும் Self-Hostable

- GitHub repo size GitHub Release GitHub உரிமம் + GitHub repo size GitHub Release GitHub உரிமம்

« லைவ் டெமோ » From 766a388660172ad60b89427ec465fd756c5d2500 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 22 Aug 2024 11:45:28 -0700 Subject: [PATCH 0749/2119] fix badge url --- doc/i18n/README.fr.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/i18n/README.fr.md b/doc/i18n/README.fr.md index c684f50e8a..6f7ef67897 100644 --- a/doc/i18n/README.fr.md +++ b/doc/i18n/README.fr.md @@ -3,7 +3,7 @@

L'OS Internet ! Gratuit, open-source et auto-hébergeable.

- Taille du dépôt GitHub Version GitHub Licence GitHub + Taille du dépôt GitHub Version GitHub Licence GitHub

« DÉMO EN DIRECT » From 2b507d1dd05c2dad3d244a9a35020ecb074c51c0 Mon Sep 17 00:00:00 2001 From: Niroyan Kugaruban Date: Thu, 22 Aug 2024 14:47:24 -0400 Subject: [PATCH 0750/2119] change --- .vscode/settings.json | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..febb024da1 --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,3 @@ +{ + "githubPullRequests.ignoredPullRequestBranches": ["main"] +} From d4e955a9e00837108adda2cc314f4c5b112d5472 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 22 Aug 2024 11:57:53 -0700 Subject: [PATCH 0751/2119] Add link to French README in the English README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index a36e64f290..ec5c847866 100644 --- a/README.md +++ b/README.md @@ -136,6 +136,7 @@ This repository, including all its contents, sub-projects, modules, and componen - [Chinese / 中文](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.zh.md) - [Danish / Dansk](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.da.md) - [English](https://github.com/HeyPuter/puter/blob/main/README.md) +- [French / Français](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.da.md) - [Hindi / हिंदी](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.hi.md) - [Italian / Italiano](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.it.md) - [Japanese / 日本語](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.jp.md) From ff02b7bb9f950d7b4784ca5307d7502bd200601d Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 22 Aug 2024 12:50:29 -0700 Subject: [PATCH 0752/2119] Delete .vscode/settings.json --- .vscode/settings.json | 3 --- 1 file changed, 3 deletions(-) delete mode 100644 .vscode/settings.json diff --git a/.vscode/settings.json b/.vscode/settings.json deleted file mode 100644 index febb024da1..0000000000 --- a/.vscode/settings.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "githubPullRequests.ignoredPullRequestBranches": ["main"] -} From 702618f81dc9cd888d038d548eb6b78aa9757346 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 22 Aug 2024 12:52:17 -0700 Subject: [PATCH 0753/2119] Add link to Tamil Readme in the English Readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index ec5c847866..14dde9f891 100644 --- a/README.md +++ b/README.md @@ -143,5 +143,6 @@ This repository, including all its contents, sub-projects, modules, and componen - [Portuguese / Português](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.pt.md) - [Russian / Русский](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ru.md) - [Spanish / Español](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.es.md) +- [Tamil / தமிழ்](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ta.md) - [Turkish / Türkçe](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.tr.md) - [Vietnamese / Tiếng Việt](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.vi.md) From fd86934bc9021541810447cf7e2a5f33b3e283b3 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 22 Aug 2024 20:27:51 -0400 Subject: [PATCH 0754/2119] feat: add method to list models --- src/backend/src/modules/puterai/AIInterfaceService.js | 5 +++++ src/backend/src/modules/puterai/ClaudeService.js | 6 ++++++ .../src/modules/puterai/OpenAICompletionService.js | 6 ++++++ src/backend/src/modules/puterai/TogetherAIService.js | 8 ++++++++ 4 files changed, 25 insertions(+) diff --git a/src/backend/src/modules/puterai/AIInterfaceService.js b/src/backend/src/modules/puterai/AIInterfaceService.js index 1abdbaf189..bd0d908325 100644 --- a/src/backend/src/modules/puterai/AIInterfaceService.js +++ b/src/backend/src/modules/puterai/AIInterfaceService.js @@ -28,6 +28,11 @@ class AIInterfaceService extends BaseService { col_interfaces.set('puter-chat-completion', { description: 'Chatbot.', methods: { + list: { + description: 'List supported models', + result: { type: 'json' }, + parameters: {}, + }, complete: { description: 'Get completions for a chat log.', parameters: { diff --git a/src/backend/src/modules/puterai/ClaudeService.js b/src/backend/src/modules/puterai/ClaudeService.js index 473ecd833f..f171c466d6 100644 --- a/src/backend/src/modules/puterai/ClaudeService.js +++ b/src/backend/src/modules/puterai/ClaudeService.js @@ -26,6 +26,12 @@ class ClaudeService extends BaseService { static IMPLEMENTS = { ['puter-chat-completion']: { + async list () { + return [ + 'claude-3-5-sonnet-20240620', + 'claude-3-haiku-20240307', + ]; + }, async complete ({ messages, stream, model }) { const adapted_messages = []; diff --git a/src/backend/src/modules/puterai/OpenAICompletionService.js b/src/backend/src/modules/puterai/OpenAICompletionService.js index b280a10fdf..1de9d57225 100644 --- a/src/backend/src/modules/puterai/OpenAICompletionService.js +++ b/src/backend/src/modules/puterai/OpenAICompletionService.js @@ -23,6 +23,12 @@ class OpenAICompletionService extends BaseService { static IMPLEMENTS = { ['puter-chat-completion']: { + async list () { + return [ + 'gpt-4o', + 'gpt-4o-mini', + ]; + }, async complete ({ messages, test_mode, stream, model }) { if ( test_mode ) { const { LoremIpsum } = require('lorem-ipsum'); diff --git a/src/backend/src/modules/puterai/TogetherAIService.js b/src/backend/src/modules/puterai/TogetherAIService.js index 851987ac5f..bf6b8c835c 100644 --- a/src/backend/src/modules/puterai/TogetherAIService.js +++ b/src/backend/src/modules/puterai/TogetherAIService.js @@ -22,6 +22,14 @@ class TogetherAIService extends BaseService { static IMPLEMENTS = { ['puter-chat-completion']: { + async list () { + let models = this.modules.kv.get(`${this.kvkey}:models`); + if ( models ) return models; + models = await this.together.models.list(); + this.modules.kv.set( + `${this.kvkey}:models`, models, { EX: 5*60 }); + return models; + }, async complete ({ messages, stream, model }) { console.log('model?', model); const completion = await this.together.chat.completions.create({ From 055c628afd2e33589d3dc66c52934505143eafd4 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 22 Aug 2024 23:28:08 -0400 Subject: [PATCH 0755/2119] feat(puterai): add mistral --- package-lock.json | 19 +++++ src/backend/package.json | 1 + .../src/modules/puterai/MistralAIService.js | 83 +++++++++++++++++++ .../src/modules/puterai/PuterAIModule.js | 5 ++ .../src/modules/puterai/TogetherAIService.js | 1 - src/puter-js/src/modules/AI.js | 5 ++ 6 files changed, 113 insertions(+), 1 deletion(-) create mode 100644 src/backend/src/modules/puterai/MistralAIService.js diff --git a/package-lock.json b/package-lock.json index 97b1540cbd..6f7ca7459a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -3401,6 +3401,14 @@ "node-pre-gyp": "bin/node-pre-gyp" } }, + "node_modules/@mistralai/mistralai": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@mistralai/mistralai/-/mistralai-1.0.3.tgz", + "integrity": "sha512-161lmlaMrQvQeC97LG3GVpQi+LKKmGb6VweEFq6otc4J4kEVaJu6RzmH5UuLCt2eSes1Q5faY6YAPTkGOo0atw==", + "peerDependencies": { + "zod": ">= 3" + } + }, "node_modules/@nodelib/fs.scandir": { "version": "2.1.5", "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", @@ -16390,6 +16398,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/zod": { + "version": "3.23.8", + "resolved": "https://registry.npmjs.org/zod/-/zod-3.23.8.tgz", + "integrity": "sha512-XBx9AXhXktjUqnepgTiE5flcKIYWi/rme0Eaj+5Y0lftuGBq+jyRu/md4WnuxqgP1ubdpNCsYEYPxrzVHD8d6g==", + "license": "MIT", + "peer": true, + "funding": { + "url": "https://github.com/sponsors/colinhacks" + } + }, "packages/backend": { "name": "@heyputer/backend", "version": "2.1.0", @@ -16619,6 +16637,7 @@ "@heyputer/kv.js": "^0.1.3", "@heyputer/multest": "^0.0.2", "@heyputer/puter-js-common": "^1.0.0", + "@mistralai/mistralai": "^1.0.3", "@opentelemetry/api": "^1.4.1", "@opentelemetry/auto-instrumentations-node": "^0.43.0", "@opentelemetry/exporter-trace-otlp-grpc": "^0.40.0", diff --git a/src/backend/package.json b/src/backend/package.json index 5d09800edc..2bd8e544df 100644 --- a/src/backend/package.json +++ b/src/backend/package.json @@ -13,6 +13,7 @@ "@heyputer/kv.js": "^0.1.3", "@heyputer/multest": "^0.0.2", "@heyputer/puter-js-common": "^1.0.0", + "@mistralai/mistralai": "^1.0.3", "@opentelemetry/api": "^1.4.1", "@opentelemetry/auto-instrumentations-node": "^0.43.0", "@opentelemetry/exporter-trace-otlp-grpc": "^0.40.0", diff --git a/src/backend/src/modules/puterai/MistralAIService.js b/src/backend/src/modules/puterai/MistralAIService.js new file mode 100644 index 0000000000..730dca0dc1 --- /dev/null +++ b/src/backend/src/modules/puterai/MistralAIService.js @@ -0,0 +1,83 @@ +const { PassThrough } = require("stream"); +const BaseService = require("../../services/BaseService"); +const { TypedValue } = require("../../services/drivers/meta/Runtime"); +const { nou } = require("../../util/langutil"); + +class MistralAIService extends BaseService { + static MODULES = { + '@mistralai/mistralai': require('@mistralai/mistralai'), + } + async _init () { + const require = this.require; + const { Mistral } = require('@mistralai/mistralai'); + this.client = new Mistral({ + apiKey: this.config.apiKey, + }); + } + static IMPLEMENTS = { + 'puter-chat-completion': { + async list () { + // They send: { "object": "list", data } + const funny_wrapper = await this.client.models.list(); + return funny_wrapper.data; + }, + async complete ({ messages, stream, model }) { + + for ( let i = 0; i < messages.length; i++ ) { + const message = messages[i]; + if ( ! message.role ) message.role = 'user'; + } + + if ( stream ) { + const stream = new PassThrough(); + const retval = new TypedValue({ + $: 'stream', + content_type: 'application/x-ndjson', + chunked: true, + }, stream); + const completion = await this.client.chat.stream({ + model: model ?? 'mistral-large-latest', + messages, + }); + (async () => { + for await ( let chunk of completion ) { + // just because Mistral wants to be different + chunk = chunk.data; + + if ( chunk.choices.length < 1 ) continue; + if ( chunk.choices[0].finish_reason ) { + stream.end(); + break; + } + if ( nou(chunk.choices[0].delta.content) ) continue; + const str = JSON.stringify({ + text: chunk.choices[0].delta.content + }); + stream.write(str + '\n'); + } + })(); + return retval; + } + + try { + const completion = await this.client.chat.complete({ + model: model ?? 'mistral-large-latest', + messages, + }); + // Expected case when mistralai/client-ts#23 is fixed + return completion.choices[0]; + } catch (e) { + if ( ! e?.rawValue?.choices[0] ) { + throw e; + } + // The SDK attempts to validate APIs response and throws + // an exception, even if the response was successful + // https://github.com/mistralai/client-ts/issues/23 + return e.rawValue.choices[0]; + } + } + } + } +} + +module.exports = { MistralAIService }; diff --git a/src/backend/src/modules/puterai/PuterAIModule.js b/src/backend/src/modules/puterai/PuterAIModule.js index fdb67a4179..2e0d2a484f 100644 --- a/src/backend/src/modules/puterai/PuterAIModule.js +++ b/src/backend/src/modules/puterai/PuterAIModule.js @@ -38,6 +38,11 @@ class PuterAIModule extends AdvancedBase { const { TogetherAIService } = require('./TogetherAIService'); services.registerService('together-ai', TogetherAIService); } + + if ( !! config?.services?.['mistral'] ) { + const { MistralAIService } = require('./MistralAIService'); + services.registerService('mistral', MistralAIService); + } } } diff --git a/src/backend/src/modules/puterai/TogetherAIService.js b/src/backend/src/modules/puterai/TogetherAIService.js index bf6b8c835c..ab0abf9564 100644 --- a/src/backend/src/modules/puterai/TogetherAIService.js +++ b/src/backend/src/modules/puterai/TogetherAIService.js @@ -48,7 +48,6 @@ class TogetherAIService extends BaseService { }, stream); (async () => { for await ( const chunk of completion ) { - console.log('IT IS THIS STRING', chunk); if ( chunk.choices.length < 1 ) continue; if ( chunk.choices[0].finish_reason ) { stream.end(); diff --git a/src/puter-js/src/modules/AI.js b/src/puter-js/src/modules/AI.js index 36bf4756cb..5938831805 100644 --- a/src/puter-js/src/modules/AI.js +++ b/src/puter-js/src/modules/AI.js @@ -226,6 +226,9 @@ class AI{ if( options.model === 'claude-3-5-sonnet' || options.model === 'claude'){ options.model = 'claude-3-5-sonnet-20240620'; } + if ( options.model === 'mistral' ) { + options.model = 'mistral-large-latest'; + } // map model to the appropriate driver if (!options.model || options.model === 'gpt-4o' || options.model === 'gpt-4o-mini') { @@ -234,6 +237,8 @@ class AI{ driver = 'claude'; }else if(options.model === 'meta-llama/Meta-Llama-3.1-8B-Instruct-Turbo' || options.model === 'meta-llama/Meta-Llama-3.1-70B-Instruct-Turbo' || options.model === 'meta-llama/Meta-Llama-3.1-405B-Instruct-Turbo' || options.model === `google/gemma-2-27b-it`){ driver = 'together-ai'; + }else if(options.model === 'mistral-large-latest' || options.model === 'codestral-latest'){ + driver = 'mistral'; } // stream flag from settings From 2d39b9be7754b5c2588f83c28183bbf0d71c6aee Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 22 Aug 2024 20:47:02 -0700 Subject: [PATCH 0756/2119] Update index.js --- src/puter-js/src/index.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/puter-js/src/index.js b/src/puter-js/src/index.js index 757439b962..c2e8bb5698 100644 --- a/src/puter-js/src/index.js +++ b/src/puter-js/src/index.js @@ -352,7 +352,7 @@ window.puter = (function() { print = function(...args){ for(let arg of args){ - document.getElementsByTagName('body')[0].append(arg); + document.body.innerHTML += arg; } } } From 937528f7676e8ace7287141e1f5057842a2b5eb7 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 22 Aug 2024 21:26:57 -0400 Subject: [PATCH 0757/2119] fix(security): signing in public folders --- src/backend/src/routers/file.js | 9 ++++++++- src/backend/src/routers/open_item.js | 11 ++++++++--- src/backend/src/routers/sign.js | 10 ++++++++-- 3 files changed, 24 insertions(+), 6 deletions(-) diff --git a/src/backend/src/routers/file.js b/src/backend/src/routers/file.js index 5fbd5cccd8..afebaa1749 100644 --- a/src/backend/src/routers/file.js +++ b/src/backend/src/routers/file.js @@ -39,6 +39,12 @@ router.get('/file', async (req, res, next)=>{ console.log(e) return res.status(403).send(e); } + + let can_write = false; + try{ + validate_signature_auth(get_url_from_req(req), 'write'); + can_write = true; + }catch(e){} const log = req.services.get('log-service').create('/file'); const errors = req.services.get('error-service').create(log); @@ -80,7 +86,8 @@ router.get('/file', async (req, res, next)=>{ if(children.length>0){ for(const child of children){ // sign file - const signed_child = await sign_file(child, 'write'); + const signed_child = await sign_file(child, + can_write ? 'write' : 'read'); signed_children.push(signed_child); } } diff --git a/src/backend/src/routers/open_item.js b/src/backend/src/routers/open_item.js index cdd94f863e..b0489a5d12 100644 --- a/src/backend/src/routers/open_item.js +++ b/src/backend/src/routers/open_item.js @@ -54,11 +54,16 @@ module.exports = eggspress('/open_item', { } const svc_acl = Context.get('services').get('acl'); - if ( ! await svc_acl.check(actor, subject, 'see') ) { - throw await svc_acl.get_safe_acl_error(actor, subject, 'see'); + if ( ! await svc_acl.check(actor, subject, 'read') ) { + throw await svc_acl.get_safe_acl_error(actor, subject, 'read'); + } + + let action = 'write'; + if ( ! await svc_acl.check(actor, subject, 'write') ) { + action = 'read'; } - const signature = await sign_file(subject.entry, 'write'); + const signature = await sign_file(subject.entry, action); const suggested_apps = await suggest_app_for_fsentry(subject.entry); console.log('suggested apps?', suggested_apps); const apps_only_one = suggested_apps.slice(0,1); diff --git a/src/backend/src/routers/sign.js b/src/backend/src/routers/sign.js index df91c9bff6..4a1379a545 100644 --- a/src/backend/src/routers/sign.js +++ b/src/backend/src/routers/sign.js @@ -111,8 +111,14 @@ module.exports = eggspress('/sign', { } const svc_acl = Context.get('services').get('acl'); - if ( ! await svc_acl.check(actor, node, 'see') ) { - throw await svc_acl.get_safe_acl_error(actor, node, 'see'); + if ( ! await svc_acl.check(actor, node, 'read') ) { + throw await svc_acl.get_safe_acl_error(actor, node, 'read'); + } + + if ( item.action === 'write' ) { + if ( ! await svc_acl.check(actor, node, 'write') ) { + throw await svc_acl.get_safe_acl_error(actor, node, 'write'); + } } if ( app !== null ) { From 53e7a91f1800b60b48575a6e41d96d2ccbd6d362 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 23 Aug 2024 00:16:29 -0400 Subject: [PATCH 0758/2119] feat(puterai): add groq --- package-lock.json | 26 +++++++ src/backend/package.json | 1 + .../src/modules/puterai/GroqAIService.js | 69 +++++++++++++++++++ .../src/modules/puterai/PuterAIModule.js | 5 ++ src/puter-js/src/modules/AI.js | 18 +++++ 5 files changed, 119 insertions(+) create mode 100644 src/backend/src/modules/puterai/GroqAIService.js diff --git a/package-lock.json b/package-lock.json index 6f7ca7459a..27fe82683f 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10597,6 +10597,31 @@ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", "dev": true }, + "node_modules/groq-sdk": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/groq-sdk/-/groq-sdk-0.5.0.tgz", + "integrity": "sha512-RVmhW7qZ+XZoy5fIuSdx/LGQJONpL8MHgZEW7dFwTdgkzStub2XQx6OKv28CHogijdwH41J+Npj/z2jBPu3vmw==", + "license": "Apache-2.0", + "dependencies": { + "@types/node": "^18.11.18", + "@types/node-fetch": "^2.6.4", + "abort-controller": "^3.0.0", + "agentkeepalive": "^4.2.1", + "form-data-encoder": "1.7.2", + "formdata-node": "^4.3.2", + "node-fetch": "^2.6.7", + "web-streams-polyfill": "^3.2.1" + } + }, + "node_modules/groq-sdk/node_modules/@types/node": { + "version": "18.19.45", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.19.45.tgz", + "integrity": "sha512-VZxPKNNhjKmaC1SUYowuXSRSMGyQGmQjvvA1xE4QZ0xce2kLtEhPDS+kqpCPBZYgqblCLQ2DAjSzmgCM5auvhA==", + "license": "MIT", + "dependencies": { + "undici-types": "~5.26.4" + } + }, "node_modules/handlebars": { "version": "4.7.8", "resolved": "https://registry.npmjs.org/handlebars/-/handlebars-4.7.8.tgz", @@ -16660,6 +16685,7 @@ "express": "^4.18.2", "file-type": "^18.5.0", "form-data": "^4.0.0", + "groq-sdk": "^0.5.0", "handlebars": "^4.7.8", "helmet": "^7.0.0", "hi-base32": "^0.5.1", diff --git a/src/backend/package.json b/src/backend/package.json index 2bd8e544df..d55ced4e9e 100644 --- a/src/backend/package.json +++ b/src/backend/package.json @@ -36,6 +36,7 @@ "express": "^4.18.2", "file-type": "^18.5.0", "form-data": "^4.0.0", + "groq-sdk": "^0.5.0", "handlebars": "^4.7.8", "helmet": "^7.0.0", "hi-base32": "^0.5.1", diff --git a/src/backend/src/modules/puterai/GroqAIService.js b/src/backend/src/modules/puterai/GroqAIService.js new file mode 100644 index 0000000000..3426d77964 --- /dev/null +++ b/src/backend/src/modules/puterai/GroqAIService.js @@ -0,0 +1,69 @@ +const { PassThrough } = require("stream"); +const BaseService = require("../../services/BaseService"); +const { TypedValue } = require("../../services/drivers/meta/Runtime"); +const { nou } = require("../../util/langutil"); + +class GroqAIService extends BaseService { + static MODULES = { + Groq: require('groq-sdk'), + } + + async _init () { + const Groq = require('groq-sdk'); + this.client = new Groq({ + apiKey: this.config.apiKey, + }); + } + + static IMPLEMENTS = { + 'puter-chat-completion': { + async list () { + // They send: { "object": "list", data } + const funny_wrapper = await this.client.models.list(); + return funny_wrapper.data; + }, + async complete ({ messages, model, stream }) { + for ( let i = 0; i < messages.length; i++ ) { + const message = messages[i]; + if ( ! message.role ) message.role = 'user'; + } + + const completion = await this.client.chat.completions.create({ + messages, + model, + stream, + }); + + if ( stream ) { + const stream = new PassThrough(); + const retval = new TypedValue({ + $: 'stream', + content_type: 'application/x-ndjson', + chunked: true, + }, stream); + (async () => { + for await ( const chunk of completion ) { + if ( chunk.choices.length < 1 ) continue; + if ( chunk.choices[0].finish_reason ) { + stream.end(); + break; + } + if ( nou(chunk.choices[0].delta.content) ) continue; + const str = JSON.stringify({ + text: chunk.choices[0].delta.content + }); + stream.write(str + '\n'); + } + })(); + return retval; + } + + return completion.choices[0]; + } + } + }; +} + +module.exports = { + GroqAIService, +}; diff --git a/src/backend/src/modules/puterai/PuterAIModule.js b/src/backend/src/modules/puterai/PuterAIModule.js index 2e0d2a484f..fb88b64e75 100644 --- a/src/backend/src/modules/puterai/PuterAIModule.js +++ b/src/backend/src/modules/puterai/PuterAIModule.js @@ -43,6 +43,11 @@ class PuterAIModule extends AdvancedBase { const { MistralAIService } = require('./MistralAIService'); services.registerService('mistral', MistralAIService); } + + if ( !! config?.services?.['groq'] ) { + const { GroqAIService } = require('./GroqAIService'); + services.registerService('groq', GroqAIService); + } } } diff --git a/src/puter-js/src/modules/AI.js b/src/puter-js/src/modules/AI.js index 5938831805..a04a79d90f 100644 --- a/src/puter-js/src/modules/AI.js +++ b/src/puter-js/src/modules/AI.js @@ -229,6 +229,9 @@ class AI{ if ( options.model === 'mistral' ) { options.model = 'mistral-large-latest'; } + if ( options.model === 'groq' ) { + options.model = 'llama3-8b-8192'; + } // map model to the appropriate driver if (!options.model || options.model === 'gpt-4o' || options.model === 'gpt-4o-mini') { @@ -239,6 +242,21 @@ class AI{ driver = 'together-ai'; }else if(options.model === 'mistral-large-latest' || options.model === 'codestral-latest'){ driver = 'mistral'; + }else if([ + "distil-whisper-large-v3-en", + "gemma2-9b-it", + "gemma-7b-it", + "llama-3.1-70b-versatile", + "llama-3.1-8b-instant", + "llama3-70b-8192", + "llama3-8b-8192", + "llama3-groq-70b-8192-tool-use-preview", + "llama3-groq-8b-8192-tool-use-preview", + "llama-guard-3-8b", + "mixtral-8x7b-32768", + "whisper-large-v3" + ].includes(options.model)) { + driver = 'groq'; } // stream flag from settings From a549fc86bc8576e74bae93da6983adb14d3897b1 Mon Sep 17 00:00:00 2001 From: Muhammad Fauzi Date: Sat, 24 Aug 2024 00:05:28 +0700 Subject: [PATCH 0759/2119] Add README.id.md --- doc/i18n/README.id.md | 131 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 doc/i18n/README.id.md diff --git a/doc/i18n/README.id.md b/doc/i18n/README.id.md new file mode 100644 index 0000000000..0854174aae --- /dev/null +++ b/doc/i18n/README.id.md @@ -0,0 +1,131 @@ +

Puter.com, Komputer Cloud Pribadi: Semua file, aplikasi, dan permainan Anda berada di satu tempat yang dapat diakses dari mana saja kapan saja.

+ +

Sistem Operasi Internet! Gratis, Sumber Terbuka, dan Dapat Dihosting Sendiri.

+ +

+ GitHub repo size GitHub Release GitHub License +

+

+ « LIVE DEMO » +
+
+ Puter.com + · + SDK + · + Discord + · + YouTube + · + Reddit + · + X (Twitter) + · + Bug Bounty +

+ +

screenshot

+ +
+ +## Puter + +Puter adalah sistem operasi internet canggih, open-source, yang dirancang untuk menjadi kaya fitur, sangat cepat, dan sangat dapat diperluas. Puter dapat digunakan sebagai: + +- Cloud pribadi yang mengutamakan privasi untuk menyimpan semua file, aplikasi, dan permainan Anda di satu tempat yang aman, yang dapat diakses dari mana saja kapan saja. +- Platform untuk membangun dan mempublikasikan situs web, aplikasi web, dan permainan. +- Alternatif untuk Dropbox, Google Drive, OneDrive, dll. Dengan antarmuka baru dan fitur-fitur canggih. +- Lingkungan desktop jarak jauh untuk server dan workstation. +- Proyek dan komunitas open-source yang ramah untuk belajar tentang pengembangan web, komputasi gemawan (cloud), sistem terdistribusi, dan banyak lagi! + +
+ +## Memulai + + +### 💻 Pengembangan Lokal + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +Ini akan menjalankan Puter di http://puter.localhost:4100 (atau di port berikutnya yang tersedia) + +
+ +### 🐳 Docker + + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ + +### 🐙 Docker Compose + + +#### Linux/macOS +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` +
+ +#### Windows + + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +### ☁️ Puter.com + +Puter tersedia sebagai layanan yang telah dihosting di [**puter.com**](https://puter.com). + +
+ +## Persyaratan Sistem + +- **Sistem Operasi:** Linux, macOS, Windows +- **RAM:** 2GB minimal (rekomendasi 4GB) +- **Penyimpanan:** 1GB ruang tersedia +- **Node.js:** Version 16+ (rekomendasi versi 22+) +- **npm:** Versi stabil termutakhir + +
+ +## Dukuangan + +Terhubung dengan maintainer dan komunitas melalui saluran-saluran berikut: + +- Laporan bug atau permintaan fitur? Silakan [buat issue](https://github.com/HeyPuter/puter/issues/new/choose). +- Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) +- Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) +- Isu keamanan? [security@puter.com](mailto:security@puter.com) +- Email maintainers di [hi@puter.com](mailto:hi@puter.com) + +Kami selalu senang membantu Anda dengan pertanyaan apa pun yang Anda miliki. Jangan ragu untuk bertanya! + +
+ + +## Lisensi + +Repositori ini, termasuk semua isinya, sub-proyek, modul, dan komponen, dilisensikan di bawah [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) kecuali dinyatakan sebaliknya secara eksplisit. Perpustakaan pihak ketiga yang termasuk dalam repositori ini mungkin tunduk pada lisensinya sendiri. + +
From 194d0bcc6d5101aa8e318c4f8a9eda1830326a7b Mon Sep 17 00:00:00 2001 From: Muhammad Fauzi Date: Sat, 24 Aug 2024 00:28:27 +0700 Subject: [PATCH 0760/2119] Add link to Indonesian Readme in the English Readme --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 14dde9f891..196aa9766f 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,7 @@ This repository, including all its contents, sub-projects, modules, and componen - [English](https://github.com/HeyPuter/puter/blob/main/README.md) - [French / Français](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.da.md) - [Hindi / हिंदी](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.hi.md) +- [Indonesian / Bahasa Indonesia](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.id.md) - [Italian / Italiano](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.it.md) - [Japanese / 日本語](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.jp.md) - [Portuguese / Português](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.pt.md) From 6cf7d0ae27be8bd6bf3ea51338faa5a83f506e56 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 23 Aug 2024 15:09:25 -0400 Subject: [PATCH 0761/2119] doc: update CONTRIBUTING.md --- CONTRIBUTING.md | 39 +++++++++++++++++++++++++++++---------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index b28814b480..40a50189cf 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -57,25 +57,44 @@ See [doc/contributors/index.md](./doc/contributors/index.md) for more informatio
+## PR Standards + +We expect the following from pull requests (it makes things easier): +- If you're closing an issue, please reference that issue in the PR description +- Avoid whitespace changes +- No regressions for "appspace" (Puter apps) + +
+ ## Commit Messages -Use the imperative, as is the convention in the Linux kernel: +**Note:** we will squash-merge some PRs so they follow . Large PRs should follow conventional commits also. The instructions below are outdated but suitable for most PRs. + +### Conventional Commits +We use [Conventional Commits](https://www.conventionalcommits.org/en/v1.0.0/) with the following prefixes: +- `fix:` for bug fixes +- `dev:` instead of `refactor:`; covers more basis +- `tweak:` for small updates +- `sync:` when updating data from another source +- `feat:` for a commit that first introduces a new feature + +Commit messages after the prefix should use the imperative (the same convention used in the repo for Linux, which Git was built for): -- correct: `Improve performance of readdir` -- incorrect: `Improved readdir` -- incorrect: `Improving readdir` +- correct: `dev: improve performance of readdir` +- incorrect: `dev: improved readdir` +- incorrect: `dev: improving readdir` We have the following exceptions to this rule: - If the commit message is in _past tense_, it's a shorthand for the following: - - `Apply changes that would be applied after one had ` + - `dev: apply changes that would be applied after one had ` - If the commit message is in _present tense_, it's shorthand for the following: - - `Apply changes that would be applied after ` + - `dev: apply changes that would be applied after ` For example, the following are correct: -- `Improved readdir` - - interpret this as: `Apply changes that would be applied after one had improved readdir` -- `Improving readdir` - - interpret this as: `Apply changes that would be applied after improving readdir` +- `dev: improved readdir` + - interpret this as: `dev: apply changes that would be applied after one had improved readdir` +- `dev: improving readdir` + - interpret this as: `dev: apply changes that would be applied after improving readdir`
From 7f9d1e90b12f8b3f19b1c2ba3b215313dd24fe47 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 23 Aug 2024 16:09:22 -0400 Subject: [PATCH 0762/2119] chore(puterai): update model --- package-lock.json | 9 +++++---- src/backend/package.json | 2 +- .../src/modules/puterai/OpenAICompletionService.js | 3 +-- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index 27fe82683f..094c3213fe 100644 --- a/package-lock.json +++ b/package-lock.json @@ -15371,9 +15371,10 @@ "dev": true }, "node_modules/tiktoken": { - "version": "1.0.15", - "resolved": "https://registry.npmjs.org/tiktoken/-/tiktoken-1.0.15.tgz", - "integrity": "sha512-sCsrq/vMWUSEW29CJLNmPvWxlVp7yh2tlkAjpJltIKqp5CKf98ZNpdeHRmAlPVFlGEbswDc6SmI8vz64W/qErw==" + "version": "1.0.16", + "resolved": "https://registry.npmjs.org/tiktoken/-/tiktoken-1.0.16.tgz", + "integrity": "sha512-hRcORIGF2YlAgWx3nzrGJOrKSJwLoc81HpXmMQk89632XAgURc7IeV2FgQ2iXo9z/J96fCvpsHg2kWoHcbj9fg==", + "license": "MIT" }, "node_modules/tildify": { "version": "2.0.0", @@ -16719,7 +16720,7 @@ "string-hash": "^1.1.3", "string-length": "^6.0.0", "svgo": "^3.0.2", - "tiktoken": "^1.0.15", + "tiktoken": "^1.0.16", "together-ai": "^0.6.0-alpha.4", "tweetnacl": "^1.0.3", "ua-parser-js": "^1.0.38", diff --git a/src/backend/package.json b/src/backend/package.json index d55ced4e9e..196807c376 100644 --- a/src/backend/package.json +++ b/src/backend/package.json @@ -70,7 +70,7 @@ "string-hash": "^1.1.3", "string-length": "^6.0.0", "svgo": "^3.0.2", - "tiktoken": "^1.0.15", + "tiktoken": "^1.0.16", "together-ai": "^0.6.0-alpha.4", "tweetnacl": "^1.0.3", "ua-parser-js": "^1.0.38", diff --git a/src/backend/src/modules/puterai/OpenAICompletionService.js b/src/backend/src/modules/puterai/OpenAICompletionService.js index 1de9d57225..e9cca41f5f 100644 --- a/src/backend/src/modules/puterai/OpenAICompletionService.js +++ b/src/backend/src/modules/puterai/OpenAICompletionService.js @@ -91,8 +91,7 @@ class OpenAICompletionService extends BaseService { throw new Error('`messages` must be an array'); } - model = model ?? 'gpt-3.5-turbo'; - // model = model ?? 'gpt-4o'; + model = model ?? 'gpt-4o-mini'; for ( let i = 0; i < messages.length; i++ ) { let msg = messages[i]; From 5a616f67dd22a0dcbb8a380bbbd2347a0029ce31 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 23 Aug 2024 16:39:30 -0400 Subject: [PATCH 0763/2119] fix(puterjs): fix settings object check --- src/puter-js/src/modules/AI.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/puter-js/src/modules/AI.js b/src/puter-js/src/modules/AI.js index a04a79d90f..f6ee7f3d13 100644 --- a/src/puter-js/src/modules/AI.js +++ b/src/puter-js/src/modules/AI.js @@ -209,8 +209,13 @@ class AI{ } // if any of the args is an object, assume it's the settings object + const is_object = v => { + return typeof v === 'object' && + !Array.isArray(v) && + v !== null; + }; for (let i = 0; i < args.length; i++) { - if (typeof args[i] === 'object') { + if (is_object(args[i])) { settings = args[i]; break; } From eb18550f411947a0d8ccaf283701596b1386cfe6 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 23 Aug 2024 19:42:53 -0400 Subject: [PATCH 0764/2119] fix(puterai): close streams --- .../src/modules/puterai/ClaudeService.js | 1 + .../src/modules/puterai/GroqAIService.js | 1 + .../src/modules/puterai/MistralAIService.js | 1 + .../modules/puterai/OpenAICompletionService.js | 1 + .../src/modules/puterai/TogetherAIService.js | 1 + src/puter-js/src/lib/utils.js | 17 +++++++---------- 6 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/backend/src/modules/puterai/ClaudeService.js b/src/backend/src/modules/puterai/ClaudeService.js index f171c466d6..3d8a82af67 100644 --- a/src/backend/src/modules/puterai/ClaudeService.js +++ b/src/backend/src/modules/puterai/ClaudeService.js @@ -90,6 +90,7 @@ class ClaudeService extends BaseService { }); stream.write(str + '\n'); } + stream.end(); })(); return retval; diff --git a/src/backend/src/modules/puterai/GroqAIService.js b/src/backend/src/modules/puterai/GroqAIService.js index 3426d77964..f0beab7269 100644 --- a/src/backend/src/modules/puterai/GroqAIService.js +++ b/src/backend/src/modules/puterai/GroqAIService.js @@ -54,6 +54,7 @@ class GroqAIService extends BaseService { }); stream.write(str + '\n'); } + stream.end(); })(); return retval; } diff --git a/src/backend/src/modules/puterai/MistralAIService.js b/src/backend/src/modules/puterai/MistralAIService.js index 730dca0dc1..b57219bbef 100644 --- a/src/backend/src/modules/puterai/MistralAIService.js +++ b/src/backend/src/modules/puterai/MistralAIService.js @@ -55,6 +55,7 @@ class MistralAIService extends BaseService { }); stream.write(str + '\n'); } + stream.end(); })(); return retval; } diff --git a/src/backend/src/modules/puterai/OpenAICompletionService.js b/src/backend/src/modules/puterai/OpenAICompletionService.js index e9cca41f5f..304cc0c2e2 100644 --- a/src/backend/src/modules/puterai/OpenAICompletionService.js +++ b/src/backend/src/modules/puterai/OpenAICompletionService.js @@ -232,6 +232,7 @@ class OpenAICompletionService extends BaseService { }); stream.write(str + '\n'); } + stream.end(); })(); return retval; } diff --git a/src/backend/src/modules/puterai/TogetherAIService.js b/src/backend/src/modules/puterai/TogetherAIService.js index ab0abf9564..9001fb9413 100644 --- a/src/backend/src/modules/puterai/TogetherAIService.js +++ b/src/backend/src/modules/puterai/TogetherAIService.js @@ -59,6 +59,7 @@ class TogetherAIService extends BaseService { }); stream.write(str + '\n'); } + stream.end(); })(); return retval; } diff --git a/src/puter-js/src/lib/utils.js b/src/puter-js/src/lib/utils.js index 1d8af33fda..212ee6bea3 100644 --- a/src/puter-js/src/lib/utils.js +++ b/src/puter-js/src/lib/utils.js @@ -279,15 +279,12 @@ async function driverCall_( // =============================================== let is_stream = false; - let got_headers = false; let signal_stream_update = null; let lastLength = 0; let response_complete = false; const parts_received = []; xhr.onreadystatechange = () => { - if ( got_headers ) return; - got_headers = true; - if ( xhr.readyState >= 2 ) { + if ( xhr.readyState === 2 ) { if ( xhr.getResponseHeader("Content-Type") !== 'application/x-ndjson' ) return; @@ -311,6 +308,12 @@ async function driverCall_( return resolve_func(Stream()); } + if ( xhr.readyState === 4 ) { + response_complete = true; + if ( is_stream ) { + signal_stream_update?.(); + } + } }; xhr.onprogress = function() { @@ -323,19 +326,13 @@ async function driverCall_( signal_stream_update(); }; - xhr.addEventListener('load', () => { - response_complete = true; - }); - // ======================== // === END OF STREAMING === // ======================== // load: success or error xhr.addEventListener('load', async function(response){ - response_complete = true; if ( is_stream ) { - signal_stream_update?.(); return; } const resp = await parseResponse(response.target); From 02c28018913198e4b817c2af54040f8e7c272995 Mon Sep 17 00:00:00 2001 From: Atharva Chavan <112580278+Atharva089@users.noreply.github.com> Date: Sat, 24 Aug 2024 10:50:37 +0530 Subject: [PATCH 0765/2119] Added the README.ro.md file Translated the README.en.md file from English to Romanian language. --- doc/i18n/README.ro.md | 129 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 doc/i18n/README.ro.md diff --git a/doc/i18n/README.ro.md b/doc/i18n/README.ro.md new file mode 100644 index 0000000000..62b99909f5 --- /dev/null +++ b/doc/i18n/README.ro.md @@ -0,0 +1,129 @@ +

Puter.com, Computerul Cloud Personal: Toate fișierele, aplicațiile și jocurile tale într-un singur loc, accesibile de oriunde, oricând.

+ +

Sistemul de Operare Internet! Gratuit, Open-Source și Găzduibil Autonom.

+ +

+ Mărime repo GitHub Versiune GitHub Release Licență GitHub +

+

+ « DEMO LIVE » +
+
+ Puter.com + · + SDK + · + Discord + · + YouTube + · + Reddit + · + X (Twitter) + · + Bug Bounty +

+ +

captură de ecran

+ +
+ +## Puter + +Puter este un sistem de operare pe internet avansat, open-source, proiectat să fie bogat în funcții, extrem de rapid și foarte extensibil. Puter poate fi folosit ca: + +- Un cloud personal axat pe confidențialitate pentru a păstra toate fișierele, aplicațiile și jocurile într-un loc sigur, accesibil de oriunde, oricând. +- O platformă pentru construirea și publicarea de site-uri web, aplicații web și jocuri. +- O alternativă la Dropbox, Google Drive, OneDrive, etc. cu o interfață nouă și caracteristici puternice. +- Un mediu desktop la distanță pentru servere și stații de lucru. +- Un proiect prietenos, open-source și o comunitate pentru a învăța despre dezvoltarea web, cloud computing, sisteme distribuite și multe altele! + +
+ +## Începeți + +### 💻 Dezvoltare Locală + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +Acest lucru va lansa Puter la http://puter.localhost:4100 (sau următorul port disponibil). + +
+ +### 🐳 Docker + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ +### 🐙 Docker Compose + +### Linux/macOS + +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` + +
+ +#### Windows + +```powershell + +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` + +
+ +### ☁️ Puter.com + +Puter este disponibil ca serviciu găzduit la [**puter.com**](https://puter.com). + +
+ +## Cerințe de Sistem + +- **Sisteme de Operare:** Linux, macOS, Windows +- **RAM:** 2GB minim (4GB recomandat) +- **Spațiu pe Disk:** 1GB spațiu liber +- **Node.js:** Versiunea 16+ (Versiunea 22+ recomandată) +- **npm:** Ultima versiune stabilă + +
+ +## Sprijin + +Conectați-vă cu întreținătorii și comunitatea prin următoarele canale: + +- Aveți o problemă sau doriți o funcționalitate nouă? Vă rugăm [să deschideți o problemă](https://github.com/HeyPuter/puter/issues/new/choose). +- Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) +- Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) +- Probleme de securitate? [security@puter.com](mailto:security@puter.com) +- Trimiteți un email întreținătorilor la [hi@puter.com](mailto:hi@puter.com) + +Suntem bucuroși să vă ajutăm cu orice întrebări aveți. Nu ezitați să ne întrebați! + +
+ +## Licență + +Acest depozit, inclusiv toate conținuturile sale, sub-proiectele, modulele și componentele, este licențiat sub [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt), cu excepția cazului în care se menționează altfel în mod explicit. Bibliotecile terțe incluse în acest depozit pot fi supuse propriilor licențe. + +
From b5e4962e71d9080eccce73484e9f322c3346d1eb Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Fri, 23 Aug 2024 23:06:10 -0700 Subject: [PATCH 0766/2119] Update README.ro.md --- doc/i18n/README.ro.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/doc/i18n/README.ro.md b/doc/i18n/README.ro.md index 62b99909f5..d56a663f50 100644 --- a/doc/i18n/README.ro.md +++ b/doc/i18n/README.ro.md @@ -3,7 +3,7 @@

Sistemul de Operare Internet! Gratuit, Open-Source și Găzduibil Autonom.

- Mărime repo GitHub Versiune GitHub Release Licență GitHub + Mărime repo GitHub Versiune GitHub Release Licență GitHub

« DEMO LIVE » From 9b0bd4f8205e9fa79ce442a8f419358f6be8d57f Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Fri, 23 Aug 2024 23:08:15 -0700 Subject: [PATCH 0767/2119] Add link to Romanian README in the English README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 196aa9766f..970b6089be 100644 --- a/README.md +++ b/README.md @@ -143,6 +143,7 @@ This repository, including all its contents, sub-projects, modules, and componen - [Japanese / 日本語](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.jp.md) - [Portuguese / Português](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.pt.md) - [Russian / Русский](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ru.md) +- [Romanian / Română](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ro.md) - [Spanish / Español](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.es.md) - [Tamil / தமிழ்](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ta.md) - [Turkish / Türkçe](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.tr.md) From 852f2ea9441ad350ab9f271ed1e0bdbf4cd95b86 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Fri, 23 Aug 2024 23:09:04 -0700 Subject: [PATCH 0768/2119] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 970b6089be..5efe8fe8c0 100644 --- a/README.md +++ b/README.md @@ -142,8 +142,8 @@ This repository, including all its contents, sub-projects, modules, and componen - [Italian / Italiano](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.it.md) - [Japanese / 日本語](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.jp.md) - [Portuguese / Português](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.pt.md) -- [Russian / Русский](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ru.md) - [Romanian / Română](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ro.md) +- [Russian / Русский](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ru.md) - [Spanish / Español](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.es.md) - [Tamil / தமிழ்](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ta.md) - [Turkish / Türkçe](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.tr.md) From ea87223c46f7ccd9db29241264c757f967db5b18 Mon Sep 17 00:00:00 2001 From: Catalin Date: Sat, 24 Aug 2024 20:31:47 +0300 Subject: [PATCH 0769/2119] Fixes issue #677: Translate README.md from English to Romanian --- doc/i18n/README.ro.md | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/doc/i18n/README.ro.md b/doc/i18n/README.ro.md index d56a663f50..e2ba40e11a 100644 --- a/doc/i18n/README.ro.md +++ b/doc/i18n/README.ro.md @@ -1,9 +1,9 @@ -

Puter.com, Computerul Cloud Personal: Toate fișierele, aplicațiile și jocurile tale într-un singur loc, accesibile de oriunde, oricând.

+

Puter.com, Calculatorul Personal Cloud: Toate fișierele, aplicațiile și jocurile dumneavoastră într-un singur loc, accesibile de oriunde și oricând.

Sistemul de Operare Internet! Gratuit, Open-Source și Găzduibil Autonom.

- Mărime repo GitHub Versiune GitHub Release Licență GitHub + Mărime GitHub repository Versiune GitHub Licență GitHub

« DEMO LIVE » @@ -24,7 +24,7 @@ Bug Bounty

-

captură de ecran

+

screenshot


@@ -32,10 +32,10 @@ Puter este un sistem de operare pe internet avansat, open-source, proiectat să fie bogat în funcții, extrem de rapid și foarte extensibil. Puter poate fi folosit ca: -- Un cloud personal axat pe confidențialitate pentru a păstra toate fișierele, aplicațiile și jocurile într-un loc sigur, accesibil de oriunde, oricând. -- O platformă pentru construirea și publicarea de site-uri web, aplicații web și jocuri. -- O alternativă la Dropbox, Google Drive, OneDrive, etc. cu o interfață nouă și caracteristici puternice. -- Un mediu desktop la distanță pentru servere și stații de lucru. +- Un cloud personal care pune pe primul loc confidențialitatea pentru a păstra toate fișierele, aplicațiile și jocurile tale într-un loc sigur, accesibil de oriunde și oricând. +- O platforma pentru a construi și publica site-uri web, aplicații web și jocuri. +- O alternativă la Dropbox, Google Drive, OneDrive, etc. cu o interfață nouă și funcționalități puternice. +- Un mediu desktop la distanță pentru servere si stații de lucru. - Un proiect prietenos, open-source și o comunitate pentru a învăța despre dezvoltarea web, cloud computing, sisteme distribuite și multe altele!
@@ -51,35 +51,36 @@ npm install npm start ``` -Acest lucru va lansa Puter la http://puter.localhost:4100 (sau următorul port disponibil). +Aceasta va lansa Puter la adresa http://puter.localhost:4100 (sau la următorul port disponibil).
### 🐳 Docker + ```bash mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter ```
+ ### 🐙 Docker Compose -### Linux/macOS +#### Linux/macOS ```bash mkdir -p puter/config puter/data sudo chown -R 1000:1000 puter wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml docker compose up ``` -
#### Windows -```powershell +```powershell mkdir -p puter cd puter New-Item -Path "puter\config" -ItemType Directory -Force @@ -87,7 +88,6 @@ New-Item -Path "puter\data" -ItemType Directory -Force Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" docker compose up ``` -
### ☁️ Puter.com @@ -106,9 +106,9 @@ Puter este disponibil ca serviciu găzduit la [**puter.com**](https://puter.com)
-## Sprijin +## Suport -Conectați-vă cu întreținătorii și comunitatea prin următoarele canale: +Conectați-vă cu cei care asigură mentenanța proiectului și comunitatea prin intermediul acestor canale: - Aveți o problemă sau doriți o funcționalitate nouă? Vă rugăm [să deschideți o problemă](https://github.com/HeyPuter/puter/issues/new/choose). - Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) @@ -116,14 +116,14 @@ Conectați-vă cu întreținătorii și comunitatea prin următoarele canale: - Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) - Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) - Probleme de securitate? [security@puter.com](mailto:security@puter.com) -- Trimiteți un email întreținătorilor la [hi@puter.com](mailto:hi@puter.com) +- Trimiteți un email celor care asigură mentenanța proiectul la [hi@puter.com](mailto:hi@puter.com) -Suntem bucuroși să vă ajutăm cu orice întrebări aveți. Nu ezitați să ne întrebați! +Suntem întotdeauna bucuroși să vă ajutăm cu orice întrebări aveți. Nu ezitați să ne întrebați!
## Licență -Acest depozit, inclusiv toate conținuturile sale, sub-proiectele, modulele și componentele, este licențiat sub [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt), cu excepția cazului în care se menționează altfel în mod explicit. Bibliotecile terțe incluse în acest depozit pot fi supuse propriilor licențe. +Acest depozit, inclusiv toate conținuturile sale, sub-proiectele, modulele și componentele, sunt licențiate sub [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt), cu excepția cazului în care se menționează altfel în mod explicit. Bibliotecile terțe incluse în acest depozit pot fi supuse propriilor licențe.
From b43ecb490a4032d385f378b1e140d0cb9b43a9c1 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sat, 24 Aug 2024 11:41:42 -0700 Subject: [PATCH 0770/2119] Place github link and icon in the toolbar --- src/gui/src/UI/UIDesktop.js | 3 +++ src/gui/src/icons/logo-github-white.svg | 6 ++++++ 2 files changed, 9 insertions(+) create mode 100644 src/gui/src/icons/logo-github-white.svg diff --git a/src/gui/src/UI/UIDesktop.js b/src/gui/src/UI/UIDesktop.js index 0bfb37dbb7..7959643ac0 100644 --- a/src/gui/src/UI/UIDesktop.js +++ b/src/gui/src/UI/UIDesktop.js @@ -994,6 +994,9 @@ async function UIDesktop(options){ ht += `
`; } + // github + ht += ``; + // do not show the fullscreen button on mobile devices since it's broken if(!isMobile.phone){ // fullscreen button diff --git a/src/gui/src/icons/logo-github-white.svg b/src/gui/src/icons/logo-github-white.svg new file mode 100644 index 0000000000..430c9d03f4 --- /dev/null +++ b/src/gui/src/icons/logo-github-white.svg @@ -0,0 +1,6 @@ + \ No newline at end of file From 9c7dc53fc9fb3754cf5c30ac65a8d4d68171c4a6 Mon Sep 17 00:00:00 2001 From: decipher Date: Sun, 25 Aug 2024 18:03:15 +0200 Subject: [PATCH 0771/2119] Update README.md Added "Installation on public server" --- README.md | 38 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 38 insertions(+) diff --git a/README.md b/README.md index 5efe8fe8c0..058a5d4b8f 100644 --- a/README.md +++ b/README.md @@ -91,6 +91,44 @@ docker compose up ```
+### 🌎 Installation on public server +Subdomain is puter. Replace "domain.com" with your domain name. + +#### -Create DNS entries for puter.domain.com and api.puter.domain.com, both pointing to the same IP. + +#### -Create apache domain configs for puter.domain.com and api.puter.domain.com and add reverse proxy entries for both subdomains +```$ a2enmod proxy``` +```$ a2enmod proxy_http``` + + +##### /etc/apache/sites-enabled/--configfile--- +``` +ProxyPass / http://localhost:4100/ +ProxyPassReverse / http://localhost:4100/ +``` +#### -Edit ./src/backend/src/config.js +add after let config = {}; +```config.api_base_url = 'https://api.puter.domain.com'; +config.origin='https://puter.domain.com'; +config.http_port=443;´ +config.pub_port=443; +config.protocol='https'; +``` + +#### -Edit ./node_modules/@heyputer/backend/src/services/WebServerService.js and ./src/backend/src/services/WebServerService.js +search for +```if (allowedDomains.some(allowedDomain => hostName ===``` +and change the line to +```if (allowedDomains.some(allowedDomain => hostName === "puter.domain.com" || hostName.endsWith('.' + allowedDomain))) {``` + +#### -Edit ./volatile/config/config.json +change ```"domain": "puter.localost"``` to ```"domain": "puter.domain.com"``` + +#### -Run sed to replace the domain in all remaining files +``` grep -rl "puter.localhost:4100" . | xargs sed -i 's/puter.localhost:4001/puter.domain.com/g' ``` +
+
+ ### ☁️ Puter.com Puter is available as a hosted service at [**puter.com**](https://puter.com). From 56b73b385d6b1410229450a7e0cbffd873b06b39 Mon Sep 17 00:00:00 2001 From: decipher Date: Sun, 25 Aug 2024 18:06:21 +0200 Subject: [PATCH 0772/2119] Update README.md --- README.md | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 058a5d4b8f..dabb41e406 100644 --- a/README.md +++ b/README.md @@ -107,8 +107,9 @@ ProxyPass / http://localhost:4100/ ProxyPassReverse / http://localhost:4100/ ``` #### -Edit ./src/backend/src/config.js -add after let config = {}; -```config.api_base_url = 'https://api.puter.domain.com'; +Add after ```let config = {};``` +``` +config.api_base_url = 'https://api.puter.domain.com'; config.origin='https://puter.domain.com'; config.http_port=443;´ config.pub_port=443; @@ -116,13 +117,13 @@ config.protocol='https'; ``` #### -Edit ./node_modules/@heyputer/backend/src/services/WebServerService.js and ./src/backend/src/services/WebServerService.js -search for +Search for ```if (allowedDomains.some(allowedDomain => hostName ===``` and change the line to ```if (allowedDomains.some(allowedDomain => hostName === "puter.domain.com" || hostName.endsWith('.' + allowedDomain))) {``` #### -Edit ./volatile/config/config.json -change ```"domain": "puter.localost"``` to ```"domain": "puter.domain.com"``` +Change ```"domain": "puter.localhost"``` to ```"domain": "puter.domain.com"``` #### -Run sed to replace the domain in all remaining files ``` grep -rl "puter.localhost:4100" . | xargs sed -i 's/puter.localhost:4001/puter.domain.com/g' ``` From 222d7dede373a9d5e1fc36929a47e4cbd5407b53 Mon Sep 17 00:00:00 2001 From: decipher Date: Sun, 25 Aug 2024 19:28:12 +0200 Subject: [PATCH 0773/2119] Added configuration option for closing registration Set config.registration_closed=true; in ./src/backend/src/config.js to close registration --- src/backend/src/routers/signup.js | 530 +++++++++++++++--------------- 1 file changed, 269 insertions(+), 261 deletions(-) diff --git a/src/backend/src/routers/signup.js b/src/backend/src/routers/signup.js index 50a503b433..b601e7c00f 100644 --- a/src/backend/src/routers/signup.js +++ b/src/backend/src/routers/signup.js @@ -65,273 +65,281 @@ module.exports = eggspress(['/signup'], { body: req.body, }); - // check bot trap, if `p102xyzname` is anything but an empty string it means - // that a bot has filled the form - // doesn't apply to temp users - if(!req.body.is_temp && req.body.p102xyzname !== '') - return res.send(); - - // check if user is already logged in - if ( req.body.is_temp && req.cookies[config.cookie_name] ) { - const { user, token } = await svc_auth.check_session( - req.cookies[config.cookie_name] - ); - res.cookie(config.cookie_name, token, { - sameSite: 'none', - secure: true, - httpOnly: true, - }); - // const decoded = await jwt.verify(token, config.jwt_secret); - // const user = await get_user({ uuid: decoded.uuid }); - if ( user ) { - return res.send({ - token: token, - user: { - username: user.username, - uuid: user.uuid, - email: user.email, - email_confirmed: user.email_confirmed, - requires_email_confirmation: user.requires_email_confirmation, - is_temp: (user.password === null && user.email === null), - taskbar_items: await get_taskbar_items(user), - } + if(config.registration_closed==true) + { + return res.status(403).send('Registration is closed.'); + } + else + { + + // check bot trap, if `p102xyzname` is anything but an empty string it means + // that a bot has filled the form + // doesn't apply to temp users + if(!req.body.is_temp && req.body.p102xyzname !== '') + return res.send(); + + // check if user is already logged in + if ( req.body.is_temp && req.cookies[config.cookie_name] ) { + const { user, token } = await svc_auth.check_session( + req.cookies[config.cookie_name] + ); + res.cookie(config.cookie_name, token, { + sameSite: 'none', + secure: true, + httpOnly: true, }); + // const decoded = await jwt.verify(token, config.jwt_secret); + // const user = await get_user({ uuid: decoded.uuid }); + if ( user ) { + return res.send({ + token: token, + user: { + username: user.username, + uuid: user.uuid, + email: user.email, + email_confirmed: user.email_confirmed, + requires_email_confirmation: user.requires_email_confirmation, + is_temp: (user.password === null && user.email === null), + taskbar_items: await get_taskbar_items(user), + } + }); + } } - } - - // temporary user - if(req.body.is_temp && !config.disable_temp_users){ - req.body.username = await generate_random_username(); - req.body.email = req.body.username + '@gmail.com'; - req.body.password = 'sadasdfasdfsadfsa'; - }else if(config.disable_temp_users){ - return res.status(400).send('Temp users are disabled.'); - } - - // send_confirmation_code - req.body.send_confirmation_code = req.body.send_confirmation_code ?? true; - - // username is required - if(!req.body.username) - return res.status(400).send('Username is required') - // username must be a string - else if (typeof req.body.username !== 'string') - return res.status(400).send('username must be a string.') - // check if username is valid - else if(!req.body.username.match(config.username_regex)) - return res.status(400).send('Username can only contain letters, numbers and underscore (_).') - // check if username is of proper length - else if(req.body.username.length > config.username_max_length) - return res.status(400).send(`Username cannot be longer than ${config.username_max_length} characters.`) - // check if username matches any reserved words - else if(config.reserved_words.includes(req.body.username)) - return res.status(400).send({message: 'This username is not available.'}); - // TODO: DRY: change_email.js - else if(!req.body.is_temp && !req.body.email) - return res.status(400).send('Email is required'); - // email, if present, must be a string - else if (req.body.email && typeof req.body.email !== 'string') - return res.status(400).send('email must be a string.') - // if email is present, validate it - else if(!req.body.is_temp && !validator.isEmail(req.body.email)) - return res.status(400).send('Please enter a valid email address.') - else if(!req.body.is_temp && !req.body.password) - return res.status(400).send('Password is required'); - // password, if present, must be a string - else if (req.body.password && typeof req.body.password !== 'string') - return res.status(400).send('password must be a string.') - else if(!req.body.is_temp && req.body.password.length < config.min_pass_length) - return res.status(400).send(`Password must be at least ${config.min_pass_length} characters long.`); - - // duplicate username check - if(await username_exists(req.body.username)) - return res.status(400).send('This username already exists in our database. Please use another one.'); - // duplicate email check (pseudo-users don't count) - let rows2 = await db.read(`SELECT EXISTS(SELECT 1 FROM user WHERE email=? AND password IS NOT NULL) AS email_exists`, [req.body.email]); - if(rows2[0].email_exists) - return res.status(400).send('This email already exists in our database. Please use another one.'); - // get pseudo user, if exists - let pseudo_user = await db.read(`SELECT * FROM user WHERE email = ? AND password IS NULL`, [req.body.email]); - pseudo_user = pseudo_user[0]; - // get uuid user, if exists - if(req.body.uuid){ - uuid_user = await db.read(`SELECT * FROM user WHERE uuid = ? LIMIT 1`, [req.body.uuid]); - uuid_user = uuid_user[0]; - } - - // email confirmation is required by default unless: - // Pseudo user converting and matching uuid is provided - let email_confirmation_required = 1; - if(pseudo_user && uuid_user && pseudo_user.id === uuid_user.id) - email_confirmation_required = 0; - - // ----------------------------------- - // Get referral user - // ----------------------------------- - let referred_by_user = undefined; - if ( req.body.referral_code ) { - referred_by_user = await get_user({ referral_code: req.body.referral_code }); - if ( ! referred_by_user ) { - return res.status(400).send('Referral code not found'); + + // temporary user + if(req.body.is_temp && !config.disable_temp_users){ + req.body.username = await generate_random_username(); + req.body.email = req.body.username + '@gmail.com'; + req.body.password = 'sadasdfasdfsadfsa'; + }else if(config.disable_temp_users){ + return res.status(400).send('Temp users are disabled.'); } - } - - // ----------------------------------- - // New User - // ----------------------------------- - const user_uuid = uuidv4(); - const email_confirm_token = uuidv4(); - let insert_res; - let email_confirm_code = Math.floor(100000 + Math.random() * 900000); - - if(pseudo_user === undefined){ - insert_res = await db.write( - `INSERT INTO user - (username, email, password, uuid, referrer, email_confirm_code, email_confirm_token, free_storage, referred_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, - [ - // username - req.body.username, - // email - req.body.is_temp ? null : req.body.email, - // password - req.body.is_temp ? null : await bcrypt.hash(req.body.password, 8), - // uuid - user_uuid, - // referrer - req.body.referrer ?? null, - // email_confirm_code - email_confirm_code, - // email_confirm_token - email_confirm_token, - // free_storage - config.storage_capacity, - // referred_by - referred_by_user ? referred_by_user.id : null, - ]); - - // record activity - db.write( - 'UPDATE `user` SET `last_activity_ts` = now() WHERE id=? LIMIT 1', - [insert_res.insertId] - ); - - // TODO: cache group id - const svc_group = req.services.get('group'); - await svc_group.add_users({ - uid: req.body.is_temp ? - config.default_temp_group : config.default_user_group, - users: [req.body.username] - }); - } - // ----------------------------------- - // Pseudo User converting - // ----------------------------------- - else{ - insert_res = await db.write( - `UPDATE user SET - username = ?, password = ?, uuid = ?, email_confirm_code = ?, email_confirm_token = ?, email_confirmed = ?, requires_email_confirmation = 1, - referred_by = ? - WHERE id = ?`, - [ - // username - req.body.username, - // password - await bcrypt.hash(req.body.password, 8), - // uuid - user_uuid, - // email_confirm_code - email_confirm_code, - // email_confirm_token - email_confirm_token, - // email_confirmed - !email_confirmation_required, - // id - pseudo_user.id, - // referred_by - referred_by_user ? referred_by_user.id : null, - ] + + // send_confirmation_code + req.body.send_confirmation_code = req.body.send_confirmation_code ?? true; + + // username is required + if(!req.body.username) + return res.status(400).send('Username is required') + // username must be a string + else if (typeof req.body.username !== 'string') + return res.status(400).send('username must be a string.') + // check if username is valid + else if(!req.body.username.match(config.username_regex)) + return res.status(400).send('Username can only contain letters, numbers and underscore (_).') + // check if username is of proper length + else if(req.body.username.length > config.username_max_length) + return res.status(400).send(`Username cannot be longer than ${config.username_max_length} characters.`) + // check if username matches any reserved words + else if(config.reserved_words.includes(req.body.username)) + return res.status(400).send({message: 'This username is not available.'}); + // TODO: DRY: change_email.js + else if(!req.body.is_temp && !req.body.email) + return res.status(400).send('Email is required'); + // email, if present, must be a string + else if (req.body.email && typeof req.body.email !== 'string') + return res.status(400).send('email must be a string.') + // if email is present, validate it + else if(!req.body.is_temp && !validator.isEmail(req.body.email)) + return res.status(400).send('Please enter a valid email address.') + else if(!req.body.is_temp && !req.body.password) + return res.status(400).send('Password is required'); + // password, if present, must be a string + else if (req.body.password && typeof req.body.password !== 'string') + return res.status(400).send('password must be a string.') + else if(!req.body.is_temp && req.body.password.length < config.min_pass_length) + return res.status(400).send(`Password must be at least ${config.min_pass_length} characters long.`); + + // duplicate username check + if(await username_exists(req.body.username)) + return res.status(400).send('This username already exists in our database. Please use another one.'); + // duplicate email check (pseudo-users don't count) + let rows2 = await db.read(`SELECT EXISTS(SELECT 1 FROM user WHERE email=? AND password IS NOT NULL) AS email_exists`, [req.body.email]); + if(rows2[0].email_exists) + return res.status(400).send('This email already exists in our database. Please use another one.'); + // get pseudo user, if exists + let pseudo_user = await db.read(`SELECT * FROM user WHERE email = ? AND password IS NULL`, [req.body.email]); + pseudo_user = pseudo_user[0]; + // get uuid user, if exists + if(req.body.uuid){ + uuid_user = await db.read(`SELECT * FROM user WHERE uuid = ? LIMIT 1`, [req.body.uuid]); + uuid_user = uuid_user[0]; + } + + // email confirmation is required by default unless: + // Pseudo user converting and matching uuid is provided + let email_confirmation_required = 1; + if(pseudo_user && uuid_user && pseudo_user.id === uuid_user.id) + email_confirmation_required = 0; + + // ----------------------------------- + // Get referral user + // ----------------------------------- + let referred_by_user = undefined; + if ( req.body.referral_code ) { + referred_by_user = await get_user({ referral_code: req.body.referral_code }); + if ( ! referred_by_user ) { + return res.status(400).send('Referral code not found'); + } + } + + // ----------------------------------- + // New User + // ----------------------------------- + const user_uuid = uuidv4(); + const email_confirm_token = uuidv4(); + let insert_res; + let email_confirm_code = Math.floor(100000 + Math.random() * 900000); + + if(pseudo_user === undefined){ + insert_res = await db.write( + `INSERT INTO user + (username, email, password, uuid, referrer, email_confirm_code, email_confirm_token, free_storage, referred_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, + [ + // username + req.body.username, + // email + req.body.is_temp ? null : req.body.email, + // password + req.body.is_temp ? null : await bcrypt.hash(req.body.password, 8), + // uuid + user_uuid, + // referrer + req.body.referrer ?? null, + // email_confirm_code + email_confirm_code, + // email_confirm_token + email_confirm_token, + // free_storage + config.storage_capacity, + // referred_by + referred_by_user ? referred_by_user.id : null, + ]); + + // record activity + db.write( + 'UPDATE `user` SET `last_activity_ts` = now() WHERE id=? LIMIT 1', + [insert_res.insertId] + ); + + // TODO: cache group id + const svc_group = req.services.get('group'); + await svc_group.add_users({ + uid: req.body.is_temp ? + config.default_temp_group : config.default_user_group, + users: [req.body.username] + }); + } + // ----------------------------------- + // Pseudo User converting + // ----------------------------------- + else{ + insert_res = await db.write( + `UPDATE user SET + username = ?, password = ?, uuid = ?, email_confirm_code = ?, email_confirm_token = ?, email_confirmed = ?, requires_email_confirmation = 1, + referred_by = ? + WHERE id = ?`, + [ + // username + req.body.username, + // password + await bcrypt.hash(req.body.password, 8), + // uuid + user_uuid, + // email_confirm_code + email_confirm_code, + // email_confirm_token + email_confirm_token, + // email_confirmed + !email_confirmation_required, + // id + pseudo_user.id, + // referred_by + referred_by_user ? referred_by_user.id : null, + ] + ); + + // TODO: cache group ids + const svc_group = req.services.get('group'); + await svc_group.remove_users({ + uid: config.default_temp_group, + users: [req.body.username], + }); + await svc_group.add_users({ + uid: config.default_user_group, + users: [req.body.username] + }); + + // record activity + db.write('UPDATE `user` SET `last_activity_ts` = now() WHERE id=? LIMIT 1', [pseudo_user.id]); + invalidate_cached_user_by_id(pseudo_user.id); + } + + // user id + // todo if pseudo user, assign directly no need to do another DB lookup + const user_id = (pseudo_user === undefined) ? insert_res.insertId : pseudo_user.id; + + const [user] = await db.pread( + 'SELECT * FROM `user` WHERE `id` = ? LIMIT 1', + [user_id] ); - - // TODO: cache group ids - const svc_group = req.services.get('group'); - await svc_group.remove_users({ - uid: config.default_temp_group, - users: [req.body.username], + + // create token for login + const { token } = await svc_auth.create_session_token(user, { + req, }); - await svc_group.add_users({ - uid: config.default_user_group, - users: [req.body.username] + // jwt.sign({uuid: user_uuid}, config.jwt_secret); + + //------------------------------------------------------------- + // email confirmation + //------------------------------------------------------------- + if((!req.body.is_temp && email_confirmation_required) || user.requires_email_confirmation){ + if(req.body.send_confirmation_code || user.requires_email_confirmation) + send_email_verification_code(email_confirm_code, user.email); + else + send_email_verification_token(user.email_confirm_token, user.email, user.uuid); + } + + //------------------------------------------------------------- + // referral code + //------------------------------------------------------------- + let referral_code; + if ( pseudo_user === undefined ) { + const svc_referralCode = Context.get('services') + .get('referral-code', { optional: true }); + if ( svc_referralCode ) { + referral_code = await svc_referralCode.gen_referral_code(user); + } + } + + await generate_system_fsentries(user); + + //set cookie + res.cookie(config.cookie_name, token, { + sameSite: 'none', + secure: true, + httpOnly: true, }); - - // record activity - db.write('UPDATE `user` SET `last_activity_ts` = now() WHERE id=? LIMIT 1', [pseudo_user.id]); - invalidate_cached_user_by_id(pseudo_user.id); - } - - // user id - // todo if pseudo user, assign directly no need to do another DB lookup - const user_id = (pseudo_user === undefined) ? insert_res.insertId : pseudo_user.id; - - const [user] = await db.pread( - 'SELECT * FROM `user` WHERE `id` = ? LIMIT 1', - [user_id] - ); - - // create token for login - const { token } = await svc_auth.create_session_token(user, { - req, - }); - // jwt.sign({uuid: user_uuid}, config.jwt_secret); - - //------------------------------------------------------------- - // email confirmation - //------------------------------------------------------------- - if((!req.body.is_temp && email_confirmation_required) || user.requires_email_confirmation){ - if(req.body.send_confirmation_code || user.requires_email_confirmation) - send_email_verification_code(email_confirm_code, user.email); - else - send_email_verification_token(user.email_confirm_token, user.email, user.uuid); - } - - //------------------------------------------------------------- - // referral code - //------------------------------------------------------------- - let referral_code; - if ( pseudo_user === undefined ) { - const svc_referralCode = Context.get('services') - .get('referral-code', { optional: true }); - if ( svc_referralCode ) { - referral_code = await svc_referralCode.gen_referral_code(user); + + // add to mailchimp + if(!req.body.is_temp){ + const svc_event = Context.get('services').get('event'); + svc_event.emit('user.save_account', { user }); } + + // return results + return res.send({ + token: token, + user:{ + username: user.username, + uuid: user.uuid, + email: user.email, + email_confirmed: user.email_confirmed, + requires_email_confirmation: user.requires_email_confirmation, + is_temp: (user.password === null && user.email === null), + taskbar_items: await get_taskbar_items(user), + referral_code, + } + }) } - - await generate_system_fsentries(user); - - //set cookie - res.cookie(config.cookie_name, token, { - sameSite: 'none', - secure: true, - httpOnly: true, - }); - - // add to mailchimp - if(!req.body.is_temp){ - const svc_event = Context.get('services').get('event'); - svc_event.emit('user.save_account', { user }); - } - - // return results - return res.send({ - token: token, - user:{ - username: user.username, - uuid: user.uuid, - email: user.email, - email_confirmed: user.email_confirmed, - requires_email_confirmation: user.requires_email_confirmation, - is_temp: (user.password === null && user.email === null), - taskbar_items: await get_taskbar_items(user), - referral_code, - } - }) }); From 28a7f0ba1fbeed906c764d7963ef33b96f7c4160 Mon Sep 17 00:00:00 2001 From: Panyakornk Date: Mon, 26 Aug 2024 01:00:44 +0700 Subject: [PATCH 0774/2119] Create README.th.md --- doc/i18n/README.th.md | 131 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 doc/i18n/README.th.md diff --git a/doc/i18n/README.th.md b/doc/i18n/README.th.md new file mode 100644 index 0000000000..1108e397a3 --- /dev/null +++ b/doc/i18n/README.th.md @@ -0,0 +1,131 @@ +

Puter.com, The Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time.

+ +

ระบบปฏิบัติการอินเทอร์เน็ต ฟรี, โอเพ่นซอร์ส, และสามารถโฮสต์ได้ด้วยตนเอง

+ +

+ GitHub repo size GitHub Release GitHub License +

+

+ « การสาธิตสด » +
+
+ Puter.com + · + ชุดพัฒนาโปรแกรม + · + ดิสคอร์ด + · + ยูทูบ + · + เรดดิท + · + X (ทวิตเตอร์) + · + นักล่าบั๊ก +

+ +

screenshot

+ +
+ +## พิวเตอร์ + +พิวเตอร์ เป็นระบบปฏิบัติการอินเทอร์เน็ตขั้นสูงแบบโอเพ่นซอร์สที่ออกแบบมาให้มีฟีเจอร์ครบถ้วน ความเร็วสูง และมีความสามารถที่จะขยายได้สูง. พิวเตอร์ สามารถใช้ได้เป็น: + +- คลาวด์ส่วนตัว เพื่อเก็บไฟล์, แอพพลิเคชัน, และเกมทั้งหมดของคุณในที่เดียวที่ปลอดภัยและสามารถเข้าถึงได้ทุกที่ทุกเวลา +- แพลตฟอร์มสำหรับการสร้างและเผยแพร่เว็บไซต์, เว็บแอปพลิเคชัน, และเกม +- ทางเลือกอีกหนึ่งทางที่สามารถใช้แทน Dropbox, Google Drive, OneDrive ฯลฯ โดยที่มีอินเทอร์เฟซใหม่และฟีเจอร์ที่ทรงพลัง +- สภาพแวดล้อมสำหรับเดสก์ท็อประยะไกลที่ใช้กับเซิร์ฟเวอร์และสถานีทำงาน +- โครงการโอเพ่นซอร์สและชุมชนที่เป็นมิตรที่คุณสามารถเรียนรู้เกี่ยวกับการพัฒนาเว็บ, คลาวด์คอมพิวติ้ง, ระบบกระจาย, และอีกมากมาย + +
+ +## การเริ่มต้นใช้งาน + + +### 💻 การพัฒนาภายในเครื่อง + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +พิวเตอร์ จะถูกเปิดใช้งานที่ http://puter.localhost:4100 (หรือพอร์ตถัดไปที่ว่าง). + +
+ +### 🐳 ด็อกเกอร์ + + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ + +### 🐙 ด็อกเกอร์ คอมโพส + + +#### ลินุกซ์/แมคโอเอส +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` +
+ +#### วินโดวส์ + + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +### ☁️ Puter.com + +สามารถใช้งาน พิวเตอร์ ได้ในรูปแบบบริการโฮสต์ที่ [**puter.com**](https://puter.com). + +
+ +## ข้อกำหนดของระบบ + +- **ระบบปฏิบัติการ:** ลินุกซ์ แมคโอเอส วินโดวส์ +- **แรม:** อย่างน้อย 2GB (แนะนำ 4GB) +- **พื้นที่เก็บข้อมูล:** พื้นที่ว่าง 1GB +- **Node.js:** เวอร์ชัน 16+ (แนะนำเวอร์ชัน 22+) +- **npm:** เวอร์ชันล่าสุดที่เสถียร + +
+ +## การช่วยเหลือ + +ติดต่อกับผู้ดูแลระบบและชุมชนผ่านช่องทางเหล่านี้: + +- พบข้อผิดพลาดหรือขอฟีเจอร์ใหม่? กรุณา [เปิดปัญหา](https://github.com/HeyPuter/puter/issues/new/choose). +- ดิสคอร์ด: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- X (ทวิตเตอร์): [x.com/HeyPuter](https://x.com/HeyPuter) +- เรดดิท: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- มาสตอดอน: [mastodon.social/@puter](https://mastodon.social/@puter) +- ปัญหาด้านความปลอดภัย [security@puter.com](mailto:security@puter.com) +- ส่งอีเมลถึงผู้ดูแลระบบได้ที่ [hi@puter.com](mailto:hi@puter.com) + +เรายินดีเสมอที่จะช่วยเหลือคุณกับทุกทุกคำถามที่คุณมี อย่าลังเลที่จะถาม + +
+ + +## ลิขสิทธิ์ + +ที่เก็บข้อมูลนี้ รวมถึงเนื้อหาทั้งหมด, โครงการย่อย, โมดูล, และส่วนประกอบต่างๆ ได้รับใบอนุญาตภายใต้ [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) เว้นแต่จะมีการระบุไว้เป็นอย่างอื่นอย่างชัดเจน ไลบรารีจากบุคคลที่สามที่รวมอยู่ในที่เก็บข้อมูลนี้อาจอยู่ภายใต้ใบอนุญาตของตนเอง + +
From cd2eb656a1ab8ab01bb5ad350622154692618be7 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sun, 25 Aug 2024 12:30:42 -0700 Subject: [PATCH 0775/2119] Add link to Thai README in the English README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 5efe8fe8c0..e626fabeb6 100644 --- a/README.md +++ b/README.md @@ -146,5 +146,6 @@ This repository, including all its contents, sub-projects, modules, and componen - [Russian / Русский](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ru.md) - [Spanish / Español](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.es.md) - [Tamil / தமிழ்](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ta.md) +- [Thai / ไทย](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.th.md) - [Turkish / Türkçe](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.tr.md) - [Vietnamese / Tiếng Việt](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.vi.md) From d8dc3ac12271091d7c808aad0a3ab79d48f5444f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20Dub=C3=A9?= Date: Sun, 25 Aug 2024 16:21:48 -0400 Subject: [PATCH 0776/2119] Update instructions.md --- doc/self-hosters/instructions.md | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/doc/self-hosters/instructions.md b/doc/self-hosters/instructions.md index becfeccd28..04f820360a 100644 --- a/doc/self-hosters/instructions.md +++ b/doc/self-hosters/instructions.md @@ -5,16 +5,12 @@ ### Self-Hosting Differences Currently, the self-hosted version of Puter is different in a few ways from [Puter.com](https://puter.com): -- There is no built-in way to install or create other apps (see below) -- Several "core" apps are missing, such as **Code** or **Draw**, because we can't include them in this repository -- Some icons are different +- There is no built-in way to access apps from puter.com (see below) +- Several "core" apps are missing, such as **Code** or **Draw** +- Some assets are different Work is ongoing to improve the **App Center** and make it available on self-hosted. -Until then, it's possible to add other apps by manually editing the database file. -This process is not recommended unless you know what you are doing. -The file will appear after you first launch Puter, and should be found in `puter/data/puter-database.sqlite` for Docker, -or `volatile/runtime/puter-database.sqlite` otherwise. -You will need a database tool that can understand SQLite databases. +Until then, it is still possible to add apps using the **Dev Center** app.
@@ -55,4 +51,4 @@ A warning will persist in the dev console until this user's password is changed. Please login to this user and change the password as your first step. -
\ No newline at end of file +
From 9a622004ea488783127abd83f3f4caf779a5aabb Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sun, 25 Aug 2024 16:54:19 -0400 Subject: [PATCH 0777/2119] fix: fix 500 when check-app has bad url --- src/backend/src/api/APIError.js | 4 ++++ src/backend/src/services/auth/AuthService.js | 3 +++ 2 files changed, 7 insertions(+) diff --git a/src/backend/src/api/APIError.js b/src/backend/src/api/APIError.js index 93bee20fc4..70b9628dda 100644 --- a/src/backend/src/api/APIError.js +++ b/src/backend/src/api/APIError.js @@ -482,6 +482,10 @@ module.exports = class APIError { status: 422, message: 'This share can not be applied to this user.', }, + 'no_origin_for_app': { + status: 400, + message: 'Puter apps must have a valid URL.' + }, // Chat // TODO: specifying these errors here might be a violation diff --git a/src/backend/src/services/auth/AuthService.js b/src/backend/src/services/auth/AuthService.js index ea0dfe4511..d8ab3eb95e 100644 --- a/src/backend/src/services/auth/AuthService.js +++ b/src/backend/src/services/auth/AuthService.js @@ -442,6 +442,9 @@ class AuthService extends BaseService { async app_uid_from_origin (origin) { origin = this._origin_from_url(origin); + if ( origin === null ) { + throw APIError.create('no_origin_for_app'); + } return await this._app_uid_from_origin(origin); } From da5635b576b18fa64947483572fc9868bc979e07 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sun, 25 Aug 2024 14:38:19 -0700 Subject: [PATCH 0778/2119] Show an error if file containing puter.js is loaded using the `file:` protocol --- src/puter-js/src/modules/PuterDialog.js | 81 +++++++++++++++++++------ 1 file changed, 64 insertions(+), 17 deletions(-) diff --git a/src/puter-js/src/modules/PuterDialog.js b/src/puter-js/src/modules/PuterDialog.js index b1e039a461..1c1790318a 100644 --- a/src/puter-js/src/modules/PuterDialog.js +++ b/src/puter-js/src/modules/PuterDialog.js @@ -1,4 +1,13 @@ class PuterDialog extends HTMLElement { + /** + * Detects if the current page is loaded using the file:// protocol. + * @returns {boolean} True if using file:// protocol, false otherwise. + */ + isUsingFileProtocol = ()=>{ + return window.location.protocol === 'file:'; + } + + constructor(resolve, reject) { super(); this.attachShadow({ mode: 'open' }); @@ -6,8 +15,9 @@ class PuterDialog extends HTMLElement { this.reject = reject; this.resolve = resolve; + let h; // Dialog - this.shadowRoot.innerHTML = ` + h = ` - -
- - -

This website uses Puter to bring you safe, secure, and private AI and Cloud features.

-
- - + .error-container h1 { + color: #e74c3c; + font-size: 20px; + text-align: center; + } + + .puter-dialog-content a:focus{ + outline: none; + } + `; + // Error message for unsupported protocol + if(window.location.protocol === 'file:'){ + h += ` +
+ +
+

Puter.js Error: Unsupported Protocol

+

It looks like you've opened this file directly in your browser (using the file:/// protocol) which is not supported by Puter.js for security reasons.

+

To view this content properly, you need to serve it through a web server. Here are some options:

+
    +
  • Use a local development server (e.g., Python's built-in server or Node.js http-server)
  • +
  • Upload the files to a web hosting service
  • +
  • Use a local server application like XAMPP or MAMP
  • +
+

If you're not familiar with these options, consider reaching out to your development team or IT support for assistance.

+
+

+ Docs| + Github| + Discord +

+
+
`; + }else{ + h += ` +
+ + +

This website uses Puter to bring you safe, secure, and private AI and Cloud features.

+
+ + +
+

Powered by Puter.js

+

By clicking 'Continue' you agree to Puter's Terms of Service and Privacy Policy.

-

Powered by Puter.js

-

By clicking 'Continue' you agree to Puter's Terms of Service and Privacy Policy.

-
-
`; + `; + } + + + this.shadowRoot.innerHTML = h; // Event listener for the 'message' event this.messageListener = async (event) => { @@ -341,7 +388,7 @@ class PuterDialog extends HTMLElement { connectedCallback() { // Add event listener to the button - this.shadowRoot.querySelector('#launch-auth-popup').addEventListener('click', ()=>{ + this.shadowRoot.querySelector('#launch-auth-popup')?.addEventListener('click', ()=>{ let w = 600; let h = 400; let title = 'Puter'; @@ -356,8 +403,8 @@ class PuterDialog extends HTMLElement { window.addEventListener('message', this.messageListener); // Add event listeners for cancel and close buttons - this.shadowRoot.querySelector('#launch-auth-popup-cancel').addEventListener('click', this.cancelListener); - this.shadowRoot.querySelector('.close-btn').addEventListener('click',this.cancelListener); + this.shadowRoot.querySelector('#launch-auth-popup-cancel')?.addEventListener('click', this.cancelListener); + this.shadowRoot.querySelector('.close-btn')?.addEventListener('click',this.cancelListener); } open() { From 155aab57d3d18b046ff678894ffc221045a71f92 Mon Sep 17 00:00:00 2001 From: decipher Date: Mon, 26 Aug 2024 04:59:08 +0200 Subject: [PATCH 0779/2119] Removed else statement for closing registration in signup.js --- src/backend/src/routers/signup.js | 530 +++++++++++++++--------------- 1 file changed, 263 insertions(+), 267 deletions(-) diff --git a/src/backend/src/routers/signup.js b/src/backend/src/routers/signup.js index b601e7c00f..d01892680c 100644 --- a/src/backend/src/routers/signup.js +++ b/src/backend/src/routers/signup.js @@ -65,281 +65,277 @@ module.exports = eggspress(['/signup'], { body: req.body, }); - if(config.registration_closed==true) - { + if( config.registration_closed == true ) { return res.status(403).send('Registration is closed.'); } - else - { - - // check bot trap, if `p102xyzname` is anything but an empty string it means - // that a bot has filled the form - // doesn't apply to temp users - if(!req.body.is_temp && req.body.p102xyzname !== '') - return res.send(); - - // check if user is already logged in - if ( req.body.is_temp && req.cookies[config.cookie_name] ) { - const { user, token } = await svc_auth.check_session( - req.cookies[config.cookie_name] - ); - res.cookie(config.cookie_name, token, { - sameSite: 'none', - secure: true, - httpOnly: true, - }); - // const decoded = await jwt.verify(token, config.jwt_secret); - // const user = await get_user({ uuid: decoded.uuid }); - if ( user ) { - return res.send({ - token: token, - user: { - username: user.username, - uuid: user.uuid, - email: user.email, - email_confirmed: user.email_confirmed, - requires_email_confirmation: user.requires_email_confirmation, - is_temp: (user.password === null && user.email === null), - taskbar_items: await get_taskbar_items(user), - } - }); - } - } - - // temporary user - if(req.body.is_temp && !config.disable_temp_users){ - req.body.username = await generate_random_username(); - req.body.email = req.body.username + '@gmail.com'; - req.body.password = 'sadasdfasdfsadfsa'; - }else if(config.disable_temp_users){ - return res.status(400).send('Temp users are disabled.'); - } - - // send_confirmation_code - req.body.send_confirmation_code = req.body.send_confirmation_code ?? true; - - // username is required - if(!req.body.username) - return res.status(400).send('Username is required') - // username must be a string - else if (typeof req.body.username !== 'string') - return res.status(400).send('username must be a string.') - // check if username is valid - else if(!req.body.username.match(config.username_regex)) - return res.status(400).send('Username can only contain letters, numbers and underscore (_).') - // check if username is of proper length - else if(req.body.username.length > config.username_max_length) - return res.status(400).send(`Username cannot be longer than ${config.username_max_length} characters.`) - // check if username matches any reserved words - else if(config.reserved_words.includes(req.body.username)) - return res.status(400).send({message: 'This username is not available.'}); - // TODO: DRY: change_email.js - else if(!req.body.is_temp && !req.body.email) - return res.status(400).send('Email is required'); - // email, if present, must be a string - else if (req.body.email && typeof req.body.email !== 'string') - return res.status(400).send('email must be a string.') - // if email is present, validate it - else if(!req.body.is_temp && !validator.isEmail(req.body.email)) - return res.status(400).send('Please enter a valid email address.') - else if(!req.body.is_temp && !req.body.password) - return res.status(400).send('Password is required'); - // password, if present, must be a string - else if (req.body.password && typeof req.body.password !== 'string') - return res.status(400).send('password must be a string.') - else if(!req.body.is_temp && req.body.password.length < config.min_pass_length) - return res.status(400).send(`Password must be at least ${config.min_pass_length} characters long.`); - - // duplicate username check - if(await username_exists(req.body.username)) - return res.status(400).send('This username already exists in our database. Please use another one.'); - // duplicate email check (pseudo-users don't count) - let rows2 = await db.read(`SELECT EXISTS(SELECT 1 FROM user WHERE email=? AND password IS NOT NULL) AS email_exists`, [req.body.email]); - if(rows2[0].email_exists) - return res.status(400).send('This email already exists in our database. Please use another one.'); - // get pseudo user, if exists - let pseudo_user = await db.read(`SELECT * FROM user WHERE email = ? AND password IS NULL`, [req.body.email]); - pseudo_user = pseudo_user[0]; - // get uuid user, if exists - if(req.body.uuid){ - uuid_user = await db.read(`SELECT * FROM user WHERE uuid = ? LIMIT 1`, [req.body.uuid]); - uuid_user = uuid_user[0]; - } - - // email confirmation is required by default unless: - // Pseudo user converting and matching uuid is provided - let email_confirmation_required = 1; - if(pseudo_user && uuid_user && pseudo_user.id === uuid_user.id) - email_confirmation_required = 0; - - // ----------------------------------- - // Get referral user - // ----------------------------------- - let referred_by_user = undefined; - if ( req.body.referral_code ) { - referred_by_user = await get_user({ referral_code: req.body.referral_code }); - if ( ! referred_by_user ) { - return res.status(400).send('Referral code not found'); - } - } - - // ----------------------------------- - // New User - // ----------------------------------- - const user_uuid = uuidv4(); - const email_confirm_token = uuidv4(); - let insert_res; - let email_confirm_code = Math.floor(100000 + Math.random() * 900000); - - if(pseudo_user === undefined){ - insert_res = await db.write( - `INSERT INTO user - (username, email, password, uuid, referrer, email_confirm_code, email_confirm_token, free_storage, referred_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, - [ - // username - req.body.username, - // email - req.body.is_temp ? null : req.body.email, - // password - req.body.is_temp ? null : await bcrypt.hash(req.body.password, 8), - // uuid - user_uuid, - // referrer - req.body.referrer ?? null, - // email_confirm_code - email_confirm_code, - // email_confirm_token - email_confirm_token, - // free_storage - config.storage_capacity, - // referred_by - referred_by_user ? referred_by_user.id : null, - ]); - - // record activity - db.write( - 'UPDATE `user` SET `last_activity_ts` = now() WHERE id=? LIMIT 1', - [insert_res.insertId] - ); - - // TODO: cache group id - const svc_group = req.services.get('group'); - await svc_group.add_users({ - uid: req.body.is_temp ? - config.default_temp_group : config.default_user_group, - users: [req.body.username] - }); - } - // ----------------------------------- - // Pseudo User converting - // ----------------------------------- - else{ - insert_res = await db.write( - `UPDATE user SET - username = ?, password = ?, uuid = ?, email_confirm_code = ?, email_confirm_token = ?, email_confirmed = ?, requires_email_confirmation = 1, - referred_by = ? - WHERE id = ?`, - [ - // username - req.body.username, - // password - await bcrypt.hash(req.body.password, 8), - // uuid - user_uuid, - // email_confirm_code - email_confirm_code, - // email_confirm_token - email_confirm_token, - // email_confirmed - !email_confirmation_required, - // id - pseudo_user.id, - // referred_by - referred_by_user ? referred_by_user.id : null, - ] - ); - - // TODO: cache group ids - const svc_group = req.services.get('group'); - await svc_group.remove_users({ - uid: config.default_temp_group, - users: [req.body.username], - }); - await svc_group.add_users({ - uid: config.default_user_group, - users: [req.body.username] - }); - - // record activity - db.write('UPDATE `user` SET `last_activity_ts` = now() WHERE id=? LIMIT 1', [pseudo_user.id]); - invalidate_cached_user_by_id(pseudo_user.id); - } - - // user id - // todo if pseudo user, assign directly no need to do another DB lookup - const user_id = (pseudo_user === undefined) ? insert_res.insertId : pseudo_user.id; - - const [user] = await db.pread( - 'SELECT * FROM `user` WHERE `id` = ? LIMIT 1', - [user_id] + + // check bot trap, if `p102xyzname` is anything but an empty string it means + // that a bot has filled the form + // doesn't apply to temp users + if(!req.body.is_temp && req.body.p102xyzname !== '') + return res.send(); + + // check if user is already logged in + if ( req.body.is_temp && req.cookies[config.cookie_name] ) { + const { user, token } = await svc_auth.check_session( + req.cookies[config.cookie_name] ); - - // create token for login - const { token } = await svc_auth.create_session_token(user, { - req, - }); - // jwt.sign({uuid: user_uuid}, config.jwt_secret); - - //------------------------------------------------------------- - // email confirmation - //------------------------------------------------------------- - if((!req.body.is_temp && email_confirmation_required) || user.requires_email_confirmation){ - if(req.body.send_confirmation_code || user.requires_email_confirmation) - send_email_verification_code(email_confirm_code, user.email); - else - send_email_verification_token(user.email_confirm_token, user.email, user.uuid); - } - - //------------------------------------------------------------- - // referral code - //------------------------------------------------------------- - let referral_code; - if ( pseudo_user === undefined ) { - const svc_referralCode = Context.get('services') - .get('referral-code', { optional: true }); - if ( svc_referralCode ) { - referral_code = await svc_referralCode.gen_referral_code(user); - } - } - - await generate_system_fsentries(user); - - //set cookie res.cookie(config.cookie_name, token, { sameSite: 'none', secure: true, httpOnly: true, }); - - // add to mailchimp - if(!req.body.is_temp){ - const svc_event = Context.get('services').get('event'); - svc_event.emit('user.save_account', { user }); + // const decoded = await jwt.verify(token, config.jwt_secret); + // const user = await get_user({ uuid: decoded.uuid }); + if ( user ) { + return res.send({ + token: token, + user: { + username: user.username, + uuid: user.uuid, + email: user.email, + email_confirmed: user.email_confirmed, + requires_email_confirmation: user.requires_email_confirmation, + is_temp: (user.password === null && user.email === null), + taskbar_items: await get_taskbar_items(user), + } + }); + } + } + + // temporary user + if(req.body.is_temp && !config.disable_temp_users){ + req.body.username = await generate_random_username(); + req.body.email = req.body.username + '@gmail.com'; + req.body.password = 'sadasdfasdfsadfsa'; + }else if(config.disable_temp_users){ + return res.status(400).send('Temp users are disabled.'); + } + + // send_confirmation_code + req.body.send_confirmation_code = req.body.send_confirmation_code ?? true; + + // username is required + if(!req.body.username) + return res.status(400).send('Username is required') + // username must be a string + else if (typeof req.body.username !== 'string') + return res.status(400).send('username must be a string.') + // check if username is valid + else if(!req.body.username.match(config.username_regex)) + return res.status(400).send('Username can only contain letters, numbers and underscore (_).') + // check if username is of proper length + else if(req.body.username.length > config.username_max_length) + return res.status(400).send(`Username cannot be longer than ${config.username_max_length} characters.`) + // check if username matches any reserved words + else if(config.reserved_words.includes(req.body.username)) + return res.status(400).send({message: 'This username is not available.'}); + // TODO: DRY: change_email.js + else if(!req.body.is_temp && !req.body.email) + return res.status(400).send('Email is required'); + // email, if present, must be a string + else if (req.body.email && typeof req.body.email !== 'string') + return res.status(400).send('email must be a string.') + // if email is present, validate it + else if(!req.body.is_temp && !validator.isEmail(req.body.email)) + return res.status(400).send('Please enter a valid email address.') + else if(!req.body.is_temp && !req.body.password) + return res.status(400).send('Password is required'); + // password, if present, must be a string + else if (req.body.password && typeof req.body.password !== 'string') + return res.status(400).send('password must be a string.') + else if(!req.body.is_temp && req.body.password.length < config.min_pass_length) + return res.status(400).send(`Password must be at least ${config.min_pass_length} characters long.`); + + // duplicate username check + if(await username_exists(req.body.username)) + return res.status(400).send('This username already exists in our database. Please use another one.'); + // duplicate email check (pseudo-users don't count) + let rows2 = await db.read(`SELECT EXISTS(SELECT 1 FROM user WHERE email=? AND password IS NOT NULL) AS email_exists`, [req.body.email]); + if(rows2[0].email_exists) + return res.status(400).send('This email already exists in our database. Please use another one.'); + // get pseudo user, if exists + let pseudo_user = await db.read(`SELECT * FROM user WHERE email = ? AND password IS NULL`, [req.body.email]); + pseudo_user = pseudo_user[0]; + // get uuid user, if exists + if(req.body.uuid){ + uuid_user = await db.read(`SELECT * FROM user WHERE uuid = ? LIMIT 1`, [req.body.uuid]); + uuid_user = uuid_user[0]; + } + + // email confirmation is required by default unless: + // Pseudo user converting and matching uuid is provided + let email_confirmation_required = 1; + if(pseudo_user && uuid_user && pseudo_user.id === uuid_user.id) + email_confirmation_required = 0; + + // ----------------------------------- + // Get referral user + // ----------------------------------- + let referred_by_user = undefined; + if ( req.body.referral_code ) { + referred_by_user = await get_user({ referral_code: req.body.referral_code }); + if ( ! referred_by_user ) { + return res.status(400).send('Referral code not found'); + } + } + + // ----------------------------------- + // New User + // ----------------------------------- + const user_uuid = uuidv4(); + const email_confirm_token = uuidv4(); + let insert_res; + let email_confirm_code = Math.floor(100000 + Math.random() * 900000); + + if(pseudo_user === undefined){ + insert_res = await db.write( + `INSERT INTO user + (username, email, password, uuid, referrer, email_confirm_code, email_confirm_token, free_storage, referred_by) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`, + [ + // username + req.body.username, + // email + req.body.is_temp ? null : req.body.email, + // password + req.body.is_temp ? null : await bcrypt.hash(req.body.password, 8), + // uuid + user_uuid, + // referrer + req.body.referrer ?? null, + // email_confirm_code + email_confirm_code, + // email_confirm_token + email_confirm_token, + // free_storage + config.storage_capacity, + // referred_by + referred_by_user ? referred_by_user.id : null, + ]); + + // record activity + db.write( + 'UPDATE `user` SET `last_activity_ts` = now() WHERE id=? LIMIT 1', + [insert_res.insertId] + ); + + // TODO: cache group id + const svc_group = req.services.get('group'); + await svc_group.add_users({ + uid: req.body.is_temp ? + config.default_temp_group : config.default_user_group, + users: [req.body.username] + }); + } + // ----------------------------------- + // Pseudo User converting + // ----------------------------------- + else{ + insert_res = await db.write( + `UPDATE user SET + username = ?, password = ?, uuid = ?, email_confirm_code = ?, email_confirm_token = ?, email_confirmed = ?, requires_email_confirmation = 1, + referred_by = ? + WHERE id = ?`, + [ + // username + req.body.username, + // password + await bcrypt.hash(req.body.password, 8), + // uuid + user_uuid, + // email_confirm_code + email_confirm_code, + // email_confirm_token + email_confirm_token, + // email_confirmed + !email_confirmation_required, + // id + pseudo_user.id, + // referred_by + referred_by_user ? referred_by_user.id : null, + ] + ); + + // TODO: cache group ids + const svc_group = req.services.get('group'); + await svc_group.remove_users({ + uid: config.default_temp_group, + users: [req.body.username], + }); + await svc_group.add_users({ + uid: config.default_user_group, + users: [req.body.username] + }); + + // record activity + db.write('UPDATE `user` SET `last_activity_ts` = now() WHERE id=? LIMIT 1', [pseudo_user.id]); + invalidate_cached_user_by_id(pseudo_user.id); + } + + // user id + // todo if pseudo user, assign directly no need to do another DB lookup + const user_id = (pseudo_user === undefined) ? insert_res.insertId : pseudo_user.id; + + const [user] = await db.pread( + 'SELECT * FROM `user` WHERE `id` = ? LIMIT 1', + [user_id] + ); + + // create token for login + const { token } = await svc_auth.create_session_token(user, { + req, + }); + // jwt.sign({uuid: user_uuid}, config.jwt_secret); + + //------------------------------------------------------------- + // email confirmation + //------------------------------------------------------------- + if((!req.body.is_temp && email_confirmation_required) || user.requires_email_confirmation){ + if(req.body.send_confirmation_code || user.requires_email_confirmation) + send_email_verification_code(email_confirm_code, user.email); + else + send_email_verification_token(user.email_confirm_token, user.email, user.uuid); + } + + //------------------------------------------------------------- + // referral code + //------------------------------------------------------------- + let referral_code; + if ( pseudo_user === undefined ) { + const svc_referralCode = Context.get('services') + .get('referral-code', { optional: true }); + if ( svc_referralCode ) { + referral_code = await svc_referralCode.gen_referral_code(user); } - - // return results - return res.send({ - token: token, - user:{ - username: user.username, - uuid: user.uuid, - email: user.email, - email_confirmed: user.email_confirmed, - requires_email_confirmation: user.requires_email_confirmation, - is_temp: (user.password === null && user.email === null), - taskbar_items: await get_taskbar_items(user), - referral_code, - } - }) } + + await generate_system_fsentries(user); + + //set cookie + res.cookie(config.cookie_name, token, { + sameSite: 'none', + secure: true, + httpOnly: true, + }); + + // add to mailchimp + if(!req.body.is_temp){ + const svc_event = Context.get('services').get('event'); + svc_event.emit('user.save_account', { user }); + } + + // return results + return res.send({ + token: token, + user:{ + username: user.username, + uuid: user.uuid, + email: user.email, + email_confirmed: user.email_confirmed, + requires_email_confirmation: user.requires_email_confirmation, + is_temp: (user.password === null && user.email === null), + taskbar_items: await get_taskbar_items(user), + referral_code, + } + }) }); From 5857248651d521f098d86b9251130274322c7c7f Mon Sep 17 00:00:00 2001 From: Yasmeen Date: Mon, 26 Aug 2024 10:49:51 +0300 Subject: [PATCH 0780/2119] Add Arabic Translation file --- doc/i18n/README.ar.md | 133 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 133 insertions(+) create mode 100644 doc/i18n/README.ar.md diff --git a/doc/i18n/README.ar.md b/doc/i18n/README.ar.md new file mode 100644 index 0000000000..d7c23240d2 --- /dev/null +++ b/doc/i18n/README.ar.md @@ -0,0 +1,133 @@ +

Puter.com، الحاسوب السحابي الشخصي: جميع ملفاتك وتطبيقاتك وألعابك في مكان واحد يمكن الوصول إليه من أي مكان في أي وقت.

+ +

نظام تشغيل الإنترنت! مجاني ومفتوح المصدر وقابل للاستضافة الذاتية.

+ +

+ GitHub repo size GitHub Release GitHub License +

+

+ « عرض توضيحي مباشر » +
+
+ Puter.com + · + مجموعة أدوات التطوير + · + ديسكورد + · + يوتيوب + · + ريديت + · + إكس (تويتر) + · + مكافأة اكتشاف الثغرات +

+ +

لقطة شاشة

+ +
+ +## بيوتر + +
+

بيوتر هو نظام تشغيل إنترنت متقدم ومفتوح المصدر، مصمم ليكون غنيًا بالميزات وسريعًا بشكل استثنائي وقابلًا للتوسع بدرجة كبيرة. يمكن استخدام بيوتر كـ:

+ +
    +
  • سحابة شخصية تعطي الأولوية للخصوصية لحفظ جميع ملفاتك وتطبيقاتك وألعابك في مكان آمن واحد، يمكن الوصول إليه من أي مكان وفي أي وقت.
  • +
  • منصة لبناء ونشر المواقع الإلكترونية وتطبيقات الويب والألعاب
  • +
  • بديل لـ Dropbox وGoogle Drive وOneDrive وغيرها، مع واجهة جديدة وميزات قوية.
  • +
  • بيئة سطح مكتب عن بُعد للخوادم ومحطات العمل.
  • +
  • مشروع ومجتمع ودود ومفتوح المصدر للتعلم عن تطوير الويب والحوسبة السحابية والأنظمة الموزعة والكثير غير ذلك!
  • +
+
+ +
+ +## البدء + +### 💻 التطوير المحلي + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +سيؤدي هذا إلى تشغيل Puter على http://puter.localhost:4100 (أو المنفذ التالي المتاح). + +
+ +### 🐳 دوكر + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ +### 🐙 دوكر كومبوز + +#### لينكس/ماك + +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` + +
+ +#### ويندوز + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` + +
+ +### ☁️ موقع Puter.com + +متاح Puter كخدمة مستضافة على[**puter.com**](https://puter.com)الموقع + +
+ +## متطلبات النظام + +- **Operating Systems:** لينكس، ماك، ويندوز +- **RAM** ٢ جيجابايت كحد أدنى (يوصى بـ ٤ جيجابايت) +- **Disk Space:** ١ جيجابايت مساحة حرة +- **Node.js:** الإصدار ١٦+ (يوصى بالإصدار ٢٢+) +- **npm:** أحدث إصدار مستقر + +
+ +## الدعم + +تواصل مع المشرفين والمجتمع من خلال هذه القنوات: + +- تقرير عن خطأ أو طلب ميزة؟ الرجاء [فتح مشكلة](https://github.com/HeyPuter/puter/issues/new/choose) + +- دسكورد: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- إكس (تويتر): [x.com/HeyPuter](https://x.com/HeyPuter) +- ريديت: [/reddit.com/r/puter](https://www.reddit.com/r/puter/) +- ماستودون: [mastodon.social/@puter](https://mastodon.social/@puter) +- مشاكل أمنية؟ [security@puter.com](mailto:security@puter.com) +- البريد الإلكتروني للمشرفين [hi@puter.com](mailto:hi@puter.com) + +نحن دائمًا سعداء لمساعدتك في أي أسئلة قد تكون لديك. لا تتردد في السؤال! + +
+ +## الترخيص + +هذا المستودع، بما في ذلك جميع محتوياته ومشاريعه الفرعية ووحداته ومكوناته، مرخص تحت [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) ما لم ينص على خلاف ذلك صراحةً. قد تخضع المكتبات الخارجية المدرجة في هذا المستودع لتراخيصها الخاصة. + +
From 577e0d4ed93fc3e8c7fa1ec7d7300c43d74b9fb5 Mon Sep 17 00:00:00 2001 From: Yasmeen Albalooshi Date: Mon, 26 Aug 2024 10:54:05 +0300 Subject: [PATCH 0781/2119] Update README.md to have Arabic Translation --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e626fabeb6..ba0ad1625f 100644 --- a/README.md +++ b/README.md @@ -132,6 +132,7 @@ This repository, including all its contents, sub-projects, modules, and componen ## Translations +- [Arabic / العربية](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ar.md) - [Bengali / বাংলা](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.bn.md) - [Chinese / 中文](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.zh.md) - [Danish / Dansk](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.da.md) From 11304d82c3229becc8d7647390397aaddd307510 Mon Sep 17 00:00:00 2001 From: VinayakPaka Date: Mon, 26 Aug 2024 20:34:51 +0530 Subject: [PATCH 0782/2119] translated README.en.md from English to Polish --- doc/i18n/README.pl.md | 123 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 doc/i18n/README.pl.md diff --git a/doc/i18n/README.pl.md b/doc/i18n/README.pl.md new file mode 100644 index 0000000000..0c82105426 --- /dev/null +++ b/doc/i18n/README.pl.md @@ -0,0 +1,123 @@ +

Puter.com, Osobisty Komputer Chmurowy: Wszystkie twoje pliki, aplikacje i gry w jednym miejscu, dostępne z dowolnego miejsca o dowolnej porze.

+

System Operacyjny Internetu! Darmowy, Open-Source i Możliwy do Samodzielnego Hostowania.

+

+ Rozmiar repozytorium GitHub Wydanie GitHub Licencja GitHub +

+

+ « DEMO NA ŻYWO » +
+
+ Puter.com + · + SDK + · + Discord + · + YouTube + · + Reddit + · + X (Twitter) + · + Bug Bounty +

+

zrzut ekranu

+
+ +## Puter + +Puter to zaawansowany, open-source'owy system operacyjny internetowy, zaprojektowany tak, aby był bogaty w funkcje, wyjątkowo szybki i wysoce rozszerzalny. Puter może być używany jako: + +- Prywatna chmura osobista do przechowywania wszystkich plików, aplikacji i gier w jednym bezpiecznym miejscu, dostępnym z dowolnego miejsca o dowolnej porze. +- Platforma do budowania i publikowania stron internetowych, aplikacji webowych i gier. +- Alternatywa dla Dropbox, Google Drive, OneDrive itp. ze świeżym interfejsem i potężnymi funkcjami. +- Zdalne środowisko pulpitu dla serwerów i stacji roboczych. +- Przyjazny, open-source'owy projekt i społeczność do nauki o tworzeniu stron internetowych, chmurze obliczeniowej, systemach rozproszonych i wielu innych! + +
+ +## Rozpoczęcie pracy +## 💻 Rozwój lokalny + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` +To uruchomi Puter na http://puter.localhost:4100 (lub na następnym dostępnym porcie). + +
+ +## 🐳 Docker + +```bash +Copy code +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` +
+ +## 🐙 Docker Compose +## Linux/macOS + +```bash +Copy code +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` +
+ +## Windows + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +## ☁️ Puter.com +Puter jest dostępny jako usługa hostowana na [**puter.com**](https://puter.com). + +
+ +## Wymagania systemowe + +- **Systemy operacyjne:** Linux, macOS, Windows +- **RAM:** Minimum 2GB (zalecane 4GB) +- **Przestrzeń dyskowa:** 1GB wolnego miejsca +- **Node.js:** Wersja 16+ (zalecana wersja 22+) +- **npm:** Najnowsza stabilna wersja + +
+ +## Wsparcie + +Połącz się z opiekunami i społecznością przez te kanały: + +- Raport o błędzie lub prośba o funkcję? Proszę otworzyć zgłoszenie. +- Discord: discord.com/invite/PQcx7Teh8u +- X (Twitter): x.com/HeyPuter +- Reddit: reddit.com/r/puter/ +- Mastodon: mastodon.social/@puter +- Problemy z bezpieczeństwem? security@puter.com +- Email do opiekunów: hi@puter.com + +Zawsze chętnie pomożemy Ci z wszelkimi pytaniami, jakie możesz mieć. Nie wahaj się pytać! +
+ +## Licencja + +To repozytorium, w tym cała jego zawartość, podprojekty, moduły i komponenty, jest licencjonowane na podstawie [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt), chyba że wyraźnie zaznaczono inaczej. Biblioteki stron trzecich zawarte w tym repozytorium mogą podlegać własnym licencjom. + +
+ + + + + From 683c20ca7f4d50299651e7306c9464b33dafb84f Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Mon, 26 Aug 2024 09:22:39 -0700 Subject: [PATCH 0783/2119] Add links to Korean and Polish READMEs in the English README --- README.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/README.md b/README.md index ba0ad1625f..5c2eaa7b51 100644 --- a/README.md +++ b/README.md @@ -142,6 +142,8 @@ This repository, including all its contents, sub-projects, modules, and componen - [Indonesian / Bahasa Indonesia](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.id.md) - [Italian / Italiano](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.it.md) - [Japanese / 日本語](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.jp.md) +- [Korean / 한국어](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ko.md) +- [Polish / Polski](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.pl.md) - [Portuguese / Português](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.pt.md) - [Romanian / Română](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ro.md) - [Russian / Русский](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ru.md) From d2c7477b3bf170be492a6d5387330645cdf9c33a Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 26 Aug 2024 17:42:15 -0400 Subject: [PATCH 0784/2119] fix(docker): ensure temp admin pass shows --- .../modules/selfhosted/DefaultUserService.js | 14 ++++++++++++- src/backend/src/services/DevConsoleService.js | 21 +++++++++++++++++-- 2 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/backend/src/modules/selfhosted/DefaultUserService.js b/src/backend/src/modules/selfhosted/DefaultUserService.js index a5873cecc8..8afa40d51a 100644 --- a/src/backend/src/modules/selfhosted/DefaultUserService.js +++ b/src/backend/src/modules/selfhosted/DefaultUserService.js @@ -90,7 +90,18 @@ class DefaultUserService extends BaseService { if ( ! is_default_password ) return; // show console widget - this.default_user_widget = () => { + this.default_user_widget = ({ is_docker }) => { + if ( is_docker ) { + // In Docker we keep the output as simple as possible because + // we're unable to determine the size of the terminal + return [ + 'Password for `admin`: ' + tmp_password, + // TODO: possible bug + // These blank lines are necessary for it to render and + // I'm not entirely sure why anymore. + '', '', + ]; + } const lines = [ `Your admin user has been created!`, `\x1B[31;1musername:\x1B[0m ${USERNAME}`, @@ -100,6 +111,7 @@ class DefaultUserService extends BaseService { surrounding_box('31;1', lines); return lines; }; + this.default_user_widget.critical = true; this.start_poll_({ tmp_password, user }); const svc_devConsole = this.services.get('dev-console'); svc_devConsole.add_widget(this.default_user_widget); diff --git a/src/backend/src/services/DevConsoleService.js b/src/backend/src/services/DevConsoleService.js index 1556c902a3..93910ac665 100644 --- a/src/backend/src/services/DevConsoleService.js +++ b/src/backend/src/services/DevConsoleService.js @@ -20,11 +20,26 @@ const { consoleLogManager } = require('../util/consolelog'); const BaseService = require('./BaseService'); class DevConsoleService extends BaseService { + static MODULES = { + fs: require('fs'), + } + _construct () { this.static_lines = []; this.widgets = []; this.identifiers = {}; this.has_updates = false; + + try { + const require = this.require; + const fs = require('fs'); + this.is_docker = fs.existsSync('/.dockerenv'); + } catch (e) { + // if this fails, we assume is_docker should + // be false. + this.log.error(e.message); + this.is_docker = false; + } } turn_on_the_warning_lights () { @@ -60,7 +75,7 @@ class DevConsoleService extends BaseService { let positions = []; for ( const w of this.widgets ) { let output; try { - output = w(); + output = w({ is_docker: this.is_docker }); } catch ( e ) { consoleLogManager.log_raw('error', e); to_remove.push(w); @@ -78,6 +93,7 @@ class DevConsoleService extends BaseService { for ( let i = this.widgets.length-1 ; i >= 0 ; i-- ) { if ( size_ok() ) break; const w = this.widgets[i]; + if ( w.critical ) continue; if ( ! w.unimportant ) continue; n_hidden++; const [start, length] = positions[i]; @@ -89,8 +105,9 @@ class DevConsoleService extends BaseService { } for ( let i = this.widgets.length-1 ; i >= 0 ; i-- ) { if ( size_ok() ) break; - n_hidden++; const w = this.widgets[i]; + if ( w.critical ) continue; + n_hidden++; const [start, length] = positions[i]; this.static_lines.splice(start, length); } From aa61c3009c624099e7bd518870b18b02c008530c Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 26 Aug 2024 17:43:33 -0400 Subject: [PATCH 0785/2119] fix: typo in a default file --- src/backend/src/modules/selfhosted/DefaultUserService.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/src/modules/selfhosted/DefaultUserService.js b/src/backend/src/modules/selfhosted/DefaultUserService.js index 8afa40d51a..db1c5d087b 100644 --- a/src/backend/src/modules/selfhosted/DefaultUserService.js +++ b/src/backend/src/modules/selfhosted/DefaultUserService.js @@ -42,7 +42,7 @@ const DEFAULT_FILES = { } }, "es": { - "date-limit": { + "rate-limit": { "max": 1000, "period": 30000 } From 45925bacb6375f860484afcbd3881bc483d1395a Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 27 Aug 2024 17:11:48 -0700 Subject: [PATCH 0786/2119] Improve the usability of the Settings tab in Dev Center --- src/dev-center/css/style.css | 1 + src/dev-center/js/dev-center.js | 85 ++++++++++++++++++++++----------- 2 files changed, 58 insertions(+), 28 deletions(-) diff --git a/src/dev-center/css/style.css b/src/dev-center/css/style.css index 02a9f37672..cc32ab3a59 100644 --- a/src/dev-center/css/style.css +++ b/src/dev-center/css/style.css @@ -264,6 +264,7 @@ section { label, input[type="text"] { display: block; + user-select: none; } #delete-app { diff --git a/src/dev-center/js/dev-center.js b/src/dev-center/js/dev-center.js index 9be94f519e..a603f3d248 100644 --- a/src/dev-center/js/dev-center.js +++ b/src/dev-center/js/dev-center.js @@ -475,6 +475,7 @@ function generate_edit_app_section(app) {
App has been successfully updated.×
+

Basic Info

@@ -487,58 +488,60 @@ function generate_edit_app_section(app) { + +
+
Change App Icon
+
+ Remove icon + + + + + +

A comma-separated list of file type specifiers. For example if you include .txt, your apps could be opened when a user clicks on a TXT file.

+ + +

Window Settings

- +
- +
- - - - + + + +
- - - - + + + +
- - + +
- - + +
- -
-
Change App Icon
-
- Remove icon - - - - - -

A comma-separated list of file type specifiers. For example if you include .txt, your apps could be opened when a user clicks on a TXT file.

- - +
@@ -2084,4 +2087,30 @@ $(document).on('change', '#edit-app-maximize-on-start', function (e) { $('#edit-app-window-width, #edit-app-window-height').prop('disabled', false); $('#edit-app-window-top, #edit-app-window-left').prop('disabled', false); } -}) \ No newline at end of file +}) + +$(document).on('change', '#edit-app-background', function (e) { + if($('#edit-app-background').is(":checked")){ + disable_window_settings() + }else{ + enable_window_settings() + } +}) + +function disable_window_settings(){ + $('#edit-app-maximize-on-start').prop('disabled', true); + $('#edit-app-fullpage-on-landing').prop('disabled', true); + $('#edit-app-window-width, #edit-app-window-height').prop('disabled', true); + $('#edit-app-window-top, #edit-app-window-left').prop('disabled', true); + $('#edit-app-window-resizable').prop('disabled', true); + $('#edit-app-hide-titlebar').prop('disabled', true); +} + +function enable_window_settings(){ + $('#edit-app-maximize-on-start').prop('disabled', false); + $('#edit-app-fullpage-on-landing').prop('disabled', false); + $('#edit-app-window-width, #edit-app-window-height').prop('disabled', false); + $('#edit-app-window-top, #edit-app-window-left').prop('disabled', false); + $('#edit-app-window-resizable').prop('disabled', false); + $('#edit-app-hide-titlebar').prop('disabled', false); +} \ No newline at end of file From b1c91758da455d4c9e1a968b7ff98cdd86ecdbb8 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 27 Aug 2024 17:27:40 -0700 Subject: [PATCH 0787/2119] Fix sort bug in dev center --- src/dev-center/js/dev-center.js | 34 ++++++++++++++++++++++++++------- 1 file changed, 27 insertions(+), 7 deletions(-) diff --git a/src/dev-center/js/dev-center.js b/src/dev-center/js/dev-center.js index a603f3d248..759eac2394 100644 --- a/src/dev-center/js/dev-center.js +++ b/src/dev-center/js/dev-center.js @@ -519,9 +519,9 @@ function generate_edit_app_section(app) {
- + - +
@@ -1318,11 +1318,31 @@ function sort_apps() { let sorted_apps; // sort - if (sortDirection === 'asc') - sorted_apps = apps.sort((a, b) => a[sortBy] > b[sortBy] ? 1 : -1); - else - sorted_apps = apps.sort((a, b) => a[sortBy] < b[sortBy] ? 1 : -1); - + if (sortDirection === 'asc'){ + sorted_apps = apps.sort((a, b) => { + if(sortBy === 'name'){ + return a[sortBy].localeCompare(b[sortBy]); + }else if(sortBy === 'created_at'){ + return new Date(a[sortBy]) - new Date(b[sortBy]); + } else if(sortBy === 'user_count' || sortBy === 'open_count'){ + return a.stats[sortBy] - b.stats[sortBy]; + }else{ + a[sortBy] > b[sortBy] ? 1 : -1 + } + }); + }else{ + sorted_apps = apps.sort((a, b) => { + if(sortBy === 'name'){ + return b[sortBy].localeCompare(a[sortBy]); + }else if(sortBy === 'created_at'){ + return new Date(b[sortBy]) - new Date(a[sortBy]); + } else if(sortBy === 'user_count' || sortBy === 'open_count'){ + return b.stats[sortBy] - a.stats[sortBy]; + }else{ + b[sortBy] > a[sortBy] ? 1 : -1 + } + }); + } // refresh app list $('.app-card').remove(); sorted_apps.forEach(app => { From d285c2097f1c388ebfb36de25c574b1c9f744262 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 27 Aug 2024 17:34:09 -0700 Subject: [PATCH 0788/2119] use flexbox for app navbar in dev center --- src/dev-center/css/style.css | 6 +++++- src/dev-center/js/dev-center.js | 2 +- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/dev-center/css/style.css b/src/dev-center/css/style.css index cc32ab3a59..a63c149606 100644 --- a/src/dev-center/css/style.css +++ b/src/dev-center/css/style.css @@ -855,7 +855,11 @@ ol li:before { float:right; margin-bottom: 10px; } .edit-app-navbar{ - overflow: hidden; margin-bottom: 60px; margin-top: 20px; + overflow: hidden; + margin-bottom: 60px; + margin-top: 20px; + display: flex; + align-items: center; } .app-title{ margin-top:0px; diff --git a/src/dev-center/js/dev-center.js b/src/dev-center/js/dev-center.js index 759eac2394..6cda685345 100644 --- a/src/dev-center/js/dev-center.js +++ b/src/dev-center/js/dev-center.js @@ -440,7 +440,7 @@ function generate_edit_app_section(app) { let h = ``; h += `
-
+

${html_encode(app.title)}

From 2385457d125ce9ccba8b0960e8bddbce18ed020a Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 27 Aug 2024 18:04:04 -0700 Subject: [PATCH 0789/2119] Remove the redundant `image/` prefix in base64 encoded app icons in dev center --- src/dev-center/index.html | 2 +- src/dev-center/js/dev-center.js | 2 +- src/gui/src/UI/UIDesktop.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/dev-center/index.html b/src/dev-center/index.html index e69ecda565..4046b446ef 100644 --- a/src/dev-center/index.html +++ b/src/dev-center/index.html @@ -245,7 +245,7 @@

My Apps

- + diff --git a/src/dev-center/js/dev-center.js b/src/dev-center/js/dev-center.js index 6cda685345..f45e958e2e 100644 --- a/src/dev-center/js/dev-center.js +++ b/src/dev-center/js/dev-center.js @@ -1111,7 +1111,7 @@ $(document).on('click', '#edit-app-icon', async function (e) { let mimeType = getMimeType(fileExtension); // Replace MIME type in the data URL - image = image.replace('data:application/octet-stream;base64', `data:image/${mimeType};base64`); + image = image.replace('data:application/octet-stream;base64', `data:${mimeType};base64`); $('#edit-app-icon').css('background-image', `url(${image})`); $('#edit-app-icon').attr('data-base64', image); diff --git a/src/gui/src/UI/UIDesktop.js b/src/gui/src/UI/UIDesktop.js index 7959643ac0..18d5e4d1c5 100644 --- a/src/gui/src/UI/UIDesktop.js +++ b/src/gui/src/UI/UIDesktop.js @@ -986,7 +986,7 @@ async function UIDesktop(options){ // 'show desktop' if(window.is_fullpage_mode){ - ht += `Show Desktop `; + ht += `Show Desktop `; } // refer From 2d1cb0050ddf0db44784f76231c5afa7792015c5 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 27 Aug 2024 22:20:32 -0400 Subject: [PATCH 0790/2119] dev: puter-wisp --- src/puter-wisp/README.md | 102 +++++ src/puter-wisp/basic.html | 412 ++++++++++++++++++ .../devlog/unit_test_usefulness/a.js | 297 +++++++++++++ .../devlog/unit_test_usefulness/b.js | 307 +++++++++++++ .../devlog/unit_test_usefulness/test_a_b.diff | 18 + src/puter-wisp/package.json | 15 + src/puter-wisp/src/exports.js | 298 +++++++++++++ src/puter-wisp/test/test.js | 50 +++ 8 files changed, 1499 insertions(+) create mode 100644 src/puter-wisp/README.md create mode 100644 src/puter-wisp/basic.html create mode 100644 src/puter-wisp/devlog/unit_test_usefulness/a.js create mode 100644 src/puter-wisp/devlog/unit_test_usefulness/b.js create mode 100644 src/puter-wisp/devlog/unit_test_usefulness/test_a_b.diff create mode 100644 src/puter-wisp/package.json create mode 100644 src/puter-wisp/src/exports.js create mode 100644 src/puter-wisp/test/test.js diff --git a/src/puter-wisp/README.md b/src/puter-wisp/README.md new file mode 100644 index 0000000000..bfbab20d3d --- /dev/null +++ b/src/puter-wisp/README.md @@ -0,0 +1,102 @@ +# Wisp Utilities + +This is still a work in progress. Thes utilities use my own stream interface +to avoid browser/node compatibility issues and because I found it more +convenient. These streams can by used as async iterator objects just like +other conventional implementations. Currently there is no logic for closing +streams or knowing if a stream has been closed, but this is planned. + +## Classes and Factory Functions + +### WispPacket (class) + +Wraps a Uint8Array containing a Wisp packet. `data` should be a Uint8Array +containing only the Wisp frame, starting at the Packet Type and ending at +the last byte of the payload (inclusive). + +```javascript +const packet = new WispPacket({ + data: new Uint8Array(...), + direction: WispPacket.SEND, // or RECV + + // `extra` is optional, for debugging + extra: { some: 'value', }, +}); + +packet.type; // ex: WispPacket.CONTINUE +``` + +#### Methods + +- `describe()` - outputs a summary string + ```javascript + packet.describe(); + // ex: "INFO v2.0 f000000000" + ``` +- `toVirtioFrame` - prepends the size of the Wisp frame (u32LE) +- `log()` - prints a collapsed console group +- `reflect()` - returns a reflected version of the packet (flips `SEND` and `RECV`) + +### NewCallbackByteStream (function) + +Returns a stream for values that get passed through a callback interface. +The stream object (an async iterator object) has a property called +`listener` which can be passed as a listener or called directly. This +listener expects only one argument which is the data to pass through the +stream (typically a value of type `Uint8Array`). + +```javascript +const byteStream = NewCallbackByteStream(); +emulator.add_listener('virtio-console0-output-bytes', + byteStream.listener); +``` + +### NewVirtioFrameStream (function) + +Takes in a byte stream (stream of `Uint8Array`) and assumes that this byte +stream contains integers (u32LE) describing the length (in bytes) of data, +followed by the data. Returns a stream which outputs a complete chunk of +data (as per the specified length) as each value, excluding the bytes that +describe the length. + +```javascript +const virtioStream = NewVirtioFrameStream(byteStream); +``` + +### NewWispPacketStream (function) + +Takes in a stream of `Uint8Array`s, each containing a complete Wisp packet, +and outputs a stream of instances of **WispPacket** + +## Example Use with v86 + +```javascript +const emulator = new V86(...); + +// Get a byte stream for /dev/hvc0 +const byteStream = NewCallbackByteStream(); +emulator.add_listener('virtio-console0-output-bytes', + byteStream.listener); + +// Get a stream of frames with prepended byte lengths +// (for example, `twisp` uses this format) +const virtioStream = NewVirtioFrameStream(byteStream); + +// Get a stream of WispPacket objects +const wispStream = NewWispPacketStream(virtioStream); + +// Async iterator +(async () => { + for ( const packet of wispStream ) { + console.log('Wisp packet!', packet.describe()); + + // Let's send back a reflected packet for INFO! + if ( packet.type === WispPacket.INFO ) { + emulator.bus.send( + 'virtio-console0-input-bytes', + packet.toVirtioFrame(), + ); + } + } +})(); +``` diff --git a/src/puter-wisp/basic.html b/src/puter-wisp/basic.html new file mode 100644 index 0000000000..07bbfb3f26 --- /dev/null +++ b/src/puter-wisp/basic.html @@ -0,0 +1,412 @@ + +Basic Emulator + + + + + + +
+
+ +
diff --git a/src/puter-wisp/devlog/unit_test_usefulness/a.js b/src/puter-wisp/devlog/unit_test_usefulness/a.js new file mode 100644 index 0000000000..75b99e7d8a --- /dev/null +++ b/src/puter-wisp/devlog/unit_test_usefulness/a.js @@ -0,0 +1,297 @@ +const lib = {}; + +// SO: 40031688 +lib.buf2hex = (buffer) => { // buffer is an ArrayBuffer + return [...new Uint8Array(buffer)] + .map(x => x.toString(16).padStart(2, '0')) + .join(''); +} + +// Tiny inline little-endian integer library +lib.get_int = (n_bytes, array8, signed=false) => { + return (v => signed ? v : v >>> 0)( + array8.slice(0,n_bytes).reduce((v,e,i)=>v|=e<<8*i,0)); +} +lib.to_int = (n_bytes, num) => { + return (new Uint8Array()).map((_,i)=>(num>>8*i)&0xFF); +} + +class ATStream { + constructor ({ delegate, acc, transform, observe }) { + this.delegate = delegate; + if ( acc ) this.acc = acc; + if ( transform ) this.transform = transform; + if ( observe ) this.observe = observe; + this.state = {}; + this.carry = []; + } + [Symbol.asyncIterator]() { return this; } + async next_value_ () { + if ( this.carry.length > 0 ) { + console.log('got from carry!', this.carry); + return { + value: this.carry.shift(), + done: false, + }; + } + return await this.delegate.next(); + } + async acc ({ value }) { + return value; + } + async next_ () { + for (;;) { + const ret = await this.next_value_(); + if ( ret.done ) return ret; + const v = await this.acc({ + state: this.state, + value: ret.value, + carry: v => this.carry.push(v), + }); + if ( this.carry.length >= 0 && v === undefined ) { + throw new Error(`no value, but carry value exists`); + } + if ( v === undefined ) continue; + // We have a value, clear the state! + this.state = {}; + if ( this.transform ) { + const new_value = await this.transform( + { value: ret.value }); + return { ...ret, value: new_value }; + } + return { ...ret, value: v }; + } + } + async next () { + const ret = await this.next_(); + if ( this.observe && !ret.done ) { + this.observe(ret); + } + return ret; + } + async enqueue_ (v) { + this.queue.push(v); + } +} + +const NewCallbackByteStream = () => { + let listener; + let queue = []; + const NOOP = () => {}; + let signal = NOOP; + (async () => { + for (;;) { + const v = await new Promise((rslv, rjct) => { + listener = rslv; + }); + queue.push(v); + signal(); + } + })(); + const stream = { + [Symbol.asyncIterator](){ + return this; + }, + async next () { + if ( queue.length > 0 ) { + return { + value: queue.shift(), + done: false, + }; + } + await new Promise(rslv => { + signal = rslv; + }); + signal = NOOP; + const v = queue.shift(); + return { value: v, done: false }; + } + }; + stream.listener = data => { + listener(data); + }; + return stream; +} + +const NewVirtioFrameStream = byteStream => { + return new ATStream({ + delegate: byteStream, + async acc ({ value, carry }) { + if ( ! this.state.buffer ) { + const size = lib.get_int(4, value); + // 512MiB limit in case of attempted abuse or a bug + // (assuming this won't happen under normal conditions) + if ( size > 512*(1024**2) ) { + throw new Error(`Way too much data! (${size} bytes)`); + } + value = value.slice(4); + this.state.buffer = new Uint8Array(size); + this.state.index = 0; + } + + const needed = this.state.buffer.length - this.state.index; + if ( value.length > needed ) { + const remaining = value.slice(needed); + console.log('we got more bytes than we needed', + needed, + remaining, + value.length, + this.state.buffer.length, + this.state.index, + ); + carry(remaining); + } + + const amount = Math.min(value.length, needed); + const added = value.slice(0, amount); + this.state.buffer.set(added, this.state.index); + this.state.index += amount; + + if ( this.state.index > this.state.buffer.length ) { + throw new Error('WUT'); + } + if ( this.state.index == this.state.buffer.length ) { + return this.state.buffer; + } + } + }); +}; + +const wisp_types = [ + { + id: 3, + label: 'CONTINUE', + describe: ({ payload }) => { + return `buffer: ${lib.get_int(4, payload)}B`; + }, + getAttributes ({ payload }) { + return { + buffer_size: lib.get_int(4, payload), + }; + } + }, + { + id: 5, + label: 'INFO', + describe: ({ payload }) => { + return `v${payload[0]}.${payload[1]} ` + + lib.buf2hex(payload.slice(2)); + }, + getAttributes ({ payload }) { + return { + version_major: payload[0], + version_minor: payload[1], + extensions: payload.slice(2), + } + } + }, +]; + +class WispPacket { + static SEND = Symbol('SEND'); + static RECV = Symbol('RECV'); + constructor ({ data, direction, extra }) { + this.direction = direction; + this.data_ = data; + this.extra = extra ?? {}; + this.types_ = { + 1: { label: 'CONNECT' }, + 2: { label: 'DATA' }, + 4: { label: 'CLOSE' }, + }; + for ( const item of wisp_types ) { + this.types_[item.id] = item; + } + } + get type () { + const i_ = this.data_[0]; + return this.types_[i_]; + } + get attributes () { + if ( ! this.type.getAttributes ) return {}; + const attrs = {}; + Object.assign(attrs, this.type.getAttributes({ + payload: this.data_.slice(5), + })); + Object.assign(attrs, this.extra); + return attrs; + } + toVirtioFrame () { + const arry = new Uint8Array(this.data_.length + 4); + arry.set(lib.to_int(4, this.data_.length), 0); + arry.set(this.data_, 4); + return arry; + } + describe () { + return this.type.label + '(' + + (this.type.describe?.({ + payload: this.data_.slice(5), + }) ?? '?') + ')'; + } + log () { + const arrow = + this.direction === this.constructor.SEND ? '->' : + this.direction === this.constructor.RECV ? '<-' : + '<>' ; + console.groupCollapsed(`WISP ${arrow} ${this.describe()}`); + const attrs = this.attributes; + for ( const k in attrs ) { + console.log(k, attrs[k]); + } + console.groupEnd(); + } + reflect () { + const reflected = new WispPacket({ + data: this.data_, + direction: + this.direction === this.constructor.SEND ? + this.constructor.RECV : + this.direction === this.constructor.RECV ? + this.constructor.SEND : + undefined, + extra: { + reflectedFrom: this, + } + }); + return reflected; + } +} + +for ( const item of wisp_types ) { + WispPacket[item.label] = item; +} + +const NewWispPacketStream = frameStream => { + return new ATStream({ + delegate: frameStream, + transform ({ value }) { + return new WispPacket({ + data: value, + direction: WispPacket.RECV, + }); + }, + observe ({ value }) { + value.log(); + } + }); +} + +class WispClient { + constructor ({ + packetStream, + sendFn, + }) { + this.packetStream = packetStream; + this.sendFn = sendFn; + } + send (packet) { + packet.log(); + this.sendFn(packet); + } +} + +module.exports = { + NewVirtioFrameStream, + NewWispPacketStream, + WispPacket, +}; diff --git a/src/puter-wisp/devlog/unit_test_usefulness/b.js b/src/puter-wisp/devlog/unit_test_usefulness/b.js new file mode 100644 index 0000000000..4cadc52675 --- /dev/null +++ b/src/puter-wisp/devlog/unit_test_usefulness/b.js @@ -0,0 +1,307 @@ +const lib = {}; + +// SO: 40031688 +lib.buf2hex = (buffer) => { // buffer is an ArrayBuffer + return [...new Uint8Array(buffer)] + .map(x => x.toString(16).padStart(2, '0')) + .join(''); +} + +// Tiny inline little-endian integer library +lib.get_int = (n_bytes, array8, signed=false) => { + return (v => signed ? v : v >>> 0)( + array8.slice(0,n_bytes).reduce((v,e,i)=>v|=e<<8*i,0)); +} +lib.to_int = (n_bytes, num) => { + return (new Uint8Array()).map((_,i)=>(num>>8*i)&0xFF); +} + +class ATStream { + constructor ({ delegate, acc, transform, observe }) { + this.delegate = delegate; + if ( acc ) this.acc = acc; + if ( transform ) this.transform = transform; + if ( observe ) this.observe = observe; + this.state = {}; + this.carry = []; + } + [Symbol.asyncIterator]() { return this; } + async next_value_ () { + if ( this.carry.length > 0 ) { + return { + value: this.carry.shift(), + done: false, + }; + } + return await this.delegate.next(); + } + async acc ({ value }) { + return value; + } + async next_ () { + for (;;) { + const ret = await this.next_value_(); + if ( ret.done ) return ret; + const v = await this.acc({ + state: this.state, + value: ret.value, + carry: v => this.carry.push(v), + }); + if ( this.carry.length > 0 && v === undefined ) { + throw new Error(`no value, but carry value exists`); + } + if ( v === undefined ) continue; + // We have a value, clear the state! + this.state = {}; + if ( this.transform ) { + const new_value = await this.transform( + { value: ret.value }); + return { ...ret, value: new_value }; + } + return { ...ret, value: v }; + } + } + async next () { + const ret = await this.next_(); + if ( this.observe && !ret.done ) { + this.observe(ret); + } + return ret; + } + async enqueue_ (v) { + this.queue.push(v); + } +} + +const NewCallbackByteStream = () => { + let listener; + let queue = []; + const NOOP = () => {}; + let signal = NOOP; + (async () => { + for (;;) { + const v = await new Promise((rslv, rjct) => { + listener = rslv; + }); + queue.push(v); + signal(); + } + })(); + const stream = { + [Symbol.asyncIterator](){ + return this; + }, + async next () { + if ( queue.length > 0 ) { + return { + value: queue.shift(), + done: false, + }; + } + await new Promise(rslv => { + signal = rslv; + }); + signal = NOOP; + const v = queue.shift(); + return { value: v, done: false }; + } + }; + stream.listener = data => { + listener(data); + }; + return stream; +} + +const NewVirtioFrameStream = byteStream => { + return new ATStream({ + delegate: byteStream, + async acc ({ value, carry }) { + if ( ! this.state.buffer ) { + if ( this.state.hold ) { + const old_val = value; + let size = this.state.hold.length + value.length; + value = new Uint8Array(size); + value.set(this.state.hold, 0); + value.set(old_val, this.state.hold.length); + } + if ( value.length < 4 ) { + this.state.hold = value; + return undefined; + } + const size = lib.get_int(4, value); + // 512MiB limit in case of attempted abuse or a bug + // (assuming this won't happen under normal conditions) + if ( size > 512*(1024**2) ) { + throw new Error(`Way too much data! (${size} bytes)`); + } + value = value.slice(4); + this.state.buffer = new Uint8Array(size); + this.state.index = 0; + } + + const needed = this.state.buffer.length - this.state.index; + if ( value.length > needed ) { + const remaining = value.slice(needed); + console.log('we got more bytes than we needed', + needed, + remaining, + value.length, + this.state.buffer.length, + this.state.index, + ); + carry(remaining); + } + + const amount = Math.min(value.length, needed); + const added = value.slice(0, amount); + this.state.buffer.set(added, this.state.index); + this.state.index += amount; + + if ( this.state.index > this.state.buffer.length ) { + throw new Error('WUT'); + } + if ( this.state.index == this.state.buffer.length ) { + return this.state.buffer; + } + } + }); +}; + +const wisp_types = [ + { + id: 3, + label: 'CONTINUE', + describe: ({ payload }) => { + return `buffer: ${lib.get_int(4, payload)}B`; + }, + getAttributes ({ payload }) { + return { + buffer_size: lib.get_int(4, payload), + }; + } + }, + { + id: 5, + label: 'INFO', + describe: ({ payload }) => { + return `v${payload[0]}.${payload[1]} ` + + lib.buf2hex(payload.slice(2)); + }, + getAttributes ({ payload }) { + return { + version_major: payload[0], + version_minor: payload[1], + extensions: payload.slice(2), + } + } + }, +]; + +class WispPacket { + static SEND = Symbol('SEND'); + static RECV = Symbol('RECV'); + constructor ({ data, direction, extra }) { + this.direction = direction; + this.data_ = data; + this.extra = extra ?? {}; + this.types_ = { + 1: { label: 'CONNECT' }, + 2: { label: 'DATA' }, + 4: { label: 'CLOSE' }, + }; + for ( const item of wisp_types ) { + this.types_[item.id] = item; + } + } + get type () { + const i_ = this.data_[0]; + return this.types_[i_]; + } + get attributes () { + if ( ! this.type.getAttributes ) return {}; + const attrs = {}; + Object.assign(attrs, this.type.getAttributes({ + payload: this.data_.slice(5), + })); + Object.assign(attrs, this.extra); + return attrs; + } + toVirtioFrame () { + const arry = new Uint8Array(this.data_.length + 4); + arry.set(lib.to_int(4, this.data_.length), 0); + arry.set(this.data_, 4); + return arry; + } + describe () { + return this.type.label + '(' + + (this.type.describe?.({ + payload: this.data_.slice(5), + }) ?? '?') + ')'; + } + log () { + const arrow = + this.direction === this.constructor.SEND ? '->' : + this.direction === this.constructor.RECV ? '<-' : + '<>' ; + console.groupCollapsed(`WISP ${arrow} ${this.describe()}`); + const attrs = this.attributes; + for ( const k in attrs ) { + console.log(k, attrs[k]); + } + console.groupEnd(); + } + reflect () { + const reflected = new WispPacket({ + data: this.data_, + direction: + this.direction === this.constructor.SEND ? + this.constructor.RECV : + this.direction === this.constructor.RECV ? + this.constructor.SEND : + undefined, + extra: { + reflectedFrom: this, + } + }); + return reflected; + } +} + +for ( const item of wisp_types ) { + WispPacket[item.label] = item; +} + +const NewWispPacketStream = frameStream => { + return new ATStream({ + delegate: frameStream, + transform ({ value }) { + return new WispPacket({ + data: value, + direction: WispPacket.RECV, + }); + }, + observe ({ value }) { + value.log(); + } + }); +} + +class WispClient { + constructor ({ + packetStream, + sendFn, + }) { + this.packetStream = packetStream; + this.sendFn = sendFn; + } + send (packet) { + packet.log(); + this.sendFn(packet); + } +} + +module.exports = { + NewVirtioFrameStream, + NewWispPacketStream, + WispPacket, +}; diff --git a/src/puter-wisp/devlog/unit_test_usefulness/test_a_b.diff b/src/puter-wisp/devlog/unit_test_usefulness/test_a_b.diff new file mode 100644 index 0000000000..311e98203c --- /dev/null +++ b/src/puter-wisp/devlog/unit_test_usefulness/test_a_b.diff @@ -0,0 +1,18 @@ +31d30 +< console.log('got from carry!', this.carry); +51c50 +< if ( this.carry.length >= 0 && v === undefined ) { +--- +> if ( this.carry.length > 0 && v === undefined ) { +120a120,130 +> if ( this.state.hold ) { +> const old_val = value; +> let size = this.state.hold.length + value.length; +> value = new Uint8Array(size); +> value.set(this.state.hold, 0); +> value.set(old_val, this.state.hold.length); +> } +> if ( value.length < 4 ) { +> this.state.hold = value; +> return undefined; +> } diff --git a/src/puter-wisp/package.json b/src/puter-wisp/package.json new file mode 100644 index 0000000000..bcb02763a8 --- /dev/null +++ b/src/puter-wisp/package.json @@ -0,0 +1,15 @@ +{ + "name": "puter-wisp", + "version": "1.0.0", + "main": "exports.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "UNLICENSED", + "directories": { + "test": "test" + }, + "description": "" +} diff --git a/src/puter-wisp/src/exports.js b/src/puter-wisp/src/exports.js new file mode 100644 index 0000000000..709bb3eba6 --- /dev/null +++ b/src/puter-wisp/src/exports.js @@ -0,0 +1,298 @@ +const lib = {}; + +// SO: 40031688 +lib.buf2hex = (buffer) => { // buffer is an ArrayBuffer + return [...new Uint8Array(buffer)] + .map(x => x.toString(16).padStart(2, '0')) + .join(''); +} + +// Tiny inline little-endian integer library +lib.get_int = (n_bytes, array8, signed=false) => { + return (v => signed ? v : v >>> 0)( + array8.slice(0,n_bytes).reduce((v,e,i)=>v|=e<<8*i,0)); +} +lib.to_int = (n_bytes, num) => { + return (new Uint8Array()).map((_,i)=>(num>>8*i)&0xFF); +} + +// Accumulator and/or Transformer (and/or Observer) Stream +// The Swiss Army Knife* of Streams! +// (* this code is not affiliated with the Swiss Army Knife corporation) +class ATStream { + constructor ({ delegate, acc, transform, observe }) { + this.delegate = delegate; + if ( acc ) this.acc = acc; + if ( transform ) this.transform = transform; + if ( observe ) this.observe = observe; + this.state = {}; + this.carry = []; + } + [Symbol.asyncIterator]() { return this; } + async next_value_ () { + if ( this.carry.length > 0 ) { + return { + value: this.carry.shift(), + done: false, + }; + } + return await this.delegate.next(); + } + async acc ({ value }) { + return value; + } + async next_ () { + for (;;) { + const ret = await this.next_value_(); + if ( ret.done ) return ret; + const v = await this.acc({ + state: this.state, + value: ret.value, + carry: v => this.carry.push(v), + }); + if ( this.carry.length > 0 && v === undefined ) { + throw new Error(`no value, but carry value exists`); + } + if ( v === undefined ) continue; + // We have a value, clear the state! + this.state = {}; + if ( this.transform ) { + const new_value = await this.transform( + { value: ret.value }); + return { ...ret, value: new_value }; + } + return { ...ret, value: v }; + } + } + async next () { + const ret = await this.next_(); + if ( this.observe && !ret.done ) { + this.observe(ret); + } + return ret; + } + async enqueue_ (v) { + this.queue.push(v); + } +} + +const NewCallbackByteStream = () => { + let listener; + let queue = []; + const NOOP = () => {}; + let signal = NOOP; + (async () => { + for (;;) { + const v = await new Promise((rslv, rjct) => { + listener = rslv; + }); + queue.push(v); + signal(); + } + })(); + const stream = { + [Symbol.asyncIterator](){ + return this; + }, + async next () { + if ( queue.length > 0 ) { + return { + value: queue.shift(), + done: false, + }; + } + await new Promise(rslv => { + signal = rslv; + }); + signal = NOOP; + const v = queue.shift(); + return { value: v, done: false }; + } + }; + stream.listener = data => { + listener(data); + }; + return stream; +} + +const NewVirtioFrameStream = byteStream => { + return new ATStream({ + delegate: byteStream, + async acc ({ value, carry }) { + if ( ! this.state.buffer ) { + if ( this.state.hold ) { + const old_val = value; + let size = this.state.hold.length + value.length; + value = new Uint8Array(size); + value.set(this.state.hold, 0); + value.set(old_val, this.state.hold.length); + } + if ( value.length < 4 ) { + this.state.hold = value; + return undefined; + } + const size = lib.get_int(4, value); + // 512MiB limit in case of attempted abuse or a bug + // (assuming this won't happen under normal conditions) + if ( size > 512*(1024**2) ) { + throw new Error(`Way too much data! (${size} bytes)`); + } + value = value.slice(4); + this.state.buffer = new Uint8Array(size); + this.state.index = 0; + } + + const needed = this.state.buffer.length - this.state.index; + if ( value.length > needed ) { + const remaining = value.slice(needed); + console.log('we got more bytes than we needed', + needed, + remaining, + value.length, + this.state.buffer.length, + this.state.index, + ); + carry(remaining); + } + + const amount = Math.min(value.length, needed); + const added = value.slice(0, amount); + this.state.buffer.set(added, this.state.index); + this.state.index += amount; + + if ( this.state.index > this.state.buffer.length ) { + throw new Error('WUT'); + } + if ( this.state.index == this.state.buffer.length ) { + return this.state.buffer; + } + } + }); +}; + +const wisp_types = [ + { + id: 3, + label: 'CONTINUE', + describe: ({ payload }) => { + return `buffer: ${lib.get_int(4, payload)}B`; + }, + getAttributes ({ payload }) { + return { + buffer_size: lib.get_int(4, payload), + }; + } + }, + { + id: 5, + label: 'INFO', + describe: ({ payload }) => { + return `v${payload[0]}.${payload[1]} ` + + lib.buf2hex(payload.slice(2)); + }, + getAttributes ({ payload }) { + return { + version_major: payload[0], + version_minor: payload[1], + extensions: payload.slice(2), + } + } + }, +]; + +class WispPacket { + static SEND = Symbol('SEND'); + static RECV = Symbol('RECV'); + constructor ({ data, direction, extra }) { + this.direction = direction; + this.data_ = data; + this.extra = extra ?? {}; + this.types_ = { + 1: { label: 'CONNECT' }, + 2: { label: 'DATA' }, + 4: { label: 'CLOSE' }, + }; + for ( const item of wisp_types ) { + this.types_[item.id] = item; + } + } + get type () { + const i_ = this.data_[0]; + return this.types_[i_]; + } + get attributes () { + if ( ! this.type.getAttributes ) return {}; + const attrs = {}; + Object.assign(attrs, this.type.getAttributes({ + payload: this.data_.slice(5), + })); + Object.assign(attrs, this.extra); + return attrs; + } + toVirtioFrame () { + const arry = new Uint8Array(this.data_.length + 4); + arry.set(lib.to_int(4, this.data_.length), 0); + arry.set(this.data_, 4); + return arry; + } + describe () { + return this.type.label + '(' + + (this.type.describe?.({ + payload: this.data_.slice(5), + }) ?? '?') + ')'; + } + log () { + const arrow = + this.direction === this.constructor.SEND ? '->' : + this.direction === this.constructor.RECV ? '<-' : + '<>' ; + console.groupCollapsed(`WISP ${arrow} ${this.describe()}`); + const attrs = this.attributes; + for ( const k in attrs ) { + console.log(k, attrs[k]); + } + console.groupEnd(); + } + reflect () { + const reflected = new WispPacket({ + data: this.data_, + direction: + this.direction === this.constructor.SEND ? + this.constructor.RECV : + this.direction === this.constructor.RECV ? + this.constructor.SEND : + undefined, + extra: { + reflectedFrom: this, + } + }); + return reflected; + } +} + +for ( const item of wisp_types ) { + WispPacket[item.label] = item; +} + +const NewWispPacketStream = frameStream => { + return new ATStream({ + delegate: frameStream, + transform ({ value }) { + return new WispPacket({ + data: value, + direction: WispPacket.RECV, + }); + }, + observe ({ value }) { + // TODO: configurable behavior, or a separate stream decorator + value.log(); + } + }); +} + +module.exports = { + NewCallbackByteStream, + NewVirtioFrameStream, + NewWispPacketStream, + WispPacket, +}; diff --git a/src/puter-wisp/test/test.js b/src/puter-wisp/test/test.js new file mode 100644 index 0000000000..be063cee0d --- /dev/null +++ b/src/puter-wisp/test/test.js @@ -0,0 +1,50 @@ +const assert = require('assert'); +const { + NewVirtioFrameStream, + NewWispPacketStream, + WispPacket, +} = require('../src/exports'); + +const NewTestByteStream = uint8array => { + return (async function * () { + for ( const item of uint8array ) { + yield Uint8Array.from([item]); + } + })(); +}; + +const NewTestFullByteStream = uint8array => { + return (async function * () { + yield uint8array; + })(); +}; + +(async () => { + const stream_behaviors = [ + NewTestByteStream, + NewTestFullByteStream, + ]; + for ( const stream_behavior of stream_behaviors ) { + const byteStream = stream_behavior( + Uint8Array.from([ + 9, 0, 0, 0, // size of frame: 9 bytes (u32-L) + 3, // CONTINUE (u8) + 0, 0, 0, 0, // stream id: 0 (u32-L) + 0x0F, 0x0F, 0, 0, // buffer size (u32-L) + ]) + ); + const virtioStream = NewVirtioFrameStream(byteStream); + const wispStream = NewWispPacketStream(virtioStream); + + const packets = []; + for await ( const packet of wispStream ) { + packets.push(packet); + } + + assert.strictEqual(packets.length, 1); + const packet = packets[0]; + assert.strictEqual(packet.type.id, 3); + assert.strictEqual(packet.type.label, 'CONTINUE'); + assert.strictEqual(packet.type, WispPacket.CONTINUE); + } +})(); \ No newline at end of file From a4766278e449bc793dac02ad6b715e2dcf64f381 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 27 Aug 2024 22:37:22 -0400 Subject: [PATCH 0791/2119] tweak: package name for @heyputer/puter-wisp --- src/puter-wisp/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/puter-wisp/package.json b/src/puter-wisp/package.json index bcb02763a8..1aab01e837 100644 --- a/src/puter-wisp/package.json +++ b/src/puter-wisp/package.json @@ -1,5 +1,5 @@ { - "name": "puter-wisp", + "name": "@heyputer/puter-wisp", "version": "1.0.0", "main": "exports.js", "scripts": { From d1d0a9cccca696024c4834d1aee884435a0ba65c Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 27 Aug 2024 22:40:27 -0400 Subject: [PATCH 0792/2119] tweak: update license for puter-wisp --- src/puter-wisp/package.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/puter-wisp/package.json b/src/puter-wisp/package.json index 1aab01e837..d443384399 100644 --- a/src/puter-wisp/package.json +++ b/src/puter-wisp/package.json @@ -7,7 +7,7 @@ }, "keywords": [], "author": "", - "license": "UNLICENSED", + "license": "AGPL-3.0-only", "directories": { "test": "test" }, From 18cfef65b865fea536045904808c201b3c123688 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 27 Aug 2024 20:02:01 -0700 Subject: [PATCH 0793/2119] Attempt to open apps from URL only if user is authenticated and desktop is loaded --- src/gui/src/UI/UIDesktop.js | 23 +++++++++++++++++++++++ src/gui/src/initgui.js | 26 +------------------------- 2 files changed, 24 insertions(+), 25 deletions(-) diff --git a/src/gui/src/UI/UIDesktop.js b/src/gui/src/UI/UIDesktop.js index 18d5e4d1c5..8a0ea74482 100644 --- a/src/gui/src/UI/UIDesktop.js +++ b/src/gui/src/UI/UIDesktop.js @@ -1022,6 +1022,29 @@ async function UIDesktop(options){ // adjust window container to take into account the toolbar height $('.window-container').css('top', window.toolbar_height); + + //-------------------------------------------------------------------------------------- + // Determine if an app was launched from URL + // i.e. https://puter.com/app/ + //-------------------------------------------------------------------------------------- + if(window.url_paths[0]?.toLocaleLowerCase() === 'app' && window.url_paths[1]){ + window.app_launched_from_url = window.url_paths[1]; + // get app metadata + try{ + window.app_launched_from_url = await puter.apps.get(window.url_paths[1]) + window.is_fullpage_mode = window.app_launched_from_url.metadata?.fullpage_on_landing ?? false; + }catch(e){ + console.error(e); + } + + // get query params, any param that doesn't start with 'puter.' will be passed to the app + window.app_query_params = {}; + for (let [key, value] of window.url_query_params) { + if(!key.startsWith('puter.')) + window.app_query_params[key] = value; + } + } + // --------------------------------------------- // Run apps from insta-login URL // --------------------------------------------- diff --git a/src/gui/src/initgui.js b/src/gui/src/initgui.js index a74763deee..b2a3e66be1 100644 --- a/src/gui/src/initgui.js +++ b/src/gui/src/initgui.js @@ -188,30 +188,7 @@ window.initgui = async function(options){ // will hold the result of the whoami API call let whoami; - const url_paths = window.location.pathname.split('/').filter(element => element); - - //-------------------------------------------------------------------------------------- - // Determine if an app was launched from URL - // i.e. https://puter.com/app/ - //-------------------------------------------------------------------------------------- - if(url_paths[0]?.toLocaleLowerCase() === 'app' && url_paths[1]){ - window.app_launched_from_url = url_paths[1]; - - // get app metadata - try{ - window.app_launched_from_url = await puter.apps.get(window.app_launched_from_url) - window.is_fullpage_mode = window.app_launched_from_url.metadata?.fullpage_on_landing ?? false; - }catch(e){ - console.error(e); - } - - // get query params, any param that doesn't start with 'puter.' will be passed to the app - window.app_query_params = {}; - for (let [key, value] of window.url_query_params) { - if(!key.startsWith('puter.')) - window.app_query_params[key] = value; - } - } + window.url_paths = window.location.pathname.split('/').filter(element => element); //-------------------------------------------------------------------------------------- // Extract 'action' from URL @@ -235,7 +212,6 @@ window.initgui = async function(options){ window.is_fullpage_mode = true; } - // Launch services before any UI is rendered await launch_services(options); From 8e4962beede7ee5de9b34ebb20ed8a5378a7ce16 Mon Sep 17 00:00:00 2001 From: pikagaufre Date: Wed, 28 Aug 2024 20:07:12 +0000 Subject: [PATCH 0794/2119] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 5c2eaa7b51..3215fc750c 100644 --- a/README.md +++ b/README.md @@ -137,7 +137,7 @@ This repository, including all its contents, sub-projects, modules, and componen - [Chinese / 中文](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.zh.md) - [Danish / Dansk](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.da.md) - [English](https://github.com/HeyPuter/puter/blob/main/README.md) -- [French / Français](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.da.md) +- [French / Français](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.fr.md) - [Hindi / हिंदी](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.hi.md) - [Indonesian / Bahasa Indonesia](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.id.md) - [Italian / Italiano](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.it.md) From a17f8408ebfa664f819591a1d66c06a2cd4df6cd Mon Sep 17 00:00:00 2001 From: EngrAdnanAhmad Date: Thu, 29 Aug 2024 02:26:52 +0500 Subject: [PATCH 0795/2119] Translated README section to Urdu with correct clickable links --- doc/i18n/README.ur.md | 125 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 125 insertions(+) create mode 100644 doc/i18n/README.ur.md diff --git a/doc/i18n/README.ur.md b/doc/i18n/README.ur.md new file mode 100644 index 0000000000..67b061fe4a --- /dev/null +++ b/doc/i18n/README.ur.md @@ -0,0 +1,125 @@ +

Puter.com, ذاتی کلاؤڈ کمپیوٹر: آپ کی تمام فائلیں، ایپس، اور کھیل ایک جگہ پر، کہیں سے بھی اور کسی بھی وقت قابل رسائی۔

+ +

انٹرنیٹ OS! مفت، اوپن سورس، اور خود میزبان.

+ +

+ GitHub repo size GitHub Release GitHub License +

+

+ « لائیو ڈیمو » +
+
+ Puter.com + · + SDK + · + ڈسکورڈ + · + یوٹیوب + · + ریڈڈٹ + · + ایکس (ٹوئٹر) + · + بگ باؤنٹی +

+ +

اسکرین شاٹ

+ +
+ +## Puter + +ایک جدید، اوپن سورس انٹرنیٹ آپریٹنگ سسٹم ہے جو کہ خصوصیات سے بھرپور، بہت تیز، اور انتہائی توسیع پذیر ہے۔ Puter + +: کو استعمال کیا جا سکتا ہے Puter + +- ایک پرائیویسی فرسٹ ذاتی کلاؤڈ کے طور پر تاکہ آپ کی تمام فائلیں، ایپس، اور کھیل ایک محفوظ جگہ پر رکھی جا سکیں، کہیں سے بھی اور کسی بھی وقت قابل رسائی ہوں۔ +- ویب سائٹس، ویب ایپس، اور کھیل بنانے اور شائع کرنے کے لئے ایک پلیٹ فارم کے طور پر۔ +- وغیرہ کا متبادل، نئے انٹرفیس اور طاقتور خصوصیات کے ساتھ۔ Dropbox، Google Drive، OneDrive +- سرورز اور ورک اسٹیشنز کے لیے ایک ریموٹ ڈیسک ٹاپ ماحول کے طور پر۔ +- ویب ڈویلپمنٹ، کلاؤڈ کمپیوٹنگ، تقسیم شدہ نظاموں، اور بہت کچھ سیکھنے کے لیے ایک دوستانہ، اوپن سورس پروجیکٹ اور کمیونٹی! + +
+ +## شروع کرنے کا طریقہ + +### 💻 مقامی ترقی + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +یہ Puter کو http://puter.localhost:4100 (یا اگلے دستیاب پورٹ) پر لانچ کرے گا۔ + +
+🐳 Docker + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+🐙 Docker Compose +Linux/macOS + +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` + +
+Windows + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +### ☁️ Puter.com + +Puter کو [**puter.com**](https://puter.com) پر میزبان سروس کے طور پر دستیاب ہے۔ + +
+ +## نظام کی ضروریات + +- **آپریٹنگ سسٹمز:** لینکس، macOS، ونڈوز +- **RAM:** کم از کم 2GB (4GB تجویز کردہ) +- **ڈسک کی جگہ:** 1GB خالی جگہ +- **Node.js:** ورژن 16+ (ورژن 22+ تجویز کردہ) +- **npm:** تازہ ترین مستحکم ورژن + +
+ +## سپورٹ + +منتظمین اور کمیونٹی سے جڑنے کے لیے یہ چینلز استعمال کریں: + +- بگ رپورٹ یا فیچر درخواست؟ براہ کرم [ایک مسئلہ کھولیں](https://github.com/HeyPuter/puter/issues/new/choose). +- ڈسکورڈ: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- ایکس (ٹوئٹر): [x.com/HeyPuter](https://x.com/HeyPuter) +- ریڈڈٹ: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- ماسٹڈون: [mastodon.social/@puter](https://mastodon.social/@puter) +- سیکیورٹی کے مسائل؟ [security@puter.com](mailto:security@puter.com) +- منتظمین کو ای میل کریں [hi@puter.com](mailto:hi@puter.com) + +ہم ہمیشہ آپ کی مدد کے لیے خوش ہیں۔ سوالات پوچھنے میں ہچکچاہٹ نہ کریں +! +
+ +## لائسنس + +اس ریپوزٹری، بشمول اس کے تمام مواد، ذیلی پروجیکٹس، ماڈیولز، اور کمپوننٹس، کو [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) کے تحت لائسنس کیا گیا ہے جب تک کہ واضح طور پر کہیں اور نہ کہا گیا ہو۔ اس ریپوزٹری میں شامل تھرڈ پارٹی لائبریریاں اپنی لائسنس کے تابع ہو سکتی ہیں۔ + +
From fa4bef887333cfa253b7cf0a3c005318c4641597 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 28 Aug 2024 14:35:39 -0700 Subject: [PATCH 0796/2119] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3215fc750c..a2f05dfbe5 100644 --- a/README.md +++ b/README.md @@ -151,4 +151,5 @@ This repository, including all its contents, sub-projects, modules, and componen - [Tamil / தமிழ்](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ta.md) - [Thai / ไทย](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.th.md) - [Turkish / Türkçe](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.tr.md) +- [Urdu / اردو](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ur.md) - [Vietnamese / Tiếng Việt](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.vi.md) From 813ee95cee6f1fca79a886b12d8fe4603ca0d213 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 27 Aug 2024 23:23:38 -0400 Subject: [PATCH 0797/2119] fix: fallback to read access in /sign --- src/backend/src/routers/sign.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/src/routers/sign.js b/src/backend/src/routers/sign.js index 4a1379a545..1813d098a3 100644 --- a/src/backend/src/routers/sign.js +++ b/src/backend/src/routers/sign.js @@ -117,7 +117,7 @@ module.exports = eggspress('/sign', { if ( item.action === 'write' ) { if ( ! await svc_acl.check(actor, node, 'write') ) { - throw await svc_acl.get_safe_acl_error(actor, node, 'write'); + item.action = 'read'; } } From c86df11abd98f50b7f495d7746a83c8abc5ce66a Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 28 Aug 2024 06:41:17 -0400 Subject: [PATCH 0798/2119] dev: launchApp as registered ipc handler Add launchApp as a registered ipc handler, which will allow communication between iframes (apps/puter.js) to be simplified. --- src/gui/src/IPC.js | 31 +++++++++++------------------ src/gui/src/initgui.js | 4 ++++ src/gui/src/services/ExecService.js | 26 ++++++++++++++++++++++++ src/gui/src/services/IPCService.js | 11 ++++++++++ 4 files changed, 53 insertions(+), 19 deletions(-) create mode 100644 src/gui/src/services/ExecService.js create mode 100644 src/gui/src/services/IPCService.js diff --git a/src/gui/src/IPC.js b/src/gui/src/IPC.js index 356e72e064..b9f136bc03 100644 --- a/src/gui/src/IPC.js +++ b/src/gui/src/IPC.js @@ -32,6 +32,7 @@ import update_mouse_position from './helpers/update_mouse_position.js'; import launch_app from './helpers/launch_app.js'; import item_icon from './helpers/item_icon.js'; +window.ipc_handlers = {}; /** * In Puter, apps are loaded in iframes and communicate with the graphical user interface (GUI), and each other, using the postMessage API. * The following sets up an Inter-Process Messaging System between apps and the GUI that enables communication @@ -88,6 +89,17 @@ window.addEventListener('message', async (event) => { const msg_id = event.data.uuid; const app_name = $(target_iframe).attr('data-app'); const app_uuid = $el_parent_window.attr('data-app_uuid'); + + if ( window.ipc_handlers.hasOwnProperty(event.data.msg) ) { + console.log('got message to new IPC handler', event.data.msg); + const ipc_context = { + appInstanceId: event.data.appInstanceID, + }; + const spec = window.ipc_handlers[event.data.msg]; + await spec.handler(event.data, { msg_id, ipc_context }); + console.log('^ end of that thing'); + return; + } // todo validate all event.data stuff coming from the client (e.g. event.data.message, .msg, ...) //------------------------------------------------- @@ -846,25 +858,6 @@ window.addEventListener('message', async (event) => { window.watchItems[event.data.item_uid].push(event.data.appInstanceID); } //-------------------------------------------------------- - // launchApp - //-------------------------------------------------------- - else if(event.data.msg === 'launchApp'){ - // TODO: Determine if the app is allowed to launch child apps? We may want to limit this to prevent abuse. - // remember app for launch callback later - const child_instance_id = window.uuidv4(); - window.child_launch_callbacks[child_instance_id] = { - parent_instance_id: event.data.appInstanceID, - launch_msg_id: msg_id, - }; - // launch child app - launch_app({ - name: event.data.app_name ?? app_name, - args: event.data.args ?? {}, - parent_instance_id: event.data.appInstanceID, - uuid: child_instance_id, - }); - } - //-------------------------------------------------------- // readAppDataFile //-------------------------------------------------------- else if(event.data.msg === 'readAppDataFile' && event.data.path !== undefined){ diff --git a/src/gui/src/initgui.js b/src/gui/src/initgui.js index b2a3e66be1..df19077815 100644 --- a/src/gui/src/initgui.js +++ b/src/gui/src/initgui.js @@ -46,6 +46,8 @@ import update_mouse_position from './helpers/update_mouse_position.js'; import { LaunchOnInitService } from './services/LaunchOnInitService.js'; import item_icon from './helpers/item_icon.js'; import { AntiCSRFService } from './services/AntiCSRFService.js'; +import { IPCService } from './services/IPCService.js'; +import { ExecService } from './services/ExecService.js'; const launch_services = async function (options) { // === Services Data Structures === @@ -75,6 +77,8 @@ const launch_services = async function (options) { globalThis.service_script_api_promise.resolve(service_script_api); // === Builtin Services === + register('ipc', new IPCService()); + register('exec', new ExecService()); register('broadcast', new BroadcastService()); register('theme', new ThemeService()); register('process', new ProcessService()); diff --git a/src/gui/src/services/ExecService.js b/src/gui/src/services/ExecService.js new file mode 100644 index 0000000000..62e9f240ac --- /dev/null +++ b/src/gui/src/services/ExecService.js @@ -0,0 +1,26 @@ +import { Service } from "../definitions.js"; +import launch_app from "../helpers/launch_app.js"; + +export class ExecService extends Service { + async _init ({ services }) { + const svc_ipc = services.get('ipc'); + svc_ipc.register_ipc_handler('launchApp', { + handler: this.launchApp.bind(this), + }); + } + + launchApp ({ app_name, args }, { ipc_context, msg_id } = {}) { + const child_instance_id = window.uuidv4(); + window.child_launch_callbacks[child_instance_id] = { + parent_instance_id: event.data.appInstanceID, + launch_msg_id: msg_id, + }; + // launch child app + launch_app({ + name: app_name, + args: args ?? {}, + parent_instance_id: ipc_context?.appInstanceId, + uuid: child_instance_id, + }); + } +} diff --git a/src/gui/src/services/IPCService.js b/src/gui/src/services/IPCService.js new file mode 100644 index 0000000000..f2f025c874 --- /dev/null +++ b/src/gui/src/services/IPCService.js @@ -0,0 +1,11 @@ +import { Service } from "../definitions.js"; + +export class IPCService extends Service { + async _init () { + // + } + + register_ipc_handler (name, spec) { + window.ipc_handlers[name] = spec; + } +} From 1cd21ee65880e14820ae799b1e916c9fa9b83470 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 28 Aug 2024 21:58:33 -0400 Subject: [PATCH 0799/2119] tweak: cleanup and comment --- src/gui/src/IPC.js | 12 +++++++++--- src/gui/src/services/ExecService.js | 9 ++++++++- src/gui/src/services/IPCService.js | 4 ++++ 3 files changed, 21 insertions(+), 4 deletions(-) diff --git a/src/gui/src/IPC.js b/src/gui/src/IPC.js index b9f136bc03..acae4ce7d5 100644 --- a/src/gui/src/IPC.js +++ b/src/gui/src/IPC.js @@ -29,7 +29,6 @@ import download from './helpers/download.js'; import path from "./lib/path.js"; import UIContextMenu from './UI/UIContextMenu.js'; import update_mouse_position from './helpers/update_mouse_position.js'; -import launch_app from './helpers/launch_app.js'; import item_icon from './helpers/item_icon.js'; window.ipc_handlers = {}; @@ -90,14 +89,21 @@ window.addEventListener('message', async (event) => { const app_name = $(target_iframe).attr('data-app'); const app_uuid = $el_parent_window.attr('data-app_uuid'); + // New IPC handlers should be registered here. + // Do this by calling `register_ipc_handler` of IPCService. if ( window.ipc_handlers.hasOwnProperty(event.data.msg) ) { - console.log('got message to new IPC handler', event.data.msg); + // The IPC context contains information about the call const ipc_context = { appInstanceId: event.data.appInstanceID, }; + + // Registered IPC handlers are an object with a `handle()` + // method. We call it "spec" here, meaning specification. const spec = window.ipc_handlers[event.data.msg]; await spec.handler(event.data, { msg_id, ipc_context }); - console.log('^ end of that thing'); + + // Early-return to avoid redundant invokation of any + // legacy IPC handler. return; } diff --git a/src/gui/src/services/ExecService.js b/src/gui/src/services/ExecService.js index 62e9f240ac..5946a075aa 100644 --- a/src/gui/src/services/ExecService.js +++ b/src/gui/src/services/ExecService.js @@ -2,6 +2,10 @@ import { Service } from "../definitions.js"; import launch_app from "../helpers/launch_app.js"; export class ExecService extends Service { + static description = ` + Manages instances of apps on the Puter desktop. + ` + async _init ({ services }) { const svc_ipc = services.get('ipc'); svc_ipc.register_ipc_handler('launchApp', { @@ -9,13 +13,16 @@ export class ExecService extends Service { }); } + // This method is exposed to apps via IPCService. launchApp ({ app_name, args }, { ipc_context, msg_id } = {}) { + // This mechanism will be replated with xdrpc soon const child_instance_id = window.uuidv4(); window.child_launch_callbacks[child_instance_id] = { parent_instance_id: event.data.appInstanceID, launch_msg_id: msg_id, }; - // launch child app + + // The "body" of this method is in a separate file launch_app({ name: app_name, args: args ?? {}, diff --git a/src/gui/src/services/IPCService.js b/src/gui/src/services/IPCService.js index f2f025c874..83ac0bf354 100644 --- a/src/gui/src/services/IPCService.js +++ b/src/gui/src/services/IPCService.js @@ -1,6 +1,10 @@ import { Service } from "../definitions.js"; export class IPCService extends Service { + static description = ` + Allows other services to expose methods to apps. + ` + async _init () { // } From d43fc62d89d51e5bfd1f1dba42a3002c520e3776 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 29 Aug 2024 13:33:37 -0700 Subject: [PATCH 0800/2119] Remove menu-aim from the list of statically linked libs --- src/gui/puter-gui.json | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gui/puter-gui.json b/src/gui/puter-gui.json index ef1927c529..97e52025af 100644 --- a/src/gui/puter-gui.json +++ b/src/gui/puter-gui.json @@ -10,7 +10,6 @@ "/lib/jquery-ui-1.13.2/jquery-ui.min.js", "/lib/lodash@4.17.21.min.js", "/lib/jquery.dragster.js", - "/lib/jquery.menu-aim.js", "/lib/html-entities.js", "/lib/timeago.min.js", "/lib/iro.min.js", From 5f7d1f589a56b3d3ea2026dcbd5f9c48b8dc9e6d Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 28 Aug 2024 21:42:41 -0400 Subject: [PATCH 0801/2119] fix: don't var when no var --- src/backend/src/services/runtime-analysis/LogService.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/backend/src/services/runtime-analysis/LogService.js b/src/backend/src/services/runtime-analysis/LogService.js index 860b29a195..5daec8a952 100644 --- a/src/backend/src/services/runtime-analysis/LogService.js +++ b/src/backend/src/services/runtime-analysis/LogService.js @@ -462,6 +462,11 @@ class LogService extends BaseService { { const fs = require('fs'); const path = '/var/puter/logs/heyputer'; + // Making this directory if it doesn't exist causes issues + // for users running with development instructions + if ( ! fs.existsSync('/var/puter') ) { + return; + } try { fs.mkdirSync(path, { recursive: true }); this.log_directory = path; From 3361043b9d507b7944e8c95ba87214c5489f439f Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 29 Aug 2024 17:13:19 -0400 Subject: [PATCH 0802/2119] chore: rename putil --- package-lock.json | 35 ++++++++++++------- src/backend/doc/contributors/index.md | 2 +- src/backend/doc/contributors/modules.md | 2 +- src/backend/package.json | 2 +- src/backend/src/CoreModule.js | 2 +- src/backend/src/DatabaseModule.js | 2 +- src/backend/src/Kernel.js | 2 +- src/backend/src/LocalDiskStorageModule.js | 2 +- src/backend/src/PuterDriversModule.js | 2 +- src/backend/src/ThirdPartyDriversModule.js | 2 +- src/backend/src/boot/RuntimeEnvironment.js | 2 +- src/backend/src/config/ConfigLoader.js | 2 +- src/backend/src/definitions/Driver.js | 2 +- .../src/filesystem/FilesystemService.js | 2 +- .../src/filesystem/batch/BatchExecutor.js | 2 +- src/backend/src/filesystem/batch/commands.js | 2 +- .../storage/DatabaseFSEntryService.js | 2 +- .../src/modules/broadcast/BroadcastModule.js | 2 +- .../src/modules/broadcast/BroadcastService.js | 2 +- .../modules/broadcast/connection/BaseLink.js | 2 +- .../broadcast/connection/KeyPairHelper.js | 2 +- .../src/modules/puterai/PuterAIModule.js | 2 +- .../modules/selfhosted/SelfHostedModule.js | 2 +- .../modules/test-drivers/TestDriversModule.js | 2 +- src/backend/src/om/IdentifierUtil.js | 2 +- src/backend/src/om/definitions/Mapping.js | 2 +- src/backend/src/om/definitions/PropType.js | 2 +- src/backend/src/om/definitions/Property.js | 2 +- src/backend/src/om/entitystorage/BaseES.js | 2 +- src/backend/src/om/entitystorage/Entity.js | 2 +- src/backend/src/om/entitystorage/SQLES.js | 2 +- .../src/om/entitystorage/ValidationES.js | 2 +- src/backend/src/om/query/query.js | 2 +- src/backend/src/routers/hosting/puter-site.js | 2 +- src/backend/src/services/BaseService.js | 2 +- src/backend/src/services/Container.js | 2 +- src/backend/src/services/EngPortalService.js | 2 +- .../src/services/OperationTraceService.js | 2 +- src/backend/src/services/RegistryService.js | 2 +- src/backend/src/services/ServicePatch.js | 2 +- src/backend/src/services/StorageService.js | 2 +- src/backend/src/services/WSPushService.js | 2 +- .../abuse-prevention/IdentificationService.js | 2 +- src/backend/src/services/auth/Actor.js | 2 +- .../database/BaseDatabaseAccessService.js | 2 +- .../src/services/drivers/DriverService.js | 2 +- .../src/services/drivers/FileFacade.js | 2 +- .../src/services/drivers/meta/Construct.js | 2 +- .../src/services/drivers/meta/Runtime.js | 2 +- src/backend/src/services/drivers/types.js | 2 +- .../services/file-cache/FileCacheService.js | 2 +- .../src/services/sla/RateLimitService.js | 2 +- .../thumbnails/HTTPThumbnailService.js | 2 +- src/backend/src/util/multivalue.js | 2 +- src/backend/src/util/pathutil.js | 2 +- src/backend/tools/test.js | 2 +- src/git/src/filesystem.js | 2 +- src/phoenix/src/platform/node/filesystem.js | 2 +- src/phoenix/src/platform/puter/filesystem.js | 2 +- .../src/puter-shell/coreutils/errno.js | 2 +- .../src/puter-shell/coreutils/touch.js | 2 +- src/phoenix/test/coreutils/errno.js | 2 +- src/pty/exports.js | 2 +- src/{puter-js-common => putil}/README.md | 0 src/{puter-js-common => putil}/index.js | 0 src/{puter-js-common => putil}/package.json | 2 +- .../src/AdvancedBase.js | 0 .../src/PosixError.js | 0 .../src/bases/BasicBase.js | 0 .../src/bases/FeatureBase.js | 0 .../src/features/NodeModuleDIFeature.js | 0 .../src/features/PropertiesFeature.js | 0 .../src/features/TraitsFeature.js | 0 .../src/libs/invoker.js | 0 .../src/libs/promise.js | 0 src/{puter-js-common => putil}/test/test.js | 0 76 files changed, 85 insertions(+), 76 deletions(-) rename src/{puter-js-common => putil}/README.md (100%) rename src/{puter-js-common => putil}/index.js (100%) rename src/{puter-js-common => putil}/package.json (84%) rename src/{puter-js-common => putil}/src/AdvancedBase.js (100%) rename src/{puter-js-common => putil}/src/PosixError.js (100%) rename src/{puter-js-common => putil}/src/bases/BasicBase.js (100%) rename src/{puter-js-common => putil}/src/bases/FeatureBase.js (100%) rename src/{puter-js-common => putil}/src/features/NodeModuleDIFeature.js (100%) rename src/{puter-js-common => putil}/src/features/PropertiesFeature.js (100%) rename src/{puter-js-common => putil}/src/features/TraitsFeature.js (100%) rename src/{puter-js-common => putil}/src/libs/invoker.js (100%) rename src/{puter-js-common => putil}/src/libs/promise.js (100%) rename src/{puter-js-common => putil}/test/test.js (100%) diff --git a/package-lock.json b/package-lock.json index 094c3213fe..140dc5a2ed 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,7 +43,7 @@ "dependencies": { "@heyputer/kv.js": "^0.1.3", "@heyputer/multest": "^0.0.2", - "@heyputer/puter-js-common": "^1.0.0", + "@heyputer/putil": "^1.0.0", "@opentelemetry/api": "^1.4.1", "@opentelemetry/auto-instrumentations-node": "^0.43.0", "@opentelemetry/exporter-trace-otlp-grpc": "^0.40.0", @@ -195,7 +195,7 @@ "webpack-cli": "^5.1.4" } }, - "asdf/puter-js-common": { + "asdf/putil": { "version": "1.0.0", "extraneous": true, "license": "UNLICENSED" @@ -2597,14 +2597,18 @@ "resolved": "src/phoenix", "link": true }, - "node_modules/@heyputer/puter-js-common": { - "resolved": "src/puter-js-common", + "node_modules/@heyputer/puter-wisp": { + "resolved": "src/puter-wisp", "link": true }, "node_modules/@heyputer/puterjs": { "resolved": "src/puter-js", "link": true }, + "node_modules/@heyputer/putil": { + "resolved": "src/putil", + "link": true + }, "node_modules/@heyputer/terminal": { "resolved": "src/terminal", "link": true @@ -12515,9 +12519,9 @@ "license": "MIT" }, "node_modules/mocha": { - "version": "10.6.0", - "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.6.0.tgz", - "integrity": "sha512-hxjt4+EEB0SA0ZDygSS015t65lJw/I2yRCS3Ae+SJ5FrbzrXgfYwJr96f0OvIXdj7h4lv/vLCrH3rkiuizFSvw==", + "version": "10.7.3", + "resolved": "https://registry.npmjs.org/mocha/-/mocha-10.7.3.tgz", + "integrity": "sha512-uQWxAu44wwiACGqjbPYmjo7Lg8sFrS3dQe7PP2FQI+woptP4vZXSMcfMyFL/e1yFEeEpV4RtyTpZROOKmxis+A==", "dev": true, "license": "MIT", "dependencies": { @@ -16442,7 +16446,7 @@ "dependencies": { "@heyputer/kv.js": "^0.1.3", "@heyputer/multest": "^0.0.2", - "@heyputer/puter-js-common": "^1.0.0", + "@heyputer/putil": "^1.0.0", "@opentelemetry/api": "^1.4.1", "@opentelemetry/auto-instrumentations-node": "^0.43.0", "@opentelemetry/exporter-trace-otlp-grpc": "^0.40.0", @@ -16617,8 +16621,8 @@ "webpack-cli": "^5.1.4" } }, - "packages/puter-js-common": { - "name": "@heyputer/puter-js-common", + "packages/putil": { + "name": "@heyputer/putil", "version": "1.0.0", "extraneous": true, "license": "UNLICENSED" @@ -16662,7 +16666,7 @@ "@aws-sdk/client-textract": "^3.621.0", "@heyputer/kv.js": "^0.1.3", "@heyputer/multest": "^0.0.2", - "@heyputer/puter-js-common": "^1.0.0", + "@heyputer/putil": "^1.0.0", "@mistralai/mistralai": "^1.0.3", "@opentelemetry/api": "^1.4.1", "@opentelemetry/auto-instrumentations-node": "^0.43.0", @@ -16902,8 +16906,13 @@ "webpack-cli": "^5.1.4" } }, - "src/puter-js-common": { - "name": "@heyputer/puter-js-common", + "src/puter-wisp": { + "name": "@heyputer/puter-wisp", + "version": "1.0.0", + "license": "AGPL-3.0-only" + }, + "src/putil": { + "name": "@heyputer/putil", "version": "1.0.0", "license": "UNLICENSED" }, diff --git a/src/backend/doc/contributors/index.md b/src/backend/doc/contributors/index.md index 52bebb8f6b..a73a5a4038 100644 --- a/src/backend/doc/contributors/index.md +++ b/src/backend/doc/contributors/index.md @@ -71,7 +71,7 @@ doing the useless work that reveals what the useful work is. ## Underlying Constructs -- [puter-js-common's README.md](../../packages/puter-js-common/README.md) +- [putil's README.md](../../packages/putil/README.md) - Whenever you see `AdvancedBase`, that's from here - Many things in backend extend this. Anything that doesn't only doesn't because it was written before `AdvancedBase` existed. diff --git a/src/backend/doc/contributors/modules.md b/src/backend/doc/contributors/modules.md index 188c7031f2..c20816c3d8 100644 --- a/src/backend/doc/contributors/modules.md +++ b/src/backend/doc/contributors/modules.md @@ -35,7 +35,7 @@ To function properly, Puter needs **CoreModule**, a database module, and a storage module. A module extends -[AdvancedBase](../../../puter-js-common/README.md) +[AdvancedBase](../../../putil/README.md) and implements an `install` method. The install method has one parameter, a [Context](../../src/util/context.js) diff --git a/src/backend/package.json b/src/backend/package.json index 196807c376..ec2f197d30 100644 --- a/src/backend/package.json +++ b/src/backend/package.json @@ -12,7 +12,7 @@ "@aws-sdk/client-textract": "^3.621.0", "@heyputer/kv.js": "^0.1.3", "@heyputer/multest": "^0.0.2", - "@heyputer/puter-js-common": "^1.0.0", + "@heyputer/putil": "^1.0.0", "@mistralai/mistralai": "^1.0.3", "@opentelemetry/api": "^1.4.1", "@opentelemetry/auto-instrumentations-node": "^0.43.0", diff --git a/src/backend/src/CoreModule.js b/src/backend/src/CoreModule.js index 13558f2caa..f9026030b7 100644 --- a/src/backend/src/CoreModule.js +++ b/src/backend/src/CoreModule.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const Library = require("./definitions/Library"); const { NotificationES } = require("./om/entitystorage/NotificationES"); const { ProtectedAppES } = require("./om/entitystorage/ProtectedAppES"); diff --git a/src/backend/src/DatabaseModule.js b/src/backend/src/DatabaseModule.js index 27caecf37b..1ba54a743f 100644 --- a/src/backend/src/DatabaseModule.js +++ b/src/backend/src/DatabaseModule.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); class DatabaseModule extends AdvancedBase { async install (context) { diff --git a/src/backend/src/Kernel.js b/src/backend/src/Kernel.js index 01062fdfa5..abcd163010 100644 --- a/src/backend/src/Kernel.js +++ b/src/backend/src/Kernel.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const { Context } = require('./util/context'); const BaseService = require("./services/BaseService"); const useapi = require('useapi'); diff --git a/src/backend/src/LocalDiskStorageModule.js b/src/backend/src/LocalDiskStorageModule.js index a4415df00b..65736f9b40 100644 --- a/src/backend/src/LocalDiskStorageModule.js +++ b/src/backend/src/LocalDiskStorageModule.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); class LocalDiskStorageModule extends AdvancedBase { async install (context) { diff --git a/src/backend/src/PuterDriversModule.js b/src/backend/src/PuterDriversModule.js index a4dfb59b06..c828080a25 100644 --- a/src/backend/src/PuterDriversModule.js +++ b/src/backend/src/PuterDriversModule.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); class PuterDriversModule extends AdvancedBase { async install () {} diff --git a/src/backend/src/ThirdPartyDriversModule.js b/src/backend/src/ThirdPartyDriversModule.js index 0365075375..9c0486a80d 100644 --- a/src/backend/src/ThirdPartyDriversModule.js +++ b/src/backend/src/ThirdPartyDriversModule.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); class ThirdPartyDriversModule extends AdvancedBase { // constructor () { diff --git a/src/backend/src/boot/RuntimeEnvironment.js b/src/backend/src/boot/RuntimeEnvironment.js index 195bb7c10e..b602a75349 100644 --- a/src/backend/src/boot/RuntimeEnvironment.js +++ b/src/backend/src/boot/RuntimeEnvironment.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const { quot } = require("../util/strutil"); const { TechnicalError } = require("../errors/TechnicalError"); const { print_error_help } = require("../errors/error_help_details"); diff --git a/src/backend/src/config/ConfigLoader.js b/src/backend/src/config/ConfigLoader.js index a07c2a649c..a9ff1e9d71 100644 --- a/src/backend/src/config/ConfigLoader.js +++ b/src/backend/src/config/ConfigLoader.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const { quot } = require("../util/strutil"); class ConfigLoader extends AdvancedBase { diff --git a/src/backend/src/definitions/Driver.js b/src/backend/src/definitions/Driver.js index ded5125512..6eaf3f2320 100644 --- a/src/backend/src/definitions/Driver.js +++ b/src/backend/src/definitions/Driver.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const { Context } = require('../util/context') const APIError = require("../api/APIError"); const { AppUnderUserActorType, UserActorType } = require("../services/auth/Actor"); diff --git a/src/backend/src/filesystem/FilesystemService.js b/src/backend/src/filesystem/FilesystemService.js index c335efe5be..bc47a6537a 100644 --- a/src/backend/src/filesystem/FilesystemService.js +++ b/src/backend/src/filesystem/FilesystemService.js @@ -27,7 +27,7 @@ const SystemFSEntryService = require('./storage/SystemFSEntryService.js'); const PerformanceMonitor = require('../monitor/PerformanceMonitor.js'); const { NodePathSelector, NodeUIDSelector, NodeInternalIDSelector } = require('./node/selectors.js'); const FSNodeContext = require('./FSNodeContext.js'); -const { AdvancedBase } = require('@heyputer/puter-js-common'); +const { AdvancedBase } = require('@heyputer/putil'); const { Context } = require('../util/context.js'); const { simple_retry } = require('../util/retryutil.js'); const APIError = require('../api/APIError.js'); diff --git a/src/backend/src/filesystem/batch/BatchExecutor.js b/src/backend/src/filesystem/batch/BatchExecutor.js index 6da8e00bc2..53f6059f6b 100644 --- a/src/backend/src/filesystem/batch/BatchExecutor.js +++ b/src/backend/src/filesystem/batch/BatchExecutor.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require('@heyputer/puter-js-common'); +const { AdvancedBase } = require('@heyputer/putil'); const PathResolver = require('../../routers/filesystem_api/batch/PathResolver'); const commands = require('./commands').commands; const { WorkUnit } = require('../../services/runtime-analysis/ExpectationService'); diff --git a/src/backend/src/filesystem/batch/commands.js b/src/backend/src/filesystem/batch/commands.js index 0385076a4e..b0ba0c7b5f 100644 --- a/src/backend/src/filesystem/batch/commands.js +++ b/src/backend/src/filesystem/batch/commands.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const { AsyncProviderFeature } = require("../../traits/AsyncProviderFeature"); const { HLMkdir, QuickMkdir } = require("../hl_operations/hl_mkdir"); const { Context } = require("../../util/context"); diff --git a/src/backend/src/filesystem/storage/DatabaseFSEntryService.js b/src/backend/src/filesystem/storage/DatabaseFSEntryService.js index df84e69d73..88adb0f815 100644 --- a/src/backend/src/filesystem/storage/DatabaseFSEntryService.js +++ b/src/backend/src/filesystem/storage/DatabaseFSEntryService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const { id2path } = require("../../helpers"); const { PuterPath } = require("../lib/PuterPath"); diff --git a/src/backend/src/modules/broadcast/BroadcastModule.js b/src/backend/src/modules/broadcast/BroadcastModule.js index f7d0dc067b..89dc422f85 100644 --- a/src/backend/src/modules/broadcast/BroadcastModule.js +++ b/src/backend/src/modules/broadcast/BroadcastModule.js @@ -1,4 +1,4 @@ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); class BroadcastModule extends AdvancedBase { async install (context) { diff --git a/src/backend/src/modules/broadcast/BroadcastService.js b/src/backend/src/modules/broadcast/BroadcastService.js index dd7d663479..1365ab1499 100644 --- a/src/backend/src/modules/broadcast/BroadcastService.js +++ b/src/backend/src/modules/broadcast/BroadcastService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const BaseService = require("../../services/BaseService"); const { CLink } = require("./connection/CLink"); const { SLink } = require("./connection/SLink"); diff --git a/src/backend/src/modules/broadcast/connection/BaseLink.js b/src/backend/src/modules/broadcast/connection/BaseLink.js index 0f391886bc..e0c4b8a2d7 100644 --- a/src/backend/src/modules/broadcast/connection/BaseLink.js +++ b/src/backend/src/modules/broadcast/connection/BaseLink.js @@ -1,4 +1,4 @@ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const { ChannelFeature } = require("../../../traits/ChannelFeature"); class BaseLink extends AdvancedBase { diff --git a/src/backend/src/modules/broadcast/connection/KeyPairHelper.js b/src/backend/src/modules/broadcast/connection/KeyPairHelper.js index ab5081681f..8c24d69fcd 100644 --- a/src/backend/src/modules/broadcast/connection/KeyPairHelper.js +++ b/src/backend/src/modules/broadcast/connection/KeyPairHelper.js @@ -1,4 +1,4 @@ -const { AdvancedBase } = require('@heyputer/puter-js-common'); +const { AdvancedBase } = require('@heyputer/putil'); class KeyPairHelper extends AdvancedBase { static MODULES = { diff --git a/src/backend/src/modules/puterai/PuterAIModule.js b/src/backend/src/modules/puterai/PuterAIModule.js index fb88b64e75..9b6ac6fab2 100644 --- a/src/backend/src/modules/puterai/PuterAIModule.js +++ b/src/backend/src/modules/puterai/PuterAIModule.js @@ -1,4 +1,4 @@ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const config = require("../../config"); class PuterAIModule extends AdvancedBase { diff --git a/src/backend/src/modules/selfhosted/SelfHostedModule.js b/src/backend/src/modules/selfhosted/SelfHostedModule.js index 8f1b6e4da0..038d6f4c88 100644 --- a/src/backend/src/modules/selfhosted/SelfHostedModule.js +++ b/src/backend/src/modules/selfhosted/SelfHostedModule.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const config = require("../../config"); class SelfHostedModule extends AdvancedBase { diff --git a/src/backend/src/modules/test-drivers/TestDriversModule.js b/src/backend/src/modules/test-drivers/TestDriversModule.js index 609324a183..3f564ec724 100644 --- a/src/backend/src/modules/test-drivers/TestDriversModule.js +++ b/src/backend/src/modules/test-drivers/TestDriversModule.js @@ -1,4 +1,4 @@ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); class TestDriversModule extends AdvancedBase { async install (context) { diff --git a/src/backend/src/om/IdentifierUtil.js b/src/backend/src/om/IdentifierUtil.js index f70245d1dc..5eb7eea200 100644 --- a/src/backend/src/om/IdentifierUtil.js +++ b/src/backend/src/om/IdentifierUtil.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const { WeakConstructorFeature } = require("../traits/WeakConstructorFeature"); const { Eq, And } = require("./query/query"); const { Entity } = require("./entitystorage/Entity"); diff --git a/src/backend/src/om/definitions/Mapping.js b/src/backend/src/om/definitions/Mapping.js index 1f6bc89910..47a3587b2b 100644 --- a/src/backend/src/om/definitions/Mapping.js +++ b/src/backend/src/om/definitions/Mapping.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const { instance_ } = require("../../monitor/PerformanceMonitor"); const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature"); const { Property } = require("./Property"); diff --git a/src/backend/src/om/definitions/PropType.js b/src/backend/src/om/definitions/PropType.js index b4a964fd7a..72477819e0 100644 --- a/src/backend/src/om/definitions/PropType.js +++ b/src/backend/src/om/definitions/PropType.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature"); class PropType extends AdvancedBase { diff --git a/src/backend/src/om/definitions/Property.js b/src/backend/src/om/definitions/Property.js index 76c11ea21b..3789da272a 100644 --- a/src/backend/src/om/definitions/Property.js +++ b/src/backend/src/om/definitions/Property.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature"); class Property extends AdvancedBase { diff --git a/src/backend/src/om/entitystorage/BaseES.js b/src/backend/src/om/entitystorage/BaseES.js index a91d4e90db..ddb49b95dd 100644 --- a/src/backend/src/om/entitystorage/BaseES.js +++ b/src/backend/src/om/entitystorage/BaseES.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature"); const { Context } = require("../../util/context"); diff --git a/src/backend/src/om/entitystorage/Entity.js b/src/backend/src/om/entitystorage/Entity.js index f02bba8c1e..abaedb330d 100644 --- a/src/backend/src/om/entitystorage/Entity.js +++ b/src/backend/src/om/entitystorage/Entity.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature"); class Entity extends AdvancedBase { diff --git a/src/backend/src/om/entitystorage/SQLES.js b/src/backend/src/om/entitystorage/SQLES.js index 0a87f5e6c0..61c901bfd0 100644 --- a/src/backend/src/om/entitystorage/SQLES.js +++ b/src/backend/src/om/entitystorage/SQLES.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const { BaseES } = require("./BaseES"); const APIError = require("../../api/APIError"); diff --git a/src/backend/src/om/entitystorage/ValidationES.js b/src/backend/src/om/entitystorage/ValidationES.js index 52cd2f9a9b..cfcf01b287 100644 --- a/src/backend/src/om/entitystorage/ValidationES.js +++ b/src/backend/src/om/entitystorage/ValidationES.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const { BaseES } = require("./BaseES"); const APIError = require("../../api/APIError"); diff --git a/src/backend/src/om/query/query.js b/src/backend/src/om/query/query.js index 80d81b384d..bdde50a30f 100644 --- a/src/backend/src/om/query/query.js +++ b/src/backend/src/om/query/query.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature"); class Predicate extends AdvancedBase { diff --git a/src/backend/src/routers/hosting/puter-site.js b/src/backend/src/routers/hosting/puter-site.js index 3e77fedff6..251ff8e3a2 100644 --- a/src/backend/src/routers/hosting/puter-site.js +++ b/src/backend/src/routers/hosting/puter-site.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const api_error_handler = require("../../api/api_error_handler"); const config = require("../../config"); const { get_user, get_app, id2path } = require("../../helpers"); diff --git a/src/backend/src/services/BaseService.js b/src/backend/src/services/BaseService.js index da6c6bae6f..0455b709fe 100644 --- a/src/backend/src/services/BaseService.js +++ b/src/backend/src/services/BaseService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const NOOP = async () => {}; diff --git a/src/backend/src/services/Container.js b/src/backend/src/services/Container.js index 7241523267..0a55f8fd57 100644 --- a/src/backend/src/services/Container.js +++ b/src/backend/src/services/Container.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const config = require("../config"); const { Context } = require("../util/context"); const { CompositeError } = require("../util/errorutil"); diff --git a/src/backend/src/services/EngPortalService.js b/src/backend/src/services/EngPortalService.js index 26d7db56d6..7e69363ac1 100644 --- a/src/backend/src/services/EngPortalService.js +++ b/src/backend/src/services/EngPortalService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); class EngPortalService extends AdvancedBase { static MODULES = { diff --git a/src/backend/src/services/OperationTraceService.js b/src/backend/src/services/OperationTraceService.js index fd86c8f41f..59c6527bbd 100644 --- a/src/backend/src/services/OperationTraceService.js +++ b/src/backend/src/services/OperationTraceService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const { Context } = require("../util/context"); const { ContextAwareFeature } = require("../traits/ContextAwareFeature"); const { OtelFeature } = require("../traits/OtelFeature"); diff --git a/src/backend/src/services/RegistryService.js b/src/backend/src/services/RegistryService.js index 6b93e4abb5..fe28147117 100644 --- a/src/backend/src/services/RegistryService.js +++ b/src/backend/src/services/RegistryService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const BaseService = require("./BaseService"); class MapCollection extends AdvancedBase { diff --git a/src/backend/src/services/ServicePatch.js b/src/backend/src/services/ServicePatch.js index f5b93b5b5b..57521585a6 100644 --- a/src/backend/src/services/ServicePatch.js +++ b/src/backend/src/services/ServicePatch.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); class ServicePatch extends AdvancedBase { patch ({ original_service }) { diff --git a/src/backend/src/services/StorageService.js b/src/backend/src/services/StorageService.js index c10f981255..f9dfa08b5b 100644 --- a/src/backend/src/services/StorageService.js +++ b/src/backend/src/services/StorageService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); class StorageService extends AdvancedBase { constructor ({ services }) { diff --git a/src/backend/src/services/WSPushService.js b/src/backend/src/services/WSPushService.js index 95a9bf7efd..669c16dca1 100644 --- a/src/backend/src/services/WSPushService.js +++ b/src/backend/src/services/WSPushService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); class WSPushService extends AdvancedBase { static MODULES = { diff --git a/src/backend/src/services/abuse-prevention/IdentificationService.js b/src/backend/src/services/abuse-prevention/IdentificationService.js index 4d2cd2204c..9de738a9c6 100644 --- a/src/backend/src/services/abuse-prevention/IdentificationService.js +++ b/src/backend/src/services/abuse-prevention/IdentificationService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const BaseService = require("../BaseService"); const { Context } = require("../../util/context"); const config = require("../../config"); diff --git a/src/backend/src/services/auth/Actor.js b/src/backend/src/services/auth/Actor.js index 410da5b191..8c929a4ed5 100644 --- a/src/backend/src/services/auth/Actor.js +++ b/src/backend/src/services/auth/Actor.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const { Context } = require("../../util/context"); const { get_user, get_app } = require("../../helpers"); const config = require("../../config"); diff --git a/src/backend/src/services/database/BaseDatabaseAccessService.js b/src/backend/src/services/database/BaseDatabaseAccessService.js index 4396d16f46..3b6fa0c877 100644 --- a/src/backend/src/services/database/BaseDatabaseAccessService.js +++ b/src/backend/src/services/database/BaseDatabaseAccessService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const BaseService = require("../BaseService"); const { DB_WRITE, DB_READ } = require("./consts"); diff --git a/src/backend/src/services/drivers/DriverService.js b/src/backend/src/services/drivers/DriverService.js index 8eb9082369..e4f8c176ea 100644 --- a/src/backend/src/services/drivers/DriverService.js +++ b/src/backend/src/services/drivers/DriverService.js @@ -23,7 +23,7 @@ const { TypedValue } = require("./meta/Runtime"); const BaseService = require("../BaseService"); const { Driver } = require("../../definitions/Driver"); const { PermissionUtil } = require("../auth/PermissionService"); -const { Invoker } = require("@heyputer/puter-js-common/src/libs/invoker"); +const { Invoker } = require("../../../../putil/src/libs/invoker"); const { get_user } = require("../../helpers"); /** diff --git a/src/backend/src/services/drivers/FileFacade.js b/src/backend/src/services/drivers/FileFacade.js index 0a6d1b1aa3..3dd65f8b09 100644 --- a/src/backend/src/services/drivers/FileFacade.js +++ b/src/backend/src/services/drivers/FileFacade.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const { Context } = require("../../util/context"); const { MultiValue } = require("../../util/multivalue"); const { stream_to_buffer } = require("../../util/streamutil"); diff --git a/src/backend/src/services/drivers/meta/Construct.js b/src/backend/src/services/drivers/meta/Construct.js index 57f8cf93df..9e344b1107 100644 --- a/src/backend/src/services/drivers/meta/Construct.js +++ b/src/backend/src/services/drivers/meta/Construct.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { BasicBase } = require("@heyputer/puter-js-common/src/bases/BasicBase"); +const { BasicBase } = require("../../../../../putil/src/bases/BasicBase"); const types = require("../types"); const { hash_serializable_object, stringify_serializable_object } = require("../../../util/datautil"); diff --git a/src/backend/src/services/drivers/meta/Runtime.js b/src/backend/src/services/drivers/meta/Runtime.js index efad76c3cd..361626fd9d 100644 --- a/src/backend/src/services/drivers/meta/Runtime.js +++ b/src/backend/src/services/drivers/meta/Runtime.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { BasicBase } = require("@heyputer/puter-js-common/src/bases/BasicBase"); +const { BasicBase } = require("../../../../../putil/src/bases/BasicBase"); const { TypeSpec } = require("./Construct"); class RuntimeEntity extends BasicBase { diff --git a/src/backend/src/services/drivers/types.js b/src/backend/src/services/drivers/types.js index 1c227bd9f7..fc0f00c829 100644 --- a/src/backend/src/services/drivers/types.js +++ b/src/backend/src/services/drivers/types.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const { is_valid_path } = require("../../filesystem/validation"); const { is_valid_url, is_valid_uuid4 } = require("../../helpers"); const { FileFacade } = require("./FileFacade"); diff --git a/src/backend/src/services/file-cache/FileCacheService.js b/src/backend/src/services/file-cache/FileCacheService.js index c46e437e0e..faefe20de2 100644 --- a/src/backend/src/services/file-cache/FileCacheService.js +++ b/src/backend/src/services/file-cache/FileCacheService.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ const TeePromise = require("@heyputer/multest/src/util/TeePromise"); -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const { FileTracker } = require("./FileTracker"); const { pausing_tee } = require("../../util/streamutil"); diff --git a/src/backend/src/services/sla/RateLimitService.js b/src/backend/src/services/sla/RateLimitService.js index ecaf7a30f7..86d5b77a91 100644 --- a/src/backend/src/services/sla/RateLimitService.js +++ b/src/backend/src/services/sla/RateLimitService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const APIError = require("../../api/APIError"); const { Context } = require("../../util/context"); const BaseService = require("../BaseService"); diff --git a/src/backend/src/services/thumbnails/HTTPThumbnailService.js b/src/backend/src/services/thumbnails/HTTPThumbnailService.js index 805d124e29..6c133f66c6 100644 --- a/src/backend/src/services/thumbnails/HTTPThumbnailService.js +++ b/src/backend/src/services/thumbnails/HTTPThumbnailService.js @@ -22,7 +22,7 @@ const axios = require('axios'); const { TeePromise } = require("../../util/promise"); -const { AdvancedBase } = require('@heyputer/puter-js-common'); +const { AdvancedBase } = require('@heyputer/putil'); const FormData = require("form-data"); const { stream_to_the_void, buffer_to_stream } = require('../../util/streamutil'); const BaseService = require('../BaseService'); diff --git a/src/backend/src/util/multivalue.js b/src/backend/src/util/multivalue.js index c834e506ba..fdda6630ae 100644 --- a/src/backend/src/util/multivalue.js +++ b/src/backend/src/util/multivalue.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); /** * MutliValue represents a subject with multiple values or a value with multiple diff --git a/src/backend/src/util/pathutil.js b/src/backend/src/util/pathutil.js index c75d070a38..124bfb3a88 100644 --- a/src/backend/src/util/pathutil.js +++ b/src/backend/src/util/pathutil.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); /** * PathBuilder implements the builder pattern for building paths. diff --git a/src/backend/tools/test.js b/src/backend/tools/test.js index 4eb44fc0aa..65fbd41979 100644 --- a/src/backend/tools/test.js +++ b/src/backend/tools/test.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/puter-js-common"); +const { AdvancedBase } = require("@heyputer/putil"); const useapi = require("useapi"); const { BaseService } = require("../exports"); const CoreModule = require("../src/CoreModule"); diff --git a/src/git/src/filesystem.js b/src/git/src/filesystem.js index 8ad0cbce55..6ef6fe0a44 100644 --- a/src/git/src/filesystem.js +++ b/src/git/src/filesystem.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { PosixError } from '@heyputer/puter-js-common/src/PosixError.js'; +import { PosixError } from '@heyputer/putil/src/PosixError.js'; import path_ from 'path-browserify'; let debug = false; diff --git a/src/phoenix/src/platform/node/filesystem.js b/src/phoenix/src/platform/node/filesystem.js index 7ca9930953..7e66a1708e 100644 --- a/src/phoenix/src/platform/node/filesystem.js +++ b/src/phoenix/src/platform/node/filesystem.js @@ -20,7 +20,7 @@ import fs from 'fs'; import path_ from 'path'; import modeString from 'fs-mode-to-string'; -import { ErrorCodes, PosixError } from '@heyputer/puter-js-common/src/PosixError.js'; +import { ErrorCodes, PosixError } from '@heyputer/putil/src/PosixError.js'; // DRY: Almost the same as puter/filesystem.js function wrapAPIs(apis) { diff --git a/src/phoenix/src/platform/puter/filesystem.js b/src/phoenix/src/platform/puter/filesystem.js index 49bc878fe1..d118814567 100644 --- a/src/phoenix/src/platform/puter/filesystem.js +++ b/src/phoenix/src/platform/puter/filesystem.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { ErrorCodes, PosixError } from '@heyputer/puter-js-common/src/PosixError.js'; +import { ErrorCodes, PosixError } from '@heyputer/putil/src/PosixError.js'; // DRY: Almost the same as node/filesystem.js function wrapAPIs(apis) { diff --git a/src/phoenix/src/puter-shell/coreutils/errno.js b/src/phoenix/src/puter-shell/coreutils/errno.js index 8ea010c1df..8ffcde10b3 100644 --- a/src/phoenix/src/puter-shell/coreutils/errno.js +++ b/src/phoenix/src/puter-shell/coreutils/errno.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { ErrorCodes, ErrorMetadata, errorFromIntegerCode } from '@heyputer/puter-js-common/src/PosixError.js'; +import { ErrorCodes, ErrorMetadata, errorFromIntegerCode } from '@heyputer/putil/src/PosixError.js'; import { Exit } from './coreutil_lib/exit.js'; const maxErrorNameLength = Object.keys(ErrorCodes) diff --git a/src/phoenix/src/puter-shell/coreutils/touch.js b/src/phoenix/src/puter-shell/coreutils/touch.js index d77b09d3d6..8ebb653112 100644 --- a/src/phoenix/src/puter-shell/coreutils/touch.js +++ b/src/phoenix/src/puter-shell/coreutils/touch.js @@ -18,7 +18,7 @@ */ import { Exit } from './coreutil_lib/exit.js'; import { resolveRelativePath } from '../../util/path.js'; -import { ErrorCodes } from '@heyputer/puter-js-common/src/PosixError.js'; +import { ErrorCodes } from '@heyputer/putil/src/PosixError.js'; export default { name: 'touch', diff --git a/src/phoenix/test/coreutils/errno.js b/src/phoenix/test/coreutils/errno.js index b749de46f9..036fb8e651 100644 --- a/src/phoenix/test/coreutils/errno.js +++ b/src/phoenix/test/coreutils/errno.js @@ -19,7 +19,7 @@ import assert from 'assert'; import { MakeTestContext } from './harness.js' import builtins from '../../src/puter-shell/coreutils/__exports__.js'; -import { ErrorCodes, ErrorMetadata } from '@heyputer/puter-js-common/src/PosixError.js'; +import { ErrorCodes, ErrorMetadata } from '@heyputer/putil/src/PosixError.js'; export const runErrnoTests = () => { describe('errno', function () { diff --git a/src/pty/exports.js b/src/pty/exports.js index 997fb79701..2dcd319711 100644 --- a/src/pty/exports.js +++ b/src/pty/exports.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { libs } from '@heyputer/puter-js-common'; +import { libs } from '@heyputer/putil'; const { TeePromise, raceCase } = libs.promise; const encoder = new TextEncoder(); diff --git a/src/puter-js-common/README.md b/src/putil/README.md similarity index 100% rename from src/puter-js-common/README.md rename to src/putil/README.md diff --git a/src/puter-js-common/index.js b/src/putil/index.js similarity index 100% rename from src/puter-js-common/index.js rename to src/putil/index.js diff --git a/src/puter-js-common/package.json b/src/putil/package.json similarity index 84% rename from src/puter-js-common/package.json rename to src/putil/package.json index f6de28c109..cbe89b9a77 100644 --- a/src/puter-js-common/package.json +++ b/src/putil/package.json @@ -1,5 +1,5 @@ { - "name": "@heyputer/puter-js-common", + "name": "@heyputer/putil", "version": "1.0.0", "description": "", "main": "index.js", diff --git a/src/puter-js-common/src/AdvancedBase.js b/src/putil/src/AdvancedBase.js similarity index 100% rename from src/puter-js-common/src/AdvancedBase.js rename to src/putil/src/AdvancedBase.js diff --git a/src/puter-js-common/src/PosixError.js b/src/putil/src/PosixError.js similarity index 100% rename from src/puter-js-common/src/PosixError.js rename to src/putil/src/PosixError.js diff --git a/src/puter-js-common/src/bases/BasicBase.js b/src/putil/src/bases/BasicBase.js similarity index 100% rename from src/puter-js-common/src/bases/BasicBase.js rename to src/putil/src/bases/BasicBase.js diff --git a/src/puter-js-common/src/bases/FeatureBase.js b/src/putil/src/bases/FeatureBase.js similarity index 100% rename from src/puter-js-common/src/bases/FeatureBase.js rename to src/putil/src/bases/FeatureBase.js diff --git a/src/puter-js-common/src/features/NodeModuleDIFeature.js b/src/putil/src/features/NodeModuleDIFeature.js similarity index 100% rename from src/puter-js-common/src/features/NodeModuleDIFeature.js rename to src/putil/src/features/NodeModuleDIFeature.js diff --git a/src/puter-js-common/src/features/PropertiesFeature.js b/src/putil/src/features/PropertiesFeature.js similarity index 100% rename from src/puter-js-common/src/features/PropertiesFeature.js rename to src/putil/src/features/PropertiesFeature.js diff --git a/src/puter-js-common/src/features/TraitsFeature.js b/src/putil/src/features/TraitsFeature.js similarity index 100% rename from src/puter-js-common/src/features/TraitsFeature.js rename to src/putil/src/features/TraitsFeature.js diff --git a/src/puter-js-common/src/libs/invoker.js b/src/putil/src/libs/invoker.js similarity index 100% rename from src/puter-js-common/src/libs/invoker.js rename to src/putil/src/libs/invoker.js diff --git a/src/puter-js-common/src/libs/promise.js b/src/putil/src/libs/promise.js similarity index 100% rename from src/puter-js-common/src/libs/promise.js rename to src/putil/src/libs/promise.js diff --git a/src/puter-js-common/test/test.js b/src/putil/test/test.js similarity index 100% rename from src/puter-js-common/test/test.js rename to src/putil/test/test.js From cf24c3dd2a030e133ec7028e13c373a1431f0373 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 29 Aug 2024 22:21:07 -0400 Subject: [PATCH 0803/2119] rename --- package-lock.json | 22 +++++++++---------- src/backend/doc/contributors/index.md | 2 +- src/backend/doc/contributors/modules.md | 2 +- src/backend/package.json | 2 +- src/backend/src/CoreModule.js | 2 +- src/backend/src/DatabaseModule.js | 2 +- src/backend/src/Kernel.js | 2 +- src/backend/src/LocalDiskStorageModule.js | 2 +- src/backend/src/PuterDriversModule.js | 2 +- src/backend/src/ThirdPartyDriversModule.js | 2 +- src/backend/src/boot/RuntimeEnvironment.js | 2 +- src/backend/src/config/ConfigLoader.js | 2 +- src/backend/src/definitions/Driver.js | 2 +- .../src/filesystem/FilesystemService.js | 2 +- .../src/filesystem/batch/BatchExecutor.js | 2 +- src/backend/src/filesystem/batch/commands.js | 2 +- .../storage/DatabaseFSEntryService.js | 2 +- .../src/modules/broadcast/BroadcastModule.js | 2 +- .../src/modules/broadcast/BroadcastService.js | 2 +- .../modules/broadcast/connection/BaseLink.js | 2 +- .../broadcast/connection/KeyPairHelper.js | 2 +- .../src/modules/puterai/PuterAIModule.js | 2 +- .../modules/selfhosted/SelfHostedModule.js | 14 +++++++++++- .../modules/test-drivers/TestDriversModule.js | 2 +- src/backend/src/om/IdentifierUtil.js | 2 +- src/backend/src/om/definitions/Mapping.js | 2 +- src/backend/src/om/definitions/PropType.js | 2 +- src/backend/src/om/definitions/Property.js | 2 +- src/backend/src/om/entitystorage/BaseES.js | 2 +- src/backend/src/om/entitystorage/Entity.js | 2 +- src/backend/src/om/entitystorage/SQLES.js | 2 +- .../src/om/entitystorage/ValidationES.js | 2 +- src/backend/src/om/query/query.js | 2 +- src/backend/src/routers/_default.js | 7 ++++++ src/backend/src/routers/hosting/puter-site.js | 2 +- src/backend/src/services/BaseService.js | 2 +- src/backend/src/services/Container.js | 2 +- src/backend/src/services/EngPortalService.js | 2 +- .../src/services/OperationTraceService.js | 2 +- src/backend/src/services/RegistryService.js | 2 +- src/backend/src/services/ServicePatch.js | 2 +- src/backend/src/services/StorageService.js | 2 +- src/backend/src/services/WSPushService.js | 2 +- .../abuse-prevention/IdentificationService.js | 2 +- src/backend/src/services/auth/Actor.js | 2 +- .../database/BaseDatabaseAccessService.js | 2 +- .../src/services/drivers/DriverService.js | 2 +- .../src/services/drivers/FileFacade.js | 2 +- .../src/services/drivers/meta/Construct.js | 2 +- .../src/services/drivers/meta/Runtime.js | 2 +- src/backend/src/services/drivers/types.js | 2 +- .../services/file-cache/FileCacheService.js | 2 +- .../src/services/sla/RateLimitService.js | 2 +- .../thumbnails/HTTPThumbnailService.js | 2 +- src/backend/src/util/multivalue.js | 2 +- src/backend/src/util/pathutil.js | 2 +- src/backend/tools/test.js | 2 +- src/git/src/filesystem.js | 2 +- src/phoenix/src/platform/node/filesystem.js | 2 +- src/phoenix/src/platform/puter/filesystem.js | 2 +- .../src/puter-shell/coreutils/errno.js | 2 +- .../src/puter-shell/coreutils/touch.js | 2 +- src/phoenix/test/coreutils/errno.js | 2 +- src/pty/exports.js | 2 +- src/putil/package.json | 8 ++++--- 65 files changed, 97 insertions(+), 76 deletions(-) diff --git a/package-lock.json b/package-lock.json index 140dc5a2ed..6a07b082e1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -43,7 +43,7 @@ "dependencies": { "@heyputer/kv.js": "^0.1.3", "@heyputer/multest": "^0.0.2", - "@heyputer/putil": "^1.0.0", + "@heyputer/putility": "^1.0.0", "@opentelemetry/api": "^1.4.1", "@opentelemetry/auto-instrumentations-node": "^0.43.0", "@opentelemetry/exporter-trace-otlp-grpc": "^0.40.0", @@ -195,7 +195,7 @@ "webpack-cli": "^5.1.4" } }, - "asdf/putil": { + "asdf/putility": { "version": "1.0.0", "extraneous": true, "license": "UNLICENSED" @@ -2605,8 +2605,8 @@ "resolved": "src/puter-js", "link": true }, - "node_modules/@heyputer/putil": { - "resolved": "src/putil", + "node_modules/@heyputer/putility": { + "resolved": "src/putility", "link": true }, "node_modules/@heyputer/terminal": { @@ -16446,7 +16446,7 @@ "dependencies": { "@heyputer/kv.js": "^0.1.3", "@heyputer/multest": "^0.0.2", - "@heyputer/putil": "^1.0.0", + "@heyputer/putility": "^1.0.0", "@opentelemetry/api": "^1.4.1", "@opentelemetry/auto-instrumentations-node": "^0.43.0", "@opentelemetry/exporter-trace-otlp-grpc": "^0.40.0", @@ -16621,8 +16621,8 @@ "webpack-cli": "^5.1.4" } }, - "packages/putil": { - "name": "@heyputer/putil", + "packages/putility": { + "name": "@heyputer/putility", "version": "1.0.0", "extraneous": true, "license": "UNLICENSED" @@ -16666,7 +16666,7 @@ "@aws-sdk/client-textract": "^3.621.0", "@heyputer/kv.js": "^0.1.3", "@heyputer/multest": "^0.0.2", - "@heyputer/putil": "^1.0.0", + "@heyputer/putility": "^1.0.0", "@mistralai/mistralai": "^1.0.3", "@opentelemetry/api": "^1.4.1", "@opentelemetry/auto-instrumentations-node": "^0.43.0", @@ -16911,10 +16911,10 @@ "version": "1.0.0", "license": "AGPL-3.0-only" }, - "src/putil": { - "name": "@heyputer/putil", + "src/putility": { + "name": "@heyputer/putility", "version": "1.0.0", - "license": "UNLICENSED" + "license": "AGPL-3.0-only" }, "src/strataparse": { "version": "0.0.0", diff --git a/src/backend/doc/contributors/index.md b/src/backend/doc/contributors/index.md index a73a5a4038..381aeef0df 100644 --- a/src/backend/doc/contributors/index.md +++ b/src/backend/doc/contributors/index.md @@ -71,7 +71,7 @@ doing the useless work that reveals what the useful work is. ## Underlying Constructs -- [putil's README.md](../../packages/putil/README.md) +- [putility's README.md](../../packages/putility/README.md) - Whenever you see `AdvancedBase`, that's from here - Many things in backend extend this. Anything that doesn't only doesn't because it was written before `AdvancedBase` existed. diff --git a/src/backend/doc/contributors/modules.md b/src/backend/doc/contributors/modules.md index c20816c3d8..c19b49d666 100644 --- a/src/backend/doc/contributors/modules.md +++ b/src/backend/doc/contributors/modules.md @@ -35,7 +35,7 @@ To function properly, Puter needs **CoreModule**, a database module, and a storage module. A module extends -[AdvancedBase](../../../putil/README.md) +[AdvancedBase](../../../putility/README.md) and implements an `install` method. The install method has one parameter, a [Context](../../src/util/context.js) diff --git a/src/backend/package.json b/src/backend/package.json index ec2f197d30..7794c4ae07 100644 --- a/src/backend/package.json +++ b/src/backend/package.json @@ -12,7 +12,7 @@ "@aws-sdk/client-textract": "^3.621.0", "@heyputer/kv.js": "^0.1.3", "@heyputer/multest": "^0.0.2", - "@heyputer/putil": "^1.0.0", + "@heyputer/putility": "^1.0.0", "@mistralai/mistralai": "^1.0.3", "@opentelemetry/api": "^1.4.1", "@opentelemetry/auto-instrumentations-node": "^0.43.0", diff --git a/src/backend/src/CoreModule.js b/src/backend/src/CoreModule.js index f9026030b7..6f3dc2433a 100644 --- a/src/backend/src/CoreModule.js +++ b/src/backend/src/CoreModule.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const Library = require("./definitions/Library"); const { NotificationES } = require("./om/entitystorage/NotificationES"); const { ProtectedAppES } = require("./om/entitystorage/ProtectedAppES"); diff --git a/src/backend/src/DatabaseModule.js b/src/backend/src/DatabaseModule.js index 1ba54a743f..02abeb4e42 100644 --- a/src/backend/src/DatabaseModule.js +++ b/src/backend/src/DatabaseModule.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); class DatabaseModule extends AdvancedBase { async install (context) { diff --git a/src/backend/src/Kernel.js b/src/backend/src/Kernel.js index abcd163010..f3747bb770 100644 --- a/src/backend/src/Kernel.js +++ b/src/backend/src/Kernel.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const { Context } = require('./util/context'); const BaseService = require("./services/BaseService"); const useapi = require('useapi'); diff --git a/src/backend/src/LocalDiskStorageModule.js b/src/backend/src/LocalDiskStorageModule.js index 65736f9b40..56a25b5052 100644 --- a/src/backend/src/LocalDiskStorageModule.js +++ b/src/backend/src/LocalDiskStorageModule.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); class LocalDiskStorageModule extends AdvancedBase { async install (context) { diff --git a/src/backend/src/PuterDriversModule.js b/src/backend/src/PuterDriversModule.js index c828080a25..7cb6e55e52 100644 --- a/src/backend/src/PuterDriversModule.js +++ b/src/backend/src/PuterDriversModule.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); class PuterDriversModule extends AdvancedBase { async install () {} diff --git a/src/backend/src/ThirdPartyDriversModule.js b/src/backend/src/ThirdPartyDriversModule.js index 9c0486a80d..ed70278b83 100644 --- a/src/backend/src/ThirdPartyDriversModule.js +++ b/src/backend/src/ThirdPartyDriversModule.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); class ThirdPartyDriversModule extends AdvancedBase { // constructor () { diff --git a/src/backend/src/boot/RuntimeEnvironment.js b/src/backend/src/boot/RuntimeEnvironment.js index b602a75349..339cca08a0 100644 --- a/src/backend/src/boot/RuntimeEnvironment.js +++ b/src/backend/src/boot/RuntimeEnvironment.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const { quot } = require("../util/strutil"); const { TechnicalError } = require("../errors/TechnicalError"); const { print_error_help } = require("../errors/error_help_details"); diff --git a/src/backend/src/config/ConfigLoader.js b/src/backend/src/config/ConfigLoader.js index a9ff1e9d71..0bb2bd76c8 100644 --- a/src/backend/src/config/ConfigLoader.js +++ b/src/backend/src/config/ConfigLoader.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const { quot } = require("../util/strutil"); class ConfigLoader extends AdvancedBase { diff --git a/src/backend/src/definitions/Driver.js b/src/backend/src/definitions/Driver.js index 6eaf3f2320..ea1e4425bf 100644 --- a/src/backend/src/definitions/Driver.js +++ b/src/backend/src/definitions/Driver.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const { Context } = require('../util/context') const APIError = require("../api/APIError"); const { AppUnderUserActorType, UserActorType } = require("../services/auth/Actor"); diff --git a/src/backend/src/filesystem/FilesystemService.js b/src/backend/src/filesystem/FilesystemService.js index bc47a6537a..e6de744c50 100644 --- a/src/backend/src/filesystem/FilesystemService.js +++ b/src/backend/src/filesystem/FilesystemService.js @@ -27,7 +27,7 @@ const SystemFSEntryService = require('./storage/SystemFSEntryService.js'); const PerformanceMonitor = require('../monitor/PerformanceMonitor.js'); const { NodePathSelector, NodeUIDSelector, NodeInternalIDSelector } = require('./node/selectors.js'); const FSNodeContext = require('./FSNodeContext.js'); -const { AdvancedBase } = require('@heyputer/putil'); +const { AdvancedBase } = require('@heyputer/putility'); const { Context } = require('../util/context.js'); const { simple_retry } = require('../util/retryutil.js'); const APIError = require('../api/APIError.js'); diff --git a/src/backend/src/filesystem/batch/BatchExecutor.js b/src/backend/src/filesystem/batch/BatchExecutor.js index 53f6059f6b..f7a50ad1e7 100644 --- a/src/backend/src/filesystem/batch/BatchExecutor.js +++ b/src/backend/src/filesystem/batch/BatchExecutor.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require('@heyputer/putil'); +const { AdvancedBase } = require('@heyputer/putility'); const PathResolver = require('../../routers/filesystem_api/batch/PathResolver'); const commands = require('./commands').commands; const { WorkUnit } = require('../../services/runtime-analysis/ExpectationService'); diff --git a/src/backend/src/filesystem/batch/commands.js b/src/backend/src/filesystem/batch/commands.js index b0ba0c7b5f..00459b11e7 100644 --- a/src/backend/src/filesystem/batch/commands.js +++ b/src/backend/src/filesystem/batch/commands.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const { AsyncProviderFeature } = require("../../traits/AsyncProviderFeature"); const { HLMkdir, QuickMkdir } = require("../hl_operations/hl_mkdir"); const { Context } = require("../../util/context"); diff --git a/src/backend/src/filesystem/storage/DatabaseFSEntryService.js b/src/backend/src/filesystem/storage/DatabaseFSEntryService.js index 88adb0f815..5244857f84 100644 --- a/src/backend/src/filesystem/storage/DatabaseFSEntryService.js +++ b/src/backend/src/filesystem/storage/DatabaseFSEntryService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const { id2path } = require("../../helpers"); const { PuterPath } = require("../lib/PuterPath"); diff --git a/src/backend/src/modules/broadcast/BroadcastModule.js b/src/backend/src/modules/broadcast/BroadcastModule.js index 89dc422f85..6b44d71593 100644 --- a/src/backend/src/modules/broadcast/BroadcastModule.js +++ b/src/backend/src/modules/broadcast/BroadcastModule.js @@ -1,4 +1,4 @@ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); class BroadcastModule extends AdvancedBase { async install (context) { diff --git a/src/backend/src/modules/broadcast/BroadcastService.js b/src/backend/src/modules/broadcast/BroadcastService.js index 1365ab1499..4344b1030f 100644 --- a/src/backend/src/modules/broadcast/BroadcastService.js +++ b/src/backend/src/modules/broadcast/BroadcastService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const BaseService = require("../../services/BaseService"); const { CLink } = require("./connection/CLink"); const { SLink } = require("./connection/SLink"); diff --git a/src/backend/src/modules/broadcast/connection/BaseLink.js b/src/backend/src/modules/broadcast/connection/BaseLink.js index e0c4b8a2d7..7b321c7fe7 100644 --- a/src/backend/src/modules/broadcast/connection/BaseLink.js +++ b/src/backend/src/modules/broadcast/connection/BaseLink.js @@ -1,4 +1,4 @@ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const { ChannelFeature } = require("../../../traits/ChannelFeature"); class BaseLink extends AdvancedBase { diff --git a/src/backend/src/modules/broadcast/connection/KeyPairHelper.js b/src/backend/src/modules/broadcast/connection/KeyPairHelper.js index 8c24d69fcd..e9fc1da4ec 100644 --- a/src/backend/src/modules/broadcast/connection/KeyPairHelper.js +++ b/src/backend/src/modules/broadcast/connection/KeyPairHelper.js @@ -1,4 +1,4 @@ -const { AdvancedBase } = require('@heyputer/putil'); +const { AdvancedBase } = require('@heyputer/putility'); class KeyPairHelper extends AdvancedBase { static MODULES = { diff --git a/src/backend/src/modules/puterai/PuterAIModule.js b/src/backend/src/modules/puterai/PuterAIModule.js index 9b6ac6fab2..5552b39063 100644 --- a/src/backend/src/modules/puterai/PuterAIModule.js +++ b/src/backend/src/modules/puterai/PuterAIModule.js @@ -1,4 +1,4 @@ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const config = require("../../config"); class PuterAIModule extends AdvancedBase { diff --git a/src/backend/src/modules/selfhosted/SelfHostedModule.js b/src/backend/src/modules/selfhosted/SelfHostedModule.js index 038d6f4c88..c35e7f2a6b 100644 --- a/src/backend/src/modules/selfhosted/SelfHostedModule.js +++ b/src/backend/src/modules/selfhosted/SelfHostedModule.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const config = require("../../config"); class SelfHostedModule extends AdvancedBase { @@ -111,6 +111,18 @@ class SelfHostedModule extends AdvancedBase { 'src/puter-js/dist/puter.dev.js'), route: '/puter.js/v2', }); + services.registerService('__serve-putilityjs-new', ServeSingleFileService, { + path: path_.resolve(__dirname, + RELATIVE_PATH, + 'src/putility/dist/putility.dev.js'), + route: '/putility.js/v1', + }); + services.registerService('__serve-gui-js', ServeSingleFileService, { + path: path_.resolve(__dirname, + RELATIVE_PATH, + 'src/gui/dist/gui.dev.js'), + route: '/putility.js/v1', + }); } } diff --git a/src/backend/src/modules/test-drivers/TestDriversModule.js b/src/backend/src/modules/test-drivers/TestDriversModule.js index 3f564ec724..c30756d9cb 100644 --- a/src/backend/src/modules/test-drivers/TestDriversModule.js +++ b/src/backend/src/modules/test-drivers/TestDriversModule.js @@ -1,4 +1,4 @@ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); class TestDriversModule extends AdvancedBase { async install (context) { diff --git a/src/backend/src/om/IdentifierUtil.js b/src/backend/src/om/IdentifierUtil.js index 5eb7eea200..1e1ab9bb94 100644 --- a/src/backend/src/om/IdentifierUtil.js +++ b/src/backend/src/om/IdentifierUtil.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const { WeakConstructorFeature } = require("../traits/WeakConstructorFeature"); const { Eq, And } = require("./query/query"); const { Entity } = require("./entitystorage/Entity"); diff --git a/src/backend/src/om/definitions/Mapping.js b/src/backend/src/om/definitions/Mapping.js index 47a3587b2b..cae78d1437 100644 --- a/src/backend/src/om/definitions/Mapping.js +++ b/src/backend/src/om/definitions/Mapping.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const { instance_ } = require("../../monitor/PerformanceMonitor"); const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature"); const { Property } = require("./Property"); diff --git a/src/backend/src/om/definitions/PropType.js b/src/backend/src/om/definitions/PropType.js index 72477819e0..201d2700af 100644 --- a/src/backend/src/om/definitions/PropType.js +++ b/src/backend/src/om/definitions/PropType.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature"); class PropType extends AdvancedBase { diff --git a/src/backend/src/om/definitions/Property.js b/src/backend/src/om/definitions/Property.js index 3789da272a..dc7c87bfb4 100644 --- a/src/backend/src/om/definitions/Property.js +++ b/src/backend/src/om/definitions/Property.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature"); class Property extends AdvancedBase { diff --git a/src/backend/src/om/entitystorage/BaseES.js b/src/backend/src/om/entitystorage/BaseES.js index ddb49b95dd..b66f18b08a 100644 --- a/src/backend/src/om/entitystorage/BaseES.js +++ b/src/backend/src/om/entitystorage/BaseES.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature"); const { Context } = require("../../util/context"); diff --git a/src/backend/src/om/entitystorage/Entity.js b/src/backend/src/om/entitystorage/Entity.js index abaedb330d..3094f55cef 100644 --- a/src/backend/src/om/entitystorage/Entity.js +++ b/src/backend/src/om/entitystorage/Entity.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature"); class Entity extends AdvancedBase { diff --git a/src/backend/src/om/entitystorage/SQLES.js b/src/backend/src/om/entitystorage/SQLES.js index 61c901bfd0..dc81efa139 100644 --- a/src/backend/src/om/entitystorage/SQLES.js +++ b/src/backend/src/om/entitystorage/SQLES.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const { BaseES } = require("./BaseES"); const APIError = require("../../api/APIError"); diff --git a/src/backend/src/om/entitystorage/ValidationES.js b/src/backend/src/om/entitystorage/ValidationES.js index cfcf01b287..485a940837 100644 --- a/src/backend/src/om/entitystorage/ValidationES.js +++ b/src/backend/src/om/entitystorage/ValidationES.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const { BaseES } = require("./BaseES"); const APIError = require("../../api/APIError"); diff --git a/src/backend/src/om/query/query.js b/src/backend/src/om/query/query.js index bdde50a30f..519d8fceb8 100644 --- a/src/backend/src/om/query/query.js +++ b/src/backend/src/om/query/query.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const { WeakConstructorFeature } = require("../../traits/WeakConstructorFeature"); class Predicate extends AdvancedBase { diff --git a/src/backend/src/routers/_default.js b/src/backend/src/routers/_default.js index 0c843e8327..0c764a121c 100644 --- a/src/backend/src/routers/_default.js +++ b/src/backend/src/routers/_default.js @@ -87,6 +87,13 @@ router.all('*', async function(req, res, next) { } }); } + if (path === '/putility/v1') { + return res.sendFile(_path.join(__dirname, config.defaultjs_asset_path, 'putility.js/v1.js'), function (err) { + if (err && err.statusCode) { + return res.status(err.statusCode).send('Error /putility.js') + } + }); + } } const db = Context.get('services').get('database').get(DB_READ, 'default'); diff --git a/src/backend/src/routers/hosting/puter-site.js b/src/backend/src/routers/hosting/puter-site.js index 251ff8e3a2..a2680a6be2 100644 --- a/src/backend/src/routers/hosting/puter-site.js +++ b/src/backend/src/routers/hosting/puter-site.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const api_error_handler = require("../../api/api_error_handler"); const config = require("../../config"); const { get_user, get_app, id2path } = require("../../helpers"); diff --git a/src/backend/src/services/BaseService.js b/src/backend/src/services/BaseService.js index 0455b709fe..e325d7f0ec 100644 --- a/src/backend/src/services/BaseService.js +++ b/src/backend/src/services/BaseService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const NOOP = async () => {}; diff --git a/src/backend/src/services/Container.js b/src/backend/src/services/Container.js index 0a55f8fd57..44878f8f3a 100644 --- a/src/backend/src/services/Container.js +++ b/src/backend/src/services/Container.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const config = require("../config"); const { Context } = require("../util/context"); const { CompositeError } = require("../util/errorutil"); diff --git a/src/backend/src/services/EngPortalService.js b/src/backend/src/services/EngPortalService.js index 7e69363ac1..ce507568ef 100644 --- a/src/backend/src/services/EngPortalService.js +++ b/src/backend/src/services/EngPortalService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); class EngPortalService extends AdvancedBase { static MODULES = { diff --git a/src/backend/src/services/OperationTraceService.js b/src/backend/src/services/OperationTraceService.js index 59c6527bbd..751efee3f6 100644 --- a/src/backend/src/services/OperationTraceService.js +++ b/src/backend/src/services/OperationTraceService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const { Context } = require("../util/context"); const { ContextAwareFeature } = require("../traits/ContextAwareFeature"); const { OtelFeature } = require("../traits/OtelFeature"); diff --git a/src/backend/src/services/RegistryService.js b/src/backend/src/services/RegistryService.js index fe28147117..3b1f45a7af 100644 --- a/src/backend/src/services/RegistryService.js +++ b/src/backend/src/services/RegistryService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const BaseService = require("./BaseService"); class MapCollection extends AdvancedBase { diff --git a/src/backend/src/services/ServicePatch.js b/src/backend/src/services/ServicePatch.js index 57521585a6..e34312bdc0 100644 --- a/src/backend/src/services/ServicePatch.js +++ b/src/backend/src/services/ServicePatch.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); class ServicePatch extends AdvancedBase { patch ({ original_service }) { diff --git a/src/backend/src/services/StorageService.js b/src/backend/src/services/StorageService.js index f9dfa08b5b..77b740070c 100644 --- a/src/backend/src/services/StorageService.js +++ b/src/backend/src/services/StorageService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); class StorageService extends AdvancedBase { constructor ({ services }) { diff --git a/src/backend/src/services/WSPushService.js b/src/backend/src/services/WSPushService.js index 669c16dca1..0ef17302b1 100644 --- a/src/backend/src/services/WSPushService.js +++ b/src/backend/src/services/WSPushService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); class WSPushService extends AdvancedBase { static MODULES = { diff --git a/src/backend/src/services/abuse-prevention/IdentificationService.js b/src/backend/src/services/abuse-prevention/IdentificationService.js index 9de738a9c6..75005df725 100644 --- a/src/backend/src/services/abuse-prevention/IdentificationService.js +++ b/src/backend/src/services/abuse-prevention/IdentificationService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const BaseService = require("../BaseService"); const { Context } = require("../../util/context"); const config = require("../../config"); diff --git a/src/backend/src/services/auth/Actor.js b/src/backend/src/services/auth/Actor.js index 8c929a4ed5..0c35597f12 100644 --- a/src/backend/src/services/auth/Actor.js +++ b/src/backend/src/services/auth/Actor.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const { Context } = require("../../util/context"); const { get_user, get_app } = require("../../helpers"); const config = require("../../config"); diff --git a/src/backend/src/services/database/BaseDatabaseAccessService.js b/src/backend/src/services/database/BaseDatabaseAccessService.js index 3b6fa0c877..16e5af9c54 100644 --- a/src/backend/src/services/database/BaseDatabaseAccessService.js +++ b/src/backend/src/services/database/BaseDatabaseAccessService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const BaseService = require("../BaseService"); const { DB_WRITE, DB_READ } = require("./consts"); diff --git a/src/backend/src/services/drivers/DriverService.js b/src/backend/src/services/drivers/DriverService.js index e4f8c176ea..bca02abe90 100644 --- a/src/backend/src/services/drivers/DriverService.js +++ b/src/backend/src/services/drivers/DriverService.js @@ -23,7 +23,7 @@ const { TypedValue } = require("./meta/Runtime"); const BaseService = require("../BaseService"); const { Driver } = require("../../definitions/Driver"); const { PermissionUtil } = require("../auth/PermissionService"); -const { Invoker } = require("../../../../putil/src/libs/invoker"); +const { Invoker } = require("../../../../putility/src/libs/invoker"); const { get_user } = require("../../helpers"); /** diff --git a/src/backend/src/services/drivers/FileFacade.js b/src/backend/src/services/drivers/FileFacade.js index 3dd65f8b09..5fa01fb61e 100644 --- a/src/backend/src/services/drivers/FileFacade.js +++ b/src/backend/src/services/drivers/FileFacade.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const { Context } = require("../../util/context"); const { MultiValue } = require("../../util/multivalue"); const { stream_to_buffer } = require("../../util/streamutil"); diff --git a/src/backend/src/services/drivers/meta/Construct.js b/src/backend/src/services/drivers/meta/Construct.js index 9e344b1107..aebbc57e3c 100644 --- a/src/backend/src/services/drivers/meta/Construct.js +++ b/src/backend/src/services/drivers/meta/Construct.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { BasicBase } = require("../../../../../putil/src/bases/BasicBase"); +const { BasicBase } = require("../../../../../putility/src/bases/BasicBase"); const types = require("../types"); const { hash_serializable_object, stringify_serializable_object } = require("../../../util/datautil"); diff --git a/src/backend/src/services/drivers/meta/Runtime.js b/src/backend/src/services/drivers/meta/Runtime.js index 361626fd9d..a830a602b7 100644 --- a/src/backend/src/services/drivers/meta/Runtime.js +++ b/src/backend/src/services/drivers/meta/Runtime.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { BasicBase } = require("../../../../../putil/src/bases/BasicBase"); +const { BasicBase } = require("../../../../../putility/src/bases/BasicBase"); const { TypeSpec } = require("./Construct"); class RuntimeEntity extends BasicBase { diff --git a/src/backend/src/services/drivers/types.js b/src/backend/src/services/drivers/types.js index fc0f00c829..0afa870114 100644 --- a/src/backend/src/services/drivers/types.js +++ b/src/backend/src/services/drivers/types.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const { is_valid_path } = require("../../filesystem/validation"); const { is_valid_url, is_valid_uuid4 } = require("../../helpers"); const { FileFacade } = require("./FileFacade"); diff --git a/src/backend/src/services/file-cache/FileCacheService.js b/src/backend/src/services/file-cache/FileCacheService.js index faefe20de2..13378f25cd 100644 --- a/src/backend/src/services/file-cache/FileCacheService.js +++ b/src/backend/src/services/file-cache/FileCacheService.js @@ -17,7 +17,7 @@ * along with this program. If not, see . */ const TeePromise = require("@heyputer/multest/src/util/TeePromise"); -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const { FileTracker } = require("./FileTracker"); const { pausing_tee } = require("../../util/streamutil"); diff --git a/src/backend/src/services/sla/RateLimitService.js b/src/backend/src/services/sla/RateLimitService.js index 86d5b77a91..344e4599fe 100644 --- a/src/backend/src/services/sla/RateLimitService.js +++ b/src/backend/src/services/sla/RateLimitService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const APIError = require("../../api/APIError"); const { Context } = require("../../util/context"); const BaseService = require("../BaseService"); diff --git a/src/backend/src/services/thumbnails/HTTPThumbnailService.js b/src/backend/src/services/thumbnails/HTTPThumbnailService.js index 6c133f66c6..ab75ab719e 100644 --- a/src/backend/src/services/thumbnails/HTTPThumbnailService.js +++ b/src/backend/src/services/thumbnails/HTTPThumbnailService.js @@ -22,7 +22,7 @@ const axios = require('axios'); const { TeePromise } = require("../../util/promise"); -const { AdvancedBase } = require('@heyputer/putil'); +const { AdvancedBase } = require('@heyputer/putility'); const FormData = require("form-data"); const { stream_to_the_void, buffer_to_stream } = require('../../util/streamutil'); const BaseService = require('../BaseService'); diff --git a/src/backend/src/util/multivalue.js b/src/backend/src/util/multivalue.js index fdda6630ae..06950b53f3 100644 --- a/src/backend/src/util/multivalue.js +++ b/src/backend/src/util/multivalue.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); /** * MutliValue represents a subject with multiple values or a value with multiple diff --git a/src/backend/src/util/pathutil.js b/src/backend/src/util/pathutil.js index 124bfb3a88..004323f9c0 100644 --- a/src/backend/src/util/pathutil.js +++ b/src/backend/src/util/pathutil.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); /** * PathBuilder implements the builder pattern for building paths. diff --git a/src/backend/tools/test.js b/src/backend/tools/test.js index 65fbd41979..f1f03773a4 100644 --- a/src/backend/tools/test.js +++ b/src/backend/tools/test.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putil"); +const { AdvancedBase } = require("@heyputer/putility"); const useapi = require("useapi"); const { BaseService } = require("../exports"); const CoreModule = require("../src/CoreModule"); diff --git a/src/git/src/filesystem.js b/src/git/src/filesystem.js index 6ef6fe0a44..58bed4cda6 100644 --- a/src/git/src/filesystem.js +++ b/src/git/src/filesystem.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { PosixError } from '@heyputer/putil/src/PosixError.js'; +import { PosixError } from '@heyputer/putility/src/PosixError.js'; import path_ from 'path-browserify'; let debug = false; diff --git a/src/phoenix/src/platform/node/filesystem.js b/src/phoenix/src/platform/node/filesystem.js index 7e66a1708e..c42b255557 100644 --- a/src/phoenix/src/platform/node/filesystem.js +++ b/src/phoenix/src/platform/node/filesystem.js @@ -20,7 +20,7 @@ import fs from 'fs'; import path_ from 'path'; import modeString from 'fs-mode-to-string'; -import { ErrorCodes, PosixError } from '@heyputer/putil/src/PosixError.js'; +import { ErrorCodes, PosixError } from '@heyputer/putility/src/PosixError.js'; // DRY: Almost the same as puter/filesystem.js function wrapAPIs(apis) { diff --git a/src/phoenix/src/platform/puter/filesystem.js b/src/phoenix/src/platform/puter/filesystem.js index d118814567..22d939a29e 100644 --- a/src/phoenix/src/platform/puter/filesystem.js +++ b/src/phoenix/src/platform/puter/filesystem.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { ErrorCodes, PosixError } from '@heyputer/putil/src/PosixError.js'; +import { ErrorCodes, PosixError } from '@heyputer/putility/src/PosixError.js'; // DRY: Almost the same as node/filesystem.js function wrapAPIs(apis) { diff --git a/src/phoenix/src/puter-shell/coreutils/errno.js b/src/phoenix/src/puter-shell/coreutils/errno.js index 8ffcde10b3..65d7e6c49e 100644 --- a/src/phoenix/src/puter-shell/coreutils/errno.js +++ b/src/phoenix/src/puter-shell/coreutils/errno.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { ErrorCodes, ErrorMetadata, errorFromIntegerCode } from '@heyputer/putil/src/PosixError.js'; +import { ErrorCodes, ErrorMetadata, errorFromIntegerCode } from '@heyputer/putility/src/PosixError.js'; import { Exit } from './coreutil_lib/exit.js'; const maxErrorNameLength = Object.keys(ErrorCodes) diff --git a/src/phoenix/src/puter-shell/coreutils/touch.js b/src/phoenix/src/puter-shell/coreutils/touch.js index 8ebb653112..e90fab6787 100644 --- a/src/phoenix/src/puter-shell/coreutils/touch.js +++ b/src/phoenix/src/puter-shell/coreutils/touch.js @@ -18,7 +18,7 @@ */ import { Exit } from './coreutil_lib/exit.js'; import { resolveRelativePath } from '../../util/path.js'; -import { ErrorCodes } from '@heyputer/putil/src/PosixError.js'; +import { ErrorCodes } from '@heyputer/putility/src/PosixError.js'; export default { name: 'touch', diff --git a/src/phoenix/test/coreutils/errno.js b/src/phoenix/test/coreutils/errno.js index 036fb8e651..4790368948 100644 --- a/src/phoenix/test/coreutils/errno.js +++ b/src/phoenix/test/coreutils/errno.js @@ -19,7 +19,7 @@ import assert from 'assert'; import { MakeTestContext } from './harness.js' import builtins from '../../src/puter-shell/coreutils/__exports__.js'; -import { ErrorCodes, ErrorMetadata } from '@heyputer/putil/src/PosixError.js'; +import { ErrorCodes, ErrorMetadata } from '@heyputer/putility/src/PosixError.js'; export const runErrnoTests = () => { describe('errno', function () { diff --git a/src/pty/exports.js b/src/pty/exports.js index 2dcd319711..ece4662931 100644 --- a/src/pty/exports.js +++ b/src/pty/exports.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -import { libs } from '@heyputer/putil'; +import { libs } from '@heyputer/putility'; const { TeePromise, raceCase } = libs.promise; const encoder = new TextEncoder(); diff --git a/src/putil/package.json b/src/putil/package.json index cbe89b9a77..80a2b5846b 100644 --- a/src/putil/package.json +++ b/src/putil/package.json @@ -1,11 +1,13 @@ { - "name": "@heyputer/putil", + "name": "@heyputer/putility", "version": "1.0.0", "description": "", "main": "index.js", "scripts": { - "test": "echo \"Error: no test specified\" && exit 1" + "test": "echo \"Error: no test specified\" && exit 1", + "start-webpack": "webpack ./index.js --output-filename putility.js --output-library putility && webpack ./index.js --output-filename putility.dev.js --output-library putility --watch --devtool source-map", + "build": "webpack ./index.js --output-filename putility.js --output-library putility && { echo \"// Copyright 2024 Puter Technologies Inc. All rights reserved.\"; echo \"// Generated on $(date '+%Y-%m-%d %H:%M')\n\"; cat ./dist/putility.js; echo \"\"; } > temp && mv temp ./dist/putility.js" }, "author": "Puter Technologies Inc.", - "license": "UNLICENSED" + "license": "AGPL-3.0-only" } From a4e9c7bdd775b5b670176e117dc8f64cfa5b88ae Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 29 Aug 2024 22:24:55 -0400 Subject: [PATCH 0804/2119] rename folder --- package-lock.json | 8 +++++++- src/backend/src/services/BaseService.js | 2 +- src/backend/src/services/OperationTraceService.js | 2 +- src/backend/src/services/auth/Actor.js | 2 +- .../src/services/database/BaseDatabaseAccessService.js | 2 +- src/backend/src/services/drivers/FileFacade.js | 2 +- src/backend/src/services/drivers/types.js | 2 +- src/backend/src/util/multivalue.js | 2 +- src/backend/src/util/pathutil.js | 2 +- src/{putil => putility}/README.md | 0 src/{putil => putility}/index.js | 0 src/{putil => putility}/package.json | 0 src/{putil => putility}/src/AdvancedBase.js | 0 src/{putil => putility}/src/PosixError.js | 0 src/{putil => putility}/src/bases/BasicBase.js | 0 src/{putil => putility}/src/bases/FeatureBase.js | 0 .../src/features/NodeModuleDIFeature.js | 0 src/{putil => putility}/src/features/PropertiesFeature.js | 0 src/{putil => putility}/src/features/TraitsFeature.js | 0 src/{putil => putility}/src/libs/invoker.js | 0 src/{putil => putility}/src/libs/promise.js | 0 src/{putil => putility}/test/test.js | 0 22 files changed, 15 insertions(+), 9 deletions(-) rename src/{putil => putility}/README.md (100%) rename src/{putil => putility}/index.js (100%) rename src/{putil => putility}/package.json (100%) rename src/{putil => putility}/src/AdvancedBase.js (100%) rename src/{putil => putility}/src/PosixError.js (100%) rename src/{putil => putility}/src/bases/BasicBase.js (100%) rename src/{putil => putility}/src/bases/FeatureBase.js (100%) rename src/{putil => putility}/src/features/NodeModuleDIFeature.js (100%) rename src/{putil => putility}/src/features/PropertiesFeature.js (100%) rename src/{putil => putility}/src/features/TraitsFeature.js (100%) rename src/{putil => putility}/src/libs/invoker.js (100%) rename src/{putil => putility}/src/libs/promise.js (100%) rename src/{putil => putility}/test/test.js (100%) diff --git a/package-lock.json b/package-lock.json index 6a07b082e1..56e501e557 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2606,7 +2606,7 @@ "link": true }, "node_modules/@heyputer/putility": { - "resolved": "src/putility", + "resolved": "src/putil", "link": true }, "node_modules/@heyputer/terminal": { @@ -16911,9 +16911,15 @@ "version": "1.0.0", "license": "AGPL-3.0-only" }, + "src/putil": { + "name": "@heyputer/putility", + "version": "1.0.0", + "license": "AGPL-3.0-only" + }, "src/putility": { "name": "@heyputer/putility", "version": "1.0.0", + "extraneous": true, "license": "AGPL-3.0-only" }, "src/strataparse": { diff --git a/src/backend/src/services/BaseService.js b/src/backend/src/services/BaseService.js index e325d7f0ec..83ba918a8f 100644 --- a/src/backend/src/services/BaseService.js +++ b/src/backend/src/services/BaseService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putility"); +const { AdvancedBase } = require("../../../putility"); const NOOP = async () => {}; diff --git a/src/backend/src/services/OperationTraceService.js b/src/backend/src/services/OperationTraceService.js index 751efee3f6..7ade53f4d8 100644 --- a/src/backend/src/services/OperationTraceService.js +++ b/src/backend/src/services/OperationTraceService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putility"); +const { AdvancedBase } = require("../../../putility"); const { Context } = require("../util/context"); const { ContextAwareFeature } = require("../traits/ContextAwareFeature"); const { OtelFeature } = require("../traits/OtelFeature"); diff --git a/src/backend/src/services/auth/Actor.js b/src/backend/src/services/auth/Actor.js index 0c35597f12..b1dde3b0e9 100644 --- a/src/backend/src/services/auth/Actor.js +++ b/src/backend/src/services/auth/Actor.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putility"); +const { AdvancedBase } = require("../../../../putility"); const { Context } = require("../../util/context"); const { get_user, get_app } = require("../../helpers"); const config = require("../../config"); diff --git a/src/backend/src/services/database/BaseDatabaseAccessService.js b/src/backend/src/services/database/BaseDatabaseAccessService.js index 16e5af9c54..ebac058bf9 100644 --- a/src/backend/src/services/database/BaseDatabaseAccessService.js +++ b/src/backend/src/services/database/BaseDatabaseAccessService.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putility"); +const { AdvancedBase } = require("../../../../putility"); const BaseService = require("../BaseService"); const { DB_WRITE, DB_READ } = require("./consts"); diff --git a/src/backend/src/services/drivers/FileFacade.js b/src/backend/src/services/drivers/FileFacade.js index 5fa01fb61e..8b3aa355f1 100644 --- a/src/backend/src/services/drivers/FileFacade.js +++ b/src/backend/src/services/drivers/FileFacade.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putility"); +const { AdvancedBase } = require("../../../../putility"); const { Context } = require("../../util/context"); const { MultiValue } = require("../../util/multivalue"); const { stream_to_buffer } = require("../../util/streamutil"); diff --git a/src/backend/src/services/drivers/types.js b/src/backend/src/services/drivers/types.js index 0afa870114..031d867e0a 100644 --- a/src/backend/src/services/drivers/types.js +++ b/src/backend/src/services/drivers/types.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putility"); +const { AdvancedBase } = require("../../../../putility"); const { is_valid_path } = require("../../filesystem/validation"); const { is_valid_url, is_valid_uuid4 } = require("../../helpers"); const { FileFacade } = require("./FileFacade"); diff --git a/src/backend/src/util/multivalue.js b/src/backend/src/util/multivalue.js index 06950b53f3..0e696d5768 100644 --- a/src/backend/src/util/multivalue.js +++ b/src/backend/src/util/multivalue.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putility"); +const { AdvancedBase } = require("../../../putility"); /** * MutliValue represents a subject with multiple values or a value with multiple diff --git a/src/backend/src/util/pathutil.js b/src/backend/src/util/pathutil.js index 004323f9c0..6fd0e13485 100644 --- a/src/backend/src/util/pathutil.js +++ b/src/backend/src/util/pathutil.js @@ -16,7 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("@heyputer/putility"); +const { AdvancedBase } = require("../../../putility"); /** * PathBuilder implements the builder pattern for building paths. diff --git a/src/putil/README.md b/src/putility/README.md similarity index 100% rename from src/putil/README.md rename to src/putility/README.md diff --git a/src/putil/index.js b/src/putility/index.js similarity index 100% rename from src/putil/index.js rename to src/putility/index.js diff --git a/src/putil/package.json b/src/putility/package.json similarity index 100% rename from src/putil/package.json rename to src/putility/package.json diff --git a/src/putil/src/AdvancedBase.js b/src/putility/src/AdvancedBase.js similarity index 100% rename from src/putil/src/AdvancedBase.js rename to src/putility/src/AdvancedBase.js diff --git a/src/putil/src/PosixError.js b/src/putility/src/PosixError.js similarity index 100% rename from src/putil/src/PosixError.js rename to src/putility/src/PosixError.js diff --git a/src/putil/src/bases/BasicBase.js b/src/putility/src/bases/BasicBase.js similarity index 100% rename from src/putil/src/bases/BasicBase.js rename to src/putility/src/bases/BasicBase.js diff --git a/src/putil/src/bases/FeatureBase.js b/src/putility/src/bases/FeatureBase.js similarity index 100% rename from src/putil/src/bases/FeatureBase.js rename to src/putility/src/bases/FeatureBase.js diff --git a/src/putil/src/features/NodeModuleDIFeature.js b/src/putility/src/features/NodeModuleDIFeature.js similarity index 100% rename from src/putil/src/features/NodeModuleDIFeature.js rename to src/putility/src/features/NodeModuleDIFeature.js diff --git a/src/putil/src/features/PropertiesFeature.js b/src/putility/src/features/PropertiesFeature.js similarity index 100% rename from src/putil/src/features/PropertiesFeature.js rename to src/putility/src/features/PropertiesFeature.js diff --git a/src/putil/src/features/TraitsFeature.js b/src/putility/src/features/TraitsFeature.js similarity index 100% rename from src/putil/src/features/TraitsFeature.js rename to src/putility/src/features/TraitsFeature.js diff --git a/src/putil/src/libs/invoker.js b/src/putility/src/libs/invoker.js similarity index 100% rename from src/putil/src/libs/invoker.js rename to src/putility/src/libs/invoker.js diff --git a/src/putil/src/libs/promise.js b/src/putility/src/libs/promise.js similarity index 100% rename from src/putil/src/libs/promise.js rename to src/putility/src/libs/promise.js diff --git a/src/putil/test/test.js b/src/putility/test/test.js similarity index 100% rename from src/putil/test/test.js rename to src/putility/test/test.js From 0d01d1f80017ed54b3cc24072f550a3a97f28074 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 29 Aug 2024 19:45:05 -0700 Subject: [PATCH 0805/2119] Update package-lock.json --- package-lock.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 56e501e557..2ce61209f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2606,7 +2606,7 @@ "link": true }, "node_modules/@heyputer/putility": { - "resolved": "src/putil", + "resolved": "src/putility", "link": true }, "node_modules/@heyputer/terminal": { @@ -16914,12 +16914,12 @@ "src/putil": { "name": "@heyputer/putility", "version": "1.0.0", + "extraneous": true, "license": "AGPL-3.0-only" }, "src/putility": { "name": "@heyputer/putility", "version": "1.0.0", - "extraneous": true, "license": "AGPL-3.0-only" }, "src/strataparse": { From 8ad435a0ea402c5b7c32b309113b08b29512fff3 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 29 Aug 2024 21:10:22 -0400 Subject: [PATCH 0806/2119] dev: bundle gui in dev --- package-lock.json | 8 +- .../modules/selfhosted/SelfHostedModule.js | 6 ++ .../src/services/PuterHomepageService.js | 39 +-------- src/gui/doc/webpack_attempts.md | 81 +++++++++++++++++++ src/gui/{src => }/package.json | 3 +- src/gui/src/index.js | 4 +- src/gui/utils.js | 14 ++-- src/gui/webpack.config.cjs | 8 ++ src/gui/webpack/BaseConfig.cjs | 27 +++++++ src/gui/webpack/EmitPlugin.cjs | 78 ++++++++++++++++++ src/gui/webpack/libPaths.cjs | 15 ++++ 11 files changed, 232 insertions(+), 51 deletions(-) create mode 100644 src/gui/doc/webpack_attempts.md rename src/gui/{src => }/package.json (90%) create mode 100644 src/gui/webpack.config.cjs create mode 100644 src/gui/webpack/BaseConfig.cjs create mode 100644 src/gui/webpack/EmitPlugin.cjs create mode 100644 src/gui/webpack/libPaths.cjs diff --git a/package-lock.json b/package-lock.json index 2ce61209f5..16947f4cb1 100644 --- a/package-lock.json +++ b/package-lock.json @@ -2545,6 +2545,10 @@ "resolved": "src/backend", "link": true }, + "node_modules/@heyputer/gui": { + "resolved": "src/gui", + "link": true + }, "node_modules/@heyputer/kv.js": { "version": "0.1.6", "resolved": "https://registry.npmjs.org/@heyputer/kv.js/-/kv.js-0.1.6.tgz", @@ -16790,8 +16794,8 @@ } }, "src/gui": { - "version": "2.3.0", - "extraneous": true, + "name": "@heyputer/gui", + "version": "2.4.0", "license": "AGPL-3.0-only", "workspaces": [ "src/*" diff --git a/src/backend/src/modules/selfhosted/SelfHostedModule.js b/src/backend/src/modules/selfhosted/SelfHostedModule.js index c35e7f2a6b..9bbd3523c1 100644 --- a/src/backend/src/modules/selfhosted/SelfHostedModule.js +++ b/src/backend/src/modules/selfhosted/SelfHostedModule.js @@ -48,6 +48,12 @@ class SelfHostedModule extends AdvancedBase { command: 'npm', args: ['run', 'start-webpack'], }, + { + name: 'gui:webpack-watch', + directory: 'src/gui', + command: 'npm', + args: ['run', 'start-webpack'], + }, { name: 'terminal:rollup-watch', directory: 'src/terminal', diff --git a/src/backend/src/services/PuterHomepageService.js b/src/backend/src/services/PuterHomepageService.js index b623662086..ce5238e999 100644 --- a/src/backend/src/services/PuterHomepageService.js +++ b/src/backend/src/services/PuterHomepageService.js @@ -255,46 +255,9 @@ class PuterHomepageService extends BaseService { ? `` : '' } - ${ - ((!bundled && manifest?.lib_paths) - ? manifest.lib_paths.map(path => `\n`) - : []).join('') - } - - - ${ - ((!bundled && manifest?.js_paths) - ? manifest.js_paths.map(path => writeScriptTag(path)) - : []).join('') - } - + + + + + + +<% if (htmlWebpackPlugin.options.appMountId) { %> +
+<% } %> + +<% if (htmlWebpackPlugin.options.appMountIds && htmlWebpackPlugin.options.appMountIds.length > 0) { %> +<% for (var index in htmlWebpackPlugin.options.appMountIds) { %> +
+<% } %> +<% } %> + +<% if (htmlWebpackPlugin.options.window) { %> + +<% } %> + +<% for (var chunk in htmlWebpackPlugin.files.chunks) { %> + +<% } %> + + + \ No newline at end of file diff --git a/src/emulator/package.json b/src/emulator/package.json new file mode 100644 index 0000000000..3879a47270 --- /dev/null +++ b/src/emulator/package.json @@ -0,0 +1,16 @@ +{ + "name": "emulator", + "version": "1.0.0", + "main": "index.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1", + "start-webpack": "webpack --watch --devtool source-map" + }, + "keywords": [], + "author": "", + "license": "AGPL-3.0-only", + "description": "", + "devDependencies": { + "html-webpack-plugin": "^5.6.0" + } +} diff --git a/src/emulator/src/main.js b/src/emulator/src/main.js new file mode 100644 index 0000000000..e4d8630c18 --- /dev/null +++ b/src/emulator/src/main.js @@ -0,0 +1 @@ +puter.ui.launchApp('editor'); diff --git a/src/emulator/webpack.config.js b/src/emulator/webpack.config.js new file mode 100644 index 0000000000..6983e59a3a --- /dev/null +++ b/src/emulator/webpack.config.js @@ -0,0 +1,12 @@ +const HtmlWebpackPlugin = require('html-webpack-plugin'); + +module.exports = { + entry: [ + './src/main.js' + ], + plugins: [ + new HtmlWebpackPlugin({ + template: 'assets/template.html' + }), + ] +}; diff --git a/submodules/v86 b/submodules/v86 new file mode 160000 index 0000000000..f3339aa78e --- /dev/null +++ b/submodules/v86 @@ -0,0 +1 @@ +Subproject commit f3339aa78eeb9221d24ff86a2ea74b9ee1d2ee90 From cd39bb5aa073286baa053f8458f0af54a4b7313a Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 2 Sep 2024 20:50:15 -0400 Subject: [PATCH 0825/2119] fix: fix sourcemap --- src/gui/webpack.config.cjs | 6 +- src/gui/webpack/BaseConfig.cjs | 4 +- src/gui/webpack/EmitPlugin.cjs | 132 +++++++++++++++++---------------- 3 files changed, 72 insertions(+), 70 deletions(-) diff --git a/src/gui/webpack.config.cjs b/src/gui/webpack.config.cjs index 3c1c4fed8d..b69b9c06d3 100644 --- a/src/gui/webpack.config.cjs +++ b/src/gui/webpack.config.cjs @@ -1,8 +1,8 @@ const BaseConfig = require('./webpack/BaseConfig.cjs'); -module.exports = { - ...BaseConfig({ env: 'dev' }), +module.exports = async () => ({ + ...(await BaseConfig({ env: 'dev' })), optimization: { minimize: false }, -}; +}); diff --git a/src/gui/webpack/BaseConfig.cjs b/src/gui/webpack/BaseConfig.cjs index 9e0d636586..7c736b350d 100644 --- a/src/gui/webpack/BaseConfig.cjs +++ b/src/gui/webpack/BaseConfig.cjs @@ -1,6 +1,6 @@ const path = require('path'); const EmitPlugin = require('./EmitPlugin.cjs'); -module.exports = (options = {}) => { +module.exports = async (options = {}) => { const config = {}; config.entry = [ './src/init_sync.js', @@ -18,7 +18,7 @@ module.exports = (options = {}) => { filename: 'bundle.min.js', }; config.plugins = [ - EmitPlugin({ + await EmitPlugin({ options, dir: path.join(__dirname, '../src/icons'), }), diff --git a/src/gui/webpack/EmitPlugin.cjs b/src/gui/webpack/EmitPlugin.cjs index d631abc1f8..9e4fd6ded3 100644 --- a/src/gui/webpack/EmitPlugin.cjs +++ b/src/gui/webpack/EmitPlugin.cjs @@ -1,78 +1,80 @@ const fs = require('fs'); const path = require('path'); const uglifyjs = require('uglify-js'); +const webpack = require('webpack'); -module.exports = ({ dir, options }) => function () { - const compiler = this; - compiler.hooks.emit.tapAsync('EmitPlugin', async (compilation, callback) => { - let prefix_text = ''; - prefix_text += `window.gui_env="${options.env}";\n`; +module.exports = async ({ dir, options }) => { + let prefix_text = ''; + prefix_text += `window.gui_env="${options.env}";\n`; - // ----------------------------------------------- - // Combine all images into a single js file - // ----------------------------------------------- - { - let icons = 'window.icons = [];\n'; - fs.readdirSync(dir).forEach(file => { - // skip dotfiles - if (file.startsWith('.')) - return; - // load image - let buff = new Buffer.from(fs.readFileSync(dir + '/' + file)); - // convert to base64 - let base64data = buff.toString('base64'); - // add to `window.icons` - if (file.endsWith('.png')) - icons += `window.icons['${file}'] = "data:image/png;base64,${base64data}";\n`; - else if (file.endsWith('.svg')) - icons += `window.icons['${file}'] = "data:image/svg+xml;base64,${base64data}";\n`; - }); - prefix_text += icons + '\n'; - } + // ----------------------------------------------- + // Combine all images into a single js file + // ----------------------------------------------- + { + let icons = 'window.icons = [];\n'; + fs.readdirSync(dir).forEach(file => { + // skip dotfiles + if (file.startsWith('.')) + return; + // load image + let buff = new Buffer.from(fs.readFileSync(dir + '/' + file)); + // convert to base64 + let base64data = buff.toString('base64'); + // add to `window.icons` + if (file.endsWith('.png')) + icons += `window.icons['${file}'] = "data:image/png;base64,${base64data}";\n`; + else if (file.endsWith('.svg')) + icons += `window.icons['${file}'] = "data:image/svg+xml;base64,${base64data}";\n`; + }); + prefix_text += icons + '\n'; + } - // ----------------------------------------------- - // Concat/merge the JS libraries and save them to ./dist/libs.js - // ----------------------------------------------- - { - const lib_paths = require('./libPaths.cjs'); - let js = ''; - for(let i = 0; i < lib_paths.length; i++){ - const file = path.join(__dirname, '../src/lib/', lib_paths[i]); - // js - if(file.endsWith('.js') && !file.endsWith('.min.js')){ - let minified_code = await uglifyjs.minify(fs.readFileSync(file).toString(), {mangle: false}); - if(minified_code && minified_code.code){ - js += minified_code.code; - if(options?.verbose) - console.log('minified: ', file); - } - }else{ - js += fs.readFileSync(file); + // ----------------------------------------------- + // Concat/merge the JS libraries and save them to ./dist/libs.js + // ----------------------------------------------- + { + const lib_paths = require('./libPaths.cjs'); + let js = ''; + for(let i = 0; i < lib_paths.length; i++){ + const file = path.join(__dirname, '../src/lib/', lib_paths[i]); + // js + if(file.endsWith('.js') && !file.endsWith('.min.js')){ + let minified_code = await uglifyjs.minify(fs.readFileSync(file).toString(), {mangle: false}); + if(minified_code && minified_code.code){ + js += minified_code.code; if(options?.verbose) - console.log('skipped minification: ', file); + console.log('minified: ', file); } - - js += '\n\n\n'; + }else{ + js += fs.readFileSync(file); + if(options?.verbose) + console.log('skipped minification: ', file); } - prefix_text += js; + + js += '\n\n\n'; } + prefix_text += js; + } + + return new webpack.BannerPlugin({ + banner: prefix_text, + raw: true, + }); - // ----------------------------------------------- - // Webpack understands this code better than I do - // ----------------------------------------------- - Object.keys(compilation.assets).forEach((assetName) => { - if (assetName.endsWith('.js')) { - const asset = compilation.assets[assetName]; - const originalSource = asset.source(); - const newSource = `${prefix_text}\n${originalSource}`; - compilation.assets[assetName] = { - source: () => newSource, - size: () => newSource.length, - }; - } - }); + // ----------------------------------------------- + // Webpack understands this code better than I do + // ----------------------------------------------- + // Object.keys(compilation.assets).forEach((assetName) => { + // if (assetName.endsWith('.js')) { + // const asset = compilation.assets[assetName]; + // const originalSource = asset.source(); + // const newSource = `${prefix_text}\n${originalSource}`; + // compilation.assets[assetName] = { + // source: () => newSource, + // size: () => newSource.length, + // }; + // } + // }); - console.log('END'); - callback(); - }); + console.log('END'); }; From d35026467eb9a5f67d6ec0c99f2a24d418b8e3a5 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 2 Sep 2024 20:52:46 -0400 Subject: [PATCH 0826/2119] fix: use jq el for focus --- src/gui/src/services/ExecService.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/src/services/ExecService.js b/src/gui/src/services/ExecService.js index 2146f758db..15ef144cff 100644 --- a/src/gui/src/services/ExecService.js +++ b/src/gui/src/services/ExecService.js @@ -51,8 +51,8 @@ export class ExecService extends Service { // If `window-active` is set (meanign the window is focused), focus the window one more time // this is to ensure that the iframe is `definitely` focused and can receive keyboard events (e.g. keydown) - if(child_process.el_win.hasClass('window-active')){ - child_process.el_win.focusWindow(); + if($(child_process.references.el_win).hasClass('window-active')){ + $(child_process.references.el_win).focusWindow(); } }); From ed7d6dcbfbf432ae90d9e379dbf47de5587a57a2 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 2 Sep 2024 21:30:22 -0400 Subject: [PATCH 0827/2119] fix: dist --- src/gui/utils.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/utils.js b/src/gui/utils.js index 1e11e40d91..389454b647 100644 --- a/src/gui/utils.js +++ b/src/gui/utils.js @@ -129,11 +129,11 @@ async function build(options){ for(let i = 0; i < js_paths.length; i++){ main_array.push(path.join(__dirname, 'src', js_paths[i])); } - webpack({ - ...BaseConfig({ + await webpack({ + ...(await BaseConfig({ ...options, env: 'prod', - }), + })), mode: 'production', optimization: { minimize: true, From e8713dc5a5a0e0a9d839581a776041e8f16c514b Mon Sep 17 00:00:00 2001 From: gng92 Date: Tue, 3 Sep 2024 19:44:42 +0400 Subject: [PATCH 0828/2119] Create README.hy.md Added Armenian translation for ./doc/i18n/README.en.md (issue #735 ) --- doc/i18n/README.hy.md | 131 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 doc/i18n/README.hy.md diff --git a/doc/i18n/README.hy.md b/doc/i18n/README.hy.md new file mode 100644 index 0000000000..b3542cf427 --- /dev/null +++ b/doc/i18n/README.hy.md @@ -0,0 +1,131 @@ +

Puter.com, The Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time.

+ +

Ինտերնետ ՕՀ! Անվճար, բաց կոդով և ինքնահոսթ հնարավորությամբ։

+ +

+ GitHub repo size GitHub Release GitHub License +

+

+ « Օնլայն դեմո » +
+
+ Puter.com + · + SDK + · + Discord + · + YouTube + · + Reddit + · + X (Twitter) + · + Bug Bounty +

+ +

screenshot

+ +
+ +## Puter + +Puter-ը առաջադեմ, բաց կոդով ինտերնետային օպերացիոն համակարգ է, որը նախագծված է լինել ֆունկցիոնալ հարուստ, բացառիկ արագ և բարձր ընդլայնելի։ Puter-ը կարող է օգտագործվել հետևյալ կերպ․ + +- Անձնական ամպային համակարգ՝ առաջնային գաղտնիությամբ, որը թույլ է տալիս պահել ձեր բոլոր ֆայլերը, հավելվածները և խաղերը մեկ անվտանգ վայրում, որը հասանելի է ցանկացած վայրից և ցանկացած ժամանակ։ +- Պլատֆորմ կայքերի, վեբ հավելվածների և խաղերի ստեղծման և հրապարակման համար։ +- Dropbox, Google Drive, OneDrive և այլ ծառայությունների այլընտրանք՝ նոր ինտերֆեյսով և հզոր գործառույթներով։ +- Հեռավոր աշխատասեղանի միջավայր սերվերների և աշխատանքային կայանների համար։ +- Պարզ, բաց կոդով նախագիծ և համայնք՝ վեբ ծրագրավորման, ամպային հաշվարկների, բաշխված համակարգերի և այլ թեմաների մասին սովորելու համար։ + +
+ +## Սկսել + + +### 💻 Լոկալ ծրագրավորում + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +Սա կգործակի Puter-ը հետևյալ հասցեով՝ http://puter.localhost:4100 (կամ հաջորդ հասանելի պորտով)։ + +
+ +### 🐳 Docker + + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ + +### 🐙 Docker Compose + + +#### Linux/macOS +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` +
+ +#### Windows + + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +### ☁️ Puter.com + +Puter-ը հասանելի է որպես հյուրընկալվող ծառայություն [**puter.com**](https://puter.com). + +
+ +## System Requirements + +- **Օպերացիոն համակարգ:** Linux, macOS, Windows +- **Օպերատիվ հիշողություն:** 2GB նվազագույնը (4GB խորհուրդ է տրվում) +- **Համակարգչի հիշողություն:** 1GB ազատ տարածություն +- **Node.js:** Տարբերակ 16+ (Տարբերակ 22+ խորհուրդ է տրվում) +- **npm:** Վերջին կայուն տարբերակը + +
+ +## Աջակցություն + +Կապվեք համակարգողների և համայնքի հետ այս կայքերի միջոցով՝ + +- Սխալների կամ գործառույթի հարցում՝ (https://github.com/HeyPuter/puter/issues/new/choose). +- Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) +- Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) +- Անվտանգության խնդիրներ՝ [security@puter.com](mailto:security@puter.com) +- Email maintainers at [hi@puter.com](mailto:hi@puter.com) + +Մենք միշտ ուրախ ենք օգնել ձեզ ցանկացած հարցում։ Մի կաշկանդվեք հարցնել։ + +
+ + +## Լիցենզիա + +Այս պահոցարանը, ներառյալ բոլոր իր բովանդակությունը, ենթա-պրոյեկտները, մոդուլները և բաղադրիչները, լիցենզավորվում են [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) լիցենզիայի տակ, եթե այլ կերպ հստակ նշված չէ։ Այս պահոցարանում ներառված երրորդ կողմի գրադարանները կարող են ենթարկվել իրենց սեփական լիցենզիաներին։ + +
From 9528cb0614ac82223207cb0d5cd6624a5a00784b Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 3 Sep 2024 11:55:05 -0400 Subject: [PATCH 0829/2119] Add link to Armenian README in the English README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 20c786b6d5..3c3b42fbd9 100644 --- a/README.md +++ b/README.md @@ -131,6 +131,7 @@ This repository, including all its contents, sub-projects, modules, and componen - [Farsi / فارسی](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.fa.md) - [Arabic / العربية](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ar.md) +- [Armenian / Հայերեն](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.hy.md) - [Bengali / বাংলা](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.bn.md) - [Chinese / 中文](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.zh.md) - [Danish / Dansk](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.da.md) From 8e56ac5ec720acabf23960da4fea7bd1d86128e8 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 3 Sep 2024 14:14:19 -0400 Subject: [PATCH 0830/2119] Update UIWindow.js --- src/gui/src/UI/UIWindow.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/src/UI/UIWindow.js b/src/gui/src/UI/UIWindow.js index 2889b95579..f495debd1d 100644 --- a/src/gui/src/UI/UIWindow.js +++ b/src/gui/src/UI/UIWindow.js @@ -330,6 +330,7 @@ async function UIWindow(options) { allowtransparency="true" allowpaymentrequest="true" allowfullscreen="true" + allow="microphone" webkitallowfullscreen="webkitallowfullscreen" mozallowfullscreen="mozallowfullscreen" sandbox="allow-forms allow-modals allow-pointer-lock allow-popups allow-popups-to-escape-sandbox ${options.iframe_srcdoc ? '' : 'allow-same-origin'} allow-scripts allow-top-navigation-by-user-activation allow-downloads allow-presentation allow-storage-access-by-user-activation">`; From 57c2d72e21be2b3537164e13540a8c59db2239b7 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 3 Sep 2024 14:24:58 -0400 Subject: [PATCH 0831/2119] Update UIWindow.js --- src/gui/src/UI/UIWindow.js | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/gui/src/UI/UIWindow.js b/src/gui/src/UI/UIWindow.js index f495debd1d..f9069c717e 100644 --- a/src/gui/src/UI/UIWindow.js +++ b/src/gui/src/UI/UIWindow.js @@ -313,6 +313,9 @@ async function UIWindow(options) { style="${!options.has_head ? ' height: 100%;' : ''}">`; // iframe, for apps if(options.iframe_url || options.iframe_srcdoc){ + let allow_str = `camera; encrypted-media; gamepad; display-capture; geolocation; gyroscope; microphone; midi; clipboard-read; clipboard-write; fullscreen;`; + if(window.co_isolation_enabled) + allow_str += ' cross-origin-isolated;'; // `; From 4910838ab1a72738b44f948cbf65feea848e5271 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 3 Sep 2024 14:44:51 -0400 Subject: [PATCH 0832/2119] fix: webpack error reporting + unintentional whitespace changes --- src/gui/utils.js | 37 ++++++++++++++++++++----------------- 1 file changed, 20 insertions(+), 17 deletions(-) diff --git a/src/gui/utils.js b/src/gui/utils.js index 389454b647..37f57c6745 100644 --- a/src/gui/utils.js +++ b/src/gui/utils.js @@ -110,7 +110,7 @@ async function build(options){ let fullpath = path.join(__dirname, 'src', css_paths[i]); // minify CSS files if not already minified, then concatenate if(css_paths[i].endsWith('.css') && !css_paths[i].endsWith('.min.css')){ - const minified_css = new CleanCSS({}).minify(fs.readFileSync(fullpath).toString()); + const minified_css = new CleanCSS({}).minify(fs.readFileSync(fullpath).toString()); css += minified_css.styles; } // otherwise, just concatenate the file @@ -129,7 +129,7 @@ async function build(options){ for(let i = 0; i < js_paths.length; i++){ main_array.push(path.join(__dirname, 'src', js_paths[i])); } - await webpack({ + const webpack_opts = { ...(await BaseConfig({ ...options, env: 'prod', @@ -138,12 +138,15 @@ async function build(options){ optimization: { minimize: true, }, - }, (err, stats) => { + } + console.log('webpack opts', webpack_opts); + await webpack(webpack_opts, (err, stats) => { if(err){ - console.error(err); - return; + throw err; + // console.error(err); + // return; } - if(options?.verbose) + //if(options?.verbose) console.log(stats.toString()); // write to ./dist/bundle.min.js // fs.writeFileSync(path.join(__dirname, 'dist', 'bundle.min.js'), fs.readFileSync(path.join(__dirname, 'dist', 'main.js'))); @@ -154,16 +157,16 @@ async function build(options){ // Copy index.js to dist/gui.js // Prepend `window.gui_env="prod";` to `./dist/gui.js` fs.writeFileSync( - path.join(__dirname, 'dist', 'gui.js'), + path.join(__dirname, 'dist', 'gui.js'), `window.gui_env="prod"; \n\n` + fs.readFileSync(path.join(__dirname, 'src', 'index.js')) ); const copy_these = [ - 'images', + 'images', 'fonts', 'favicons', - 'browserconfig.xml', - 'manifest.json', + 'browserconfig.xml', + 'manifest.json', 'favicon.ico', 'security.txt', ]; @@ -192,7 +195,7 @@ async function build(options){ * also includes the necessary CSS and JavaScript files, as well as the required meta tags for social * media sharing and search engine optimization. The function is designed to be used in development * environments to generate the HTML content for the GUI. - * + * * @param {Object} options - The configuration options for the GUI. * @param {string} options.env - The environment in which the GUI is running (e.g., "dev" or "prod"). * @param {string} options.api_origin - The origin of the API server. @@ -204,7 +207,7 @@ async function build(options){ * @param {string} options.origin - The origin of the GUI. * @param {string} options.social_card - The URL of the social media card image. * @returns {string} The HTML content for the GUI based on the specified configuration options. - * + * */ function generateDevHtml(options){ let start_t = Date.now(); @@ -281,7 +284,7 @@ function generateDevHtml(options){ // preload images when applicable h += ``; h += ``; - + h += ``; // To indicate that the GUI is running to any 3rd-party scripts that may be running on the page @@ -295,7 +298,7 @@ function generateDevHtml(options){ h += ``; } } - + // load images and icons as base64 for performance if(options.env === 'dev'){ h += ``; h += ` - - `; - + + `; + console.log(`/index.js: ` + (Date.now() - start_t)/1000); return h; } From 64597e28fba658d5985cc262df554059abdd6013 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 3 Sep 2024 14:56:14 -0400 Subject: [PATCH 0833/2119] temporarily remove lang files for further testing --- doc/i18n/README.nl.md | 124 --------------------------------------- doc/i18n/README.sv.md | 131 ------------------------------------------ doc/i18n/README.ua.md | 127 ---------------------------------------- 3 files changed, 382 deletions(-) delete mode 100644 doc/i18n/README.nl.md delete mode 100644 doc/i18n/README.sv.md delete mode 100644 doc/i18n/README.ua.md diff --git a/doc/i18n/README.nl.md b/doc/i18n/README.nl.md deleted file mode 100644 index 50052eac82..0000000000 --- a/doc/i18n/README.nl.md +++ /dev/null @@ -1,124 +0,0 @@ -

Puter.com, The Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time.

-

Het Internet OS! Gratis, Open-Source en Self-Hostable.

- -

- GitHub repo grootte GitHub Release GitHub Licentie -

-

- « LIVE DEMO » -
-
- Puter.com - · - SDK - · - Discord - · - YouTube - · - Reddit - · - X (Twitter) - · - Bug Bounty -

- -

screenshot

- -
- -## Puter - -Puter is een geavanceerd, open-source internet besturingssysteem dat is ontworpen om rijk aan functies te zijn, uitzonderlijk snel en zeer uitbreidbaar. Puter kan worden gebruikt als: - -- Een privacygerichte persoonlijke cloud om al uw bestanden, apps en games op één veilige plek te bewaren, overal en altijd toegankelijk. -- Een platform voor het bouwen en publiceren van websites, web-apps en games. -- Een alternatief voor Dropbox, Google Drive, OneDrive, etc. met een frisse interface en krachtige functies. -- Een externe desktopomgeving voor servers en werkstations. -- Een vriendelijk, open-source project en community om te leren over webontwikkeling, cloud computing, gedistribueerde systemen en nog veel meer! - -
- -## Aan de slag - -### 💻 Lokale ontwikkeling - -```bash -git clone https://github.com/HeyPuter/puter -cd puter -npm install -npm start -``` - -Dit start Puter op http://puter.localhost:4100 (of de volgende beschikbare poort). - -
- -### 🐳 Docker - -```bash -mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter -``` - -
- -### 🐙 Docker Compose - -#### Linux/macOS -```bash -mkdir -p puter/config puter/data -sudo chown -R 1000:1000 puter -wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml -docker compose up -``` -
- -#### Windows - -```powershell -mkdir -p puter -cd puter -New-Item -Path "puter\config" -ItemType Directory -Force -New-Item -Path "puter\data" -ItemType Directory -Force -Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" -docker compose up -``` -
- -### ☁️ Puter.com - -Puter is beschikbaar als een gehoste service op [**puter.com**](https://puter.com). - -
- -## Systeemvereisten - -- **Besturingssystemen:** Linux, macOS, Windows -- **RAM:** Minimaal 2 GB (4 GB aanbevolen) -- **Schijfruimte:** 1 GB vrije ruimte -- **Node.js:** Versie 16+ (Versie 22+ aanbevolen) -- **npm:** Laatste stabiele versie - -
- -## Ondersteuning - -Neem contact op met de onderhouders en community via deze kanalen: - -- Een bug rapporteren of een functieverzoek indienen? Maak [een issue aan](https://github.com/HeyPuter/puter/issues/new/choose). -- Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) -- X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) -- Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) -- Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) -- Beveiligingsproblemen? [security@puter.com](mailto:security@puter.com) -- E-mail de onderhouders op [hi@puter.com](mailto:hi@puter.com) - -We helpen je graag met al je vragen. Aarzel niet om te vragen! - -
- -## Licentie - -Deze repository, inclusief alle inhoud, subprojecten, modules en componenten, is gelicentieerd onder [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt), tenzij anders vermeld. Derdenbibliotheken die in deze repository zijn opgenomen, kunnen onderworpen zijn aan hun eigen licenties. - -
diff --git a/doc/i18n/README.sv.md b/doc/i18n/README.sv.md deleted file mode 100644 index 4bc8679e39..0000000000 --- a/doc/i18n/README.sv.md +++ /dev/null @@ -1,131 +0,0 @@ -

Puter.com, The Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time.

- -

The Internet OS! Free, Open-Source, and Self-Hostable.

- -

- sizeizeizeize leaseeaseeaseease GitHubeLLicense -

-

- « LIVE DEMO » -
-
- Puter.com - · - SDK - · - Discord - · - YouTube - · - Reddit - · - X (Twitter) - · - Bug Bounty -

- -

screenshot

- -
- -## Puter - -Puter iatusystem designbe feature-ally, exceptionhighly extensiblehly extecsibbe. Puter an be A privacy-firstd as: - an be A privacy-firstd as: - -- cloud to keep personr fileapps,s, apps, and games in one secure place, accessible from anywhere at an- t platform fr building and publishing websites, web apps, and games. -- An alternative to Dropbox, Google Drive, OneDrive, etc. with a fresh interface and powers and workstat- nsote desktop environment for servers and workstations. -- ers and workspenions project and cotedty to ls, and much moredevelopment, Gettis, and mucti -ng, distributDe system Sand much more! - -
- -## Gettis, and muc - - -### 💻 Local DeGetting S - -```bash -git clone https://github.com/HeyPuter/puter -cd puter -npm install -npm start -``` - - next available Puter at http://puter.localhost:4100 (or ate next available port). - -
- -### 🐳 Docker - - -```bash -mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter -``` - -
- - -### 🐙 Docker Compose - - -#### Linux/macOS -```bash -mkdir -p puter/config puter/data -sudo chown -R 1000:1000 puter -wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml -docker compose up -``` -
- -#### Windows - - -```powershell -mkdir -p puter -cd puter -New-Item -Path "puter\config" -ItemType Directory -Force -New-Item -Path "puter\data" -ItemType Directory -Force -Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" -docker compose up -``` -
- -### ☁️ Puter.com - -Puter is available as a hosted service at [**puter.com**](https://puter.com). - -
- -## System Requirements - -- **Operating Systems:** Linux, macOS, Windows -- **RAM:** 2GB minimum (4GB recommended) -- **Disk Space:** 1GB free space -- **Node.js:** Version 16+ (Version 22+ recommended) -- **npm:** Latest stable version - -
- -## Support - -Connect with the maintainers and community through these channels: - -- Bug report or feature request? Please [open an issue](https://github.com/HeyPuter/puter/issues/new/choose). -- Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) -- X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) -- Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) -- Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) -- Security issues? [security@puter.com](mailto:security@puter.com) -- Email maintainers at [hi@puter.com](mailto:hi@puter.com) - -We are always happy to help you with any questions you may have. Don't hesitate to ask! - -
- - -## License - -This repository, including all its contents, sub-projects, modules, and components, is licensed under [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) unless explicitly stated otherwise. Third-party libraries included in this repository may be subject to their own licenses. - -
diff --git a/doc/i18n/README.ua.md b/doc/i18n/README.ua.md deleted file mode 100644 index 17c2965359..0000000000 --- a/doc/i18n/README.ua.md +++ /dev/null @@ -1,127 +0,0 @@ -

Puter.com, The Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time.

-

Інтернет-ОС! Безкоштовна, відкрита та самостійно-хостована.

- -

- Розмір репозиторію GitHub Випуск GitHub Ліцензія GitHub -

-

- « ЖИВИЙ ДЕМО » -
-
- Puter.com - · - SDK - · - Discord - · - YouTube - · - Reddit - · - X (Twitter) - · - Bug Bounty -

- -

знімок екрана

- -
- -## Puter - -Puter - це передова, відкрита операційна система Інтернету, яка має багатий функціонал, виняткову швидкість та високу розширюваність. Puter може бути використаний як: - -- Особистий хмарний сервіс з підвищеною конфіденційністю, щоб зберігати всі ваші файли, додатки та ігри в безпечному місці, доступному з будь-якого місця та в будь-який час. -- Платформа для створення та публікації веб-сайтів, веб-додатків та ігор. -- Альтернатива Dropbox, Google Drive, OneDrive тощо з новим інтерфейсом та потужними функціями. -- Віддалена робоча область для серверів та робочих станцій. -- Дружній відкритий проект та спільнота для вивчення веб-розробки, хмарних обчислень, розподілених систем та багато іншого! - -
- -## Початок роботи - -### 💻 Локальна розробка - -```bash -git clone https://github.com/HeyPuter/puter -cd puter -npm install -npm start -``` - -Це запустить Puter за адресою http://puter.localhost:4100 (або наступний доступний порт). - -
- -### 🐳 Docker - -```bash -mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter -``` - -
- -### 🐙 Docker Compose - -#### Linux/macOS - -```bash -mkdir -p puter/config puter/data -sudo chown -R 1000:1000 puter -wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml -docker compose up -``` - -
- -#### Windows - -```powershell -mkdir -p puter -cd puter -New-Item -Path "puter\config" -ItemType Directory -Force -New-Item -Path "puter\data" -ItemType Directory -Force -Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" -docker compose up -``` - -
- -### ☁️ Puter.com - -Puter доступний як хостована послуга на [**puter.com**](https://puter.com). - -
- -## Системні вимоги - -- **Операційні системи:** Linux, macOS, Windows -- **Оперативна пам'ять:** Мінімум 2 ГБ (рекомендовано 4 ГБ) -- **Дисковий простір:** 1 ГБ вільного місця -- **Node.js:** Версія 16+ (рекомендовано версію 22+) -- **npm:** Остання стабільна версія - -
- -## Підтримка - -Зв'яжіться з розробниками та спільнотою через ці канали: - -- Звіт про помилку або запит функції? Будь ласка, [створіть питання](https://github.com/HeyPuter/puter/issues/new/choose). -- Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) -- X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) -- Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) -- Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) -- Проблеми безпеки? [security@puter.com](mailto:security@puter.com) -- Напишіть розробникам на [hi@puter.com](mailto:hi@puter.com) - -Ми завжди раді допомогти вам з будь-якими питаннями. Не соромтеся запитувати! - -
- -## Ліцензія - -Цей репозиторій, включаючи всі його вміст, підпроекти, модулі та компоненти, ліцензовано за [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt), якщо не зазначено інше. Сторонні бібліотеки, включені в цей репозиторій, можуть підлягати власним ліцензіям. - -
From 72c90778e8ec4d75c2f5f28d67abffe5541fc058 Mon Sep 17 00:00:00 2001 From: Rino Godson Date: Thu, 5 Sep 2024 07:12:27 +0530 Subject: [PATCH 0834/2119] Add Malayalam translation to README.md --- doc/i18n/README.ml.md | 132 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 doc/i18n/README.ml.md diff --git a/doc/i18n/README.ml.md b/doc/i18n/README.ml.md new file mode 100644 index 0000000000..e1f4ace881 --- /dev/null +++ b/doc/i18n/README.ml.md @@ -0,0 +1,132 @@ +

Puter.com, The Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time.

+ +

ഇന്റർനെറ്റ് ഓപ്പറേറ്റിംഗ് സിസ്റ്റം!
സൗജന്യവും, ഓപ്പൺ സോഴ്സും സ്വയം ഹോസ്റ്റ് ചെയ്യാൻ പറ്റുന്നതും

+ +

+ GitHub repo size GitHub Release GitHub License +

+

+ « ലൈവ് ഡെമോ » +
+
+ Puter.com + · + SDK + · + Discord + · + YouTube + · + Reddit + · + X (Twitter) + · + Bug Bounty +

+ +

screenshot

+ +
+ +## പ്യൂട്ടർ (Puter) + +ഫീച്ചറുകളാൽ സമ്പുഷ്ടവും അസാധാരണമാംവിധം വേഗതയേറിയതും,വളരെ വിപുലീകരിക്കാവുന്നതുമായ ഒരു നൂതന, ഓപ്പൺ സോഴ്‌സ് ഇന്റർനെറ്റ് ഓപ്പറേറ്റിംഗ് സിസ്റ്റമാണ് പ്യൂട്ടർ. പ്യൂട്ടർ ഇനിപ്പറയുന്ന രീതിയിൽ ഉപയോഗിക്കാം: + +- നിങ്ങളുടെ എല്ലാ ഫയലുകളും ആപ്പുകളും ഗെയിമുകളും ഒരു സുരക്ഷിത സ്ഥലത്ത് സൂക്ഷിക്കുന്നതിനുള്ള, സ്വകാര്യതയ്ക്ക് മുൻഗണന കൊടുക്കുന്ന ആദ്യത്തെ വ്യക്തിഗത ക്ലൗഡ്, എവിടെ നിന്നും എപ്പോൾ വേണമെങ്കിലും ആക്‌സസ് ചെയ്യാൻ കഴിയും. +- വെബ്‌സൈറ്റുകൾ, വെബ് ആപ്പുകൾ, ഗെയിമുകൾ എന്നിവ നിർമ്മിക്കുന്നതിനും പ്രസിദ്ധീകരിക്കുന്നതിനുമുള്ള ഒരു പ്ലാറ്റ്ഫോം. +- പുതിയ ഇന്റർഫേസും, ശക്തമായ ഫീച്ചറുകളും അടങ്ങിയ, ഡ്രോപ്പ്‌ബോക്‌സ്, ഗൂഗിൾ ഡ്രൈവ്, വൺഡ്രൈവ് മുതലായവയ്‌ക്കുള്ള ബദൽ. +- സെർവറുകൾക്കും വർക്ക്സ്റ്റേഷനുകൾക്കും, ഒരു വിദൂര ഡെസ്ക്ടോപ്പ് പരിസ്ഥിതി. +- വെബ് ഡെവലപ്മെന്റ്, ക്ലൗഡ് കംപ്യൂട്ടിംഗ്, ഡിസ്ട്രിബ്യൂട്ടഡ് സിസ്റ്റങ്ങൾ എന്നിവയെ കുറിച്ചും, അതിലേറെ കാര്യങ്ങളെ കുറിച്ചും അറിയാനുള്ള സൗഹൃദപരവും ഓപ്പൺ സോഴ്സുമായ പ്രോജക്റ്റും കമ്മ്യൂണിറ്റിയും! + +
+ +## തുടങ്ങാനായി + + +### 💻 ലോക്കൽ ഡെവലപ്മെന്റ് + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + + +ഇത് http://puter.localhost:4100 (അല്ലെങ്കിൽ അടുത്ത ലഭ്യമായ പോർട്ടിൽ) എന്നതിൽ Puter സമാരംഭിക്കും + +
+ +### 🐳 Docker + + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ + +### 🐙 Docker Compose + + +#### Linux/macOS +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` +
+ +#### Windows + + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +### ☁️ Puter.com + +പ്യൂട്ടർ [**puter.com**](https://puter.com) എന്നതിൽ ഹോസ്റ്റ് ചെയ്‌ത സേവനമായി ലഭ്യമാണ്. + +
+ +## സിസ്റ്റത്തിന്റെ ആവശ്യകതകൾ + +- **ഓപ്പറേറ്റിംഗ് സിസ്റ്റങ്ങൾ:** ലിനക്സ്, മാക്ക് ഒഎസ്, വിൻഡോസ് +- **RAM:** 2GB കുറഞ്ഞത് (4GB ശുപാർശ ചെയ്യുന്നു) +- **ഡിസ്ക് സ്പേസ്:** 1GB ഒഴിഞ്ഞ ഇടം +- **Node.js:** Version 16+ (Version 22+ ശുപാർശ ചെയ്യുന്നു) +- **npm:** ഏറ്റവും പുതിയ സ്ഥിരതയുള്ള പതിപ്പ് + +
+ +## പിന്തുണ + +ഈ ചാനലുകളിലൂടെ പരിപാലിക്കുന്നവരുമായും കമ്മ്യൂണിറ്റിയുമായും ബന്ധപ്പെടുക: + +- ബഗ്ഗ് റിപ്പോർട്ടോ, ഫീച്ചർ റിക്ക്വസ്റ്റോ ഉണ്ടോ? ദയവുചെയ്ത് [ഒരു ഇഷ്യൂ തുടങ്ങുക](https://github.com/HeyPuter/puter/issues/new/choose). +- ഡിസ്കോർഡ്: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- എക്സ് (ട്വിറ്റർ): [x.com/HeyPuter](https://x.com/HeyPuter) +- റെഡ്ഡിറ്റ്: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- മാസ്റ്റഡൺ: [mastodon.social/@puter](https://mastodon.social/@puter) +- സുരക്ഷാ പ്രശ്നങ്ങളുണ്ടോ? [security@puter.com](mailto:security@puter.com) +- ഇമെയിൽ മെയിന്റൈനർമാർ: [hi@puter.com](mailto:hi@puter.com) + +നിങ്ങൾക്ക് ഉണ്ടായേക്കാവുന്ന ഏത് ചോദ്യങ്ങളിലും നിങ്ങളെ സഹായിക്കുന്നതിൽ ഞങ്ങൾക്ക് എപ്പോഴും സന്തോഷമുണ്ട്. ചോദിക്കാൻ മടിക്കേണ്ട! + +
+ + +## ലൈസൻസ് + +ഈ ശേഖരം, അതിന്റെ എല്ലാ ഉള്ളടക്കങ്ങളും, ഉപപദ്ധതികളും, മൊഡ്യൂളുകളും, ഘടകങ്ങളും ഉൾപ്പെടെ, [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) എന്നതിന് കീഴിൽ ലൈസൻസുള്ളതാണ്. ഈ ശേഖരത്തിൽ ഉൾപ്പെടുത്തിയിരിക്കുന്ന മൂന്നാം കക്ഷി ലൈബ്രറികൾ അവരുടെ സ്വന്തം ലൈസൻസുകൾക്ക് വിധേയമായിരിക്കാം. + +
From 7139d2974948ea28128bce7b5e7c7e36139901fa Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 4 Sep 2024 22:03:26 -0400 Subject: [PATCH 0835/2119] Add link to Malayalam README in the English README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3c3b42fbd9..3f17375d46 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,7 @@ This repository, including all its contents, sub-projects, modules, and componen - [Italian / Italiano](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.it.md) - [Japanese / 日本語](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.jp.md) - [Korean / 한국어](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ko.md) +- [Malayalam / മലയാളം](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ml.md) - [Polish / Polski](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.pl.md) - [Portuguese / Português](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.pt.md) - [Romanian / Română](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ro.md) From a33d721e2143c76780fc1397c213ca4848eebffd Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 3 Sep 2024 18:59:56 -0400 Subject: [PATCH 0836/2119] fix phoenix WINSZ handling --- src/phoenix/src/ansi-shell/ANSIShell.js | 5 +++- src/phoenix/src/main_puter.js | 29 +++++++++++++--------- src/phoenix/src/pty/XDocumentPTT.js | 19 ++++++++++++++ src/phoenix/src/puter-shell/main.js | 3 +++ src/terminal/src/pty/XDocumentANSIShell.js | 8 ++++++ 5 files changed, 51 insertions(+), 13 deletions(-) diff --git a/src/phoenix/src/ansi-shell/ANSIShell.js b/src/phoenix/src/ansi-shell/ANSIShell.js index 93df6c31af..580ba2b7c5 100644 --- a/src/phoenix/src/ansi-shell/ANSIShell.js +++ b/src/phoenix/src/ansi-shell/ANSIShell.js @@ -91,7 +91,10 @@ export class ANSIShell extends EventTarget { }) Object.defineProperty(this.env, 'COLS', { enumerable: true, - get: () => this.variables.size?.cols ?? 0 + get: () => { + const v = this.variables.size?.cols ?? 0 + return v; + } }) this.export_('LANG', 'en_US.UTF-8'); diff --git a/src/phoenix/src/main_puter.js b/src/phoenix/src/main_puter.js index 85dc0af028..01e0339139 100644 --- a/src/phoenix/src/main_puter.js +++ b/src/phoenix/src/main_puter.js @@ -30,10 +30,11 @@ window.main_shell = async () => { .entries() ); - let resolveConfigured = null; - const configured_ = new Promise(rslv => { - resolveConfigured = rslv; - }); + // let resolveConfigured = null; + // const configured_ = new Promise(rslv => { + // resolveConfigured = rslv; + // }); + const puterSDK = globalThis.puter; const terminal = puter.ui.parentApp(); if (!terminal) { @@ -45,9 +46,10 @@ window.main_shell = async () => { if (message.$ === 'config') { const configValues = { ...message }; // Only copy the config that we actually need - config['puter.auth.username'] = configValues['puter.auth.username']; + // config['puter.auth.username'] = configValues['puter.auth.username']; config['puter.auth.token'] = configValues['puter.auth.token']; - resolveConfigured(); + // console.log('set!'); + // resolveConfigured(); } }); terminal.on('close', () => { @@ -59,14 +61,17 @@ window.main_shell = async () => { terminal.postMessage({ $: 'ready' }); - await configured_; + const ptt = new XDocumentPTT(terminal); - const puterSDK = globalThis.puter; - if ( config['puter.auth.token'] ) { - await puterSDK.setAuthToken(config['puter.auth.token']); - } + // await configured_; + const user = await puterSDK.auth.getUser(); + config['puter.auth.username'] = user.username; + // await new Promise(rslv => setTimeout(rslv, 0)); + + // if ( config['puter.auth.token'] ) { + // await puterSDK.setAuthToken(config['puter.auth.token']); + // } - const ptt = new XDocumentPTT(terminal); await launchPuterShell(new Context({ ptt, config, puterSDK, diff --git a/src/phoenix/src/pty/XDocumentPTT.js b/src/phoenix/src/pty/XDocumentPTT.js index e9afbb6fec..3ea15e564c 100644 --- a/src/phoenix/src/pty/XDocumentPTT.js +++ b/src/phoenix/src/pty/XDocumentPTT.js @@ -21,7 +21,26 @@ import { BetterReader } from "dev-pty"; const encoder = new TextEncoder(); export class XDocumentPTT { + static IOCTL = { + TIOCGWINSZ: { + id: 104, + }, + } constructor(terminalConnection) { + for ( const k in XDocumentPTT.IOCTL ) { + this[k] = async () => { + return await new Promise((resolve, reject) => { + terminalConnection.postMessage({ + $: 'ioctl.request', + requestCode: XDocumentPTT.IOCTL[k].id, + }); + this.once('ioctl.set', evt => { + resolve(evt); + }); + }); + }; + } + this.ioctl_listeners = {}; this.readableStream = new ReadableStream({ diff --git a/src/phoenix/src/puter-shell/main.js b/src/phoenix/src/puter-shell/main.js index 8c200a9224..7ba7f8823e 100644 --- a/src/phoenix/src/puter-shell/main.js +++ b/src/phoenix/src/puter-shell/main.js @@ -136,6 +136,9 @@ export const launchPuterShell = async (ctx) => { })); }); + // NEXT + ptt.TIOCGWINSZ(); + const fire = (text) => { // Define fire-like colors (ANSI 256-color codes) const fireColors = [202, 208, 166]; diff --git a/src/terminal/src/pty/XDocumentANSIShell.js b/src/terminal/src/pty/XDocumentANSIShell.js index 953659ec2b..e793014620 100644 --- a/src/terminal/src/pty/XDocumentANSIShell.js +++ b/src/terminal/src/pty/XDocumentANSIShell.js @@ -29,6 +29,14 @@ export class XDocumentANSIShell { shell.on('message', message => { // When the shell reports it's ready, send configuration + if (message.$ === 'ioctl.request') { + if (message.requestCode === 104) { + shell.postMessage({ + $: 'ioctl.set', + windowSize: this.internal_.windowSize, + }); + } + } if (message.$ === 'ready') { const params = Object.fromEntries( new URLSearchParams(window.location.search) From 6bdcae769d311b5deb82136d5e35d7ad986bca28 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 4 Sep 2024 23:50:42 -0400 Subject: [PATCH 0837/2119] fix: double-echo in phoenix --- src/phoenix/doc/devlog.md | 40 +++++++++++++++++++ src/phoenix/src/pty/XDocumentPTT.js | 27 +++++++++++++ src/phoenix/src/puter-shell/main.js | 1 + .../providers/PuterAppCommandProvider.js | 10 +++++ 4 files changed, 78 insertions(+) diff --git a/src/phoenix/doc/devlog.md b/src/phoenix/doc/devlog.md index 59aad3f962..3d02820819 100644 --- a/src/phoenix/doc/devlog.md +++ b/src/phoenix/doc/devlog.md @@ -1150,3 +1150,43 @@ This change can be made incrementally as follows: - update the command to use the new implementation - Once all commands are updated, the XDocumentPuterShell class will be dormant and can safely be removed. + +## 2024-09-04 + +### Terminal I/O + +Prior to recent changes it was not possible to run phoenix shell inside +another instance of phoenix shell. The following had to be resolved for +this to work: +- Phoenix was waiting for a configuration object from the parent app, + under the assumption that this parent app is a terminal. Phoenix now + does not require this configuration object. +- Initial terminal size had to be requested for by Phoenix after some + initialization to avoid a race condition. +- Apps called by an application under a terminal were not able to control + `echo` behavior. + +The new IO functionality follows the +[Selective Layer Implementation Pattern](https://puter.com/@ed/documentation/glossary.md##Selective-Layer-Implementation-Pattern) +with the following implemented: +- IOCTL: `TIOCGWINSZ`, sent via postMessage +- signal: `ioctl.set` event to simulate "SIGWINCH", + but this should be merged with existing code that + implements the concept of signals. +- ptt.termios: a high-level mimic of termios + (currently only echo control is implemented) + +XDocumentPTT now implements `TIOCGWINSZ` (named after the POSIX equivalent) +which requests the window size. This function calls `postMessage` on the +AppConnection with the following +[type-tagged object](../../../doc/api/type-tagged.md): +`{ $: 'ioctl.request', requestCode: 104 }`. + +The window size information is still provided +by the badly-named `ioctl.set` event, which should later be changed to +a similar convention, like `{ $: 'signal', code: 28 }`. + +The termios implementation is a high-level mimic and does not actually +use the underlying IOCTL implementation. Instead it sends a type-tagged +object that looks like `{ $: 'chtermios', termios: { echo: false } }`, +where `echo` can be `true` or `false`. diff --git a/src/phoenix/src/pty/XDocumentPTT.js b/src/phoenix/src/pty/XDocumentPTT.js index 3ea15e564c..b1054d3962 100644 --- a/src/phoenix/src/pty/XDocumentPTT.js +++ b/src/phoenix/src/pty/XDocumentPTT.js @@ -41,6 +41,18 @@ export class XDocumentPTT { }; } + this.termios = new Proxy({}, { + set (target, k, v) { + terminalConnection.postMessage({ + $: 'chtermios', + termios: { + [k]: v, + } + }); + return Reflect.set(target, k, v); + } + }); + this.ioctl_listeners = {}; this.readableStream = new ReadableStream({ @@ -91,4 +103,19 @@ export class XDocumentPTT { listener(evt); } } + + once (name, listener) { + const wrapper = evt => { + listener(evt); + this.off(name, wrapper); + }; + this.on(name, wrapper); + } + + off (name, listener) { + if ( ! this.ioctl_listeners.hasOwnProperty(name) ) return; + this.ioctl_listeners[name] = this.ioctl_listeners[name].filter( + l => l !== listener + ); + } } diff --git a/src/phoenix/src/puter-shell/main.js b/src/phoenix/src/puter-shell/main.js index 7ba7f8823e..0d4b94cd6a 100644 --- a/src/phoenix/src/puter-shell/main.js +++ b/src/phoenix/src/puter-shell/main.js @@ -138,6 +138,7 @@ export const launchPuterShell = async (ctx) => { // NEXT ptt.TIOCGWINSZ(); + ptt.termios.echo = false; const fire = (text) => { // Define fire-like colors (ANSI 256-color codes) diff --git a/src/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js b/src/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js index c25892449d..2014989335 100644 --- a/src/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js +++ b/src/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js @@ -88,6 +88,15 @@ export class PuterAppCommandProvider { if (message.$ === 'stdout') { ctx.externs.out.write(decoder.decode(message.data)); } + if (message.$ === 'chtermios') { + if ( message.termios.echo !== undefined ) { + if ( message.termios.echo ) { + ctx.externs.echo.on(); + } else { + ctx.externs.echo.off(); + } + } + } }); // Repeatedly copy data from stdin to the child, while it's running. @@ -108,6 +117,7 @@ export class PuterAppCommandProvider { setTimeout(next_data, 0); } + // TODO: propagate sigint to the app return Promise.race([ app_close_promise, sigint_promise ]); } }; From cc4ab1cb36a002929f26a39f252a262fc1f1aab4 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 4 Sep 2024 23:51:57 -0400 Subject: [PATCH 0838/2119] fix: html-webpack-plugin dev dep --- package-lock.json | 2 +- package.json | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/package-lock.json b/package-lock.json index a28ed1a782..4bc12305ef 100644 --- a/package-lock.json +++ b/package-lock.json @@ -28,6 +28,7 @@ "express": "^4.18.2", "globals": "^15.0.0", "html-entities": "^2.3.3", + "html-webpack-plugin": "^5.6.0", "license-check-and-add": "^4.0.5", "mocha": "^10.6.0", "nodemon": "^3.1.0", @@ -10880,7 +10881,6 @@ "resolved": "https://registry.npmjs.org/html-webpack-plugin/-/html-webpack-plugin-5.6.0.tgz", "integrity": "sha512-iwaY4wzbe48AfKLZ/Cc8k0L+FKG6oSNRaZ8x5A/T/IVDGyXcbHncM9TdDa93wn0FsSm82FhTKW7f3vS61thXAw==", "dev": true, - "license": "MIT", "dependencies": { "@types/html-minifier-terser": "^6.0.0", "html-minifier-terser": "^6.0.2", diff --git a/package.json b/package.json index 886b2def04..1f342be07f 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "express": "^4.18.2", "globals": "^15.0.0", "html-entities": "^2.3.3", + "html-webpack-plugin": "^5.6.0", "license-check-and-add": "^4.0.5", "mocha": "^10.6.0", "nodemon": "^3.1.0", From abb44b6d68ff29c40d726d6f20a83fe680abf879 Mon Sep 17 00:00:00 2001 From: Sergiy <143416400+SergiyZyuzko@users.noreply.github.com> Date: Sat, 7 Sep 2024 16:41:31 +0000 Subject: [PATCH 0839/2119] Ukrainian Translation added --- doc/i18n/README.ua.md | 129 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 doc/i18n/README.ua.md diff --git a/doc/i18n/README.ua.md b/doc/i18n/README.ua.md new file mode 100644 index 0000000000..1eac38e171 --- /dev/null +++ b/doc/i18n/README.ua.md @@ -0,0 +1,129 @@ +

Puter.com, The Personal Cloud Computer: Всі ваші файли, додатки та ігри в одному місці, доступні з будь-якого куточка світу в будь-який час.

+ +

Інтернет ОС! Безкоштовна, відкрита та self-hosted.

+ +

+ Розмір репозиторію на GitHub Остання версія на GitHub Ліцензія GitHub +

+

+ « Онлайн ДЕМО » +
+
+ Puter.com + · + SDK + · + Discord + · + YouTube + · + Reddit + · + X (Twitter) + · + Bug Bounty +

+ +

скріншот

+ +
+ +## Puter + +Puter — це просунута, інтернет-ОС, з відкритим кодом, створена для того, щоб бути багатофункціональною, надзвичайно швидкою та розширюваною. Puter може використовуватися як: + +- Приватний хмарний сервіс для збереження всіх ваших файлів, додатків і ігор у безпечному місці, доступному в будь-який час з будь-якого місця. +- Платформа для створення та публікації вебсайтів, вебдодатків і ігор. +- Альтернатива Dropbox, Google Drive, OneDrive і тд, з свіженьким інтерфейсом та потужними функціями. +- Віддалене робоче середовище для серверів і робочих станцій. +- Дружній, відкритий проєкт та спільнота для вивчення веброзробки, хмарних обчислень, розподілених систем і багато іншого! + +
+ +## Початок роботи + +### Локальна розробка + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +Це запустить Puter на http://puter.localhost:4100 (або на наступному доступному порті). + +
+ +### 🐳 Docker + + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ + +### 🐙 Docker Compose + + +#### Linux/macOS +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` +
+ +#### Windows + + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +### ☁️ Puter.com + +Puter доступний як hosted service на [**puter.com**](https://puter.com). + +
+ +## Системні вимоги + +- **Операційні Системи:** Linux, macOS, Windows +- **RAM:** 2GB мінімум (4GB рекомендовано) +- **Місце на диску:** 1GB вільного місця +- **Node.js:** Version 16+ (Version 22+ рекомендовано) +- **npm:** остання "stable" версія + +
+ +## Підтримка + +Зв'язатися з розробниками та спільнотою можна через такі канали: + +- Повідомити про помилку, або запит щодо нової фічі? Будь ласка, [створіть issue](https://github.com/HeyPuter/puter/issues/new/choose). +- Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) +- Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) +- Питання щодо Security? [security@puter.com](mailto:security@puter.com) +- Написати розробникам [hi@puter.com](mailto:hi@puter.com) + +Ми завжди готові допомогти Вам з будь-якими питаннями, що можуть виникнути. Не соромтеся ставити нам питання! +
+ + +## License + +Цей репорзиторій, включаючи увесь його контент, дочірні проєкти, модулі, і компоненти, ліцензовано за [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt), якщо явно не вказано інше. Сторонні бібліотеки, включені в цей репозиторій, можуть підпадати під дію інших ліцензій. + +
From 11ddbf70c8add1226022897a05df6f1aa1b65098 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sat, 7 Sep 2024 09:49:40 -0700 Subject: [PATCH 0840/2119] Add link to Ukrainian README from the English README --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3f17375d46..fc647cbba2 100644 --- a/README.md +++ b/README.md @@ -153,5 +153,6 @@ This repository, including all its contents, sub-projects, modules, and componen - [Tamil / தமிழ்](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ta.md) - [Thai / ไทย](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.th.md) - [Turkish / Türkçe](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.tr.md) +- [Ukrainian / Українська](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.uk.md) - [Urdu / اردو](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ur.md) - [Vietnamese / Tiếng Việt](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.vi.md) From a4a349a64adf1e3b1d4c444fc44c23786cdc3846 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sat, 7 Sep 2024 09:50:04 -0700 Subject: [PATCH 0841/2119] Update README.md --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fc647cbba2..e37f3e9fb7 100644 --- a/README.md +++ b/README.md @@ -153,6 +153,6 @@ This repository, including all its contents, sub-projects, modules, and componen - [Tamil / தமிழ்](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ta.md) - [Thai / ไทย](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.th.md) - [Turkish / Türkçe](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.tr.md) -- [Ukrainian / Українська](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.uk.md) +- [Ukrainian / Українська](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ua.md) - [Urdu / اردو](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ur.md) - [Vietnamese / Tiếng Việt](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.vi.md) From 89d11e3b0f8aaa263bdf3755a087aabd0c7dc031 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Gy=C3=A1rf=C3=A1s=20Bal=C3=A1zs?= Date: Tue, 10 Sep 2024 14:02:10 +0200 Subject: [PATCH 0842/2119] translation-hun-readme --- doc/i18n/README.hu.md | 132 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 132 insertions(+) create mode 100644 doc/i18n/README.hu.md diff --git a/doc/i18n/README.hu.md b/doc/i18n/README.hu.md new file mode 100644 index 0000000000..bf6ea5b273 --- /dev/null +++ b/doc/i18n/README.hu.md @@ -0,0 +1,132 @@ +

Puter.com, A személyi felhő számítógép:  Minden fájl, alkalmazás és játék egy helyen elérhető bárhonnan, bármikor.

+ +

Az internetes oprendszer! Ingyenes, nyílt-forráskódú, saját szerveren futtatható.

+ +

+ GitHub repo size GitHub Release GitHub License +

+

+ « ÉLŐ DEMO » +
+
+ Puter.com + · + SDK + · + Discord + · + YouTube + · + Reddit + · + X (Twitter) + · + Bug Bounty +

+ +

screenshot

+ +
+ +## Puter +A Puter egy fejlett, nyílt forráskódú internetes operációs rendszer, amelyet úgy terveztek, hogy funkciókban gazdag, kivételesen gyors és nagymértékben bővíthető legyen. A Puter a következőképpen használható: + +- Egy adatvédelmet előtérbe helyező személyes felhő, amely minden fájlt, alkalmazást és játékot egy biztonságos helyen tart. Bárhonnan és bármikor elérhető. +- Egy platform weboldalak, web-appok, és játékok készítéséhez/közzétételéhez. +- A Dropbox, Google Drive, OneDrive (stb.) alternatívája megújult felülettel és hatékony funkciókkal. +- Egy távoli desktop-környezet szervereknek és workstation-öknek. +- Egy barátságos, nyílt forráskódú projekt és közösség, amely a webfejlesztéssel, a felhőalapú számítástechnikával, elosztott rendszerekkel és sok más érdekes témával foglalkozik! + +
+ +## Első lépések + + +### 💻 Helyi (lokális) fejlesztés + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +Ezzel a http://puter.localhost:4100 -on futtatjuk Putert. (vagy a legközelebbi elérhető porton). + +
+ +### 🐳 Docker + + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ + +### 🐙 Docker Compose + + +#### Linux/macOS +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` +
+ +#### Windows + + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +### ☁️ Puter.com + +A Puter elérhető hostolt szolgáltatásként a [**puter.com**](https://puter.com) címen. + +
+ +## Rendszerkövetelmények + +- **Operációs rendszerek:** Linux, macOS, Windows +- **RAM:** 2GB minimum (4GB ajánlott) +- **Tárhely:** 1GB szabad tárhely +- **Node.js:** 16+ (22+ verzió ajánlott) +- **npm:** legújabb stabil verzió + +
+ +## Támogatás + +Lépj kapcsolatba a fejlesztőkkel és a közösséggel az alábbi platformokon: + +- Észrevételeid/javaslataid vannak? Az [alábbi linken](https://github.com/HeyPuter/puter/issues/new/choose) megoszthatod velünk. +- Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) +- Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) +- Biztonsági hibák? [security@puter.com](mailto:security@puter.com) +- A fejlesztőket a [hi@puter.com](mailto:hi@puter.com) email címen érheted el. + + +Mindig örömmel segítünk bármilyen felmerülő kérdésben. Bátran kérdezz tőlünk! + +
+ + +## License + + +Ez a repo, beleértve annak minden tartalmát, alprojektjeit, moduljait és komponenseit, az [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) licenc alatt áll, hacsak másképp nem rendelkeznek róla. A repoban szereplő harmadik fél által fejlesztett könyvtárak saját licencfeltételek alá eshetnek. + +
From d38fb9f0e107556541e1cd82ad6093c03827c199 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Tue, 10 Sep 2024 08:59:41 -0700 Subject: [PATCH 0843/2119] Update README.md --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index e37f3e9fb7..7cdd1ee75a 100644 --- a/README.md +++ b/README.md @@ -140,6 +140,7 @@ This repository, including all its contents, sub-projects, modules, and componen - [French / Français](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.fr.md) - [Hebrew/ עברית](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.he.md) - [Hindi / हिंदी](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.hi.md) +- [Hungarian / Magyar](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.hu.md) - [Indonesian / Bahasa Indonesia](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.id.md) - [Italian / Italiano](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.it.md) - [Japanese / 日本語](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.jp.md) From 33de98107f6e3284acb180b1a44bb02ae082642f Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 10 Sep 2024 14:04:32 -0400 Subject: [PATCH 0844/2119] fix: email change on account with unverified email Changing the email address on an account that did not already have a confirmed email would result in the email_confirmed column never being set. This commit fixes that. Additionally, an SQL statement using the unconfirmed email to identify a row was changed so it now uses the user ID instead, which is safer. Resolves: 759 --- src/backend/src/helpers.js | 2 +- src/backend/src/routers/change_email.js | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/backend/src/helpers.js b/src/backend/src/helpers.js index cdcf4c963c..d874bc366f 100644 --- a/src/backend/src/helpers.js +++ b/src/backend/src/helpers.js @@ -1379,7 +1379,7 @@ function is_valid_url ( url ) { function hyphenize_confirm_code(email_confirm_code){ email_confirm_code = email_confirm_code.toString(); email_confirm_code = - email_confirm_code[0] + + [0] + email_confirm_code[1] + email_confirm_code[2] + '-' + diff --git a/src/backend/src/routers/change_email.js b/src/backend/src/routers/change_email.js index 9ff54301e9..716a85c9a7 100644 --- a/src/backend/src/routers/change_email.js +++ b/src/backend/src/routers/change_email.js @@ -64,8 +64,8 @@ const CHANGE_EMAIL_CONFIRM = eggspress('/change_email/confirm', { // If other users have the same unconfirmed email, revoke it await db.write( - 'UPDATE `user` SET `unconfirmed_change_email` = NULL, `change_email_confirm_token` = NULL WHERE `unconfirmed_change_email` = ?', - [rows[0].unconfirmed_change_email] + 'UPDATE `user` SET `unconfirmed_change_email` = NULL, `email_confirmed`=1, `change_email_confirm_token` = NULL WHERE `id` = ?', + [user_id] ); const new_email = rows[0].unconfirmed_change_email; From 0743189ddbfb10c73347ddd2e9ce835dafa19bb7 Mon Sep 17 00:00:00 2001 From: the-heidi Date: Wed, 11 Sep 2024 20:30:38 -0700 Subject: [PATCH 0845/2119] Update README.ko.md to fix phrasing issues --- doc/i18n/README.ko.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/doc/i18n/README.ko.md b/doc/i18n/README.ko.md index cc0ed0fa36..bf586ff2ea 100644 --- a/doc/i18n/README.ko.md +++ b/doc/i18n/README.ko.md @@ -1,6 +1,6 @@

Puter.com, The Personal Cloud Computer: All your files, apps, and games in one place accessible from anywhere at any time.

-

인터넷 OS! 무료이고 오픈소스이며 자체 호스팅이 가능합니다.

+

Puter: 인터넷 OS! 무료이고 오픈소스이며 자체 호스팅이 가능합니다.

GitHub repo size GitHub Release GitHub License @@ -30,11 +30,11 @@ ## Puter -Puter는 기능이 풍부하고, 매우 빠르며, 높은 확장성을 갖춘 고급 오픈소스 인터넷 운영 체제입니다. Puter는 다음과 같이 사용될 수 있습니다: +Puter는 오픈소스 인터넷 운영 체제로, 매우 빠르고 확장성이 뛰어나며 새로운 인터페이스와 다양한 기능을 갖추고 있습니다. Puter는 다음과 같이 사용될 수 있습니다: - 모든 파일, 앱, 게임을 한 곳에 안전하게 보관하고 언제 어디서나 접근할 수 있는 프라이버시 중심의 개인 클라우드로 사용할 수 있습니다. - 웹사이트, 웹 앱, 게임을 구축하고 배포하는 플랫폼으로 활용할 수 있습니다. -- 새로운 인터페이스와 강력한 기능을 갖춘 Dropbox, Google Drive, OneDrive 등의 대안으로 사용할 수 있습니다. +- Dropbox, Google Drive, OneDrive 등의 대안으로 사용할 수 있으며 보다 발전된 기능과 인터페이스를 제공합니다. - 서버와 워크스테이션을 위한 원격 데스크톱 환경으로 활용할 수 있습니다. - 웹 개발, 클라우드 컴퓨팅, 분산 시스템 등에 대해 배울 수 있는 친근한 오픈소스 프로젝트이자 커뮤니티입니다! From c0b301019246c508fb7215187175ee3c76ca7377 Mon Sep 17 00:00:00 2001 From: Bibek Panda <75358427+bibekp-dev@users.noreply.github.com> Date: Thu, 12 Sep 2024 12:58:03 +0530 Subject: [PATCH 0846/2119] Create README.de.md --- doc/i18n/README.de.md | 1 + 1 file changed, 1 insertion(+) create mode 100644 doc/i18n/README.de.md diff --git a/doc/i18n/README.de.md b/doc/i18n/README.de.md new file mode 100644 index 0000000000..8b13789179 --- /dev/null +++ b/doc/i18n/README.de.md @@ -0,0 +1 @@ + From c204cd366af5a7c1ed332355aebdc7d5235e5725 Mon Sep 17 00:00:00 2001 From: Bibek Panda <75358427+bibekp-dev@users.noreply.github.com> Date: Thu, 12 Sep 2024 13:03:07 +0530 Subject: [PATCH 0847/2119] Created and updated README.de.md for English To German Translation German translation changes are committed in README.de.md file --- doc/i18n/README.de.md | 130 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 130 insertions(+) diff --git a/doc/i18n/README.de.md b/doc/i18n/README.de.md index 8b13789179..35350090dc 100644 --- a/doc/i18n/README.de.md +++ b/doc/i18n/README.de.md @@ -1 +1,131 @@ +

Puter.com, Der persönliche Cloud-Computer: Alle Ihre Dateien, Apps und Spiele an einem Ort, jederzeit und überall zugänglich.

+

Das Internet-Betriebssystem! Kostenlos, Open-Source und selbst hostbar.

+ +

+ GitHub Repo-Größe GitHub Release GitHub Lizenz +

+

+ « LIVE DEMO » +
+
+ Puter.com + · + SDK + · + Discord + · + YouTube + · + Reddit + · + X (Twitter) + · + Bug Bounty +

+ +

Screenshot

+ +
+ +## Puter + +Puter ist ein fortschrittliches, Open-Source-Internet-Betriebssystem, das funktionsreich, außergewöhnlich schnell und hochgradig erweiterbar konzipiert wurde. Puter kann verwendet werden als: + +- Eine datenschutzfreundliche persönliche Cloud, um alle Ihre Dateien, Apps und Spiele an einem sicheren Ort aufzubewahren, jederzeit und überall zugänglich. +- Eine Plattform zum Erstellen und Veröffentlichen von Websites, Webanwendungen und Spielen. +- Eine Alternative zu Dropbox, Google Drive, OneDrive usw. mit einer frischen Benutzeroberfläche und leistungsstarken Funktionen. +- Eine Remote-Desktop-Umgebung für Server und Workstations. +- Ein freundliches, Open-Source-Projekt und eine Community, um mehr über Webentwicklung, Cloud Computing, verteilte Systeme und vieles mehr zu lernen! + +
+ +## Erste Schritte + + +### 💻 Lokale Entwicklung + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +Dies startet Puter unter http://puter.localhost:4100 (oder dem nächsten verfügbaren Port). + +
+ +### 🐳 Docker + + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ + +### 🐙 Docker Compose + + +#### Linux/macOS +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` +
+ +#### Windows + + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +### ☁️ Puter.com + +Puter ist als gehosteter Dienst unter [**puter.com**](https://puter.com) verfügbar. + +
+ +## Systemanforderungen + +- **Betriebssysteme:** Linux, macOS, Windows +- **RAM:** Mindestens 2GB (4GB empfohlen) +- **Festplattenspeicher:** 1GB freier Speicherplatz +- **Node.js:** Version 16+ (Version 22+ empfohlen) +- **npm:** Neueste stabile Version + +
+ +## Unterstützung + +Verbinden Sie sich mit den Maintainern und der Community über diese Kanäle: + +- Fehlerbericht oder Funktionsanfrage? Bitte [öffnen Sie ein Issue](https://github.com/HeyPuter/puter/issues/new/choose). +- Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) +- Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) +- Sicherheitsprobleme? [security@puter.com](mailto:security@puter.com) +- E-Mail an die Maintainer: [hi@puter.com](mailto:hi@puter.com) + +Wir helfen Ihnen gerne bei allen Fragen, die Sie haben könnten. Zögern Sie nicht zu fragen! + +
+ + +## Lizenz + +Dieses Repository, einschließlich aller Inhalte, Unterprojekte, Module und Komponenten, ist unter [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) lizenziert, sofern nicht ausdrücklich anders angegeben. In diesem Repository enthaltene Bibliotheken von Drittanbietern können ihren eigenen Lizenzen unterliegen. + +
From cc794fb70ba5b71aa03664a8e7bb3ef32361e649 Mon Sep 17 00:00:00 2001 From: 4nshuman Date: Sat, 14 Sep 2024 20:14:52 +0530 Subject: [PATCH 0848/2119] added translation for german alt on image tag --- doc/i18n/README.de.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/doc/i18n/README.de.md b/doc/i18n/README.de.md index 35350090dc..9c9f345991 100644 --- a/doc/i18n/README.de.md +++ b/doc/i18n/README.de.md @@ -3,7 +3,7 @@

Das Internet-Betriebssystem! Kostenlos, Open-Source und selbst hostbar.

- GitHub Repo-Größe GitHub Release GitHub Lizenz + GitHub Repo-Größe GitHub Veröffentlichung GitHub Lizenz

« LIVE DEMO » @@ -24,7 +24,7 @@ Bug Bounty

-

Screenshot

+

Bildschirmfoto


From 8f6b3c07a931b34817ff22121b5e82ef2ddec5ca Mon Sep 17 00:00:00 2001 From: 4nshuman Date: Sat, 14 Sep 2024 20:15:09 +0530 Subject: [PATCH 0849/2119] added swedish translation file --- doc/i18n/README.sv.md | 129 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 129 insertions(+) create mode 100644 doc/i18n/README.sv.md diff --git a/doc/i18n/README.sv.md b/doc/i18n/README.sv.md new file mode 100644 index 0000000000..39ece1c193 --- /dev/null +++ b/doc/i18n/README.sv.md @@ -0,0 +1,129 @@ +

Puter.com, Den personliga molndatorn: Alla dina filer, appar och spel på ett ställe tillgängliga var som helst när som helst.

+ +

Internet OS! Gratis, öppen källkod och självhostad.

+ +

+ GitHub repo storlek GitHub Utgåva GitHub Licens +

+

+ « LIVE DEMO » +
+
+ Puter.com + · + SDK + · + Discord + · + YouTube + · + Reddit + · + X (Twitter) + · + Bug Bounty +

+ +

skärmdump

+ +
+ +## Puter + +Puter är ett avancerat, öppen källkod internetoperativsystem designat för att vara funktionsrikt, exceptionellt snabbt och mycket utbyggbart. Puter kan användas som: + +- Ett integritetsfokuserat personligt moln för att hålla alla dina filer, appar och spel på ett säkert ställe, tillgängligt var som helst när som helst. +- En plattform för att bygga och publicera webbplatser, webbappar och spel. +- Ett alternativ till Dropbox, Google Drive, OneDrive, etc. med ett fräscht gränssnitt och kraftfulla funktioner. +- En fjärrskrivbordsmiljö för servrar och arbetsstationer. +- Ett vänligt, öppen källkod-projekt och gemenskap för att lära sig om webbutveckling, molndatorer, distribuerade system och mycket mer! + +
+ +## Komma igång + +### 💻 Lokal Utveckling + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +Detta kommer att starta Puter på http://puter.localhost:4100 (eller nästa lediga port). + +
+ +### 🐳 Docker + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ +### 🐙 Docker Compose + +#### Linux/macOS + +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` + +
+ +#### Windows + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` + +
+ +### ☁️ Puter.com + +Puter är tillgängligt som en värdtjänst på [**puter.com**](https://puter.com). + +
+ +## Systemkrav + +- **Operating Systems:** Linux, macOS, Windows +- **RAM:** 2GB minimum (4GB recommended) +- **Disk Space:** 1GB free space +- **Node.js:** Version 16+ (Version 22+ recommended) +- **npm:** Latest stable version + +
+ +## Support + +Anslut med underhållarna och gemenskapen genom dessa kanaler: + +- Buggrapport eller funktionsförfrågan? Vänligen [öppna ett ärende](https://github.com/HeyPuter/puter/issues/new/choose). +- Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) +- Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) +- Säkerhetsproblem? [security@puter.com](mailto:security@puter.com) +- E-posta underhållarna på [hi@puter.com](mailto:hi@puter.com) + +Vi hjälper dig gärna med eventuella frågor du kan ha. Tveka inte att fråga! + +
+ +## Licens + +Detta arkiv, inklusive allt dess innehåll, delprojekt, moduler och komponenter, är licensierat under [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) om inte annat uttryckligen anges. Tredjepartsbibliotek som ingår i detta arkiv kan vara föremål för sina egna licenser. + +
+ From a45def27a5ab3c2d08506fbd5fe5564077750c1d Mon Sep 17 00:00:00 2001 From: 4nshuman Date: Sat, 14 Sep 2024 20:15:59 +0530 Subject: [PATCH 0850/2119] fixed translation list alphabetical order --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 7cdd1ee75a..339ecd58c7 100644 --- a/README.md +++ b/README.md @@ -129,13 +129,13 @@ This repository, including all its contents, sub-projects, modules, and componen ## Translations -- [Farsi / فارسی](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.fa.md) - [Arabic / العربية](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ar.md) - [Armenian / Հայերեն](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.hy.md) - [Bengali / বাংলা](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.bn.md) - [Chinese / 中文](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.zh.md) - [Danish / Dansk](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.da.md) - [English](https://github.com/HeyPuter/puter/blob/main/README.md) +- [Farsi / فارسی](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.fa.md) - [Finnish / Suomi](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.fi.md) - [French / Français](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.fr.md) - [Hebrew/ עברית](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.he.md) From 50c6e74f993fcb597d18dde47c19aaa96dade15c Mon Sep 17 00:00:00 2001 From: 4nshuman Date: Sat, 14 Sep 2024 20:16:35 +0530 Subject: [PATCH 0851/2119] added swedish translation to the list --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 339ecd58c7..fa45f66165 100644 --- a/README.md +++ b/README.md @@ -151,6 +151,7 @@ This repository, including all its contents, sub-projects, modules, and componen - [Romanian / Română](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ro.md) - [Russian / Русский](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ru.md) - [Spanish / Español](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.es.md) +- [Swedish / Svenska](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.sv.md) - [Tamil / தமிழ்](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.ta.md) - [Thai / ไทย](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.th.md) - [Turkish / Türkçe](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.tr.md) From cadd7453c4ff0b777b6c5b88cadeab28f820d3a5 Mon Sep 17 00:00:00 2001 From: 4nshuman Date: Sat, 14 Sep 2024 20:17:02 +0530 Subject: [PATCH 0852/2119] added german translation link to the list --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index fa45f66165..441ebfa5e0 100644 --- a/README.md +++ b/README.md @@ -138,6 +138,7 @@ This repository, including all its contents, sub-projects, modules, and componen - [Farsi / فارسی](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.fa.md) - [Finnish / Suomi](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.fi.md) - [French / Français](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.fr.md) +- [German/ Deutsch](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.de.md) - [Hebrew/ עברית](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.he.md) - [Hindi / हिंदी](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.hi.md) - [Hungarian / Magyar](https://github.com/HeyPuter/puter/blob/main/doc/i18n/README.hu.md) From 2c0b8428c5a571c2bbb4e0a5121b0e43c92cbf0f Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 4 Sep 2024 23:57:45 -0400 Subject: [PATCH 0853/2119] dev: add emulator image build --- src/emulator/basic.html | 412 ++++++++++++++++++ src/emulator/image/Dockerfile | 57 +++ src/emulator/image/basic-boot | 14 + src/emulator/image/build.sh | 50 +++ src/emulator/image/clean.sh | 3 + src/emulator/image/debug-service | 19 + src/emulator/image/initd/network-service | 17 + src/emulator/image/qemu.sh | 7 + src/emulator/image/rootfs/etc/hostname | 1 + .../image/rootfs/etc/network/interfaces | 4 + src/emulator/image/rootfs/etc/resolv.conf | 1 + src/emulator/image/twisp-service | 25 ++ 12 files changed, 610 insertions(+) create mode 100644 src/emulator/basic.html create mode 100644 src/emulator/image/Dockerfile create mode 100644 src/emulator/image/basic-boot create mode 100755 src/emulator/image/build.sh create mode 100755 src/emulator/image/clean.sh create mode 100644 src/emulator/image/debug-service create mode 100644 src/emulator/image/initd/network-service create mode 100755 src/emulator/image/qemu.sh create mode 100644 src/emulator/image/rootfs/etc/hostname create mode 100644 src/emulator/image/rootfs/etc/network/interfaces create mode 100644 src/emulator/image/rootfs/etc/resolv.conf create mode 100644 src/emulator/image/twisp-service diff --git a/src/emulator/basic.html b/src/emulator/basic.html new file mode 100644 index 0000000000..07bbfb3f26 --- /dev/null +++ b/src/emulator/basic.html @@ -0,0 +1,412 @@ + +Basic Emulator + + + + + + +
+
+ +
diff --git a/src/emulator/image/Dockerfile b/src/emulator/image/Dockerfile new file mode 100644 index 0000000000..c45e3b8efa --- /dev/null +++ b/src/emulator/image/Dockerfile @@ -0,0 +1,57 @@ +FROM i386/alpine:edge + +RUN apk add --update \ + alpine-base bash ncurses shadow curl \ + linux-lts linux-firmware-none linux-headers \ + gcc make gcompat musl-dev libx11-dev xinit \ + bind-tools \ + util-linux \ + htop vim nano \ + && \ + setup-xorg-base xhost xterm xcalc xdotool xkill || true && \ + setup-devd udev || true && \ + touch /root/.Xdefaults && \ + rm /etc/motd /etc/issue && \ + passwd -d root && \ + chsh -s /bin/bash + +RUN apk add neofetch + +COPY basic-boot /etc/init.d/ +RUN chmod +x /etc/init.d/basic-boot + +COPY assets/twisp /bin/twisp +RUN chmod u+x /bin/twisp +COPY twisp-service /etc/init.d/ +RUN chmod +x /etc/init.d/twisp-service +RUN rc-update add twisp-service default + +COPY debug-service /etc/init.d/ +RUN chmod +x /etc/init.d/debug-service +RUN rc-update add debug-service default + +COPY initd/network-service /etc/init.d/ +RUN chmod +x /etc/init.d/network-service +RUN rc-update add network-service default + +# setup init system +# COPY rc.conf /etc/rc.conf +RUN rc-update add dmesg sysinit +RUN rc-update add basic-boot sysinit + +RUN rc-update add root boot +RUN rc-update add localmount boot +RUN rc-update add modules boot +RUN rc-update add sysctl boot +RUN rc-update add bootmisc boot +RUN rc-update add syslog boot + +RUN rc-update add mount-ro shutdown +RUN rc-update add killprocs shutdown +RUN rc-update add savecache shutdown + +COPY rootfs/ / + +RUN setup-hostname puter-alpine + +RUN bash \ No newline at end of file diff --git a/src/emulator/image/basic-boot b/src/emulator/image/basic-boot new file mode 100644 index 0000000000..11e9d3824e --- /dev/null +++ b/src/emulator/image/basic-boot @@ -0,0 +1,14 @@ +#!/sbin/openrc-run + +description="Run Essential Boot Scripts" + +start() { + ebegin "Running Essential Boot Scripts" + mount / -o remount,rw + eend $? +} + +stop() { + ebegin "Stopping Essential Boot Scripts" + eend $? +} diff --git a/src/emulator/image/build.sh b/src/emulator/image/build.sh new file mode 100755 index 0000000000..f8d51fa5e6 --- /dev/null +++ b/src/emulator/image/build.sh @@ -0,0 +1,50 @@ +#!/usr/bin/env bash +set -veu + +if [ -w /var/run/docker.sock ] +then + echo true +else + echo "You aren't in the docker group, please run usermod -a -G docker $USER && newgrp docker" + exit 2 +fi + + +IMAGES="$(dirname "$0")"/build/x86images +OUT_ROOTFS_TAR="$IMAGES"/rootfs.tar +OUT_ROOTFS_BIN="$IMAGES"/rootfs.bin +OUT_ROOTFS_MNT="$IMAGES"/rootfs.mntpoint +CONTAINER_NAME=alpine-full +IMAGE_NAME=i386/alpine-full + +rm -rf $OUT_ROOTFS_BIN || : + +mkdir -p "$IMAGES" +docker build . --platform linux/386 --rm --tag "$IMAGE_NAME" +docker rm "$CONTAINER_NAME" || true +docker create --platform linux/386 -t -i --name "$CONTAINER_NAME" "$IMAGE_NAME" bash + +docker export "$CONTAINER_NAME" > "$OUT_ROOTFS_TAR" +dd if=/dev/zero "of=$OUT_ROOTFS_BIN" bs=512M count=2 + +loop=$(sudo losetup -f) +sudo losetup -P "$loop" "$OUT_ROOTFS_BIN" +sudo mkfs.ext4 "$loop" +mkdir -p "$OUT_ROOTFS_MNT" +sudo mount "$loop" "$OUT_ROOTFS_MNT" + +sudo tar -xf "$OUT_ROOTFS_TAR" -C "$OUT_ROOTFS_MNT" +sudo cp -r "$OUT_ROOTFS_MNT/boot" "$IMAGES/boot" + +sudo umount "$loop" +sudo losetup -d "$loop" +rm "$OUT_ROOTFS_TAR" +rm -rf "$OUT_ROOTFS_MNT" + +echo "done! created" +sudo chown -R $USER:$USER $IMAGES/boot +cd "$IMAGES" +mkdir -p rootfs +split -b50M rootfs.bin rootfs/ +cd ../ +find x86images/rootfs/* | jq -Rnc "[inputs]" diff --git a/src/emulator/image/clean.sh b/src/emulator/image/clean.sh new file mode 100755 index 0000000000..81dec73eb1 --- /dev/null +++ b/src/emulator/image/clean.sh @@ -0,0 +1,3 @@ +sudo umount build/x86images/rootfs.mntpoint +sudo rm -rf ./build + diff --git a/src/emulator/image/debug-service b/src/emulator/image/debug-service new file mode 100644 index 0000000000..d3f48d5a85 --- /dev/null +++ b/src/emulator/image/debug-service @@ -0,0 +1,19 @@ +#!/sbin/openrc-run + +description="Run debug init" + +depend() { + after twisp-service +} + +start() { + ebegin "Running Debug Init" + echo " 🛠 bash will be on tty2" + setsid bash < /dev/tty2 > /dev/tty2 2>&1 & + eend $? +} + +stop() { + ebegin "Stopping Debug Init" + eend $? +} diff --git a/src/emulator/image/initd/network-service b/src/emulator/image/initd/network-service new file mode 100644 index 0000000000..b68ba438ce --- /dev/null +++ b/src/emulator/image/initd/network-service @@ -0,0 +1,17 @@ +#!/sbin/openrc-run + +description="Run network setup" + +start() { + ebegin "Running network setup" + modprobe ne2k-pci + ifupdown ifup eth0 + ip link set lo up + echo "nameserver 192.168.86.1" > /etc/resolv.conf + eend $? +} + +stop() { + ebegin "Stopping network setup" + eend $? +} diff --git a/src/emulator/image/qemu.sh b/src/emulator/image/qemu.sh new file mode 100755 index 0000000000..f0388f53e1 --- /dev/null +++ b/src/emulator/image/qemu.sh @@ -0,0 +1,7 @@ +qemu-system-i386 \ + -kernel ./build/x86images/boot/vmlinuz-lts \ + -initrd ./build/x86images/boot/initramfs-lts \ + -append "rw root=/dev/sda console=ttyS0 init=/sbin/init rootfstype=ext4" \ + -hda ./build/x86images/rootfs.bin \ + -m 1024M \ + -nographic diff --git a/src/emulator/image/rootfs/etc/hostname b/src/emulator/image/rootfs/etc/hostname new file mode 100644 index 0000000000..9e566746c7 --- /dev/null +++ b/src/emulator/image/rootfs/etc/hostname @@ -0,0 +1 @@ +puter-alpine diff --git a/src/emulator/image/rootfs/etc/network/interfaces b/src/emulator/image/rootfs/etc/network/interfaces new file mode 100644 index 0000000000..f6278a2378 --- /dev/null +++ b/src/emulator/image/rootfs/etc/network/interfaces @@ -0,0 +1,4 @@ +iface eth0 inet static + address 192.168.86.100 + netmask 255.255.255.0 + gateway 192.168.86.1 diff --git a/src/emulator/image/rootfs/etc/resolv.conf b/src/emulator/image/rootfs/etc/resolv.conf new file mode 100644 index 0000000000..c43526bf56 --- /dev/null +++ b/src/emulator/image/rootfs/etc/resolv.conf @@ -0,0 +1 @@ +nameserver 192.168.86.1 diff --git a/src/emulator/image/twisp-service b/src/emulator/image/twisp-service new file mode 100644 index 0000000000..8ca743e43f --- /dev/null +++ b/src/emulator/image/twisp-service @@ -0,0 +1,25 @@ +#!/sbin/openrc-run + +description="twisp daemon" +command="/bin/twisp" +command_args="--pty /dev/hvc0" +pidfile="/var/run/twisp.pid" +command_background="yes" +start_stop_daemon_args="--background --make-pidfile" + +depend() { + need localmount + after bootmisc +} + +start() { + ebegin "Starting ${description}" + start-stop-daemon --start --pidfile "${pidfile}" --background --exec ${command} -- ${command_args} + eend $? +} + +stop() { + ebegin "Stopping ${description}" + start-stop-daemon --stop --pidfile "${pidfile}" + eend $? +} From 41e7526372f3b5e4f263613ac6985aefac71cb86 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 5 Sep 2024 01:29:26 -0400 Subject: [PATCH 0854/2119] dev: add twisp submodule --- .gitmodules | 3 +++ submodules/twisp | 1 + 2 files changed, 4 insertions(+) create mode 160000 submodules/twisp diff --git a/.gitmodules b/.gitmodules index 339cb8a471..c2dfcc1d99 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,3 +1,6 @@ [submodule "submodules/v86"] path = submodules/v86 url = git@github.com:copy/v86.git +[submodule "submodules/twisp"] + path = submodules/twisp + url = git@github.com:MercuryWorkshop/twisp.git diff --git a/submodules/twisp b/submodules/twisp new file mode 160000 index 0000000000..ae6e6527d7 --- /dev/null +++ b/submodules/twisp @@ -0,0 +1 @@ +Subproject commit ae6e6527d79c5206c305f27658ff16a6d2840748 From 28adc4e5d556155613b94d1cc6df48061c3a1ad1 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 5 Sep 2024 01:30:57 -0400 Subject: [PATCH 0855/2119] dev: add emulator page --- .../modules/selfhosted/SelfHostedModule.js | 8 + src/emulator/assets/template.html | 19 + src/emulator/image/Dockerfile | 2 - src/emulator/image/assets/.gitignore | 2 + src/emulator/image/build.sh | 7 +- src/emulator/image/build/.gitignore | 2 + src/emulator/src/main.js | 388 +++++++++++++++++- tools/build_v86.sh | 43 ++ 8 files changed, 462 insertions(+), 9 deletions(-) create mode 100644 src/emulator/image/assets/.gitignore create mode 100644 src/emulator/image/build/.gitignore create mode 100755 tools/build_v86.sh diff --git a/src/backend/src/modules/selfhosted/SelfHostedModule.js b/src/backend/src/modules/selfhosted/SelfHostedModule.js index 6ec4b6e2ba..a10989428e 100644 --- a/src/backend/src/modules/selfhosted/SelfHostedModule.js +++ b/src/backend/src/modules/selfhosted/SelfHostedModule.js @@ -117,10 +117,18 @@ class SelfHostedModule extends AdvancedBase { prefix: '/builtin/dev-center', path: path_.resolve(__dirname, RELATIVE_PATH, 'src/dev-center'), }, + { + prefix: '/builtin/emulator/image', + path: path_.resolve(__dirname, RELATIVE_PATH, 'src/emulator/image'), + }, { prefix: '/builtin/emulator', path: path_.resolve(__dirname, RELATIVE_PATH, 'src/emulator/dist'), }, + { + prefix: '/vendor/v86/bios', + path: path_.resolve(__dirname, RELATIVE_PATH, 'submodules/v86/bios'), + }, { prefix: '/vendor/v86', path: path_.resolve(__dirname, RELATIVE_PATH, 'submodules/v86/build'), diff --git a/src/emulator/assets/template.html b/src/emulator/assets/template.html index 87721584de..15d555bce7 100644 --- a/src/emulator/assets/template.html +++ b/src/emulator/assets/template.html @@ -16,6 +16,20 @@ + @@ -41,5 +55,10 @@ <% } %> +
+
+ +
+ \ No newline at end of file diff --git a/src/emulator/image/Dockerfile b/src/emulator/image/Dockerfile index c45e3b8efa..d46fa5974d 100644 --- a/src/emulator/image/Dockerfile +++ b/src/emulator/image/Dockerfile @@ -52,6 +52,4 @@ RUN rc-update add savecache shutdown COPY rootfs/ / -RUN setup-hostname puter-alpine - RUN bash \ No newline at end of file diff --git a/src/emulator/image/assets/.gitignore b/src/emulator/image/assets/.gitignore new file mode 100644 index 0000000000..d6b7ef32c8 --- /dev/null +++ b/src/emulator/image/assets/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/src/emulator/image/build.sh b/src/emulator/image/build.sh index f8d51fa5e6..8e3a45b61c 100755 --- a/src/emulator/image/build.sh +++ b/src/emulator/image/build.sh @@ -10,7 +10,7 @@ else fi -IMAGES="$(dirname "$0")"/build/x86images +IMAGES="$(dirname "$0")"/build OUT_ROOTFS_TAR="$IMAGES"/rootfs.tar OUT_ROOTFS_BIN="$IMAGES"/rootfs.bin OUT_ROOTFS_MNT="$IMAGES"/rootfs.mntpoint @@ -43,8 +43,3 @@ rm -rf "$OUT_ROOTFS_MNT" echo "done! created" sudo chown -R $USER:$USER $IMAGES/boot -cd "$IMAGES" -mkdir -p rootfs -split -b50M rootfs.bin rootfs/ -cd ../ -find x86images/rootfs/* | jq -Rnc "[inputs]" diff --git a/src/emulator/image/build/.gitignore b/src/emulator/image/build/.gitignore new file mode 100644 index 0000000000..d6b7ef32c8 --- /dev/null +++ b/src/emulator/image/build/.gitignore @@ -0,0 +1,2 @@ +* +!.gitignore diff --git a/src/emulator/src/main.js b/src/emulator/src/main.js index e4d8630c18..37d5a3c698 100644 --- a/src/emulator/src/main.js +++ b/src/emulator/src/main.js @@ -1 +1,387 @@ -puter.ui.launchApp('editor'); +"use strict"; +// puter.ui.launchApp('editor'); + +// Libs + // SO: 40031688 + function buf2hex(buffer) { // buffer is an ArrayBuffer + return [...new Uint8Array(buffer)] + .map(x => x.toString(16).padStart(2, '0')) + .join(''); + } + +class ATStream { + constructor ({ delegate, acc, transform, observe }) { + this.delegate = delegate; + if ( acc ) this.acc = acc; + if ( transform ) this.transform = transform; + if ( observe ) this.observe = observe; + this.state = {}; + this.carry = []; + } + [Symbol.asyncIterator]() { return this; } + async next_value_ () { + if ( this.carry.length > 0 ) { + console.log('got from carry!', this.carry); + return { + value: this.carry.shift(), + done: false, + }; + } + return await this.delegate.next(); + } + async acc ({ value }) { + return value; + } + async next_ () { + for (;;) { + const ret = await this.next_value_(); + if ( ret.done ) return ret; + const v = await this.acc({ + state: this.state, + value: ret.value, + carry: v => this.carry.push(v), + }); + if ( this.carry.length >= 0 && v === undefined ) { + throw new Error(`no value, but carry value exists`); + } + if ( v === undefined ) continue; + // We have a value, clear the state! + this.state = {}; + if ( this.transform ) { + const new_value = await this.transform( + { value: ret.value }); + return { ...ret, value: new_value }; + } + return { ...ret, value: v }; + } + } + async next () { + const ret = await this.next_(); + if ( this.observe && !ret.done ) { + this.observe(ret); + } + return ret; + } + async enqueue_ (v) { + this.queue.push(v); + } +} + +const NewCallbackByteStream = () => { + let listener; + let queue = []; + const NOOP = () => {}; + let signal = NOOP; + (async () => { + for (;;) { + const v = await new Promise((rslv, rjct) => { + listener = rslv; + }); + queue.push(v); + signal(); + } + })(); + const stream = { + [Symbol.asyncIterator](){ + return this; + }, + async next () { + if ( queue.length > 0 ) { + return { + value: queue.shift(), + done: false, + }; + } + await new Promise(rslv => { + signal = rslv; + }); + signal = NOOP; + const v = queue.shift(); + return { value: v, done: false }; + } + }; + stream.listener = data => { + listener(data); + }; + return stream; +} + +// Tiny inline little-endian integer library +const get_int = (n_bytes, array8, signed=false) => { + return (v => signed ? v : v >>> 0)( + array8.slice(0,n_bytes).reduce((v,e,i)=>v|=e<<8*i,0)); +} +const to_int = (n_bytes, num) => { + return (new Uint8Array()).map((_,i)=>(num>>8*i)&0xFF); +} + +const NewVirtioFrameStream = byteStream => { + return new ATStream({ + delegate: byteStream, + async acc ({ value, carry }) { + if ( ! this.state.buffer ) { + const size = get_int(4, value); + // 512MiB limit in case of attempted abuse or a bug + // (assuming this won't happen under normal conditions) + if ( size > 512*(1024**2) ) { + throw new Error(`Way too much data! (${size} bytes)`); + } + value = value.slice(4); + this.state.buffer = new Uint8Array(size); + this.state.index = 0; + } + + const needed = this.state.buffer.length - this.state.index; + if ( value.length > needed ) { + const remaining = value.slice(needed); + console.log('we got more bytes than we needed', + needed, + remaining, + value.length, + this.state.buffer.length, + this.state.index, + ); + carry(remaining); + } + + const amount = Math.min(value.length, needed); + const added = value.slice(0, amount); + this.state.buffer.set(added, this.state.index); + this.state.index += amount; + + if ( this.state.index > this.state.buffer.length ) { + throw new Error('WUT'); + } + if ( this.state.index == this.state.buffer.length ) { + return this.state.buffer; + } + } + }); +}; + +const wisp_types = [ + { + id: 3, + label: 'CONTINUE', + describe: ({ payload }) => { + return `buffer: ${get_int(4, payload)}B`; + }, + getAttributes ({ payload }) { + return { + buffer_size: get_int(4, payload), + }; + } + }, + { + id: 5, + label: 'INFO', + describe: ({ payload }) => { + return `v${payload[0]}.${payload[1]} ` + + buf2hex(payload.slice(2)); + }, + getAttributes ({ payload }) { + return { + version_major: payload[0], + version_minor: payload[1], + extensions: payload.slice(2), + } + } + }, +]; + +class WispPacket { + static SEND = Symbol('SEND'); + static RECV = Symbol('RECV'); + constructor ({ data, direction, extra }) { + this.direction = direction; + this.data_ = data; + this.extra = extra ?? {}; + this.types_ = { + 1: { label: 'CONNECT' }, + 2: { label: 'DATA' }, + 4: { label: 'CLOSE' }, + }; + for ( const item of wisp_types ) { + this.types_[item.id] = item; + } + } + get type () { + const i_ = this.data_[0]; + return this.types_[i_]; + } + get attributes () { + if ( ! this.type.getAttributes ) return {}; + const attrs = {}; + Object.assign(attrs, this.type.getAttributes({ + payload: this.data_.slice(5), + })); + Object.assign(attrs, this.extra); + return attrs; + } + toVirtioFrame () { + const arry = new Uint8Array(this.data_.length + 4); + arry.set(to_int(4, this.data_.length), 0); + arry.set(this.data_, 4); + return arry; + } + describe () { + return this.type.label + '(' + + (this.type.describe?.({ + payload: this.data_.slice(5), + }) ?? '?') + ')'; + } + log () { + const arrow = + this.direction === this.constructor.SEND ? '->' : + this.direction === this.constructor.RECV ? '<-' : + '<>' ; + console.groupCollapsed(`WISP ${arrow} ${this.describe()}`); + const attrs = this.attributes; + for ( const k in attrs ) { + console.log(k, attrs[k]); + } + console.groupEnd(); + } + reflect () { + const reflected = new WispPacket({ + data: this.data_, + direction: + this.direction === this.constructor.SEND ? + this.constructor.RECV : + this.direction === this.constructor.RECV ? + this.constructor.SEND : + undefined, + extra: { + reflectedFrom: this, + } + }); + return reflected; + } +} + +for ( const item of wisp_types ) { + WispPacket[item.label] = item; +} + +const NewWispPacketStream = frameStream => { + return new ATStream({ + delegate: frameStream, + transform ({ value }) { + return new WispPacket({ + data: value, + direction: WispPacket.RECV, + }); + }, + observe ({ value }) { + value.log(); + } + }); +} + +class WispClient { + constructor ({ + packetStream, + sendFn, + }) { + this.packetStream = packetStream; + this.sendFn = sendFn; + } + send (packet) { + packet.log(); + this.sendFn(packet); + } +} + +window.onload = async function() +{ + const resp = await fetch( + './image/build/rootfs.bin' + ); + const arrayBuffer = await resp.arrayBuffer(); + var emulator = window.emulator = new V86({ + wasm_path: "/vendor/v86/v86.wasm", + memory_size: 512 * 1024 * 1024, + vga_memory_size: 2 * 1024 * 1024, + screen_container: document.getElementById("screen_container"), + bios: { + url: "/vendor/v86/bios/seabios.bin", + }, + vga_bios: { + url: "/vendor/v86/bios/vgabios.bin", + }, + + initrd: { + url: './image/build/boot/initramfs-lts', + }, + bzimage: { + url: './image/build/boot/vmlinuz-lts', + async: false + }, + cmdline: 'rw root=/dev/sda init=/sbin/init rootfstype=ext4', + // cmdline: 'rw root=/dev/sda init=/bin/bash rootfstype=ext4', + // cmdline: "rw init=/sbin/init root=/dev/sda rootfstype=ext4", + // cmdline: "rw init=/sbin/init root=/dev/sda rootfstype=ext4 random.trust_cpu=on 8250.nr_uarts=10 spectre_v2=off pti=off mitigations=off", + + // cdrom: { + // // url: "../images/al32-2024.07.10.iso", + // url: "./image/build/rootfs.bin", + // }, + hda: { + buffer: arrayBuffer, + // url: './image/build/rootfs.bin', + async: true, + // size: 1073741824, + // size: 805306368, + }, + // bzimage_initrd_from_filesystem: true, + autostart: true, + + network_relay_url: "wisp://127.0.0.1:3000", + virtio_console: true, + }); + + + const decoder = new TextDecoder(); + const byteStream = NewCallbackByteStream(); + emulator.add_listener('virtio-console0-output-bytes', + byteStream.listener); + const virtioStream = NewVirtioFrameStream(byteStream); + const wispStream = NewWispPacketStream(virtioStream); + + class PTYManager { + constructor ({ client }) { + this.client = client; + } + init () { + this.run_(); + } + async run_ () { + const handlers_ = { + [WispPacket.INFO.id]: ({ packet }) => { + // console.log('guess we doing info packets now', packet); + this.client.send(packet.reflect()); + } + }; + for await ( const packet of this.client.packetStream ) { + // console.log('what we got here?', + // packet.type, + // packet, + // ); + handlers_[packet.type.id]?.({ packet }); + } + } + } + + const ptyMgr = new PTYManager({ + client: new WispClient({ + packetStream: wispStream, + sendFn: packet => { + emulator.bus.send( + "virtio-console0-input-bytes", + packet.toVirtioFrame(), + ); + } + }) + }); + ptyMgr.init(); +} diff --git a/tools/build_v86.sh b/tools/build_v86.sh new file mode 100755 index 0000000000..d4746225c4 --- /dev/null +++ b/tools/build_v86.sh @@ -0,0 +1,43 @@ +#!/bin/bash + +start_dir=$(pwd) +cleanup() { + cd "$start_dir" +} +trap cleanup ERR EXIT +set -e + +echo -e "\x1B[36;1m<<< Adding Targets >>>\x1B[0m" + +rustup target add wasm32-unknown-unknown +rustup target add i686-unknown-linux-gnu + +echo -e "\x1B[36;1m<<< Building v86 >>>\x1B[0m" + +cd submodules/v86 +make all +cd - + +echo -e "\x1B[36;1m<<< Building Twisp >>>\x1B[0m" + +cd submodules/twisp + +RUSTFLAGS="-C target-feature=+crt-static" cargo build \ + --release \ + --target i686-unknown-linux-gnu \ + `# TODO: what are default features?` \ + --no-default-features + +echo -e "\x1B[36;1m<<< Preparing to Build Imag >>>\x1B[0m" + +cd - + +cp submodules/twisp/target/i686-unknown-linux-gnu/release/twisp \ + src/emulator/image/assets/ + +echo -e "\x1B[36;1m<<< Building Image >>>\x1B[0m" + +cd src/emulator/image +./clean.sh +./build.sh +cd - From 21383eec3cc327fa8ed37121320ae66fc8723904 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 5 Sep 2024 18:51:06 -0400 Subject: [PATCH 0856/2119] dev: get basic PTY integration working --- src/emulator/assets/template.html | 10 + src/emulator/src/main.js | 415 +++++++++------------------- src/phoenix/src/pty/XDocumentPTT.js | 8 +- src/puter-wisp/src/exports.js | 106 ++++++- 4 files changed, 243 insertions(+), 296 deletions(-) diff --git a/src/emulator/assets/template.html b/src/emulator/assets/template.html index 15d555bce7..750a05491c 100644 --- a/src/emulator/assets/template.html +++ b/src/emulator/assets/template.html @@ -22,12 +22,22 @@ line-height: 16px; } BODY { + padding: 0; + margin: 0; background-color: #111; display: flex; justify-content: center; align-items: center; height: 100vh; overflow: hidden; + background: linear-gradient(135deg, #232323 50%, transparent 50%) 0% 0% / 3em 3em #101010; + background-position: center center; + background-size: 5px 5px; + } + #screen_container { + padding: 5px; + background-color: #000; + box-shadow: 0 0 32px 0 rgba(0,0,0,0.7); } diff --git a/src/emulator/src/main.js b/src/emulator/src/main.js index 37d5a3c698..6ef3b3dc37 100644 --- a/src/emulator/src/main.js +++ b/src/emulator/src/main.js @@ -1,282 +1,13 @@ "use strict"; -// puter.ui.launchApp('editor'); -// Libs - // SO: 40031688 - function buf2hex(buffer) { // buffer is an ArrayBuffer - return [...new Uint8Array(buffer)] - .map(x => x.toString(16).padStart(2, '0')) - .join(''); - } - -class ATStream { - constructor ({ delegate, acc, transform, observe }) { - this.delegate = delegate; - if ( acc ) this.acc = acc; - if ( transform ) this.transform = transform; - if ( observe ) this.observe = observe; - this.state = {}; - this.carry = []; - } - [Symbol.asyncIterator]() { return this; } - async next_value_ () { - if ( this.carry.length > 0 ) { - console.log('got from carry!', this.carry); - return { - value: this.carry.shift(), - done: false, - }; - } - return await this.delegate.next(); - } - async acc ({ value }) { - return value; - } - async next_ () { - for (;;) { - const ret = await this.next_value_(); - if ( ret.done ) return ret; - const v = await this.acc({ - state: this.state, - value: ret.value, - carry: v => this.carry.push(v), - }); - if ( this.carry.length >= 0 && v === undefined ) { - throw new Error(`no value, but carry value exists`); - } - if ( v === undefined ) continue; - // We have a value, clear the state! - this.state = {}; - if ( this.transform ) { - const new_value = await this.transform( - { value: ret.value }); - return { ...ret, value: new_value }; - } - return { ...ret, value: v }; - } - } - async next () { - const ret = await this.next_(); - if ( this.observe && !ret.done ) { - this.observe(ret); - } - return ret; - } - async enqueue_ (v) { - this.queue.push(v); - } -} - -const NewCallbackByteStream = () => { - let listener; - let queue = []; - const NOOP = () => {}; - let signal = NOOP; - (async () => { - for (;;) { - const v = await new Promise((rslv, rjct) => { - listener = rslv; - }); - queue.push(v); - signal(); - } - })(); - const stream = { - [Symbol.asyncIterator](){ - return this; - }, - async next () { - if ( queue.length > 0 ) { - return { - value: queue.shift(), - done: false, - }; - } - await new Promise(rslv => { - signal = rslv; - }); - signal = NOOP; - const v = queue.shift(); - return { value: v, done: false }; - } - }; - stream.listener = data => { - listener(data); - }; - return stream; -} - -// Tiny inline little-endian integer library -const get_int = (n_bytes, array8, signed=false) => { - return (v => signed ? v : v >>> 0)( - array8.slice(0,n_bytes).reduce((v,e,i)=>v|=e<<8*i,0)); -} -const to_int = (n_bytes, num) => { - return (new Uint8Array()).map((_,i)=>(num>>8*i)&0xFF); -} - -const NewVirtioFrameStream = byteStream => { - return new ATStream({ - delegate: byteStream, - async acc ({ value, carry }) { - if ( ! this.state.buffer ) { - const size = get_int(4, value); - // 512MiB limit in case of attempted abuse or a bug - // (assuming this won't happen under normal conditions) - if ( size > 512*(1024**2) ) { - throw new Error(`Way too much data! (${size} bytes)`); - } - value = value.slice(4); - this.state.buffer = new Uint8Array(size); - this.state.index = 0; - } - - const needed = this.state.buffer.length - this.state.index; - if ( value.length > needed ) { - const remaining = value.slice(needed); - console.log('we got more bytes than we needed', - needed, - remaining, - value.length, - this.state.buffer.length, - this.state.index, - ); - carry(remaining); - } - - const amount = Math.min(value.length, needed); - const added = value.slice(0, amount); - this.state.buffer.set(added, this.state.index); - this.state.index += amount; - - if ( this.state.index > this.state.buffer.length ) { - throw new Error('WUT'); - } - if ( this.state.index == this.state.buffer.length ) { - return this.state.buffer; - } - } - }); -}; - -const wisp_types = [ - { - id: 3, - label: 'CONTINUE', - describe: ({ payload }) => { - return `buffer: ${get_int(4, payload)}B`; - }, - getAttributes ({ payload }) { - return { - buffer_size: get_int(4, payload), - }; - } - }, - { - id: 5, - label: 'INFO', - describe: ({ payload }) => { - return `v${payload[0]}.${payload[1]} ` + - buf2hex(payload.slice(2)); - }, - getAttributes ({ payload }) { - return { - version_major: payload[0], - version_minor: payload[1], - extensions: payload.slice(2), - } - } - }, -]; - -class WispPacket { - static SEND = Symbol('SEND'); - static RECV = Symbol('RECV'); - constructor ({ data, direction, extra }) { - this.direction = direction; - this.data_ = data; - this.extra = extra ?? {}; - this.types_ = { - 1: { label: 'CONNECT' }, - 2: { label: 'DATA' }, - 4: { label: 'CLOSE' }, - }; - for ( const item of wisp_types ) { - this.types_[item.id] = item; - } - } - get type () { - const i_ = this.data_[0]; - return this.types_[i_]; - } - get attributes () { - if ( ! this.type.getAttributes ) return {}; - const attrs = {}; - Object.assign(attrs, this.type.getAttributes({ - payload: this.data_.slice(5), - })); - Object.assign(attrs, this.extra); - return attrs; - } - toVirtioFrame () { - const arry = new Uint8Array(this.data_.length + 4); - arry.set(to_int(4, this.data_.length), 0); - arry.set(this.data_, 4); - return arry; - } - describe () { - return this.type.label + '(' + - (this.type.describe?.({ - payload: this.data_.slice(5), - }) ?? '?') + ')'; - } - log () { - const arrow = - this.direction === this.constructor.SEND ? '->' : - this.direction === this.constructor.RECV ? '<-' : - '<>' ; - console.groupCollapsed(`WISP ${arrow} ${this.describe()}`); - const attrs = this.attributes; - for ( const k in attrs ) { - console.log(k, attrs[k]); - } - console.groupEnd(); - } - reflect () { - const reflected = new WispPacket({ - data: this.data_, - direction: - this.direction === this.constructor.SEND ? - this.constructor.RECV : - this.direction === this.constructor.RECV ? - this.constructor.SEND : - undefined, - extra: { - reflectedFrom: this, - } - }); - return reflected; - } -} - -for ( const item of wisp_types ) { - WispPacket[item.label] = item; -} - -const NewWispPacketStream = frameStream => { - return new ATStream({ - delegate: frameStream, - transform ({ value }) { - return new WispPacket({ - data: value, - direction: WispPacket.RECV, - }); - }, - observe ({ value }) { - value.log(); - } - }); -} +const { XDocumentPTT } = require("../../phoenix/src/pty/XDocumentPTT"); +const { + NewWispPacketStream, + WispPacket, + NewCallbackByteStream, + NewVirtioFrameStream, + DataBuilder, +} = require("../../puter-wisp/src/exports"); class WispClient { constructor ({ @@ -347,28 +78,132 @@ window.onload = async function() byteStream.listener); const virtioStream = NewVirtioFrameStream(byteStream); const wispStream = NewWispPacketStream(virtioStream); + + const shell = puter.ui.parentApp(); + const ptt = new XDocumentPTT(shell, { + disableReader: true, + }) + + ptt.termios.echo = false; class PTYManager { + static STATE_INIT = { + name: 'init', + handlers: { + [WispPacket.INFO.id]: function ({ packet }) { + this.client.send(packet.reflect()); + this.state = this.constructor.STATE_READY; + } + } + }; + static STATE_READY = { + name: 'ready', + handlers: { + [WispPacket.DATA.id]: function ({ packet }) { + console.log('stream id?', packet.streamId); + const pty = this.stream_listeners_[packet.streamId]; + pty.on_payload(packet.payload); + } + }, + on: function () { + const pty = this.getPTY(); + console.log('PTY created', pty); + pty.on_payload = data => { + ptt.out.write(data); + } + (async () => { + // for (;;) { + // const buff = await ptt.in.read(); + // if ( buff === undefined ) continue; + // console.log('this is what ptt in gave', buff); + // pty.send(buff); + // } + const stream = ptt.readableStream; + for await ( const chunk of stream ) { + if ( chunk === undefined ) { + console.error('huh, missing chunk', chunk); + continue; + } + pty.send(chunk); + } + })() + }, + } + + set state (value) { + console.log('[PTYManager] State updated: ', value.name); + this.state_ = value; + if ( this.state_.on ) { + this.state_.on.call(this) + } + } + get state () { return this.state_ } + constructor ({ client }) { + this.streamId = 0; + this.state_ = null; this.client = client; + this.state = this.constructor.STATE_INIT; + this.stream_listeners_ = {}; } init () { this.run_(); } async run_ () { - const handlers_ = { - [WispPacket.INFO.id]: ({ packet }) => { - // console.log('guess we doing info packets now', packet); - this.client.send(packet.reflect()); - } - }; for await ( const packet of this.client.packetStream ) { - // console.log('what we got here?', - // packet.type, - // packet, - // ); - handlers_[packet.type.id]?.({ packet }); + const handlers_ = this.state_.handlers; + if ( ! handlers_[packet.type.id] ) { + console.error(`No handler for packet type ${packet.type.id}`); + console.log(handlers_, this); + continue; + } + handlers_[packet.type.id].call(this, { packet }); + } + } + + getPTY () { + const streamId = ++this.streamId; + const data = new DataBuilder({ leb: true }) + .uint8(0x01) + .uint32(streamId) + .uint8(0x03) + .uint16(10) + .utf8('/bin/bash') + // .utf8('/usr/bin/htop') + .build(); + const packet = new WispPacket( + { data, direction: WispPacket.SEND }); + this.client.send(packet); + const pty = new PTY({ client: this.client, streamId }); + console.log('setting to stream id', streamId); + this.stream_listeners_[streamId] = pty; + return pty; + } + } + + class PTY { + constructor ({ client, streamId }) { + this.client = client; + this.streamId = streamId; + } + + on_payload (data) { + + } + + send (data) { + // convert text into buffers + if ( typeof data === 'string' ) { + data = (new TextEncoder()).encode(data, 'utf-8') } + data = new DataBuilder({ leb: true }) + .uint8(0x02) + .uint32(this.streamId) + .cat(data) + .build(); + const packet = new WispPacket( + { data, direction: WispPacket.SEND }); + this.client.send(packet); } } @@ -376,9 +211,11 @@ window.onload = async function() client: new WispClient({ packetStream: wispStream, sendFn: packet => { + const virtioframe = packet.toVirtioFrame(); + console.log('virtio frame', virtioframe); emulator.bus.send( "virtio-console0-input-bytes", - packet.toVirtioFrame(), + virtioframe, ); } }) diff --git a/src/phoenix/src/pty/XDocumentPTT.js b/src/phoenix/src/pty/XDocumentPTT.js index b1054d3962..7cb6a9bb83 100644 --- a/src/phoenix/src/pty/XDocumentPTT.js +++ b/src/phoenix/src/pty/XDocumentPTT.js @@ -26,7 +26,7 @@ export class XDocumentPTT { id: 104, }, } - constructor(terminalConnection) { + constructor(terminalConnection, opts = {}) { for ( const k in XDocumentPTT.IOCTL ) { this[k] = async () => { return await new Promise((resolve, reject) => { @@ -75,8 +75,10 @@ export class XDocumentPTT { } }); this.out = this.writableStream.getWriter(); - this.in = this.readableStream.getReader(); - this.in = new BetterReader({ delegate: this.in }); + if ( ! opts.disableReader ) { + this.in = this.readableStream.getReader(); + this.in = new BetterReader({ delegate: this.in }); + } terminalConnection.on('message', message => { if (message.$ === 'ioctl.set') { diff --git a/src/puter-wisp/src/exports.js b/src/puter-wisp/src/exports.js index 709bb3eba6..8d9d8eeb06 100644 --- a/src/puter-wisp/src/exports.js +++ b/src/puter-wisp/src/exports.js @@ -13,7 +13,7 @@ lib.get_int = (n_bytes, array8, signed=false) => { array8.slice(0,n_bytes).reduce((v,e,i)=>v|=e<<8*i,0)); } lib.to_int = (n_bytes, num) => { - return (new Uint8Array()).map((_,i)=>(num>>8*i)&0xFF); + return (new Uint8Array(n_bytes)).map((_,i)=>(num>>8*i)&0xFF); } // Accumulator and/or Transformer (and/or Observer) Stream @@ -183,6 +183,26 @@ const wisp_types = [ }; } }, + { + id: 1, + label: 'CONNECT', + describe: ({ attributes }) => { + return `${ + attributes.type === 1 ? 'TCP' : + attributes.type === 2 ? 'UDP' : + attributes.type === 3 ? 'PTY' : + 'UNKNOWN' + } ${attributes.host}:${attributes.port}`; + }, + getAttributes: ({ payload }) => { + const type = payload[0]; + const port = lib.get_int(2, payload.slice(1)); + const host = new TextDecoder().decode(payload.slice(3)); + return { + type, port, host, + }; + } + }, { id: 5, label: 'INFO', @@ -198,6 +218,20 @@ const wisp_types = [ } } }, + { + id: 2, + label: 'DATA', + describe: ({ attributes }) => { + return `${attributes.length}B`; + }, + getAttributes ({ payload }) { + return { + length: payload.length, + contents: payload, + utf8: new TextDecoder().decode(payload), + } + } + }, ]; class WispPacket { @@ -208,8 +242,6 @@ class WispPacket { this.data_ = data; this.extra = extra ?? {}; this.types_ = { - 1: { label: 'CONNECT' }, - 2: { label: 'DATA' }, 4: { label: 'CLOSE' }, }; for ( const item of wisp_types ) { @@ -222,14 +254,28 @@ class WispPacket { } get attributes () { if ( ! this.type.getAttributes ) return {}; - const attrs = {}; + const attrs = { + streamId: this.streamId, + }; Object.assign(attrs, this.type.getAttributes({ payload: this.data_.slice(5), })); Object.assign(attrs, this.extra); return attrs; } + get payload () { + return this.data_.slice(5); + } + get streamId () { + return lib.get_int(4, this.data_.slice(1)); + } toVirtioFrame () { + console.log( + 'WISP packet to virtio frame', + this.data_, + this.data_.length, + lib.to_int(4, this.data_.length), + ); const arry = new Uint8Array(this.data_.length + 4); arry.set(lib.to_int(4, this.data_.length), 0); arry.set(this.data_, 4); @@ -238,6 +284,7 @@ class WispPacket { describe () { return this.type.label + '(' + (this.type.describe?.({ + attributes: this.attributes, payload: this.data_.slice(5), }) ?? '?') + ')'; } @@ -290,9 +337,60 @@ const NewWispPacketStream = frameStream => { }); } +class DataBuilder { + constructor ({ leb } = {}) { + this.pos = 0; + this.steps = []; + this.leb = leb; + } + uint8(value) { + this.steps.push(['setUint8', this.pos, value]); + this.pos++; + return this; + } + uint16(value, leb) { + leb ??= this.leb; + this.steps.push(['setUint8', this.pos, value, leb]); + this.pos += 2; + return this; + } + uint32(value, leb) { + leb ??= this.leb; + this.steps.push(['setUint32', this.pos, value, leb]); + this.pos += 4; + return this; + } + utf8(value) { + const encoded = new TextEncoder().encode(value); + this.steps.push(['array', 'set', encoded, this.pos]); + this.pos += encoded.length; + return this; + } + cat(data) { + this.steps.push(['array', 'set', data, this.pos]); + this.pos += data.length; + return this; + } + build () { + const array = new Uint8Array(this.pos); + const view = new DataView(array.buffer); + for ( const step of this.steps ) { + let target = view; + let fn_name = step.shift(); + if ( fn_name === 'array' ) { + fn_name = step.shift(); + target = array; + } + target[fn_name](...step); + } + return array; + } +} + module.exports = { NewCallbackByteStream, NewVirtioFrameStream, NewWispPacketStream, WispPacket, + DataBuilder, }; From db3e0b5ce84e4b0b35550f380da97b5d6fcb394b Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sun, 8 Sep 2024 01:44:13 -0400 Subject: [PATCH 0857/2119] fix: simplify callback listener and fix async bug --- src/puter-wisp/src/exports.js | 13 +--- src/puter-wisp/test/test.js | 128 ++++++++++++++++++++++++++++++---- 2 files changed, 115 insertions(+), 26 deletions(-) diff --git a/src/puter-wisp/src/exports.js b/src/puter-wisp/src/exports.js index 8d9d8eeb06..39f06e0ddd 100644 --- a/src/puter-wisp/src/exports.js +++ b/src/puter-wisp/src/exports.js @@ -77,19 +77,9 @@ class ATStream { } const NewCallbackByteStream = () => { - let listener; let queue = []; const NOOP = () => {}; let signal = NOOP; - (async () => { - for (;;) { - const v = await new Promise((rslv, rjct) => { - listener = rslv; - }); - queue.push(v); - signal(); - } - })(); const stream = { [Symbol.asyncIterator](){ return this; @@ -110,7 +100,8 @@ const NewCallbackByteStream = () => { } }; stream.listener = data => { - listener(data); + queue.push(data); + signal(); }; return stream; } diff --git a/src/puter-wisp/test/test.js b/src/puter-wisp/test/test.js index be063cee0d..53f5b54c7d 100644 --- a/src/puter-wisp/test/test.js +++ b/src/puter-wisp/test/test.js @@ -19,32 +19,130 @@ const NewTestFullByteStream = uint8array => { })(); }; -(async () => { +/** + * This will send 'sz'-sized chunks of the uint8array + * until the uint8array is exhausted. The last chunk + * may be smaller than 'sz'. + * @curry + * @param {*} sz + * @param {*} uint8array + */ +const NewTestWindowByteStream = sz => { + const fn = uint8array => { + return (async function * () { + let offset = 0; + while ( offset < uint8array.length ) { + const end = Math.min(offset + sz, uint8array.length); + const chunk = uint8array.slice(offset, end); + offset += sz; + yield chunk; + } + })(); + }; + fn.name_ = `NewTestWindowByteStream(${sz})`; + return fn; +}; + +const NewTestChunkedByteStream = chunks => { + return (async function * () { + for ( const chunk of chunks ) { + yield chunk; + } + })(); +} + +const test = async (name, fn) => { + console.log(`\x1B[36;1m=== [ Running test: ${name} ] ===\x1B[0m`); + await fn(); +}; + +const BASH_TEST_BYTES = [ + 22, 0, 0, 0, 2, 1, 0, 0, 0, 27, 91, 63, 50, 48, 48, 52, 108, 13, 27, 91, 63, 50, 48, 48, 52, 104, + 10, 0, 0, 0, 2, 1, 0, 0, 0, 40, 110, 111, 110, 101, + 10, 0, 0, 0, 2, 1, 0, 0, 0, 41, 58, 47, 35, 32, + 7, 0, 0, 0, 2, 1, 0, 0, 0, 13, 10, + 14, 0, 0, 0, 2, 1, 0, 0, 0, 27, 91, 63, 50, 48, 48, 52, 108, 13, + 17, 0, 0, 0, 2, 1, 0, 0, 0, 27, 91, 63, 50, 48, 48, 52, 104, 40, 110, 111, 110, + 11, 0, 0, 0, 2, 1, 0, 0, 0, 101, 41, 58, 47, 35, 32 +] + +const runit = async () => { const stream_behaviors = [ NewTestByteStream, NewTestFullByteStream, + NewTestWindowByteStream(2), + NewTestWindowByteStream(3), ]; + for ( const stream_behavior of stream_behaviors ) { - const byteStream = stream_behavior( + await test(`Wisp CONTINUE ${stream_behavior.name_ ?? stream_behavior.name}`, async () => { + const byteStream = stream_behavior( + Uint8Array.from([ + 9, 0, 0, 0, // size of frame: 9 bytes (u32-L) + 3, // CONTINUE (u8) + 0, 0, 0, 0, // stream id: 0 (u32-L) + 0x0F, 0x0F, 0, 0, // buffer size (u32-L) + ]) + ); + const virtioStream = NewVirtioFrameStream(byteStream); + const wispStream = NewWispPacketStream(virtioStream); + + const packets = []; + for await ( const packet of wispStream ) { + packets.push(packet); + } + + assert.strictEqual(packets.length, 1); + const packet = packets[0]; + assert.strictEqual(packet.type.id, 3); + assert.strictEqual(packet.type.label, 'CONTINUE'); + assert.strictEqual(packet.type, WispPacket.CONTINUE); + }); + } + + await test('bash prompt chunking', async () => { + const byteStream = NewTestChunkedByteStream([ + // These are data frames from virtio->twisp->bash + // "(none" + Uint8Array.from([ + 10, 0, 0, 0, 2, 1, 0, 0, 0, + 40, 110, 111, 110, 101 + ]), + // "):/# " Uint8Array.from([ - 9, 0, 0, 0, // size of frame: 9 bytes (u32-L) - 3, // CONTINUE (u8) - 0, 0, 0, 0, // stream id: 0 (u32-L) - 0x0F, 0x0F, 0, 0, // buffer size (u32-L) - ]) - ); + 10, 0, 0, 0, 2, 1, 0, 0, 0, + 41, 58, 47, 35, 32, + ]), + ]); const virtioStream = NewVirtioFrameStream(byteStream); const wispStream = NewWispPacketStream(virtioStream); - const packets = []; + const data = []; for await ( const packet of wispStream ) { - packets.push(packet); + for ( const item of packet.payload ) { + data.push(item); + } } - assert.strictEqual(packets.length, 1); - const packet = packets[0]; - assert.strictEqual(packet.type.id, 3); - assert.strictEqual(packet.type.label, 'CONTINUE'); - assert.strictEqual(packet.type, WispPacket.CONTINUE); + const expected = [ + 40, 110, 111, 110, 101, + 41, 58, 47, 35, 32, + ]; + + assert.strictEqual(data.length, expected.length); + for ( let i = 0; i < data.length; i++ ) { + assert.strictEqual(data[i], expected[i]); + } + }); +}; + +(async () => { + try { + await runit(); + } catch (e) { + console.error(e); + console.log(`\x1B[31;1mTest Failed\x1B[0m`); + process.exit(1); } + console.log(`\x1B[32;1mAll tests passed\x1B[0m`); })(); \ No newline at end of file From e1ec84877ac8dc6b5d63e9cf5464beae94f7cbdf Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sun, 8 Sep 2024 23:52:45 -0400 Subject: [PATCH 0858/2119] dev: resize handling --- src/emulator/src/main.js | 24 +++++++++++++++++++ src/phoenix/src/ansi-shell/ANSIShell.js | 1 + .../providers/PuterAppCommandProvider.js | 15 +++++++++++- src/puter-wisp/src/exports.js | 14 +++++++++++ 4 files changed, 53 insertions(+), 1 deletion(-) diff --git a/src/emulator/src/main.js b/src/emulator/src/main.js index 6ef3b3dc37..633d0a0dac 100644 --- a/src/emulator/src/main.js +++ b/src/emulator/src/main.js @@ -108,9 +108,20 @@ window.onload = async function() on: function () { const pty = this.getPTY(); console.log('PTY created', pty); + + // resize + ptt.on('ioctl.set', evt => { + console.log('event?', evt); + pty.resize(evt.windowSize); + }); + ptt.TIOCGWINSZ(); + + // data from PTY pty.on_payload = data => { ptt.out.write(data); } + + // data to PTY (async () => { // for (;;) { // const buff = await ptt.in.read(); @@ -205,6 +216,19 @@ window.onload = async function() { data, direction: WispPacket.SEND }); this.client.send(packet); } + + resize ({ rows, cols }) { + console.log('resize called!'); + const data = new DataBuilder({ leb: true }) + .uint8(0xf0) + .uint32(this.streamId) + .uint16(rows) + .uint16(cols) + .build(); + const packet = new WispPacket( + { data, direction: WispPacket.SEND }); + this.client.send(packet); + } } const ptyMgr = new PTYManager({ diff --git a/src/phoenix/src/ansi-shell/ANSIShell.js b/src/phoenix/src/ansi-shell/ANSIShell.js index 580ba2b7c5..4d9cd47f70 100644 --- a/src/phoenix/src/ansi-shell/ANSIShell.js +++ b/src/phoenix/src/ansi-shell/ANSIShell.js @@ -219,6 +219,7 @@ export class ANSIShell extends EventTarget { } const executionCtx = this.ctx.sub({ + shell: this, vars: this.variables, env: this.env, locals: { diff --git a/src/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js b/src/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js index 2014989335..ff88897546 100644 --- a/src/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js +++ b/src/phoenix/src/puter-shell/providers/PuterAppCommandProvider.js @@ -60,6 +60,17 @@ export class PuterAppCommandProvider { }; const child = await puter.ui.launchApp(id, args); + const resize_listener = evt => { + child.postMessage({ + $: 'ioctl.set', + windowSize: { + rows: evt.detail.rows, + cols: evt.detail.cols, + } + }); + }; + ctx.shell.addEventListener('signal.window-resize', resize_listener); + // Wait for app to close. const app_close_promise = new Promise((resolve, reject) => { child.on('close', (data) => { @@ -118,7 +129,9 @@ export class PuterAppCommandProvider { } // TODO: propagate sigint to the app - return Promise.race([ app_close_promise, sigint_promise ]); + const exit = await Promise.race([ app_close_promise, sigint_promise ]); + ctx.shell.removeEventListener('signal.window-resize', resize_listener); + return exit; } }; } diff --git a/src/puter-wisp/src/exports.js b/src/puter-wisp/src/exports.js index 39f06e0ddd..88b5028324 100644 --- a/src/puter-wisp/src/exports.js +++ b/src/puter-wisp/src/exports.js @@ -223,6 +223,20 @@ const wisp_types = [ } } }, + { + // TODO: extension types should not be hardcoded here + id: 0xf0, + label: 'RESIZE', + describe: ({ attributes }) => { + return `${attributes.cols}x${attributes.rows}`; + }, + getAttributes ({ payload }) { + return { + rows: lib.get_int(2, payload), + cols: lib.get_int(2, payload.slice(2)), + } + } + }, ]; class WispPacket { From e2cb6194bb015dcf4a3f40c0be74f5a7559c64bb Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 9 Sep 2024 16:24:56 -0400 Subject: [PATCH 0859/2119] dev: add startup apps, start emulator by default --- doc/devmeta/track-comments.md | 3 +++ src/backend/src/services/BaseService.js | 4 ++-- src/gui/src/UI/UIDesktop.js | 6 ++++++ src/gui/src/definitions.js | 9 +++++++-- src/gui/src/initgui.js | 5 +++++ src/gui/src/services/ProcessService.js | 17 ++++++++++++++++ src/putility/index.js | 4 ++++ src/putility/src/concepts/Service.js | 26 +++++++++++++++++++++++++ 8 files changed, 70 insertions(+), 4 deletions(-) create mode 100644 src/putility/src/concepts/Service.js diff --git a/doc/devmeta/track-comments.md b/doc/devmeta/track-comments.md index 1c373262e2..260d7f3330 100644 --- a/doc/devmeta/track-comments.md +++ b/doc/devmeta/track-comments.md @@ -57,3 +57,6 @@ Comments beginning with `// track:`. See It may be applicable to write an iterator in the future, or something will come up that require these to be handled with a modular approach instead. +- `track: checkpoint` + A location where some statement about the state of the + software must hold true. diff --git a/src/backend/src/services/BaseService.js b/src/backend/src/services/BaseService.js index 83ba918a8f..1b169fae6d 100644 --- a/src/backend/src/services/BaseService.js +++ b/src/backend/src/services/BaseService.js @@ -16,11 +16,11 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ -const { AdvancedBase } = require("../../../putility"); +const { concepts } = require("@heyputer/putility"); const NOOP = async () => {}; -class BaseService extends AdvancedBase { +class BaseService extends concepts.Service { constructor (service_resources, ...a) { const { services, config, my_config, name, args } = service_resources; super(service_resources, ...a); diff --git a/src/gui/src/UI/UIDesktop.js b/src/gui/src/UI/UIDesktop.js index 8a0ea74482..d78170b3c6 100644 --- a/src/gui/src/UI/UIDesktop.js +++ b/src/gui/src/UI/UIDesktop.js @@ -1022,6 +1022,12 @@ async function UIDesktop(options){ // adjust window container to take into account the toolbar height $('.window-container').css('top', window.toolbar_height); + // track: checkpoint + //----------------------------- + // GUI is ready to launch apps! + //----------------------------- + + globalThis.services.emit('gui:ready'); //-------------------------------------------------------------------------------------- // Determine if an app was launched from URL diff --git a/src/gui/src/definitions.js b/src/gui/src/definitions.js index 8e5911ed1e..7f928bca5a 100644 --- a/src/gui/src/definitions.js +++ b/src/gui/src/definitions.js @@ -17,9 +17,13 @@ * along with this program. If not, see . */ -import { AdvancedBase } from "@heyputer/putility"; +import { concepts, AdvancedBase } from "@heyputer/putility"; -export class Service { +export class Service extends concepts.Service { + // TODO: Service todo items + static TODO = [ + 'consolidate with BaseService from backend' + ]; construct (o) { this.$puter = {}; for ( const k in o ) this.$puter[k] = o[k]; @@ -28,6 +32,7 @@ export class Service { } init (...a) { if ( ! this._init ) return; + this.services = a[0].services; return this._init(...a) } }; diff --git a/src/gui/src/initgui.js b/src/gui/src/initgui.js index df19077815..0506994edf 100644 --- a/src/gui/src/initgui.js +++ b/src/gui/src/initgui.js @@ -55,6 +55,11 @@ const launch_services = async function (options) { const services_m_ = {}; globalThis.services = { get: (name) => services_m_[name], + emit: (id, args) => { + for (const [_, instance] of services_l_) { + instance.__on(id, args ?? []); + } + } }; const register = (name, instance) => { services_l_.push([name, instance]); diff --git a/src/gui/src/services/ProcessService.js b/src/gui/src/services/ProcessService.js index 08683772b4..b210a6b6ca 100644 --- a/src/gui/src/services/ProcessService.js +++ b/src/gui/src/services/ProcessService.js @@ -22,6 +22,10 @@ import { InitProcess, Service } from "../definitions.js"; const NULL_UUID = '00000000-0000-0000-0000-000000000000'; export class ProcessService extends Service { + static INITRC = [ + 'test-emu' + ]; + async _init () { this.processes = []; this.processes_map = new Map(); @@ -33,6 +37,19 @@ export class ProcessService extends Service { this.register_(root); } + ['__on_gui:ready'] () { + const svc_exec = this.services.get('exec'); + for ( let spec of ProcessService.INITRC ) { + if ( typeof spec === 'string' ) { + spec = { name: spec }; + } + + svc_exec.launchApp({ + app_name: spec.name, + }); + } + } + get_init () { return this.processes_map.get(NULL_UUID); } diff --git a/src/putility/index.js b/src/putility/index.js index ce7be26ae1..74835bcd5d 100644 --- a/src/putility/index.js +++ b/src/putility/index.js @@ -17,10 +17,14 @@ * along with this program. If not, see . */ const { AdvancedBase } = require('./src/AdvancedBase'); +const { Service } = require('./src/concepts/Service'); module.exports = { AdvancedBase, libs: { promise: require('./src/libs/promise'), }, + concepts: { + Service, + }, }; diff --git a/src/putility/src/concepts/Service.js b/src/putility/src/concepts/Service.js new file mode 100644 index 0000000000..023beb7806 --- /dev/null +++ b/src/putility/src/concepts/Service.js @@ -0,0 +1,26 @@ +const { AdvancedBase } = require("../AdvancedBase"); + +const NOOP = async () => {}; + +/** + * Service will be incrementally updated to consolidate + * BaseService in Puter's backend with Service in Puter's frontend, + * becoming the common base for both and a useful utility in general. + */ +class Service extends AdvancedBase { + async __on (id, args) { + const handler = this.__get_event_handler(id); + + return await handler(id, ...args); + } + + __get_event_handler (id) { + return this[`__on_${id}`]?.bind?.(this) + || this.constructor[`__on_${id}`]?.bind?.(this.constructor) + || NOOP; + } +} + +module.exports = { + Service, +}; From 62634b0afe4d33da08768975322d4deb23041442 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 9 Sep 2024 18:25:33 -0400 Subject: [PATCH 0860/2119] feat: add connectToInstance method to puter.ui --- src/emulator/src/main.js | 4 ++ src/gui/src/definitions.js | 13 ++++++ src/gui/src/services/ExecService.js | 33 +++++++++++++ src/gui/src/services/ProcessService.js | 10 ++++ src/phoenix/src/puter-shell/main.js | 2 + .../providers/EmuCommandProvider.js | 46 +++++++++++++++++++ src/puter-js/src/modules/UI.js | 24 ++++++++++ 7 files changed, 132 insertions(+) create mode 100644 src/phoenix/src/puter-shell/providers/EmuCommandProvider.js diff --git a/src/emulator/src/main.js b/src/emulator/src/main.js index 633d0a0dac..1b7d7f9992 100644 --- a/src/emulator/src/main.js +++ b/src/emulator/src/main.js @@ -23,6 +23,10 @@ class WispClient { } } +puter.ui.on('connection', event => { + console.log('emulator got connection event', event); +}); + window.onload = async function() { const resp = await fetch( diff --git a/src/gui/src/definitions.js b/src/gui/src/definitions.js index 7f928bca5a..5ef2f925c7 100644 --- a/src/gui/src/definitions.js +++ b/src/gui/src/definitions.js @@ -85,6 +85,10 @@ export class Process extends AdvancedBase{ this._signal(sig); } + handle_connection (other_process) { + throw new Error('Not implemented'); + } + get type () { const _to_type_name = (name) => { return name.replace(/Process$/, '').toLowerCase(); @@ -139,6 +143,15 @@ export class PortalProcess extends Process { const target = this.references.iframe.contentWindow; // NEXT: ... } + + handle_connection (other_process, args) { + const target = this.references.iframe.contentWindow; + target.postMessage({ + msg: 'connection', + appInstanceID: other_process.uuid, + args, + }); + } }; export class PseudoProcess extends Process { _construct () { this.type_ = 'ui' } diff --git a/src/gui/src/services/ExecService.js b/src/gui/src/services/ExecService.js index 15ef144cff..213705b911 100644 --- a/src/gui/src/services/ExecService.js +++ b/src/gui/src/services/ExecService.js @@ -11,6 +11,9 @@ export class ExecService extends Service { svc_ipc.register_ipc_handler('launchApp', { handler: this.launchApp.bind(this), }); + svc_ipc.register_ipc_handler('connectToInstance', { + handler: this.connectToInstance.bind(this), + }); } // This method is exposed to apps via IPCService. @@ -70,4 +73,34 @@ export class ExecService extends Service { usesSDK: true, }; } + + async connectToInstance ({ app_name, args }, { ipc_context, msg_id } = {}) { + const caller_process = ipc_context?.caller?.process; + if ( ! caller_process ) { + throw new Error('Caller process not found'); + } + + console.log( + caller_process.name, + app_name, + ); + // TODO: permissions integration; for now it's hardcoded + if ( caller_process.name !== 'phoenix' ) { + throw new Error('Connection not allowed.'); + } + if ( app_name !== 'test-emu' ) { + throw new Error('Connection not allowed.'); + } + + const svc_process = this.services.get('process'); + const options = svc_process.select_by_name(app_name); + const process = options[0]; + + await process.handle_connection(caller_process, args); + + return { + appInstanceID: process.uuid, + response, + }; + } } diff --git a/src/gui/src/services/ProcessService.js b/src/gui/src/services/ProcessService.js index b210a6b6ca..d41404ee3c 100644 --- a/src/gui/src/services/ProcessService.js +++ b/src/gui/src/services/ProcessService.js @@ -66,6 +66,16 @@ export class ProcessService extends Service { return this.uuid_to_treelist.get(uuid); } + select_by_name (name) { + const list = []; + for ( const process of this.processes ) { + if ( process.name === name ) { + list.push(process); + } + } + return list; + } + register (process) { this.register_(process); this.attach_to_parent_(process); diff --git a/src/phoenix/src/puter-shell/main.js b/src/phoenix/src/puter-shell/main.js index 0d4b94cd6a..e79252dad1 100644 --- a/src/phoenix/src/puter-shell/main.js +++ b/src/phoenix/src/puter-shell/main.js @@ -35,6 +35,7 @@ import { MultiWriter } from '../ansi-shell/ioutil/MultiWriter.js'; import { CompositeCommandProvider } from './providers/CompositeCommandProvider.js'; import { ScriptCommandProvider } from './providers/ScriptCommandProvider.js'; import { PuterAppCommandProvider } from './providers/PuterAppCommandProvider.js'; +import { EmuCommandProvider } from './providers/EmuCommandProvider.js'; const argparser_registry = { [SimpleArgParser.name]: SimpleArgParser @@ -92,6 +93,7 @@ export const launchPuterShell = async (ctx) => { // PuterAppCommandProvider is only usable on Puter ...(ctx.platform.name === 'puter' ? [new PuterAppCommandProvider()] : []), new ScriptCommandProvider(), + new EmuCommandProvider(), ]); ctx = ctx.sub({ diff --git a/src/phoenix/src/puter-shell/providers/EmuCommandProvider.js b/src/phoenix/src/puter-shell/providers/EmuCommandProvider.js new file mode 100644 index 0000000000..1af4d9d6ea --- /dev/null +++ b/src/phoenix/src/puter-shell/providers/EmuCommandProvider.js @@ -0,0 +1,46 @@ +import { Exit } from "../coreutils/coreutil_lib/exit"; + +export class EmuCommandProvider { + static AVAILABLE = [ + 'bash', + 'htop', + ]; + + static EMU_APP_NAME = 'test-emu'; + + constructor () { + this.available = this.constructor.AVAILABLE; + this.emulator = null; + } + + async aquire_emulator () { + if ( this.emulator ) return this.emulator; + + // FUTURE: when we have a way to query instances + // without exposing the real instance id + /* + const instances = await puter.ui.queryInstances(); + if ( instances.length < 0 ) { + return; + } + const instance = instances[0]; + */ + + const conn = await puter.ui.connectToInstance(this.constructor.EMU_APP_NAME); + return this.emulator = conn; + } + + async lookup (id, { ctx }) { + if ( ! this.available.includes(id) ) { + return; + } + + const emu = await this.aquire_emulator(); + if ( ! emu ) { + ctx.externs.out.write('No emulator available.\n'); + return new Exit(1); + } + + ctx.externs.out.write(`Launching ${id} in emulator ${emu.appInstanceID}\n`); + } +} diff --git a/src/puter-js/src/modules/UI.js b/src/puter-js/src/modules/UI.js index 2cf327a5c5..f8d9a794a3 100644 --- a/src/puter-js/src/modules/UI.js +++ b/src/puter-js/src/modules/UI.js @@ -203,6 +203,7 @@ class UI extends EventListener { const eventNames = [ 'localeChanged', 'themeChanged', + 'connection', ]; super(eventNames); this.#eventNames = eventNames; @@ -460,6 +461,15 @@ class UI extends EventListener { this.emit(name, data); this.#lastBroadcastValue.set(name, data); } + else if ( e.data.msg === 'connection' ) { + const conn = AppConnection.from(e.data, { + appInstanceID: this.appInstanceID, + messageTarget: window.parent, + }); + this.emit('connection', { + conn + }); + } }); // We need to send the mouse position to the host environment @@ -951,6 +961,20 @@ class UI extends EventListener { }); } + connectToInstance = async function connectToInstance (app_name) { + const app_info = await this.#ipc_stub({ + method: 'connectToInstance', + parameters: { + app_name, + } + }); + + return AppConnection.from(app_info, { + appInstanceID: this.appInstanceID, + messageTarget: this.messageTarget, + }); + } + parentApp() { return this.#parentAppConnection; } From e3d4a5f3b3b9dab600db1e39e47dbf19703c493c Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 11 Sep 2024 23:59:25 -0400 Subject: [PATCH 0861/2119] dev: multi-instance many-to-many app-to-app comms I'll elaborate here because the commit name is confusing. Any time an app gets a connection to another app, either because it launched that app (or was launched by that app) or requested a connection to that app, the ID the app gets to represent the app it's communicating with is now a pseudo app id rather than the app instance ID. This accomplishes two things: 1. It's more secure. There are multiple places where GUI assumes that knowing an app's instance ID means you can do things as that app. 2. Between the same two apps, there may now be more than one connection. This is useful for situations like Phoenix shell talking to the emulator in multiple separate instances to pipe commands. (this is coming later) --- src/gui/src/IPC.js | 16 +++++++++++ src/gui/src/definitions.js | 17 +++++++++--- src/gui/src/helpers/launch_app.js | 2 +- src/gui/src/services/ExecService.js | 29 ++++++++++++++++---- src/gui/src/services/IPCService.js | 42 ++++++++++++++++++++++++++++- src/phoenix/src/main_puter.js | 1 - src/puter-js/src/modules/UI.js | 6 ++++- 7 files changed, 100 insertions(+), 13 deletions(-) diff --git a/src/gui/src/IPC.js b/src/gui/src/IPC.js index beeb0f9058..9a08a50e48 100644 --- a/src/gui/src/IPC.js +++ b/src/gui/src/IPC.js @@ -1439,6 +1439,22 @@ window.addEventListener('message', async (event) => { const { appInstanceID, targetAppInstanceID, targetAppOrigin, contents } = event.data; // TODO: Determine if we should allow the message // TODO: Track message traffic between apps + const svc_ipc = globalThis.services.get('ipc'); + // const svc_exec = globalThis.services() + + const conn = svc_ipc.get_connection(targetAppInstanceID); + if ( conn ) { + conn.send(contents); + // conn.send({ + // msg: 'messageToApp', + // appInstanceID, + // targetAppInstanceID, + // contents, + // }, targetAppOrigin); + return; + } + + console.log(`🔒 App ${appInstanceID} is sending to ${targetAppInstanceID} insecurely`); // pass on the message const target_iframe = window.iframe_for_app_instance(targetAppInstanceID); diff --git a/src/gui/src/definitions.js b/src/gui/src/definitions.js index 5ef2f925c7..22c1496686 100644 --- a/src/gui/src/definitions.js +++ b/src/gui/src/definitions.js @@ -35,6 +35,9 @@ export class Service extends concepts.Service { this.services = a[0].services; return this._init(...a) } + get context () { + return { services: this.services }; + } }; export const PROCESS_INITIALIZING = { i18n_key: 'initializing' }; @@ -139,16 +142,22 @@ export class PortalProcess extends Process { } } - send (channel, object, context) { + send (channel, data, context) { const target = this.references.iframe.contentWindow; - // NEXT: ... + target.postMessage({ + msg: 'messageToApp', + appInstanceID: channel.returnAddress, + targetAppInstanceID: this.uuid, + contents: data, + // }, new URL(this.references.iframe.src).origin); + }, '*'); } - handle_connection (other_process, args) { + handle_connection (connection, args) { const target = this.references.iframe.contentWindow; target.postMessage({ msg: 'connection', - appInstanceID: other_process.uuid, + appInstanceID: connection.uuid, args, }); } diff --git a/src/gui/src/helpers/launch_app.js b/src/gui/src/helpers/launch_app.js index 00e2d2a7dd..bbb47c2a75 100644 --- a/src/gui/src/helpers/launch_app.js +++ b/src/gui/src/helpers/launch_app.js @@ -183,7 +183,7 @@ const launch_app = async (options)=>{ // add parent_app_instance_id to URL if (options.parent_instance_id) { - iframe_url.searchParams.append('puter.parent_instance_id', options.parent_instance_id); + iframe_url.searchParams.append('puter.parent_instance_id', options.parent_pseudo_id); } if(file_signature){ diff --git a/src/gui/src/services/ExecService.js b/src/gui/src/services/ExecService.js index 213705b911..386b6cac57 100644 --- a/src/gui/src/services/ExecService.js +++ b/src/gui/src/services/ExecService.js @@ -20,19 +20,30 @@ export class ExecService extends Service { async launchApp ({ app_name, args }, { ipc_context, msg_id } = {}) { const app = ipc_context?.caller?.app; const process = ipc_context?.caller?.process; - + // This mechanism will be replated with xdrpc soon const child_instance_id = window.uuidv4(); + const svc_ipc = this.services.get('ipc'); + const connection = ipc_context ? svc_ipc.add_connection({ + source: process.uuid, + target: child_instance_id, + }) : undefined; + // The "body" of this method is in a separate file const child_process = await launch_app({ name: app_name, args: args ?? {}, parent_instance_id: app?.appInstanceID, uuid: child_instance_id, + ...(connection ? { + parent_pseudo_id: connection.backward.uuid, + } : {}), }); const send_child_launched_msg = (...a) => { + if ( ! process ) return; + // TODO: (maybe) message process instead of iframe const parent_iframe = process?.references?.iframe; parent_iframe.contentWindow.postMessage({ msg: 'childAppLaunched', @@ -67,9 +78,10 @@ export class ExecService extends Service { window.report_app_closed(child_process.uuid); } }); - + return { - appInstanceID: child_instance_id, + appInstanceID: connection ? + connection.forward.uuid : child_instance_id, usesSDK: true, }; } @@ -96,10 +108,17 @@ export class ExecService extends Service { const options = svc_process.select_by_name(app_name); const process = options[0]; - await process.handle_connection(caller_process, args); + const svc_ipc = this.services.get('ipc'); + const connection = svc_ipc.add_connection({ + source: caller_process.uuid, + target: process.uuid, + }); + + const response = await process.handle_connection( + connection.backward, args); return { - appInstanceID: process.uuid, + appInstanceID: connection.forward.uuid, response, }; } diff --git a/src/gui/src/services/IPCService.js b/src/gui/src/services/IPCService.js index 83ac0bf354..82f7c8f22e 100644 --- a/src/gui/src/services/IPCService.js +++ b/src/gui/src/services/IPCService.js @@ -1,12 +1,52 @@ import { Service } from "../definitions.js"; +class InternalConnection { + constructor ({ source, target, uuid, reverse }, { services }) { + this.services = services; + this.source = source; + this.target = target; + this.uuid = uuid; + this.reverse = reverse; + } + + send (data) { + const svc_process = this.services.get('process'); + const process = svc_process.get_by_uuid(this.target); + const channel = { + returnAddress: this.reverse, + }; + process.send(channel, data); + } +} + export class IPCService extends Service { static description = ` Allows other services to expose methods to apps. ` async _init () { - // + this.connections_ = {}; + } + + add_connection ({ source, target }) { + const uuid = window.uuidv4(); + const r_uuid = window.uuidv4(); + const forward = this.connections_[uuid] = { + source, target, + uuid: uuid, reverse: r_uuid, + }; + const backward = this.connections_[r_uuid] = { + source: target, target: source, + uuid: r_uuid, reverse: uuid, + }; + return { forward, backward }; + } + + get_connection (uuid) { + const entry = this.connections_[uuid]; + if ( ! entry ) return; + if ( entry.object ) return entry.object; + return entry.object = new InternalConnection(entry, this.context); } register_ipc_handler (name, spec) { diff --git a/src/phoenix/src/main_puter.js b/src/phoenix/src/main_puter.js index 01e0339139..d61ef04f88 100644 --- a/src/phoenix/src/main_puter.js +++ b/src/phoenix/src/main_puter.js @@ -53,7 +53,6 @@ window.main_shell = async () => { } }); terminal.on('close', () => { - console.log('Terminal closed; exiting Phoenix...'); puter.exit(); }); diff --git a/src/puter-js/src/modules/UI.js b/src/puter-js/src/modules/UI.js index f8d9a794a3..59a832ccd5 100644 --- a/src/puter-js/src/modules/UI.js +++ b/src/puter-js/src/modules/UI.js @@ -47,6 +47,7 @@ class AppConnection extends EventListener { // Message is from a different AppConnection; ignore it. return; } + // TODO: does this check really make sense? if (event.data.targetAppInstanceID !== this.appInstanceID) { console.error(`AppConnection received message intended for wrong app! appInstanceID=${this.appInstanceID}, target=${event.data.targetAppInstanceID}`); return; @@ -89,7 +90,10 @@ class AppConnection extends EventListener { msg: 'messageToApp', appInstanceID: this.appInstanceID, targetAppInstanceID: this.targetAppInstanceID, - targetAppOrigin: '*', // TODO: Specify this somehow + // Note: there was a TODO comment here about specifying the origin, + // but this should not happen here; the origin should be specified + // on the other side where the expected origin for the app is known. + targetAppOrigin: '*', contents: message, }, this.#puterOrigin); } From bc83e90e3321c2cc49c458f812b184d05d75e831 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 12 Sep 2024 13:49:34 -0400 Subject: [PATCH 0862/2119] tweak: use virtualization-optimized kernel --- src/emulator/image/.gitignore | 1 + src/emulator/image/Dockerfile | 2 +- src/emulator/image/build/.gitignore | 2 -- src/emulator/src/main.js | 4 ++-- 4 files changed, 4 insertions(+), 5 deletions(-) create mode 100644 src/emulator/image/.gitignore delete mode 100644 src/emulator/image/build/.gitignore diff --git a/src/emulator/image/.gitignore b/src/emulator/image/.gitignore new file mode 100644 index 0000000000..378eac25d3 --- /dev/null +++ b/src/emulator/image/.gitignore @@ -0,0 +1 @@ +build diff --git a/src/emulator/image/Dockerfile b/src/emulator/image/Dockerfile index d46fa5974d..e589ab6154 100644 --- a/src/emulator/image/Dockerfile +++ b/src/emulator/image/Dockerfile @@ -2,7 +2,7 @@ FROM i386/alpine:edge RUN apk add --update \ alpine-base bash ncurses shadow curl \ - linux-lts linux-firmware-none linux-headers \ + linux-virt linux-firmware-none linux-headers \ gcc make gcompat musl-dev libx11-dev xinit \ bind-tools \ util-linux \ diff --git a/src/emulator/image/build/.gitignore b/src/emulator/image/build/.gitignore deleted file mode 100644 index d6b7ef32c8..0000000000 --- a/src/emulator/image/build/.gitignore +++ /dev/null @@ -1,2 +0,0 @@ -* -!.gitignore diff --git a/src/emulator/src/main.js b/src/emulator/src/main.js index 1b7d7f9992..b346e86d4b 100644 --- a/src/emulator/src/main.js +++ b/src/emulator/src/main.js @@ -46,10 +46,10 @@ window.onload = async function() }, initrd: { - url: './image/build/boot/initramfs-lts', + url: './image/build/boot/initramfs-virt', }, bzimage: { - url: './image/build/boot/vmlinuz-lts', + url: './image/build/boot/vmlinuz-virt', async: false }, cmdline: 'rw root=/dev/sda init=/sbin/init rootfstype=ext4', From 404fbaa4cbe0b5a7a7b9f54ce864c912067a04fa Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 12 Sep 2024 17:26:38 -0400 Subject: [PATCH 0863/2119] dev: add terminal multiplexing This involves establishing the protocol through which phoenix instances run a command on the emulator. The pty is able to communicate with the terminal in both directions. This commit adds logs to be removed later. There are a few things left that this commit does not address: - handling close of delegate process - handling sigint from phoenix to delegate process - closing the connection to twisp --- src/emulator/src/main.js | 92 +++++++++++++++- src/gui/src/definitions.js | 26 ++++- src/gui/src/services/ExecService.js | 7 +- .../providers/EmuCommandProvider.js | 103 ++++++++++++++++-- src/puter-js/src/modules/UI.js | 24 +++- 5 files changed, 235 insertions(+), 17 deletions(-) diff --git a/src/emulator/src/main.js b/src/emulator/src/main.js index b346e86d4b..55ace20fcc 100644 --- a/src/emulator/src/main.js +++ b/src/emulator/src/main.js @@ -9,6 +9,16 @@ const { DataBuilder, } = require("../../puter-wisp/src/exports"); +const status = { + ready: false, +}; + +const state = { + ready_listeners: [], +}; + +let ptyMgr; + class WispClient { constructor ({ packetStream, @@ -23,8 +33,74 @@ class WispClient { } } +const setup_pty = (ptt, pty) => { + console.log('PTY created', pty); + + // resize + ptt.on('ioctl.set', evt => { + console.log('event?', evt); + pty.resize(evt.windowSize); + }); + ptt.TIOCGWINSZ(); + + // data from PTY + pty.on_payload = data => { + ptt.out.write(data); + } + + // data to PTY + (async () => { + // for (;;) { + // const buff = await ptt.in.read(); + // if ( buff === undefined ) continue; + // console.log('this is what ptt in gave', buff); + // pty.send(buff); + // } + const stream = ptt.readableStream; + for await ( const chunk of stream ) { + if ( chunk === undefined ) { + console.error('huh, missing chunk', chunk); + continue; + } + console.log('sending to pty', chunk); + pty.send(chunk); + } + })() +} + + puter.ui.on('connection', event => { + const { conn, accept, reject } = event; + if ( ! status.ready ) { + console.log('status not ready, adding listener'); + state.ready_listeners.push(() => { + console.log('a listener was called'); + conn.postMessage({ + $: 'status', + ...status, + }); + }); + } + accept({ + version: '1.0.0', + status, + }); console.log('emulator got connection event', event); + + const pty_on_first_message = message => { + conn.off('message', pty_on_first_message); + console.log('[!!] message from connection', message); + const pty = ptyMgr.getPTY({ + command: '/bin/bash' + }); + console.log('setting up ptt with...', conn); + const ptt = new XDocumentPTT(conn, { + disableReader: true, + }); + ptt.termios.echo = false; + setup_pty(ptt, pty); + } + conn.on('message', pty_on_first_message); }); window.onload = async function() @@ -83,12 +159,14 @@ window.onload = async function() const virtioStream = NewVirtioFrameStream(byteStream); const wispStream = NewWispPacketStream(virtioStream); + /* const shell = puter.ui.parentApp(); const ptt = new XDocumentPTT(shell, { disableReader: true, }) ptt.termios.echo = false; + */ class PTYManager { static STATE_INIT = { @@ -110,6 +188,13 @@ window.onload = async function() } }, on: function () { + console.log('ready.on called') + status.ready = true; + for ( const listener of state.ready_listeners ) { + console.log('calling listener'); + listener(); + } + return; const pty = this.getPTY(); console.log('PTY created', pty); @@ -176,14 +261,14 @@ window.onload = async function() } } - getPTY () { + getPTY ({ command }) { const streamId = ++this.streamId; const data = new DataBuilder({ leb: true }) .uint8(0x01) .uint32(streamId) .uint8(0x03) .uint16(10) - .utf8('/bin/bash') + .utf8(command) // .utf8('/usr/bin/htop') .build(); const packet = new WispPacket( @@ -235,7 +320,7 @@ window.onload = async function() } } - const ptyMgr = new PTYManager({ + ptyMgr = new PTYManager({ client: new WispClient({ packetStream: wispStream, sendFn: packet => { @@ -249,4 +334,5 @@ window.onload = async function() }) }); ptyMgr.init(); + } diff --git a/src/gui/src/definitions.js b/src/gui/src/definitions.js index 22c1496686..f2e7f8f58a 100644 --- a/src/gui/src/definitions.js +++ b/src/gui/src/definitions.js @@ -18,6 +18,7 @@ */ import { concepts, AdvancedBase } from "@heyputer/putility"; +import TeePromise from "./util/TeePromise.js"; export class Service extends concepts.Service { // TODO: Service todo items @@ -153,13 +154,36 @@ export class PortalProcess extends Process { }, '*'); } - handle_connection (connection, args) { + async handle_connection (connection, args) { const target = this.references.iframe.contentWindow; + const connection_response = new TeePromise(); + window.addEventListener('message', (evt) => { + if ( evt.source !== target ) return; + // Using '$' instead of 'msg' to avoid handling by IPC.js + // (following type-tagged message convention) + if ( evt.data.$ !== 'connection-resp' ) return; + if ( evt.data.connection !== connection.uuid ) return; + if ( evt.data.accept ) { + connection_response.resolve(evt.data.value); + } else { + connection_response.reject(evt.data.value + ?? new Error('Connection rejected')); + } + }); target.postMessage({ msg: 'connection', appInstanceID: connection.uuid, args, }); + const outcome = await Promise.race([ + connection_response, + new Promise((resolve, reject) => { + setTimeout(() => { + reject(new Error('Connection timeout')); + }, 5000); + }) + ]); + return outcome; } }; export class PseudoProcess extends Process { diff --git a/src/gui/src/services/ExecService.js b/src/gui/src/services/ExecService.js index 386b6cac57..5fcad6edaa 100644 --- a/src/gui/src/services/ExecService.js +++ b/src/gui/src/services/ExecService.js @@ -108,6 +108,10 @@ export class ExecService extends Service { const options = svc_process.select_by_name(app_name); const process = options[0]; + if ( ! process ) { + throw new Error(`No process found: ${app_name}`); + } + const svc_ipc = this.services.get('ipc'); const connection = svc_ipc.add_connection({ source: caller_process.uuid, @@ -116,9 +120,10 @@ export class ExecService extends Service { const response = await process.handle_connection( connection.backward, args); - + return { appInstanceID: connection.forward.uuid, + usesSDK: true, response, }; } diff --git a/src/phoenix/src/puter-shell/providers/EmuCommandProvider.js b/src/phoenix/src/puter-shell/providers/EmuCommandProvider.js index 1af4d9d6ea..08a3ef6761 100644 --- a/src/phoenix/src/puter-shell/providers/EmuCommandProvider.js +++ b/src/phoenix/src/puter-shell/providers/EmuCommandProvider.js @@ -1,21 +1,19 @@ +import { TeePromise } from "@heyputer/putility/src/libs/promise"; import { Exit } from "../coreutils/coreutil_lib/exit"; export class EmuCommandProvider { - static AVAILABLE = [ - 'bash', - 'htop', - ]; + static AVAILABLE = { + 'bash': '/bin/bash', + 'htop': '/usr/bin/htop', + }; static EMU_APP_NAME = 'test-emu'; constructor () { this.available = this.constructor.AVAILABLE; - this.emulator = null; } - async aquire_emulator () { - if ( this.emulator ) return this.emulator; - + async aquire_emulator ({ ctx }) { // FUTURE: when we have a way to query instances // without exposing the real instance id /* @@ -27,20 +25,103 @@ export class EmuCommandProvider { */ const conn = await puter.ui.connectToInstance(this.constructor.EMU_APP_NAME); - return this.emulator = conn; + const p_ready = new TeePromise(); + conn.on('message', message => { + if ( message.$ === 'status' ) { + p_ready.resolve(); + } + console.log('[!!] message from the emulator', message); + }); + if ( conn.response.status.ready ) { + p_ready.resolve(); + } + console.log('awaiting emulator ready'); + ctx.externs.out.write('Waiting for emulator...\n'); + await p_ready; + console.log('emulator ready'); + return conn; } async lookup (id, { ctx }) { - if ( ! this.available.includes(id) ) { + if ( ! (id in this.available) ) { return; } - const emu = await this.aquire_emulator(); + const emu = await this.aquire_emulator({ ctx }); if ( ! emu ) { ctx.externs.out.write('No emulator available.\n'); return new Exit(1); } ctx.externs.out.write(`Launching ${id} in emulator ${emu.appInstanceID}\n`); + + return { + name: id, + path: 'Emulator', + execute: this.execute.bind(this, { id, emu, ctx }), + } + } + + async execute ({ id, emu }, ctx) { + // TODO: DRY: most copied from PuterAppCommandProvider + const resize_listener = evt => { + emu.postMessage({ + $: 'ioctl.set', + windowSize: { + rows: evt.detail.rows, + cols: evt.detail.cols, + } + }); + }; + ctx.shell.addEventListener('signal.window-resize', resize_listener); + + // TODO: handle CLOSE -> emu needs to close connection first + const app_close_promise = new TeePromise(); + const sigint_promise = new TeePromise(); + + const decoder = new TextDecoder(); + emu.on('message', message => { + if (message.$ === 'stdout') { + ctx.externs.out.write(decoder.decode(message.data)); + } + if (message.$ === 'chtermios') { + if ( message.termios.echo !== undefined ) { + if ( message.termios.echo ) { + ctx.externs.echo.on(); + } else { + ctx.externs.echo.off(); + } + } + } + }); + + // Repeatedly copy data from stdin to the child, while it's running. + // DRY: Initially copied from PathCommandProvider + let data, done; + const next_data = async () => { + console.log('!~!!!!!'); + ({ value: data, done } = await Promise.race([ + app_close_promise, sigint_promise, ctx.externs.in_.read(), + ])); + console.log('next_data', data, done); + if (data) { + console.log('sending stdin data'); + emu.postMessage({ + $: 'stdin', + data: data, + }); + if (!done) setTimeout(next_data, 0); + } + }; + setTimeout(next_data, 0); + + emu.postMessage({ + $: 'exec', + command: this.available[id], + args: [], + }); + + const never_resolve = new TeePromise(); + await never_resolve; } } diff --git a/src/puter-js/src/modules/UI.js b/src/puter-js/src/modules/UI.js index 59a832ccd5..6175b52da0 100644 --- a/src/puter-js/src/modules/UI.js +++ b/src/puter-js/src/modules/UI.js @@ -25,6 +25,11 @@ class AppConnection extends EventListener { values.appInstanceID, values.usesSDK ); + + // When a connection is established the app is able to + // provide some additional information about itself + connection.response = values.response; + return connection; } @@ -466,12 +471,29 @@ class UI extends EventListener { this.#lastBroadcastValue.set(name, data); } else if ( e.data.msg === 'connection' ) { + e.data.usesSDK = true; // we can safely assume this const conn = AppConnection.from(e.data, { appInstanceID: this.appInstanceID, messageTarget: window.parent, }); + const accept = value => { + this.messageTarget?.postMessage({ + $: 'connection-resp', + connection: e.data.appInstanceID, + accept: true, + value, + }); + }; + const reject = value => { + this.messageTarget?.postMessage({ + $: 'connection-resp', + connection: e.data.appInstanceID, + accept: false, + value, + }); + }; this.emit('connection', { - conn + conn, accept, reject, }); } }); From 4589ed95be1d9d8d5b1c29dab21765b607debfe6 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 12 Sep 2024 19:04:21 -0400 Subject: [PATCH 0864/2119] dev: handle pty close Return to phoenix shell when a pty stream is closed by twisp. Pipes in phoenix with commands from the emulator do not appear to be working properly, but something in there is working. --- src/emulator/src/main.js | 11 ++++++++++- .../src/puter-shell/providers/EmuCommandProvider.js | 7 +++++-- src/puter-wisp/src/exports.js | 12 ++++++++++++ 3 files changed, 27 insertions(+), 3 deletions(-) diff --git a/src/emulator/src/main.js b/src/emulator/src/main.js index 55ace20fcc..67f2daf555 100644 --- a/src/emulator/src/main.js +++ b/src/emulator/src/main.js @@ -91,8 +91,13 @@ puter.ui.on('connection', event => { conn.off('message', pty_on_first_message); console.log('[!!] message from connection', message); const pty = ptyMgr.getPTY({ - command: '/bin/bash' + command: message.command, }); + pty.on_close = () => { + conn.postMessage({ + $: 'pty.close', + }); + } console.log('setting up ptt with...', conn); const ptt = new XDocumentPTT(conn, { disableReader: true, @@ -185,6 +190,10 @@ window.onload = async function() console.log('stream id?', packet.streamId); const pty = this.stream_listeners_[packet.streamId]; pty.on_payload(packet.payload); + }, + [WispPacket.CLOSE.id]: function ({ packet }) { + const pty = this.stream_listeners_[packet.streamId]; + pty.on_close(); } }, on: function () { diff --git a/src/phoenix/src/puter-shell/providers/EmuCommandProvider.js b/src/phoenix/src/puter-shell/providers/EmuCommandProvider.js index 08a3ef6761..4fbdade840 100644 --- a/src/phoenix/src/puter-shell/providers/EmuCommandProvider.js +++ b/src/phoenix/src/puter-shell/providers/EmuCommandProvider.js @@ -5,6 +5,7 @@ export class EmuCommandProvider { static AVAILABLE = { 'bash': '/bin/bash', 'htop': '/usr/bin/htop', + 'emu-sort': '/usr/bin/sort', }; static EMU_APP_NAME = 'test-emu'; @@ -93,6 +94,9 @@ export class EmuCommandProvider { } } } + if (message.$ === 'pty.close') { + app_close_promise.resolve(); + } }); // Repeatedly copy data from stdin to the child, while it's running. @@ -121,7 +125,6 @@ export class EmuCommandProvider { args: [], }); - const never_resolve = new TeePromise(); - await never_resolve; + await app_close_promise; } } diff --git a/src/puter-wisp/src/exports.js b/src/puter-wisp/src/exports.js index 88b5028324..ae39724e1c 100644 --- a/src/puter-wisp/src/exports.js +++ b/src/puter-wisp/src/exports.js @@ -223,6 +223,18 @@ const wisp_types = [ } } }, + { + id: 4, + label: 'CLOSE', + describe: ({ attributes }) => { + return `reason: ${attributes.code}`; + }, + getAttributes ({ payload }) { + return { + code: payload[0], + } + } + }, { // TODO: extension types should not be hardcoded here id: 0xf0, From 25817bf6a2185426890e52108ccebc579b377fab Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 16 Sep 2024 16:22:25 -0400 Subject: [PATCH 0865/2119] dev: add puter-linux app to db migrations --- .../database/SqliteDatabaseAccessService.js | 35 +++++++++++-------- .../sqlite_setup/0027_emulator-app.dbmig.js | 23 ++++++++++++ src/gui/src/services/ExecService.js | 2 +- src/gui/src/services/ProcessService.js | 2 +- .../providers/EmuCommandProvider.js | 2 +- 5 files changed, 46 insertions(+), 18 deletions(-) create mode 100644 src/backend/src/services/database/sqlite_setup/0027_emulator-app.dbmig.js diff --git a/src/backend/src/services/database/SqliteDatabaseAccessService.js b/src/backend/src/services/database/SqliteDatabaseAccessService.js index 5458cbf370..2c6470b4bc 100644 --- a/src/backend/src/services/database/SqliteDatabaseAccessService.js +++ b/src/backend/src/services/database/SqliteDatabaseAccessService.js @@ -44,21 +44,6 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { this.db = new Database(this.config.path); - // Database upgrade logic - const HIGHEST_VERSION = 24; - const TARGET_VERSION = (() => { - const args = Context.get('args'); - if ( args['database-target-version'] ) { - return parseInt(args['database-target-version']); - } - return HIGHEST_VERSION; - })(); - - const [{ user_version }] = do_setup - ? [{ user_version: -1 }] - : await this._read('PRAGMA user_version'); - this.log.info('database version: ' + user_version); - const upgrade_files = []; const available_migrations = [ @@ -138,8 +123,28 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { [23, [ '0026_user-groups.dbmig.js', ]], + [24, [ + '0027_emulator-app.dbmig.js', + ]], ]; + // Database upgrade logic + const HIGHEST_VERSION = + available_migrations[available_migrations.length - 1][0] + 1; + const TARGET_VERSION = (() => { + const args = Context.get('args'); + if ( args['database-target-version'] ) { + return parseInt(args['database-target-version']); + } + return HIGHEST_VERSION; + })(); + + const [{ user_version }] = do_setup + ? [{ user_version: -1 }] + : await this._read('PRAGMA user_version'); + this.log.info('database version: ' + user_version); + + for ( const [v_lt_or_eq, files] of available_migrations ) { if ( v_lt_or_eq + 1 >= TARGET_VERSION && TARGET_VERSION !== HIGHEST_VERSION ) { this.log.noticeme(`Early exit: target version set to ${TARGET_VERSION}`); diff --git a/src/backend/src/services/database/sqlite_setup/0027_emulator-app.dbmig.js b/src/backend/src/services/database/sqlite_setup/0027_emulator-app.dbmig.js new file mode 100644 index 0000000000..0e3b5ad13f --- /dev/null +++ b/src/backend/src/services/database/sqlite_setup/0027_emulator-app.dbmig.js @@ -0,0 +1,23 @@ +const insert = async (tbl, subject) => { + const keys = Object.keys(subject); + + await write( + 'INSERT INTO `'+ tbl +'` ' + + '(' + keys.map(key => key).join(', ') + ') ' + + 'VALUES (' + keys.map(() => '?').join(', ') + ')', + keys.map(key => subject[key]) + ); +} + +await insert('apps', { + uid: 'app-fbbdb72b-ad08-4cb4-86a1-de0f27cf2e1e', + owner_user_id: 1, + name: 'puter-linux', + index_url: 'https://builtins.namespaces.puter.com/emulator', + title: 'Puter Linux', + description: 'Linux emulator for Puter', + approved_for_listing: 1, + approved_for_opening_items: 1, + approved_for_incentive_program: 0, + timestamp: '2020-01-01 00:00:00', +}); diff --git a/src/gui/src/services/ExecService.js b/src/gui/src/services/ExecService.js index 5fcad6edaa..ed6813a791 100644 --- a/src/gui/src/services/ExecService.js +++ b/src/gui/src/services/ExecService.js @@ -100,7 +100,7 @@ export class ExecService extends Service { if ( caller_process.name !== 'phoenix' ) { throw new Error('Connection not allowed.'); } - if ( app_name !== 'test-emu' ) { + if ( app_name !== 'puter-linux' ) { throw new Error('Connection not allowed.'); } diff --git a/src/gui/src/services/ProcessService.js b/src/gui/src/services/ProcessService.js index d41404ee3c..a6ac38a69d 100644 --- a/src/gui/src/services/ProcessService.js +++ b/src/gui/src/services/ProcessService.js @@ -23,7 +23,7 @@ const NULL_UUID = '00000000-0000-0000-0000-000000000000'; export class ProcessService extends Service { static INITRC = [ - 'test-emu' + 'puter-linux' ]; async _init () { diff --git a/src/phoenix/src/puter-shell/providers/EmuCommandProvider.js b/src/phoenix/src/puter-shell/providers/EmuCommandProvider.js index 4fbdade840..81f90cea31 100644 --- a/src/phoenix/src/puter-shell/providers/EmuCommandProvider.js +++ b/src/phoenix/src/puter-shell/providers/EmuCommandProvider.js @@ -8,7 +8,7 @@ export class EmuCommandProvider { 'emu-sort': '/usr/bin/sort', }; - static EMU_APP_NAME = 'test-emu'; + static EMU_APP_NAME = 'puter-linux'; constructor () { this.available = this.constructor.AVAILABLE; From 8aed3d9454f657c64225cbab202da06a103402ba Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Mon, 16 Sep 2024 17:45:14 -0400 Subject: [PATCH 0866/2119] dev: prep for network build --- src/emulator/src/main.js | 23 ++++++++++++++++++- .../providers/EmuCommandProvider.js | 13 +++++++++++ 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/src/emulator/src/main.js b/src/emulator/src/main.js index 67f2daf555..8a04929947 100644 --- a/src/emulator/src/main.js +++ b/src/emulator/src/main.js @@ -110,6 +110,23 @@ puter.ui.on('connection', event => { window.onload = async function() { + let emu_config; try { + emu_config = await puter.fs.read('config.json'); + } catch (e) {} + + if ( ! emu_config ) { + await puter.fs.write('config.json', JSON.stringify({})); + emu_config = {}; + } + + if ( emu_config instanceof Blob ) { + emu_config = await emu_config.text(); + } + + if ( typeof emu_config === 'string' ) { + emu_config = JSON.parse(emu_config); + } + const resp = await fetch( './image/build/rootfs.bin' ); @@ -152,10 +169,14 @@ window.onload = async function() // bzimage_initrd_from_filesystem: true, autostart: true, - network_relay_url: "wisp://127.0.0.1:3000", + network_relay_url: emu_config.network_relay ?? "wisp://127.0.0.1:3000", virtio_console: true, }); + emulator.add_listener('download-error', function(e) { + status.missing_files || (status.missing_files = []); + status.missing_files.push(e.file_name); + }); const decoder = new TextDecoder(); const byteStream = NewCallbackByteStream(); diff --git a/src/phoenix/src/puter-shell/providers/EmuCommandProvider.js b/src/phoenix/src/puter-shell/providers/EmuCommandProvider.js index 81f90cea31..3c2257c2a6 100644 --- a/src/phoenix/src/puter-shell/providers/EmuCommandProvider.js +++ b/src/phoenix/src/puter-shell/providers/EmuCommandProvider.js @@ -36,6 +36,19 @@ export class EmuCommandProvider { if ( conn.response.status.ready ) { p_ready.resolve(); } + console.log('status from emu', conn.response); + if ( conn.response.status.missing_files ) { + const pfx = '\x1B[31;1m┃\x1B[0m '; + ctx.externs.out.write('\n'); + ctx.externs.out.write('\x1B[31;1m┃ Emulator is missing files:\x1B[0m\n'); + for (const file of conn.response.status.missing_files) { + ctx.externs.out.write(pfx+`- ${file}\n`); + } + ctx.externs.out.write(pfx+'\n'); + ctx.externs.out.write(pfx+'\x1B[33;1mDid you run `./tools/build_v86.sh`?\x1B[0m\n'); + ctx.externs.out.write('\n'); + return; + } console.log('awaiting emulator ready'); ctx.externs.out.write('Waiting for emulator...\n'); await p_ready; From 48873b6d239faf9346a21f07e406ea041239890b Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 17 Sep 2024 17:15:50 -0400 Subject: [PATCH 0867/2119] git: add epoxy-tls submodule --- .gitmodules | 3 +++ submodules/epoxy-tls | 1 + 2 files changed, 4 insertions(+) create mode 160000 submodules/epoxy-tls diff --git a/.gitmodules b/.gitmodules index c2dfcc1d99..0000f1d57a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -4,3 +4,6 @@ [submodule "submodules/twisp"] path = submodules/twisp url = git@github.com:MercuryWorkshop/twisp.git +[submodule "submodules/epoxy-tls"] + path = submodules/epoxy-tls + url = git@github.com:MercuryWorkshop/epoxy-tls.git diff --git a/submodules/epoxy-tls b/submodules/epoxy-tls new file mode 160000 index 0000000000..7fdacb2623 --- /dev/null +++ b/submodules/epoxy-tls @@ -0,0 +1 @@ +Subproject commit 7fdacb26237a0a69faacd1c08d746584fbd98f94 From e3431cd7f54c6235379be3dc584299399a100189 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 18 Sep 2024 14:48:55 -0400 Subject: [PATCH 0868/2119] dev: add build script for relay --- tools/build_relay.sh | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) create mode 100644 tools/build_relay.sh diff --git a/tools/build_relay.sh b/tools/build_relay.sh new file mode 100644 index 0000000000..1990efcc46 --- /dev/null +++ b/tools/build_relay.sh @@ -0,0 +1,17 @@ + +#!/bin/bash + +start_dir=$(pwd) +cleanup() { + cd "$start_dir" +} +trap cleanup ERR EXIT +set -e + +echo -e "\x1B[36;1m<<< Building epoxy-tls >>>\x1B[0m" + +cd submodules/epoxy-tls +rustup install nightly +rustup override set nightly +cargo b -r +cd - From f2acd83b72c388939233fd7145f2dcf78d8ad39e Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 18 Sep 2024 16:19:48 -0400 Subject: [PATCH 0869/2119] fix: upsert subdomain check to insert only --- src/backend/src/om/entitystorage/SubdomainES.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/backend/src/om/entitystorage/SubdomainES.js b/src/backend/src/om/entitystorage/SubdomainES.js index 2932db5ae9..27a543e0ca 100644 --- a/src/backend/src/om/entitystorage/SubdomainES.js +++ b/src/backend/src/om/entitystorage/SubdomainES.js @@ -39,7 +39,9 @@ class SubdomainES extends BaseES { } }, async upsert (entity, extra) { - await this._check_max_subdomains(); + if ( ! extra.old_entity ) { + await this._check_max_subdomains(); + } return await this.upstream.upsert(entity, extra); }, From 04568937890315450854ad106ce3fbaf7fbf62c3 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 18 Sep 2024 16:20:11 -0400 Subject: [PATCH 0870/2119] dev: add emulator prod deployment --- src/emulator/src/main.js | 10 +++++++--- src/emulator/webpack.config.js | 4 ++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/src/emulator/src/main.js b/src/emulator/src/main.js index 8a04929947..6966b9e2fa 100644 --- a/src/emulator/src/main.js +++ b/src/emulator/src/main.js @@ -1,5 +1,9 @@ "use strict"; +console.log(`emulator running in mode: ${MODE}`) + +const PATH_V86 = MODE === 'dev' ? '/vendor/v86' : './vendor/v86'; + const { XDocumentPTT } = require("../../phoenix/src/pty/XDocumentPTT"); const { NewWispPacketStream, @@ -132,15 +136,15 @@ window.onload = async function() ); const arrayBuffer = await resp.arrayBuffer(); var emulator = window.emulator = new V86({ - wasm_path: "/vendor/v86/v86.wasm", + wasm_path: PATH_V86 + "/v86.wasm", memory_size: 512 * 1024 * 1024, vga_memory_size: 2 * 1024 * 1024, screen_container: document.getElementById("screen_container"), bios: { - url: "/vendor/v86/bios/seabios.bin", + url: PATH_V86 + "/bios/seabios.bin", }, vga_bios: { - url: "/vendor/v86/bios/vgabios.bin", + url: PATH_V86 + "/bios/vgabios.bin", }, initrd: { diff --git a/src/emulator/webpack.config.js b/src/emulator/webpack.config.js index 6983e59a3a..6dee896116 100644 --- a/src/emulator/webpack.config.js +++ b/src/emulator/webpack.config.js @@ -1,4 +1,5 @@ const HtmlWebpackPlugin = require('html-webpack-plugin'); +const DefinePlugin = require('webpack').DefinePlugin; module.exports = { entry: [ @@ -8,5 +9,8 @@ module.exports = { new HtmlWebpackPlugin({ template: 'assets/template.html' }), + new DefinePlugin({ + MODE: JSON.stringify(process.env.MODE ?? 'dev') + }), ] }; From 439653458eab38e622cf215ae96b6af34d1db7d4 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 18 Sep 2024 16:22:26 -0400 Subject: [PATCH 0871/2119] fix: quick patch to avoid columnify error --- src/phoenix/src/puter-shell/coreutils/ls.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/phoenix/src/puter-shell/coreutils/ls.js b/src/phoenix/src/puter-shell/coreutils/ls.js index 351d190959..4d216f5ba4 100644 --- a/src/phoenix/src/puter-shell/coreutils/ls.js +++ b/src/phoenix/src/puter-shell/coreutils/ls.js @@ -235,7 +235,7 @@ export default { ...(filesystem.capabilities['readdir.www'] ? ['www'] : []), 'size', time_properties[time], ], - maxLineWidth: ctx.env.COLS, + maxLineWidth: ctx.env.COLS ?? 80, config: { // json: { // maxWidth: 20, From afc0ac8548bccc216bd8734dab28fdfd4f7df0a9 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 18 Sep 2024 17:01:02 -0400 Subject: [PATCH 0872/2119] dev: attempt to fix process select issue --- src/gui/src/services/ProcessService.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/gui/src/services/ProcessService.js b/src/gui/src/services/ProcessService.js index a6ac38a69d..a963e6e87e 100644 --- a/src/gui/src/services/ProcessService.js +++ b/src/gui/src/services/ProcessService.js @@ -67,8 +67,11 @@ export class ProcessService extends Service { } select_by_name (name) { + // TODO: figure out why 'this.processes' doesn't work here + const processes = Array.from(svc_process.processes_map.values()) + const list = []; - for ( const process of this.processes ) { + for ( const process of processes ) { if ( process.name === name ) { list.push(process); } From f4dd195245acfc7c79aced4ff95cd7b19c86c870 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 18 Sep 2024 17:04:45 -0400 Subject: [PATCH 0873/2119] dev: fix previous commit --- src/gui/src/services/ProcessService.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/services/ProcessService.js b/src/gui/src/services/ProcessService.js index a963e6e87e..8129fc8534 100644 --- a/src/gui/src/services/ProcessService.js +++ b/src/gui/src/services/ProcessService.js @@ -68,7 +68,7 @@ export class ProcessService extends Service { select_by_name (name) { // TODO: figure out why 'this.processes' doesn't work here - const processes = Array.from(svc_process.processes_map.values()) + const processes = Array.from(this.processes_map.values()) const list = []; for ( const process of processes ) { From cb324cc125285b5cd6a6b0cebf444a6cd873ded9 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 18 Sep 2024 20:55:00 -0400 Subject: [PATCH 0874/2119] fix: error in process.handle_connection --- src/gui/src/definitions.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/definitions.js b/src/gui/src/definitions.js index f2e7f8f58a..e14fcba245 100644 --- a/src/gui/src/definitions.js +++ b/src/gui/src/definitions.js @@ -174,7 +174,7 @@ export class PortalProcess extends Process { msg: 'connection', appInstanceID: connection.uuid, args, - }); + }, '*'); const outcome = await Promise.race([ connection_response, new Promise((resolve, reject) => { From 4311b482fd629c6d1f65956eb711c8e890453179 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 18 Sep 2024 21:02:51 -0400 Subject: [PATCH 0875/2119] fix: second half of connectToInstance --- src/puter-js/src/modules/UI.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/puter-js/src/modules/UI.js b/src/puter-js/src/modules/UI.js index 6175b52da0..5b9627f710 100644 --- a/src/puter-js/src/modules/UI.js +++ b/src/puter-js/src/modules/UI.js @@ -482,7 +482,7 @@ class UI extends EventListener { connection: e.data.appInstanceID, accept: true, value, - }); + }, '*'); }; const reject = value => { this.messageTarget?.postMessage({ @@ -490,7 +490,7 @@ class UI extends EventListener { connection: e.data.appInstanceID, accept: false, value, - }); + }, '*'); }; this.emit('connection', { conn, accept, reject, From bd918395517da90dc057ab13f6cacba3612dfb81 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 19 Sep 2024 17:41:37 -0700 Subject: [PATCH 0876/2119] Don't allow background processes to change the browser's URL --- src/gui/src/UI/UIWindow.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/UI/UIWindow.js b/src/gui/src/UI/UIWindow.js index f9069c717e..6de29b42bd 100644 --- a/src/gui/src/UI/UIWindow.js +++ b/src/gui/src/UI/UIWindow.js @@ -218,7 +218,7 @@ async function UIWindow(options) { data-sort_by ="${options.sort_by ?? 'name'}" data-sort_order ="${options.sort_order ?? 'asc'}" data-multiselectable = "${options.selectable_body}" - data-update_window_url = "${options.update_window_url}" + data-update_window_url = "${options.update_window_url && options.is_visible}" data-user_set_url_params = "${html_encode(user_set_url_params)}" data-initial_zindex = "${zindex}" style=" z-index: ${zindex}; From 31e2773743c336630c917e893b0148441f5fc515 Mon Sep 17 00:00:00 2001 From: Ruthwik Chikoti Date: Sat, 21 Sep 2024 18:21:27 +0530 Subject: [PATCH 0877/2119] feat: translate README.md to Dutch --- doc/i18n/README.nl.md | 131 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 131 insertions(+) create mode 100644 doc/i18n/README.nl.md diff --git a/doc/i18n/README.nl.md b/doc/i18n/README.nl.md new file mode 100644 index 0000000000..74d48278a2 --- /dev/null +++ b/doc/i18n/README.nl.md @@ -0,0 +1,131 @@ +

Puter.com, De Persoonlijke Cloud Computer: Al je bestanden, apps en games op één plek, overal en altijd toegankelijk.

+ +

Het Internet OS! Gratis, Open-Source en Zelf te Hosten.

+ +

+ GitHub repo grootte GitHub Release GitHub Licentie +

+

+ « LIVE DEMO » +
+
+ Puter.com + · + SDK + · + Discord + · + YouTube + · + Reddit + · + X (Twitter) + · + Bug Bounty +

+ +

screenshot

+ +
+ +## Puter + +Puter is een geavanceerd, open-source internetbesturingssysteem ontworpen om functierijk, uitzonderlijk snel en zeer uitbreidbaar te zijn. Puter kan worden gebruikt als: + +- Een privacy-gerichte persoonlijke cloud om al je bestanden, apps en games op één veilige plek te bewaren, overal en altijd toegankelijk. +- Een platform voor het bouwen en publiceren van websites, web-apps en games. +- Een alternatief voor Dropbox, Google Drive, OneDrive, etc. met een frisse interface en krachtige functies. +- Een externe desktopomgeving voor servers en werkstations. +- Een vriendelijk, open-source project en gemeenschap om te leren over webontwikkeling, cloud computing, gedistribueerde systemen en veel meer! + +
+ +## Aan de slag + + +### 💻 Lokale Ontwikkeling + +```bash +git clone https://github.com/HeyPuter/puter +cd puter +npm install +npm start +``` + +Dit zal Puter starten op http://puter.localhost:4100 (of de eerstvolgende beschikbare poort). + +
+ +### 🐳 Docker + + +```bash +mkdir puter && cd puter && mkdir -p puter/config puter/data && sudo chown -R 1000:1000 puter && docker run --rm -p 4100:4100 -v `pwd`/puter/config:/etc/puter -v `pwd`/puter/data:/var/puter ghcr.io/heyputer/puter +``` + +
+ + +### 🐙 Docker Compose + + +#### Linux/macOS +```bash +mkdir -p puter/config puter/data +sudo chown -R 1000:1000 puter +wget https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml +docker compose up +``` +
+ +#### Windows + + +```powershell +mkdir -p puter +cd puter +New-Item -Path "puter\config" -ItemType Directory -Force +New-Item -Path "puter\data" -ItemType Directory -Force +Invoke-WebRequest -Uri "https://raw.githubusercontent.com/HeyPuter/puter/main/docker-compose.yml" -OutFile "docker-compose.yml" +docker compose up +``` +
+ +### ☁️ Puter.com + +Puter is beschikbaar als een gehoste service op [**puter.com**](https://puter.com). + +
+ +## Systeemvereisten + +- **Besturingssystemen:** Linux, macOS, Windows +- **RAM:** 2GB minimum (4GB aanbevolen) +- **Schijfruimte:** 1GB vrije ruimte +- **Node.js:** Versie 16+ (Versie 22+ aanbevolen) +- **npm:** Laatste stabiele versie + +
+ +## Ondersteuning + +Verbind met de onderhouders en de gemeenschap via deze kanalen: + +- Bug rapport of functieverzoek? [Open een issue](https://github.com/HeyPuter/puter/issues/new/choose). +- Discord: [discord.com/invite/PQcx7Teh8u](https://discord.com/invite/PQcx7Teh8u) +- X (Twitter): [x.com/HeyPuter](https://x.com/HeyPuter) +- Reddit: [reddit.com/r/puter/](https://www.reddit.com/r/puter/) +- Mastodon: [mastodon.social/@puter](https://mastodon.social/@puter) +- Beveiligingsproblemen? [security@puter.com](mailto:security@puter.com) +- E-mail onderhouders op [hi@puter.com](mailto:hi@puter.com) + +We helpen je graag met al je vragen. Aarzel niet om te vragen! + +
+ + +## Licentie + +Deze repository, inclusief alle inhoud, subprojecten, modules en componenten, is gelicentieerd onder [AGPL-3.0](https://github.com/HeyPuter/puter/blob/main/LICENSE.txt) tenzij expliciet anders vermeld. Bibliotheken van derden die in deze repository zijn opgenomen, kunnen onderworpen zijn aan hun eigen licenties. + +
\ No newline at end of file From 07d3592d885d9ea0c28501acd5895d7b8ce093bd Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sat, 21 Sep 2024 15:39:19 -0400 Subject: [PATCH 0878/2119] tweak: don't auto-start puter-linux for now --- src/gui/src/services/ProcessService.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/services/ProcessService.js b/src/gui/src/services/ProcessService.js index 8129fc8534..a4b7a65876 100644 --- a/src/gui/src/services/ProcessService.js +++ b/src/gui/src/services/ProcessService.js @@ -23,7 +23,7 @@ const NULL_UUID = '00000000-0000-0000-0000-000000000000'; export class ProcessService extends Service { static INITRC = [ - 'puter-linux' + // 'puter-linux' ]; async _init () { From 3ce8da37eb2b3f8e5692784789b4c6739681efb0 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Sun, 22 Sep 2024 12:40:38 -0700 Subject: [PATCH 0879/2119] close #772 --- src/dev-center/css/style.css | 18 ++++++++++++++++++ src/dev-center/index.html | 4 ++-- src/dev-center/js/dev-center.js | 32 ++++++++++++++++++++++++-------- 3 files changed, 44 insertions(+), 10 deletions(-) diff --git a/src/dev-center/css/style.css b/src/dev-center/css/style.css index a63c149606..51a88904af 100644 --- a/src/dev-center/css/style.css +++ b/src/dev-center/css/style.css @@ -36,6 +36,16 @@ body{ align-items: center; flex: 1; } + +h1 .app-count{ + font-size: 20px; + color: #6d767d; + font-weight: 400; + margin-left: 10px; + background-color: #EEE; + padding: 2px 10px; + border-radius: 3px; +} /* ------------------------------------ Button ------------------------------------*/ @@ -451,6 +461,14 @@ label { background-color: #3273dc; } +.sidebar-nav > li .app-count{ + font-size: 14px; + color: #f6f6f6; + font-weight: 400; + margin-left: 10px; + float: right; +} + .sidebar hr { margin-top: 20px; margin-bottom: 20px; diff --git a/src/dev-center/index.html b/src/dev-center/index.html index 4046b446ef..9f104d14d0 100644 --- a/src/dev-center/index.html +++ b/src/dev-center/index.html @@ -51,7 +51,7 @@
- - `; +
`; }, init: ($el_window) => { $el_window.find('.change-ui-colors').on('click', function (e) { diff --git a/src/gui/src/UI/Settings/UITabSecurity.js b/src/gui/src/UI/Settings/UITabSecurity.js index 9ddda082ca..5961444efa 100644 --- a/src/gui/src/UI/Settings/UITabSecurity.js +++ b/src/gui/src/UI/Settings/UITabSecurity.js @@ -21,10 +21,8 @@ import Button from "../Components/Button.js"; import Flexer from "../Components/Flexer.js"; import JustHTML from "../Components/JustHTML.js"; import PasswordEntry from "../Components/PasswordEntry.js"; -import UIAlert from "../UIAlert.js"; import UIComponentWindow from "../UIComponentWindow.js"; import UIWindow2FASetup from "../UIWindow2FASetup.js"; -import UIWindowQR from "../UIWindowQR.js"; export default { id: 'security', @@ -160,7 +158,6 @@ export default { is_resizable: false, body_css: { width: 'initial', - height: '100%', 'background-color': 'rgb(245 247 249)', 'backdrop-filter': 'blur(3px)', padding: '20px', diff --git a/src/gui/src/css/style.css b/src/gui/src/css/style.css index ccc414a7cb..163fdf118e 100644 --- a/src/gui/src/css/style.css +++ b/src/gui/src/css/style.css @@ -3899,9 +3899,9 @@ fieldset[name=number-code] { display: inline-block; width: 40px; font-size: 13px; + line-height: 20px; } - .version { font-size: 9px; color: #343c4f; @@ -3969,7 +3969,18 @@ fieldset[name=number-code] { align-items: center; height: 45px; } - +.settings-card:hover { + border-color: #a6a6a6; +} +.settings-card-success:hover { + border-color: green; +} +.settings-card-warning:hover { + border-color: #c08400; +} +.settings-card-danger:hover { + border-color: #af0000; +} .thin-card { padding: 0 15px; } diff --git a/src/gui/src/i18n/translations/en.js b/src/gui/src/i18n/translations/en.js index 9947911bf5..c30974ae8c 100644 --- a/src/gui/src/i18n/translations/en.js +++ b/src/gui/src/i18n/translations/en.js @@ -38,6 +38,8 @@ const en = { browse: "Browse", cancel: 'Cancel', center: 'Center', + change: 'Change', + change_always_open_with: "Do you want to always open this type of file with", change_desktop_background: 'Change desktop background…', change_email: "Change Email", change_language: "Change Language", @@ -49,7 +51,6 @@ const en = { close_all_windows: "Close All Windows", close_all_windows_confirm: "Are you sure you want to close all windows?", close_all_windows_and_log_out: 'Close Windows and Log Out', - change_always_open_with: "Do you want to always open this type of file with", color: 'Color', confirm: 'Confirm', confirm_2fa_setup: 'I have added the code to my authenticator app', From 45ecce4653c9a876a1485d1b53a9eeec732727cf Mon Sep 17 00:00:00 2001 From: jelveh Date: Mon, 11 Nov 2024 20:49:49 -0800 Subject: [PATCH 1127/2119] Update style.css --- src/gui/src/css/style.css | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/gui/src/css/style.css b/src/gui/src/css/style.css index 163fdf118e..1b052b8317 100644 --- a/src/gui/src/css/style.css +++ b/src/gui/src/css/style.css @@ -3969,17 +3969,8 @@ fieldset[name=number-code] { align-items: center; height: 45px; } -.settings-card:hover { - border-color: #a6a6a6; -} -.settings-card-success:hover { - border-color: green; -} -.settings-card-warning:hover { - border-color: #c08400; -} -.settings-card-danger:hover { - border-color: #af0000; +.settings-card .button{ + box-shadow: none; } .thin-card { padding: 0 15px; From 1adfe5c70947d9de008c9d601f91b1ee14128d5d Mon Sep 17 00:00:00 2001 From: jelveh Date: Tue, 12 Nov 2024 12:40:14 -0800 Subject: [PATCH 1128/2119] feat: the `socialLink` UI component --- src/gui/src/IPC.js | 77 +++++++++++++++++++++++++++++++++- src/puter-js/src/modules/UI.js | 6 +++ 2 files changed, 82 insertions(+), 1 deletion(-) diff --git a/src/gui/src/IPC.js b/src/gui/src/IPC.js index 7d4823e80c..8cef32cc4e 100644 --- a/src/gui/src/IPC.js +++ b/src/gui/src/IPC.js @@ -30,6 +30,9 @@ import path from "./lib/path.js"; import UIContextMenu from './UI/UIContextMenu.js'; import update_mouse_position from './helpers/update_mouse_position.js'; import item_icon from './helpers/item_icon.js'; +import UIPopover from './UI/UIPopover.js'; +import socialLink from './helpers/socialLink.js'; + import { PROCESS_IPC_ATTACHED } from './definitions.js'; window.ipc_handlers = {}; @@ -46,7 +49,7 @@ window.ipc_handlers = {}; */ const ipc_listener = async (event, handled) => { const app_env = event.data?.env ?? 'app'; - + // Only process messages from apps if(app_env !== 'app') return handled.resolve(false); @@ -192,6 +195,78 @@ const ipc_listener = async (event, handled) => { response: prompt_resp, }, '*'); } + //-------------------------------------------------------- + // socialShare + //-------------------------------------------------------- + else if(event.data.msg === 'socialShare' && event.data.url !== undefined){ + const window_position = $el_parent_window.position(); + + // left position provided + if(event.data.options.left !== undefined){ + event.data.options.left = Math.abs(event.data.options.left); + event.data.options.left += window_position.left; + } + // left position not provided + else{ + // use top left of the window + event.data.options.left = window_position.left; + } + if(event.data.options.top !== undefined){ + event.data.options.top = Math.abs(event.data.options.top); + event.data.options.top += window_position.top + 30; + }else{ + // use top left of the window + event.data.options.top = window_position.top + 30; + } + + // top and left must be numbers + event.data.options.top = parseFloat(event.data.options.top); + event.data.options.left = parseFloat(event.data.options.left); + + const social_links = socialLink({url: event.data.url, title: event.data.message, description: event.data.message}); + + let h = ``; + let copy_icon = ` `; + + // create html + h += `
`; + h += `
`; + h += ``; + h += ``; + h += `
`; + + h += `

${i18n('share_to')}

` + h += `` + h += `` + h += `` + h += `` + h += `` + h += `` + h += '
'; + + let po = await UIPopover({ + content: h, + // snapToElement: this, + // parent_element: this, + // width: 300, + height: 100, + left: event.data.options.left, + top: event.data.options.top, + position: 'bottom', + }); + + $(po).find('.copy-link').on('click', function(e){ + const url = $(po).find('.social-url').val(); + navigator.clipboard.writeText(url); + // set checkmark + $(po).find('.copy-link').html(` `); + // reset checkmark + setTimeout(function(){ + $(po).find('.copy-link').html(copy_icon) + }, 1000); + }) + } + //-------------------------------------------------------- // env //-------------------------------------------------------- diff --git a/src/puter-js/src/modules/UI.js b/src/puter-js/src/modules/UI.js index 1d318644c2..61ab1b8adc 100644 --- a/src/puter-js/src/modules/UI.js +++ b/src/puter-js/src/modules/UI.js @@ -608,6 +608,12 @@ class UI extends EventListener { }) } + socialShare = function(url, message, options, callback) { + return new Promise((resolve) => { + this.#postMessageWithCallback('socialShare', resolve, { url, message, options }); + }) + } + prompt = function(message, placeholder, options, callback) { return new Promise((resolve) => { this.#postMessageWithCallback('PROMPT', resolve, { message, placeholder, options }); From ac3317aea918953358947638ca11822baa38e23f Mon Sep 17 00:00:00 2001 From: jelveh Date: Tue, 12 Nov 2024 13:27:29 -0800 Subject: [PATCH 1129/2119] fix: issue with popover closing when clicked --- src/gui/src/IPC.js | 17 ++++++++++++++--- src/gui/src/UI/UIPopover.js | 2 +- src/gui/src/initgui.js | 4 ++++ src/puter-js/src/modules/UI.js | 15 +++++++++++++++ 4 files changed, 34 insertions(+), 4 deletions(-) diff --git a/src/gui/src/IPC.js b/src/gui/src/IPC.js index 8cef32cc4e..18580da0f0 100644 --- a/src/gui/src/IPC.js +++ b/src/gui/src/IPC.js @@ -231,7 +231,7 @@ const ipc_listener = async (event, handled) => { // create html h += `
`; h += `
`; - h += ``; + h += ``; h += ``; h += `
`; @@ -247,7 +247,8 @@ const ipc_listener = async (event, handled) => { let po = await UIPopover({ content: h, // snapToElement: this, - // parent_element: this, + parent_element: $el_parent_window, + parent_id: parent_window_id, // width: 300, height: 100, left: event.data.options.left, @@ -256,6 +257,8 @@ const ipc_listener = async (event, handled) => { }); $(po).find('.copy-link').on('click', function(e){ + e.preventDefault(); + e.stopPropagation(); const url = $(po).find('.social-url').val(); navigator.clipboard.writeText(url); // set checkmark @@ -264,6 +267,8 @@ const ipc_listener = async (event, handled) => { setTimeout(function(){ $(po).find('.copy-link').html(copy_icon) }, 1000); + + return false; }) } @@ -393,6 +398,13 @@ const ipc_listener = async (event, handled) => { }); } //-------------------------------------------------------- + // mouseClicked + //-------------------------------------------------------- + else if(event.data.msg === 'mouseClicked'){ + // close all popovers whose parent_id is parent_window_id + $('.popover[data-parent_id="'+parent_window_id+'"]').remove(); + } + //-------------------------------------------------------- // showDirectoryPicker //-------------------------------------------------------- else if(event.data.msg === 'showDirectoryPicker'){ @@ -488,7 +500,6 @@ const ipc_listener = async (event, handled) => { // update mouse position update_mouse_position(x + window_position.left, y + window_position.top); } - //-------------------------------------------------------- // contextMenu //-------------------------------------------------------- diff --git a/src/gui/src/UI/UIPopover.js b/src/gui/src/UI/UIPopover.js index 23f6f21bb9..ed5a3cf9da 100644 --- a/src/gui/src/UI/UIPopover.js +++ b/src/gui/src/UI/UIPopover.js @@ -30,7 +30,7 @@ function UIPopover(options){ options.content = options.content ?? ''; let h = ''; - h += `
`; + h += `
`; h += options.content; h += `
`; diff --git a/src/gui/src/initgui.js b/src/gui/src/initgui.js index b05681c4e0..7f6755d0ce 100644 --- a/src/gui/src/initgui.js +++ b/src/gui/src/initgui.js @@ -1225,6 +1225,10 @@ window.initgui = async function(options){ // if mouse is clicked on a window, activate it if(window.mouseover_window !== undefined){ + // if popover clicked on, don't activate window. This is because if an app + // is using the popover API to show a popover, the popover will be closed if the window is activated + if($(e.target).hasClass('popover') || $(e.target).parents('.popover').length > 0) + return; $(window.mouseover_window).focusWindow(e); } }) diff --git a/src/puter-js/src/modules/UI.js b/src/puter-js/src/modules/UI.js index 61ab1b8adc..7c9f7ab87a 100644 --- a/src/puter-js/src/modules/UI.js +++ b/src/puter-js/src/modules/UI.js @@ -530,6 +530,21 @@ class UI extends EventListener { y: this.mouseY, }, '*'); }); + + // click + document.addEventListener('click', async (event)=>{ + // Get the mouse position from the event object + this.mouseX = event.clientX; + this.mouseY = event.clientY; + + // send the mouse position to the host environment + this.messageTarget?.postMessage({ + msg: "mouseClicked", + appInstanceID: this.appInstanceID, + x: this.mouseX, + y: this.mouseY, + }, '*'); + }) } onWindowClose = function(callback) { From b589512c9dedec22fd41b92cbba2570042149873 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 12 Nov 2024 17:58:32 -0500 Subject: [PATCH 1130/2119] feat: search endpoint --- .../hl_operations/hl_name_search.js | 41 +++++++++++++++++++ .../src/routers/filesystem_api/search.js | 20 +++++++++ .../src/services/FilesystemAPIService.js | 2 + 3 files changed, 63 insertions(+) create mode 100644 src/backend/src/filesystem/hl_operations/hl_name_search.js create mode 100644 src/backend/src/routers/filesystem_api/search.js diff --git a/src/backend/src/filesystem/hl_operations/hl_name_search.js b/src/backend/src/filesystem/hl_operations/hl_name_search.js new file mode 100644 index 0000000000..b44f757058 --- /dev/null +++ b/src/backend/src/filesystem/hl_operations/hl_name_search.js @@ -0,0 +1,41 @@ +const { DB_READ } = require("../../services/database/consts"); +const { Context } = require("../../util/context"); +const { NodeUIDSelector } = require("../node/selectors"); +const { HLFilesystemOperation } = require("./definitions"); + +class HLNameSearch extends HLFilesystemOperation { + async _run () { + let { actor, term } = this.values; + const services = Context.get('services'); + const svc_fs = services.get('filesystem'); + const db = services.get('database') + .get(DB_READ, 'fs.namesearch'); + + term = term.replace(/%/g, ''); + term = '%' + term + '%'; + + // Only user actors can do this, because the permission + // system would otherwise slow things down + if ( ! actor.type.user ) return []; + + const results = await db.read( + `SELECT uuid FROM fsentries WHERE name LIKE ? AND ` + + `user_id = ?`, + [term, actor.type.user.id] + ); + + const uuids = results.map(v => v.uuid); + + const fsnodes = await Promise.all(uuids.map(async uuid => { + return await svc_fs.node(new NodeUIDSelector(uuid)); + })); + + return Promise.all(fsnodes.map(async fsnode => { + return await fsnode.getSafeEntry(); + })); + } +} + +module.exports = { + HLNameSearch, +}; diff --git a/src/backend/src/routers/filesystem_api/search.js b/src/backend/src/routers/filesystem_api/search.js new file mode 100644 index 0000000000..379823b1e2 --- /dev/null +++ b/src/backend/src/routers/filesystem_api/search.js @@ -0,0 +1,20 @@ +const eggspress = require("../../api/eggspress"); +const { HLNameSearch } = require("../../filesystem/hl_operations/hl_name_search"); +const { subdomain } = require("../../helpers"); +const verified = require("../../middleware/verified"); + +module.exports = eggspress('/search', { + subdomain: 'api', + auth2: true, + verified: true, + fs: true, + json: true, + allowedMethods: ['POST'], +}, async (req, res, next) => { + const hl_name_search = new HLNameSearch(); + const result = await hl_name_search.run({ + actor: req.actor, + term: req.body.text, + }); + res.send(result); +}); diff --git a/src/backend/src/services/FilesystemAPIService.js b/src/backend/src/services/FilesystemAPIService.js index 521a093445..b8872e5271 100644 --- a/src/backend/src/services/FilesystemAPIService.js +++ b/src/backend/src/services/FilesystemAPIService.js @@ -38,6 +38,8 @@ class FilesystemAPIService extends BaseService { app.use(require('../routers/filesystem_api/copy')) app.use(require('../routers/filesystem_api/move')) app.use(require('../routers/filesystem_api/rename')) + + app.use(require('../routers/filesystem_api/search')) // v1 app.use(require('../routers/writeFile')) From 55d2af189e9479fb5980ce149ce74e890b325014 Mon Sep 17 00:00:00 2001 From: jelveh Date: Tue, 12 Nov 2024 20:20:43 -0800 Subject: [PATCH 1131/2119] feat: search --- .../hl_operations/hl_name_search.js | 2 +- src/gui/src/UI/UIDesktop.js | 8 + src/gui/src/UI/UIWindow.js | 5 +- src/gui/src/UI/UIWindowSearch.js | 259 ++++++++++++++++++ src/gui/src/css/style.css | 48 +++- src/gui/src/helpers/item_icon.js | 4 + src/gui/src/icons/search.svg | 4 + src/gui/src/initgui.js | 6 + src/gui/src/keyboard.js | 54 ++++ 9 files changed, 387 insertions(+), 3 deletions(-) create mode 100644 src/gui/src/UI/UIWindowSearch.js create mode 100644 src/gui/src/icons/search.svg diff --git a/src/backend/src/filesystem/hl_operations/hl_name_search.js b/src/backend/src/filesystem/hl_operations/hl_name_search.js index b44f757058..fb05e2b258 100644 --- a/src/backend/src/filesystem/hl_operations/hl_name_search.js +++ b/src/backend/src/filesystem/hl_operations/hl_name_search.js @@ -20,7 +20,7 @@ class HLNameSearch extends HLFilesystemOperation { const results = await db.read( `SELECT uuid FROM fsentries WHERE name LIKE ? AND ` + - `user_id = ?`, + `user_id = ? LIMIT 50`, [term, actor.type.user.id] ); diff --git a/src/gui/src/UI/UIDesktop.js b/src/gui/src/UI/UIDesktop.js index 560e3d105a..55812ec442 100644 --- a/src/gui/src/UI/UIDesktop.js +++ b/src/gui/src/UI/UIDesktop.js @@ -41,6 +41,7 @@ import UINotification from "./UINotification.js" import UIWindowWelcome from "./UIWindowWelcome.js" import launch_app from "../helpers/launch_app.js" import item_icon from "../helpers/item_icon.js" +import UIWindowSearch from "./UIWindowSearch.js" async function UIDesktop(options){ let h = ''; @@ -1032,6 +1033,9 @@ async function UIDesktop(options){ if(!window.is_embedded) ht += `
`; + // search button + ht += `
`; + // user options menu ht += `
`; h += `${window.user.username}`; @@ -1498,6 +1502,10 @@ $(document).on('click', '.close-launch-popover', function(){ }); }); +$(document).on('click', '.search-btn', function(){ + UIWindowSearch(); +}) + $(document).on('click', '.toolbar-puter-logo', function(){ UIWindowSettings(); }) diff --git a/src/gui/src/UI/UIWindow.js b/src/gui/src/UI/UIWindow.js index 942f56df88..f681ac8922 100644 --- a/src/gui/src/UI/UIWindow.js +++ b/src/gui/src/UI/UIWindow.js @@ -3449,7 +3449,10 @@ $.fn.focusWindow = function(event) { if(this.hasClass('window')){ const $app_iframe = $(this).find('.window-app-iframe'); const win_id = $(this).attr('data-id'); + + // remove active class from all windows, except for this window $('.window').not(this).removeClass('window-active'); + // add active class to this window $(this).addClass('window-active'); // disable pointer events on all windows' iframes, except for this window's iframe $('.window-app-iframe').not($app_iframe).css('pointer-events', 'none'); @@ -3509,7 +3512,7 @@ $.fn.focusWindow = function(event) { window.history.replaceState({window_id: $(this).attr('data-id')}, '', '/app/'+url_app_name+$(this).attr('data-user_set_url_params')); document.title = $(this).attr('data-name'); } - $(`.taskbar .taskbar-item[data-app="${$(this).attr('data-app')}"]`).addClass('taskbar-item-active'); + $(`.taskbar .taskbar-item[data-app="${$(this).attr('data-app')}"]`).addClass('taskbar-item-active'); }else{ $('.window').find('.item-selected').addClass('item-blurred'); $('.desktop').find('.item-blurred').removeClass('item-blurred'); diff --git a/src/gui/src/UI/UIWindowSearch.js b/src/gui/src/UI/UIWindowSearch.js new file mode 100644 index 0000000000..9ff4a1b21b --- /dev/null +++ b/src/gui/src/UI/UIWindowSearch.js @@ -0,0 +1,259 @@ +/** + * Copyright (C) 2024 Puter Technologies Inc. + * + * This file is part of Puter. + * + * Puter 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 . + */ + +import UIWindow from './UIWindow.js' +import path from "../lib/path.js" +import UIAlert from './UIAlert.js' +import launch_app from '../helpers/launch_app.js' +import item_icon from '../helpers/item_icon.js' + +async function UIWindowSearch(options){ + let h = ''; + + h += `
`; + h += ``; + h += `
`; + h += `
`; + + const el_window = await UIWindow({ + icon: null, + single_instance: true, + app: 'search', + uid: null, + is_dir: false, + body_content: h, + has_head: false, + selectable_body: false, + draggable_body: true, + allow_context_menu: false, + is_draggable: false, + is_resizable: false, + is_droppable: false, + init_center: true, + allow_native_ctxmenu: true, + allow_user_select: true, + window_class: 'window-search', + onAppend: function(el_window){ + }, + width: 500, + dominant: true, + window_css: { + height: 'initial', + padding: '0', + }, + body_css: { + width: 'initial', + 'max-height': 'calc(100vh - 200px)', + 'background-color': 'rgb(241 246 251)', + 'backdrop-filter': 'blur(3px)', + 'padding': '0', + 'height': 'initial', + 'overflow': 'hidden', + 'min-height': '65px', + 'padding-bottom': '10px', + } + }); + + $(el_window).find('.search-input').focus(); + + // Debounce function to limit rate of API calls + function debounce(func, wait) { + let timeout; + return function (...args) { + const context = this; + clearTimeout(timeout); + timeout = setTimeout(() => { + func.apply(context, args); + }, wait); + }; + } + + // State for managing loading indicator + let isSearching = false; + + // Debounced search function + const performSearch = debounce(async function(searchInput, resultsContainer) { + // Don't search if input is empty + if (searchInput.val() === '') { + resultsContainer.html(''); + resultsContainer.hide(); + return; + } + + // Set loading state + if (!isSearching) { + isSearching = true; + } + + try { + // Perform the search + let results = await fetch(window.api_origin + '/search', { + method: 'POST', + headers: { + 'Content-Type': 'application/json', + 'Authorization': `Bearer ${puter.authToken}` + }, + body: JSON.stringify({ text: searchInput.val() }) + }); + + results = await results.json(); + + // Hide results if there are none + if(results.length === 0) + resultsContainer.hide(); + else + resultsContainer.show(); + + // Build results HTML + let h = ''; + + for(let i = 0; i < results.length; i++){ + const result = results[i]; + h += `
`; + // icon + h += ``; + h += html_encode(result.name); + h += `
`; + } + resultsContainer.html(h); + } catch (error) { + resultsContainer.html('
Search failed. Please try again.
'); + console.error('Search error:', error); + } finally { + isSearching = false; + } + }, 300); // Wait 300ms after last keystroke before searching + + // Event binding + $(el_window).find('.search-input').on('input', function(e) { + const searchInput = $(this); + const resultsContainer = $(el_window).find('.search-results'); + performSearch(searchInput, resultsContainer); + }); +} + +$(document).on('click', '.search-result', async function(e){ + const fspath = $(this).data('path'); + const fsuid = $(this).data('uid'); + const is_dir = $(this).attr('data-is_dir') === 'true' || $(this).data('is_dir') === '1'; + let open_item_meta; + + if(is_dir){ + UIWindow({ + path: fspath, + title: path.basename(fspath), + icon: await item_icon({is_dir: true, path: fspath}), + uid: fsuid, + is_dir: is_dir, + app: 'explorer', + // top: options.maximized ? 0 : undefined, + // left: options.maximized ? 0 : undefined, + // height: options.maximized ? `calc(100% - ${window.taskbar_height + window.toolbar_height + 1}px)` : undefined, + // width: options.maximized ? `100%` : undefined, + }); + + // close search window + $(this).closest('.window').close(); + + return; + } + + // get all info needed to open an item + try{ + open_item_meta = await $.ajax({ + url: window.api_origin + "/open_item", + type: 'POST', + contentType: "application/json", + data: JSON.stringify({ + uid: fsuid ?? undefined, + path: fspath ?? undefined, + }), + headers: { + "Authorization": "Bearer "+window.auth_token + }, + statusCode: { + 401: function () { + window.logout(); + }, + }, + }); + }catch(err){ + // Ignored + } + + // get a list of suggested apps for this file type. + let suggested_apps = open_item_meta?.suggested_apps ?? await window.suggest_apps_for_fsentry({uid: fsuid, path: fspath}); + + //--------------------------------------------- + // No suitable apps, ask if user would like to + // download + //--------------------------------------------- + if(suggested_apps.length === 0){ + //--------------------------------------------- + // If .zip file, unzip it + //--------------------------------------------- + if(path.extname(fspath) === '.zip'){ + window.unzipItem(fspath); + return; + } + const alert_resp = await UIAlert( + 'Found no suitable apps to open this file with. Would you like to download it instead?', + [ + { + label: i18n('download_file'), + value: 'download_file', + type: 'primary', + + }, + { + label: i18n('cancel') + } + ]) + if(alert_resp === 'download_file'){ + window.trigger_download([fspath]); + } + return; + } + //--------------------------------------------- + // First suggested app is default app to open this item + //--------------------------------------------- + else{ + launch_app({ + name: suggested_apps[0].name, + token: open_item_meta.token, + file_path: fspath, + app_obj: suggested_apps[0], + window_title: path.basename(fspath), + file_uid: fsuid, + // maximized: options.maximized, + file_signature: open_item_meta.signature, + }); + } + + + // close + $(this).closest('.window').close(); +}) + +export default UIWindowSearch \ No newline at end of file diff --git a/src/gui/src/css/style.css b/src/gui/src/css/style.css index 1b052b8317..2f7a05429a 100644 --- a/src/gui/src/css/style.css +++ b/src/gui/src/css/style.css @@ -4230,4 +4230,50 @@ fieldset[name=number-code] { .welcome-window-footer a:hover{ color: #1d1e23; -} \ No newline at end of file +} + +/* +* ------------------------------------ +* Search +* ------------------------------------ +*/ +.search-input-wrapper{ + width: 100%; + border-radius: 5px; + padding-bottom: 10px; + padding-top: 20px; + position: absolute; + padding-left: 15px; + padding-right: 15px; + box-sizing: border-box; + background: #f1f6fc; +} +.search-input{ + padding-left: 33px !important; + background-repeat: no-repeat; + background-position: 5px center; + background-size: 20px; +} +.search-results{ + padding-right: 15px; + margin-top: 70px; + padding-left: 15px; + padding-right: 15px; + padding-bottom: 5px; + display: none; +} +.search-result{ + padding: 10px; cursor: pointer; + font-size: 13px; + display: flex; + align-items: center; +} +.search-result-active{ + background-color: #4092da; + color: #fff; + border-radius: 5px; +} +.search-results .search-result:last-child { + margin-bottom: 0; +} + \ No newline at end of file diff --git a/src/gui/src/helpers/item_icon.js b/src/gui/src/helpers/item_icon.js index f17ea7893b..44d8d9c6ae 100644 --- a/src/gui/src/helpers/item_icon.js +++ b/src/gui/src/helpers/item_icon.js @@ -51,6 +51,10 @@ const item_icon = async (fsentry)=>{ // thumbnail // -------------------------------------------------- if(fsentry.thumbnail){ + // if thumbnail but a directory under AppData, then it's a thumbnail for an app and must be treated as an icon + if(fsentry.path.startsWith(window.appdata_path + '/')) + return {image: fsentry.thumbnail, type: 'icon'}; + // otherwise, it's a thumbnail for a file return {image: fsentry.thumbnail, type: 'thumb'}; } // -------------------------------------------------- diff --git a/src/gui/src/icons/search.svg b/src/gui/src/icons/search.svg new file mode 100644 index 0000000000..69f733ba59 --- /dev/null +++ b/src/gui/src/icons/search.svg @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/gui/src/initgui.js b/src/gui/src/initgui.js index 7f6755d0ce..f37044d041 100644 --- a/src/gui/src/initgui.js +++ b/src/gui/src/initgui.js @@ -1420,6 +1420,12 @@ $(document).on('click', '.generic-close-window-button', function(e){ $(this).closest('.window').close(); }); +$(document).on('click', function(e){ + if(!$(e.target).hasClass('window-search') && $(e.target).closest('.window-search').length === 0 && !$(e.target).is('.toolbar-btn.search-btn')){ + $('.window-search').close(); + } +}) + // Re-calculate desktop height and width on window resize and re-position the login and signup windows $(window).on("resize", function () { // If host env is popup, don't continue because the popup window has its own resize requirements. diff --git a/src/gui/src/keyboard.js b/src/gui/src/keyboard.js index aa9e448708..9f3fedf27c 100644 --- a/src/gui/src/keyboard.js +++ b/src/gui/src/keyboard.js @@ -18,11 +18,23 @@ */ import UIAlert from './UI/UIAlert.js'; +import UIWindowSearch from './UI/UIWindowSearch.js'; import launch_app from './helpers/launch_app.js'; import open_item from './helpers/open_item.js'; $(document).bind('keydown', async function(e){ const focused_el = document.activeElement; + //----------------------------------------------------------------------------- + // Search + // ctrl/command + f, will open UIWindowSearch + //----------------------------------------------------------------------------- + if((e.ctrlKey || e.metaKey) && e.which === 70 && !$(focused_el).is('input') && !$(focused_el).is('textarea')){ + e.preventDefault(); + e.stopPropagation(); + UIWindowSearch(); + return false; + } + //----------------------------------------------------------------------- // ← ↑ → ↓: an arrow key is pressed //----------------------------------------------------------------------- @@ -290,6 +302,32 @@ $(document).bind('keydown', async function(e){ next_item.scrollIntoView(false); } } + // ---------------------------------------------- + // Navigate search results in the search window + // ---------------------------------------------- + else if($('.window-search').length > 0){ + let selected_item = $('.window-search .search-result-active').get(0); + let selected_item_index = selected_item ? $('.window-search .search-result').index(selected_item) : -1; + let new_selected_item_index = selected_item_index; + let new_selected_item; + + // if up arrow is pressed + if(e.which === 38){ + new_selected_item_index = selected_item_index - 1; + if(new_selected_item_index < 0) + new_selected_item_index = $('.window-search .search-result').length - 1; + } + // if down arrow is pressed + else if(e.which === 40){ + new_selected_item_index = selected_item_index + 1; + if(new_selected_item_index >= $('.window-search .search-result').length) + new_selected_item_index = 0; + } + new_selected_item = $('.window-search .search-result').get(new_selected_item_index); + $(selected_item).removeClass('search-result-active'); + $(new_selected_item).addClass('search-result-active'); + new_selected_item.scrollIntoView(false); + } } //----------------------------------------------------------------------- // if the Esc key is pressed on a FileDialog/Alert, close that FileDialog/Alert @@ -313,6 +351,12 @@ $(document).bind('keydown', async function(e){ $(focused_el).val($(focused_el).closest('.window').attr('data-path')); $(focused_el).attr('data-path', $(focused_el).closest('.window').attr('data-path')); } + //----------------------------------------------------------------------- + // if the Esc key is pressed on a Search Window, close the Search Window + //----------------------------------------------------------------------- + else if( e.which === 27 && $('.window-search').length > 0){ + $('.window-search').close(); + } //----------------------------------------------------------------------- // Esc key should: @@ -612,6 +656,16 @@ $(document).bind("keyup keydown", async function(e){ return false; } //----------------------------------------------------------------------- + // Enter key on a search window result + //----------------------------------------------------------------------- + if(e.which === 13 && $('.window-search').length > 0 + // prevent firing twice, because this will be fired on both keyup and keydown + && e.type === 'keydown'){ + $('.window-search .search-result-active').trigger('click'); + + return false; + } + //----------------------------------------------------------------------- // Open // Enter key on a selected item will open it //----------------------------------------------------------------------- From 7ca0a02fa4fdc6b93f7eb6515e5fba504e40275c Mon Sep 17 00:00:00 2001 From: jelveh Date: Tue, 12 Nov 2024 20:45:53 -0800 Subject: [PATCH 1132/2119] tweak: safe data URI strings for icons in search --- src/gui/src/UI/UIDesktop.js | 2 +- src/gui/src/UI/UITaskbar.js | 2 +- src/gui/src/UI/UIWindowSearch.js | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/gui/src/UI/UIDesktop.js b/src/gui/src/UI/UIDesktop.js index 55812ec442..8388fece14 100644 --- a/src/gui/src/UI/UIDesktop.js +++ b/src/gui/src/UI/UIDesktop.js @@ -1034,7 +1034,7 @@ async function UIDesktop(options){ ht += `
`; // search button - ht += `
`; + ht += `
`; // user options menu ht += `
`; diff --git a/src/gui/src/UI/UITaskbar.js b/src/gui/src/UI/UITaskbar.js index 10cd0c0b0e..7b32814040 100644 --- a/src/gui/src/UI/UITaskbar.js +++ b/src/gui/src/UI/UITaskbar.js @@ -91,7 +91,7 @@ async function UITaskbar(options){ let apps_str = ''; apps_str += `
` - apps_str += ``; + apps_str += ``; apps_str += ``; apps_str += `
`; // ------------------------------------------- diff --git a/src/gui/src/UI/UIWindowSearch.js b/src/gui/src/UI/UIWindowSearch.js index 9ff4a1b21b..ab28278da3 100644 --- a/src/gui/src/UI/UIWindowSearch.js +++ b/src/gui/src/UI/UIWindowSearch.js @@ -27,7 +27,7 @@ async function UIWindowSearch(options){ let h = ''; h += `
`; - h += ``; + h += ``; h += `
`; h += `
`; From 5725bd8c66539564e7f58f96c6e81044a3751f97 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 13 Nov 2024 12:11:37 -0500 Subject: [PATCH 1133/2119] fix: report path for broken files as /-void/ --- src/backend/src/filesystem/FSNodeContext.js | 13 +++++++++++-- .../filesystem/storage/DatabaseFSEntryService.js | 6 +++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/src/backend/src/filesystem/FSNodeContext.js b/src/backend/src/filesystem/FSNodeContext.js index 11f66b7686..d575206601 100644 --- a/src/backend/src/filesystem/FSNodeContext.js +++ b/src/backend/src/filesystem/FSNodeContext.js @@ -827,6 +827,10 @@ module.exports = class FSNodeContext { .with('fs.fsentry:uuid') .obtain('fs.fsentry:path') .exec(this.uid ?? this.entry.uuid); + + if ( fsentry.path && fsentry.path.startsWith('/-void/') ) { + fsentry.broken = true; + } fsentry.dirname = _path.dirname(fsentry.path); fsentry.dirpath = fsentry.dirname; @@ -856,8 +860,13 @@ module.exports = class FSNodeContext { // Use client-friendly IDs for shortcut_to fsentry.shortcut_to = (res.shortcut_to ? await id2uuid(res.shortcut_to) : undefined); - fsentry.shortcut_to_path = (res.shortcut_to - ? await id2path(res.shortcut_to) : undefined); + try { + fsentry.shortcut_to_path = (res.shortcut_to + ? await id2path(res.shortcut_to) : undefined); + } catch (e) { + fsentry.shortcut_invalid = true; + fsentry.shortcut_uid = res.shortcut_to; + } // Add file_request_url if(res.file_request_token && res.file_request_token !== ''){ diff --git a/src/backend/src/filesystem/storage/DatabaseFSEntryService.js b/src/backend/src/filesystem/storage/DatabaseFSEntryService.js index 5244857f84..ecf674ef23 100644 --- a/src/backend/src/filesystem/storage/DatabaseFSEntryService.js +++ b/src/backend/src/filesystem/storage/DatabaseFSEntryService.js @@ -250,7 +250,11 @@ class DatabaseFSEntryService extends AdvancedBase { info.given('fs.fsentry:uuid').provide('fs.fsentry:path') .addStrategy('mysql', async uuid => { // TODO: move id2path here - return await id2path(uuid); + try { + return await id2path(uuid); + } catch (e) { + return '/-void/' + uuid; + } }); (async () => { From 8f59c2614d57e863edd72161d12733f9d2a786d4 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 13 Nov 2024 12:54:54 -0500 Subject: [PATCH 1134/2119] tweak: put groups manager behind a flag --- src/gui/src/extensions/groups-manager.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/src/extensions/groups-manager.js b/src/gui/src/extensions/groups-manager.js index 1ae8cdacd7..7f1c57dc96 100644 --- a/src/gui/src/extensions/groups-manager.js +++ b/src/gui/src/extensions/groups-manager.js @@ -77,6 +77,7 @@ class UIGroupsManager extends UIElement { $(window).on('ctxmenu-will-open', event => { if ( event.detail.options?.id !== 'user-options-menu' ) return; + if ( ! window.experimental_features ) return; const newMenuItems = [ { From 89aab0390591874b25755eaff52ac135f34d47d5 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 13 Nov 2024 13:15:22 -0500 Subject: [PATCH 1135/2119] tweak: enable share --- src/backend/src/services/ShareService.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/backend/src/services/ShareService.js b/src/backend/src/services/ShareService.js index 63e7e7760f..2a033a9301 100644 --- a/src/backend/src/services/ShareService.js +++ b/src/backend/src/services/ShareService.js @@ -42,7 +42,8 @@ class ShareService extends BaseService { // about whether or not a user has access to this feature const svc_featureFlag = this.services.get('feature-flag'); svc_featureFlag.register('share', { - $: 'permission-flag' + $: 'config-flag', + value: true }); } From 27cc07e985a799fae791d6edf61b7e656e0e182e Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 13 Nov 2024 15:02:10 -0500 Subject: [PATCH 1136/2119] fix: files shared array in notification --- src/backend/src/structured/sequence/share.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/backend/src/structured/sequence/share.js b/src/backend/src/structured/sequence/share.js index 7c248b8d82..008e5b4f3d 100644 --- a/src/backend/src/structured/sequence/share.js +++ b/src/backend/src/structured/sequence/share.js @@ -506,7 +506,7 @@ module.exports = new Sequence([ const files = []; { for ( const item of shares_work.list() ) { - if ( item.type !== 'file' ) continue; + if ( item.thing.$ !== 'fs-share' ) continue; files.push( await item.node.getSafeEntry(), ); @@ -515,7 +515,7 @@ module.exports = new Sequence([ const apps = []; { for ( const item of shares_work.list() ) { - if ( item.type !== 'app' ) continue; + if ( item.thing.$ !== 'app' ) continue; // TODO: is there a general way to create a // client-safe app right now without // going through entity storage? From 622205ae513a99506face600a3a07438645293f9 Mon Sep 17 00:00:00 2001 From: jelveh Date: Wed, 13 Nov 2024 13:49:17 -0800 Subject: [PATCH 1137/2119] tweak: enable sharing --- src/gui/src/UI/UIItem.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/src/UI/UIItem.js b/src/gui/src/UI/UIItem.js index c554adb59c..59281cc22b 100644 --- a/src/gui/src/UI/UIItem.js +++ b/src/gui/src/UI/UIItem.js @@ -782,7 +782,7 @@ function UIItem(options){ // ------------------------------------------- menu_items.push('-'); } - if(!are_trashed && (window.user.feature_flags?.share !== false)){ + if(!are_trashed){ menu_items.push({ html: 'Share With…', onClick: async function(){ @@ -1086,7 +1086,7 @@ function UIItem(options){ // ------------------------------------------- // Share With… // ------------------------------------------- - if(!is_trashed && !is_trash && (window.user.feature_flags?.share !== false)){ + if(!is_trashed && !is_trash){ menu_items.push({ html: 'Share With…', onClick: async function(){ From 599c7ad0a1e5e617a67c22675a86a87a528b2077 Mon Sep 17 00:00:00 2001 From: jelveh Date: Wed, 13 Nov 2024 14:43:30 -0800 Subject: [PATCH 1138/2119] Update UIElement.js --- src/gui/src/UI/UIElement.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gui/src/UI/UIElement.js b/src/gui/src/UI/UIElement.js index ccd09c9a31..57aaeac833 100644 --- a/src/gui/src/UI/UIElement.js +++ b/src/gui/src/UI/UIElement.js @@ -118,7 +118,6 @@ export default def(class UIElement extends AdvancedBase { async open_as_window (options = {}) { const placeholder = Placeholder(); - console.log('window options?', this.windowOptions); let win; this.close = () => $(win).close(); win = await UIWindow({ From 9a311058ef1d79da81d4d8d277609e0399c8d9c1 Mon Sep 17 00:00:00 2001 From: jelveh Date: Wed, 13 Nov 2024 15:45:02 -0800 Subject: [PATCH 1139/2119] tweak: disable `sidebar_items` polling --- src/gui/src/UI/UIDesktop.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/gui/src/UI/UIDesktop.js b/src/gui/src/UI/UIDesktop.js index 8388fece14..20f5415e28 100644 --- a/src/gui/src/UI/UIDesktop.js +++ b/src/gui/src/UI/UIDesktop.js @@ -569,11 +569,11 @@ async function UIDesktop(options){ window.sidebar_items = val; }) // also update every 2 seconds - setInterval(async () => { - puter.kv.get("sidebar_items").then(async (val) => { - window.sidebar_items = val; - }) - }, 2000); + // setInterval(async () => { + // puter.kv.get("sidebar_items").then(async (val) => { + // window.sidebar_items = val; + // }) + // }, 2000); // Get menubar style puter.kv.get('menubar_style').then(async (val) => { From b5bb95e2d7f6021a6341e26cf15d5449ada48830 Mon Sep 17 00:00:00 2001 From: jelveh Date: Wed, 13 Nov 2024 15:59:29 -0800 Subject: [PATCH 1140/2119] feat: add error handling to the share flow --- src/gui/src/UI/UIWindowShare.js | 81 +++++++++++++++++++++------------ 1 file changed, 53 insertions(+), 28 deletions(-) diff --git a/src/gui/src/UI/UIWindowShare.js b/src/gui/src/UI/UIWindowShare.js index 67aebc8a73..2923bb342a 100644 --- a/src/gui/src/UI/UIWindowShare.js +++ b/src/gui/src/UI/UIWindowShare.js @@ -170,7 +170,7 @@ async function UIWindowShare(items, recipient){ recipients.forEach(perm => { //check if this user has been printed here before, important for multiple items if(!printed_users.includes(perm.user.username)){ - perm_list += `
` + perm_list += `
` perm_list += `${perm.user.email ?? perm.user.username}`; perm_list += `
`; perm_list += `
`; @@ -205,6 +205,22 @@ async function UIWindowShare(items, recipient){ recipient_email = recipient_id; else recipient_username = recipient_id; + + // see if the recipient is already in the list + let recipient_already_in_list = false; + $(el_window).find('.item-perm-recipient-card').each(function(){ + if((recipient_username && $(this).data('recipient-username') === recipient_username) ||(recipient_email && $(this).data('recipient-email') === recipient_email)){ + recipient_already_in_list = true; + return false; + } + }) + + if(recipient_already_in_list){ + $(el_window).find('.error').html('This user already has access'); + $(el_window).find('.error').fadeIn(); + return; + } + // can't share with self if(recipient_username === window.user.username){ $(el_window).find('.error').html('You can\'t share with yourself'); @@ -244,33 +260,42 @@ async function UIWindowShare(items, recipient){ ] }), success: function(response) { - // show success message - $(el_window).find('.access-recipient-print').html(recipient_id); - let perm_id = `fs:${items[0].uid}:${access_level}`; - - // append recipient to list - let perm_list = ''; - perm_list += `
` - perm_list += `${recipient_username}`; - perm_list += `
`; - perm_list += `
`; - - // reset input - $(el_window).find('.error').hide(); - $(el_window).find('.access-recipient').val(''); - - // disable 'Give Access' button - $(el_window).find('.give-access-btn').prop('disabled', true); - - // append recipient to list - $(el_window).find('.share-recipients').append(`${perm_list}`); - - // add to contacts - if(!contacts.includes(recipient_username)){ - contacts.push(recipient_username); - puter.kv.set('contacts', JSON.stringify(contacts)); + if (response.status === "mixed") { + response.recipients.forEach(recipient => { + if (recipient.code === "user_does_not_exist") { + $(el_window).find('.error').html(recipient.message); + $(el_window).find('.error').fadeIn(); + cancelled_due_to_error = true; + } + }); + } else { + // show success message + $(el_window).find('.access-recipient-print').html(recipient_id); + let perm_id = `fs:${items[0].uid}:${access_level}`; + + // append recipient to list + let perm_list = ''; + perm_list += `
` + perm_list += `${recipient_username}`; + perm_list += `
`; + perm_list += `
`; + + // reset input + $(el_window).find('.error').hide(); + $(el_window).find('.access-recipient').val(''); + + // disable 'Give Access' button + $(el_window).find('.give-access-btn').prop('disabled', true); + + // append recipient to list + $(el_window).find('.share-recipients').append(`${perm_list}`); + + // add to contacts + if(!contacts.includes(recipient_username)){ + contacts.push(recipient_username); + puter.kv.set('contacts', JSON.stringify(contacts)); + } } - }, error: function(err) { // at this point 'username_not_found' and 'shared_with_self' are the only @@ -282,7 +307,7 @@ async function UIWindowShare(items, recipient){ } // re-enable share button $(el_window).find('.give-access-btn').prop('disabled', false); - + } }); From 94b10c78b7fa2320b8a873225a90b3e90c62d7aa Mon Sep 17 00:00:00 2001 From: jelveh Date: Wed, 13 Nov 2024 17:30:03 -0800 Subject: [PATCH 1141/2119] tweak: sharing style --- src/gui/src/UI/UIWindowShare.js | 19 ++++++++++++------- src/gui/src/css/style.css | 23 +++++++++++++++++++++++ 2 files changed, 35 insertions(+), 7 deletions(-) diff --git a/src/gui/src/UI/UIWindowShare.js b/src/gui/src/UI/UIWindowShare.js index 2923bb342a..e406362654 100644 --- a/src/gui/src/UI/UIWindowShare.js +++ b/src/gui/src/UI/UIWindowShare.js @@ -27,7 +27,6 @@ async function UIWindowShare(items, recipient){ //------------------------------------------------ // Icons //------------------------------------------------ - h += `
`; // 1 item shared if(items.length === 1) @@ -61,7 +60,7 @@ async function UIWindowShare(items, recipient){ h += `
`; // ------------------------------------------------ - // Name + // Item Name // ------------------------------------------------ h += `

`; h += `Share ${html_encode(items[0].name)}`; @@ -69,7 +68,9 @@ async function UIWindowShare(items, recipient){ h += ` and ${items.length - 1} other item${items.length > 2 ? 's' : ''}`; h += `

`; - // form + // ------------------------------------------------ + // Recipient + // ------------------------------------------------ h += `
`; // Error msg h += `
`; @@ -85,7 +86,9 @@ async function UIWindowShare(items, recipient){ h += `
`; h += ``; - //recipients + // ------------------------------------------------ + // Already Shared With + // ------------------------------------------------ h += `

People with access

`; h += ``; @@ -124,6 +127,7 @@ async function UIWindowShare(items, recipient){ let contacts = []; + // get contacts puter.kv.get('contacts').then((kv_contacts) => { if(kv_contacts){ try{ @@ -139,7 +143,8 @@ async function UIWindowShare(items, recipient){ // /stat let perms = []; - let printed_users = []; + let printed_users = []; + for(let i=0; i Date: Wed, 13 Nov 2024 20:39:58 -0500 Subject: [PATCH 1142/2119] fix: don't check share permission anymore --- src/backend/src/services/ShareService.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/src/services/ShareService.js b/src/backend/src/services/ShareService.js index 2a033a9301..2456dd9515 100644 --- a/src/backend/src/services/ShareService.js +++ b/src/backend/src/services/ShareService.js @@ -257,7 +257,7 @@ class ShareService extends BaseService { methods: ['POST'], mw: [ configurable_auth(), - featureflag({ feature: 'share' }), + // featureflag({ feature: 'share' }), ], handler: async (req, res) => { const actor = Actor.adapt(req.user); From caf8d2a055c1a115525fad37f01e0f4a534d55c8 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 13 Nov 2024 21:14:56 -0500 Subject: [PATCH 1143/2119] dev: track ll_readshares depth --- .../src/filesystem/ll_operations/ll_readshares.js | 13 +++++++++---- 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/src/backend/src/filesystem/ll_operations/ll_readshares.js b/src/backend/src/filesystem/ll_operations/ll_readshares.js index e8132154e4..a27e31d5e7 100644 --- a/src/backend/src/filesystem/ll_operations/ll_readshares.js +++ b/src/backend/src/filesystem/ll_operations/ll_readshares.js @@ -33,12 +33,13 @@ class LLReadShares extends LLFilesystemOperation { async _run () { const results = []; - await this.recursive_part(results, this.values); + const stats = await this.recursive_part(results, this.values); + // console.log('LL_READ_SHARES_STATS !!!!!', stats); return results; } - async recursive_part (results, { subject, user, actor }) { + async recursive_part (results, { subject, user, actor, depth = 0 }) { actor = actor || Context.get('actor'); const ll_readdir = new LLReadDir(); const children = await ll_readdir.run({ @@ -73,11 +74,15 @@ class LLReadShares extends LLFilesystemOperation { } const p = this.recursive_part(results, { - subject: child, user }); + subject: child, + user, + depth: depth + 1, + }); promises.push(p); } - await Promise.all(promises); + const stats = await Promise.all(promises); + return Math.max(depth, ...stats); } } From 34836e374fccac297a6f0fa5f323f3609d0c9179 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 13 Nov 2024 22:15:09 -0500 Subject: [PATCH 1144/2119] fix: only add enabled_logs when not empty --- src/gui/src/services/DebugService.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/gui/src/services/DebugService.js b/src/gui/src/services/DebugService.js index a0de5ae510..696ea255ca 100644 --- a/src/gui/src/services/DebugService.js +++ b/src/gui/src/services/DebugService.js @@ -9,7 +9,10 @@ export class DebugService extends Service { const svc_exec = this.services.get('exec'); svc_exec.register_param_provider(() => { return { - enabled_logs: this.enabled_logs.join(';'), + ...(this.enabled_logs.length > 0 + ? { enabled_logs: this.enabled_logs.join(';') } + : {} + ), }; }); } From cd22425a3d363f6008b3d07f40a082769ee22a14 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 13 Nov 2024 22:44:54 -0500 Subject: [PATCH 1145/2119] fix: replace ll_readshares with better approach Recursively checking for files with 'see' permission? What was I thinking? This replaces the disasterously awful approach of scanning a user's entire file tree to find shares, with an approach which instead selects on the permissions table and extracts file UUIDs from permissions. --- .../filesystem/hl_operations/hl_readdir.js | 3 +- .../filesystem/ll_operations/ll_readshares.js | 91 ++++++++++--------- 2 files changed, 49 insertions(+), 45 deletions(-) diff --git a/src/backend/src/filesystem/hl_operations/hl_readdir.js b/src/backend/src/filesystem/hl_operations/hl_readdir.js index a6bb9c0ebe..32061f0284 100644 --- a/src/backend/src/filesystem/hl_operations/hl_readdir.js +++ b/src/backend/src/filesystem/hl_operations/hl_readdir.js @@ -64,7 +64,8 @@ class HLReadDir extends HLFilesystemOperation { const ll_listusers = new LLListUsers(); children = await ll_listusers.run(this.values); } else if ( - await subject.getUserPart() !== user.username + await subject.getUserPart() !== user.username && + await subject.isUserDirectory() ) { this.log.noticeme('THIS HAPPEN'); const ll_readshares = new LLReadShares(); diff --git a/src/backend/src/filesystem/ll_operations/ll_readshares.js b/src/backend/src/filesystem/ll_operations/ll_readshares.js index a27e31d5e7..c797d65f0a 100644 --- a/src/backend/src/filesystem/ll_operations/ll_readshares.js +++ b/src/backend/src/filesystem/ll_operations/ll_readshares.js @@ -16,8 +16,12 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ +const { get_user } = require("../../helpers"); +const { PermissionUtil } = require("../../services/auth/PermissionService"); +const { DB_WRITE } = require("../../services/database/consts"); const { Context } = require("../../util/context"); const { TYPE_DIRECTORY } = require("../FSNodeContext"); +const { NodeUIDSelector } = require("../node/selectors"); const { LLFilesystemOperation } = require("./definitions"); const { LLReadDir } = require("./ll_readdir"); @@ -32,57 +36,56 @@ class LLReadShares extends LLFilesystemOperation { `; async _run () { + const { subject, user, actor, depth = 0 } = this.values; + + const svc = this.context.get('services'); + + const svc_fs = svc.get('filesystem'); + const svc_acl = svc.get('acl'); + const db = svc.get('database').get(DB_WRITE, 'll_readshares'); + + const issuer_username = await subject.getUserPart(); + const issuer_user = await get_user({ username: issuer_username }); + const rows = await db.read( + 'SELECT DISTINCT permission FROM `user_to_user_permissions` ' + + 'WHERE `holder_user_id` = ? AND `issuer_user_id` = ? ' + + 'AND `permission` LIKE ?', + [user.id, issuer_user.id, 'fs:%'] + ); + + const fsentry_uuids = []; + for ( const row of rows ) { + const parts = PermissionUtil.split(row.permission); + fsentry_uuids.push(parts[1]); + } + const results = []; - const stats = await this.recursive_part(results, this.values); - // console.log('LL_READ_SHARES_STATS !!!!!', stats); - - return results; - } - - async recursive_part (results, { subject, user, actor, depth = 0 }) { - actor = actor || Context.get('actor'); + const ll_readdir = new LLReadDir(); - const children = await ll_readdir.run({ - subject, user, + let interm_results = await ll_readdir.run({ + subject, + actor, + user, no_thumbs: true, no_assocs: true, no_acl: true, }); - - const svc = Context.get('services'); - const svc_acl = svc.get('acl'); - - const promises = []; - - for ( const child of children ) { - // If we have at least see permission: terminal node - const acl_result = await svc_acl.check(actor, child, 'see'); - console.log( - '\x1B[31;1mWHAT DIS?\x1B[0m', - actor, - child.entry?.path, - child.selectors_[0].describe(), - acl_result, - ) - if ( acl_result ) { - results.push(child); - continue; - } - - if ( await child.get('type') !== TYPE_DIRECTORY ) { - continue; - } - - const p = this.recursive_part(results, { - subject: child, - user, - depth: depth + 1, - }); - promises.push(p); + + // Clone interm_results in case ll_readdir ever implements caching + interm_results = interm_results.slice(); + + for ( const fsentry_uuid of fsentry_uuids ) { + const node = await svc_fs.node(new NodeUIDSelector(fsentry_uuid)); + if ( ! node ) continue; + interm_results.push(node); } - - const stats = await Promise.all(promises); - return Math.max(depth, ...stats); + + for ( const node of interm_results ) { + if ( ! await svc_acl.check(actor, node, 'see') ) continue; + results.push(node); + } + + return results; } } From 22dd42ef7f64d32ada0c776287f53a80a4470315 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 13 Nov 2024 23:13:45 -0500 Subject: [PATCH 1146/2119] fix: attempt at fixing broadcast --- src/backend/src/Kernel.js | 2 +- src/backend/src/modules/broadcast/BroadcastService.js | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/backend/src/Kernel.js b/src/backend/src/Kernel.js index 4acd43fd5d..68cb207eb0 100644 --- a/src/backend/src/Kernel.js +++ b/src/backend/src/Kernel.js @@ -82,7 +82,7 @@ class Kernel extends AdvancedBase { // const app = express(); const config = require('./config'); - globalThis.ll = () => {}; + globalThis.ll = o => o; globalThis.xtra_log = () => {}; if ( config.env === 'dev' ) { globalThis.ll = o => { diff --git a/src/backend/src/modules/broadcast/BroadcastService.js b/src/backend/src/modules/broadcast/BroadcastService.js index 4344b1030f..de7079b68d 100644 --- a/src/backend/src/modules/broadcast/BroadcastService.js +++ b/src/backend/src/modules/broadcast/BroadcastService.js @@ -56,7 +56,11 @@ class BroadcastService extends BaseService { if ( meta.from_outside ) return; for ( const peer of this.peers_ ) { - peer.send({ key, data, meta }); + try { + peer.send({ key, data, meta }); + } catch (e) { + // + } } } From 665471f9f02b1f1163edb47932a31f52577ee7df Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 13 Nov 2024 23:25:44 -0500 Subject: [PATCH 1147/2119] fix: add mixxing context to BroadcastService --- src/backend/src/modules/broadcast/BroadcastService.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/backend/src/modules/broadcast/BroadcastService.js b/src/backend/src/modules/broadcast/BroadcastService.js index de7079b68d..95ce0dd7be 100644 --- a/src/backend/src/modules/broadcast/BroadcastService.js +++ b/src/backend/src/modules/broadcast/BroadcastService.js @@ -20,6 +20,7 @@ const { AdvancedBase } = require("@heyputer/putility"); const BaseService = require("../../services/BaseService"); const { CLink } = require("./connection/CLink"); const { SLink } = require("./connection/SLink"); +const { Context } = require("../../util/context"); class BroadcastService extends BaseService { static MODULES = { @@ -96,7 +97,10 @@ class BroadcastService extends BaseService { } meta.from_outside = true; - svc_event.emit(key, data, meta); + const context = Context.get(undefined, { allow_fallback: true }); + context.arun(async () => { + await svc_event.emit(key, data, meta); + }); }); }); From 9d7987fae50b510f1836e306d5f6f497a560de08 Mon Sep 17 00:00:00 2001 From: jelveh Date: Thu, 14 Nov 2024 09:37:06 -0800 Subject: [PATCH 1148/2119] fix: disabled sortable on sharing section in the sidebar --- src/gui/src/UI/UIWindow.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/gui/src/UI/UIWindow.js b/src/gui/src/UI/UIWindow.js index f681ac8922..252e2e5bcd 100644 --- a/src/gui/src/UI/UIWindow.js +++ b/src/gui/src/UI/UIWindow.js @@ -1097,7 +1097,7 @@ async function UIWindow(options) { // don't show current user's folder! if(shared_user.name === window.user.username) continue; - ht += `
Date: Thu, 14 Nov 2024 09:55:39 -0800 Subject: [PATCH 1149/2119] Update UIWindow.js --- src/gui/src/UI/UIWindow.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/UI/UIWindow.js b/src/gui/src/UI/UIWindow.js index 252e2e5bcd..ebfee3d5fa 100644 --- a/src/gui/src/UI/UIWindow.js +++ b/src/gui/src/UI/UIWindow.js @@ -1103,7 +1103,7 @@ async function UIWindow(options) { title="${html_encode(shared_user.name)}" data-is_shared="1"> ${shared_user.name} -
`; +
`; } } $(el_window).find('.window-sidebar').append(ht); From 3f3f4e6cb9fd3faad2e87fbf9ea1f09b934151ca Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 14 Nov 2024 13:57:58 -0500 Subject: [PATCH 1150/2119] fix: un-awked notif check in wrong place --- src/backend/src/services/WebServerService.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/backend/src/services/WebServerService.js b/src/backend/src/services/WebServerService.js index 0960bbc66c..88ce271134 100644 --- a/src/backend/src/services/WebServerService.js +++ b/src/backend/src/services/WebServerService.js @@ -182,10 +182,10 @@ class WebServerService extends BaseService { }); socket.on('trash.is_empty', (msg) => { socket.broadcast.to(socket.user.id).emit('trash.is_empty', msg); - const svc_event = this.services.get('event'); - svc_event.emit('web.socket.user-connected', { - user: socket.user - }); + }); + const svc_event = this.services.get('event'); + svc_event.emit('web.socket.user-connected', { + user: socket.user }); }); From 00e0fb350a5f19361e23299535a7b6ad0d4ac09d Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 14 Nov 2024 13:59:42 -0500 Subject: [PATCH 1151/2119] dev: add notif.ack message --- src/backend/src/services/NotificationService.js | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/backend/src/services/NotificationService.js b/src/backend/src/services/NotificationService.js index fda6b5a6c1..9314838cd7 100644 --- a/src/backend/src/services/NotificationService.js +++ b/src/backend/src/services/NotificationService.js @@ -70,6 +70,8 @@ class NotificationService extends BaseService { app.use('/notif', router); router.use(auth2); + + const svc_event = this.services.get('event'); [['ack','acknowledged'],['read','read']].forEach(([ep_name, col_name]) => { Endpoint({ @@ -92,6 +94,13 @@ class NotificationService extends BaseService { 'LIMIT 1', [ack_ts, req.body.uid, req.user.id], ); + + svc_event.emit('outer.gui.notif.ack', { + user_id_list: [req.user.id], + response: { + uid: req.body.uid, + }, + }); res.json({}); } From 9e303a2f7c7bf6ac9032e6c9b87bffd3126baa86 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 14 Nov 2024 15:18:21 -0500 Subject: [PATCH 1152/2119] fix: occasional db error from notics --- src/backend/src/om/entitystorage/NotificationES.js | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/backend/src/om/entitystorage/NotificationES.js b/src/backend/src/om/entitystorage/NotificationES.js index 334a330e1c..5c3eb3a916 100644 --- a/src/backend/src/om/entitystorage/NotificationES.js +++ b/src/backend/src/om/entitystorage/NotificationES.js @@ -16,6 +16,7 @@ * You should have received a copy of the GNU Affero General Public License * along with this program. If not, see . */ +const { nou } = require("../../util/langutil"); const { Eq, IsNotNull } = require("../query/query"); const { BaseES } = require("./BaseES"); @@ -44,7 +45,14 @@ class NotificationES extends BaseES { } }, async read_transform (entity) { - await entity.set('value', JSON.parse(await entity.get('value') ?? '{}')); + let value = await entity.get('value'); + if ( typeof value === 'string' ) { + value = JSON.parse(value); + } + if ( nou(value) ) { + value = {}; + } + await entity.set('value', value); } } } From a6650ee2d8074aeb7c476e5572334853f1b6d7e8 Mon Sep 17 00:00:00 2001 From: jelveh Date: Thu, 14 Nov 2024 12:52:15 -0800 Subject: [PATCH 1153/2119] feat: handle `notif.ack` in desktop --- src/gui/src/UI/UIDesktop.js | 13 +++++++++++++ src/gui/src/UI/UINotification.js | 2 +- src/gui/src/css/style.css | 3 ++- 3 files changed, 16 insertions(+), 2 deletions(-) diff --git a/src/gui/src/UI/UIDesktop.js b/src/gui/src/UI/UIDesktop.js index 20f5415e28..86c97f3544 100644 --- a/src/gui/src/UI/UIDesktop.js +++ b/src/gui/src/UI/UIDesktop.js @@ -46,6 +46,13 @@ import UIWindowSearch from "./UIWindowSearch.js" async function UIDesktop(options){ let h = ''; + // Set up the desktop channel for communication between different tabs in the same browser + window.channel = new BroadcastChannel('puter-desktop-channel'); + channel.onmessage = function(e){ + } + + // channel.postMessage({'hello': 'world'}); + // connect socket. window.socket = io(window.gui_origin + '/', { auth: { @@ -122,6 +129,7 @@ async function UIDesktop(options){ text: notification.text, icon: icon, value: notification, + uid, close: async () => { await fetch(`${window.api_origin}/notif/mark-ack`, { method: 'POST', @@ -160,6 +168,7 @@ async function UIDesktop(options){ icon, title: notification.title, text: notification.text ?? notification.title, + uid: notif_info.uid, close: async () => { await fetch(`${window.api_origin}/notif/mark-ack`, { method: 'POST', @@ -176,6 +185,10 @@ async function UIDesktop(options){ } }); + window.socket.on('notif.ack', ({ uid }) => { + $(`.notification[data-uid="${uid}"]`).remove(); + }); + window.socket.on('app.opened', async (app) => { // don't update if this is the original client that initiated the action if(app.original_client_socket_id === window.socket.id) diff --git a/src/gui/src/UI/UINotification.js b/src/gui/src/UI/UINotification.js index 587d0a813a..47828b993d 100644 --- a/src/gui/src/UI/UINotification.js +++ b/src/gui/src/UI/UINotification.js @@ -22,7 +22,7 @@ function UINotification(options){ options.text = options.text ?? ''; let h = ''; - h += `
`; + h += `
`; h += ``; h += `
`; h += ``; diff --git a/src/gui/src/css/style.css b/src/gui/src/css/style.css index 1849c3a9d7..ec35754839 100644 --- a/src/gui/src/css/style.css +++ b/src/gui/src/css/style.css @@ -1173,7 +1173,7 @@ span.header-sort-icon img { min-width: 170px; height: calc(100% - 28px); float: left; - border-right: 1px solid #CCC; + border-right: 0.5px solid #CCC; padding: 15px 10px; box-sizing: border-box; background-color: hsla(var(--window-sidebar-hue), @@ -1182,6 +1182,7 @@ span.header-sort-icon img { calc(0.5 + 0.5*var(--window-sidebar-alpha))); overflow-y: scroll; margin-top: 1px; + box-shadow: inset -4px 0 8px -8px rgba(0, 0, 0, 0.3); } .window-sidebar .ui-resizable-e { From 0cbe0139d7f306ce62992f1eda94d99e09b32df8 Mon Sep 17 00:00:00 2001 From: jelveh Date: Thu, 14 Nov 2024 14:08:49 -0800 Subject: [PATCH 1154/2119] feat: when sharing, users can choose between 'viewer' and 'editor' for permissions --- src/gui/src/IPC.js | 2 +- src/gui/src/UI/UIDesktop.js | 4 ++-- src/gui/src/UI/UIWindowShare.js | 13 +++++++++++-- src/gui/src/helpers.js | 2 +- src/gui/src/helpers/refresh_item_container.js | 2 +- 5 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/gui/src/IPC.js b/src/gui/src/IPC.js index 18580da0f0..bd8132dad5 100644 --- a/src/gui/src/IPC.js +++ b/src/gui/src/IPC.js @@ -1316,7 +1316,7 @@ const ipc_listener = async (event, handled) => { // now add new items UIItem({ appendTo: $(`.item-container[data-path="${html_encode(path.dirname(target_path))}" i]`), - immutable: res.immutable, + immutable: res.immutable || res.writable === false, associated_app_name: res.associated_app?.name, path: target_path, icon: await item_icon(res), diff --git a/src/gui/src/UI/UIDesktop.js b/src/gui/src/UI/UIDesktop.js index 86c97f3544..d62b104fee 100644 --- a/src/gui/src/UI/UIDesktop.js +++ b/src/gui/src/UI/UIDesktop.js @@ -351,7 +351,7 @@ async function UIDesktop(options){ // create new item on matching containers UIItem({ appendTo: $(`.item-container[data-path='${html_encode(dest_path)}' i]`), - immutable: fsentry.immutable, + immutable: fsentry.immutable || fsentry.writable === false, uid: fsentry.uid, path: fsentry.path, icon: await item_icon(fsentry), @@ -526,7 +526,7 @@ async function UIDesktop(options){ UIItem({ appendTo: $(`.item-container[data-path='${html_encode(item.dirpath)}' i]`), uid: item.uid, - immutable: item.immutable, + immutable: item.immutable || item.writable === false, associated_app_name: item.associated_app?.name, path: item.path, icon: await item_icon(item), diff --git a/src/gui/src/UI/UIWindowShare.js b/src/gui/src/UI/UIWindowShare.js index e406362654..506e9477e3 100644 --- a/src/gui/src/UI/UIWindowShare.js +++ b/src/gui/src/UI/UIWindowShare.js @@ -79,9 +79,15 @@ async function UIWindowShare(items, recipient){ h += ``; h += `
`; // Username/email - h += ``; + h += ``; + // type + h += ``; + // Share - h += `` + h += `` h += `
`; h += `
`; h += ``; @@ -245,6 +251,9 @@ async function UIWindowShare(items, recipient){ let share_result; let access_level = 'write'; + if($(el_window).find('.access-type').val() === 'Viewer') + access_level = 'read'; + $.ajax({ url: puter.APIOrigin + "/share", type: "POST", diff --git a/src/gui/src/helpers.js b/src/gui/src/helpers.js index 7c6a010fb8..2657bcef53 100644 --- a/src/gui/src/helpers.js +++ b/src/gui/src/helpers.js @@ -1485,7 +1485,7 @@ window.move_items = async function(el_items, dest_path, is_undo = false){ // create new item on matching containers const options = { appendTo: $(`.item-container[data-path="${html_encode(dest_path)}" i]`), - immutable: fsentry.immutable, + immutable: fsentry.immutable || (fsentry.writable === false), associated_app_name: fsentry.associated_app?.name, uid: fsentry.uid, path: fsentry.path, diff --git a/src/gui/src/helpers/refresh_item_container.js b/src/gui/src/helpers/refresh_item_container.js index 3de003295d..a4cdc6f8e9 100644 --- a/src/gui/src/helpers/refresh_item_container.js +++ b/src/gui/src/helpers/refresh_item_container.js @@ -175,7 +175,7 @@ const refresh_item_container = function(el_item_container, options){ UIItem({ appendTo: el_item_container, uid: fsentry.uid, - immutable: fsentry.immutable, + immutable: fsentry.immutable || fsentry.writable === false, associated_app_name: fsentry.associated_app?.name, path: item_path, icon: await item_icon(fsentry), From db79a72daab5460bc8e24f6e16c6280291b2f6fe Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 14 Nov 2024 17:31:42 -0500 Subject: [PATCH 1155/2119] feat(backend): add comments for fsentries --- src/backend/src/CoreModule.js | 3 + src/backend/src/services/CommentService.js | 156 ++++++++++++++++++ .../database/SqliteDatabaseAccessService.js | 3 + .../database/sqlite_setup/0030_comments.sql | 43 +++++ 4 files changed, 205 insertions(+) create mode 100644 src/backend/src/services/CommentService.js create mode 100644 src/backend/src/services/database/sqlite_setup/0030_comments.sql diff --git a/src/backend/src/CoreModule.js b/src/backend/src/CoreModule.js index 3a1f30bfbd..0394601fb7 100644 --- a/src/backend/src/CoreModule.js +++ b/src/backend/src/CoreModule.js @@ -344,6 +344,9 @@ const install = async ({ services, app, useapi, modapi }) => { const { DriverUsagePolicyService } = require('./services/drivers/DriverUsagePolicyService'); services.registerService('driver-usage-policy', DriverUsagePolicyService); + + const { CommentService } = require('./services/CommentService'); + services.registerService('comment', CommentService); } const install_legacy = async ({ services }) => { diff --git a/src/backend/src/services/CommentService.js b/src/backend/src/services/CommentService.js new file mode 100644 index 0000000000..f71b1a3388 --- /dev/null +++ b/src/backend/src/services/CommentService.js @@ -0,0 +1,156 @@ +const APIError = require("../api/APIError"); +const FSNodeParam = require("../api/filesystem/FSNodeParam"); +const configurable_auth = require("../middleware/configurable_auth"); +const { Endpoint } = require("../util/expressutil"); +const BaseService = require("./BaseService"); +const { DB_WRITE } = require("./database/consts"); + +class CommentService extends BaseService { + static MODULES = { + uuidv4: require('uuid').v4, + } + _init () { + const svc_database = this.services.get('database'); + this.db = svc_database.get(DB_WRITE, 'notification'); + } + ['__on_install.routes'] (_, { app }) { + const r_comment = (() => { + const require = this.require; + const express = require('express'); + return express.Router() + })(); + + app.use('/comment', r_comment); + + Endpoint({ + route: '/comment', + methods: ['POST'], + mw: [configurable_auth()], + handler: async (req, res) => { + const comment = await this.create_comment_({ req, res }); + + if ( ! req.body.on ) { + throw APIError.create('field_missing', null, { key: 'on' }); + } + + const on_ = req.body.on; + + if ( on_.startsWith('fs:') ) { + const node = await (new FSNodeParam('path')).consolidate({ + req, + getParam: () => on_.slice(3), + }); + + if ( req.body.version ) { + // this.attach_comment_to_fsentry_version({ + // node, comment, version, + // }); + res.status(400).send('not implemented yet'); + return; + } else { + this.attach_comment_to_fsentry({ + node, comment, + }); + } + } + + res.json({ + uid: comment.uid, + }); + } + }).attach(app); + + Endpoint({ + route: '/comment/list', + methods: ['POST'], + mw: [configurable_auth()], + handler: async (req, res) => { + if ( ! req.body.on ) { + throw APIError.create('field_missing', null, { key: 'on' }); + } + + const on_ = req.body.on; + + let comments; + + if ( on_.startsWith('fs:') ) { + const node = await (new FSNodeParam('path')).consolidate({ + req, + getParam: () => on_.slice(3), + }); + + if ( req.body.version ) { + // this.attach_comment_to_fsentry_version({ + // node, comment, version, + // }); + res.status(400).send('not implemented yet'); + return; + } else { + comments = await this.get_comments_for_fsentry({ + node, + }); + } + } + + const client_safe_comments = []; + for ( const comment of comments ) { + client_safe_comments.push({ + uid: comment.uid, + text: comment.text, + created: comment.created_at, + }); + } + + res.json({ + comments: client_safe_comments, + }); + } + }).attach(app); + + } + + async create_comment_ ({ req, res }) { + if ( ! req.body.text ) { + throw APIError.create('field_missing', null, { key: 'text' }); + } + + const text = req.body.text; + + const uuid = this.modules.uuidv4(); + + const result = await this.db.write( + 'INSERT INTO `user_comments` ' + + '(`uid`, `user_id`, `metadata`, `text`) ' + + 'VALUES (?, ?, ?, ?)', + [uuid, req.user.id, '{}', text], + ); + + return { + id: result.insertId, + uid: uuid, + }; + } + + async attach_comment_to_fsentry ({ node, comment }) { + await this.db.write( + 'INSERT INTO `user_fsentry_comments` ' + + '(`user_comment_id`, `fsentry_id`) ' + + 'VALUES (?, ?)', + [comment.id, await node.get('mysql-id')], + ); + } + + async get_comments_for_fsentry ({ node }) { + const comments = await this.db.read( + 'SELECT * FROM `user_comments` ' + + 'JOIN `user_fsentry_comments` ' + + 'ON `user_comments`.`id` = `user_fsentry_comments`.`user_comment_id` ' + + 'WHERE `fsentry_id` = ?', + [await node.get('mysql-id')], + ); + + return comments; + } +} + +module.exports = { CommentService }; diff --git a/src/backend/src/services/database/SqliteDatabaseAccessService.js b/src/backend/src/services/database/SqliteDatabaseAccessService.js index 6ba6ae10e1..2ea7649ccf 100644 --- a/src/backend/src/services/database/SqliteDatabaseAccessService.js +++ b/src/backend/src/services/database/SqliteDatabaseAccessService.js @@ -132,6 +132,9 @@ class SqliteDatabaseAccessService extends BaseDatabaseAccessService { [26, [ '0029_emulator_priv.sql', ]], + [27, [ + '0030_comments.sql', + ]], ]; // Database upgrade logic diff --git a/src/backend/src/services/database/sqlite_setup/0030_comments.sql b/src/backend/src/services/database/sqlite_setup/0030_comments.sql new file mode 100644 index 0000000000..238572b245 --- /dev/null +++ b/src/backend/src/services/database/sqlite_setup/0030_comments.sql @@ -0,0 +1,43 @@ +CREATE TABLE `user_comments` ( + `id` INTEGER PRIMARY KEY, + `uid` TEXT NOT NULL UNIQUE, + `user_id` INTEGER NOT NULL, + `metadata` JSON DEFAULT NULL, + `text` TEXT NOT NULL, + `created_at` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + FOREIGN KEY("user_id") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE INDEX `idx_user_comments_uid` ON `user_comments` (`uid`); + +CREATE TABLE `user_fsentry_comments` ( + `id` INTEGER PRIMARY KEY, + `user_comment_id` INTEGER NOT NULL, + `fsentry_id` INTEGER NOT NULL, + FOREIGN KEY("user_comment_id") REFERENCES "user_comments" ("id") ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY("fsentry_id") REFERENCES "fsentries" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE TABLE `user_fsentry_version_comments` ( + `id` INTEGER PRIMARY KEY, + `user_comment_id` INTEGER NOT NULL, + `fsentry_version_id` INTEGER NOT NULL, + FOREIGN KEY("user_comment_id") REFERENCES "user_comments" ("id") ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY("fsentry_version_id") REFERENCES "fsentry_versions" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE TABLE `user_group_comments` ( + `id` INTEGER PRIMARY KEY, + `user_comment_id` INTEGER NOT NULL, + `group_id` INTEGER NOT NULL, + FOREIGN KEY("user_comment_id") REFERENCES "user_comments" ("id") ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY("group_id") REFERENCES "group" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); + +CREATE TABLE `user_user_comments` ( + `id` INTEGER PRIMARY KEY, + `user_comment_id` INTEGER NOT NULL, + `user_id` INTEGER NOT NULL, + FOREIGN KEY("user_comment_id") REFERENCES "user_comments" ("id") ON DELETE CASCADE ON UPDATE CASCADE, + FOREIGN KEY("user_id") REFERENCES "user" ("id") ON DELETE CASCADE ON UPDATE CASCADE +); From cf4b6aa1c24d936f9a42ca1e2945eea40939c970 Mon Sep 17 00:00:00 2001 From: jelveh Date: Thu, 14 Nov 2024 14:45:35 -0800 Subject: [PATCH 1156/2119] feat: in Share window, display access level next to recipient --- src/gui/src/UI/UIWindowShare.js | 22 ++++++++++++++++++++-- src/gui/src/css/style.css | 22 ++++++++++++++++++++-- 2 files changed, 40 insertions(+), 4 deletions(-) diff --git a/src/gui/src/UI/UIWindowShare.js b/src/gui/src/UI/UIWindowShare.js index 506e9477e3..1421865c68 100644 --- a/src/gui/src/UI/UIWindowShare.js +++ b/src/gui/src/UI/UIWindowShare.js @@ -164,11 +164,11 @@ async function UIWindowShare(items, recipient){ //check if this user has been printed here before, important for multiple items if(!printed_users.includes(fsentry.owner.username)){ perm_list += `
` + perm_list += `
owner
`; if(fsentry.owner.username === window.user.username) perm_list += `You (${fsentry.owner.email ?? fsentry.owner.username})`; else perm_list += fsentry.owner.email ?? fsentry.owner.username; - perm_list += `
owner
`; perm_list += `
`; // add this user to the list of printed users printed_users.push(fsentry.owner.username); @@ -182,9 +182,19 @@ async function UIWindowShare(items, recipient){ //check if this user has been printed here before, important for multiple items if(!printed_users.includes(perm.user.username)){ perm_list += `
` + // viewer/editor + perm_list += `
`; + if(perm.access === 'read') + perm_list += `viewer`; + else if(perm.access === 'write') + perm_list += `editor`; + perm_list += `
`; + // username perm_list += `${perm.user.email ?? perm.user.username}`; perm_list += `
`; + perm_list += `
`; + // add this user to the list of printed users printed_users.push(perm.user.username); } @@ -250,7 +260,7 @@ async function UIWindowShare(items, recipient){ let cancelled_due_to_error = false; let share_result; let access_level = 'write'; - + if($(el_window).find('.access-type').val() === 'Viewer') access_level = 'read'; @@ -290,6 +300,14 @@ async function UIWindowShare(items, recipient){ // append recipient to list let perm_list = ''; perm_list += `
` + // viewer/editor + perm_list += `
`; + if(access_level === 'read') + perm_list += `viewer`; + else if(access_level === 'write') + perm_list += `editor`; + perm_list += `
`; + // recipient username perm_list += `${recipient_username}`; perm_list += `
`; perm_list += `
`; diff --git a/src/gui/src/css/style.css b/src/gui/src/css/style.css index ec35754839..0d5957920e 100644 --- a/src/gui/src/css/style.css +++ b/src/gui/src/css/style.css @@ -1978,6 +1978,7 @@ label { -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; color: #2f3f53; + font-size: 14px; } .unsupported-device-notice { @@ -2112,10 +2113,26 @@ label { .permission-owner-badge { background-color: #9dacbd; - border-radius: 2px; +} + +.permission-editor-badge{ + background-color: #007cff; +} + +.permission-viewer-badge{ + background-color: #41c95d; +} + +.permission-owner-badge, .permission-editor-badge, .permission-viewer-badge { + display: inline-block; + width: 45px; + text-align: center; padding: 2px 4px; + border-radius: 2px; color: white; - font-size: 13px; + font-size: 12px; + margin-right: 10px; + margin-top: -2px; } .remove-permission-link:hover, .disassociate-website-link:hover { @@ -2130,6 +2147,7 @@ label { border-radius: 3px; border: 1px solid #e0e0e0; color: #65707b; + font-size: 13px; } .remove-permission-icon { From 085d808817e985f2bc52b7a91a31991ca3b2e89f Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 14 Nov 2024 18:09:38 -0500 Subject: [PATCH 1157/2119] fix: add username to comments --- src/backend/src/services/CommentService.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/backend/src/services/CommentService.js b/src/backend/src/services/CommentService.js index f71b1a3388..3420ccd30e 100644 --- a/src/backend/src/services/CommentService.js +++ b/src/backend/src/services/CommentService.js @@ -1,5 +1,6 @@ const APIError = require("../api/APIError"); const FSNodeParam = require("../api/filesystem/FSNodeParam"); +const { get_user } = require("../helpers"); const configurable_auth = require("../middleware/configurable_auth"); const { Endpoint } = require("../util/expressutil"); const BaseService = require("./BaseService"); @@ -98,6 +99,9 @@ class CommentService extends BaseService { uid: comment.uid, text: comment.text, created: comment.created_at, + user: { + username: comment.user?.username, + }, }); } @@ -149,6 +153,12 @@ class CommentService extends BaseService { [await node.get('mysql-id')], ); + for ( const comment of comments ) { + const user_id = comment.user_id; + const user = await get_user({ id: user_id }); + comment.user = user; + } + return comments; } } From d0f16c810509c7e4e8acba3408c71655664cfad2 Mon Sep 17 00:00:00 2001 From: jelveh Date: Thu, 14 Nov 2024 15:38:26 -0800 Subject: [PATCH 1158/2119] fix: don't allow sharing with recipient just shared with --- src/gui/src/UI/UIWindowShare.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/UI/UIWindowShare.js b/src/gui/src/UI/UIWindowShare.js index 1421865c68..f79c9c1b77 100644 --- a/src/gui/src/UI/UIWindowShare.js +++ b/src/gui/src/UI/UIWindowShare.js @@ -299,7 +299,7 @@ async function UIWindowShare(items, recipient){ // append recipient to list let perm_list = ''; - perm_list += `
` + perm_list += `
` // viewer/editor perm_list += `
`; if(access_level === 'read') From b1ffb8eca13520fa41833f5361ff6a6505a80a2c Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 14 Nov 2024 19:25:57 -0500 Subject: [PATCH 1159/2119] fix: new sessions miss notifications --- src/backend/src/services/NotificationService.js | 15 +++++++++++++-- src/backend/src/services/WebServerService.js | 8 +++++--- src/gui/src/UI/UIDesktop.js | 1 + 3 files changed, 19 insertions(+), 5 deletions(-) diff --git a/src/backend/src/services/NotificationService.js b/src/backend/src/services/NotificationService.js index 9314838cd7..89412e36b7 100644 --- a/src/backend/src/services/NotificationService.js +++ b/src/backend/src/services/NotificationService.js @@ -35,6 +35,10 @@ class NotificationService extends BaseService { express: require('express'), } + _construct () { + this.merged_on_user_connected_ = {}; + } + async _init () { const svc_database = this.services.get('database'); this.db = svc_database.get(DB_WRITE, 'notification'); @@ -109,6 +113,13 @@ class NotificationService extends BaseService { } async on_user_connected ({ user }) { + if ( this.merged_on_user_connected_[user.uuid] ) { + clearTimeout(this.merged_on_user_connected_[user.uuid]); + } + this.merged_on_user_connected_[user.uuid] = + setTimeout(() => this.do_on_user_connected({ user }), 2000); + } + async do_on_user_connected ({ user }) { // query the users unread notifications const notifications = await this.db.read( 'SELECT * FROM `notification` ' + @@ -116,7 +127,7 @@ class NotificationService extends BaseService { 'ORDER BY created_at ASC', [user.id] ); - + // set all the notifications to "shown" const shown_ts = Math.floor(Date.now() / 1000); await this.db.write( @@ -140,7 +151,7 @@ class NotificationService extends BaseService { notification: notif.value, }) } - + // send the unread notifications to gui const svc_event = this.services.get('event'); svc_event.emit('outer.gui.notif.unreads', { diff --git a/src/backend/src/services/WebServerService.js b/src/backend/src/services/WebServerService.js index 88ce271134..fc42ee05e2 100644 --- a/src/backend/src/services/WebServerService.js +++ b/src/backend/src/services/WebServerService.js @@ -183,9 +183,11 @@ class WebServerService extends BaseService { socket.on('trash.is_empty', (msg) => { socket.broadcast.to(socket.user.id).emit('trash.is_empty', msg); }); - const svc_event = this.services.get('event'); - svc_event.emit('web.socket.user-connected', { - user: socket.user + socket.on('puter_is_actually_open', (msg) => { + const svc_event = this.services.get('event'); + svc_event.emit('web.socket.user-connected', { + user: socket.user + }); }); }); diff --git a/src/gui/src/UI/UIDesktop.js b/src/gui/src/UI/UIDesktop.js index d62b104fee..81ed4c93d7 100644 --- a/src/gui/src/UI/UIDesktop.js +++ b/src/gui/src/UI/UIDesktop.js @@ -66,6 +66,7 @@ async function UIDesktop(options){ window.socket.on('connect', function(){ // console.log('GUI Socket: Connected', window.socket.id); + window.socket.emit('puter_is_actually_open'); }); window.socket.on('reconnect', function(){ From 045259cefbe24e3f52fe3840e4975d3243e99957 Mon Sep 17 00:00:00 2001 From: jelveh Date: Thu, 14 Nov 2024 17:19:21 -0800 Subject: [PATCH 1160/2119] feat: show unread notification count in the browser tab's title --- src/gui/src/UI/UIDesktop.js | 1 + src/gui/src/UI/UINotification.js | 28 ++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/gui/src/UI/UIDesktop.js b/src/gui/src/UI/UIDesktop.js index 81ed4c93d7..9c733886cc 100644 --- a/src/gui/src/UI/UIDesktop.js +++ b/src/gui/src/UI/UIDesktop.js @@ -188,6 +188,7 @@ async function UIDesktop(options){ window.socket.on('notif.ack', ({ uid }) => { $(`.notification[data-uid="${uid}"]`).remove(); + update_tab_notif_count_badge(); }); window.socket.on('app.opened', async (app) => { diff --git a/src/gui/src/UI/UINotification.js b/src/gui/src/UI/UINotification.js index 47828b993d..c5b64fe529 100644 --- a/src/gui/src/UI/UINotification.js +++ b/src/gui/src/UI/UINotification.js @@ -36,6 +36,8 @@ function UINotification(options){ $('.notification-container').prepend(h); + update_tab_notif_count_badge(); + const el_notification = document.getElementById(`ui-notification__${window.global_element_id}`); // now wrap it in a div @@ -106,6 +108,8 @@ function UINotification(options){ }else{ $('.notification-container').addClass('has-multiple'); } + + update_tab_notif_count_badge(); }, 500); } // Show Notification @@ -131,10 +135,34 @@ $(document).on('click', '.notifications-close-all', function(e){ }, 300); // remove the 'has-multiple' class $('.notification-container').removeClass('has-multiple'); + + // update tab notification count badge + update_tab_notif_count_badge(); + // prevent default e.stopPropagation(); e.preventDefault(); return false; }) +window.update_tab_notif_count_badge = function(){ + // count open notifications + let count = $('.notification').length; + + // see if title is in the format "(n) Title" + let title = document.title; + let titleMatch = title.match(/^\((\d+)\) (.*)/); + if(titleMatch){ + // remove the count + title = titleMatch[2]; + } + + // if there are notifications, add the count to the title + if(count > 0){ + document.title = `(${count}) ${title}`; + }else{ + document.title = title; + } +} + export default UINotification; \ No newline at end of file From 69bfa601993eb6c47c3555b92559878d76ba749e Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 15 Nov 2024 12:08:40 -0500 Subject: [PATCH 1161/2119] fix: only allow UserActorType for ShareService --- src/backend/src/services/ShareService.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/backend/src/services/ShareService.js b/src/backend/src/services/ShareService.js index 2456dd9515..0711d4fc6a 100644 --- a/src/backend/src/services/ShareService.js +++ b/src/backend/src/services/ShareService.js @@ -261,6 +261,9 @@ class ShareService extends BaseService { ], handler: async (req, res) => { const actor = Actor.adapt(req.user); + if ( ! (actor.type instanceof UserActorType) ) { + throw APIError.create('forbidden'); + } return await share_sequence.call(this, { actor, req, res, }); From 2eaf1080d66b08bfb45553803452633133cda028 Mon Sep 17 00:00:00 2001 From: 4nshuman Date: Sat, 9 Nov 2024 15:15:23 +0530 Subject: [PATCH 1162/2119] added a chime playback --- src/gui/src/initgui.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/gui/src/initgui.js b/src/gui/src/initgui.js index f37044d041..35cd564902 100644 --- a/src/gui/src/initgui.js +++ b/src/gui/src/initgui.js @@ -152,6 +152,11 @@ if(jQuery){ }; } +window.playStartUpChime = ()=>{ + let audio = new Audio('/src/audio/puter_chime.mp3'); + audio.play(); +} + window.initgui = async function(options){ let url = new URL(window.location); url = url.href; From 4885a76a756ca85e177e93bd1ecfc053d6975122 Mon Sep 17 00:00:00 2001 From: 4nshuman Date: Sat, 9 Nov 2024 15:15:57 +0530 Subject: [PATCH 1163/2119] added event listener to play chime on the first click --- src/gui/src/initgui.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/gui/src/initgui.js b/src/gui/src/initgui.js index 35cd564902..9abf30d2ee 100644 --- a/src/gui/src/initgui.js +++ b/src/gui/src/initgui.js @@ -155,8 +155,11 @@ if(jQuery){ window.playStartUpChime = ()=>{ let audio = new Audio('/src/audio/puter_chime.mp3'); audio.play(); + document.removeEventListener("click", window.playStartUpChime); } +document.addEventListener("click", window.playStartUpChime); + window.initgui = async function(options){ let url = new URL(window.location); url = url.href; From 1919cb3d99a9643dd16c91c0c22f68591ffa4c4d Mon Sep 17 00:00:00 2001 From: 4nshuman Date: Sat, 9 Nov 2024 15:16:04 +0530 Subject: [PATCH 1164/2119] . --- src/gui/src/initgui.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gui/src/initgui.js b/src/gui/src/initgui.js index 9abf30d2ee..2652c6fb2e 100644 --- a/src/gui/src/initgui.js +++ b/src/gui/src/initgui.js @@ -155,7 +155,6 @@ if(jQuery){ window.playStartUpChime = ()=>{ let audio = new Audio('/src/audio/puter_chime.mp3'); audio.play(); - document.removeEventListener("click", window.playStartUpChime); } document.addEventListener("click", window.playStartUpChime); From edeb79d92c77efe8bbece71a1225d31c48529ef8 Mon Sep 17 00:00:00 2001 From: 4nshuman Date: Sat, 9 Nov 2024 15:16:16 +0530 Subject: [PATCH 1165/2119] play chime only once --- src/gui/src/initgui.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/src/initgui.js b/src/gui/src/initgui.js index 2652c6fb2e..9abf30d2ee 100644 --- a/src/gui/src/initgui.js +++ b/src/gui/src/initgui.js @@ -155,6 +155,7 @@ if(jQuery){ window.playStartUpChime = ()=>{ let audio = new Audio('/src/audio/puter_chime.mp3'); audio.play(); + document.removeEventListener("click", window.playStartUpChime); } document.addEventListener("click", window.playStartUpChime); From 14b962b459312149fbdbabaab1bec63ed3189547 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 15 Nov 2024 13:34:56 -0500 Subject: [PATCH 1166/2119] dev: add function-flag feature flag type --- src/backend/src/services/FeatureFlagService.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/backend/src/services/FeatureFlagService.js b/src/backend/src/services/FeatureFlagService.js index 58d288fdec..357ba7a8a4 100644 --- a/src/backend/src/services/FeatureFlagService.js +++ b/src/backend/src/services/FeatureFlagService.js @@ -42,10 +42,21 @@ class FeatureFlagService extends BaseService { if ( ! this.known_flags.has(permission) ) { this.known_flags.set(permission, true); } - + + if ( this.known_flags[permission].$ === 'config-flag' ) { + return this.known_flags[permission].value; + } const actor = options.actor ?? Context.get('actor'); + if ( this.known_flags[permission].$ === 'function-flag' ) { + return await this.known_flags[permission].fn({ + ...options, + actor + }); + } + + const svc_permission = this.services.get('permission'); const reading = await svc_permission.scan(actor, `feature:${permission}`); const l = PermissionUtil.reading_to_options(reading); @@ -60,6 +71,10 @@ class FeatureFlagService extends BaseService { summary[key] = value.value; continue; } + if ( value.$ === 'function-flag' ) { + summary[key] = await value.fn({ actor }); + continue; + } const svc_permission = this.services.get('permission'); const reading = await svc_permission.scan(actor, `feature:${key}`); const l = PermissionUtil.reading_to_options(reading); From 08779ac45538ece6cf4c0d10ddf0cb7f38f21e5a Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 15 Nov 2024 13:40:20 -0500 Subject: [PATCH 1167/2119] dev: make share feature flag reflect user state --- src/backend/src/services/ShareService.js | 17 +++++++++++++++-- 1 file changed, 15 insertions(+), 2 deletions(-) diff --git a/src/backend/src/services/ShareService.js b/src/backend/src/services/ShareService.js index 0711d4fc6a..8c25108d06 100644 --- a/src/backend/src/services/ShareService.js +++ b/src/backend/src/services/ShareService.js @@ -42,8 +42,14 @@ class ShareService extends BaseService { // about whether or not a user has access to this feature const svc_featureFlag = this.services.get('feature-flag'); svc_featureFlag.register('share', { - $: 'config-flag', - value: true + $: 'function-flag', + fn: async ({ actor }) => { + const user = actor.type.user; + if ( ! user ) { + throw new Error('expected user'); + } + return !! user.email_confirmed; + } }); } @@ -264,6 +270,13 @@ class ShareService extends BaseService { if ( ! (actor.type instanceof UserActorType) ) { throw APIError.create('forbidden'); } + + if ( ! actor.type.user.email_confirmed ) { + throw APIError.create('email_must_be_confirmed', null, { + action: 'share something', + }); + } + return await share_sequence.call(this, { actor, req, res, }); From f8ac0dbdb788198accd107cbcda412338168366b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20Dub=C3=A9?= Date: Fri, 15 Nov 2024 13:41:03 -0500 Subject: [PATCH 1168/2119] Revert "play chime only once" This reverts commit edeb79d92c77efe8bbece71a1225d31c48529ef8. --- src/gui/src/initgui.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/gui/src/initgui.js b/src/gui/src/initgui.js index 9abf30d2ee..2652c6fb2e 100644 --- a/src/gui/src/initgui.js +++ b/src/gui/src/initgui.js @@ -155,7 +155,6 @@ if(jQuery){ window.playStartUpChime = ()=>{ let audio = new Audio('/src/audio/puter_chime.mp3'); audio.play(); - document.removeEventListener("click", window.playStartUpChime); } document.addEventListener("click", window.playStartUpChime); From fa5d731641027ee6201b4b7287ca941af96f9c61 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20Dub=C3=A9?= Date: Fri, 15 Nov 2024 13:41:03 -0500 Subject: [PATCH 1169/2119] Revert "." This reverts commit 1919cb3d99a9643dd16c91c0c22f68591ffa4c4d. --- src/gui/src/initgui.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/gui/src/initgui.js b/src/gui/src/initgui.js index 2652c6fb2e..9abf30d2ee 100644 --- a/src/gui/src/initgui.js +++ b/src/gui/src/initgui.js @@ -155,6 +155,7 @@ if(jQuery){ window.playStartUpChime = ()=>{ let audio = new Audio('/src/audio/puter_chime.mp3'); audio.play(); + document.removeEventListener("click", window.playStartUpChime); } document.addEventListener("click", window.playStartUpChime); From 5fd11cc607ab92b333c964e5477ef9fb1388f7d9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20Dub=C3=A9?= Date: Fri, 15 Nov 2024 13:41:03 -0500 Subject: [PATCH 1170/2119] Revert "added event listener to play chime on the first click" This reverts commit 4885a76a756ca85e177e93bd1ecfc053d6975122. --- src/gui/src/initgui.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/gui/src/initgui.js b/src/gui/src/initgui.js index 9abf30d2ee..35cd564902 100644 --- a/src/gui/src/initgui.js +++ b/src/gui/src/initgui.js @@ -155,11 +155,8 @@ if(jQuery){ window.playStartUpChime = ()=>{ let audio = new Audio('/src/audio/puter_chime.mp3'); audio.play(); - document.removeEventListener("click", window.playStartUpChime); } -document.addEventListener("click", window.playStartUpChime); - window.initgui = async function(options){ let url = new URL(window.location); url = url.href; From 98bd10c82bbb329f5de0ecc5e735ae8bc97cbdfc Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Eric=20Dub=C3=A9?= Date: Fri, 15 Nov 2024 13:41:03 -0500 Subject: [PATCH 1171/2119] Revert "added a chime playback" This reverts commit 2eaf1080d66b08bfb45553803452633133cda028. --- src/gui/src/initgui.js | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/gui/src/initgui.js b/src/gui/src/initgui.js index 35cd564902..f37044d041 100644 --- a/src/gui/src/initgui.js +++ b/src/gui/src/initgui.js @@ -152,11 +152,6 @@ if(jQuery){ }; } -window.playStartUpChime = ()=>{ - let audio = new Audio('/src/audio/puter_chime.mp3'); - audio.play(); -} - window.initgui = async function(options){ let url = new URL(window.location); url = url.href; From cdd1a8c4e379b885ff48a874ae5577d2f0efae06 Mon Sep 17 00:00:00 2001 From: jelveh Date: Fri, 15 Nov 2024 12:07:48 -0800 Subject: [PATCH 1172/2119] feat: Require email confirmation before sharing --- src/gui/src/UI/UIItem.js | 49 ++++++++++++++++++++-------------------- 1 file changed, 25 insertions(+), 24 deletions(-) diff --git a/src/gui/src/UI/UIItem.js b/src/gui/src/UI/UIItem.js index 59281cc22b..3c2f6e294f 100644 --- a/src/gui/src/UI/UIItem.js +++ b/src/gui/src/UI/UIItem.js @@ -786,18 +786,18 @@ function UIItem(options){ menu_items.push({ html: 'Share With…', onClick: async function(){ - // if(window.user.is_temp && - // !await UIWindowSaveAccount({ - // message: 'Please create an account to proceed.', - // send_confirmation_code: true, - // window_options: { - // backdrop: true, - // close_on_backdrop_click: false, - // } - // },)) - // return; - // else if(!window.user.email_confirmed && !await UIWindowEmailConfirmationRequired()) - // return; + if(window.user.is_temp && + !await UIWindowSaveAccount({ + send_confirmation_code: true, + message: 'Please create an account to proceed.', + window_options: { + backdrop: true, + close_on_backdrop_click: false, + } + })) + return; + else if(!window.user.email_confirmed && !await UIWindowEmailConfirmationRequired()) + return; let items = []; $selected_items.each(function() { @@ -1090,18 +1090,19 @@ function UIItem(options){ menu_items.push({ html: 'Share With…', onClick: async function(){ - // if(window.user.is_temp && - // !await UIWindowSaveAccount({ - // message: 'Please create an account to proceed.', - // send_confirmation_code: true, - // window_options: { - // backdrop: true, - // close_on_backdrop_click: false, - // } - // })) - // return; - // else if(!window.user.email_confirmed && !await UIWindowEmailConfirmationRequired()) - // return; + if(window.user.is_temp && + !await UIWindowSaveAccount({ + send_confirmation_code: true, + message: 'Please create an account to proceed.', + window_options: { + backdrop: true, + close_on_backdrop_click: false, + } + })) + return; + else if(!window.user.email_confirmed && !await UIWindowEmailConfirmationRequired()) + return; + UIWindowShare([{uid: $(el_item).attr('data-uid'), path: $(el_item).attr('data-path'), name: $(el_item).attr('data-name'), icon: $(el_item_icon).find('img').attr('src')}]); } }); From 8fefd4a61f0005d4f3ec2e43f7249f3edd91c837 Mon Sep 17 00:00:00 2001 From: jelveh Date: Fri, 15 Nov 2024 15:29:23 -0800 Subject: [PATCH 1173/2119] feat: allow `launchApp` to open explorer at a specific path --- src/gui/src/UI/UIWindow.js | 4 ++++ src/gui/src/helpers/launch_app.js | 14 ++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/src/gui/src/UI/UIWindow.js b/src/gui/src/UI/UIWindow.js index ebfee3d5fa..0873a394fc 100644 --- a/src/gui/src/UI/UIWindow.js +++ b/src/gui/src/UI/UIWindow.js @@ -2879,6 +2879,10 @@ window.navbar_path_droppable = (el_window)=>{ * */ window.navbar_path = (abs_path)=>{ + // remove trailing slash + if(abs_path.endsWith('/') && abs_path !== '/') + abs_path = abs_path.slice(0, -1); + const dirs = (abs_path === '/' ? [''] : abs_path.split('/')); const dirpaths = (abs_path === '/' ? ['/'] : []) const path_seperator_html = ``; diff --git a/src/gui/src/helpers/launch_app.js b/src/gui/src/helpers/launch_app.js index b1435232a1..261e2673d3 100644 --- a/src/gui/src/helpers/launch_app.js +++ b/src/gui/src/helpers/launch_app.js @@ -129,6 +129,20 @@ const launch_app = async (options)=>{ else title = path.dirname(options.path); + // if options.args.path is provided, use it as the path + if(options.args?.path){ + // if args.path is provided, enforce the directory + let fsentry = await puter.fs.stat(options.args.path); + if(!fsentry.is_dir){ + let parent = path.dirname(options.args.path); + if(parent === options.args.path) + parent = window.home_path; + options.path = parent; + }else{ + options.path = options.args.path; + } + } + // open window el_win = UIWindow({ element_uuid: uuid, From e482b00a303ca7ec0230be1924334d59adc00f8e Mon Sep 17 00:00:00 2001 From: jelveh Date: Fri, 15 Nov 2024 15:38:59 -0800 Subject: [PATCH 1174/2119] fix: `launchApp` on explorer supports `~` now --- src/gui/src/helpers/launch_app.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/gui/src/helpers/launch_app.js b/src/gui/src/helpers/launch_app.js index 261e2673d3..09914e1372 100644 --- a/src/gui/src/helpers/launch_app.js +++ b/src/gui/src/helpers/launch_app.js @@ -143,6 +143,13 @@ const launch_app = async (options)=>{ } } + // if path starts with ~, replace it with home_path + if(options.path && options.path.startsWith('~/')) + options.path = window.home_path + options.path.slice(1); + // if path is ~, replace it with home_path + else if(options.path === '~') + options.path = window.home_path; + // open window el_win = UIWindow({ element_uuid: uuid, From e0128aa88c54548304532282e5ed1b4a2d36ff3e Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 15 Nov 2024 18:28:24 -0500 Subject: [PATCH 1175/2119] fix: prevent permission cycles --- .../src/services/auth/PermissionService.js | 11 +++- .../src/unstructured/permission-scan-lib.js | 58 +++++++++++++++++++ .../src/unstructured/permission-scanners.js | 33 ++++++++++- 3 files changed, 99 insertions(+), 3 deletions(-) create mode 100644 src/backend/src/unstructured/permission-scan-lib.js diff --git a/src/backend/src/services/auth/PermissionService.js b/src/backend/src/services/auth/PermissionService.js index 38e5b88c80..27b4bb4bd1 100644 --- a/src/backend/src/services/auth/PermissionService.js +++ b/src/backend/src/services/auth/PermissionService.js @@ -23,6 +23,7 @@ const { const { get_user, get_app } = require("../../helpers"); const { AssignableMethodsFeature } = require("../../traits/AssignableMethodsFeature"); +const { remove_paths_through_user } = require("../../unstructured/permission-scan-lib"); const { Context } = require("../../util/context"); const { get_a_letter, cylog } = require("../../util/debugutil"); const BaseService = require("../BaseService"); @@ -180,6 +181,7 @@ class PermissionUtil { }); } if ( finding.$ === 'path' ) { + if ( finding.has_terminal === false ) continue; const new_extras = ( finding.data ) ? [ finding.data, ...extras, @@ -223,8 +225,14 @@ class PermissionService extends BaseService { return options.length > 0; } - async scan (actor, permission_options) { + async scan (actor, permission_options, _reserved, state) { const reading = []; + + if ( ! state ) { + state = { + anti_cycle_actors: [actor], + }; + } if ( ! Array.isArray(permission_options) ) { permission_options = [permission_options]; @@ -240,6 +248,7 @@ class PermissionService extends BaseService { actor, permission_options, reading, + state, }); const end_ts = Date.now(); diff --git a/src/backend/src/unstructured/permission-scan-lib.js b/src/backend/src/unstructured/permission-scan-lib.js new file mode 100644 index 0000000000..6a266b1d45 --- /dev/null +++ b/src/backend/src/unstructured/permission-scan-lib.js @@ -0,0 +1,58 @@ +/** + * Filters a permission reading so that it does not contain paths through the + * specified user. This operation is performed recursively on all paths in the + * reading. + * + * This does not prevent all possible cycles. To prevent all cycles, this filter + * must by applied on each reading for a permission holder, specifying the + * permission issuer as the user to filter out. + */ +const remove_paths_through_user = ({ reading, user }) => { + const no_cycle_reading = []; + + for ( let i = 0 ; i < reading.length ; i++ ) { + const node = reading[i]; + + console.log('checking node...', node); + + if ( node.$ === 'path' ) { + if ( + node.issuer_username === user.username + ) { + console.log('filtered out one'); + // process.exit(0); + continue; + } + + node.reading = remove_paths_through_user({ + reading: node.reading, + user, + }); + } + + no_cycle_reading.push(node); + } + + console.log('\x1B[36;1m ====', reading.length - no_cycle_reading.length, 'nodes filtered out ====\x1B[0m'); + + return no_cycle_reading; +}; + +const reading_has_terminal = ({ reading }) => { + for ( let i = 0 ; i < reading.length ; i++ ) { + const node = reading[i]; + if ( node.has_terminal ) { + return true; + } + if ( node.$ === 'option' ) { + return true; + } + } + + return false; +}; + +module.exports = { + remove_paths_through_user, + reading_has_terminal, +}; diff --git a/src/backend/src/unstructured/permission-scanners.js b/src/backend/src/unstructured/permission-scanners.js index 4dc4ee88e5..06adc8f8a7 100644 --- a/src/backend/src/unstructured/permission-scanners.js +++ b/src/backend/src/unstructured/permission-scanners.js @@ -5,6 +5,7 @@ const { } = require("../data/hardcoded-permissions"); const { get_user } = require("../helpers"); const { Actor, UserActorType, AppUnderUserActorType } = require("../services/auth/Actor"); +const { reading_has_terminal } = require("./permission-scan-lib"); /* OPTIMAL FOLD LEVEL: 3 @@ -46,7 +47,7 @@ const PERMISSION_SCANNERS = [ { name: 'user-user', async scan (a) { - const { reading, actor, permission_options } = a.values(); + const { reading, actor, permission_options, state } = a.values(); if ( !(actor.type instanceof UserActorType) ) { return; } @@ -85,11 +86,26 @@ const PERMISSION_SCANNERS = [ }), }); + let should_continue = false; + for ( const seen_actor of state.anti_cycle_actors ) { + if ( seen_actor.type.user.id === issuer_actor.type.user.id ) { + should_continue = true; + break; + } + } + + if ( should_continue ) continue; + // const issuer_perm = await this.check(issuer_actor, row.permission); - const issuer_reading = await a.icall('scan', issuer_actor, row.permission); + const issuer_reading = await a.icall( + 'scan', issuer_actor, row.permission, undefined, state); + + const has_terminal = reading_has_terminal({ reading: issuer_reading }); + reading.push({ $: 'path', via: 'user', + has_terminal, permission: row.permission, data: row.extra, holder_username: actor.type.user.username, @@ -134,9 +150,13 @@ const PERMISSION_SCANNERS = [ if ( ! issuer_group.hasOwnProperty(permission) ) continue; const issuer_reading = await a.icall('scan', issuer_actor, permission) + + const has_terminal = reading_has_terminal({ reading: issuer_reading }); + reading.push({ $: 'path', via: 'hc-user-group', + has_terminal, permission, data: issuer_group[permission], holder_username: actor.type.user.username, @@ -188,9 +208,12 @@ const PERMISSION_SCANNERS = [ const issuer_reading = await a.icall('scan', issuer_actor, row.permission); + const has_terminal = reading_has_terminal({ reading: issuer_reading }); + reading.push({ $: 'path', via: 'user-group', + has_terminal, // issuer: issuer_actor, permission: row.permission, data: row.extra, @@ -240,6 +263,8 @@ const PERMISSION_SCANNERS = [ const issuer_actor = actor.get_related_actor(UserActorType); const issuer_reading = await a.icall('scan', issuer_actor, permission_options); + + const has_terminal = reading_has_terminal({ reading: issuer_reading }); for ( const permission of permission_options ) { { @@ -249,6 +274,7 @@ const PERMISSION_SCANNERS = [ reading.push({ $: 'path', permission, + has_terminal, source: 'user-app-implied', by: 'user-app-hc-1', data: implied, @@ -267,6 +293,7 @@ const PERMISSION_SCANNERS = [ reading.push({ $: 'path', permission, + has_terminal, source: 'user-app-implied', by: 'user-app-hc-2', data: implicit_permissions[permission], @@ -301,10 +328,12 @@ const PERMISSION_SCANNERS = [ })(); const issuer_actor = actor.get_related_actor(UserActorType); const issuer_reading = await a.icall('scan', issuer_actor, row.permission); + const has_terminal = reading_has_terminal({ reading: issuer_reading }); reading.push({ $: 'path', via: 'user-app', permission: row.permission, + has_terminal, data: row.extra, issuer_username: actor.type.user.username, reading: issuer_reading, From 59fa600f2bcd0ef6470e2c7cb9ad2c9ad84a05cc Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Sat, 16 Nov 2024 20:04:10 -0500 Subject: [PATCH 1176/2119] dev: edge rate limit for email share --- src/backend/src/services/ShareService.js | 5 +++++ .../src/services/abuse-prevention/EdgeRateLimitService.js | 4 ++++ 2 files changed, 9 insertions(+) diff --git a/src/backend/src/services/ShareService.js b/src/backend/src/services/ShareService.js index 8c25108d06..e3754648ab 100644 --- a/src/backend/src/services/ShareService.js +++ b/src/backend/src/services/ShareService.js @@ -266,6 +266,11 @@ class ShareService extends BaseService { // featureflag({ feature: 'share' }), ], handler: async (req, res) => { + const svc_edgeRateLimit = req.services.get('edge-rate-limit'); + if ( ! svc_edgeRateLimit.check('verify-pass-recovery-token') ) { + return res.status(429).send('Too many requests.'); + } + const actor = Actor.adapt(req.user); if ( ! (actor.type instanceof UserActorType) ) { throw APIError.create('forbidden'); diff --git a/src/backend/src/services/abuse-prevention/EdgeRateLimitService.js b/src/backend/src/services/abuse-prevention/EdgeRateLimitService.js index 3d9963971a..2cbcde0c5a 100644 --- a/src/backend/src/services/abuse-prevention/EdgeRateLimitService.js +++ b/src/backend/src/services/abuse-prevention/EdgeRateLimitService.js @@ -44,6 +44,10 @@ class EdgeRateLimitService extends BaseService { limit: 10, window: 15 * MINUTE, }, + ['share']: { + limit: 30, + window: 1 * MINUTE, + }, ['send-confirm-email']: { limit: 10, window: HOUR, From 0885937f033caf35503eeb9e65bb390952992faf Mon Sep 17 00:00:00 2001 From: jelveh Date: Sat, 16 Nov 2024 19:07:09 -0800 Subject: [PATCH 1177/2119] feat: Implement profile pictures --- src/gui/puter-gui.json | 3 +- src/gui/src/UI/Settings/UITabAccount.js | 54 +++++++++- src/gui/src/UI/UIDesktop.js | 4 +- src/gui/src/UI/UIWindowSessionList.js | 8 +- src/gui/src/css/style.css | 138 ++++++++++++++++-------- src/gui/src/helpers.js | 55 ++++++++++ src/gui/src/lib/croppie.min.js | 1 + src/gui/src/static-assets.js | 1 + src/gui/webpack/libPaths.cjs | 3 +- 9 files changed, 216 insertions(+), 51 deletions(-) create mode 100644 src/gui/src/lib/croppie.min.js diff --git a/src/gui/puter-gui.json b/src/gui/puter-gui.json index 3f40f762ff..9ad5a6667e 100644 --- a/src/gui/puter-gui.json +++ b/src/gui/puter-gui.json @@ -14,7 +14,8 @@ "/lib/timeago.min.js", "/lib/iro.min.js", "/lib/isMobile.min.js", - "/lib/fflate-0.8.2.min.js" + "/lib/fflate-0.8.2.min.js", + "/lib/croppie.min.js" ], "css_paths": [ "/css/normalize.css", diff --git a/src/gui/src/UI/Settings/UITabAccount.js b/src/gui/src/UI/Settings/UITabAccount.js index 47a027d7c6..95de65cf62 100644 --- a/src/gui/src/UI/Settings/UITabAccount.js +++ b/src/gui/src/UI/Settings/UITabAccount.js @@ -22,6 +22,7 @@ import UIWindowChangeEmail from './UIWindowChangeEmail.js'; import UIWindowChangeUsername from '../UIWindowChangeUsername.js'; import UIWindowConfirmUserDeletion from './UIWindowConfirmUserDeletion.js'; import UIWindowManageSessions from '../UIWindowManageSessions.js'; +import UIWindow from '../UIWindow.js'; // About export default { @@ -29,7 +30,14 @@ export default { title_i18n_key: 'account', icon: 'user.svg', html: () => { - let h = `

${i18n('account')}

`; + let h = ''; + // h += `

${i18n('account')}

`; + + // profile picture + h += `
`; + h += `
`; + h += `
`; + h += `
`; // change password button if(!window.user.is_temp){ @@ -125,5 +133,49 @@ export default { } }); }); + + $el_window.find('.change-profile-picture').on('click', async function (e) { + // open dialog + UIWindow({ + path: '/' + window.user.username + '/Desktop', + // this is the uuid of the window to which this dialog will return + parent_uuid: $el_window.attr('data-element_uuid'), + allowed_file_types: ['.png', '.jpg', '.jpeg'], + show_maximize_button: false, + show_minimize_button: false, + title: 'Open', + is_dir: true, + is_openFileDialog: true, + selectable_body: false, + }); + }) + + $el_window.on('file_opened', async function(e){ + let selected_file = Array.isArray(e.detail) ? e.detail[0] : e.detail; + // set profile picture + const profile_pic = await puter.fs.read(selected_file.path) + // blob to base64 + const reader = new FileReader(); + reader.readAsDataURL(profile_pic); + reader.onloadend = function() { + // resizes the image to 150x150 + const img = new Image(); + img.src = reader.result; + img.onload = function() { + const canvas = document.createElement('canvas'); + const ctx = canvas.getContext('2d'); + canvas.width = 150; + canvas.height = 150; + ctx.drawImage(img, 0, 0, 150, 150); + const base64data = canvas.toDataURL('image/png'); + // update profile picture + $el_window.find('.profile-picture').css('background-image', 'url(' + html_encode(base64data) + ')'); + $('.profile-image').css('background-image', 'url(' + html_encode(base64data) + ')'); + $('.profile-image').addClass('profile-image-has-picture'); + // update profile picture + update_profile(window.user.username, {picture: base64data}) + } + } + }) }, }; diff --git a/src/gui/src/UI/UIDesktop.js b/src/gui/src/UI/UIDesktop.js index 9c733886cc..2137534050 100644 --- a/src/gui/src/UI/UIDesktop.js +++ b/src/gui/src/UI/UIDesktop.js @@ -1052,8 +1052,8 @@ async function UIDesktop(options){ ht += `
`; // user options menu - ht += `
`; - h += `${window.user.username}`; + ht += `
`; + ht += `
`; ht += `
`; ht += `
`; diff --git a/src/gui/src/UI/UIWindowSessionList.js b/src/gui/src/UI/UIWindowSessionList.js index 023b554656..c1bfdd654a 100644 --- a/src/gui/src/UI/UIWindowSessionList.js +++ b/src/gui/src/UI/UIWindowSessionList.js @@ -32,10 +32,14 @@ async function UIWindowSessionList(options){ h += `
${i18n('signing_in')}
`; // session list h += `
`; - h += `

${i18n('sign_in_with_puter')}

` + h += `

${i18n('sign_in_with_puter')}

` for (let index = 0; index < window.logged_in_users.length; index++) { const l_user = window.logged_in_users[index]; - h += `
${l_user.username}
`; + h += `
`; + // profile picture + h += `
`; + h += `
${l_user.username}
`; + h += `
`; } h += `
`; // c2a diff --git a/src/gui/src/css/style.css b/src/gui/src/css/style.css index 0d5957920e..43fca3c865 100644 --- a/src/gui/src/css/style.css +++ b/src/gui/src/css/style.css @@ -79,7 +79,7 @@ font-variation-settings: "slnt"0; } -pre{ +pre { font-family: "Inter", "Helvetica Neue", HelveticaNeue, Helvetica, Arial, sans-serif; } @@ -611,7 +611,7 @@ span.header-sort-icon img { } .item-name, .item-name-editor, .item-name-shadow { - font-size: 13px; + font-size: 12px; color: white; text-shadow: 0px 0px 3px #00000082, 0px 0px 3px #00000082, 0px 0px 3px #00000082; -webkit-font-smoothing: antialiased; @@ -1263,27 +1263,32 @@ span.header-sort-icon img { background-color: #fefeff; } -.window-sidebar-item-placeholder{ +.window-sidebar-item-placeholder { height: 27px !important; } + .window-sidebar-item { cursor: pointer !important; user-select: none; } + .window-sidebar-item:not(.window-sidebar-title):hover { cursor: grab; } + .window-sidebar-item.grabbing { cursor: grabbing !important; } + .window-sidebar-item-dragging { background-color: #f5f5f5 !important; opacity: 0.8; cursor: grabbing; } + .ui-sortable-helper { background: white !important; - box-shadow: 0 2px 8px rgba(0,0,0,0.1) !important; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1) !important; } .window-sidebar-item-icon { @@ -1362,16 +1367,17 @@ span.header-sort-icon img { flex-grow: 1; } -.window-filedialog-upload-here{ +.window-filedialog-upload-here { -webkit-font-smoothing: antialiased; opacity: 0.7; font-size: 14px; } -.window-filedialog-upload-here:hover{ +.window-filedialog-upload-here:hover { cursor: pointer; opacity: 1; } + .savefiledialog-save-btn, .openfiledialog-open-btn { margin-left: 10px; } @@ -1590,7 +1596,8 @@ span.header-sort-icon img { border-bottom: none; border-top: 1px solid #00000033; } -.context-menu .context-menu-divider{ + +.context-menu .context-menu-divider { padding-top: 5px; padding-bottom: 5px; } @@ -2115,11 +2122,11 @@ label { background-color: #9dacbd; } -.permission-editor-badge{ +.permission-editor-badge { background-color: #007cff; } -.permission-viewer-badge{ +.permission-viewer-badge { background-color: #41c95d; } @@ -2168,20 +2175,24 @@ label { max-height: 200px; overflow: hidden; } -.ui-menu{ + +.ui-menu { margin-top: 5px; border-radius: 5px; } -.ui-menu .ui-menu-item{ + +.ui-menu .ui-menu-item { padding: 5px 10px; border-radius: 5px; } + .ui-menu .ui-menu-item .ui-menu-item-wrapper { background: none; border: none; padding: 5px 10px; font-size: 14px; } + .ui-menu .ui-menu-item:hover .ui-menu-item-wrapper, .ui-menu .ui-menu-item:focus .ui-menu-item-wrapper, .ui-menu .ui-menu-item:active .ui-menu-item-wrapper, @@ -2856,13 +2867,14 @@ fieldset[name=number-code] { opacity: 1; } -.welcome-window-close-button{ +.welcome-window-close-button { opacity: 0.7; font-weight: 300; top: 5px; right: 5px; } -.welcome-window-close-button:hover{ + +.welcome-window-close-button:hover { opacity: 1; } @@ -3690,12 +3702,12 @@ fieldset[name=number-code] { margin-top: 1px; } -.settings-sidebar-title{ - margin-bottom: 20px; - font-weight: bold; - -webkit-font-smoothing: antialiased; - margin-top: 15px; - color: #8c8c8c; +.settings-sidebar-title { + margin-bottom: 20px; + font-weight: bold; + -webkit-font-smoothing: antialiased; + margin-top: 15px; + color: #8c8c8c; font-size: 19px; } @@ -3835,6 +3847,30 @@ fieldset[name=number-code] { opacity: 1; } +.profile-picture { + cursor: pointer; + position: relative; + overflow: hidden; + background-position: center; + background-size: cover; + background-repeat: no-repeat; + border: 1px solid #EEE; + width: 120px; + height: 120px; + border-radius: 50%; + margin-right: 0; + margin-top: 20px; + margin-bottom: 20px; + background-color: #c5cdd4; +} + +.profile-picture:hover { + background-color: #a6afb7; +} + +.profile-image-has-picture{ + border: 1px solid white; +} .driver-usage { background-color: white; bottom: 0; @@ -3982,7 +4018,7 @@ fieldset[name=number-code] { background-color: #f6f6f6; } -.language-item .checkmark{ +.language-item .checkmark { width: 15px; height: 15px; border-radius: 50%; @@ -3991,9 +4027,11 @@ fieldset[name=number-code] { position: absolute; right: 10px; } + .language-item.active { background-color: #e0e0e0; } + .language-item.active .checkmark { display: inline-block; } @@ -4011,9 +4049,11 @@ fieldset[name=number-code] { align-items: center; height: 45px; } -.settings-card .button{ + +.settings-card .button { box-shadow: none; } + .thin-card { padding: 0 15px; } @@ -4193,6 +4233,7 @@ fieldset[name=number-code] { .visible-xs { display: block !important; } + .settings-sidebar { display: none; position: fixed; @@ -4205,6 +4246,7 @@ fieldset[name=number-code] { .visible-sm { display: block !important; } + .settings-sidebar { display: none; position: fixed; @@ -4231,46 +4273,49 @@ fieldset[name=number-code] { } } -.sidebar-toggle{ - position: absolute; +.sidebar-toggle { + position: absolute; z-index: 9999999999; left: 2px; - border: 0; - padding-top: 5px; - padding-bottom: 5px; + border: 0; + padding-top: 5px; + padding-bottom: 5px; top: 3px; } + .sidebar-toggle .sidebar-toggle-button { - height: 20px; + height: 20px; width: 20px; } .sidebar-toggle span:nth-child(1) { - margin-top: 5px; + margin-top: 5px; } .sidebar-toggle span { - border-bottom: 2px solid #858585; - display: block; - margin-bottom: 5px; - width: 100%; + border-bottom: 2px solid #858585; + display: block; + margin-bottom: 5px; + width: 100%; } + .settings-sidebar.active { display: block; } -.welcome-window-footer{ - position: absolute; bottom: 20px; +.welcome-window-footer { + position: absolute; + bottom: 20px; } -.welcome-window-footer a{ +.welcome-window-footer a { color: #727c8d; text-decoration: none; font-size: 12px; -webkit-font-smoothing: antialiased; } -.welcome-window-footer a:hover{ +.welcome-window-footer a:hover { color: #1d1e23; } @@ -4279,7 +4324,7 @@ fieldset[name=number-code] { * Search * ------------------------------------ */ -.search-input-wrapper{ +.search-input-wrapper { width: 100%; border-radius: 5px; padding-bottom: 10px; @@ -4290,13 +4335,15 @@ fieldset[name=number-code] { box-sizing: border-box; background: #f1f6fc; } -.search-input{ + +.search-input { padding-left: 33px !important; background-repeat: no-repeat; background-position: 5px center; background-size: 20px; } -.search-results{ + +.search-results { padding-right: 15px; margin-top: 70px; padding-left: 15px; @@ -4304,18 +4351,21 @@ fieldset[name=number-code] { padding-bottom: 5px; display: none; } -.search-result{ - padding: 10px; cursor: pointer; + +.search-result { + padding: 10px; + cursor: pointer; font-size: 13px; display: flex; align-items: center; } -.search-result-active{ + +.search-result-active { background-color: #4092da; color: #fff; border-radius: 5px; } + .search-results .search-result:last-child { margin-bottom: 0; -} - \ No newline at end of file +} \ No newline at end of file diff --git a/src/gui/src/helpers.js b/src/gui/src/helpers.js index 2657bcef53..a968f59fe6 100644 --- a/src/gui/src/helpers.js +++ b/src/gui/src/helpers.js @@ -445,6 +445,35 @@ window.update_auth_data = async (auth_token, user)=>{ $('.user-email').html(html_encode(user.email)); } + // ---------------------------------------------------- + // get .profile file and update user profile + // ---------------------------------------------------- + user.profile = {}; + puter.fs.read('/'+user.username+'/Public/.profile').then((blob)=>{ + blob.text() + .then(text => { + const profile = JSON.parse(text); + if(profile.picture){ + window.user.profile.picture = html_encode(profile.picture); + } + + // update profile picture in GUI + if(window.user.profile.picture){ + $('.profile-pic').css('background-image', 'url('+window.user.profile.picture+')'); + } + }) + .catch(error => { + console.error('Error converting Blob to JSON:', error); + }); + }).catch((e)=>{ + if(e?.code === "subject_does_not_exist"){ + // create .profile file + puter.fs.write('/'+user.username+'/Public/.profile', JSON.stringify({})); + } + }); + + // ---------------------------------------------------- + const to_storable_user = user => { const storable_user = {...user}; delete storable_user.taskbar_items; @@ -2597,3 +2626,29 @@ window.detectHostOS = function(){ } } +window.update_profile = function(username, key_vals){ + puter.fs.read('/'+username+'/Public/.profile').then((blob)=>{ + blob.text() + .then(text => { + const profile = JSON.parse(text); + + for (const key in key_vals) { + profile[key] = key_vals[key]; + // update window.user.profile + window.user.profile[key] = key_vals[key]; + } + + puter.fs.write('/'+username+'/Public/.profile', JSON.stringify(profile)); + }) + .catch(error => { + console.error('Error converting Blob to JSON:', error); + }); + }).catch((e)=>{ + if(e?.code === "subject_does_not_exist"){ + // create .profile file + puter.fs.write('/'+username+'/Public/.profile', JSON.stringify({})); + } + // Ignored + console.log(e); + }); +} \ No newline at end of file diff --git a/src/gui/src/lib/croppie.min.js b/src/gui/src/lib/croppie.min.js new file mode 100644 index 0000000000..1223fd23f1 --- /dev/null +++ b/src/gui/src/lib/croppie.min.js @@ -0,0 +1 @@ +!function(e,t){"function"==typeof define&&define.amd?define(t):"object"==typeof exports&&"string"!=typeof exports.nodeName?module.exports=t():e.Croppie=t()}("undefined"!=typeof self?self:this,function(){"function"!=typeof Promise&&function(e){function n(e,t){return function(){e.apply(t,arguments)}}function r(e){if("object"!=typeof this)throw new TypeError("Promises must be constructed via new");if("function"!=typeof e)throw new TypeError("not a function");this._state=null,this._value=null,this._deferreds=[],u(e,n(i,this),n(o,this))}function a(n){var i=this;return null===this._state?void this._deferreds.push(n):void c(function(){var e=i._state?n.onFulfilled:n.onRejected;if(null!==e){var t;try{t=e(i._value)}catch(e){return void n.reject(e)}n.resolve(t)}else(i._state?n.resolve:n.reject)(i._value)})}function i(e){try{if(e===this)throw new TypeError("A promise cannot be resolved with itself.");if(e&&("object"==typeof e||"function"==typeof e)){var t=e.then;if("function"==typeof t)return void u(n(t,e),n(i,this),n(o,this))}this._state=!0,this._value=e,s.call(this)}catch(e){o.call(this,e)}}function o(e){this._state=!1,this._value=e,s.call(this)}function s(){for(var e=0,t=this._deferreds.length;en.top+t&&l.bottomn.left+e&&l.right=s.maxX&&(o.x=l.minX,n.x=s.maxX),n.x<=s.minX&&(o.x=l.maxX,n.x=s.minX),n.y>=s.maxY&&(o.y=l.minY,n.y=s.maxY),n.y<=s.minY&&(o.y=l.maxY,n.y=s.minY)}r(),I.call(t),F.call(t)}).call(i,{value:parseFloat(t.value),origin:new L(i.elements.preview),viewportRect:i.elements.viewport.getBoundingClientRect(),transform:E.parse(i.elements.preview)})}function n(e){var t,n;if("ctrl"===i.options.mouseWheelZoom&&!0!==e.ctrlKey)return 0;t=e.wheelDelta?e.wheelDelta/1200:e.deltaY?e.deltaY/1060:e.detail?e.detail/-60:0,n=i._currentZoom+t*i._currentZoom,e.preventDefault(),B.call(i,n),o.call(i)}x(e,"cr-slider-wrap"),x(t,"cr-slider"),t.type="range",t.step="0.0001",t.value="1",t.style.display=i.options.showZoomer?"":"none",t.setAttribute("aria-label","zoom"),i.element.appendChild(e),e.appendChild(t),i._currentZoom=1,i.elements.zoomer.addEventListener("input",o),i.elements.zoomer.addEventListener("change",o),i.options.mouseWheelZoom&&(i.elements.boundary.addEventListener("mousewheel",n),i.elements.boundary.addEventListener("DOMMouseScroll",n))}.call(a),a.options.enableResize&&function(){var l,u,c,h,p,e,t,d=this,m=document.createElement("div"),i=!1,f=50;x(m,"cr-resizer"),b(m,{width:this.options.viewport.width+"px",height:this.options.viewport.height+"px"}),this.options.resizeControls.height&&(x(e=document.createElement("div"),"cr-resizer-vertical"),m.appendChild(e));this.options.resizeControls.width&&(x(t=document.createElement("div"),"cr-resizer-horisontal"),m.appendChild(t));function n(e){if((void 0===e.button||0===e.button)&&(e.preventDefault(),!i)){var t=d.elements.overlay.getBoundingClientRect();if(i=!0,u=e.pageX,c=e.pageY,l=-1!==e.currentTarget.className.indexOf("vertical")?"v":"h",h=t.width,p=t.height,e.touches){var n=e.touches[0];u=n.pageX,c=n.pageY}window.addEventListener("mousemove",o),window.addEventListener("touchmove",o),window.addEventListener("mouseup",r),window.addEventListener("touchend",r),document.body.style[w]="none"}}function o(e){var t=e.pageX,n=e.pageY;if(e.preventDefault(),e.touches){var i=e.touches[0];t=i.pageX,n=i.pageY}var o=t-u,r=n-c,a=d.options.viewport.height+r,s=d.options.viewport.width+o;"v"===l&&f<=a&&a<=p?(b(m,{height:a+"px"}),d.options.boundary.height+=r,b(d.elements.boundary,{height:d.options.boundary.height+"px"}),d.options.viewport.height+=r,b(d.elements.viewport,{height:d.options.viewport.height+"px"})):"h"===l&&f<=s&&s<=h&&(b(m,{width:s+"px"}),d.options.boundary.width+=o,b(d.elements.boundary,{width:d.options.boundary.width+"px"}),d.options.viewport.width+=o,b(d.elements.viewport,{width:d.options.viewport.width+"px"})),z.call(d),W.call(d),Z.call(d),F.call(d),c=n,u=t}function r(){i=!1,window.removeEventListener("mousemove",o),window.removeEventListener("touchmove",o),window.removeEventListener("mouseup",r),window.removeEventListener("touchend",r),document.body.style[w]=""}e&&(e.addEventListener("mousedown",n),e.addEventListener("touchstart",n));t&&(t.addEventListener("mousedown",n),t.addEventListener("touchstart",n));this.elements.boundary.appendChild(m)}.call(a)}function R(){return this.options.enableExif&&window.EXIF}function B(e){if(this.options.enableZoom){var t=this.elements.zoomer,n=A(e,4);t.value=Math.max(parseFloat(t.min),Math.min(parseFloat(t.max),n)).toString()}}function Z(e){var t=this,n=t._currentZoom,i=t.elements.preview.getBoundingClientRect(),o=t.elements.viewport.getBoundingClientRect(),r=E.parse(t.elements.preview.style[g]),a=new L(t.elements.preview),s=o.top-i.top+o.height/2,l=o.left-i.left+o.width/2,u={},c={};if(e){var h=a.x,p=a.y,d=r.x,m=r.y;u.y=h,u.x=p,r.y=d,r.x=m}else u.y=s/n,u.x=l/n,c.y=(u.y-a.y)*(1-n),c.x=(u.x-a.x)*(1-n),r.x-=c.x,r.y-=c.y;var f={};f[v]=u.x+"px "+u.y+"px",f[g]=r.toString(),b(t.elements.preview,f)}function z(){if(this.elements){var e=this.elements.boundary.getBoundingClientRect(),t=this.elements.preview.getBoundingClientRect();b(this.elements.overlay,{width:t.width+"px",height:t.height+"px",top:t.top-e.top+"px",left:t.left-e.left+"px"})}}L.prototype.toString=function(){return this.x+"px "+this.y+"px"};var a,s,h,M,I=(a=z,s=500,function(){var e=this,t=arguments,n=h&&!M;clearTimeout(M),M=setTimeout(function(){M=null,h||a.apply(e,t)},s),n&&a.apply(e,t)});function F(){var e,t=this,n=t.get();X.call(t)&&(t.options.update.call(t,n),t.$&&"undefined"==typeof Prototype?t.$(t.element).trigger("update.croppie",n):(window.CustomEvent?e=new CustomEvent("update",{detail:n}):(e=document.createEvent("CustomEvent")).initCustomEvent("update",!0,!0,n),t.element.dispatchEvent(e)))}function X(){return 0l.max)?B.call(r,uthis._originalImageWidth&&(g=(d=this._originalImageWidth-h)/o*u),i<0&&(p=0,v=Math.abs(i)/r*c),m+p>this._originalImageHeight&&(w=(m=this._originalImageHeight-p)/r*c),l.drawImage(this.elements.preview,h,p,d,m,f,v,g,w),a&&(l.fillStyle="#fff",l.globalCompositeOperation="destination-in",l.beginPath(),l.arc(s.width/2,s.height/2,s.width/2,0,2*Math.PI,!0),l.closePath(),l.fill()),s}function k(c,h){var e,i,o,r,p=this,d=[],t=null,n=R.call(p);if("string"==typeof c)e=c,c={};else if(Array.isArray(c))d=c.slice();else{if(void 0===c&&p.data.url)return Y.call(p),F.call(p),null;e=c.url,d=c.points||[],t=void 0===c.zoom?null:c.zoom}return p.data.bound=!1,p.data.url=e||p.data.url,p.data.boundZoom=t,(i=e,o=n,r=new Image,r.style.opacity="0",new Promise(function(e,t){function n(){r.style.opacity="1",setTimeout(function(){e(r)},1)}r.removeAttribute("crossOrigin"),i.match(/^https?:\/\/|^\/\//)&&r.setAttribute("crossOrigin","anonymous"),r.onload=function(){o?EXIF.getData(r,function(){n()}):n()},r.onerror=function(e){r.style.opacity=1,setTimeout(function(){t(e)},1)},r.src=i})).then(function(e){if(function(t){this.elements.img.parentNode&&(Array.prototype.forEach.call(this.elements.img.classList,function(e){t.classList.add(e)}),this.elements.img.parentNode.replaceChild(t,this.elements.img),this.elements.preview=t),this.elements.img=t}.call(p,e),d.length)p.options.relative&&(d=[d[0]*e.naturalWidth/100,d[1]*e.naturalHeight/100,d[2]*e.naturalWidth/100,d[3]*e.naturalHeight/100]);else{var t,n,i=m(e),o=p.elements.viewport.getBoundingClientRect(),r=o.width/o.height;r Date: Sun, 17 Nov 2024 11:06:10 -0800 Subject: [PATCH 1178/2119] fix: mobile-friendly taskbar --- src/gui/src/UI/UIDesktop.js | 2 ++ src/gui/src/UI/UITaskbar.js | 24 +++++++++++++++++++++ src/gui/src/UI/UITaskbarItem.js | 4 ++++ src/gui/src/css/style.css | 38 +++++++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+) diff --git a/src/gui/src/UI/UIDesktop.js b/src/gui/src/UI/UIDesktop.js index 2137534050..eec8c38bf3 100644 --- a/src/gui/src/UI/UIDesktop.js +++ b/src/gui/src/UI/UIDesktop.js @@ -1708,6 +1708,8 @@ window.remove_taskbar_item = function(item){ $(item).animate({width: 0}, 200, function(){ $(item).remove(); }) + + window.recalibrate_taskbar_item_positions(); } window.enter_fullpage_mode = (el_window)=>{ diff --git a/src/gui/src/UI/UITaskbar.js b/src/gui/src/UI/UITaskbar.js index 7b32814040..1557125852 100644 --- a/src/gui/src/UI/UITaskbar.js +++ b/src/gui/src/UI/UITaskbar.js @@ -237,6 +237,7 @@ async function UITaskbar(options){ } }) + window.recalibrate_taskbar_item_positions(); window.make_taskbar_sortable(); } @@ -303,4 +304,27 @@ window.make_taskbar_sortable = function(){ }); } +window.recalibrate_taskbar_item_positions = function(){ + // if this is mobile rearrange taskbar item positions based on absolute position + // taskbar items must be centered unless there is overflow. If there is overflow, the taskbar items must be left aligned + if(isMobile.phone){ + let taskbar_items = $('.taskbar-item'); + let taskbar_width = taskbar_items.length * 60; + + if(taskbar_width > window.desktop_width){ + // set taskbar items to absolute position + $('.taskbar-item').css('position', 'absolute'); + // set left position for each taskbar item + let left = 0; + for (let index = 0; index < taskbar_items.length; index++) { + const taskbar_item = taskbar_items[index]; + $(taskbar_item).css('left', left); + left += 60; + } + }else{ + $('.taskbar-item').css('position', 'unset'); + $('.taskbar').css('justify-content', 'center'); + } + } +} export default UITaskbar; \ No newline at end of file diff --git a/src/gui/src/UI/UITaskbarItem.js b/src/gui/src/UI/UITaskbarItem.js index fd293cced4..31007ee9c5 100644 --- a/src/gui/src/UI/UITaskbarItem.js +++ b/src/gui/src/UI/UITaskbarItem.js @@ -376,6 +376,10 @@ function UITaskbarItem(options){ } }); + if(options.append_to_taskbar){ + window.recalibrate_taskbar_item_positions(); + } + return el_taskbar_item; } diff --git a/src/gui/src/css/style.css b/src/gui/src/css/style.css index 43fca3c865..4162877202 100644 --- a/src/gui/src/css/style.css +++ b/src/gui/src/css/style.css @@ -2412,6 +2412,44 @@ label { } } +.device-phone .taskbar { + justify-content: center; + overflow: visible !important; + overflow-x: scroll !important; +} + +.device-phone .taskbar .taskbar-item, .device-phone .taskbar .taskbar-item-sortable-placeholder { + width: 40px !important; + height: 40px !important; + margin-right: 5px; + overflow: visible !important; + padding: 5px 5px 10px 5px; + position: absolute; +} + +.device-phone .taskbar-icon { + height: 40px; + width: 40px; +} + +/* Hide scrollbar for Chrome, Safari and Opera */ +.device-phone .taskbar ::-webkit-scrollbar { + width: 0 !important; + display: none; +} + +/* Hide scrollbar for IE, Edge and Firefox */ +.device-phone .taskbar { + -ms-overflow-style: none; + /* IE and Edge */ + scrollbar-width: none; + /* Firefox */ +} + +/***************************************************** + * Tooltip + *****************************************************/ + .ui-tooltip, .arrow:after { background-color: rgba(231, 238, 245, .92); box-shadow: none; From b11016dab321717f2c367e985167a4689fc02814 Mon Sep 17 00:00:00 2001 From: jelveh Date: Sun, 17 Nov 2024 11:33:42 -0800 Subject: [PATCH 1179/2119] fix: mobile detection --- src/gui/src/UI/UITaskbar.js | 4 ++- src/gui/src/css/style.css | 67 ++++++++++++++++++++----------------- 2 files changed, 39 insertions(+), 32 deletions(-) diff --git a/src/gui/src/UI/UITaskbar.js b/src/gui/src/UI/UITaskbar.js index 1557125852..d0818e0e26 100644 --- a/src/gui/src/UI/UITaskbar.js +++ b/src/gui/src/UI/UITaskbar.js @@ -94,6 +94,7 @@ async function UITaskbar(options){ apps_str += ``; apps_str += ``; apps_str += `
`; + // ------------------------------------------- // Recent apps // ------------------------------------------- @@ -307,13 +308,14 @@ window.make_taskbar_sortable = function(){ window.recalibrate_taskbar_item_positions = function(){ // if this is mobile rearrange taskbar item positions based on absolute position // taskbar items must be centered unless there is overflow. If there is overflow, the taskbar items must be left aligned - if(isMobile.phone){ + if(isMobile.phone || window.desktop_width < 800){ let taskbar_items = $('.taskbar-item'); let taskbar_width = taskbar_items.length * 60; if(taskbar_width > window.desktop_width){ // set taskbar items to absolute position $('.taskbar-item').css('position', 'absolute'); + $('.taskbar').css('display', 'block'); // set left position for each taskbar item let left = 0; for (let index = 0; index < taskbar_items.length; index++) { diff --git a/src/gui/src/css/style.css b/src/gui/src/css/style.css index 4162877202..7c97d318dd 100644 --- a/src/gui/src/css/style.css +++ b/src/gui/src/css/style.css @@ -2412,38 +2412,43 @@ label { } } -.device-phone .taskbar { - justify-content: center; - overflow: visible !important; - overflow-x: scroll !important; -} - -.device-phone .taskbar .taskbar-item, .device-phone .taskbar .taskbar-item-sortable-placeholder { - width: 40px !important; - height: 40px !important; - margin-right: 5px; - overflow: visible !important; - padding: 5px 5px 10px 5px; - position: absolute; -} - -.device-phone .taskbar-icon { - height: 40px; - width: 40px; -} - -/* Hide scrollbar for Chrome, Safari and Opera */ -.device-phone .taskbar ::-webkit-scrollbar { - width: 0 !important; - display: none; -} +@media screen and (max-width: 768px) { -/* Hide scrollbar for IE, Edge and Firefox */ -.device-phone .taskbar { - -ms-overflow-style: none; - /* IE and Edge */ - scrollbar-width: none; - /* Firefox */ + .taskbar { + justify-content: center; + overflow: visible !important; + overflow-x: scroll !important; + overflow-y: hidden !important; + } + + .taskbar .taskbar-item, .taskbar .taskbar-item-sortable-placeholder { + width: 40px !important; + height: 40px !important; + margin-right: 5px; + overflow: visible !important; + padding: 5px 5px 10px 5px; + position: absolute; + } + + .taskbar-icon { + height: 40px; + width: 40px; + } + + /* Hide scrollbar for Chrome, Safari and Opera */ + .taskbar ::-webkit-scrollbar { + width: 0 !important; + display: none; + } + + /* Hide scrollbar for IE, Edge and Firefox */ + .taskbar { + -ms-overflow-style: none; + /* IE and Edge */ + scrollbar-width: none; + /* Firefox */ + } + } /***************************************************** From 0e45132c05aa1106503fef02b7e4c97ecc675e10 Mon Sep 17 00:00:00 2001 From: jelveh Date: Mon, 18 Nov 2024 07:22:13 -0800 Subject: [PATCH 1180/2119] feat: show profile pics in sharing notifications --- src/gui/src/UI/UIDesktop.js | 19 +++++++++++++++---- src/gui/src/UI/UINotification.js | 2 +- src/gui/src/helpers.js | 29 +++++++++++++++++++++++++++++ 3 files changed, 45 insertions(+), 5 deletions(-) diff --git a/src/gui/src/UI/UIDesktop.js b/src/gui/src/UI/UIDesktop.js index eec8c38bf3..549028b5a7 100644 --- a/src/gui/src/UI/UIDesktop.js +++ b/src/gui/src/UI/UIDesktop.js @@ -123,12 +123,23 @@ async function UIDesktop(options){ $(`.window[data-path="${html_encode(window.trash_path)}" i]`).find('.item-container').empty(); }) - window.socket.on('notif.message', ({ uid, notification }) => { - const icon = window.icons[notification.icon]; + window.socket.on('notif.message', async ({ uid, notification }) => { + let icon = window.icons[notification.icon]; + let round_icon = false; + + if(notification.template === "file-shared-with-you" && notification.fields?.username){ + let profile_pic = await get_profile_picture(notification.fields.username); + if(profile_pic){ + icon = profile_pic; + round_icon = true; + } + } + UINotification({ title: notification.title, text: notification.text, icon: icon, + round_icon: round_icon, value: notification, uid, close: async () => { @@ -1756,5 +1767,5 @@ window.reset_window_size_and_position = (el_window)=>{ left: 'calc(50% - 340px)', }); } - -export default UIDesktop; + +export default UIDesktop; \ No newline at end of file diff --git a/src/gui/src/UI/UINotification.js b/src/gui/src/UI/UINotification.js index c5b64fe529..127007ab45 100644 --- a/src/gui/src/UI/UINotification.js +++ b/src/gui/src/UI/UINotification.js @@ -25,7 +25,7 @@ function UINotification(options){ h += `
`; h += ``; h += `
`; - h += ``; + h += ``; h += `
`; h += `
`; h += `
${html_encode(options.title)}
`; diff --git a/src/gui/src/helpers.js b/src/gui/src/helpers.js index a968f59fe6..afec23e079 100644 --- a/src/gui/src/helpers.js +++ b/src/gui/src/helpers.js @@ -2651,4 +2651,33 @@ window.update_profile = function(username, key_vals){ // Ignored console.log(e); }); +} + +window.blob2str = (blob) => { + return new Promise((resolve, reject) => { + const reader = new FileReader(); + reader.onload = () => resolve(reader.result); + reader.onerror = reject; + reader.readAsText(blob); + }); +} + +window.get_profile_picture = async function(username){ + let icon; + // try getting profile pic + try{ + let stat = await puter.fs.stat('/' + username + '/Public/.profile'); + if(stat.size > 0 && stat.is_dir === false && stat.size < 1000000){ + let profile_json = await puter.fs.read('/' + username + '/Public/.profile'); + profile_json = await blob2str(profile_json); + const profile = JSON.parse(profile_json); + + if(profile.picture && profile.picture.startsWith('data:image')){ + icon = profile.picture; + } + } + }catch(e){ + } + + return icon; } \ No newline at end of file From 905b5d851ef68d923d8f7fbaddbe214cb812bae6 Mon Sep 17 00:00:00 2001 From: jelveh Date: Mon, 18 Nov 2024 10:40:15 -0800 Subject: [PATCH 1181/2119] fix: allow scrolling of user list in share window --- src/gui/src/UI/UIWindowShare.js | 2 +- src/gui/src/css/style.css | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/src/gui/src/UI/UIWindowShare.js b/src/gui/src/UI/UIWindowShare.js index f79c9c1b77..c31dc433c1 100644 --- a/src/gui/src/UI/UIWindowShare.js +++ b/src/gui/src/UI/UIWindowShare.js @@ -96,7 +96,7 @@ async function UIWindowShare(items, recipient){ // Already Shared With // ------------------------------------------------ h += `

People with access

`; - h += ``; diff --git a/src/gui/src/css/style.css b/src/gui/src/css/style.css index 7c97d318dd..772024aa07 100644 --- a/src/gui/src/css/style.css +++ b/src/gui/src/css/style.css @@ -2174,6 +2174,7 @@ label { .share-recipients { max-height: 200px; overflow: hidden; + overflow-y: scroll; } .ui-menu { From 4cc63b25801b9470dc3f136fcf05456eb8bc65a1 Mon Sep 17 00:00:00 2001 From: jelveh Date: Mon, 18 Nov 2024 11:29:15 -0800 Subject: [PATCH 1182/2119] Update UIWindowShare.js --- src/gui/src/UI/UIWindowShare.js | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/gui/src/UI/UIWindowShare.js b/src/gui/src/UI/UIWindowShare.js index c31dc433c1..59e190ef49 100644 --- a/src/gui/src/UI/UIWindowShare.js +++ b/src/gui/src/UI/UIWindowShare.js @@ -369,6 +369,9 @@ $(document).on('click', '.remove-permission-link', async function(){ let recipient_username = $(this).attr('data-recipient-username'); let permission = $(this).attr('data-permission'); + // remove from list. do this first so the user doesn't have to wait for the server + $('.item-perm-recipient-card[data-recipient-username="'+recipient_username+'"][data-permission="'+permission+'"]').remove(); + fetch(puter.APIOrigin + "/auth/revoke-user-user", { "headers": { "Content-Type": "application/json", @@ -380,7 +383,6 @@ $(document).on('click', '.remove-permission-link', async function(){ }), "method": "POST" }).then((response) => { - $('.item-perm-recipient-card[data-permission="'+permission+'"]').remove(); }).catch((err) => { console.error(err); }) From 7e7234b2f3fb89560108447cfd7fa87499ec6f38 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 19 Nov 2024 10:17:41 -0500 Subject: [PATCH 1183/2119] fix: update share email --- src/backend/src/services/EmailService.js | 8 +++++++- src/backend/src/structured/sequence/share.js | 1 + 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/backend/src/services/EmailService.js b/src/backend/src/services/EmailService.js index 6f03e70ba1..d00e76323a 100644 --- a/src/backend/src/services/EmailService.js +++ b/src/backend/src/services/EmailService.js @@ -143,7 +143,13 @@ If this was not you, please contact support@puter.com immediately. }, 'share_by_email': { subject: 'share by email', - html: `testing: {{link}}` + html: ` +

Hi there,

+

You've received a share from {{sender_name}} on Puter:

+

{{link}}

+

Sincerely,

+

Puter

+ ` }, } diff --git a/src/backend/src/structured/sequence/share.js b/src/backend/src/structured/sequence/share.js index 008e5b4f3d..26fc187f9a 100644 --- a/src/backend/src/structured/sequence/share.js +++ b/src/backend/src/structured/sequence/share.js @@ -591,6 +591,7 @@ module.exports = new Sequence([ await svc_email.send_email({ email }, 'share_by_email', { link: email_link, + sender_name: actor.type.user.username, }); } }, From 0fd3b1e61157d989d55e6dacba2add0e03d260e7 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 19 Nov 2024 11:08:54 -0500 Subject: [PATCH 1184/2119] fix: usage bug --- src/backend/src/services/drivers/DriverService.js | 7 ++++++- src/backend/src/services/sla/MonthlyUsageService.js | 3 ++- 2 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/backend/src/services/drivers/DriverService.js b/src/backend/src/services/drivers/DriverService.js index bca02abe90..033c082fff 100644 --- a/src/backend/src/services/drivers/DriverService.js +++ b/src/backend/src/services/drivers/DriverService.js @@ -320,10 +320,15 @@ class DriverService extends BaseService { { name: 'enforce monthly usage limit', on_call: async args => { + // Typo-Tolerance + if ( effective_policy['monthy-limit'] ) { + effective_policy['monthly-limit'] = effective_policy['monthy-limit']; + } + if ( ! effective_policy?.['monthly-limit'] ) return args; const svc_monthlyUsage = services.get('monthly-usage'); const count = await svc_monthlyUsage.check_2( - actor, method_key + actor, method_key, 0 ); if ( count >= effective_policy['monthly-limit'] ) { throw APIError.create('monthly_limit_exceeded', null, { diff --git a/src/backend/src/services/sla/MonthlyUsageService.js b/src/backend/src/services/sla/MonthlyUsageService.js index 696f311c33..329aec6ce2 100644 --- a/src/backend/src/services/sla/MonthlyUsageService.js +++ b/src/backend/src/services/sla/MonthlyUsageService.js @@ -63,7 +63,8 @@ class MonthlyUsageService extends BaseService { } - async check_2 (actor, key) { + async check_2 (actor, key, ver) { + // TODO: get 'ver' working here for future updates key = `${actor.uid}:${key}`; if ( actor.type instanceof UserActorType ) { return await this._user_check_2(actor, key); From 86789920c457c91d1ae88000d50e1b7759c2347a Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 19 Nov 2024 12:40:03 -0500 Subject: [PATCH 1185/2119] dev: apply all relevant shares on verified email --- src/backend/src/routers/_default.js | 6 +++ src/backend/src/routers/confirm-email.js | 6 +++ src/backend/src/services/ShareService.js | 49 ++++++++++++++++++++++++ 3 files changed, 61 insertions(+) diff --git a/src/backend/src/routers/_default.js b/src/backend/src/routers/_default.js index fe45f4cd9e..fe9eb2edca 100644 --- a/src/backend/src/routers/_default.js +++ b/src/backend/src/routers/_default.js @@ -272,6 +272,12 @@ router.all('*', async function(req, res, next) { const svc_referralCode = Context.get('services').get('referral-code'); svc_referralCode.on_verified(user); + + const svc_event = req.services.get('event'); + svc_event.emit('user.email-confirmed', { + user_uid: user.uuid, + email: user.email, + }); })(); } } diff --git a/src/backend/src/routers/confirm-email.js b/src/backend/src/routers/confirm-email.js index bf013c544a..d187b2cb93 100644 --- a/src/backend/src/routers/confirm-email.js +++ b/src/backend/src/routers/confirm-email.js @@ -72,6 +72,12 @@ router.post('/confirm-email', auth, express.json(), async (req, res, next)=>{ ); const svc_getUser = req.services.get('get-user'); await svc_getUser.get_user({ id: req.user.id, force: true }); + + const svc_event = req.services.get('event'); + svc_event.emit('user.email-confirmed', { + user_uid: req.user.uuid, + email: req.user.email, + }); } // Build response object diff --git a/src/backend/src/services/ShareService.js b/src/backend/src/services/ShareService.js index e3754648ab..c5bb1a6acb 100644 --- a/src/backend/src/services/ShareService.js +++ b/src/backend/src/services/ShareService.js @@ -51,6 +51,50 @@ class ShareService extends BaseService { return !! user.email_confirmed; } }); + + const svc_event = this.services.get('event'); + svc_event.on('user.email-confirmed', async (_, { user_uid, email }) => { + const user = await get_user({ uuid: user_uid }); + const relevant_shares = await this.db.read( + 'SELECT * FROM share WHERE recipient_email = ?', + [email], + ); + + for ( const share of relevant_shares ) { + share.data = this.db.case({ + mysql: () => share.data, + otherwise: () => + JSON.parse(share.data ?? '{}'), + })(); + + const issuer_user = await get_user({ + id: share.issuer_user_id, + }); + + if ( ! issuer_user ) { + continue; + } + + const issuer_actor = await Actor.create(UserActorType, { + user: issuer_user, + }); + + const svc_permission = this.services.get('permission'); + + for ( const permission of share.data.permissions ) { + await svc_permission.grant_user_user_permission( + issuer_actor, + user.username, + permission, + ); + } + + await this.db.write( + 'DELETE FROM share WHERE uid = ?', + [share.uid], + ); + } + }); } ['__on_install.routes'] (_, { app }) { @@ -170,6 +214,11 @@ class ShareService extends BaseService { permission, ); } + + await this.db.write( + 'DELETE FROM share WHERE uid = ?', + [share.uid], + ); res.json({ $: 'api:status-report', From 7ed557f375a961a5dd8cb2e36d82784d8e3e6af6 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 19 Nov 2024 13:08:39 -0500 Subject: [PATCH 1186/2119] dev: add fake chat service, for testing --- .../src/modules/puterai/FakeChatService.js | 37 +++++++++++++++++++ .../src/modules/puterai/PuterAIModule.js | 3 ++ 2 files changed, 40 insertions(+) create mode 100644 src/backend/src/modules/puterai/FakeChatService.js diff --git a/src/backend/src/modules/puterai/FakeChatService.js b/src/backend/src/modules/puterai/FakeChatService.js new file mode 100644 index 0000000000..915d390059 --- /dev/null +++ b/src/backend/src/modules/puterai/FakeChatService.js @@ -0,0 +1,37 @@ +const BaseService = require("../../services/BaseService"); + +class FakeChatService extends BaseService { + static IMPLEMENTS = { + ['puter-chat-completion']: { + async list () { + return ['fake']; + }, + async complete ({ messages, stream, model }) { + return { + message: { + "id": "00000000-0000-0000-0000-000000000000", + "type": "message", + "role": "assistant", + "model": "fake", + "content": [ + { + "type": "text", + "text": "I am a fake AI, I don't know how to respond to anything." + } + ], + "stop_reason": "end_turn", + "stop_sequence": null, + "usage": { + "input_tokens": 0, + "output_tokens": 1 + } + } + } + } + } + } +} + +module.exports = { + FakeChatService, +}; diff --git a/src/backend/src/modules/puterai/PuterAIModule.js b/src/backend/src/modules/puterai/PuterAIModule.js index df20aea0e5..a1241530f6 100644 --- a/src/backend/src/modules/puterai/PuterAIModule.js +++ b/src/backend/src/modules/puterai/PuterAIModule.js @@ -53,6 +53,9 @@ class PuterAIModule extends AdvancedBase { const { XAIService } = require('./XAIService'); services.registerService('xai', XAIService); } + + const { FakeChatService } = require('./FakeChatService'); + services.registerService('fake-chat', FakeChatService); } } From 01725ffebf86ed332087c877956e59570ea700ed Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 19 Nov 2024 13:08:58 -0500 Subject: [PATCH 1187/2119] fix: potential null-or-undefined in DriverService --- src/backend/src/services/drivers/DriverService.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/backend/src/services/drivers/DriverService.js b/src/backend/src/services/drivers/DriverService.js index 033c082fff..5973db5dd3 100644 --- a/src/backend/src/services/drivers/DriverService.js +++ b/src/backend/src/services/drivers/DriverService.js @@ -321,7 +321,7 @@ class DriverService extends BaseService { name: 'enforce monthly usage limit', on_call: async args => { // Typo-Tolerance - if ( effective_policy['monthy-limit'] ) { + if ( effective_policy?.['monthy-limit'] ) { effective_policy['monthly-limit'] = effective_policy['monthy-limit']; } From 65e6d6c09fd464b3fea979689fab5f26a2647c4a Mon Sep 17 00:00:00 2001 From: jelveh Date: Tue, 19 Nov 2024 10:52:42 -0800 Subject: [PATCH 1188/2119] fix: give camera and recorder write permission to Desktop --- src/gui/src/UI/UIDesktop.js | 42 ++++++++++++++++++++++++++++++++++++- src/gui/src/index.js | 1 - 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/src/gui/src/UI/UIDesktop.js b/src/gui/src/UI/UIDesktop.js index 549028b5a7..cc724ed555 100644 --- a/src/gui/src/UI/UIDesktop.js +++ b/src/gui/src/UI/UIDesktop.js @@ -51,8 +51,48 @@ async function UIDesktop(options){ channel.onmessage = function(e){ } - // channel.postMessage({'hello': 'world'}); + // Give Camera and Recorder write permissions to Desktop + puter.kv.get('has_set_default_app_user_permissions').then(async (user_permissions) => { + if(!user_permissions){ + // Camera + try{ + await fetch( window.api_origin + "/auth/grant-user-app", { + "headers": { + "Content-Type": "application/json", + "Authorization": "Bearer " + window.auth_token, + }, + "body": JSON.stringify({ + app_uid: 'app-5584fbf7-ed69-41fc-99cd-85da21b1ef51', + permission: `fs:${html_encode(window.desktop_path)}:write` + }), + "method": "POST", + }); + }catch(err){ + console.error(err); + } + + // Recorder + try{ + await fetch( window.api_origin + "/auth/grant-user-app", { + "headers": { + "Content-Type": "application/json", + "Authorization": "Bearer " + window.auth_token, + }, + "body": JSON.stringify({ + app_uid: 'app-7bdca1a4-6373-4c98-ad97-03ff2d608ca1', + permission: `fs:${html_encode(window.desktop_path)}:write` + }), + "method": "POST", + }); + }catch(err){ + console.error(err); + } + + // Set flag to true + puter.kv.set('has_set_default_app_user_permissions', true); + } + }) // connect socket. window.socket = io(window.gui_origin + '/', { auth: { diff --git a/src/gui/src/index.js b/src/gui/src/index.js index d476b5efd0..57a05ff63a 100644 --- a/src/gui/src/index.js +++ b/src/gui/src/index.js @@ -62,7 +62,6 @@ window.gui = async function(options){ // DEV: Load the initgui.js file if we are in development mode if(!window.gui_env || window.gui_env === "dev"){ await window.loadScript('/sdk/puter.dev.js'); - // await window.loadScript(`${options.asset_dir}/initgui.js`, {isModule: true}); } if (window.gui_env === 'dev2') { From e0f4c527f4eec3ba2fd46ee5425debdcc91d2d4b Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 19 Nov 2024 14:31:19 -0500 Subject: [PATCH 1189/2119] dev: migrate referral service and use user.email-confirmed event --- src/backend/src/routers/_default.js | 3 --- src/backend/src/services/ReferralCodeService.js | 16 +++++++++++----- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/src/backend/src/routers/_default.js b/src/backend/src/routers/_default.js index fe9eb2edca..085a81edc7 100644 --- a/src/backend/src/routers/_default.js +++ b/src/backend/src/routers/_default.js @@ -270,9 +270,6 @@ router.all('*', async function(req, res, next) { // return results h += `

Your email has been successfully confirmed.

`; - const svc_referralCode = Context.get('services').get('referral-code'); - svc_referralCode.on_verified(user); - const svc_event = req.services.get('event'); svc_event.emit('user.email-confirmed', { user_uid: user.uuid, diff --git a/src/backend/src/services/ReferralCodeService.js b/src/backend/src/services/ReferralCodeService.js index 07732cd902..b3660a4ffa 100644 --- a/src/backend/src/services/ReferralCodeService.js +++ b/src/backend/src/services/ReferralCodeService.js @@ -21,17 +21,23 @@ const { generate_random_code } = require('../util/identifier'); const { Context } = require('../util/context'); const { get_user } = require('../helpers'); const { DB_WRITE } = require('./database/consts'); +const BaseService = require('./BaseService'); -class ReferralCodeService { - constructor ({ services }) { - this.log = services.get('log-service').create('referral-service'); - this.errors = services.get('error-service').create(this.log); - +class ReferralCodeService extends BaseService { + _construct () { this.REFERRAL_INCREASE_LEFT = 1 * 1024 * 1024 * 1024; // 1 GB this.REFERRAL_INCREASE_RIGHT = 1 * 1024 * 1024 * 1024; // 1 GB this.STORAGE_INCREASE_STRING = '1 GB'; } + async _init () { + const svc_event = this.services.get('event'); + svc_event.on('user.email-confirmed', async (_, { user_uid }) => { + const user = await get_user({ uuid: user_uid }); + await this.on_verified(user); + }); + } + async gen_referral_code (user) { let iteration = 0; let rng = seedrandom(`gen1-${user.id}`); From dca7892fca479720ee80da61ea9328966ec9f7dd Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 19 Nov 2024 14:39:17 -0500 Subject: [PATCH 1190/2119] sync: update CoreModule --- src/backend/src/CoreModule.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/backend/src/CoreModule.js b/src/backend/src/CoreModule.js index 0394601fb7..11044452e4 100644 --- a/src/backend/src/CoreModule.js +++ b/src/backend/src/CoreModule.js @@ -347,6 +347,9 @@ const install = async ({ services, app, useapi, modapi }) => { const { CommentService } = require('./services/CommentService'); services.registerService('comment', CommentService); + + const { ReferralCodeService } = require('./services/ReferralCodeService'); + services.registerService('referral-code', ReferralCodeService); } const install_legacy = async ({ services }) => { @@ -355,7 +358,6 @@ const install_legacy = async ({ services }) => { const PerformanceMonitor = require('./monitor/PerformanceMonitor'); const { OperationTraceService } = require('./services/OperationTraceService'); const { WSPushService } = require('./services/WSPushService'); - const { ReferralCodeService } = require('./services/ReferralCodeService'); const { ClientOperationService } = require('./services/ClientOperationService'); const { EngPortalService } = require('./services/EngPortalService'); const { AppInformationService } = require('./services/AppInformationService'); @@ -366,7 +368,6 @@ const install_legacy = async ({ services }) => { // services.registerService('filesystem', FilesystemService); services.registerService('operationTrace', OperationTraceService); services.registerService('__event-push-ws', WSPushService); - services.registerService('referral-code', ReferralCodeService); services.registerService('file-cache', FileCacheService); services.registerService('client-operation', ClientOperationService); services.registerService('app-information', AppInformationService); From 0fa3be9d430442cb07e93c26205a78376aa1c446 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 19 Nov 2024 15:00:04 -0500 Subject: [PATCH 1191/2119] clean: cleanup backend logs --- src/backend/src/api/APIError.js | 1 - src/backend/src/drivers/DBKVStore.js | 2 -- src/backend/src/helpers.js | 4 +++- src/backend/src/om/entitystorage/AppES.js | 1 - src/backend/src/routers/open_item.js | 1 - .../src/services/FeatureFlagService.js | 1 - .../src/services/drivers/DriverService.js | 18 +++++++------- .../services/file-cache/FileCacheService.js | 1 - .../src/services/sla/MonthlyUsageService.js | 22 ++++++++--------- .../src/services/sla/RateLimitService.js | 24 +++++++++---------- .../src/unstructured/permission-scanners.js | 4 ---- src/backend/src/util/listenerutil.js | 1 - 12 files changed, 33 insertions(+), 47 deletions(-) diff --git a/src/backend/src/api/APIError.js b/src/backend/src/api/APIError.js index 55ab0bd649..fc32d7e37e 100644 --- a/src/backend/src/api/APIError.js +++ b/src/backend/src/api/APIError.js @@ -596,7 +596,6 @@ module.exports = class APIError { }); } serialize () { - console.log('MESSAGE FROM ERROR: ' + `|${this.message}|`); return { ...this.fields, $: 'heyputer:api/APIError', diff --git a/src/backend/src/drivers/DBKVStore.js b/src/backend/src/drivers/DBKVStore.js index a4e2f05cca..59b994bb6c 100644 --- a/src/backend/src/drivers/DBKVStore.js +++ b/src/backend/src/drivers/DBKVStore.js @@ -31,7 +31,6 @@ class DBKVStore extends Driver { } static METHODS = { get: async function ({ app_uid, key }) { - console.log('THIS WAS CALLED', { key }); const actor = this.context.get('actor'); // If the actor is an app then it gets its own KV store. @@ -67,7 +66,6 @@ class DBKVStore extends Driver { return kv[0]?.value ?? null; }, set: async function ({ app_uid, key, value }) { - console.log('THIS WAS CALLED (SET)', { key, value }) const actor = this.context.get('actor'); // Validate the key diff --git a/src/backend/src/helpers.js b/src/backend/src/helpers.js index e60d24e786..c9de4a8db3 100644 --- a/src/backend/src/helpers.js +++ b/src/backend/src/helpers.js @@ -1121,7 +1121,9 @@ async function jwt_auth(req){ token: token, }; }catch(e){ - console.log('ERROR', e); + if ( ! (e instanceof APIError) ) { + console.log('ERROR', e); + } throw(e.message); } } diff --git a/src/backend/src/om/entitystorage/AppES.js b/src/backend/src/om/entitystorage/AppES.js index 09f71e52fd..91f821f7ff 100644 --- a/src/backend/src/om/entitystorage/AppES.js +++ b/src/backend/src/om/entitystorage/AppES.js @@ -205,7 +205,6 @@ class AppES extends BaseES { })(); if ( ! is_owner ) { - for ( let i=0;i<20;i++ ) console.log('TYHIS IS HAPPEN'); entity.del('approved_for_listing'); entity.del('approved_for_opening_items'); entity.del('approved_for_incentive_program'); diff --git a/src/backend/src/routers/open_item.js b/src/backend/src/routers/open_item.js index b0489a5d12..1220d5aa62 100644 --- a/src/backend/src/routers/open_item.js +++ b/src/backend/src/routers/open_item.js @@ -65,7 +65,6 @@ module.exports = eggspress('/open_item', { const signature = await sign_file(subject.entry, action); const suggested_apps = await suggest_app_for_fsentry(subject.entry); - console.log('suggested apps?', suggested_apps); const apps_only_one = suggested_apps.slice(0,1); const _app = apps_only_one[0]; if ( ! _app ) { diff --git a/src/backend/src/services/FeatureFlagService.js b/src/backend/src/services/FeatureFlagService.js index 357ba7a8a4..65337fabad 100644 --- a/src/backend/src/services/FeatureFlagService.js +++ b/src/backend/src/services/FeatureFlagService.js @@ -17,7 +17,6 @@ class FeatureFlagService extends BaseService { async _init () { const svc_detailProvider = this.services.get('whoami'); svc_detailProvider.register_provider(async (context, out) => { - console.log(`\x1B[36;1mCALLED\x1B[0m`); if ( ! context.actor ) return; out.feature_flags = await this.get_summary(context.actor); }); diff --git a/src/backend/src/services/drivers/DriverService.js b/src/backend/src/services/drivers/DriverService.js index 5973db5dd3..74c180317a 100644 --- a/src/backend/src/services/drivers/DriverService.js +++ b/src/backend/src/services/drivers/DriverService.js @@ -105,7 +105,7 @@ class DriverService extends BaseService { try { return await this._call(o); } catch ( e ) { - console.error(e); + this.log.error('Driver error response: ' + e.toString()); return this._driver_response_from_error(e); } } @@ -194,7 +194,6 @@ class DriverService extends BaseService { } return { success: true, ...meta, result }; } catch ( e ) { - console.error(e); let for_user = (e instanceof APIError) || (e instanceof DriverError); if ( ! for_user ) this.errors.report(`driver:${iface}:${method}`, { source: e, @@ -205,6 +204,7 @@ class DriverService extends BaseService { args, } }); + this.log.error('Driver error response: ' + e.toString()); return this._driver_response_from_error(e, meta); } } @@ -294,8 +294,12 @@ class DriverService extends BaseService { effective_policy = effective_policy.policy; - console.log('EFFECTIVE', - JSON.stringify(effective_policy, undefined, ' ')); + this.log.info('Invoking Driver Call', { + service_name, + iface, + method, + policy: effective_policy + }); const method_key = `V1:${service_name}:${iface}:${method}`; @@ -400,12 +404,6 @@ class DriverService extends BaseService { async _driver_response_from_error (e, meta) { let serializable = (e instanceof APIError) || (e instanceof DriverError); - if ( serializable ) { - console.log('Serialized error test', JSON.stringify( - e.serialize(), null, 2 - )) - console.log('Serialized error message: ', e.serialize().message) - } return { success: false, ...meta, diff --git a/src/backend/src/services/file-cache/FileCacheService.js b/src/backend/src/services/file-cache/FileCacheService.js index 13378f25cd..c7113923fb 100644 --- a/src/backend/src/services/file-cache/FileCacheService.js +++ b/src/backend/src/services/file-cache/FileCacheService.js @@ -172,7 +172,6 @@ class FileCacheService extends AdvancedBase { } await this._precache_make_room(size); - console.log(`precache input key: ${key}`); this.precache.set(key, data); tracker.phase = FileTracker.PHASE_PRECACHE; })() diff --git a/src/backend/src/services/sla/MonthlyUsageService.js b/src/backend/src/services/sla/MonthlyUsageService.js index 329aec6ce2..6eddaa04dc 100644 --- a/src/backend/src/services/sla/MonthlyUsageService.js +++ b/src/backend/src/services/sla/MonthlyUsageService.js @@ -99,16 +99,16 @@ class MonthlyUsageService extends BaseService { // months are zero-indexed by getUTCMonth, which could be confusing const month = new Date().getUTCMonth() + 1; - console.log( - 'what check query?', - 'SELECT SUM(`count`) AS sum FROM `service_usage_monthly` ' + - 'WHERE `year` = ? AND `month` = ? AND `user_id` = ? ' + - 'AND `key` = ?', - [ - year, month, actor.type.user.id, - key, - ] - ); + // console.log( + // 'what check query?', + // 'SELECT SUM(`count`) AS sum FROM `service_usage_monthly` ' + + // 'WHERE `year` = ? AND `month` = ? AND `user_id` = ? ' + + // 'AND `key` = ?', + // [ + // year, month, actor.type.user.id, + // key, + // ] + // ); const rows = await this.db.read( 'SELECT SUM(`count`) AS sum FROM `service_usage_monthly` ' + 'WHERE `year` = ? AND `month` = ? AND `user_id` = ? ' + @@ -119,8 +119,6 @@ class MonthlyUsageService extends BaseService { ] ); - console.log('what rows?', rows); - return rows[0]?.sum || 0; } diff --git a/src/backend/src/services/sla/RateLimitService.js b/src/backend/src/services/sla/RateLimitService.js index 344e4599fe..bef5159231 100644 --- a/src/backend/src/services/sla/RateLimitService.js +++ b/src/backend/src/services/sla/RateLimitService.js @@ -63,10 +63,10 @@ class RateLimitService extends BaseService { window_start = ts_fr_sql(row.window_start); const count = row.count; - console.log( - 'set window_start and count from DATABASE', - { window_start, count } - ); + // console.log( + // 'set window_start and count from DATABASE', + // { window_start, count } + // ); kv.set(`${kvkey}:window_start`, window_start); kv.set(`${kvkey}:count`, count); @@ -89,20 +89,20 @@ class RateLimitService extends BaseService { ); } - console.log( - 'DEBUGGING COMPARISON', - { window_start, period, now: Date.now() } - ); + // console.log( + // 'DEBUGGING COMPARISON', + // { window_start, period, now: Date.now() } + // ); if ( window_start + period < Date.now() ) { window_start = Date.now(); kv.set(`${kvkey}:window_start`, window_start); kv.set(`${kvkey}:count`, 0); - console.log( - 'REFRESH window_start and count', - { window_start, count: 0 } - ); + // console.log( + // 'REFRESH window_start and count', + // { window_start, count: 0 } + // ); await this.db.write( 'UPDATE `rl_usage_fixed_window` SET `window_start` = ?, `count` = ? WHERE `key` = ?', diff --git a/src/backend/src/unstructured/permission-scanners.js b/src/backend/src/unstructured/permission-scanners.js index 06adc8f8a7..124ef348ad 100644 --- a/src/backend/src/unstructured/permission-scanners.js +++ b/src/backend/src/unstructured/permission-scanners.js @@ -126,12 +126,10 @@ const PERMISSION_SCANNERS = [ const svc_group = await a.iget('services').get('group'); const groups = await svc_group.list_groups_with_member( { user_id: actor.type.user.id }); - console.log('uh, groups?', actor.type.user.id, groups); const group_uids = {}; for ( const group of groups ) { group_uids[group.values.uid] = group; } - console.log('group uids', group_uids); for ( const issuer_username in hardcoded_user_group_permissions ) { const issuer_actor = new Actor({ @@ -141,12 +139,10 @@ const PERMISSION_SCANNERS = [ }); const issuer_groups = hardcoded_user_group_permissions[issuer_username]; - console.log('issuer groups', issuer_groups); for ( const group_uid in issuer_groups ) { if ( ! group_uids[group_uid] ) continue; const issuer_group = issuer_groups[group_uid]; for ( const permission of permission_options ) { - console.log('permission?', permission); if ( ! issuer_group.hasOwnProperty(permission) ) continue; const issuer_reading = await a.icall('scan', issuer_actor, permission) diff --git a/src/backend/src/util/listenerutil.js b/src/backend/src/util/listenerutil.js index 2a9416c87c..f6b3c8ee28 100644 --- a/src/backend/src/util/listenerutil.js +++ b/src/backend/src/util/listenerutil.js @@ -67,7 +67,6 @@ class RemoveFromArrayDetachable extends AlsoDetachable { } detach_ () { - for ( let i=0; i < 10; i++ ) console.log('THIS DOES GET CALLED'); const index = this.array.indexOf(this.element); if ( index !== -1 ) { this.array.splice(index, 1); From 36ca7f63aa7d5986bbd512652eae1d151c6deae9 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Tue, 19 Nov 2024 16:47:41 -0500 Subject: [PATCH 1192/2119] dev: update referral and share notifs --- src/backend/src/services/EmailService.js | 11 ++++++----- src/backend/src/services/NotificationService.js | 5 +++++ src/backend/src/services/ReferralCodeService.js | 16 +++++++++++++++- src/backend/src/structured/sequence/share.js | 13 +++++++++++++ 4 files changed, 39 insertions(+), 6 deletions(-) diff --git a/src/backend/src/services/EmailService.js b/src/backend/src/services/EmailService.js index d00e76323a..21ddfab1b9 100644 --- a/src/backend/src/services/EmailService.js +++ b/src/backend/src/services/EmailService.js @@ -132,21 +132,22 @@ If this was not you, please contact support@puter.com immediately. ` }, // TODO: revise email contents - 'share_existing_user': { + 'share_by_username': { subject: 'Puter share from {{susername}}', - html: ` + html: /*html*/`

Hi there {{rusername}},

-

{{link}}

+

You've received a share from {{susername}} on Puter.

+

Go to puter.com to check it out.

Sincerely,

Puter

` }, 'share_by_email': { subject: 'share by email', - html: ` + html: /*html*/`

Hi there,

You've received a share from {{sender_name}} on Puter:

-

{{link}}

+

{{link}}

Sincerely,

Puter

` diff --git a/src/backend/src/services/NotificationService.js b/src/backend/src/services/NotificationService.js index 89412e36b7..3be1d189a2 100644 --- a/src/backend/src/services/NotificationService.js +++ b/src/backend/src/services/NotificationService.js @@ -29,6 +29,10 @@ const UsernameNotifSelector = username => async (self) => { return [user.id]; }; +const UserIDNotifSelector = user_id => async (self) => { + return [user_id]; +}; + class NotificationService extends BaseService { static MODULES = { uuidv4: require('uuid').v4, @@ -214,4 +218,5 @@ class NotificationService extends BaseService { module.exports = { NotificationService, UsernameNotifSelector, + UserIDNotifSelector, }; diff --git a/src/backend/src/services/ReferralCodeService.js b/src/backend/src/services/ReferralCodeService.js index b3660a4ffa..151bc9af6b 100644 --- a/src/backend/src/services/ReferralCodeService.js +++ b/src/backend/src/services/ReferralCodeService.js @@ -22,6 +22,7 @@ const { Context } = require('../util/context'); const { get_user } = require('../helpers'); const { DB_WRITE } = require('./database/consts'); const BaseService = require('./BaseService'); +const { UsernameNotifSelector, UserIDNotifSelector } = require('./NotificationService'); class ReferralCodeService extends BaseService { _construct () { @@ -117,7 +118,20 @@ class ReferralCodeService extends BaseService { const svc_email = Context.get('services').get('email'); await svc_email.send_email (referred_by, 'new-referral', { storage_increase: this.STORAGE_INCREASE_STRING - }) + }); + + const svc_notification = Context.get('services').get('notification'); + svc_notification.notify(UserIDNotifSelector(referred_by.id), { + source: 'referral', + icon: 'c-check.svg', + text: `You have referred user ${user.username} and ` + + `have received ${this.STORAGE_INCREASE_STRING} of storage.`, + template: 'referral', + fields: { + storage_increase: this.STORAGE_INCREASE_STRING, + referred_username: user.username + } + }); } } diff --git a/src/backend/src/structured/sequence/share.js b/src/backend/src/structured/sequence/share.js index 26fc187f9a..b59fd4e207 100644 --- a/src/backend/src/structured/sequence/share.js +++ b/src/backend/src/structured/sequence/share.js @@ -485,6 +485,7 @@ module.exports = new Sequence([ const svc_permission = a.iget('services').get('permission'); const svc_notification = a.iget('services').get('notification'); + const svc_email = a.iget('services').get('email'); const actor = a.get('actor'); @@ -541,6 +542,18 @@ module.exports = new Sequence([ (files.length === 1 ? 'file' : 'files') + ' ' + 'with you.', }); + + + // Working on notifications + // Email should have a link to a shared file, right? + // .. how do I make those URLs? (gui feature) + await svc_email.send_email({ + email: recipient_item.user.email, + }, 'share_by_username', { + // link: // TODO: create a link to the shared file + susername: actor.type.user.username, + rusername: username, + }); result.recipients[recipient_item.i] = { $: 'api:status-report', status: 'success' }; From f693211348c5883f2eb93db142789a1804b8b4a2 Mon Sep 17 00:00:00 2001 From: jelveh Date: Tue, 19 Nov 2024 17:02:47 -0800 Subject: [PATCH 1193/2119] add: missing translation keys to different language files --- src/gui/src/UI/UIWindowShare.js | 24 +- src/gui/src/i18n/translations/ar.js | 20 +- src/gui/src/i18n/translations/bn.js | 23 + src/gui/src/i18n/translations/br.js | 658 +++++++++--------- src/gui/src/i18n/translations/da.js | 19 + src/gui/src/i18n/translations/de.js | 20 + src/gui/src/i18n/translations/emoji.js | 5 + src/gui/src/i18n/translations/en.js | 13 +- src/gui/src/i18n/translations/es.js | 19 + src/gui/src/i18n/translations/fa.js | 184 +++++ src/gui/src/i18n/translations/fi.js | 18 + src/gui/src/i18n/translations/fr.js | 20 + src/gui/src/i18n/translations/he.js | 19 + src/gui/src/i18n/translations/hi.js | 20 + src/gui/src/i18n/translations/hu.js | 504 +++++++------- src/gui/src/i18n/translations/hy.js | 18 + src/gui/src/i18n/translations/id.js | 20 +- src/gui/src/i18n/translations/ig.js | 19 + src/gui/src/i18n/translations/it.js | 18 + src/gui/src/i18n/translations/ja.js | 20 + src/gui/src/i18n/translations/ko.js | 20 + src/gui/src/i18n/translations/ku.js | 18 + src/gui/src/i18n/translations/nb.js | 178 ++++- src/gui/src/i18n/translations/nl.js | 19 + src/gui/src/i18n/translations/nn.js | 197 +++++- src/gui/src/i18n/translations/pl.js | 19 + src/gui/src/i18n/translations/pt.js | 18 + src/gui/src/i18n/translations/ro.js | 19 + src/gui/src/i18n/translations/ru.js | 20 + src/gui/src/i18n/translations/sv.js | 20 + src/gui/src/i18n/translations/ta.js | 20 + src/gui/src/i18n/translations/th.js | 23 + src/gui/src/i18n/translations/tr.js | 22 +- src/gui/src/i18n/translations/translations.js | 2 - src/gui/src/i18n/translations/ua.js | 22 + src/gui/src/i18n/translations/ur.js | 36 + src/gui/src/i18n/translations/vi.js | 19 + src/gui/src/i18n/translations/zh.js | 20 + src/gui/src/i18n/translations/zhtw.js | 18 + 39 files changed, 1784 insertions(+), 587 deletions(-) diff --git a/src/gui/src/UI/UIWindowShare.js b/src/gui/src/UI/UIWindowShare.js index 59e190ef49..7716257123 100644 --- a/src/gui/src/UI/UIWindowShare.js +++ b/src/gui/src/UI/UIWindowShare.js @@ -82,8 +82,8 @@ async function UIWindowShare(items, recipient){ h += ``; // type h += ``; // Share @@ -95,13 +95,13 @@ async function UIWindowShare(items, recipient){ // ------------------------------------------------ // Already Shared With // ------------------------------------------------ - h += `

People with access

`; + h += `

${i18n('People with access')}

`; h += ``; h += `
`; const el_window = await UIWindow({ - title: 'Share With…', + title: i18n('Share With…'), icon: null, uid: null, is_dir: false, @@ -164,7 +164,7 @@ async function UIWindowShare(items, recipient){ //check if this user has been printed here before, important for multiple items if(!printed_users.includes(fsentry.owner.username)){ perm_list += `
` - perm_list += `
owner
`; + perm_list += `
${i18n('Owner')}
`; if(fsentry.owner.username === window.user.username) perm_list += `You (${fsentry.owner.email ?? fsentry.owner.username})`; else @@ -185,9 +185,9 @@ async function UIWindowShare(items, recipient){ // viewer/editor perm_list += `
`; if(perm.access === 'read') - perm_list += `viewer`; + perm_list += `${i18n('Viewer')}`; else if(perm.access === 'write') - perm_list += `editor`; + perm_list += `${i18n('Editor')}`; perm_list += `
`; // username perm_list += `${perm.user.email ?? perm.user.username}`; @@ -237,19 +237,19 @@ async function UIWindowShare(items, recipient){ }) if(recipient_already_in_list){ - $(el_window).find('.error').html('This user already has access to this item'); + $(el_window).find('.error').html(i18n('This user already has access to this item')); $(el_window).find('.error').fadeIn(); return; } // can't share with self if(recipient_username === window.user.username){ - $(el_window).find('.error').html('You can\'t share with yourself'); + $(el_window).find('.error').html(i18n("You can't share with yourself.")); $(el_window).find('.error').fadeIn(); return; } else if(recipient_email && recipient_email === window.user.email){ - $(el_window).find('.error').html('You can\'t share with yourself'); + $(el_window).find('.error').html(i18n("You can't share with yourself.")); $(el_window).find('.error').fadeIn(); return; } @@ -303,9 +303,9 @@ async function UIWindowShare(items, recipient){ // viewer/editor perm_list += `
`; if(access_level === 'read') - perm_list += `viewer`; + perm_list += `${i18n('Viewer')}`; else if(access_level === 'write') - perm_list += `editor`; + perm_list += `i18n('Viewer')`; perm_list += `
`; // recipient username perm_list += `${recipient_username}`; diff --git a/src/gui/src/i18n/translations/ar.js b/src/gui/src/i18n/translations/ar.js index 6cf2074fcc..d57fb9ea76 100644 --- a/src/gui/src/i18n/translations/ar.js +++ b/src/gui/src/i18n/translations/ar.js @@ -344,7 +344,25 @@ const ar = { login2fa_recovery_instructions: "أدخل أحد رموز الاسترداد الخاصة بك للوصول إلى حسابك.", login2fa_use_recovery_code: "استخدام رمز الاسترداد", login2fa_recovery_back: "الرجوع", - login2fa_recovery_placeholder: "XXXXXXXX" + login2fa_recovery_placeholder: "XXXXXXXX", + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" } }; diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index eb9a79a73a..6f18fd559a 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -348,6 +348,29 @@ const bn = { login2fa_use_recovery_code: "একটি পুনরুদ্ধার কোড ব্যবহার করুন", login2fa_recovery_back: "পিছনে", login2fa_recovery_placeholder: "XXXXXXXX", + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "password_recovery_token_invalid": undefined, // In English: "This password recovery token is no longer valid." + "password_recovery_unknown_error": undefined, // In English: "An unknown error occurred. Please try again later." + "password_required": undefined, // In English: "Password is required." + "password_strength_error": undefined, // In English: "Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, one number, and one special character." + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" + }, }; diff --git a/src/gui/src/i18n/translations/br.js b/src/gui/src/i18n/translations/br.js index e46761a821..776e0ddf2e 100644 --- a/src/gui/src/i18n/translations/br.js +++ b/src/gui/src/i18n/translations/br.js @@ -24,328 +24,346 @@ const br = { code: "br", dictionary: { about: "Sobre", - account: "Conta", - account_password: "Verificar Senha da Conta", - access_granted_to: "Acesso Concedido Para", - add_existing_account: "Adicionar Conta Existente", - all_fields_required: 'Todos os campos são obrigatórios.', - allow: 'Permitir', - apply: "Aplicar", - ascending: 'Ascendente', - associated_websites: "Sites Associados", - auto_arrange: 'Organizar Automaticamente', - background: "Plano de Fundo", - browse: "Navegar", - cancel: 'Cancelar', - center: 'Centralizar', - change_desktop_background: 'Mudar plano de fundo da área de trabalho…', - change_email: "Mudar Email", - change_language: "Mudar Idioma", - change_password: "Mudar Senha", - change_ui_colors: "Mudar Cores da Interface", - change_username: "Mudar Nome de Usuário", - close: 'Fechar', - close_all_windows: "Fechar Todas as Janelas", - close_all_windows_confirm: "Tem certeza de que deseja fechar todas as janelas?", - close_all_windows_and_log_out: 'Fechar Janelas e Sair', - change_always_open_with: "Deseja sempre abrir este tipo de arquivo com", - color: 'Cor', - confirm: 'Confirmar', - confirm_2fa_setup: 'Adicionei o código ao meu aplicativo autenticador', - confirm_2fa_recovery: 'Salvei meus códigos de recuperação em um local seguro', - confirm_account_for_free_referral_storage_c2a: 'Crie uma conta e confirme seu endereço de e-mail para receber 1 GB de armazenamento gratuito. Seu amigo também receberá 1 GB de armazenamento gratuito.', - confirm_code_generic_incorrect: "Código Incorreto.", - confirm_code_generic_too_many_requests: "Muitas solicitações. Por favor, aguarde alguns minutos.", - confirm_code_generic_submit: "Enviar Código", - confirm_code_generic_try_again: "Tente Novamente", - confirm_code_generic_title: "Digite o Código de Confirmação", - confirm_code_2fa_instruction: "Digite o código de 6 dígitos do seu aplicativo autenticador.", - confirm_code_2fa_submit_btn: "Enviar", - confirm_code_2fa_title: "Digite o Código 2FA", - confirm_delete_multiple_items: 'Tem certeza de que deseja excluir permanentemente estes itens?', - confirm_delete_single_item: 'Deseja excluir permanentemente este item?', - confirm_open_apps_log_out: 'Você tem aplicativos abertos. Tem certeza de que deseja sair?', - confirm_new_password: "Confirmar Nova Senha", - confirm_delete_user: "Tem certeza de que deseja excluir sua conta? Todos os seus arquivos e dados serão permanentemente excluídos. Esta ação não pode ser desfeita.", - confirm_delete_user_title: "Excluir Conta?", - confirm_session_revoke: "Tem certeza de que deseja revogar esta sessão?", - confirm_your_email_address: "Confirme Seu Endereço de Email", - contact_us: "Fale Conosco", - contact_us_verification_required: "Você deve ter um endereço de e-mail verificado para usar isto.", - contain: 'Conter', - continue: "Continuar", - copy: 'Copiar', - copy_link: "Copiar Link", - copying: "Copiando", - copying_file: "Copiando %%", - cover: 'Cobrir', - create_account: "Criar Conta", - create_free_account: "Criar Conta Gratuita", - create_shortcut: "Criar Atalho", - credits: "Créditos", - current_password: "Senha Atual", - cut: 'Recortar', - clock: "Relógio", - clock_visible_hide: 'Ocultar - Sempre oculto', - clock_visible_show: 'Mostrar - Sempre visível', - clock_visible_auto: 'Auto - Padrão, visível apenas no modo de tela cheia.', - close_all: 'Fechar Tudo', - created: 'Criado', - date_modified: 'Data de modificação', - default: 'Padrão', - delete: 'Excluir', - delete_account: "Excluir Conta", - delete_permanently: "Excluir Permanentemente", - deleting_file: "Excluindo %%", - deploy_as_app: 'Implantar como aplicativo', - descending: 'Descendente', - desktop: 'Área de Trabalho', - desktop_background_fit: "Ajustar", - developers: "Desenvolvedores", - dir_published_as_website: `%strong% foi publicado em:`, - disable_2fa: 'Desativar 2FA', - disable_2fa_confirm: "Tem certeza de que deseja desativar 2FA?", - disable_2fa_instructions: "Digite sua senha para desativar 2FA.", - disassociate_dir: "Desassociar Diretório", - documents: 'Documentos', - dont_allow: 'Não Permitir', - download: 'Baixar', - download_file: 'Baixar Arquivo', - downloading: "Baixando", - email: "Email", - email_change_confirmation_sent: "Um e-mail de confirmação foi enviado para seu novo endereço de e-mail. Por favor, verifique sua caixa de entrada e siga as instruções para concluir o processo.", - email_invalid: 'Email inválido.', - email_or_username: "Email ou Nome de Usuário", - email_required: 'Email é obrigatório.', - empty_trash: 'Esvaziar Lixeira', - empty_trash_confirmation: `Tem certeza de que deseja excluir permanentemente os itens na Lixeira?`, - emptying_trash: 'Esvaziando Lixeira…', - enable_2fa: 'Ativar 2FA', - end_hard: "Finalizar Forçadamente", - end_process_force_confirm: "Tem certeza de que deseja finalizar forçadamente este processo?", - end_soft: "Finalizar Suavemente", - enlarged_qr_code: "Código QR Ampliado", - enter_password_to_confirm_delete_user: "Digite sua senha para confirmar a exclusão da conta", - error_message_is_missing: "Mensagem de erro está ausente.", - error_unknown_cause: "Ocorreu um erro desconhecido.", - error_uploading_files: "Falha ao carregar arquivos", - favorites: "Favoritos", - feedback: "Feedback", - feedback_c2a: "Por favor, use o formulário abaixo para nos enviar seu feedback, comentários e relatórios de bugs.", - feedback_sent_confirmation: "Obrigado por nos contatar. Se você tiver um e-mail associado à sua conta, você receberá uma resposta nossa o mais rápido possível.", - fit: "Ajustar", - folder: 'Pasta', - force_quit: 'Forçar Encerrar', - forgot_pass_c2a: "Esqueceu a senha?", - from: "De", - general: "Geral", - get_a_copy_of_on_puter: `Obtenha uma cópia de '%%' em Puter.com!`, - get_copy_link: 'Obter Link de Cópia', - hide_all_windows: "Ocultar Todas as Janelas", - home: 'Início', - html_document: 'Documento HTML', - hue: 'Matiz', - image: 'Imagem', - incorrect_password: "Senha incorreta", - invite_link: "Link de Convite", - item: 'item', - items_in_trash_cannot_be_renamed: `Este item não pode ser renomeado porque está na lixeira. Para renomear este item, primeiro arraste-o para fora da Lixeira.`, - jpeg_image: 'Imagem JPEG', - keep_in_taskbar: 'Manter na Barra de Tarefas', - language: "Idioma", - license: "Licença", - lightness: 'Luminosidade', - link_copied: "Link copiado", - loading: 'Carregando', - log_in: "Entrar", - log_into_another_account_anyway: 'Entrar em outra conta de qualquer maneira', - log_out: 'Sair', - looks_good: "Parece bom!", - manage_sessions: "Gerenciar Sessões", - menubar_style: "Estilo da Barra de Menus", - menubar_style_desktop: "Área de Trabalho", - menubar_style_system: "Sistema", - menubar_style_window: "Janela", - modified: 'Modificado', - move: 'Mover', - moving_file: "Movendo %%", - my_websites: "Meus Sites", - name: 'Nome', - name_cannot_be_empty: 'O nome não pode estar vazio.', - name_cannot_contain_double_period: "O nome não pode ser o caractere '..'.", - name_cannot_contain_period: "O nome não pode ser o caractere '.'.", - name_cannot_contain_slash: "O nome não pode conter o caractere '/'.", - name_must_be_string: "O nome só pode ser uma string.", - name_too_long: `O nome não pode ter mais de %% caracteres.`, - new: 'Novo', - new_email: 'Novo Email', - new_folder: 'Nova pasta', - new_password: "Nova Senha", - new_username: "Novo Nome de Usuário", - "no": "Não", - "no_dir_associated_with_site": "Nenhum diretório associado a este endereço.", - "no_websites_published": "Você ainda não publicou nenhum site.", - "ok": "OK", - "open": "Abrir", - "open_in_new_tab": "Abrir em Nova Aba", - "open_in_new_window": "Abrir em Nova Janela", - "open_with": "Abrir Com", - "original_name": "Nome Original", - "original_path": "Caminho Original", - "oss_code_and_content": "Software e Conteúdo de Código Aberto", - "password": "Senha", - "password_changed": "Senha alterada.", - "password_recovery_rate_limit": "Você atingiu nosso limite de tentativas; por favor, aguarde alguns minutos. Para evitar isso no futuro, evite recarregar a página muitas vezes.", - "password_recovery_token_invalid": "Este token de recuperação de senha não é mais válido.", - "password_recovery_unknown_error": "Ocorreu um erro desconhecido. Por favor, tente novamente mais tarde.", - "password_required": "Senha é necessária.", - "password_strength_error": "A senha deve ter pelo menos 8 caracteres e conter pelo menos uma letra maiúscula, uma letra minúscula, um número e um caractere especial.", - "passwords_do_not_match": "`Nova Senha` e `Confirmar Nova Senha` não correspondem.", - "paste": "Colar", - "paste_into_folder": "Colar na Pasta", - "path": "Caminho", - "personalization": "Personalização", - "pick_name_for_website": "Escolha um nome para o seu site:", - "picture": "Imagem", - "pictures": "Imagens", - "plural_suffix": "s", - "powered_by_puter_js": "Desenvolvido por {{link=docs}}Puter.js{{/link}}", - "preparing": "Preparando...", - "preparing_for_upload": "Preparando para upload...", - "print": "Imprimir", - "privacy": "Privacidade", - "proceed_to_login": "Prossiga para o login", - "proceed_with_account_deletion": "Prosseguir com a Exclusão da Conta", - "process_status_initializing": "Inicializando", - "process_status_running": "Executando", - "process_type_app": "App", - "process_type_init": "Início", - "process_type_ui": "UI", - "properties": "Propriedades", - "public": "Público", - "publish": "Publicar", - "publish_as_website": "Publicar como site", - "puter_description": "Puter é uma nuvem pessoal que prioriza a privacidade para manter todos os seus arquivos, aplicativos e jogos em um lugar seguro, acessível de qualquer lugar a qualquer momento.", - "reading_file": "Lendo %strong%", - "recent": "Recente", - "recommended": "Recomendado", - "recover_password": "Recuperar Senha", - "refer_friends_c2a": "Ganhe 1 GB para cada amigo que criar e confirmar uma conta no Puter. Seu amigo também ganhará 1 GB!", - "refer_friends_social_media_c2a": "Ganhe 1 GB de armazenamento gratuito no Puter.com!", - "refresh": "Atualizar", - "release_address_confirmation": "Tem certeza de que deseja liberar este endereço?", - "remove_from_taskbar": "Remover da Barra de Tarefas", - "rename": "Renomear", - "repeat": "Repetir", - "replace": "Substituir", - "replace_all": "Substituir Todos", - "resend_confirmation_code": "Reenviar Código de Confirmação", - "reset_colors": "Redefinir Cores", - "restart_puter_confirm": "Tem certeza de que deseja reiniciar o Puter?", - "restore": "Restaurar", - "save": "Salvar", - "saturation": "Saturação", - "save_account": "Salvar conta", - "save_account_to_get_copy_link": "Por favor, crie uma conta para prosseguir.", - "save_account_to_publish": "Por favor, crie uma conta para prosseguir.", - "save_session": "Salvar sessão", - "save_session_c2a": "Crie uma conta para salvar sua sessão atual e evitar perder seu trabalho.", - "scan_qr_c2a": "Escaneie o código abaixo para fazer login nesta sessão a partir de outros dispositivos", - "scan_qr_2fa": "Escaneie o código QR com seu aplicativo autenticador", - "scan_qr_generic": "Escaneie este código QR usando seu telefone ou outro dispositivo", - "search": "Buscar", - "seconds": "segundos", - "security": "Segurança", - "select": "Selecionar", - "selected": "selecionado", - "select_color": "Selecionar cor…", - "sessions": "Sessões", - "send": "Enviar", - "send_password_recovery_email": "Enviar E-mail de Recuperação de Senha", - "session_saved": "Obrigado por criar uma conta. Esta sessão foi salva.", - "settings": "Configurações", - "set_new_password": "Definir Nova Senha", - "share": "Compartilhar", - "share_to": "Compartilhar para", - "share_with": "Compartilhar com:", - "shortcut_to": "Atalho para", - "show_all_windows": "Mostrar Todas as Janelas", - "show_hidden": "Mostrar ocultos", - "sign_in_with_puter": "Entrar com Puter", - "sign_up": "Cadastrar-se", - "signing_in": "Entrando...", - "size": "Tamanho", - "skip": "Pular", - "something_went_wrong": "Algo deu errado.", - "sort_by": "Ordenar por", - "start": "Iniciar", - "status": "Status", - "storage_usage": "Uso de Armazenamento", - "storage_puter_used": "usado pelo Puter", - "taking_longer_than_usual": "Levando um pouco mais de tempo do que o normal. Por favor, aguarde...", - "task_manager": "Gerenciador de Tarefas", - "taskmgr_header_name": "Nome", - "taskmgr_header_status": "Status", - "taskmgr_header_type": "Tipo", - "terms": "Termos", - "text_document": "Documento de texto", - "tos_fineprint": "Ao clicar em 'Criar Conta Gratuita' você concorda com os {{link=terms}}Termos de Serviço{{/link}} e a {{link=privacy}}Política de Privacidade{{/link}} do Puter.", - "transparency": "Transparência", - "trash": "Lixeira", - "two_factor": "Autenticação de Dois Fatores", - "two_factor_disabled": "2FA Desativada", - "two_factor_enabled": "2FA Ativada", - "type": "Tipo", - "type_confirm_to_delete_account": "Digite 'confirmar' para excluir sua conta.", - "ui_colors": "Cores da Interface", - "ui_manage_sessions": "Gerenciador de Sessões", - "ui_revoke": "Revogar", - "undo": "Desfazer", - "unlimited": "Ilimitado", - "unzip": "Descompactar", - "upload": "Upload", - "upload_here": "Fazer upload aqui", - "usage": "Uso", - "username": "Nome de Usuário", - "username_changed": "Nome de usuário atualizado com sucesso.", - "username_required": "Nome de usuário é necessário.", - "versions": "Versões", - "videos": "Vídeos", - "visibility": "Visibilidade", - "yes": "Sim", - "yes_release_it": "Sim, Liberar", - "you_have_been_referred_to_puter_by_a_friend": "Você foi indicado ao Puter por um amigo!", - "zip": "Compactar", - "zipping_file": "Compactando %strong%", - - // === 2FA Setup === - "setup2fa_1_step_heading": "Abra seu aplicativo autenticador", - "setup2fa_1_instructions": ` - Você pode usar qualquer aplicativo autenticador que suporte o protocolo de Senha de Uso Único com Base em Tempo (TOTP). - Existem muitas opções, mas se você não tiver certeza - Authy - é uma escolha sólida para Android e iOS. - `, - "setup2fa_2_step_heading": "Escaneie o código QR", - "setup2fa_3_step_heading": "Digite o código de 6 dígitos", - "setup2fa_4_step_heading": "Copie seus códigos de recuperação", - "setup2fa_4_instructions": ` - Esses códigos de recuperação são a única maneira de acessar sua conta se você perder seu telefone ou não puder usar seu aplicativo autenticador. - Certifique-se de armazená-los em um lugar seguro. + account: "Conta", + account_password: "Verificar Senha da Conta", + access_granted_to: "Acesso Concedido Para", + add_existing_account: "Adicionar Conta Existente", + all_fields_required: 'Todos os campos são obrigatórios.', + allow: 'Permitir', + apply: "Aplicar", + ascending: 'Ascendente', + associated_websites: "Sites Associados", + auto_arrange: 'Organizar Automaticamente', + background: "Plano de Fundo", + browse: "Navegar", + cancel: 'Cancelar', + center: 'Centralizar', + change_desktop_background: 'Mudar plano de fundo da área de trabalho…', + change_email: "Mudar Email", + change_language: "Mudar Idioma", + change_password: "Mudar Senha", + change_ui_colors: "Mudar Cores da Interface", + change_username: "Mudar Nome de Usuário", + close: 'Fechar', + close_all_windows: "Fechar Todas as Janelas", + close_all_windows_confirm: "Tem certeza de que deseja fechar todas as janelas?", + close_all_windows_and_log_out: 'Fechar Janelas e Sair', + change_always_open_with: "Deseja sempre abrir este tipo de arquivo com", + color: 'Cor', + confirm: 'Confirmar', + confirm_2fa_setup: 'Adicionei o código ao meu aplicativo autenticador', + confirm_2fa_recovery: 'Salvei meus códigos de recuperação em um local seguro', + confirm_account_for_free_referral_storage_c2a: 'Crie uma conta e confirme seu endereço de e-mail para receber 1 GB de armazenamento gratuito. Seu amigo também receberá 1 GB de armazenamento gratuito.', + confirm_code_generic_incorrect: "Código Incorreto.", + confirm_code_generic_too_many_requests: "Muitas solicitações. Por favor, aguarde alguns minutos.", + confirm_code_generic_submit: "Enviar Código", + confirm_code_generic_try_again: "Tente Novamente", + confirm_code_generic_title: "Digite o Código de Confirmação", + confirm_code_2fa_instruction: "Digite o código de 6 dígitos do seu aplicativo autenticador.", + confirm_code_2fa_submit_btn: "Enviar", + confirm_code_2fa_title: "Digite o Código 2FA", + confirm_delete_multiple_items: 'Tem certeza de que deseja excluir permanentemente estes itens?', + confirm_delete_single_item: 'Deseja excluir permanentemente este item?', + confirm_open_apps_log_out: 'Você tem aplicativos abertos. Tem certeza de que deseja sair?', + confirm_new_password: "Confirmar Nova Senha", + confirm_delete_user: "Tem certeza de que deseja excluir sua conta? Todos os seus arquivos e dados serão permanentemente excluídos. Esta ação não pode ser desfeita.", + confirm_delete_user_title: "Excluir Conta?", + confirm_session_revoke: "Tem certeza de que deseja revogar esta sessão?", + confirm_your_email_address: "Confirme Seu Endereço de Email", + contact_us: "Fale Conosco", + contact_us_verification_required: "Você deve ter um endereço de e-mail verificado para usar isto.", + contain: 'Conter', + continue: "Continuar", + copy: 'Copiar', + copy_link: "Copiar Link", + copying: "Copiando", + copying_file: "Copiando %%", + cover: 'Cobrir', + create_account: "Criar Conta", + create_free_account: "Criar Conta Gratuita", + create_shortcut: "Criar Atalho", + credits: "Créditos", + current_password: "Senha Atual", + cut: 'Recortar', + clock: "Relógio", + clock_visible_hide: 'Ocultar - Sempre oculto', + clock_visible_show: 'Mostrar - Sempre visível', + clock_visible_auto: 'Auto - Padrão, visível apenas no modo de tela cheia.', + close_all: 'Fechar Tudo', + created: 'Criado', + date_modified: 'Data de modificação', + default: 'Padrão', + delete: 'Excluir', + delete_account: "Excluir Conta", + delete_permanently: "Excluir Permanentemente", + deleting_file: "Excluindo %%", + deploy_as_app: 'Implantar como aplicativo', + descending: 'Descendente', + desktop: 'Área de Trabalho', + desktop_background_fit: "Ajustar", + developers: "Desenvolvedores", + dir_published_as_website: `%strong% foi publicado em:`, + disable_2fa: 'Desativar 2FA', + disable_2fa_confirm: "Tem certeza de que deseja desativar 2FA?", + disable_2fa_instructions: "Digite sua senha para desativar 2FA.", + disassociate_dir: "Desassociar Diretório", + documents: 'Documentos', + dont_allow: 'Não Permitir', + download: 'Baixar', + download_file: 'Baixar Arquivo', + downloading: "Baixando", + email: "Email", + email_change_confirmation_sent: "Um e-mail de confirmação foi enviado para seu novo endereço de e-mail. Por favor, verifique sua caixa de entrada e siga as instruções para concluir o processo.", + email_invalid: 'Email inválido.', + email_or_username: "Email ou Nome de Usuário", + email_required: 'Email é obrigatório.', + empty_trash: 'Esvaziar Lixeira', + empty_trash_confirmation: `Tem certeza de que deseja excluir permanentemente os itens na Lixeira?`, + emptying_trash: 'Esvaziando Lixeira…', + enable_2fa: 'Ativar 2FA', + end_hard: "Finalizar Forçadamente", + end_process_force_confirm: "Tem certeza de que deseja finalizar forçadamente este processo?", + end_soft: "Finalizar Suavemente", + enlarged_qr_code: "Código QR Ampliado", + enter_password_to_confirm_delete_user: "Digite sua senha para confirmar a exclusão da conta", + error_message_is_missing: "Mensagem de erro está ausente.", + error_unknown_cause: "Ocorreu um erro desconhecido.", + error_uploading_files: "Falha ao carregar arquivos", + favorites: "Favoritos", + feedback: "Feedback", + feedback_c2a: "Por favor, use o formulário abaixo para nos enviar seu feedback, comentários e relatórios de bugs.", + feedback_sent_confirmation: "Obrigado por nos contatar. Se você tiver um e-mail associado à sua conta, você receberá uma resposta nossa o mais rápido possível.", + fit: "Ajustar", + folder: 'Pasta', + force_quit: 'Forçar Encerrar', + forgot_pass_c2a: "Esqueceu a senha?", + from: "De", + general: "Geral", + get_a_copy_of_on_puter: `Obtenha uma cópia de '%%' em Puter.com!`, + get_copy_link: 'Obter Link de Cópia', + hide_all_windows: "Ocultar Todas as Janelas", + home: 'Início', + html_document: 'Documento HTML', + hue: 'Matiz', + image: 'Imagem', + incorrect_password: "Senha incorreta", + invite_link: "Link de Convite", + item: 'item', + items_in_trash_cannot_be_renamed: `Este item não pode ser renomeado porque está na lixeira. Para renomear este item, primeiro arraste-o para fora da Lixeira.`, + jpeg_image: 'Imagem JPEG', + keep_in_taskbar: 'Manter na Barra de Tarefas', + language: "Idioma", + license: "Licença", + lightness: 'Luminosidade', + link_copied: "Link copiado", + loading: 'Carregando', + log_in: "Entrar", + log_into_another_account_anyway: 'Entrar em outra conta de qualquer maneira', + log_out: 'Sair', + looks_good: "Parece bom!", + manage_sessions: "Gerenciar Sessões", + menubar_style: "Estilo da Barra de Menus", + menubar_style_desktop: "Área de Trabalho", + menubar_style_system: "Sistema", + menubar_style_window: "Janela", + modified: 'Modificado', + move: 'Mover', + moving_file: "Movendo %%", + my_websites: "Meus Sites", + name: 'Nome', + name_cannot_be_empty: 'O nome não pode estar vazio.', + name_cannot_contain_double_period: "O nome não pode ser o caractere '..'.", + name_cannot_contain_period: "O nome não pode ser o caractere '.'.", + name_cannot_contain_slash: "O nome não pode conter o caractere '/'.", + name_must_be_string: "O nome só pode ser uma string.", + name_too_long: `O nome não pode ter mais de %% caracteres.`, + new: 'Novo', + new_email: 'Novo Email', + new_folder: 'Nova pasta', + new_password: "Nova Senha", + new_username: "Novo Nome de Usuário", + "no": "Não", + "no_dir_associated_with_site": "Nenhum diretório associado a este endereço.", + "no_websites_published": "Você ainda não publicou nenhum site.", + "ok": "OK", + "open": "Abrir", + "open_in_new_tab": "Abrir em Nova Aba", + "open_in_new_window": "Abrir em Nova Janela", + "open_with": "Abrir Com", + "original_name": "Nome Original", + "original_path": "Caminho Original", + "oss_code_and_content": "Software e Conteúdo de Código Aberto", + "password": "Senha", + "password_changed": "Senha alterada.", + "password_recovery_rate_limit": "Você atingiu nosso limite de tentativas; por favor, aguarde alguns minutos. Para evitar isso no futuro, evite recarregar a página muitas vezes.", + "password_recovery_token_invalid": "Este token de recuperação de senha não é mais válido.", + "password_recovery_unknown_error": "Ocorreu um erro desconhecido. Por favor, tente novamente mais tarde.", + "password_required": "Senha é necessária.", + "password_strength_error": "A senha deve ter pelo menos 8 caracteres e conter pelo menos uma letra maiúscula, uma letra minúscula, um número e um caractere especial.", + "passwords_do_not_match": "`Nova Senha` e `Confirmar Nova Senha` não correspondem.", + "paste": "Colar", + "paste_into_folder": "Colar na Pasta", + "path": "Caminho", + "personalization": "Personalização", + "pick_name_for_website": "Escolha um nome para o seu site:", + "picture": "Imagem", + "pictures": "Imagens", + "plural_suffix": "s", + "powered_by_puter_js": "Desenvolvido por {{link=docs}}Puter.js{{/link}}", + "preparing": "Preparando...", + "preparing_for_upload": "Preparando para upload...", + "print": "Imprimir", + "privacy": "Privacidade", + "proceed_to_login": "Prossiga para o login", + "proceed_with_account_deletion": "Prosseguir com a Exclusão da Conta", + "process_status_initializing": "Inicializando", + "process_status_running": "Executando", + "process_type_app": "App", + "process_type_init": "Início", + "process_type_ui": "UI", + "properties": "Propriedades", + "public": "Público", + "publish": "Publicar", + "publish_as_website": "Publicar como site", + "puter_description": "Puter é uma nuvem pessoal que prioriza a privacidade para manter todos os seus arquivos, aplicativos e jogos em um lugar seguro, acessível de qualquer lugar a qualquer momento.", + "reading_file": "Lendo %strong%", + "recent": "Recente", + "recommended": "Recomendado", + "recover_password": "Recuperar Senha", + "refer_friends_c2a": "Ganhe 1 GB para cada amigo que criar e confirmar uma conta no Puter. Seu amigo também ganhará 1 GB!", + "refer_friends_social_media_c2a": "Ganhe 1 GB de armazenamento gratuito no Puter.com!", + "refresh": "Atualizar", + "release_address_confirmation": "Tem certeza de que deseja liberar este endereço?", + "remove_from_taskbar": "Remover da Barra de Tarefas", + "rename": "Renomear", + "repeat": "Repetir", + "replace": "Substituir", + "replace_all": "Substituir Todos", + "resend_confirmation_code": "Reenviar Código de Confirmação", + "reset_colors": "Redefinir Cores", + "restart_puter_confirm": "Tem certeza de que deseja reiniciar o Puter?", + "restore": "Restaurar", + "save": "Salvar", + "saturation": "Saturação", + "save_account": "Salvar conta", + "save_account_to_get_copy_link": "Por favor, crie uma conta para prosseguir.", + "save_account_to_publish": "Por favor, crie uma conta para prosseguir.", + "save_session": "Salvar sessão", + "save_session_c2a": "Crie uma conta para salvar sua sessão atual e evitar perder seu trabalho.", + "scan_qr_c2a": "Escaneie o código abaixo para fazer login nesta sessão a partir de outros dispositivos", + "scan_qr_2fa": "Escaneie o código QR com seu aplicativo autenticador", + "scan_qr_generic": "Escaneie este código QR usando seu telefone ou outro dispositivo", + "search": "Buscar", + "seconds": "segundos", + "security": "Segurança", + "select": "Selecionar", + "selected": "selecionado", + "select_color": "Selecionar cor…", + "sessions": "Sessões", + "send": "Enviar", + "send_password_recovery_email": "Enviar E-mail de Recuperação de Senha", + "session_saved": "Obrigado por criar uma conta. Esta sessão foi salva.", + "settings": "Configurações", + "set_new_password": "Definir Nova Senha", + "share": "Compartilhar", + "share_to": "Compartilhar para", + "share_with": "Compartilhar com:", + "shortcut_to": "Atalho para", + "show_all_windows": "Mostrar Todas as Janelas", + "show_hidden": "Mostrar ocultos", + "sign_in_with_puter": "Entrar com Puter", + "sign_up": "Cadastrar-se", + "signing_in": "Entrando...", + "size": "Tamanho", + "skip": "Pular", + "something_went_wrong": "Algo deu errado.", + "sort_by": "Ordenar por", + "start": "Iniciar", + "status": "Status", + "storage_usage": "Uso de Armazenamento", + "storage_puter_used": "usado pelo Puter", + "taking_longer_than_usual": "Levando um pouco mais de tempo do que o normal. Por favor, aguarde...", + "task_manager": "Gerenciador de Tarefas", + "taskmgr_header_name": "Nome", + "taskmgr_header_status": "Status", + "taskmgr_header_type": "Tipo", + "terms": "Termos", + "text_document": "Documento de texto", + "tos_fineprint": "Ao clicar em 'Criar Conta Gratuita' você concorda com os {{link=terms}}Termos de Serviço{{/link}} e a {{link=privacy}}Política de Privacidade{{/link}} do Puter.", + "transparency": "Transparência", + "trash": "Lixeira", + "two_factor": "Autenticação de Dois Fatores", + "two_factor_disabled": "2FA Desativada", + "two_factor_enabled": "2FA Ativada", + "type": "Tipo", + "type_confirm_to_delete_account": "Digite 'confirmar' para excluir sua conta.", + "ui_colors": "Cores da Interface", + "ui_manage_sessions": "Gerenciador de Sessões", + "ui_revoke": "Revogar", + "undo": "Desfazer", + "unlimited": "Ilimitado", + "unzip": "Descompactar", + "upload": "Upload", + "upload_here": "Fazer upload aqui", + "usage": "Uso", + "username": "Nome de Usuário", + "username_changed": "Nome de usuário atualizado com sucesso.", + "username_required": "Nome de usuário é necessário.", + "versions": "Versões", + "videos": "Vídeos", + "visibility": "Visibilidade", + "yes": "Sim", + "yes_release_it": "Sim, Liberar", + "you_have_been_referred_to_puter_by_a_friend": "Você foi indicado ao Puter por um amigo!", + "zip": "Compactar", + "zipping_file": "Compactando %strong%", + + // === 2FA Setup === + "setup2fa_1_step_heading": "Abra seu aplicativo autenticador", + "setup2fa_1_instructions": ` + Você pode usar qualquer aplicativo autenticador que suporte o protocolo de Senha de Uso Único com Base em Tempo (TOTP). + Existem muitas opções, mas se você não tiver certeza + Authy + é uma escolha sólida para Android e iOS. `, - "setup2fa_5_step_heading": "Confirme a configuração do 2FA", - "setup2fa_5_confirmation_1": "Salvei meus códigos de recuperação em um local seguro", - "setup2fa_5_confirmation_2": "Estou pronto para ativar o 2FA", - "setup2fa_5_button": "Ativar 2FA", + "setup2fa_2_step_heading": "Escaneie o código QR", + "setup2fa_3_step_heading": "Digite o código de 6 dígitos", + "setup2fa_4_step_heading": "Copie seus códigos de recuperação", + "setup2fa_4_instructions": ` + Esses códigos de recuperação são a única maneira de acessar sua conta se você perder seu telefone ou não puder usar seu aplicativo autenticador. + Certifique-se de armazená-los em um lugar seguro. + `, + "setup2fa_5_step_heading": "Confirme a configuração do 2FA", + "setup2fa_5_confirmation_1": "Salvei meus códigos de recuperação em um local seguro", + "setup2fa_5_confirmation_2": "Estou pronto para ativar o 2FA", + "setup2fa_5_button": "Ativar 2FA", + + // === 2FA Login === + "login2fa_otp_title": "Digite o Código 2FA", + "login2fa_otp_instructions": "Digite o código de 6 dígitos do seu aplicativo autenticador.", + "login2fa_recovery_title": "Digite um código de recuperação", + "login2fa_recovery_instructions": "Digite um dos seus códigos de recuperação para acessar sua conta.", + "login2fa_use_recovery_code": "Usar um código de recuperação", + "login2fa_recovery_back": "Voltar", + "login2fa_recovery_placeholder": "XXXXXXXX", - // === 2FA Login === - "login2fa_otp_title": "Digite o Código 2FA", - "login2fa_otp_instructions": "Digite o código de 6 dígitos do seu aplicativo autenticador.", - "login2fa_recovery_title": "Digite um código de recuperação", - "login2fa_recovery_instructions": "Digite um dos seus códigos de recuperação para acessar sua conta.", - "login2fa_use_recovery_code": "Usar um código de recuperação", - "login2fa_recovery_back": "Voltar", - "login2fa_recovery_placeholder": "XXXXXXXX" + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" } }; diff --git a/src/gui/src/i18n/translations/da.js b/src/gui/src/i18n/translations/da.js index 4ea1141bd0..399282799a 100644 --- a/src/gui/src/i18n/translations/da.js +++ b/src/gui/src/i18n/translations/da.js @@ -345,6 +345,25 @@ const da = { login2fa_use_recovery_code: 'Brug en gendannelseskode', login2fa_recovery_back: 'Tilbage', login2fa_recovery_placeholder: 'XXXXXXXX', + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" + } }; diff --git a/src/gui/src/i18n/translations/de.js b/src/gui/src/i18n/translations/de.js index 7b77e09b9b..e5b7008238 100644 --- a/src/gui/src/i18n/translations/de.js +++ b/src/gui/src/i18n/translations/de.js @@ -345,6 +345,26 @@ const de = { login2fa_use_recovery_code: 'Verwenden Sie einen Wiederherstellungscode', login2fa_recovery_back: 'Zurück', login2fa_recovery_placeholder: 'XXXXXXXX', + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "confirm": undefined, // In English: "Confirm" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" + } }; diff --git a/src/gui/src/i18n/translations/emoji.js b/src/gui/src/i18n/translations/emoji.js index 04ac847ad7..595ba15a3a 100644 --- a/src/gui/src/i18n/translations/emoji.js +++ b/src/gui/src/i18n/translations/emoji.js @@ -181,6 +181,11 @@ const emoji = { yes_release_it: '✅🆓', you_have_been_referred_to_puter_by_a_friend: "👤🔁🆓", zip: "📂🔒", + + // *********************************** + // Missing translations + // *********************************** + } }; diff --git a/src/gui/src/i18n/translations/en.js b/src/gui/src/i18n/translations/en.js index c30974ae8c..ddbd38c23e 100644 --- a/src/gui/src/i18n/translations/en.js +++ b/src/gui/src/i18n/translations/en.js @@ -352,11 +352,14 @@ const en = { login2fa_recovery_back: 'Back', login2fa_recovery_placeholder: 'XXXXXXXX', - // Subscriptions - 'offering.free': 'Use Puter', - 'offering.pay-puter': 'Pay Puter', - 'offering.pay-puter-more': 'Pay Puter More', - 'offering.pay-puter-even-more': 'Pay Puter Even More', + // Sharing + 'Editor': 'Editor', + 'Viewer': 'Viewer', + 'People with access': 'People with access', + 'Share With…' : 'Share With…', + 'Owner': 'Owner', + "You can't share with yourself.": `You can't share with yourself.`, + 'This user already has access to this item': 'This user already has access to this item', } }; diff --git a/src/gui/src/i18n/translations/es.js b/src/gui/src/i18n/translations/es.js index 2de11e0b1b..76a0583962 100644 --- a/src/gui/src/i18n/translations/es.js +++ b/src/gui/src/i18n/translations/es.js @@ -352,6 +352,25 @@ const es = { login2fa_use_recovery_code: 'Usar un código de recuperación', login2fa_recovery_back: 'Atras', login2fa_recovery_placeholder: 'XXXXXXXX', + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" + } }; diff --git a/src/gui/src/i18n/translations/fa.js b/src/gui/src/i18n/translations/fa.js index dd8947451f..2914189428 100644 --- a/src/gui/src/i18n/translations/fa.js +++ b/src/gui/src/i18n/translations/fa.js @@ -173,6 +173,190 @@ const fa = { yes_release_it: 'بله، آن را آزاد کن', you_have_been_referred_to_puter_by_a_friend: "شما توسط یک دوست به Puter معرفی شده اید!", zip: "فشرده سازی", + + // *********************************** + // Missing translations + // *********************************** + "account_password": undefined, // In English: "Verify Account Password" + "allow": undefined, // In English: "Allow" + "associated_websites": undefined, // In English: "Associated Websites" + "change": undefined, // In English: "Change" + "change_always_open_with": undefined, // In English: "Do you want to always open this type of file with" + "change_email": undefined, // In English: "Change Email" + "change_ui_colors": undefined, // In English: "Change UI Colors" + "clock_visibility": undefined, // In English: "Clock Visibility" + "close": undefined, // In English: "Close" + "close_all_windows_confirm": undefined, // In English: "Are you sure you want to close all windows?" + "close_all_windows_and_log_out": undefined, // In English: "Close Windows and Log Out" + "confirm": undefined, // In English: "Confirm" + "confirm_2fa_setup": undefined, // In English: "I have added the code to my authenticator app" + "confirm_2fa_recovery": undefined, // In English: "I have saved my recovery codes in a secure location" + "confirm_code_generic_incorrect": undefined, // In English: "Incorrect Code." + "confirm_code_generic_too_many_requests": undefined, // In English: "Too many requests. Please wait a few minutes." + "confirm_code_generic_submit": undefined, // In English: "Submit Code" + "confirm_code_generic_try_again": undefined, // In English: "Try Again" + "confirm_code_generic_title": undefined, // In English: "Enter Confirmation Code" + "confirm_code_2fa_instruction": undefined, // In English: "Enter the 6-digit code from your authenticator app." + "confirm_code_2fa_submit_btn": undefined, // In English: "Submit" + "confirm_code_2fa_title": undefined, // In English: "Enter 2FA Code" + "confirm_delete_multiple_items": undefined, // In English: "Are you sure you want to permanently delete these items?" + "confirm_delete_single_item": undefined, // In English: "Do you want to permanently delete this item?" + "confirm_open_apps_log_out": undefined, // In English: "You have open apps. Are you sure you want to log out?" + "confirm_delete_user": undefined, // In English: "Are you sure you want to delete your account? All your files and data will be permanently deleted. This action cannot be undone." + "confirm_delete_user_title": undefined, // In English: "Delete Account?" + "confirm_session_revoke": undefined, // In English: "Are you sure you want to revoke this session?" + "confirm_your_email_address": undefined, // In English: "Confirm Your Email Address" + "contact_us_verification_required": undefined, // In English: "You must have a verified email address to use this." + "copying_file": undefined, // In English: "Copying %%" + "credits": undefined, // In English: "Credits" + "clock_visible_hide": undefined, // In English: "Hide - Always hidden" + "clock_visible_show": undefined, // In English: "Show - Always visible" + "clock_visible_auto": undefined, // In English: "Auto - Default, visible only in full-screen mode." + "close_all": undefined, // In English: "Close All" + "created": undefined, // In English: "Created" + "default": undefined, // In English: "Default" + "delete_account": undefined, // In English: "Delete Account" + "deleting_file": undefined, // In English: "Deleting %%" + "desktop": undefined, // In English: "Desktop" + "developers": undefined, // In English: "Developers" + "disable_2fa": undefined, // In English: "Disable 2FA" + "disable_2fa_confirm": undefined, // In English: "Are you sure you want to disable 2FA?" + "disable_2fa_instructions": undefined, // In English: "Enter your password to disable 2FA." + "documents": undefined, // In English: "Documents" + "dont_allow": undefined, // In English: "Don't Allow" + "download_file": undefined, // In English: "Download File" + "email_change_confirmation_sent": undefined, // In English: "A confirmation email has been sent to your new email address. Please check your inbox and follow the instructions to complete the process." + "email_invalid": undefined, // In English: "Email is invalid." + "email_required": undefined, // In English: "Email is required." + "enable_2fa": undefined, // In English: "Enable 2FA" + "end_hard": undefined, // In English: "End Hard" + "end_process_force_confirm": undefined, // In English: "Are you sure you want to force-quit this process?" + "end_soft": undefined, // In English: "End Soft" + "enlarged_qr_code": undefined, // In English: "Enlarged QR Code" + "enter_password_to_confirm_delete_user": undefined, // In English: "Enter your password to confirm account deletion" + "error_message_is_missing": undefined, // In English: "Error message is missing." + "error_unknown_cause": undefined, // In English: "An unknown error occurred." + "error_uploading_files": undefined, // In English: "Failed to upload files" + "favorites": undefined, // In English: "Favorites" + "fit": undefined, // In English: "Fit" + "folder": undefined, // In English: "Folder" + "force_quit": undefined, // In English: "Force Quit" + "home": undefined, // In English: "Home" + "hue": undefined, // In English: "Hue" + "incorrect_password": undefined, // In English: "Incorrect password" + "item": undefined, // In English: "item" + "license": undefined, // In English: "License" + "lightness": undefined, // In English: "Lightness" + "link_copied": undefined, // In English: "Link copied" + "loading": undefined, // In English: "Loading" + "log_into_another_account_anyway": undefined, // In English: "Log into another account anyway" + "looks_good": undefined, // In English: "Looks good!" + "manage_sessions": undefined, // In English: "Manage Sessions" + "menubar_style": undefined, // In English: "Menubar Style" + "menubar_style_desktop": undefined, // In English: "Desktop" + "menubar_style_system": undefined, // In English: "System" + "menubar_style_window": undefined, // In English: "Window" + "modified": undefined, // In English: "Modified" + "new_email": undefined, // In English: "New Email" + "no": undefined, // In English: "No" + "original_name": undefined, // In English: "Original Name" + "original_path": undefined, // In English: "Original Path" + "oss_code_and_content": undefined, // In English: "Open Source Software and Content" + "password_recovery_rate_limit": undefined, // In English: "You've reached our rate-limit; please wait a few minutes. To prevent this in the future, avoid reloading the page too many times." + "password_recovery_token_invalid": undefined, // In English: "This password recovery token is no longer valid." + "password_recovery_unknown_error": undefined, // In English: "An unknown error occurred. Please try again later." + "password_required": undefined, // In English: "Password is required." + "password_strength_error": undefined, // In English: "Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, one number, and one special character." + "path": undefined, // In English: "Path" + "pictures": undefined, // In English: "Pictures" + "plural_suffix": undefined, // In English: "s" + "print": undefined, // In English: "Print" + "privacy": undefined, // In English: "Privacy" + "proceed_to_login": undefined, // In English: "Proceed to login" + "proceed_with_account_deletion": undefined, // In English: "Proceed with Account Deletion" + "process_status_initializing": undefined, // In English: "Initializing" + "process_status_running": undefined, // In English: "Running" + "process_type_app": undefined, // In English: "App" + "process_type_init": undefined, // In English: "Init" + "process_type_ui": undefined, // In English: "UI" + "public": undefined, // In English: "Public" + "puter_description": undefined, // In English: "Puter is a privacy-first personal cloud to keep all your files, apps, and games in one secure place, accessible from anywhere at any time." + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "recommended": undefined, // In English: "Recommended" + "replace": undefined, // In English: "Replace" + "replace_all": undefined, // In English: "Replace All" + "reset_colors": undefined, // In English: "Reset Colors" + "restart_puter_confirm": undefined, // In English: "Are you sure you want to restart Puter?" + "save": undefined, // In English: "Save" + "saturation": undefined, // In English: "Saturation" + "save_account": undefined, // In English: "Save account" + "save_session": undefined, // In English: "Save session" + "scan_qr_2fa": undefined, // In English: "Scan the QR code with your authenticator app" + "scan_qr_generic": undefined, // In English: "Scan this QR code using your phone or another device" + "search": undefined, // In English: "Search" + "seconds": undefined, // In English: "seconds" + "selected": undefined, // In English: "selected" + "sessions": undefined, // In English: "Sessions" + "share": undefined, // In English: "Share" + "share_with": undefined, // In English: "Share with:" + "shortcut_to": undefined, // In English: "Shortcut to" + "skip": undefined, // In English: "Skip" + "something_went_wrong": undefined, // In English: "Something went wrong." + "status": undefined, // In English: "Status" + "storage_usage": undefined, // In English: "Storage Usage" + "taskmgr_header_name": undefined, // In English: "Name" + "taskmgr_header_status": undefined, // In English: "Status" + "taskmgr_header_type": undefined, // In English: "Type" + "terms": undefined, // In English: "Terms" + "transparency": undefined, // In English: "Transparency" + "two_factor": undefined, // In English: "Two Factor Authentication" + "two_factor_disabled": undefined, // In English: "2FA Disabled" + "two_factor_enabled": undefined, // In English: "2FA Enabled" + "type_confirm_to_delete_account": undefined, // In English: "Type 'confirm' to delete your account." + "ui_colors": undefined, // In English: "UI Colors" + "ui_manage_sessions": undefined, // In English: "Session Manager" + "ui_revoke": undefined, // In English: "Revoke" + "unlimited": undefined, // In English: "Unlimited" + "unzipping": undefined, // In English: "Unzipping %strong%" + "username_required": undefined, // In English: "Username is required." + "videos": undefined, // In English: "Videos" + "visibility": undefined, // In English: "Visibility" + "yes": undefined, // In English: "Yes" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "setup2fa_1_step_heading": undefined, // In English: "Open your authenticator app" + "setup2fa_1_instructions": undefined, // In English: " + // You can use any authenticator app that supports the Time-based One-Time Password (TOTP) protocol. + // There are many to choose from, but if you're unsure + // Authy + // is a solid choice for Android and iOS. + //" + "setup2fa_2_step_heading": undefined, // In English: "Scan the QR code" + "setup2fa_3_step_heading": undefined, // In English: "Enter the 6-digit code" + "setup2fa_4_step_heading": undefined, // In English: "Copy your recovery codes" + "setup2fa_4_instructions": undefined, // In English: " + // These recovery codes are the only way to access your account if you lose your phone or can't use your authenticator app. + // Make sure to store them in a safe place. + // " + "setup2fa_5_step_heading": undefined, // In English: "Confirm 2FA setup" + "setup2fa_5_confirmation_1": undefined, // In English: "I have saved my recovery codes in a secure location" + "setup2fa_5_confirmation_2": undefined, // In English: "I am ready to enable 2FA" + "setup2fa_5_button": undefined, // In English: "Enable 2FA" + "login2fa_otp_title": undefined, // In English: "Enter 2FA Code" + "login2fa_otp_instructions": undefined, // In English: "Enter the 6-digit code from your authenticator app." + "login2fa_recovery_title": undefined, // In English: "Enter a recovery code" + "login2fa_recovery_instructions": undefined, // In English: "Enter one of your recovery codes to access your account." + "login2fa_use_recovery_code": undefined, // In English: "Use a recovery code" + "login2fa_recovery_back": undefined, // In English: "Back" + "login2fa_recovery_placeholder": undefined, // In English: "XXXXXXXX" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" } }; diff --git a/src/gui/src/i18n/translations/fi.js b/src/gui/src/i18n/translations/fi.js index 21d006db70..789ac2a9aa 100644 --- a/src/gui/src/i18n/translations/fi.js +++ b/src/gui/src/i18n/translations/fi.js @@ -403,6 +403,24 @@ const fi = { login2fa_use_recovery_code: 'Käytä palautuskoodi', login2fa_recovery_back: 'Takaisin', login2fa_recovery_placeholder: 'XXXXXXXX', + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" } } diff --git a/src/gui/src/i18n/translations/fr.js b/src/gui/src/i18n/translations/fr.js index 7cc30be810..6d4395224e 100644 --- a/src/gui/src/i18n/translations/fr.js +++ b/src/gui/src/i18n/translations/fr.js @@ -345,6 +345,26 @@ const fr = { login2fa_use_recovery_code: 'Utiliser un code de récupération', login2fa_recovery_back: 'Retour', login2fa_recovery_placeholder: 'XXXXXXXX', + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "confirm": undefined, // In English: "Confirm" + "public": undefined, // In English: "Public" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" } }; diff --git a/src/gui/src/i18n/translations/he.js b/src/gui/src/i18n/translations/he.js index 9a77db0575..2d485bc67f 100644 --- a/src/gui/src/i18n/translations/he.js +++ b/src/gui/src/i18n/translations/he.js @@ -363,6 +363,25 @@ const en = { login2fa_use_recovery_code: "שימוש בקוד שחזור", login2fa_recovery_back: "לאחור", login2fa_recovery_placeholder: "XXXXXXXX", + + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" }, }; diff --git a/src/gui/src/i18n/translations/hi.js b/src/gui/src/i18n/translations/hi.js index bfdaf7e91f..1aa83ac797 100644 --- a/src/gui/src/i18n/translations/hi.js +++ b/src/gui/src/i18n/translations/hi.js @@ -337,6 +337,26 @@ const hi = { login2fa_use_recovery_code: 'पुनर्प्राप्ति कोड का उपयोग करें', login2fa_recovery_back: 'पीछे', login2fa_recovery_placeholder: 'XXXXXXXX', + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "confirm": undefined, // In English: "Confirm" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" + } }; diff --git a/src/gui/src/i18n/translations/hu.js b/src/gui/src/i18n/translations/hu.js index 38769e3556..707dea92c2 100644 --- a/src/gui/src/i18n/translations/hu.js +++ b/src/gui/src/i18n/translations/hu.js @@ -88,251 +88,269 @@ const hu = { created: "Létrehozva", date_modified: "Módosítás dátuma", default: "Alapértelmezett", - delete: "Törlés", - delete_account: "Fiók törlése", - delete_permanently: "Végleges törlés", - deleting_file: "Törlés: %%", - deploy_as_app: "Alkalmazásként telepít", - descending: "Csökkenő", - desktop: "Asztal", - desktop_background_fit: "Illesztés", - developers: "Fejlesztők", - dir_published_as_website: "%strong% közzétéve a következő címen:", - disable_2fa: "2FA letiltása", - disable_2fa_confirm: "Biztosan letiltod a 2FA-t?", - disable_2fa_instructions: "Add meg a jelszavad a 2FA letiltásához.", - disassociate_dir: "Könyvtár leválasztása", - documents: "Dokumentumok", - dont_allow: "Nem engedélyez", - download: "Letöltés", - download_file: "Fájl letöltése", - downloading: "Letöltés", - email: "Email", - email_change_confirmation_sent: "Megerősítő emailt küldtünk az új email címedre. Kérlek, ellenőrizd a postaládádat és kövesd az utasításokat a folyamat befejezéséhez.", - email_invalid: "Érvénytelen email cím.", - email_or_username: "Email vagy Felhasználónév", - email_required: "Email szükséges.", - empty_trash: "Kuka ürítése", - empty_trash_confirmation: "Biztosan véglegesen törölni akarod a Kukában lévő elemeket?", - emptying_trash: "Kuka ürítése...", - enable_2fa: "2FA engedélyezése", - end_hard: "Kemény befejezés", - end_process_force_confirm: "Biztosan kényszerített kilépést hajtasz végre erre a folyamatra?", - end_soft: "Lágy befejezés", - enlarged_qr_code: "Nagyított QR kód", - enter_password_to_confirm_delete_user: "Add meg a jelszavad a fiók törlésének megerősítéséhez", - error_message_is_missing: "Hiányzik a hibaüzenet.", - error_unknown_cause: "Ismeretlen hiba történt.", - error_uploading_files: "Fájlok feltöltése sikertelen", - favorites: "Kedvencek", - feedback: "Visszajelzés", - feedback_c2a: "Kérlek, használd az alábbi űrlapot, hogy elküldd nekünk visszajelzésedet, észrevételeidet és hibajelentéseidet.", - feedback_sent_confirmation: "Köszönjük, hogy kapcsolatba léptél velünk. Ha van email címed a fiókodhoz társítva, hamarosan hallani fogsz rólunk.", - fit: "Illesztés", - folder: "Mappa", - force_quit: "Kényszerített kilépés", - forgot_pass_c2a: "Elfelejtetted a jelszavad?", - from: "Tól", - general: "Általános", - get_a_copy_of_on_puter: "Szerezz egy példányt a(z) '%%' Puter.com-on!", - get_copy_link: "Másolási link megszerzése", - hide_all_windows: "Minden ablak elrejtése", - home: "Otthon", - html_document: "HTML dokumentum", - hue: "Színárnyalat", - image: "Kép", - incorrect_password: "Helytelen jelszó", - invite_link: "Meghívó link", - item: "elem", - items_in_trash_cannot_be_renamed: "Ez az elem nem nevezhető át, mert a kukában van. A név megváltoztatásához először húzd ki a Kukából.", - jpeg_image: "JPEG kép", - keep_in_taskbar: "Tartsa a tálcán", - language: "Nyelv", - license: "Licenc", - lightness: "Világosság", - link_copied: "Link másolva", - loading: "Betöltés", - log_in: "Bejelentkezés", - log_into_another_account_anyway: "Bejelentkezés egy másik fiókba", - log_out: "Kijelentkezés", - looks_good: "Jól néz ki!", - manage_sessions: "Munkamenetek kezelése", - menubar_style: "Menü stílusa", - menubar_style_desktop: "Asztal", - menubar_style_system: "Rendszer", - menubar_style_window: "Ablak", - modified: "Módosítva", - move: "Mozgatás", - moving_file: "Mozgatás: %%", - my_websites: "Saját weboldalaim", - name: "Név", - name_cannot_be_empty: "A név nem lehet üres.", - name_cannot_contain_double_period: "A név nem tartalmazhatja a '..' karaktert.", - name_cannot_contain_period: "A név nem tartalmazhatja a '.' karaktert.", - name_cannot_contain_slash: "A név nem tartalmazhatja a '/' karaktert.", - name_must_be_string: "A név csak szöveg lehet.", - name_too_long: "A név nem lehet hosszabb, mint %% karakter.", - new: "Új", - new_email: "Új email", - new_folder: "Új mappa", - new_password: "Új jelszó", - new_username: "Új felhasználónév", - no: "Nem", - no_dir_associated_with_site: "Ehhez a címhez nincs társítva könyvtár.", - no_websites_published: "Még nem publikáltál egyetlen weboldalt sem. Kattints jobb gombbal egy mappára a kezdéshez.", - ok: "Rendben", - open: "Megnyitás", - open_in_new_tab: "Megnyitás új lapon", - open_in_new_window: "Megnyitás új ablakban", - open_with: "Megnyitás ezzel", - original_name: "Eredeti név", - original_path: "Eredeti útvonal", - oss_code_and_content: "Nyílt forráskódú szoftver és tartalom", - password: "Jelszó", - password_changed: "Jelszó megváltoztatva.", - password_recovery_rate_limit: "Elérted a korlátunkat; kérlek, várj néhány percet. A jövőben kerüld az oldal túl sokszori újratöltését.", - password_recovery_token_invalid: "Ez a jelszó visszaállítási token már nem érvényes.", - password_recovery_unknown_error: "Ismeretlen hiba történt. Kérlek, próbáld újra később.", - password_required: "Jelszó szükséges.", - password_strength_error: "A jelszónak legalább 8 karakter hosszúnak kell lennie és tartalmaznia kell legalább egy nagybetűt, egy kisbetűt, egy számot és egy speciális karaktert.", - passwords_do_not_match: "'Új jelszó' és 'Új jelszó megerősítése' nem egyeznek.", - paste: "Beillesztés", - paste_into_folder: "Beillesztés a mappába", - path: "Útvonal", - personalization: "Személyre szabás", - pick_name_for_website: "Válassz nevet a weboldaladnak:", - picture: "Kép", - pictures: "Képek", - plural_suffix: "k", - powered_by_puter_js: "A Puter.js hajtja", - preparing: "Előkészítés...", - preparing_for_upload: "Feltöltés előkészítése...", - print: "Nyomtatás", - privacy: "Adatvédelem", - proceed_to_login: "Folytatás a bejelentkezéshez", - proceed_with_account_deletion: "Fiók törlésének folytatása", - process_status_initializing: "Inicializálás", - process_status_running: "Fut", - process_type_app: "Alkalmazás", - process_type_init: "Inicializálás", - process_type_ui: "Felhasználói felület", - properties: "Tulajdonságok", - public: "Nyilvános", - publish: "Közzététel", - publish_as_website: "Közzététel weboldalként", - puter_description: "A Puter egy adatvédelmi elsőként kezelt személyes felhő, amelyben minden fájlodat, alkalmazásodat és játékodat egy biztonságos helyen tárolhatod, bárhonnan, bármikor elérhetően.", - reading_file: "Fájl olvasása: %strong%", - recent: "Legutóbbi", - recommended: "Ajánlott", - recover_password: "Jelszó visszaállítása", - refer_friends_c2a: "Kapj 1 GB-ot minden barátodért, aki létrehoz és megerősít egy fiókot a Puteren. A barátod is kap 1 GB-ot!", - refer_friends_social_media_c2a: "Kapj 1 GB ingyenes tárhelyet a Puter.com-on!", - refresh: "Frissítés", - release_address_confirmation: "Biztosan felszabadítod ezt a címet?", - remove_from_taskbar: "Eltávolítás a tálcáról", - rename: "Átnevezés", - repeat: "Ismétlés", - replace: "Csere", - replace_all: "Összes cseréje", - resend_confirmation_code: "Megerősítő kód újraküldése", - reset_colors: "Színek visszaállítása", - restart_puter_confirm: "Biztosan újraindítod a Putert?", - restore: "Visszaállítás", - save: "Mentés", - saturation: "Telítettség", - save_account: "Fiók mentése", - save_account_to_get_copy_link: "A folytatáshoz kérlek, hozz létre egy fiókot.", - save_account_to_publish: "A folytatáshoz kérlek, hozz létre egy fiókot.", - save_session: "Munkamenet mentése", - save_session_c2a: "Hozz létre egy fiókot, hogy mentsd az aktuális munkamenetedet és elkerüld a munkád elvesztését.", - scan_qr_c2a: "Olvasd be az alábbi kódot, hogy bejelentkezhess ebbe a munkamenetbe más eszközökről", - scan_qr_2fa: "Olvasd be a QR-kódot a hitelesítő alkalmazásoddal", - scan_qr_generic: "Olvasd be ezt a QR-kódot a telefonoddal vagy más eszközzel", - search: "Keresés", - seconds: "másodperc", - security: "Biztonság", - select: "Kiválasztás", - selected: "kiválasztva", - select_color: "Szín kiválasztása...", - sessions: "Munkamenetek", - send: "Küldés", - send_password_recovery_email: "Jelszó visszaállító email küldése", - session_saved: "Köszönjük, hogy létrehoztál egy fiókot. Ez a munkamenet mentésre került.", - settings: "Beállítások", - set_new_password: "Új jelszó beállítása", - share: "Megosztás", - share_to: "Megosztás ide:", - share_with: "Megosztás valakivel:", - shortcut_to: "Parancsikon ide:", - show_all_windows: "Összes ablak megjelenítése", - show_hidden: "Rejtett megjelenítése", - sign_in_with_puter: "Bejelentkezés Puterrel", - sign_up: "Regisztráció", - signing_in: "Bejelentkezés...", - size: "Méret", - skip: "Kihagyás", - something_went_wrong: "Valami hiba történt.", - sort_by: "Rendezés", - start: "Indítás", - status: "Állapot", - storage_usage: "Tárhely használat", - storage_puter_used: "Puter által használt", - taking_longer_than_usual: "Kicsit tovább tart, mint általában. Kérlek várj...", - task_manager: "Feladatkezelő", - taskmgr_header_name: "Név", - taskmgr_header_status: "Állapot", - taskmgr_header_type: "Típus", - terms: "Feltételek", - text_document: "Szöveges dokumentum", - tos_fineprint: "A 'Ingyenes fiók létrehozása' gombra kattintva elfogadod a Puter {{link=terms}}Szolgáltatási feltételeit{{/link}} és {{link=privacy}}Adatvédelmi irányelveit{{/link}}.", - transparency: "Átlátszóság", - trash: "Kuka", - two_factor: "Kétfaktoros hitelesítés", - two_factor_disabled: "2FA letiltva", - two_factor_enabled: "2FA engedélyezve", - type: "Típus", - type_confirm_to_delete_account: "Írd be, hogy 'megerősít' a fiók törléséhez.", - ui_colors: "UI színek", - ui_manage_sessions: "Munkamenetkezelő", - ui_revoke: "Visszavonás", - undo: "Visszavonás", - unlimited: "Korlátlan", - unzip: "Kibontás", - upload: "Feltöltés", - upload_here: "Feltöltés ide", - usage: "Használat", - username: "Felhasználónév", - username_changed: "A felhasználónév sikeresen frissítve.", - username_required: "Felhasználónév szükséges.", - versions: "Verziók", - videos: "Videók", - visibility: "Láthatóság", - yes: "Igen", - yes_release_it: "Igen, Engedd El", - you_have_been_referred_to_puter_by_a_friend: "Egy barátod ajánlott téged a Puterhez!", - zip: "Zip", - zipping_file: "Tömörítés: %strong%", + delete: "Törlés", + delete_account: "Fiók törlése", + delete_permanently: "Végleges törlés", + deleting_file: "Törlés: %%", + deploy_as_app: "Alkalmazásként telepít", + descending: "Csökkenő", + desktop: "Asztal", + desktop_background_fit: "Illesztés", + developers: "Fejlesztők", + dir_published_as_website: "%strong% közzétéve a következő címen:", + disable_2fa: "2FA letiltása", + disable_2fa_confirm: "Biztosan letiltod a 2FA-t?", + disable_2fa_instructions: "Add meg a jelszavad a 2FA letiltásához.", + disassociate_dir: "Könyvtár leválasztása", + documents: "Dokumentumok", + dont_allow: "Nem engedélyez", + download: "Letöltés", + download_file: "Fájl letöltése", + downloading: "Letöltés", + email: "Email", + email_change_confirmation_sent: "Megerősítő emailt küldtünk az új email címedre. Kérlek, ellenőrizd a postaládádat és kövesd az utasításokat a folyamat befejezéséhez.", + email_invalid: "Érvénytelen email cím.", + email_or_username: "Email vagy Felhasználónév", + email_required: "Email szükséges.", + empty_trash: "Kuka ürítése", + empty_trash_confirmation: "Biztosan véglegesen törölni akarod a Kukában lévő elemeket?", + emptying_trash: "Kuka ürítése...", + enable_2fa: "2FA engedélyezése", + end_hard: "Kemény befejezés", + end_process_force_confirm: "Biztosan kényszerített kilépést hajtasz végre erre a folyamatra?", + end_soft: "Lágy befejezés", + enlarged_qr_code: "Nagyított QR kód", + enter_password_to_confirm_delete_user: "Add meg a jelszavad a fiók törlésének megerősítéséhez", + error_message_is_missing: "Hiányzik a hibaüzenet.", + error_unknown_cause: "Ismeretlen hiba történt.", + error_uploading_files: "Fájlok feltöltése sikertelen", + favorites: "Kedvencek", + feedback: "Visszajelzés", + feedback_c2a: "Kérlek, használd az alábbi űrlapot, hogy elküldd nekünk visszajelzésedet, észrevételeidet és hibajelentéseidet.", + feedback_sent_confirmation: "Köszönjük, hogy kapcsolatba léptél velünk. Ha van email címed a fiókodhoz társítva, hamarosan hallani fogsz rólunk.", + fit: "Illesztés", + folder: "Mappa", + force_quit: "Kényszerített kilépés", + forgot_pass_c2a: "Elfelejtetted a jelszavad?", + from: "Tól", + general: "Általános", + get_a_copy_of_on_puter: "Szerezz egy példányt a(z) '%%' Puter.com-on!", + get_copy_link: "Másolási link megszerzése", + hide_all_windows: "Minden ablak elrejtése", + home: "Otthon", + html_document: "HTML dokumentum", + hue: "Színárnyalat", + image: "Kép", + incorrect_password: "Helytelen jelszó", + invite_link: "Meghívó link", + item: "elem", + items_in_trash_cannot_be_renamed: "Ez az elem nem nevezhető át, mert a kukában van. A név megváltoztatásához először húzd ki a Kukából.", + jpeg_image: "JPEG kép", + keep_in_taskbar: "Tartsa a tálcán", + language: "Nyelv", + license: "Licenc", + lightness: "Világosság", + link_copied: "Link másolva", + loading: "Betöltés", + log_in: "Bejelentkezés", + log_into_another_account_anyway: "Bejelentkezés egy másik fiókba", + log_out: "Kijelentkezés", + looks_good: "Jól néz ki!", + manage_sessions: "Munkamenetek kezelése", + menubar_style: "Menü stílusa", + menubar_style_desktop: "Asztal", + menubar_style_system: "Rendszer", + menubar_style_window: "Ablak", + modified: "Módosítva", + move: "Mozgatás", + moving_file: "Mozgatás: %%", + my_websites: "Saját weboldalaim", + name: "Név", + name_cannot_be_empty: "A név nem lehet üres.", + name_cannot_contain_double_period: "A név nem tartalmazhatja a '..' karaktert.", + name_cannot_contain_period: "A név nem tartalmazhatja a '.' karaktert.", + name_cannot_contain_slash: "A név nem tartalmazhatja a '/' karaktert.", + name_must_be_string: "A név csak szöveg lehet.", + name_too_long: "A név nem lehet hosszabb, mint %% karakter.", + new: "Új", + new_email: "Új email", + new_folder: "Új mappa", + new_password: "Új jelszó", + new_username: "Új felhasználónév", + no: "Nem", + no_dir_associated_with_site: "Ehhez a címhez nincs társítva könyvtár.", + no_websites_published: "Még nem publikáltál egyetlen weboldalt sem. Kattints jobb gombbal egy mappára a kezdéshez.", + ok: "Rendben", + open: "Megnyitás", + open_in_new_tab: "Megnyitás új lapon", + open_in_new_window: "Megnyitás új ablakban", + open_with: "Megnyitás ezzel", + original_name: "Eredeti név", + original_path: "Eredeti útvonal", + oss_code_and_content: "Nyílt forráskódú szoftver és tartalom", + password: "Jelszó", + password_changed: "Jelszó megváltoztatva.", + password_recovery_rate_limit: "Elérted a korlátunkat; kérlek, várj néhány percet. A jövőben kerüld az oldal túl sokszori újratöltését.", + password_recovery_token_invalid: "Ez a jelszó visszaállítási token már nem érvényes.", + password_recovery_unknown_error: "Ismeretlen hiba történt. Kérlek, próbáld újra később.", + password_required: "Jelszó szükséges.", + password_strength_error: "A jelszónak legalább 8 karakter hosszúnak kell lennie és tartalmaznia kell legalább egy nagybetűt, egy kisbetűt, egy számot és egy speciális karaktert.", + passwords_do_not_match: "'Új jelszó' és 'Új jelszó megerősítése' nem egyeznek.", + paste: "Beillesztés", + paste_into_folder: "Beillesztés a mappába", + path: "Útvonal", + personalization: "Személyre szabás", + pick_name_for_website: "Válassz nevet a weboldaladnak:", + picture: "Kép", + pictures: "Képek", + plural_suffix: "k", + powered_by_puter_js: "A Puter.js hajtja", + preparing: "Előkészítés...", + preparing_for_upload: "Feltöltés előkészítése...", + print: "Nyomtatás", + privacy: "Adatvédelem", + proceed_to_login: "Folytatás a bejelentkezéshez", + proceed_with_account_deletion: "Fiók törlésének folytatása", + process_status_initializing: "Inicializálás", + process_status_running: "Fut", + process_type_app: "Alkalmazás", + process_type_init: "Inicializálás", + process_type_ui: "Felhasználói felület", + properties: "Tulajdonságok", + public: "Nyilvános", + publish: "Közzététel", + publish_as_website: "Közzététel weboldalként", + puter_description: "A Puter egy adatvédelmi elsőként kezelt személyes felhő, amelyben minden fájlodat, alkalmazásodat és játékodat egy biztonságos helyen tárolhatod, bárhonnan, bármikor elérhetően.", + reading_file: "Fájl olvasása: %strong%", + recent: "Legutóbbi", + recommended: "Ajánlott", + recover_password: "Jelszó visszaállítása", + refer_friends_c2a: "Kapj 1 GB-ot minden barátodért, aki létrehoz és megerősít egy fiókot a Puteren. A barátod is kap 1 GB-ot!", + refer_friends_social_media_c2a: "Kapj 1 GB ingyenes tárhelyet a Puter.com-on!", + refresh: "Frissítés", + release_address_confirmation: "Biztosan felszabadítod ezt a címet?", + remove_from_taskbar: "Eltávolítás a tálcáról", + rename: "Átnevezés", + repeat: "Ismétlés", + replace: "Csere", + replace_all: "Összes cseréje", + resend_confirmation_code: "Megerősítő kód újraküldése", + reset_colors: "Színek visszaállítása", + restart_puter_confirm: "Biztosan újraindítod a Putert?", + restore: "Visszaállítás", + save: "Mentés", + saturation: "Telítettség", + save_account: "Fiók mentése", + save_account_to_get_copy_link: "A folytatáshoz kérlek, hozz létre egy fiókot.", + save_account_to_publish: "A folytatáshoz kérlek, hozz létre egy fiókot.", + save_session: "Munkamenet mentése", + save_session_c2a: "Hozz létre egy fiókot, hogy mentsd az aktuális munkamenetedet és elkerüld a munkád elvesztését.", + scan_qr_c2a: "Olvasd be az alábbi kódot, hogy bejelentkezhess ebbe a munkamenetbe más eszközökről", + scan_qr_2fa: "Olvasd be a QR-kódot a hitelesítő alkalmazásoddal", + scan_qr_generic: "Olvasd be ezt a QR-kódot a telefonoddal vagy más eszközzel", + search: "Keresés", + seconds: "másodperc", + security: "Biztonság", + select: "Kiválasztás", + selected: "kiválasztva", + select_color: "Szín kiválasztása...", + sessions: "Munkamenetek", + send: "Küldés", + send_password_recovery_email: "Jelszó visszaállító email küldése", + session_saved: "Köszönjük, hogy létrehoztál egy fiókot. Ez a munkamenet mentésre került.", + settings: "Beállítások", + set_new_password: "Új jelszó beállítása", + share: "Megosztás", + share_to: "Megosztás ide:", + share_with: "Megosztás valakivel:", + shortcut_to: "Parancsikon ide:", + show_all_windows: "Összes ablak megjelenítése", + show_hidden: "Rejtett megjelenítése", + sign_in_with_puter: "Bejelentkezés Puterrel", + sign_up: "Regisztráció", + signing_in: "Bejelentkezés...", + size: "Méret", + skip: "Kihagyás", + something_went_wrong: "Valami hiba történt.", + sort_by: "Rendezés", + start: "Indítás", + status: "Állapot", + storage_usage: "Tárhely használat", + storage_puter_used: "Puter által használt", + taking_longer_than_usual: "Kicsit tovább tart, mint általában. Kérlek várj...", + task_manager: "Feladatkezelő", + taskmgr_header_name: "Név", + taskmgr_header_status: "Állapot", + taskmgr_header_type: "Típus", + terms: "Feltételek", + text_document: "Szöveges dokumentum", + tos_fineprint: "A 'Ingyenes fiók létrehozása' gombra kattintva elfogadod a Puter {{link=terms}}Szolgáltatási feltételeit{{/link}} és {{link=privacy}}Adatvédelmi irányelveit{{/link}}.", + transparency: "Átlátszóság", + trash: "Kuka", + two_factor: "Kétfaktoros hitelesítés", + two_factor_disabled: "2FA letiltva", + two_factor_enabled: "2FA engedélyezve", + type: "Típus", + type_confirm_to_delete_account: "Írd be, hogy 'megerősít' a fiók törléséhez.", + ui_colors: "UI színek", + ui_manage_sessions: "Munkamenetkezelő", + ui_revoke: "Visszavonás", + undo: "Visszavonás", + unlimited: "Korlátlan", + unzip: "Kibontás", + upload: "Feltöltés", + upload_here: "Feltöltés ide", + usage: "Használat", + username: "Felhasználónév", + username_changed: "A felhasználónév sikeresen frissítve.", + username_required: "Felhasználónév szükséges.", + versions: "Verziók", + videos: "Videók", + visibility: "Láthatóság", + yes: "Igen", + yes_release_it: "Igen, Engedd El", + you_have_been_referred_to_puter_by_a_friend: "Egy barátod ajánlott téged a Puterhez!", + zip: "Zip", + zipping_file: "Tömörítés: %strong%", - // === 2FA Setup === - setup2fa_1_step_heading: "Nyisd meg a hitelesítő alkalmazásod", - setup2fa_1_instructions: "Bármely hitelesítő alkalmazást használhatod, amely támogatja az időalapú egyszeri jelszó (TOTP) protokollt. Sok választási lehetőség van, de ha nem vagy biztos benne, az Authy jó választás Android és iOS rendszeren.", - setup2fa_2_step_heading: "Olvasd be a QR-kódot", - setup2fa_3_step_heading: "Add meg a 6-jegyű kódot", - setup2fa_4_step_heading: "Másold le a helyreállítási kódjaidat", - setup2fa_4_instructions: "Ezek a helyreállítási kódok az egyetlen módja annak, hogy hozzáférj a fiókodhoz, ha elveszíted a telefonodat vagy nem tudod használni a hitelesítő alkalmazásodat. Ügyelj arra, hogy biztonságos helyen tárold őket.", - setup2fa_5_step_heading: "2FA beállítás megerősítése", - setup2fa_5_confirmation_1: "A helyreállítási kódokat biztonságos helyen tároltam", - setup2fa_5_confirmation_2: "Készen állok a 2FA engedélyezésére", - setup2fa_5_button: "2FA engedélyezése", + // === 2FA Setup === + setup2fa_1_step_heading: "Nyisd meg a hitelesítő alkalmazásod", + setup2fa_1_instructions: "Bármely hitelesítő alkalmazást használhatod, amely támogatja az időalapú egyszeri jelszó (TOTP) protokollt. Sok választási lehetőség van, de ha nem vagy biztos benne, az Authy jó választás Android és iOS rendszeren.", + setup2fa_2_step_heading: "Olvasd be a QR-kódot", + setup2fa_3_step_heading: "Add meg a 6-jegyű kódot", + setup2fa_4_step_heading: "Másold le a helyreállítási kódjaidat", + setup2fa_4_instructions: "Ezek a helyreállítási kódok az egyetlen módja annak, hogy hozzáférj a fiókodhoz, ha elveszíted a telefonodat vagy nem tudod használni a hitelesítő alkalmazásodat. Ügyelj arra, hogy biztonságos helyen tárold őket.", + setup2fa_5_step_heading: "2FA beállítás megerősítése", + setup2fa_5_confirmation_1: "A helyreállítási kódokat biztonságos helyen tároltam", + setup2fa_5_confirmation_2: "Készen állok a 2FA engedélyezésére", + setup2fa_5_button: "2FA engedélyezése", - // === 2FA Login === - login2fa_otp_title: "2FA kód megadása", - login2fa_otp_instructions: "Add meg a 6-jegyű kódot a hitelesítő alkalmazásodból.", - login2fa_recovery_title: "Add meg egy helyreállítási kódot", - login2fa_recovery_instructions: "Add meg az egyik helyreállítási kódodat a fiókhoz való hozzáféréshez.", - login2fa_use_recovery_code: "Használj helyreállítási kódot", - login2fa_recovery_back: "Vissza", - login2fa_recovery_placeholder: "XXXXXXXX", + // === 2FA Login === + login2fa_otp_title: "2FA kód megadása", + login2fa_otp_instructions: "Add meg a 6-jegyű kódot a hitelesítő alkalmazásodból.", + login2fa_recovery_title: "Add meg egy helyreállítási kódot", + login2fa_recovery_instructions: "Add meg az egyik helyreállítási kódodat a fiókhoz való hozzáféréshez.", + login2fa_use_recovery_code: "Használj helyreállítási kódot", + login2fa_recovery_back: "Vissza", + login2fa_recovery_placeholder: "XXXXXXXX", + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" } }; diff --git a/src/gui/src/i18n/translations/hy.js b/src/gui/src/i18n/translations/hy.js index cc5e0eab41..bef227e683 100644 --- a/src/gui/src/i18n/translations/hy.js +++ b/src/gui/src/i18n/translations/hy.js @@ -345,6 +345,24 @@ const hy = { login2fa_use_recovery_code: "Օգտագործել վերականգնման կոդը", login2fa_recovery_back: "Հետ", login2fa_recovery_placeholder: "XXXXXXXX", + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" } }; diff --git a/src/gui/src/i18n/translations/id.js b/src/gui/src/i18n/translations/id.js index 9e1bcd4f5b..cbdfc39802 100644 --- a/src/gui/src/i18n/translations/id.js +++ b/src/gui/src/i18n/translations/id.js @@ -345,7 +345,25 @@ const id = { login2fa_recovery_instructions: "Masukkan salah satu kode pemulihan Anda untuk mengakses akun Anda.", login2fa_use_recovery_code: "Gunakan kode pemulihan", login2fa_recovery_back: "Kembali", - login2fa_recovery_placeholder: "XXXXXXXX" + login2fa_recovery_placeholder: "XXXXXXXX", + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" } }; diff --git a/src/gui/src/i18n/translations/ig.js b/src/gui/src/i18n/translations/ig.js index ef583e65fb..8e694ce17a 100644 --- a/src/gui/src/i18n/translations/ig.js +++ b/src/gui/src/i18n/translations/ig.js @@ -346,6 +346,25 @@ const ig = { login2fa_use_recovery_code: 'Ji koodu mgbake', login2fa_recovery_back: 'Azu', login2fa_recovery_placeholder: 'XXXXXXXX', + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" + } }; diff --git a/src/gui/src/i18n/translations/it.js b/src/gui/src/i18n/translations/it.js index 9fb87cedd7..8d1720fd6c 100644 --- a/src/gui/src/i18n/translations/it.js +++ b/src/gui/src/i18n/translations/it.js @@ -345,6 +345,24 @@ const it = { login2fa_use_recovery_code: 'Usa un codice di recupero', login2fa_recovery_back: 'Indietro', login2fa_recovery_placeholder: 'XXXXXXXX', + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" } }; diff --git a/src/gui/src/i18n/translations/ja.js b/src/gui/src/i18n/translations/ja.js index d6409e8e6f..5dc01d8a5e 100644 --- a/src/gui/src/i18n/translations/ja.js +++ b/src/gui/src/i18n/translations/ja.js @@ -347,6 +347,26 @@ const ja = { login2fa_recovery_back: '戻る', login2fa_recovery_placeholder: 'XXXXXXXX', + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "plural_suffix": undefined, // In English: "s" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" + } }; diff --git a/src/gui/src/i18n/translations/ko.js b/src/gui/src/i18n/translations/ko.js index 47fca47795..a5686556e8 100644 --- a/src/gui/src/i18n/translations/ko.js +++ b/src/gui/src/i18n/translations/ko.js @@ -346,6 +346,26 @@ const ko = { login2fa_use_recovery_code: "복구코드 사용", login2fa_recovery_back: "뒤로 가기", login2fa_recovery_placeholder: "XXXXXXXX", + + // *********************************** + // Missing translations + // *********************************** + "account_password": undefined, // In English: "Verify Account Password" + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" + }, }; diff --git a/src/gui/src/i18n/translations/ku.js b/src/gui/src/i18n/translations/ku.js index f57e9ab9b3..1d596bb6de 100644 --- a/src/gui/src/i18n/translations/ku.js +++ b/src/gui/src/i18n/translations/ku.js @@ -377,6 +377,24 @@ const ku = { login2fa_use_recovery_code: "بەکارهێنانی کۆدی پشتڕاستکردنەوە", login2fa_recovery_back: "گەڕانەوە", login2fa_recovery_placeholder: "XXXXXXXX", + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" }, }; diff --git a/src/gui/src/i18n/translations/nb.js b/src/gui/src/i18n/translations/nb.js index 191e0bef5a..cc6a0d722a 100644 --- a/src/gui/src/i18n/translations/nb.js +++ b/src/gui/src/i18n/translations/nb.js @@ -180,7 +180,183 @@ const nb = { yes_release_it: "Ja, frigi den", yes: 'ja', you_have_been_referred_to_puter_by_a_friend: "Du har blitt henvist til Puter av en venn!", - zip: "Zip" + zip: "Zip", + + // *********************************** + // Missing translations + // *********************************** + "about": undefined, // In English: "About" + "account": undefined, // In English: "Account" + "account_password": undefined, // In English: "Verify Account Password" + "allow": undefined, // In English: "Allow" + "associated_websites": undefined, // In English: "Associated Websites" + "auto_arrange": undefined, // In English: "Auto Arrange" + "change": undefined, // In English: "Change" + "change_email": undefined, // In English: "Change Email" + "change_ui_colors": undefined, // In English: "Change UI Colors" + "clock_visibility": undefined, // In English: "Clock Visibility" + "close": undefined, // In English: "Close" + "close_all_windows_confirm": undefined, // In English: "Are you sure you want to close all windows?" + "confirm": undefined, // In English: "Confirm" + "confirm_2fa_setup": undefined, // In English: "I have added the code to my authenticator app" + "confirm_2fa_recovery": undefined, // In English: "I have saved my recovery codes in a secure location" + "confirm_code_generic_incorrect": undefined, // In English: "Incorrect Code." + "confirm_code_generic_too_many_requests": undefined, // In English: "Too many requests. Please wait a few minutes." + "confirm_code_generic_submit": undefined, // In English: "Submit Code" + "confirm_code_generic_try_again": undefined, // In English: "Try Again" + "confirm_code_generic_title": undefined, // In English: "Enter Confirmation Code" + "confirm_code_2fa_instruction": undefined, // In English: "Enter the 6-digit code from your authenticator app." + "confirm_code_2fa_submit_btn": undefined, // In English: "Submit" + "confirm_code_2fa_title": undefined, // In English: "Enter 2FA Code" + "confirm_delete_user": undefined, // In English: "Are you sure you want to delete your account? All your files and data will be permanently deleted. This action cannot be undone." + "confirm_delete_user_title": undefined, // In English: "Delete Account?" + "confirm_session_revoke": undefined, // In English: "Are you sure you want to revoke this session?" + "confirm_your_email_address": undefined, // In English: "Confirm Your Email Address" + "contact_us_verification_required": undefined, // In English: "You must have a verified email address to use this." + "copying_file": undefined, // In English: "Copying %%" + "credits": undefined, // In English: "Credits" + "clock": undefined, // In English: "Clock" + "clock_visible_hide": undefined, // In English: "Hide - Always hidden" + "clock_visible_show": undefined, // In English: "Show - Always visible" + "clock_visible_auto": undefined, // In English: "Auto - Default, visible only in full-screen mode." + "close_all": undefined, // In English: "Close All" + "created": undefined, // In English: "Created" + "default": undefined, // In English: "Default" + "delete_account": undefined, // In English: "Delete Account" + "deleting_file": undefined, // In English: "Deleting %%" + "desktop": undefined, // In English: "Desktop" + "developers": undefined, // In English: "Developers" + "disable_2fa": undefined, // In English: "Disable 2FA" + "disable_2fa_confirm": undefined, // In English: "Are you sure you want to disable 2FA?" + "disable_2fa_instructions": undefined, // In English: "Enter your password to disable 2FA." + "documents": undefined, // In English: "Documents" + "dont_allow": undefined, // In English: "Don't Allow" + "email_change_confirmation_sent": undefined, // In English: "A confirmation email has been sent to your new email address. Please check your inbox and follow the instructions to complete the process." + "email_invalid": undefined, // In English: "Email is invalid." + "email_required": undefined, // In English: "Email is required." + "enable_2fa": undefined, // In English: "Enable 2FA" + "end_hard": undefined, // In English: "End Hard" + "end_process_force_confirm": undefined, // In English: "Are you sure you want to force-quit this process?" + "end_soft": undefined, // In English: "End Soft" + "enlarged_qr_code": undefined, // In English: "Enlarged QR Code" + "enter_password_to_confirm_delete_user": undefined, // In English: "Enter your password to confirm account deletion" + "error_message_is_missing": undefined, // In English: "Error message is missing." + "error_unknown_cause": undefined, // In English: "An unknown error occurred." + "error_uploading_files": undefined, // In English: "Failed to upload files" + "favorites": undefined, // In English: "Favorites" + "fit": undefined, // In English: "Fit" + "folder": undefined, // In English: "Folder" + "force_quit": undefined, // In English: "Force Quit" + "home": undefined, // In English: "Home" + "hue": undefined, // In English: "Hue" + "incorrect_password": undefined, // In English: "Incorrect password" + "language": undefined, // In English: "Language" + "license": undefined, // In English: "License" + "lightness": undefined, // In English: "Lightness" + "link_copied": undefined, // In English: "Link copied" + "looks_good": undefined, // In English: "Looks good!" + "manage_sessions": undefined, // In English: "Manage Sessions" + "menubar_style": undefined, // In English: "Menubar Style" + "menubar_style_desktop": undefined, // In English: "Desktop" + "menubar_style_system": undefined, // In English: "System" + "menubar_style_window": undefined, // In English: "Window" + "modified": undefined, // In English: "Modified" + "new_email": undefined, // In English: "New Email" + "original_name": undefined, // In English: "Original Name" + "original_path": undefined, // In English: "Original Path" + "oss_code_and_content": undefined, // In English: "Open Source Software and Content" + "password_recovery_rate_limit": undefined, // In English: "You've reached our rate-limit; please wait a few minutes. To prevent this in the future, avoid reloading the page too many times." + "password_recovery_token_invalid": undefined, // In English: "This password recovery token is no longer valid." + "password_recovery_unknown_error": undefined, // In English: "An unknown error occurred. Please try again later." + "password_required": undefined, // In English: "Password is required." + "password_strength_error": undefined, // In English: "Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, one number, and one special character." + "path": undefined, // In English: "Path" + "personalization": undefined, // In English: "Personalization" + "pictures": undefined, // In English: "Pictures" + "print": undefined, // In English: "Print" + "privacy": undefined, // In English: "Privacy" + "proceed_with_account_deletion": undefined, // In English: "Proceed with Account Deletion" + "process_status_initializing": undefined, // In English: "Initializing" + "process_status_running": undefined, // In English: "Running" + "process_type_app": undefined, // In English: "App" + "process_type_init": undefined, // In English: "Init" + "process_type_ui": undefined, // In English: "UI" + "public": undefined, // In English: "Public" + "puter_description": undefined, // In English: "Puter is a privacy-first personal cloud to keep all your files, apps, and games in one secure place, accessible from anywhere at any time." + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "recommended": undefined, // In English: "Recommended" + "reset_colors": undefined, // In English: "Reset Colors" + "restart_puter_confirm": undefined, // In English: "Are you sure you want to restart Puter?" + "save": undefined, // In English: "Save" + "saturation": undefined, // In English: "Saturation" + "scan_qr_2fa": undefined, // In English: "Scan the QR code with your authenticator app" + "scan_qr_generic": undefined, // In English: "Scan this QR code using your phone or another device" + "search": undefined, // In English: "Search" + "seconds": undefined, // In English: "seconds" + "security": undefined, // In English: "Security" + "sessions": undefined, // In English: "Sessions" + "settings": undefined, // In English: "Settings" + "share": undefined, // In English: "Share" + "share_with": undefined, // In English: "Share with:" + "shortcut_to": undefined, // In English: "Shortcut to" + "something_went_wrong": undefined, // In English: "Something went wrong." + "status": undefined, // In English: "Status" + "storage_usage": undefined, // In English: "Storage Usage" + "storage_puter_used": undefined, // In English: "used by Puter" + "task_manager": undefined, // In English: "Task Manager" + "taskmgr_header_name": undefined, // In English: "Name" + "taskmgr_header_status": undefined, // In English: "Status" + "taskmgr_header_type": undefined, // In English: "Type" + "terms": undefined, // In English: "Terms" + "transparency": undefined, // In English: "Transparency" + "two_factor": undefined, // In English: "Two Factor Authentication" + "two_factor_disabled": undefined, // In English: "2FA Disabled" + "two_factor_enabled": undefined, // In English: "2FA Enabled" + "type_confirm_to_delete_account": undefined, // In English: "Type 'confirm' to delete your account." + "ui_colors": undefined, // In English: "UI Colors" + "ui_manage_sessions": undefined, // In English: "Session Manager" + "ui_revoke": undefined, // In English: "Revoke" + "unlimited": undefined, // In English: "Unlimited" + "unzipping": undefined, // In English: "Unzipping %strong%" + "usage": undefined, // In English: "Usage" + "username_required": undefined, // In English: "Username is required." + "videos": undefined, // In English: "Videos" + "visibility": undefined, // In English: "Visibility" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "setup2fa_1_step_heading": undefined, // In English: "Open your authenticator app" + "setup2fa_1_instructions": undefined, // In English: " + // You can use any authenticator app that supports the Time-based One-Time Password (TOTP) protocol. + // There are many to choose from, but if you're unsure + // Authy + // is a solid choice for Android and iOS. + // " + "setup2fa_2_step_heading": undefined, // In English: "Scan the QR code" + "setup2fa_3_step_heading": undefined, // In English: "Enter the 6-digit code" + "setup2fa_4_step_heading": undefined, // In English: "Copy your recovery codes" + "setup2fa_4_instructions": undefined, // In English: " + // These recovery codes are the only way to access your account if you lose your phone or can't use your authenticator app. + // Make sure to store them in a safe place. + // " + "setup2fa_5_step_heading": undefined, // In English: "Confirm 2FA setup" + "setup2fa_5_confirmation_1": undefined, // In English: "I have saved my recovery codes in a secure location" + "setup2fa_5_confirmation_2": undefined, // In English: "I am ready to enable 2FA" + "setup2fa_5_button": undefined, // In English: "Enable 2FA" + "login2fa_otp_title": undefined, // In English: "Enter 2FA Code" + "login2fa_otp_instructions": undefined, // In English: "Enter the 6-digit code from your authenticator app." + "login2fa_recovery_title": undefined, // In English: "Enter a recovery code" + "login2fa_recovery_instructions": undefined, // In English: "Enter one of your recovery codes to access your account." + "login2fa_use_recovery_code": undefined, // In English: "Use a recovery code" + "login2fa_recovery_back": undefined, // In English: "Back" + "login2fa_recovery_placeholder": undefined, // In English: "XXXXXXXX" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" } }; diff --git a/src/gui/src/i18n/translations/nl.js b/src/gui/src/i18n/translations/nl.js index e4bc171b0f..bce7531694 100644 --- a/src/gui/src/i18n/translations/nl.js +++ b/src/gui/src/i18n/translations/nl.js @@ -346,6 +346,25 @@ const nl = { login2fa_use_recovery_code: 'Gebruik een herstelcode', login2fa_recovery_back: 'Terug', login2fa_recovery_placeholder: 'XXXXXXXX', + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" + } }; diff --git a/src/gui/src/i18n/translations/nn.js b/src/gui/src/i18n/translations/nn.js index 1f323609dc..566b03b42c 100644 --- a/src/gui/src/i18n/translations/nn.js +++ b/src/gui/src/i18n/translations/nn.js @@ -161,7 +161,202 @@ const nn = { versions: "Versjonar", yes_release_it: "Ja, slepp den", you_have_been_referred_to_puter_by_a_friend: "Du har blitt referert til Puter av ein ven!", - zip: "Zip" + zip: "Zip", + + // *********************************** + // Missing translations + // *********************************** + "about": undefined, // In English: "About" + "account": undefined, // In English: "Account" + "account_password": undefined, // In English: "Verify Account Password" + "allow": undefined, // In English: "Allow" + "associated_websites": undefined, // In English: "Associated Websites" + "auto_arrange": undefined, // In English: "Auto Arrange" + "change": undefined, // In English: "Change" + "change_always_open_with": undefined, // In English: "Do you want to always open this type of file with" + "change_email": undefined, // In English: "Change Email" + "change_ui_colors": undefined, // In English: "Change UI Colors" + "clock_visibility": undefined, // In English: "Clock Visibility" + "close": undefined, // In English: "Close" + "close_all_windows_confirm": undefined, // In English: "Are you sure you want to close all windows?" + "close_all_windows_and_log_out": undefined, // In English: "Close Windows and Log Out" + "confirm": undefined, // In English: "Confirm" + "confirm_2fa_setup": undefined, // In English: "I have added the code to my authenticator app" + "confirm_2fa_recovery": undefined, // In English: "I have saved my recovery codes in a secure location" + "confirm_code_generic_incorrect": undefined, // In English: "Incorrect Code." + "confirm_code_generic_too_many_requests": undefined, // In English: "Too many requests. Please wait a few minutes." + "confirm_code_generic_submit": undefined, // In English: "Submit Code" + "confirm_code_generic_try_again": undefined, // In English: "Try Again" + "confirm_code_generic_title": undefined, // In English: "Enter Confirmation Code" + "confirm_code_2fa_instruction": undefined, // In English: "Enter the 6-digit code from your authenticator app." + "confirm_code_2fa_submit_btn": undefined, // In English: "Submit" + "confirm_code_2fa_title": undefined, // In English: "Enter 2FA Code" + "confirm_delete_multiple_items": undefined, // In English: "Are you sure you want to permanently delete these items?" + "confirm_delete_single_item": undefined, // In English: "Do you want to permanently delete this item?" + "confirm_open_apps_log_out": undefined, // In English: "You have open apps. Are you sure you want to log out?" + "confirm_delete_user": undefined, // In English: "Are you sure you want to delete your account? All your files and data will be permanently deleted. This action cannot be undone." + "confirm_delete_user_title": undefined, // In English: "Delete Account?" + "confirm_session_revoke": undefined, // In English: "Are you sure you want to revoke this session?" + "confirm_your_email_address": undefined, // In English: "Confirm Your Email Address" + "contact_us_verification_required": undefined, // In English: "You must have a verified email address to use this." + "copying_file": undefined, // In English: "Copying %%" + "credits": undefined, // In English: "Credits" + "clock": undefined, // In English: "Clock" + "clock_visible_hide": undefined, // In English: "Hide - Always hidden" + "clock_visible_show": undefined, // In English: "Show - Always visible" + "clock_visible_auto": undefined, // In English: "Auto - Default, visible only in full-screen mode." + "close_all": undefined, // In English: "Close All" + "created": undefined, // In English: "Created" + "default": undefined, // In English: "Default" + "delete_account": undefined, // In English: "Delete Account" + "deleting_file": undefined, // In English: "Deleting %%" + "desktop": undefined, // In English: "Desktop" + "developers": undefined, // In English: "Developers" + "disable_2fa": undefined, // In English: "Disable 2FA" + "disable_2fa_confirm": undefined, // In English: "Are you sure you want to disable 2FA?" + "disable_2fa_instructions": undefined, // In English: "Enter your password to disable 2FA." + "documents": undefined, // In English: "Documents" + "dont_allow": undefined, // In English: "Don't Allow" + "download_file": undefined, // In English: "Download File" + "email_change_confirmation_sent": undefined, // In English: "A confirmation email has been sent to your new email address. Please check your inbox and follow the instructions to complete the process." + "email_invalid": undefined, // In English: "Email is invalid." + "email_required": undefined, // In English: "Email is required." + "enable_2fa": undefined, // In English: "Enable 2FA" + "end_hard": undefined, // In English: "End Hard" + "end_process_force_confirm": undefined, // In English: "Are you sure you want to force-quit this process?" + "end_soft": undefined, // In English: "End Soft" + "enlarged_qr_code": undefined, // In English: "Enlarged QR Code" + "enter_password_to_confirm_delete_user": undefined, // In English: "Enter your password to confirm account deletion" + "error_message_is_missing": undefined, // In English: "Error message is missing." + "error_unknown_cause": undefined, // In English: "An unknown error occurred." + "error_uploading_files": undefined, // In English: "Failed to upload files" + "favorites": undefined, // In English: "Favorites" + "fit": undefined, // In English: "Fit" + "folder": undefined, // In English: "Folder" + "force_quit": undefined, // In English: "Force Quit" + "home": undefined, // In English: "Home" + "hue": undefined, // In English: "Hue" + "incorrect_password": undefined, // In English: "Incorrect password" + "item": undefined, // In English: "item" + "language": undefined, // In English: "Language" + "license": undefined, // In English: "License" + "lightness": undefined, // In English: "Lightness" + "link_copied": undefined, // In English: "Link copied" + "loading": undefined, // In English: "Loading" + "log_into_another_account_anyway": undefined, // In English: "Log into another account anyway" + "looks_good": undefined, // In English: "Looks good!" + "manage_sessions": undefined, // In English: "Manage Sessions" + "menubar_style": undefined, // In English: "Menubar Style" + "menubar_style_desktop": undefined, // In English: "Desktop" + "menubar_style_system": undefined, // In English: "System" + "menubar_style_window": undefined, // In English: "Window" + "modified": undefined, // In English: "Modified" + "new_email": undefined, // In English: "New Email" + "no": undefined, // In English: "No" + "original_name": undefined, // In English: "Original Name" + "original_path": undefined, // In English: "Original Path" + "oss_code_and_content": undefined, // In English: "Open Source Software and Content" + "password_recovery_rate_limit": undefined, // In English: "You've reached our rate-limit; please wait a few minutes. To prevent this in the future, avoid reloading the page too many times." + "password_recovery_token_invalid": undefined, // In English: "This password recovery token is no longer valid." + "password_recovery_unknown_error": undefined, // In English: "An unknown error occurred. Please try again later." + "password_required": undefined, // In English: "Password is required." + "password_strength_error": undefined, // In English: "Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, one number, and one special character." + "path": undefined, // In English: "Path" + "personalization": undefined, // In English: "Personalization" + "pictures": undefined, // In English: "Pictures" + "plural_suffix": undefined, // In English: "s" + "print": undefined, // In English: "Print" + "privacy": undefined, // In English: "Privacy" + "proceed_to_login": undefined, // In English: "Proceed to login" + "proceed_with_account_deletion": undefined, // In English: "Proceed with Account Deletion" + "process_status_initializing": undefined, // In English: "Initializing" + "process_status_running": undefined, // In English: "Running" + "process_type_app": undefined, // In English: "App" + "process_type_init": undefined, // In English: "Init" + "process_type_ui": undefined, // In English: "UI" + "public": undefined, // In English: "Public" + "puter_description": undefined, // In English: "Puter is a privacy-first personal cloud to keep all your files, apps, and games in one secure place, accessible from anywhere at any time." + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "recommended": undefined, // In English: "Recommended" + "replace": undefined, // In English: "Replace" + "replace_all": undefined, // In English: "Replace All" + "reset_colors": undefined, // In English: "Reset Colors" + "restart_puter_confirm": undefined, // In English: "Are you sure you want to restart Puter?" + "save": undefined, // In English: "Save" + "saturation": undefined, // In English: "Saturation" + "save_account": undefined, // In English: "Save account" + "save_session": undefined, // In English: "Save session" + "scan_qr_2fa": undefined, // In English: "Scan the QR code with your authenticator app" + "scan_qr_generic": undefined, // In English: "Scan this QR code using your phone or another device" + "search": undefined, // In English: "Search" + "seconds": undefined, // In English: "seconds" + "security": undefined, // In English: "Security" + "selected": undefined, // In English: "selected" + "sessions": undefined, // In English: "Sessions" + "settings": undefined, // In English: "Settings" + "share": undefined, // In English: "Share" + "share_with": undefined, // In English: "Share with:" + "shortcut_to": undefined, // In English: "Shortcut to" + "skip": undefined, // In English: "Skip" + "something_went_wrong": undefined, // In English: "Something went wrong." + "status": undefined, // In English: "Status" + "storage_usage": undefined, // In English: "Storage Usage" + "storage_puter_used": undefined, // In English: "used by Puter" + "task_manager": undefined, // In English: "Task Manager" + "taskmgr_header_name": undefined, // In English: "Name" + "taskmgr_header_status": undefined, // In English: "Status" + "taskmgr_header_type": undefined, // In English: "Type" + "terms": undefined, // In English: "Terms" + "transparency": undefined, // In English: "Transparency" + "two_factor": undefined, // In English: "Two Factor Authentication" + "two_factor_disabled": undefined, // In English: "2FA Disabled" + "two_factor_enabled": undefined, // In English: "2FA Enabled" + "type_confirm_to_delete_account": undefined, // In English: "Type 'confirm' to delete your account." + "ui_colors": undefined, // In English: "UI Colors" + "ui_manage_sessions": undefined, // In English: "Session Manager" + "ui_revoke": undefined, // In English: "Revoke" + "unlimited": undefined, // In English: "Unlimited" + "unzipping": undefined, // In English: "Unzipping %strong%" + "usage": undefined, // In English: "Usage" + "username_required": undefined, // In English: "Username is required." + "videos": undefined, // In English: "Videos" + "visibility": undefined, // In English: "Visibility" + "yes": undefined, // In English: "Yes" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "setup2fa_1_step_heading": undefined, // In English: "Open your authenticator app" + "setup2fa_1_instructions": undefined, // In English: " + // You can use any authenticator app that supports the Time-based One-Time Password (TOTP) protocol. + // There are many to choose from, but if you're unsure + // Authy + // is a solid choice for Android and iOS. + // " + "setup2fa_2_step_heading": undefined, // In English: "Scan the QR code" + "setup2fa_3_step_heading": undefined, // In English: "Enter the 6-digit code" + "setup2fa_4_step_heading": undefined, // In English: "Copy your recovery codes" + "setup2fa_4_instructions": undefined, // In English: " + // These recovery codes are the only way to access your account if you lose your phone or can't use your authenticator app. + // Make sure to store them in a safe place. + // " + "setup2fa_5_step_heading": undefined, // In English: "Confirm 2FA setup" + "setup2fa_5_confirmation_1": undefined, // In English: "I have saved my recovery codes in a secure location" + "setup2fa_5_confirmation_2": undefined, // In English: "I am ready to enable 2FA" + "setup2fa_5_button": undefined, // In English: "Enable 2FA" + "login2fa_otp_title": undefined, // In English: "Enter 2FA Code" + "login2fa_otp_instructions": undefined, // In English: "Enter the 6-digit code from your authenticator app." + "login2fa_recovery_title": undefined, // In English: "Enter a recovery code" + "login2fa_recovery_instructions": undefined, // In English: "Enter one of your recovery codes to access your account." + "login2fa_use_recovery_code": undefined, // In English: "Use a recovery code" + "login2fa_recovery_back": undefined, // In English: "Back" + "login2fa_recovery_placeholder": undefined, // In English: "XXXXXXXX" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" } }; diff --git a/src/gui/src/i18n/translations/pl.js b/src/gui/src/i18n/translations/pl.js index cb6ba1531c..d486277b98 100644 --- a/src/gui/src/i18n/translations/pl.js +++ b/src/gui/src/i18n/translations/pl.js @@ -345,6 +345,25 @@ const pl = { login2fa_use_recovery_code: 'Użyj kod odzyskiwania', login2fa_recovery_back: 'Powrót', login2fa_recovery_placeholder: 'XXXXXXXX', + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "plural_suffix": undefined, // In English: "s" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" } }; diff --git a/src/gui/src/i18n/translations/pt.js b/src/gui/src/i18n/translations/pt.js index 4f8f251e3c..9d7a82bbc1 100644 --- a/src/gui/src/i18n/translations/pt.js +++ b/src/gui/src/i18n/translations/pt.js @@ -345,6 +345,24 @@ const pt = { login2fa_use_recovery_code: 'Use a recovery code', login2fa_recovery_back: 'Back', login2fa_recovery_placeholder: 'XXXXXXXX', + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" } }; diff --git a/src/gui/src/i18n/translations/ro.js b/src/gui/src/i18n/translations/ro.js index e6ef5553a7..6086b726ff 100644 --- a/src/gui/src/i18n/translations/ro.js +++ b/src/gui/src/i18n/translations/ro.js @@ -343,6 +343,25 @@ const ro = { login2fa_use_recovery_code: "Folosiți un cod de restaurare", login2fa_recovery_back: "Înapoi", login2fa_recovery_placeholder: "XXXXXXXX", + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" + } } diff --git a/src/gui/src/i18n/translations/ru.js b/src/gui/src/i18n/translations/ru.js index 34802e926d..7e85db9585 100644 --- a/src/gui/src/i18n/translations/ru.js +++ b/src/gui/src/i18n/translations/ru.js @@ -346,6 +346,26 @@ const ru = { login2fa_use_recovery_code: 'Используйте код восстановления доступа', login2fa_recovery_back: 'Назад', login2fa_recovery_placeholder: 'XXXXXXXX', + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "confirm_your_email_address": undefined, // In English: "Confirm Your Email Address" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" + } }; diff --git a/src/gui/src/i18n/translations/sv.js b/src/gui/src/i18n/translations/sv.js index fcceafe8fe..27eb1149e1 100644 --- a/src/gui/src/i18n/translations/sv.js +++ b/src/gui/src/i18n/translations/sv.js @@ -346,6 +346,26 @@ const sv = { login2fa_use_recovery_code: "Använd en återhämtningskod", login2fa_recovery_back: "Tillbaka", login2fa_recovery_placeholder: "XXXXXXXX", + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "plural_suffix": undefined, // In English: "s" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" + } }; diff --git a/src/gui/src/i18n/translations/ta.js b/src/gui/src/i18n/translations/ta.js index 878024b784..4774a7415a 100644 --- a/src/gui/src/i18n/translations/ta.js +++ b/src/gui/src/i18n/translations/ta.js @@ -344,6 +344,26 @@ const ta = { login2fa_use_recovery_code: 'மீட்புக் குறியீட்டைப் பயன்படுத்தவும்', login2fa_recovery_back: 'மீண்டும்', login2fa_recovery_placeholder: 'XXXXXXXX', + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "confirm": undefined, // In English: "Confirm" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" + } }; diff --git a/src/gui/src/i18n/translations/th.js b/src/gui/src/i18n/translations/th.js index 4d391ba393..01637c1bd0 100644 --- a/src/gui/src/i18n/translations/th.js +++ b/src/gui/src/i18n/translations/th.js @@ -343,6 +343,29 @@ const th = { login2fa_recovery_back: 'ย้อนกลับ', login2fa_recovery_placeholder: 'XXXXXXXX', + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "confirm": undefined, // In English: "Confirm" + "path": undefined, // In English: "Path" + "plural_suffix": undefined, // In English: "s" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "save": undefined, // In English: "Save" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" + } }; diff --git a/src/gui/src/i18n/translations/tr.js b/src/gui/src/i18n/translations/tr.js index 0e1a29f689..7edaf77b6a 100644 --- a/src/gui/src/i18n/translations/tr.js +++ b/src/gui/src/i18n/translations/tr.js @@ -347,7 +347,27 @@ const tr = { login2fa_recovery_instructions: "Hesabınıza erişmek için kurtarma kodlarınızdan birini girin.", login2fa_use_recovery_code: "Bir kurtarma kodu kullan", login2fa_recovery_back: "Geri", - login2fa_recovery_placeholder: "XXXXXXXX" + login2fa_recovery_placeholder: "XXXXXXXX", + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "confirm": undefined, // In English: "Confirm" + "plural_suffix": undefined, // In English: "s" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" } }; diff --git a/src/gui/src/i18n/translations/translations.js b/src/gui/src/i18n/translations/translations.js index 46824464bd..d9f493889c 100644 --- a/src/gui/src/i18n/translations/translations.js +++ b/src/gui/src/i18n/translations/translations.js @@ -55,8 +55,6 @@ import vi from "./vi.js"; import emoji from './emoji.js'; import id from './id.js'; - - export default { ar, bn, diff --git a/src/gui/src/i18n/translations/ua.js b/src/gui/src/i18n/translations/ua.js index ee521f5663..182728eec4 100644 --- a/src/gui/src/i18n/translations/ua.js +++ b/src/gui/src/i18n/translations/ua.js @@ -330,6 +330,28 @@ const ua = { login2fa_use_recovery_code: 'Використовуйте код відновлення', login2fa_recovery_back: 'Назад', login2fa_recovery_placeholder: 'XXXXXXXX', + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "deleting_file": undefined, // In English: "Deleting %%" + "print": undefined, // In English: "Print" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "share": undefined, // In English: "Share" + "something_went_wrong": undefined, // In English: "Something went wrong." + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" } } diff --git a/src/gui/src/i18n/translations/ur.js b/src/gui/src/i18n/translations/ur.js index 8b48be53bb..00e01bf033 100644 --- a/src/gui/src/i18n/translations/ur.js +++ b/src/gui/src/i18n/translations/ur.js @@ -358,6 +358,42 @@ const ur = { login2fa_use_recovery_code: "ریکوری کوڈ استعمال کریں۔", login2fa_recovery_back: "پیچھے", login2fa_recovery_placeholder: "XXXXXXXX", + + // *********************************** + // Missing translations + // *********************************** + "allow": undefined, // In English: "Allow" + "associated_websites": undefined, // In English: "Associated Websites" + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "confirm": undefined, // In English: "Confirm" + "confirm_your_email_address": undefined, // In English: "Confirm Your Email Address" + "close_all": undefined, // In English: "Close All" + "created": undefined, // In English: "Created" + "dont_allow": undefined, // In English: "Don't Allow" + "error_message_is_missing": undefined, // In English: "Error message is missing." + "folder": undefined, // In English: "Folder" + "modified": undefined, // In English: "Modified" + "original_name": undefined, // In English: "Original Name" + "original_path": undefined, // In English: "Original Path" + "path": undefined, // In English: "Path" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "save": undefined, // In English: "Save" + "sessions": undefined, // In English: "Sessions" + "share": undefined, // In English: "Share" + "share_with": undefined, // In English: "Share with:" + "shortcut_to": undefined, // In English: "Shortcut to" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" }, }; diff --git a/src/gui/src/i18n/translations/vi.js b/src/gui/src/i18n/translations/vi.js index a8a0e6c184..759b9ecf3f 100644 --- a/src/gui/src/i18n/translations/vi.js +++ b/src/gui/src/i18n/translations/vi.js @@ -346,6 +346,25 @@ const vi = { login2fa_use_recovery_code: 'Sử dụng mã khôi phục', login2fa_recovery_back: 'Quay lại', login2fa_recovery_placeholder: 'XXXXXXXX', + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "plural_suffix": undefined, // In English: "s" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" } }; diff --git a/src/gui/src/i18n/translations/zh.js b/src/gui/src/i18n/translations/zh.js index 7c5646d309..b826ee03dc 100644 --- a/src/gui/src/i18n/translations/zh.js +++ b/src/gui/src/i18n/translations/zh.js @@ -346,6 +346,26 @@ const zh = { login2fa_use_recovery_code: '使用恢复码', login2fa_recovery_back: '后退', login2fa_recovery_placeholder: '********', + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "plural_suffix": undefined, // In English: "s" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" + } }; diff --git a/src/gui/src/i18n/translations/zhtw.js b/src/gui/src/i18n/translations/zhtw.js index 9dc5165047..bec81cd7d9 100644 --- a/src/gui/src/i18n/translations/zhtw.js +++ b/src/gui/src/i18n/translations/zhtw.js @@ -345,6 +345,24 @@ const zhtw = { login2fa_use_recovery_code: '使用恢復碼', login2fa_recovery_back: '返回', login2fa_recovery_placeholder: 'XXXXXXXX', + + // *********************************** + // Missing translations + // *********************************** + "change": undefined, // In English: "Change" + "clock_visibility": undefined, // In English: "Clock Visibility" + "reading": undefined, // In English: "Reading %strong%" + "writing": undefined, // In English: "Writing %strong%" + "unzipping": undefined, // In English: "Unzipping %strong%" + "sequencing": undefined, // In English: "Sequencing %strong%" + "zipping": undefined, // In English: "Zipping %strong%" + "Editor": undefined, // In English: "Editor" + "Viewer": undefined, // In English: "Viewer" + "People with access": undefined, // In English: "People with access" + "Share With…": undefined, // In English: "Share With…" + "Owner": undefined, // In English: "Owner" + "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "This user already has access to this item": undefined, // In English: "This user already has access to this item" } }; From 35fd15854ad3cc92924c4ded752e337f467a7125 Mon Sep 17 00:00:00 2001 From: jelveh Date: Tue, 19 Nov 2024 17:54:28 -0800 Subject: [PATCH 1194/2119] fix: capitalize `Hindi` in i18n --- src/gui/src/i18n/translations/hi.js | 2 +- src/gui/src/i18n/translations/ig.js | 1 - 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/src/gui/src/i18n/translations/hi.js b/src/gui/src/i18n/translations/hi.js index 1aa83ac797..9a82689cb8 100644 --- a/src/gui/src/i18n/translations/hi.js +++ b/src/gui/src/i18n/translations/hi.js @@ -20,7 +20,7 @@ const hi = { name: "हिंदी", - english_name: "hindi", + english_name: "Hindi", code: "hi", dictionary: { about: "के बारे में", diff --git a/src/gui/src/i18n/translations/ig.js b/src/gui/src/i18n/translations/ig.js index 8e694ce17a..34f967354d 100644 --- a/src/gui/src/i18n/translations/ig.js +++ b/src/gui/src/i18n/translations/ig.js @@ -364,7 +364,6 @@ const ig = { "Owner": undefined, // In English: "Owner" "You can't share with yourself.": undefined, // In English: "You can't share with yourself." "This user already has access to this item": undefined, // In English: "This user already has access to this item" - } }; From b2afeb162a172e647934e39053a2721d49e1a98e Mon Sep 17 00:00:00 2001 From: Bansal <118830821+Abhinav-Bansal751@users.noreply.github.com> Date: Wed, 20 Nov 2024 11:02:54 +0530 Subject: [PATCH 1195/2119] Update es.js --- src/gui/src/i18n/translations/es.js | 30 ++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/gui/src/i18n/translations/es.js b/src/gui/src/i18n/translations/es.js index 76a0583962..d36388aea4 100644 --- a/src/gui/src/i18n/translations/es.js +++ b/src/gui/src/i18n/translations/es.js @@ -356,22 +356,22 @@ const es = { // *********************************** // Missing translations // *********************************** - "change": undefined, // In English: "Change" - "clock_visibility": undefined, // In English: "Clock Visibility" - "reading": undefined, // In English: "Reading %strong%" - "writing": undefined, // In English: "Writing %strong%" - "unzipping": undefined, // In English: "Unzipping %strong%" - "sequencing": undefined, // In English: "Sequencing %strong%" - "zipping": undefined, // In English: "Zipping %strong%" - "Editor": undefined, // In English: "Editor" - "Viewer": undefined, // In English: "Viewer" - "People with access": undefined, // In English: "People with access" - "Share With…": undefined, // In English: "Share With…" - "Owner": undefined, // In English: "Owner" - "You can't share with yourself.": undefined, // In English: "You can't share with yourself." - "This user already has access to this item": undefined, // In English: "This user already has access to this item" + "change": 'cambiar', // In English: "Change" + "clock_visibility": 'visibilidad_reloj', // In English: "Clock Visibility" + "reading": 'lectura', // In English: "Reading %strong%" + "writing": 'escribiendo', // In English: "Writing %strong%" + "unzipping": 'descomprimiendo', // In English: "Unzipping %strong%" + "sequencing": 'secuenciación', // In English: "Sequencing %strong%" + "zipping": 'comprimir', // In English: "Zipping %strong%" + "Editor": 'Editor', // In English: "Editor" + "Viewer": 'Espectador', // In English: "Viewer" + "People with access": 'personas con acceso', // In English: "People with access" + "Share With…": 'Compartir con…', // In English: "Share With…" + "Owner": 'Dueño', // In English: "Owner" + "You can't share with yourself.": 'No puedes compartir contigo mismo.', // In English: "You can't share with yourself." + "This user already has access to this item": 'Este usuario ya tiene acceso a este elemento.', // In English: "This user already has access to this item" } }; -export default es; \ No newline at end of file +export default es; From 2c862403994ff6385144841db07dcc94c5c2fc2e Mon Sep 17 00:00:00 2001 From: jelveh Date: Tue, 19 Nov 2024 21:42:29 -0800 Subject: [PATCH 1196/2119] fix: add placeholders --- src/gui/src/i18n/translations/es.js | 33 +++++++++++++---------------- 1 file changed, 15 insertions(+), 18 deletions(-) diff --git a/src/gui/src/i18n/translations/es.js b/src/gui/src/i18n/translations/es.js index d36388aea4..63cf1b16ec 100644 --- a/src/gui/src/i18n/translations/es.js +++ b/src/gui/src/i18n/translations/es.js @@ -353,24 +353,21 @@ const es = { login2fa_recovery_back: 'Atras', login2fa_recovery_placeholder: 'XXXXXXXX', - // *********************************** - // Missing translations - // *********************************** - "change": 'cambiar', // In English: "Change" - "clock_visibility": 'visibilidad_reloj', // In English: "Clock Visibility" - "reading": 'lectura', // In English: "Reading %strong%" - "writing": 'escribiendo', // In English: "Writing %strong%" - "unzipping": 'descomprimiendo', // In English: "Unzipping %strong%" - "sequencing": 'secuenciación', // In English: "Sequencing %strong%" - "zipping": 'comprimir', // In English: "Zipping %strong%" - "Editor": 'Editor', // In English: "Editor" - "Viewer": 'Espectador', // In English: "Viewer" - "People with access": 'personas con acceso', // In English: "People with access" - "Share With…": 'Compartir con…', // In English: "Share With…" - "Owner": 'Dueño', // In English: "Owner" - "You can't share with yourself.": 'No puedes compartir contigo mismo.', // In English: "You can't share with yourself." - "This user already has access to this item": 'Este usuario ya tiene acceso a este elemento.', // In English: "This user already has access to this item" - + "change": "cambiar", // In English: "Change" + "clock_visibility": "visibilidadReloj", // In English: "Clock Visibility" + "reading": "lectura %strong%", // In English: "Reading %strong%" + "writing": "escribiendo %strong%", // In English: "Writing %strong%" + "unzipping": "descomprimiendo %strong%", // In English: "Unzipping %strong%" + "sequencing": "secuenciación %strong%", // In English: "Sequencing %strong%" + "zipping": "comprimiendo %strong%", // In English: "Zipping %strong%" + "Editor": "Editor", // In English: "Editor" + "Viewer": "Espectador", // In English: "Viewer" + "People with access": "Personas con acceso", // In English: "People with access" + "Share With…": "Compartir con…", // In English: "Share With…" + "Owner": "Propietario", // In English: "Owner" + "You can't share with yourself.": "No puedes compartir contigo mismo.", // In English: "You can't share with yourself." + "This user already has access to this item": "Este usuario ya tiene acceso a este elemento." // In English: "This user already has access to this item" + } }; From 2d522537eeb8e0a47602e804961ccf40b30d40f1 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 21:41:07 +0600 Subject: [PATCH 1197/2119] add translation for: change --- src/gui/src/i18n/translations/bn.js | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 6f18fd559a..fefd94eabb 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -47,7 +47,7 @@ const bn = { close_all_windows: "সমস্ত উইন্ডো বন্ধ করুন", close_all_windows_confirm: "আপনি কি সমস্ত উইন্ডো বন্ধ করতে চান?", close_all_windows_and_log_out: "উইন্ডো বন্ধ এবং লগ আউট করুন", - change_always_open_with: "আপনি কি এই ধরনের ফাইলটি সবসময় এই সাথে খোলার জন্য চান", + change_always_open_with: "আপনি কি এই ধরনের ফাইলটি সবসময় এই সাথে খোলার জন্য চান", color: "রঙ", confirm: "অনুমোদন", confirm_2fa_setup: "আমি আমার অথেন্টিকেশন অ্যাপ্লিকেশনে কোডটি যোগ করেছি", @@ -63,7 +63,7 @@ const bn = { confirm_code_2fa_title: "2FA কোড প্রবেশ করুন", confirm_delete_multiple_items: "আপনি কি নিশ্চিত যে আপনি এই আইটেমগুলি স্থায়ীভাবে মুছতে চান?", confirm_delete_single_item: "আপনি কি এই আইটেমটি স্থায়ীভাবে মুছতে চান?", - confirm_open_apps_log_out: "আপনার খোলা অ্যাপ আছে। আপনি কি নিশ্চিত যে আপনি লগ আউট করতে চান?", + confirm_open_apps_log_out: "আপনার খোলা অ্যাপ আছে। আপনি কি নিশ্চিত যে আপনি লগ আউট করতে চান?", confirm_new_password: "নতুন পাসওয়ার্ড নিশ্চিত করুন", confirm_delete_user: "আপনি কি নিশ্চিত যে আপনি আপনার অ্যাকাউন্টটি মুছতে চান? সমস্ত আপনার ফাইল এবং ডেটা স্থায়ীভাবে মুছে ফেলা হবে। এই ক্রিয়াটি ফিরে পাওয়া যাবে না।", confirm_delete_user_title: "অ্যাকাউন্ট মুছে ফেলুন?", @@ -200,7 +200,7 @@ const bn = { password_reset: "পাসওয়ার্ড রিসেট করুন", password_reset_confirmation: "পাসওয়ার্ড সেট করতে নীচের ফর্মটি পূরণ করুন।", password_reset_request_expired: "আপনার পাসওয়ার্ড রিসেট রিকোয়েস্টের মেয়াদ শেষ হয়ে গেছে। দয়া করে পুনরায় চেষ্টা করুন।", - password_reset_sent: "পাসওয়ার্ড রিসেট রিকোয়েস্ট সফলভাবে প্রেরিত হয়েছে। আপনার ইনবক্স পরীক্ষা করুন এবং নির্দেশানুযায়ী প্রক্রিয়াটি সম্পন্ন করতে।", + password_reset_sent: "পাসওয়ার্ড রিসেট রিকোয়েস্ট সফলভাবে প্রেরিত হয়েছে। আপনার ইনবক্স পরীক্ষা করুন এবং নির্দেশানুযায়ী প্রক্রিয়াটি সম্পন্ন করতে।", password_update_success: "পাসওয়ার্ড সফলভাবে আপডেট হয়েছে!", passwords_do_not_match: "পাসওয়ার্ড মিলে না", paste: "পেস্ট", @@ -232,7 +232,7 @@ const bn = { recent: "সাম্প্রতিক", recommended: "অনুমোদিত", recover_password: "পাসওয়ার্ড পুনরুদ্ধার করুন", - refer_friends_c2a: "Puter তে অ্যাকাউন্ট তৈরি এবং নিশ্চিতকরণ করে একটি বন্ধুর প্রতি 1 জিবি পান। আপনার বন্ধুও 1 জিবি পাবে!", + refer_friends_c2a: "Puter তে অ্যাকাউন্ট তৈরি এবং নিশ্চিতকরণ করে একটি বন্ধুর প্রতি 1 জিবি পান। আপনার বন্ধুও 1 জিবি পাবে!", refer_friends_social_media_c2a: `Puter.com এ 1 GB বিনামূল্যের সংরক্ষণ পান!`, refresh: "রিফ্রেশ", release_address_confirmation: `আপনি কি নিশ্চিত যে আপনি এই ঠিকানা রিলিজ করতে চান?`, @@ -349,10 +349,10 @@ const bn = { login2fa_recovery_back: "পিছনে", login2fa_recovery_placeholder: "XXXXXXXX", - // *********************************** - // Missing translations - // *********************************** - "change": undefined, // In English: "Change" + // *********************************** + // Missing translations + // *********************************** + "change": "পরিবর্তন", // In English: "Change" "clock_visibility": undefined, // In English: "Clock Visibility" "password_recovery_token_invalid": undefined, // In English: "This password recovery token is no longer valid." "password_recovery_unknown_error": undefined, // In English: "An unknown error occurred. Please try again later." From e3782f7b428cb4c8f73cdc91f0e525eedc5d397a Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 21:41:41 +0600 Subject: [PATCH 1198/2119] add translation for: clock_visibility --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index fefd94eabb..ba4b5e6e3c 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -353,7 +353,7 @@ const bn = { // Missing translations // *********************************** "change": "পরিবর্তন", // In English: "Change" - "clock_visibility": undefined, // In English: "Clock Visibility" + "clock_visibility": "ঘড়ি দেখা", // In English: "Clock Visibility" "password_recovery_token_invalid": undefined, // In English: "This password recovery token is no longer valid." "password_recovery_unknown_error": undefined, // In English: "An unknown error occurred. Please try again later." "password_required": undefined, // In English: "Password is required." From 1fa0bebfd52e48b37d714e8dfafd155613ae97fc Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 21:42:44 +0600 Subject: [PATCH 1199/2119] update translation for: Clock Visibility --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index ba4b5e6e3c..4320cf8f04 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -353,7 +353,7 @@ const bn = { // Missing translations // *********************************** "change": "পরিবর্তন", // In English: "Change" - "clock_visibility": "ঘড়ি দেখা", // In English: "Clock Visibility" + "clock_visibility": "ঘড়ির দৃশ্যমানতা", // In English: "Clock Visibility" "password_recovery_token_invalid": undefined, // In English: "This password recovery token is no longer valid." "password_recovery_unknown_error": undefined, // In English: "An unknown error occurred. Please try again later." "password_required": undefined, // In English: "Password is required." From 86a54b9415f70b520a00c73a9e8c5fb418e5bb42 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 21:43:36 +0600 Subject: [PATCH 1200/2119] add translation: password_recovery_token_invalid --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 4320cf8f04..9d8ebae95b 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -354,7 +354,7 @@ const bn = { // *********************************** "change": "পরিবর্তন", // In English: "Change" "clock_visibility": "ঘড়ির দৃশ্যমানতা", // In English: "Clock Visibility" - "password_recovery_token_invalid": undefined, // In English: "This password recovery token is no longer valid." + "password_recovery_token_invalid": "এই পাসওয়ার্ড রিকোভারি টোকেনটি আর ব্যবহারযোগ্য নয়।", // In English: "This password recovery token is no longer valid." "password_recovery_unknown_error": undefined, // In English: "An unknown error occurred. Please try again later." "password_required": undefined, // In English: "Password is required." "password_strength_error": undefined, // In English: "Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, one number, and one special character." From ae20fd5afa0a159934ba73b36d6c325f43a7ce47 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 21:45:19 +0600 Subject: [PATCH 1201/2119] add translation: password_recovery_unknown_error --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 9d8ebae95b..037237a208 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -355,7 +355,7 @@ const bn = { "change": "পরিবর্তন", // In English: "Change" "clock_visibility": "ঘড়ির দৃশ্যমানতা", // In English: "Clock Visibility" "password_recovery_token_invalid": "এই পাসওয়ার্ড রিকোভারি টোকেনটি আর ব্যবহারযোগ্য নয়।", // In English: "This password recovery token is no longer valid." - "password_recovery_unknown_error": undefined, // In English: "An unknown error occurred. Please try again later." + "password_recovery_unknown_error": "একটি অজানা ত্রুটি ঘটেছে. অনুগ্রহ করে পরবর্তীতে আবার চেষ্টা করুন।", // In English: "An unknown error occurred. Please try again later." "password_required": undefined, // In English: "Password is required." "password_strength_error": undefined, // In English: "Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, one number, and one special character." "reading": undefined, // In English: "Reading %strong%" From da2dee842ac1248a4018245337d9631dcb724e00 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 21:45:49 +0600 Subject: [PATCH 1202/2119] add translation: password_required --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 037237a208..61e91a3e1e 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -356,7 +356,7 @@ const bn = { "clock_visibility": "ঘড়ির দৃশ্যমানতা", // In English: "Clock Visibility" "password_recovery_token_invalid": "এই পাসওয়ার্ড রিকোভারি টোকেনটি আর ব্যবহারযোগ্য নয়।", // In English: "This password recovery token is no longer valid." "password_recovery_unknown_error": "একটি অজানা ত্রুটি ঘটেছে. অনুগ্রহ করে পরবর্তীতে আবার চেষ্টা করুন।", // In English: "An unknown error occurred. Please try again later." - "password_required": undefined, // In English: "Password is required." + "password_required": "পাসওয়ার্ড প্রযোজ্য।", // In English: "Password is required." "password_strength_error": undefined, // In English: "Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, one number, and one special character." "reading": undefined, // In English: "Reading %strong%" "writing": undefined, // In English: "Writing %strong%" From a820721f743ac9772eadb68b4c7f618a6d709219 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 21:47:09 +0600 Subject: [PATCH 1203/2119] add translation: password_strength_error --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 61e91a3e1e..3658540ed1 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -357,7 +357,7 @@ const bn = { "password_recovery_token_invalid": "এই পাসওয়ার্ড রিকোভারি টোকেনটি আর ব্যবহারযোগ্য নয়।", // In English: "This password recovery token is no longer valid." "password_recovery_unknown_error": "একটি অজানা ত্রুটি ঘটেছে. অনুগ্রহ করে পরবর্তীতে আবার চেষ্টা করুন।", // In English: "An unknown error occurred. Please try again later." "password_required": "পাসওয়ার্ড প্রযোজ্য।", // In English: "Password is required." - "password_strength_error": undefined, // In English: "Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, one number, and one special character." + "password_strength_error": "পাসওয়ার্ড অন্ততপক্ষে 8 অক্ষরবিশিষ্ট দীর্ঘ হতে হবে এবং কমপক্ষে একটি বড় হাতের অক্ষর, একটি ছোট হাতের অক্ষর, একটি সংখ্যা এবং একটি বিশেষ অক্ষর থাকতে হবে৷", // In English: "Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, one number, and one special character." "reading": undefined, // In English: "Reading %strong%" "writing": undefined, // In English: "Writing %strong%" "unzipping": undefined, // In English: "Unzipping %strong%" From be7d651f7f321e0c42f2f3742dcb6b51ca361c4e Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 21:48:59 +0600 Subject: [PATCH 1204/2119] add translation: reading --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 3658540ed1..bcdbeba349 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -358,7 +358,7 @@ const bn = { "password_recovery_unknown_error": "একটি অজানা ত্রুটি ঘটেছে. অনুগ্রহ করে পরবর্তীতে আবার চেষ্টা করুন।", // In English: "An unknown error occurred. Please try again later." "password_required": "পাসওয়ার্ড প্রযোজ্য।", // In English: "Password is required." "password_strength_error": "পাসওয়ার্ড অন্ততপক্ষে 8 অক্ষরবিশিষ্ট দীর্ঘ হতে হবে এবং কমপক্ষে একটি বড় হাতের অক্ষর, একটি ছোট হাতের অক্ষর, একটি সংখ্যা এবং একটি বিশেষ অক্ষর থাকতে হবে৷", // In English: "Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, one number, and one special character." - "reading": undefined, // In English: "Reading %strong%" + "reading": "%strong% পড়ছে", // In English: "Reading %strong%" "writing": undefined, // In English: "Writing %strong%" "unzipping": undefined, // In English: "Unzipping %strong%" "sequencing": undefined, // In English: "Sequencing %strong%" From 27da49dcd33a3aa16c4f35e98a5fdac799797dea Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 21:49:21 +0600 Subject: [PATCH 1205/2119] add translation: writing --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index bcdbeba349..1e4cca6b7d 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -359,7 +359,7 @@ const bn = { "password_required": "পাসওয়ার্ড প্রযোজ্য।", // In English: "Password is required." "password_strength_error": "পাসওয়ার্ড অন্ততপক্ষে 8 অক্ষরবিশিষ্ট দীর্ঘ হতে হবে এবং কমপক্ষে একটি বড় হাতের অক্ষর, একটি ছোট হাতের অক্ষর, একটি সংখ্যা এবং একটি বিশেষ অক্ষর থাকতে হবে৷", // In English: "Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, one number, and one special character." "reading": "%strong% পড়ছে", // In English: "Reading %strong%" - "writing": undefined, // In English: "Writing %strong%" + "writing": "%strong% লিখছে", // In English: "Writing %strong%" "unzipping": undefined, // In English: "Unzipping %strong%" "sequencing": undefined, // In English: "Sequencing %strong%" "zipping": undefined, // In English: "Zipping %strong%" From f9b2a81d001d091affdb12afc90ee9fb1e869010 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 21:49:45 +0600 Subject: [PATCH 1206/2119] add translation: unzipping --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 1e4cca6b7d..87d9765e79 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -360,7 +360,7 @@ const bn = { "password_strength_error": "পাসওয়ার্ড অন্ততপক্ষে 8 অক্ষরবিশিষ্ট দীর্ঘ হতে হবে এবং কমপক্ষে একটি বড় হাতের অক্ষর, একটি ছোট হাতের অক্ষর, একটি সংখ্যা এবং একটি বিশেষ অক্ষর থাকতে হবে৷", // In English: "Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, one number, and one special character." "reading": "%strong% পড়ছে", // In English: "Reading %strong%" "writing": "%strong% লিখছে", // In English: "Writing %strong%" - "unzipping": undefined, // In English: "Unzipping %strong%" + "unzipping": "%strong% আনজিপিং হচ্ছে", // In English: "Unzipping %strong%" "sequencing": undefined, // In English: "Sequencing %strong%" "zipping": undefined, // In English: "Zipping %strong%" "Editor": undefined, // In English: "Editor" From 84a68a36889e657683935ef67d2365fc8d5b8139 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 21:50:42 +0600 Subject: [PATCH 1207/2119] add translation: sequencing --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 87d9765e79..0ac7d51e27 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -361,7 +361,7 @@ const bn = { "reading": "%strong% পড়ছে", // In English: "Reading %strong%" "writing": "%strong% লিখছে", // In English: "Writing %strong%" "unzipping": "%strong% আনজিপিং হচ্ছে", // In English: "Unzipping %strong%" - "sequencing": undefined, // In English: "Sequencing %strong%" + "sequencing": "%strong% ক্রমানুসারে করা হচ্ছে", // In English: "Sequencing %strong%" "zipping": undefined, // In English: "Zipping %strong%" "Editor": undefined, // In English: "Editor" "Viewer": undefined, // In English: "Viewer" From f468c172f470f30ddfb37b90322026e4a0f3fe1f Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 21:51:10 +0600 Subject: [PATCH 1208/2119] add translation: zipping --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 0ac7d51e27..729cea599b 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -362,7 +362,7 @@ const bn = { "writing": "%strong% লিখছে", // In English: "Writing %strong%" "unzipping": "%strong% আনজিপিং হচ্ছে", // In English: "Unzipping %strong%" "sequencing": "%strong% ক্রমানুসারে করা হচ্ছে", // In English: "Sequencing %strong%" - "zipping": undefined, // In English: "Zipping %strong%" + "zipping": "%strong% জিপ করা হচ্ছে", // In English: "Zipping %strong%" "Editor": undefined, // In English: "Editor" "Viewer": undefined, // In English: "Viewer" "People with access": undefined, // In English: "People with access" From 6ac6870b9a969d66c61e959a503ac5c6a75901c9 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 21:51:29 +0600 Subject: [PATCH 1209/2119] add translation: Editor --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 729cea599b..cd9eb2402d 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -363,7 +363,7 @@ const bn = { "unzipping": "%strong% আনজিপিং হচ্ছে", // In English: "Unzipping %strong%" "sequencing": "%strong% ক্রমানুসারে করা হচ্ছে", // In English: "Sequencing %strong%" "zipping": "%strong% জিপ করা হচ্ছে", // In English: "Zipping %strong%" - "Editor": undefined, // In English: "Editor" + "Editor": "সম্পাদক", // In English: "Editor" "Viewer": undefined, // In English: "Viewer" "People with access": undefined, // In English: "People with access" "Share With…": undefined, // In English: "Share With…" From efbe0e0f7ee9aa3ece8ce18fa74841bacde5ff71 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 21:51:48 +0600 Subject: [PATCH 1210/2119] add translation: Viewer --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index cd9eb2402d..cf939c581d 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -364,7 +364,7 @@ const bn = { "sequencing": "%strong% ক্রমানুসারে করা হচ্ছে", // In English: "Sequencing %strong%" "zipping": "%strong% জিপ করা হচ্ছে", // In English: "Zipping %strong%" "Editor": "সম্পাদক", // In English: "Editor" - "Viewer": undefined, // In English: "Viewer" + "Viewer": "দর্শক", // In English: "Viewer" "People with access": undefined, // In English: "People with access" "Share With…": undefined, // In English: "Share With…" "Owner": undefined, // In English: "Owner" From e43e646f5434ba3eb7dae9863b1d6765659582e3 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 21:52:20 +0600 Subject: [PATCH 1211/2119] add translation: People with access --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index cf939c581d..fcb346b572 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -365,7 +365,7 @@ const bn = { "zipping": "%strong% জিপ করা হচ্ছে", // In English: "Zipping %strong%" "Editor": "সম্পাদক", // In English: "Editor" "Viewer": "দর্শক", // In English: "Viewer" - "People with access": undefined, // In English: "People with access" + "People with access": "মানুষ যাদের প্রবেশাধিকার আছে", // In English: "People with access" "Share With…": undefined, // In English: "Share With…" "Owner": undefined, // In English: "Owner" "You can't share with yourself.": undefined, // In English: "You can't share with yourself." From 712852b3aa877be7ae0c3c2645d048077051abce Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 21:52:39 +0600 Subject: [PATCH 1212/2119] =?UTF-8?q?add=20translation:=20Share=20With?= =?UTF-8?q?=E2=80=A6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index fcb346b572..e7734eb7fb 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -366,7 +366,7 @@ const bn = { "Editor": "সম্পাদক", // In English: "Editor" "Viewer": "দর্শক", // In English: "Viewer" "People with access": "মানুষ যাদের প্রবেশাধিকার আছে", // In English: "People with access" - "Share With…": undefined, // In English: "Share With…" + "Share With…": "শেয়ার করুন...", // In English: "Share With…" "Owner": undefined, // In English: "Owner" "You can't share with yourself.": undefined, // In English: "You can't share with yourself." "This user already has access to this item": undefined, // In English: "This user already has access to this item" From 3bd07dfabd2bd57e61f45112b032c4a98d34868b Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 21:52:59 +0600 Subject: [PATCH 1213/2119] add translation: Owner --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index e7734eb7fb..d524998fc6 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -367,7 +367,7 @@ const bn = { "Viewer": "দর্শক", // In English: "Viewer" "People with access": "মানুষ যাদের প্রবেশাধিকার আছে", // In English: "People with access" "Share With…": "শেয়ার করুন...", // In English: "Share With…" - "Owner": undefined, // In English: "Owner" + "Owner": "মালিক", // In English: "Owner" "You can't share with yourself.": undefined, // In English: "You can't share with yourself." "This user already has access to this item": undefined, // In English: "This user already has access to this item" From b76d2922c313853b6ab10b9e115ea62d3ca6b640 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 21:53:25 +0600 Subject: [PATCH 1214/2119] add translation: You can't share with yourself. --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index d524998fc6..8461f7eda0 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -368,7 +368,7 @@ const bn = { "People with access": "মানুষ যাদের প্রবেশাধিকার আছে", // In English: "People with access" "Share With…": "শেয়ার করুন...", // In English: "Share With…" "Owner": "মালিক", // In English: "Owner" - "You can't share with yourself.": undefined, // In English: "You can't share with yourself." + "You can't share with yourself.": "আপনি নিজের সাথে শেয়ার করতে পারবেন না।", // In English: "You can't share with yourself." "This user already has access to this item": undefined, // In English: "This user already has access to this item" }, From ede6ed4a0cea76782c9561c62f5d90e50a41d5d8 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 21:54:25 +0600 Subject: [PATCH 1215/2119] add translation: This user already has access to this item --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 8461f7eda0..8583bc3877 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -369,7 +369,7 @@ const bn = { "Share With…": "শেয়ার করুন...", // In English: "Share With…" "Owner": "মালিক", // In English: "Owner" "You can't share with yourself.": "আপনি নিজের সাথে শেয়ার করতে পারবেন না।", // In English: "You can't share with yourself." - "This user already has access to this item": undefined, // In English: "This user already has access to this item" + "This user already has access to this item": "এই ব্যবহারকারীর ইতিমধ্যেই এই আইটেমে প্রবেশাধিকার আছে।", // In English: "This user already has access to this item" }, }; From 7b15d804df696278947c4ab0e45db5e09096f29c Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 21:57:22 +0600 Subject: [PATCH 1216/2119] update translation: change_desktop_background --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 8583bc3877..091a93b594 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -37,7 +37,7 @@ const bn = { browse: "ব্রাউজ", cancel: "বাতিল করুন", center: "কেন্দ্র", - change_desktop_background: "ডেস্কটপ পৃষ্ঠভূমি পরিবর্তন করুন…", + change_desktop_background: "ডেস্কটপ এর ব্যকগ্রাউন্ড পরিবর্তন করুন…", change_email: "ইমেল পরিবর্তন করুন", change_language: "ভাষা পরিবর্তন করুন", change_password: "পাসওয়ার্ড পরিবর্তন করুন", From 8ade96a54dd5c43f32381adb6df9bbac84008cdc Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 21:57:42 +0600 Subject: [PATCH 1217/2119] update translation: change_email --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 091a93b594..29c3c25a14 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -38,7 +38,7 @@ const bn = { cancel: "বাতিল করুন", center: "কেন্দ্র", change_desktop_background: "ডেস্কটপ এর ব্যকগ্রাউন্ড পরিবর্তন করুন…", - change_email: "ইমেল পরিবর্তন করুন", + change_email: "ইমেইল পরিবর্তন করুন", change_language: "ভাষা পরিবর্তন করুন", change_password: "পাসওয়ার্ড পরিবর্তন করুন", change_ui_colors: "ইউআই রঙ পরিবর্তন করুন", From ea1d46e27d4024118ed7978dd6c68da19edff8a9 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 21:57:59 +0600 Subject: [PATCH 1218/2119] update translation: change_ui_colors --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 29c3c25a14..799ee69030 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -41,7 +41,7 @@ const bn = { change_email: "ইমেইল পরিবর্তন করুন", change_language: "ভাষা পরিবর্তন করুন", change_password: "পাসওয়ার্ড পরিবর্তন করুন", - change_ui_colors: "ইউআই রঙ পরিবর্তন করুন", + change_ui_colors: "ইউআই এর রঙ পরিবর্তন করুন", change_username: "ইউজারনেম পরিবর্তন করুন", close: "বন্ধ করুন", close_all_windows: "সমস্ত উইন্ডো বন্ধ করুন", From 0d753063799d7915332aa22242c42bae5bf90cb4 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 21:58:59 +0600 Subject: [PATCH 1219/2119] update translation: close_all_windows_and_log_out --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 799ee69030..ea8a83c9ab 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -46,7 +46,7 @@ const bn = { close: "বন্ধ করুন", close_all_windows: "সমস্ত উইন্ডো বন্ধ করুন", close_all_windows_confirm: "আপনি কি সমস্ত উইন্ডো বন্ধ করতে চান?", - close_all_windows_and_log_out: "উইন্ডো বন্ধ এবং লগ আউট করুন", + close_all_windows_and_log_out: "সমস্ত উইন্ডো বন্ধ এবং লগ আউট করুন", change_always_open_with: "আপনি কি এই ধরনের ফাইলটি সবসময় এই সাথে খোলার জন্য চান", color: "রঙ", confirm: "অনুমোদন", From c6a01e30601a51bd4a71cf41821fdadf478a80ee Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:00:05 +0600 Subject: [PATCH 1220/2119] update translation: change_always_open_with --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index ea8a83c9ab..157570a81b 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -47,7 +47,7 @@ const bn = { close_all_windows: "সমস্ত উইন্ডো বন্ধ করুন", close_all_windows_confirm: "আপনি কি সমস্ত উইন্ডো বন্ধ করতে চান?", close_all_windows_and_log_out: "সমস্ত উইন্ডো বন্ধ এবং লগ আউট করুন", - change_always_open_with: "আপনি কি এই ধরনের ফাইলটি সবসময় এই সাথে খোলার জন্য চান", + change_always_open_with: "আপনি কি এই ধরনের ফাইলটি সবসময় একটি নির্দিষ্ট এপ্লিকেশনের মাধ্যমে ওপেন করতে চান?", color: "রঙ", confirm: "অনুমোদন", confirm_2fa_setup: "আমি আমার অথেন্টিকেশন অ্যাপ্লিকেশনে কোডটি যোগ করেছি", From d9d5c09f158675df95a38d6eaa72cea9f3d26ef3 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:01:14 +0600 Subject: [PATCH 1221/2119] update translation: confirm --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 157570a81b..0be6942c8d 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -49,7 +49,7 @@ const bn = { close_all_windows_and_log_out: "সমস্ত উইন্ডো বন্ধ এবং লগ আউট করুন", change_always_open_with: "আপনি কি এই ধরনের ফাইলটি সবসময় একটি নির্দিষ্ট এপ্লিকেশনের মাধ্যমে ওপেন করতে চান?", color: "রঙ", - confirm: "অনুমোদন", + confirm: "নিশ্চিতকরণ", confirm_2fa_setup: "আমি আমার অথেন্টিকেশন অ্যাপ্লিকেশনে কোডটি যোগ করেছি", confirm_2fa_recovery: "আমি আমার পুনরুদ্ধার কোডগুলি একটি নিরাপদ স্থানে সংরক্ষণ করেছি", confirm_account_for_free_referral_storage_c2a: "একটি অ্যাকাউন্ট তৈরি করুন এবং আপনার ইমেল ঠিকানা নিশ্চিত করুন যাতে ফ্রি 1 জিবি স্টোরেজ পান। আপনার বন্ধুও 1 জিবি ফ্রি স্টোরেজ পাবেন।", From 3c31791fe6c573213bb4d825404018e4bcfbd465 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:01:58 +0600 Subject: [PATCH 1222/2119] update translation: confirm --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 0be6942c8d..523757d371 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -50,7 +50,7 @@ const bn = { change_always_open_with: "আপনি কি এই ধরনের ফাইলটি সবসময় একটি নির্দিষ্ট এপ্লিকেশনের মাধ্যমে ওপেন করতে চান?", color: "রঙ", confirm: "নিশ্চিতকরণ", - confirm_2fa_setup: "আমি আমার অথেন্টিকেশন অ্যাপ্লিকেশনে কোডটি যোগ করেছি", + confirm_2fa_setup: "২ ফ্যাক্টর অথেনটিকেশন নিশ্চিত করুন", confirm_2fa_recovery: "আমি আমার পুনরুদ্ধার কোডগুলি একটি নিরাপদ স্থানে সংরক্ষণ করেছি", confirm_account_for_free_referral_storage_c2a: "একটি অ্যাকাউন্ট তৈরি করুন এবং আপনার ইমেল ঠিকানা নিশ্চিত করুন যাতে ফ্রি 1 জিবি স্টোরেজ পান। আপনার বন্ধুও 1 জিবি ফ্রি স্টোরেজ পাবেন।", confirm_code_generic_incorrect: "ভুল কোড।", From 41ec3a969896c3bdbbcc28dfca291f584672a949 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:02:34 +0600 Subject: [PATCH 1223/2119] update translation: confirm_2fa_recovery --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 523757d371..48e6effb3d 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -51,7 +51,7 @@ const bn = { color: "রঙ", confirm: "নিশ্চিতকরণ", confirm_2fa_setup: "২ ফ্যাক্টর অথেনটিকেশন নিশ্চিত করুন", - confirm_2fa_recovery: "আমি আমার পুনরুদ্ধার কোডগুলি একটি নিরাপদ স্থানে সংরক্ষণ করেছি", + confirm_2fa_recovery: "২ ফ্যাক্টর অথেনটিকেশন এর রিকোভারি কী গুলো নিশ্চিত করুন", confirm_account_for_free_referral_storage_c2a: "একটি অ্যাকাউন্ট তৈরি করুন এবং আপনার ইমেল ঠিকানা নিশ্চিত করুন যাতে ফ্রি 1 জিবি স্টোরেজ পান। আপনার বন্ধুও 1 জিবি ফ্রি স্টোরেজ পাবেন।", confirm_code_generic_incorrect: "ভুল কোড।", confirm_code_generic_too_many_requests: "অনেক অনুরোধ। দয়া করে কয়েক মিনিট অপেক্ষা করুন।", From 3c07c3093345db0537828a0d2436ed666cc183c0 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:03:17 +0600 Subject: [PATCH 1224/2119] update translation: confirmation for referral confirm_account_for_free_referral_storage_c2a --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 48e6effb3d..56fb4410ec 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -52,7 +52,7 @@ const bn = { confirm: "নিশ্চিতকরণ", confirm_2fa_setup: "২ ফ্যাক্টর অথেনটিকেশন নিশ্চিত করুন", confirm_2fa_recovery: "২ ফ্যাক্টর অথেনটিকেশন এর রিকোভারি কী গুলো নিশ্চিত করুন", - confirm_account_for_free_referral_storage_c2a: "একটি অ্যাকাউন্ট তৈরি করুন এবং আপনার ইমেল ঠিকানা নিশ্চিত করুন যাতে ফ্রি 1 জিবি স্টোরেজ পান। আপনার বন্ধুও 1 জিবি ফ্রি স্টোরেজ পাবেন।", + confirm_account_for_free_referral_storage_c2a: "একটি অ্যাকাউন্ট তৈরি করুন এবং আপনার ইমেল ঠিকানা নিশ্চিত করুন যাতে ফ্রি ১ জিবি স্টোরেজ পান। আপনার বন্ধুও ১ জিবি ফ্রি স্টোরেজ পাবেন।", confirm_code_generic_incorrect: "ভুল কোড।", confirm_code_generic_too_many_requests: "অনেক অনুরোধ। দয়া করে কয়েক মিনিট অপেক্ষা করুন।", confirm_code_generic_submit: "কোড জমা দিন", From 3114eb2dd5b81cb6e3e17ae5d2ec7df0f2bd3569 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:04:12 +0600 Subject: [PATCH 1225/2119] update translation: confirming too many request confirm_code_generic_too_many_requests --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 56fb4410ec..7f458b3439 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -54,7 +54,7 @@ const bn = { confirm_2fa_recovery: "২ ফ্যাক্টর অথেনটিকেশন এর রিকোভারি কী গুলো নিশ্চিত করুন", confirm_account_for_free_referral_storage_c2a: "একটি অ্যাকাউন্ট তৈরি করুন এবং আপনার ইমেল ঠিকানা নিশ্চিত করুন যাতে ফ্রি ১ জিবি স্টোরেজ পান। আপনার বন্ধুও ১ জিবি ফ্রি স্টোরেজ পাবেন।", confirm_code_generic_incorrect: "ভুল কোড।", - confirm_code_generic_too_many_requests: "অনেক অনুরোধ। দয়া করে কয়েক মিনিট অপেক্ষা করুন।", + confirm_code_generic_too_many_requests: "কোড জেনারেশনের রিকোয়েস্ট অনেকবার এসেছে। দয়া করে কয়েক মিনিট অপেক্ষা করুন।", confirm_code_generic_submit: "কোড জমা দিন", confirm_code_generic_try_again: "আবার চেষ্টা করুন", confirm_code_generic_title: "অনুমোদন কোড প্রবেশ করুন", From e5229f4c7e515f840e91b049224cdf8c3d8db171 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:04:32 +0600 Subject: [PATCH 1226/2119] update translation: confirm_code_2fa_instruction --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 7f458b3439..9620c1a3e8 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -58,7 +58,7 @@ const bn = { confirm_code_generic_submit: "কোড জমা দিন", confirm_code_generic_try_again: "আবার চেষ্টা করুন", confirm_code_generic_title: "অনুমোদন কোড প্রবেশ করুন", - confirm_code_2fa_instruction: "আপনার অথেন্টিকেশন অ্যাপ্লিকেশন থেকে 6-ডিজিট কোডটি প্রবেশ করুন।", + confirm_code_2fa_instruction: "আপনার অথেন্টিকেশন অ্যাপ্লিকেশন থেকে ৬-ডিজিট কোডটি প্রবেশ করুন।", confirm_code_2fa_submit_btn: "জমা দিন", confirm_code_2fa_title: "2FA কোড প্রবেশ করুন", confirm_delete_multiple_items: "আপনি কি নিশ্চিত যে আপনি এই আইটেমগুলি স্থায়ীভাবে মুছতে চান?", From 4555a21fa1f2fca5e8309bc2e184600348ab4266 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:04:54 +0600 Subject: [PATCH 1227/2119] update translation: confirm_code_2fa_instruction --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 9620c1a3e8..337f9c229c 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -61,7 +61,7 @@ const bn = { confirm_code_2fa_instruction: "আপনার অথেন্টিকেশন অ্যাপ্লিকেশন থেকে ৬-ডিজিট কোডটি প্রবেশ করুন।", confirm_code_2fa_submit_btn: "জমা দিন", confirm_code_2fa_title: "2FA কোড প্রবেশ করুন", - confirm_delete_multiple_items: "আপনি কি নিশ্চিত যে আপনি এই আইটেমগুলি স্থায়ীভাবে মুছতে চান?", + confirm_delete_multiple_items: "আপনি কি নিশ্চিত যে আপনি এই আইটেমগুলি স্থায়ীভাবে ডিলিট করে ফেলতে চান?", confirm_delete_single_item: "আপনি কি এই আইটেমটি স্থায়ীভাবে মুছতে চান?", confirm_open_apps_log_out: "আপনার খোলা অ্যাপ আছে। আপনি কি নিশ্চিত যে আপনি লগ আউট করতে চান?", confirm_new_password: "নতুন পাসওয়ার্ড নিশ্চিত করুন", From 127a241b84eeb7ff195c4eb6866e79e1aca70699 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:05:30 +0600 Subject: [PATCH 1228/2119] update translation: confirm_delete_user --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 337f9c229c..a5660fda6d 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -65,7 +65,7 @@ const bn = { confirm_delete_single_item: "আপনি কি এই আইটেমটি স্থায়ীভাবে মুছতে চান?", confirm_open_apps_log_out: "আপনার খোলা অ্যাপ আছে। আপনি কি নিশ্চিত যে আপনি লগ আউট করতে চান?", confirm_new_password: "নতুন পাসওয়ার্ড নিশ্চিত করুন", - confirm_delete_user: "আপনি কি নিশ্চিত যে আপনি আপনার অ্যাকাউন্টটি মুছতে চান? সমস্ত আপনার ফাইল এবং ডেটা স্থায়ীভাবে মুছে ফেলা হবে। এই ক্রিয়াটি ফিরে পাওয়া যাবে না।", + confirm_delete_user: "আপনি কি নিশ্চিত যে আপনি আপনার অ্যাকাউন্টটি মুছতে চান? আপনার সমস্ত ফাইল এবং ডেটা স্থায়ীভাবে মুছে ফেলা হবে। এই প্রক্রিয়া শেষে আগের ডেটা আর ফিরে পাওয়া যাবে না।", confirm_delete_user_title: "অ্যাকাউন্ট মুছে ফেলুন?", confirm_session_revoke: "আপনি কি নিশ্চিত যে আপনি এই সেশনটি প্রত্যাহার করতে চান?", confirm_your_email_address: "আপনার ইমেল ঠিকানা নিশ্চিত করুন", From 20c49b6a05ac44cb4c08e25c2766c4d036c8b84c Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:06:14 +0600 Subject: [PATCH 1229/2119] update translation: clock_visible_auto --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index a5660fda6d..a01d04c89f 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -87,7 +87,7 @@ const bn = { clock: "ঘড়ি", clock_visible_hide: "লুকান - সর্বদা লুকিয়ে রাখা", clock_visible_show: "দেখান - সর্বদা দৃশ্যমান", - clock_visible_auto: "অটো - ডিফল্ট, মুখ্যম্বর মোডে শুধুমাত্র দৃশ্যমান।", + clock_visible_auto: "অটো - ডিফল্ট, অটো মোডে শুধুমাত্র দৃশ্যমান।", close_all: "সমস্ত বন্ধ করুন", created: "তৈরি করা হয়েছে", date_modified: "তারিখ পরিবর্তন", From 6bef43468a206ebd380f9973b2ab1c94746c2cfb Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:06:34 +0600 Subject: [PATCH 1230/2119] update translation: close_all --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index a01d04c89f..1f67165554 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -88,7 +88,7 @@ const bn = { clock_visible_hide: "লুকান - সর্বদা লুকিয়ে রাখা", clock_visible_show: "দেখান - সর্বদা দৃশ্যমান", clock_visible_auto: "অটো - ডিফল্ট, অটো মোডে শুধুমাত্র দৃশ্যমান।", - close_all: "সমস্ত বন্ধ করুন", + close_all: "সবকিছু বন্ধ করুন", created: "তৈরি করা হয়েছে", date_modified: "তারিখ পরিবর্তন", default: "ডিফল্ট", From c2da4527b75d42a40a32ab032b3045b6967af623 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:06:59 +0600 Subject: [PATCH 1231/2119] update translation: date_modified --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 1f67165554..cf4293ba23 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -90,7 +90,7 @@ const bn = { clock_visible_auto: "অটো - ডিফল্ট, অটো মোডে শুধুমাত্র দৃশ্যমান।", close_all: "সবকিছু বন্ধ করুন", created: "তৈরি করা হয়েছে", - date_modified: "তারিখ পরিবর্তন", + date_modified: "তারিখ পরিবর্তন করা হয়েছে", default: "ডিফল্ট", delete: "মুছে ফেলুন", delete_account: "অ্যাকাউন্ট মুছে ফেলুন", From b267547ea75a05d9e1263b57dfec313e94a51494 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:07:23 +0600 Subject: [PATCH 1232/2119] update translation: deploy_as_app --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index cf4293ba23..7d51349be5 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -96,7 +96,7 @@ const bn = { delete_account: "অ্যাকাউন্ট মুছে ফেলুন", delete_permanently: "চিরকালের জন্য মুছুন", deleting_file: "ফাইল মুছে ফেলা হচ্ছে %%", - deploy_as_app: "অ্যাপ্লিকেশন হিসেবে ডিপ্লয়", + deploy_as_app: "অ্যাপ্লিকেশন হিসেবে ডিপ্লয় করা হয়েছে", descending: "অবতলভাবে", desktop: "ডেস্কটপ", desktop_background_fit: "ফিট", From a7f032a3259d332543148fac549863d35d68ff75 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:07:52 +0600 Subject: [PATCH 1233/2119] update translation: disable_2fa --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 7d51349be5..50e9a55f99 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -102,7 +102,7 @@ const bn = { desktop_background_fit: "ফিট", developers: "ডেভেলপারগণ", dir_published_as_website: `%strong% প্রকাশিত হয়েছে:`, - disable_2fa: "2FA অক্ষম করুন", + disable_2fa: "2FA বন্ধ করুন", disable_2fa_confirm: "আপনি কি নিশ্চিত যে আপনি 2FA অক্ষম করতে চান?", disable_2fa_instructions: "2FA অক্ষম করতে আপনার পাসওয়ার্ড লিখুন।", disassociate_dir: "ডিরেক্টরি আনসোসিএট করুন", From 451b23eb4c8522bff59b99d3c380ed1d1ef77e90 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:08:06 +0600 Subject: [PATCH 1234/2119] update translation: disable_2fa_confirm --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 50e9a55f99..ed4f9e1544 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -103,7 +103,7 @@ const bn = { developers: "ডেভেলপারগণ", dir_published_as_website: `%strong% প্রকাশিত হয়েছে:`, disable_2fa: "2FA বন্ধ করুন", - disable_2fa_confirm: "আপনি কি নিশ্চিত যে আপনি 2FA অক্ষম করতে চান?", + disable_2fa_confirm: "আপনি কি নিশ্চিত যে আপনি 2FA বন্ধ করতে চান?", disable_2fa_instructions: "2FA অক্ষম করতে আপনার পাসওয়ার্ড লিখুন।", disassociate_dir: "ডিরেক্টরি আনসোসিএট করুন", documents: "ডকুমেন্টস", From 3bbacdeaea2e00da277d6cf405c00bcf8fabf396 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:08:21 +0600 Subject: [PATCH 1235/2119] update translation: disable_2fa_instructions --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index ed4f9e1544..334603d122 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -104,7 +104,7 @@ const bn = { dir_published_as_website: `%strong% প্রকাশিত হয়েছে:`, disable_2fa: "2FA বন্ধ করুন", disable_2fa_confirm: "আপনি কি নিশ্চিত যে আপনি 2FA বন্ধ করতে চান?", - disable_2fa_instructions: "2FA অক্ষম করতে আপনার পাসওয়ার্ড লিখুন।", + disable_2fa_instructions: "2FA বন্ধ করতে আপনার পাসওয়ার্ড লিখুন।", disassociate_dir: "ডিরেক্টরি আনসোসিএট করুন", documents: "ডকুমেন্টস", dont_allow: "অনুমতি দিন না", From 67cc5b03ad9abf4cb6bc8c3332a59f2331137931 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:08:45 +0600 Subject: [PATCH 1236/2119] update translation: dont_allow --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 334603d122..13a8dd9393 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -107,7 +107,7 @@ const bn = { disable_2fa_instructions: "2FA বন্ধ করতে আপনার পাসওয়ার্ড লিখুন।", disassociate_dir: "ডিরেক্টরি আনসোসিএট করুন", documents: "ডকুমেন্টস", - dont_allow: "অনুমতি দিন না", + dont_allow: "অনুমতি দিবেন না", download: "ডাউনলোড", download_file: "ফাইল ডাউনলোড করুন", downloading: "ডাউনলোড হচ্ছে", From faf5a48ee1c06cc69270a2f1f3a959d70f504027 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:09:11 +0600 Subject: [PATCH 1237/2119] update translation: email_change_confirmation_sent --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 13a8dd9393..b91f4e6c6d 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -112,7 +112,7 @@ const bn = { download_file: "ফাইল ডাউনলোড করুন", downloading: "ডাউনলোড হচ্ছে", email: "ইমেল", - email_change_confirmation_sent: "নতুন ইমেল ঠিকানা নিশ্চিতকরণের জন্য একটি নিশ্চিতকরণ ইমেল পাঠানো হয়েছে। আপনার ইনবক্স পরীক্ষা করুন এবং নির্দেশানুযায়ী প্রক্রিয়াটি সম্পন্ন করতে।", + email_change_confirmation_sent: "নতুন ইমেল ঠিকানা নিশ্চিতকরণের জন্য একটি নিশ্চিতকরণ ইমেল পাঠানো হয়েছে। আপনার ইনবক্স পরীক্ষা করুন এবং নির্দেশানুযায়ী প্রক্রিয়াটি সম্পন্ন করুন।", email_invalid: "ইমেল অবৈধ।", email_or_username: "ইমেল বা ইউজারনেম", email_required: "ইমেল প্রয়োজন।", From 9e918042b1927165aabac30f6f9647d3aedb0610 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:09:31 +0600 Subject: [PATCH 1238/2119] update translation: email_invalid --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index b91f4e6c6d..decedc42ac 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -113,7 +113,7 @@ const bn = { downloading: "ডাউনলোড হচ্ছে", email: "ইমেল", email_change_confirmation_sent: "নতুন ইমেল ঠিকানা নিশ্চিতকরণের জন্য একটি নিশ্চিতকরণ ইমেল পাঠানো হয়েছে। আপনার ইনবক্স পরীক্ষা করুন এবং নির্দেশানুযায়ী প্রক্রিয়াটি সম্পন্ন করুন।", - email_invalid: "ইমেল অবৈধ।", + email_invalid: "ইমেলটি বৈধ নয়।", email_or_username: "ইমেল বা ইউজারনেম", email_required: "ইমেল প্রয়োজন।", empty_trash: "খালি ট্র্যাশ", From 9314b949ff544b9d9d919dc7da6213f5392f5395 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:11:04 +0600 Subject: [PATCH 1239/2119] update translation: feedback_sent_confirmation --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index decedc42ac..bf135c7b41 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -131,7 +131,7 @@ const bn = { favorites: "প্রিয়", feedback: "প্রতিক্রিয়া", feedback_c2a: "নীচের ফর্মটি ব্যবহার করে আপনার মতামত, মন্তব্য এবং বাগ রিপোর্ট প্রেরণ করুন।", - feedback_sent_confirmation: "আমাদের সাথে যোগাযোগ করার জন্য ধন্যবাদ। আপনার একাউন্টে ইমেল সংযোজন থাকলে আমরা যত তাড়াতাড়ি সম্ভব তাদের থেকে ফিরে পাবেন।", + feedback_sent_confirmation: "আমাদের সাথে যোগাযোগ করার জন্য ধন্যবাদ। আপনার একাউন্টে ইমেল সংযোজন থাকলে আমরা যত তাড়াতাড়ি সম্ভব আপনার কাছে ফিরে আসতে পারবো।", fit: "ফিট", folder: "ফোল্ডার", force_quit: "প্রবল বন্ধ", From b8adacabc1c6af44ce466915d2d2c20b44a2c18f Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:11:44 +0600 Subject: [PATCH 1240/2119] update translation: force_quit --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index bf135c7b41..a7c7a34957 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -134,7 +134,7 @@ const bn = { feedback_sent_confirmation: "আমাদের সাথে যোগাযোগ করার জন্য ধন্যবাদ। আপনার একাউন্টে ইমেল সংযোজন থাকলে আমরা যত তাড়াতাড়ি সম্ভব আপনার কাছে ফিরে আসতে পারবো।", fit: "ফিট", folder: "ফোল্ডার", - force_quit: "প্রবল বন্ধ", + force_quit: "জোর করে বন্ধ করা", forgot_pass_c2a: "পাসওয়ার্ড ভুলে গেছেন?", from: "থেকে", general: "সাধারণ", From f6a4a7864a0bccb8d44d2350f4d5009b43a6a050 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:12:23 +0600 Subject: [PATCH 1241/2119] update translation: hide_all_windows --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index a7c7a34957..e7dd532208 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -140,7 +140,7 @@ const bn = { general: "সাধারণ", get_a_copy_of_on_puter: `পিউটার ডটকমে '%%' এর একটি অনুলিপি পান!`, get_copy_link: "কপি লিংক নিন", - hide_all_windows: "সমস্ত উইন্ডো লুকান", + hide_all_windows: "সমস্ত উইন্ডো ঢেকে ফেলুন", home: "হোম", html_document: "এইচটিএমএল ডকুমেন্ট", hue: "হিউ", From c6a734896da70910ac9762340317e0a45b5732ec Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:12:43 +0600 Subject: [PATCH 1242/2119] update translation: items_in_trash_cannot_be_renamed --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index e7dd532208..48e238a3e3 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -148,7 +148,7 @@ const bn = { incorrect_password: "ভুল পাসওয়ার্ড", invite_link: "আমন্ত্রণ লিংক", item: "আইটেম", - items_in_trash_cannot_be_renamed: `এই আইটেমটি নাম পরিবর্তন করা যাবে না কারণ এটি ট্র্যাশে রয়েছে। এই আইটেমটির নাম পরিবর্তন করতে, প্রথমে এটি ট্র্যাশ থেকে তুলে নিন।`, + items_in_trash_cannot_be_renamed: `এই আইটেমটির নাম পরিবর্তন করা যাবে না কারণ এটি ট্র্যাশে রয়েছে। এই আইটেমটির নাম পরিবর্তন করতে, প্রথমে এটি ট্র্যাশ থেকে তুলে নিন।`, jpeg_image: "জেপিইজি ইমেজ", keep_in_taskbar: "টাস্কবারে রাখুন", language: "ভাষা", From 88efa1c89c6a6f836e14373387c7d7c6c63b512e Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:13:11 +0600 Subject: [PATCH 1243/2119] update translation: lightness --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 48e238a3e3..e51e22c3ae 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -153,7 +153,7 @@ const bn = { keep_in_taskbar: "টাস্কবারে রাখুন", language: "ভাষা", license: "লাইসেন্স", - lightness: "হালকালোত্ব", + lightness: "হালকার মতো", link_copied: "লিংক কপি করা হয়েছে", loading: "লোড হচ্ছে", log_in: "লগ ইন করুন", From af2e1687ca8045a295b51955a8a70b184a17ac59 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:13:57 +0600 Subject: [PATCH 1244/2119] update translation: open_in_new_window --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index e51e22c3ae..089e5fe8e8 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -187,7 +187,7 @@ const bn = { ok: "ঠিক আছে", open: "খোলা", open_in_new_tab: "নতুন ট্যাবে খুলুন", - open_in_new_window: "নতুন উইন্ডোয়ে খুলুন", + open_in_new_window: "নতুন উইন্ডোতে খুলুন", open_with: "দিয়ে খোলুন", original_name: "মৌলিক নাম", original_path: "মূল পথ", From 38fec34d562f07cee4f8d712939d530e1db427e3 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:14:12 +0600 Subject: [PATCH 1245/2119] update translation: open_with --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 089e5fe8e8..7c9309902e 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -188,7 +188,7 @@ const bn = { open: "খোলা", open_in_new_tab: "নতুন ট্যাবে খুলুন", open_in_new_window: "নতুন উইন্ডোতে খুলুন", - open_with: "দিয়ে খোলুন", + open_with: "দিয়ে খুলুন", original_name: "মৌলিক নাম", original_path: "মূল পথ", oss_code_and_content: "ওপেন সোর্স সফটওয়্যার এবং কন্টেন্ট", From 90fa5f184c7d1e1a2dc171c99bdf65488b041c2f Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:14:45 +0600 Subject: [PATCH 1246/2119] update translation: password_recovery_rate_limit --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 7c9309902e..a600de642f 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -194,7 +194,7 @@ const bn = { oss_code_and_content: "ওপেন সোর্স সফটওয়্যার এবং কন্টেন্ট", password: "পাসওয়ার্ড", password_changed: "পাসওয়ার্ড পরিবর্তন করা হয়েছে।", - password_recovery_rate_limit: "আপনি আমাদের রেকভারি সিস্টেমে প্রতি দিনে অধিকতর পাঁচবার ব্যবহার করতে পারবেন না। দয়া করে কয়েক ঘণ্টা অপেক্ষা করুন এবং পুনরায় চেষ্টা করুন।", + password_recovery_rate_limit: "আপনি আমাদের রিকভারি সিস্টেমে প্রতি দিনে অধিকতর পাঁচবার ব্যবহার করতে পারবেন না। দয়া করে কয়েক ঘণ্টা অপেক্ষা করুন এবং পুনরায় চেষ্টা করুন।", password_recovery_sent: "আপনার পাসওয়ার্ড পুনরুদ্ধারের জন্য নির্দেশানুযায়ী একটি ইমেল পাঠানো হয়েছে।", password_requirements: "পাসওয়ার্ড অবশ্যই অবশ্যই ৮ অক্ষরের বৃহত্তর হতে হবে।", password_reset: "পাসওয়ার্ড রিসেট করুন", From 90a2a44c450326507a8773e27e6a62b961a0fa74 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:15:10 +0600 Subject: [PATCH 1247/2119] update translation: password_requirements --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index a600de642f..565c9ceb13 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -196,7 +196,7 @@ const bn = { password_changed: "পাসওয়ার্ড পরিবর্তন করা হয়েছে।", password_recovery_rate_limit: "আপনি আমাদের রিকভারি সিস্টেমে প্রতি দিনে অধিকতর পাঁচবার ব্যবহার করতে পারবেন না। দয়া করে কয়েক ঘণ্টা অপেক্ষা করুন এবং পুনরায় চেষ্টা করুন।", password_recovery_sent: "আপনার পাসওয়ার্ড পুনরুদ্ধারের জন্য নির্দেশানুযায়ী একটি ইমেল পাঠানো হয়েছে।", - password_requirements: "পাসওয়ার্ড অবশ্যই অবশ্যই ৮ অক্ষরের বৃহত্তর হতে হবে।", + password_requirements: "পাসওয়ার্ড অবশ্যই অবশ্যই ৮ অক্ষরের বড় অক্ষর থাকতে হবে।", password_reset: "পাসওয়ার্ড রিসেট করুন", password_reset_confirmation: "পাসওয়ার্ড সেট করতে নীচের ফর্মটি পূরণ করুন।", password_reset_request_expired: "আপনার পাসওয়ার্ড রিসেট রিকোয়েস্টের মেয়াদ শেষ হয়ে গেছে। দয়া করে পুনরায় চেষ্টা করুন।", From 47717f1d41b7d77c36c6d1c4702bff90fab5b424 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:15:33 +0600 Subject: [PATCH 1248/2119] update translation: password_reset_sent --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 565c9ceb13..8e33961629 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -200,7 +200,7 @@ const bn = { password_reset: "পাসওয়ার্ড রিসেট করুন", password_reset_confirmation: "পাসওয়ার্ড সেট করতে নীচের ফর্মটি পূরণ করুন।", password_reset_request_expired: "আপনার পাসওয়ার্ড রিসেট রিকোয়েস্টের মেয়াদ শেষ হয়ে গেছে। দয়া করে পুনরায় চেষ্টা করুন।", - password_reset_sent: "পাসওয়ার্ড রিসেট রিকোয়েস্ট সফলভাবে প্রেরিত হয়েছে। আপনার ইনবক্স পরীক্ষা করুন এবং নির্দেশানুযায়ী প্রক্রিয়াটি সম্পন্ন করতে।", + password_reset_sent: "পাসওয়ার্ড রিসেট রিকোয়েস্ট সফলভাবে প্রেরিত হয়েছে। আপনার ইনবক্স পরীক্ষা করুন এবং নির্দেশানুযায়ী প্রক্রিয়াটি সম্পন্ন করুন।", password_update_success: "পাসওয়ার্ড সফলভাবে আপডেট হয়েছে!", passwords_do_not_match: "পাসওয়ার্ড মিলে না", paste: "পেস্ট", From fd7e762850323ce55cad5151ffbdca307601e72b Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:15:51 +0600 Subject: [PATCH 1249/2119] update translation: passwords_do_not_match --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 8e33961629..d0dc2ec28b 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -202,7 +202,7 @@ const bn = { password_reset_request_expired: "আপনার পাসওয়ার্ড রিসেট রিকোয়েস্টের মেয়াদ শেষ হয়ে গেছে। দয়া করে পুনরায় চেষ্টা করুন।", password_reset_sent: "পাসওয়ার্ড রিসেট রিকোয়েস্ট সফলভাবে প্রেরিত হয়েছে। আপনার ইনবক্স পরীক্ষা করুন এবং নির্দেশানুযায়ী প্রক্রিয়াটি সম্পন্ন করুন।", password_update_success: "পাসওয়ার্ড সফলভাবে আপডেট হয়েছে!", - passwords_do_not_match: "পাসওয়ার্ড মিলে না", + passwords_do_not_match: "পাসওয়ার্ড মিলছে না", paste: "পেস্ট", paste_into_folder: "ফোল্ডারে পেস্ট করুন", path: "পথ", From 26250800de595ddeb1ae772edfae9ffc02f4f233 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:16:08 +0600 Subject: [PATCH 1250/2119] update translation: personalization --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index d0dc2ec28b..bc05b7a2dd 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -206,7 +206,7 @@ const bn = { paste: "পেস্ট", paste_into_folder: "ফোল্ডারে পেস্ট করুন", path: "পথ", - personalization: "ব্যক্তিগতীকরণ", + personalization: "ব্যক্তিগতকরণ", pick_name_for_website: "আপনার ওয়েবসাইটের জন্য নাম নির্বাচন করুন:", picture: "ছবি", pictures: "চিত্র", From eb19ec0c48cae8bcf506024cd6e9ab09d18e97eb Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:17:11 +0600 Subject: [PATCH 1251/2119] update translation: refer_friends_c2a --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index bc05b7a2dd..efaa9ed3b8 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -232,7 +232,7 @@ const bn = { recent: "সাম্প্রতিক", recommended: "অনুমোদিত", recover_password: "পাসওয়ার্ড পুনরুদ্ধার করুন", - refer_friends_c2a: "Puter তে অ্যাকাউন্ট তৈরি এবং নিশ্চিতকরণ করে একটি বন্ধুর প্রতি 1 জিবি পান। আপনার বন্ধুও 1 জিবি পাবে!", + refer_friends_c2a: "Puter তে অ্যাকাউন্ট তৈরি এবং নিশ্চিতকরণ করে একটি বন্ধুকে রেফার করার জন্য প্রতি রেফারে ১ জিবি পান। আপনার বন্ধুও ১ জিবি পাবে!", refer_friends_social_media_c2a: `Puter.com এ 1 GB বিনামূল্যের সংরক্ষণ পান!`, refresh: "রিফ্রেশ", release_address_confirmation: `আপনি কি নিশ্চিত যে আপনি এই ঠিকানা রিলিজ করতে চান?`, From b89a5ad52312d5efbc00e21d274293aeea9b2ff3 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:17:27 +0600 Subject: [PATCH 1252/2119] update translation: refer_friends_social_media_c2a --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index efaa9ed3b8..ff1582d35c 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -233,7 +233,7 @@ const bn = { recommended: "অনুমোদিত", recover_password: "পাসওয়ার্ড পুনরুদ্ধার করুন", refer_friends_c2a: "Puter তে অ্যাকাউন্ট তৈরি এবং নিশ্চিতকরণ করে একটি বন্ধুকে রেফার করার জন্য প্রতি রেফারে ১ জিবি পান। আপনার বন্ধুও ১ জিবি পাবে!", - refer_friends_social_media_c2a: `Puter.com এ 1 GB বিনামূল্যের সংরক্ষণ পান!`, + refer_friends_social_media_c2a: `Puter.com এ ১ জিবি বিনামূল্যের সংরক্ষণ পান!`, refresh: "রিফ্রেশ", release_address_confirmation: `আপনি কি নিশ্চিত যে আপনি এই ঠিকানা রিলিজ করতে চান?`, remove_from_taskbar: "টাস্কবার থেকে সরান", From 7a8da04634a230ee239b10a0dd5ddbe49e7be553 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:17:50 +0600 Subject: [PATCH 1253/2119] update translation: replace_all --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index ff1582d35c..d020441f76 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -240,7 +240,7 @@ const bn = { rename: "পুনঃনামকরণ", repeat: "পুনরাবৃত্তি", replace: "প্রতিস্থাপন", - replace_all: "সমস্ত প্রতিস্থাপন", + replace_all: "সমস্তকিছু প্রতিস্থাপন করে ফেলুন", resend_confirmation_code: "পুনরায় নিশ্চিতকরণ কোড প্রেরণ করুন", reset_colors: "রঙ পুনঃনির্ধারণ করুন", restart_puter_confirm: "আপনি কি নিশ্চিত যে Puter পুনরায় চালু করতে চান?", From fdd0c67b1d570a4f1d8630daf9a26ad25328311f Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:18:28 +0600 Subject: [PATCH 1254/2119] update translation: reset_colors --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index d020441f76..20cd6ad90a 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -242,7 +242,7 @@ const bn = { replace: "প্রতিস্থাপন", replace_all: "সমস্তকিছু প্রতিস্থাপন করে ফেলুন", resend_confirmation_code: "পুনরায় নিশ্চিতকরণ কোড প্রেরণ করুন", - reset_colors: "রঙ পুনঃনির্ধারণ করুন", + reset_colors: "রঙ আগেরমত করুন", restart_puter_confirm: "আপনি কি নিশ্চিত যে Puter পুনরায় চালু করতে চান?", restore: "পুনরুদ্ধার", save: "সংরক্ষণ করুন", From 9fd977761cff4390808caad60195c56046852808 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:19:15 +0600 Subject: [PATCH 1255/2119] update translation: skip --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 20cd6ad90a..b97a264d4a 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -277,7 +277,7 @@ const bn = { sign_up: "নিবন্ধন করুন", signing_in: "সাইন ইন হচ্ছে...", size: "আকার", - skip: "পার যান", + skip: "এটি বাদ দিন", something_went_wrong: "কিছু সমস্যা হয়েছে।", sort_by: "অনুযায়ী সাজান", start: "শুরু", From 16e6307bca16f7978f9d200e4462210bf51c5589 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:20:11 +0600 Subject: [PATCH 1256/2119] update translation: two_factor_disabled --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index b97a264d4a..45dc3aa40e 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -295,7 +295,7 @@ const bn = { transparency: "স্বচ্ছতা", trash: "আবর্জনা", two_factor: "দুটি ফ্যাক্টর প্রমাণীকরণ", - two_factor_disabled: "2FA অক্ষম", + two_factor_disabled: "2FA বন্ধ করা হয়েছে", two_factor_enabled: "2FA সক্ষম", type: "ধরণ", type_confirm_to_delete_account: "অ্যাকাউন্ট মোছার জন্য 'অনুমোদন' টাইপ করুন।", From d2eae202234192910152b20418956bc5dd3162af Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:20:26 +0600 Subject: [PATCH 1257/2119] update translation:two_factor_enabled --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 45dc3aa40e..f75fabf0ab 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -296,7 +296,7 @@ const bn = { trash: "আবর্জনা", two_factor: "দুটি ফ্যাক্টর প্রমাণীকরণ", two_factor_disabled: "2FA বন্ধ করা হয়েছে", - two_factor_enabled: "2FA সক্ষম", + two_factor_enabled: "2FA চালু করা হয়েছে", type: "ধরণ", type_confirm_to_delete_account: "অ্যাকাউন্ট মোছার জন্য 'অনুমোদন' টাইপ করুন।", ui_colors: "ইউআই রঙ", From 43a2afc843b652ba1e14d9401f97a34e7e913604 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:20:49 +0600 Subject: [PATCH 1258/2119] update translation: undo --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index f75fabf0ab..9316ef83e1 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -302,7 +302,7 @@ const bn = { ui_colors: "ইউআই রঙ", ui_manage_sessions: "সেশন ম্যানেজার", ui_revoke: "প্রত্যাহার করুন", - undo: "আনডো", + undo: "আনডু করুন", unlimited: "অসীম", unzip: "আনজিপ", upload: "আপলোড", From f85adbe7ec4206c62e06c530da11d2cc4ce0435a Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:21:46 +0600 Subject: [PATCH 1259/2119] update translation: setup2fa_1_instructions --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 9316ef83e1..539acb993c 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -323,7 +323,7 @@ const bn = { // === 2FA Setup === setup2fa_1_step_heading: "আপনার প্রামাণিকতা অ্যাপ খুলুন", setup2fa_1_instructions: ` - আপনি যেকোনো প্রামাণিকতা অ্যাপ ব্যবহার করতে পারেন যা Time-based One-Time Password (TOTP) প্রোটোকল সমর্থন করে। + আপনি যেকোনো অথেনটিকেশন অ্যাপ ব্যবহার করতে পারেন যা Time-based One-Time Password (TOTP) প্রোটোকল সমর্থন করে। অনেক বিকল্প রয়েছে, তবে যদি আপনি নিশ্চিত না হন Authy একটি ভালো পছন্দ Android এবং iOS এর জন্য। From af7be2c917df4961b37c1987e2e58beed05aec08 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:21:59 +0600 Subject: [PATCH 1260/2119] update translation: setup2fa_3_step_heading --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 539acb993c..3fedc66b86 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -329,7 +329,7 @@ const bn = { একটি ভালো পছন্দ Android এবং iOS এর জন্য। `, setup2fa_2_step_heading: "QR কোড স্ক্যান করুন", - setup2fa_3_step_heading: "6-টি অংকের কোড লিখুন", + setup2fa_3_step_heading: "৬-টি অংকের কোড লিখুন", setup2fa_4_step_heading: "আপনার পুনরুদ্ধার কোড কপি করুন", setup2fa_4_instructions: ` এই পুনরুদ্ধার কোডগুলি আপনার অ্যাকাউন্টে অ্যাক্সেস পাওয়ার একমাত্র উপায় যদি আপনি আপনার ফোন হারান বা আপনার প্রামাণিকতা অ্যাপ ব্যবহার করতে না পারেন। From 98e2331a563435dfdd56084ff85aa50c7caea4a2 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:22:33 +0600 Subject: [PATCH 1261/2119] update translation: setup2fa_4_instructions --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 3fedc66b86..c5db2ad873 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -332,7 +332,7 @@ const bn = { setup2fa_3_step_heading: "৬-টি অংকের কোড লিখুন", setup2fa_4_step_heading: "আপনার পুনরুদ্ধার কোড কপি করুন", setup2fa_4_instructions: ` - এই পুনরুদ্ধার কোডগুলি আপনার অ্যাকাউন্টে অ্যাক্সেস পাওয়ার একমাত্র উপায় যদি আপনি আপনার ফোন হারান বা আপনার প্রামাণিকতা অ্যাপ ব্যবহার করতে না পারেন। + এই পুনরুদ্ধার কোডগুলি আপনার অ্যাকাউন্টে অ্যাক্সেস পাওয়ার একমাত্র উপায়। যদি আপনি আপনার ফোন হারিয়ে ফেলেন বা আপনার প্রামাণিকতা অ্যাপ ব্যবহার করতে না পারেন, তবে নিশ্চিত করুন যে আপনি তাদের একটি নিরাপদ জায়গায় সংরক্ষণ করেছেন। `, setup2fa_5_step_heading: "2FA সেটআপ নিশ্চিত করুন", From 0d1e676ce1a855e8843cf274e1ce45c596b74e81 Mon Sep 17 00:00:00 2001 From: FahimFBA Date: Wed, 20 Nov 2024 22:22:53 +0600 Subject: [PATCH 1262/2119] update translation: login2fa_otp_instructions --- src/gui/src/i18n/translations/bn.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index c5db2ad873..c682c4bcc7 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -342,7 +342,7 @@ const bn = { // === 2FA Login === login2fa_otp_title: "2FA কোড লিখুন", - login2fa_otp_instructions: "আপনার প্রামাণিকতা অ্যাপ থেকে 6-টি অংকের কোড লিখুন।", + login2fa_otp_instructions: "আপনার প্রামাণিকতা অ্যাপ থেকে ৬-টি অংকের কোড লিখুন।", login2fa_recovery_title: "একটি পুনরুদ্ধার কোড লিখুন", login2fa_recovery_instructions: "আপনার অ্যাকাউন্টে অ্যাক্সেস পাওয়ার জন্য আপনার পুনরুদ্ধার কোডগুলির মধ্য থেকে একটি লিখুন।", login2fa_use_recovery_code: "একটি পুনরুদ্ধার কোড ব্যবহার করুন", From d43e79243a75347f67b79e5d5b1514de34b04dee Mon Sep 17 00:00:00 2001 From: motabbirhossain Date: Wed, 20 Nov 2024 22:46:17 +0600 Subject: [PATCH 1263/2119] Added missing translations for Bengali localization (#842) --- src/gui/src/i18n/translations/bn.js | 41 ++++++++++++++++------------- 1 file changed, 22 insertions(+), 19 deletions(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 6f18fd559a..361abe48c6 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -349,28 +349,31 @@ const bn = { login2fa_recovery_back: "পিছনে", login2fa_recovery_placeholder: "XXXXXXXX", + + // *********************************** - // Missing translations + // Translations Bangla // *********************************** - "change": undefined, // In English: "Change" - "clock_visibility": undefined, // In English: "Clock Visibility" - "password_recovery_token_invalid": undefined, // In English: "This password recovery token is no longer valid." - "password_recovery_unknown_error": undefined, // In English: "An unknown error occurred. Please try again later." - "password_required": undefined, // In English: "Password is required." - "password_strength_error": undefined, // In English: "Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, one number, and one special character." - "reading": undefined, // In English: "Reading %strong%" - "writing": undefined, // In English: "Writing %strong%" - "unzipping": undefined, // In English: "Unzipping %strong%" - "sequencing": undefined, // In English: "Sequencing %strong%" - "zipping": undefined, // In English: "Zipping %strong%" - "Editor": undefined, // In English: "Editor" - "Viewer": undefined, // In English: "Viewer" - "People with access": undefined, // In English: "People with access" - "Share With…": undefined, // In English: "Share With…" - "Owner": undefined, // In English: "Owner" - "You can't share with yourself.": undefined, // In English: "You can't share with yourself." - "This user already has access to this item": undefined, // In English: "This user already has access to this item" + + change: "পরিবর্তন", + clock_visibility: "ঘড়ির দৃশ্যমানতা", + password_recovery_token_invalid: "এই পাসওয়ার্ড পুনরুদ্ধার টোকেন আর বৈধ নয়।", + password_recovery_unknown_error: "একটি অজানা ত্রুটি ঘটেছে। দয়া করে পরে আবার চেষ্টা করুন।", + password_required: "পাসওয়ার্ড প্রয়োজন।", + password_strength_error: "পাসওয়ার্ড কমপক্ষে ৮ অক্ষর দীর্ঘ হতে হবে এবং এতে কমপক্ষে একটি বড় হাতের অক্ষর, একটি ছোট হাতের অক্ষর, একটি সংখ্যা, এবং একটি বিশেষ অক্ষর থাকতে হবে।", + reading: "পড়া হচ্ছে", + writing: "লেখা হচ্ছে", + unzipping: "আনজিপ করা হচ্ছে", + sequencing: "অনুক্রম তৈরি করা হচ্ছে", + zipping: "জিপ করা হচ্ছে", + editor: "সম্পাদক", + Viewer: "দর্শক", + people_with_access: "যাদের অ্যাক্সেস আছে", + share_with:"শেয়ার করুন", + owner: "মালিক", + you_can_not_share_with_yourself: "আপনি নিজের সাথে শেয়ার করতে পারবেন না।", + this_user_already_has_access_to_this_item: "এই ব্যবহারকারীর ইতিমধ্যেই এই আইটেমে অ্যাক্সেস রয়েছে।" }, }; From 4ca1bddbd1cc703fc7a2822a66f53db1f1a77277 Mon Sep 17 00:00:00 2001 From: Kazi Shariful Islam <96835101+kazi331@users.noreply.github.com> Date: Wed, 20 Nov 2024 22:57:27 +0600 Subject: [PATCH 1264/2119] Update bn.js updated with manual translation --- src/gui/src/i18n/translations/bn.js | 36 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 6f18fd559a..cf292842f5 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -352,24 +352,24 @@ const bn = { // *********************************** // Missing translations // *********************************** - "change": undefined, // In English: "Change" - "clock_visibility": undefined, // In English: "Clock Visibility" - "password_recovery_token_invalid": undefined, // In English: "This password recovery token is no longer valid." - "password_recovery_unknown_error": undefined, // In English: "An unknown error occurred. Please try again later." - "password_required": undefined, // In English: "Password is required." - "password_strength_error": undefined, // In English: "Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, one number, and one special character." - "reading": undefined, // In English: "Reading %strong%" - "writing": undefined, // In English: "Writing %strong%" - "unzipping": undefined, // In English: "Unzipping %strong%" - "sequencing": undefined, // In English: "Sequencing %strong%" - "zipping": undefined, // In English: "Zipping %strong%" - "Editor": undefined, // In English: "Editor" - "Viewer": undefined, // In English: "Viewer" - "People with access": undefined, // In English: "People with access" - "Share With…": undefined, // In English: "Share With…" - "Owner": undefined, // In English: "Owner" - "You can't share with yourself.": undefined, // In English: "You can't share with yourself." - "This user already has access to this item": undefined, // In English: "This user already has access to this item" + "change": "পরিবর্তন করুন", + "clock_visibility": "ঘড়ির দৃশ্যমানতা", + "password_recovery_token_invalid": "এই পাসওয়ার্ড পুনরুদ্ধার টোকেনটি আর সঠিক নয়।", + "password_recovery_unknown_error": "একটি অজানা ত্রুটি ঘটেছে। অনুগ্রহ করে পরে আবার চেষ্টা করুন।", + "password_required": "পাসওয়ার্ড প্রয়োজন।", + "password_strength_error": "পাসওয়ার্ড কমপক্ষে ৮ সংখার হতে হবে এবং এতে অন্তত একটি বড় হাতের অক্ষর, একটি ছোট হাতের অক্ষর, একটি সংখ্যা, এবং একটি বিশেষ অক্ষর থাকতে হবে।", + "reading": "পড়া হচ্ছে", + "writing": "লেখা হচ্ছে", + "unzipping": "আনজিপ করা হচ্ছে", + "sequencing": "ক্রমানুসারে সাজানো হচ্ছে", + "zipping": "জিপ করা হচ্ছে", + "Editor": "সম্পাদক", + "Viewer": "দর্শক", + "People with access": "যাদের অ্যাক্সেস আছে", + "Share With…": "শেয়ার করুন…", + "Owner": "মালিক", + "You can't share with yourself.": "নিজের সাথে শেয়ার করতে পারবেন না।", + "This user already has access to this item": "এই ব্যবহারকারীর ইতিমধ্যে এটাতে অ্যাক্সেস রয়েছে।" }, }; From d911754e2b37fef3241adb6b38fd057e752a565d Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 20 Nov 2024 11:57:41 -0500 Subject: [PATCH 1265/2119] dev: fix test_mode flag --- .../src/modules/puterai/AITestModeService.js | 12 +++++++++ .../src/modules/puterai/AWSPollyService.js | 5 ++++ .../src/modules/puterai/AWSTextractService.js | 5 ++++ .../puterai/OpenAICompletionService.js | 6 +++++ .../src/modules/puterai/PuterAIModule.js | 3 +++ .../src/services/auth/PermissionService.js | 4 +++ .../src/services/drivers/DriverService.js | 26 ++++++++++++++++++- 7 files changed, 60 insertions(+), 1 deletion(-) create mode 100644 src/backend/src/modules/puterai/AITestModeService.js diff --git a/src/backend/src/modules/puterai/AITestModeService.js b/src/backend/src/modules/puterai/AITestModeService.js new file mode 100644 index 0000000000..64289acae1 --- /dev/null +++ b/src/backend/src/modules/puterai/AITestModeService.js @@ -0,0 +1,12 @@ +const BaseService = require("../../services/BaseService"); + +class AITestModeService extends BaseService { + async _init () { + const svc_driver = this.services.get('driver'); + svc_driver.register_test_service('puter-chat-completion', 'openai-completion'); + } +} + +module.exports = { + AITestModeService, +}; diff --git a/src/backend/src/modules/puterai/AWSPollyService.js b/src/backend/src/modules/puterai/AWSPollyService.js index 1c8fd022d2..5189e2592f 100644 --- a/src/backend/src/modules/puterai/AWSPollyService.js +++ b/src/backend/src/modules/puterai/AWSPollyService.js @@ -12,6 +12,11 @@ class AWSPollyService extends BaseService { } static IMPLEMENTS = { + ['driver-capabilities']: { + supports_test_mode (iface, method_name) { + return iface === 'puter-tts' && method_name === 'synthesize'; + } + }, ['puter-tts']: { async list_voices () { const polly_voices = await this.describe_voices(); diff --git a/src/backend/src/modules/puterai/AWSTextractService.js b/src/backend/src/modules/puterai/AWSTextractService.js index 01e605e8dd..e216397a56 100644 --- a/src/backend/src/modules/puterai/AWSTextractService.js +++ b/src/backend/src/modules/puterai/AWSTextractService.js @@ -9,6 +9,11 @@ class AWSTextractService extends BaseService { } static IMPLEMENTS = { + ['driver-capabilities']: { + supports_test_mode (iface, method_name) { + return iface === 'puter-ocr' && method_name === 'recognize'; + } + }, ['puter-ocr']: { async recognize ({ source, test_mode }) { if ( test_mode ) { diff --git a/src/backend/src/modules/puterai/OpenAICompletionService.js b/src/backend/src/modules/puterai/OpenAICompletionService.js index 7c170fe317..5c4fc1f076 100644 --- a/src/backend/src/modules/puterai/OpenAICompletionService.js +++ b/src/backend/src/modules/puterai/OpenAICompletionService.js @@ -22,6 +22,12 @@ class OpenAICompletionService extends BaseService { } static IMPLEMENTS = { + ['driver-capabilities']: { + supports_test_mode (iface, method_name) { + return iface === 'puter-chat-completion' && + method_name === 'complete'; + } + }, ['puter-chat-completion']: { async list () { return [ diff --git a/src/backend/src/modules/puterai/PuterAIModule.js b/src/backend/src/modules/puterai/PuterAIModule.js index a1241530f6..f5618759c0 100644 --- a/src/backend/src/modules/puterai/PuterAIModule.js +++ b/src/backend/src/modules/puterai/PuterAIModule.js @@ -56,6 +56,9 @@ class PuterAIModule extends AdvancedBase { const { FakeChatService } = require('./FakeChatService'); services.registerService('fake-chat', FakeChatService); + + const{ AITestModeService } = require('./AITestModeService'); + services.registerService('ai-test-mode', AITestModeService); } } diff --git a/src/backend/src/services/auth/PermissionService.js b/src/backend/src/services/auth/PermissionService.js index 27b4bb4bd1..59d42d9196 100644 --- a/src/backend/src/services/auth/PermissionService.js +++ b/src/backend/src/services/auth/PermissionService.js @@ -226,6 +226,10 @@ class PermissionService extends BaseService { } async scan (actor, permission_options, _reserved, state) { + if ( ! state ) this.log.info('scan', { + actor: actor.uid, + permission_options, + }); const reading = []; if ( ! state ) { diff --git a/src/backend/src/services/drivers/DriverService.js b/src/backend/src/services/drivers/DriverService.js index 74c180317a..c9220b67b1 100644 --- a/src/backend/src/services/drivers/DriverService.js +++ b/src/backend/src/services/drivers/DriverService.js @@ -37,6 +37,7 @@ class DriverService extends BaseService { _construct () { this.drivers = {}; this.interface_to_implementation = {}; + this.interface_to_test_service = {}; } async ['__on_registry.collections'] () { @@ -77,6 +78,10 @@ class DriverService extends BaseService { register_driver (interface_name, implementation) { this.interface_to_implementation[interface_name] = implementation; } + + register_test_service (interface_name, service_name) { + this.interface_to_test_service[interface_name] = service_name; + } get_interface (interface_name) { const o = {}; @@ -113,7 +118,8 @@ class DriverService extends BaseService { async _call ({ driver, iface, method, args }) { console.log('??', driver, iface, method, args); const processed_args = await this._process_args(iface, method, args); - if ( Context.get('test_mode') ) { + const test_mode = Context.get('test_mode'); + if ( test_mode ) { processed_args.test_mode = true; } @@ -141,18 +147,31 @@ class DriverService extends BaseService { driver = driver ?? iface_to_driver[iface] ?? iface; + let skip_usage = false; + if ( test_mode && this.interface_to_test_service[iface] ) { + driver = this.interface_to_test_service[iface]; + } + const driver_service_exists = (() => { + console.log('CHECKING FOR THIS', driver, iface); return this.services.has(driver) && this.services.get(driver).list_traits() .includes(iface); })(); if ( driver_service_exists ) { const service = this.services.get(driver); + + const caps = service.as('driver-capabilities'); + if ( test_mode && caps && caps.supports_test_mode(iface, method) ) { + skip_usage = true; + } + return await this.call_new_({ actor, service, service_name: driver, iface, method, args: processed_args, + skip_usage, }); } @@ -240,6 +259,7 @@ class DriverService extends BaseService { service, service_name, iface, method, args, + skip_usage, }) { const svc_permission = this.services.get('permission'); const reading = await svc_permission.scan( @@ -324,6 +344,8 @@ class DriverService extends BaseService { { name: 'enforce monthly usage limit', on_call: async args => { + if ( skip_usage ) return args; + // Typo-Tolerance if ( effective_policy?.['monthy-limit'] ) { effective_policy['monthly-limit'] = effective_policy['monthy-limit']; @@ -343,6 +365,8 @@ class DriverService extends BaseService { return args; }, on_return: async result => { + if ( skip_usage ) return result; + console.log('monthly usage is returning'); const svc_monthlyUsage = services.get('monthly-usage'); const extra = { From f0012fdf8788dc339937af19d9a1ef2ccc743160 Mon Sep 17 00:00:00 2001 From: nada Date: Wed, 20 Nov 2024 19:30:26 +0200 Subject: [PATCH 1266/2119] fixixng arabic translation --- src/gui/src/i18n/translations/ar.js | 702 ++++++++++++++-------------- 1 file changed, 363 insertions(+), 339 deletions(-) diff --git a/src/gui/src/i18n/translations/ar.js b/src/gui/src/i18n/translations/ar.js index d57fb9ea76..d5db271270 100644 --- a/src/gui/src/i18n/translations/ar.js +++ b/src/gui/src/i18n/translations/ar.js @@ -1,6 +1,4 @@ -/** - * Copyright (C) 2024 Puter Technologies Inc. - * +/** * Copyright (C) 2024 Puter Technologies Inc. * * This file is part of Puter. * * Puter is free software: you can redistribute it and/or modify @@ -18,352 +16,378 @@ */ const ar = { - name: "العربية", - english_name: "Arabic", - code: "ar", - dictionary: { - about: "حول", - account: "حساب", - account_password: "تحقق من كلمة مرور الحساب", - access_granted_to: "تم منح الوصول إلى", - add_existing_account: "إضافة حساب موجود", - all_fields_required: "جميع الحقول مطلوبة.", - allow: "السماح", - apply: "تطبيق", - ascending: "تصاعدي", - associated_websites: "المواقع المرتبطة", - auto_arrange: "ترتيب تلقائي", - background: "خلفية", - browse: "تصفح", - cancel: "إلغاء", - center: "مركز", - change_desktop_background: "تغيير خلفية سطح المكتب...", - change_email: "تغيير البريد الإلكتروني", - change_language: "تغيير اللغة", - change_password: "تغيير كلمة المرور", - change_ui_colors: "تغيير ألوان واجهة المستخدم", - change_username: "تغيير اسم المستخدم", - close: "إغلاق", - close_all_windows: "إغلاق جميع النوافذ", - close_all_windows_confirm: "هل أنت متأكد أنك تريد إغلاق جميع النوافذ؟", - close_all_windows_and_log_out: "إغلاق النوافذ وتسجيل الخروج", - change_always_open_with: "هل تريد دائمًا فتح هذا النوع من الملفات باستخدام", - color: "لون", - confirm: "تأكيد", - confirm_2fa_setup: "لقد أضفت الرمز إلى تطبيق المصادقة", - confirm_2fa_recovery: "لقد حفظت رموز الاسترداد في مكان آمن", - confirm_account_for_free_referral_storage_c2a: "أنشئ حسابًا وقم بتأكيد عنوان بريدك الإلكتروني للحصول على 1 جيجابايت من مساحة التخزين المجانية. سيحصل صديقك أيضًا على 1 جيجابايت من مساحة التخزين المجانية.", - confirm_code_generic_incorrect: "رمز غير صحيح.", - confirm_code_generic_too_many_requests: "طلبات كثيرة جدًا. يرجى الانتظار بضع دقائق.", - confirm_code_generic_submit: "إرسال الرمز", - confirm_code_generic_try_again: "حاول مرة أخرى", - confirm_code_generic_title: "أدخل رمز التأكيد", - confirm_code_2fa_instruction: "أدخل الرمز المكون من 6 أرقام من تطبيق المصادقة الخاص بك.", - confirm_code_2fa_submit_btn: "إرسال", - confirm_code_2fa_title: "أدخل رمز المصادقة الثنائية", - confirm_delete_multiple_items: "هل أنت متأكد أنك تريد حذف هذه العناصر نهائيًا؟", - confirm_delete_single_item: "هل تريد حذف هذا العنصر نهائيًا؟", - confirm_open_apps_log_out: "لديك تطبيقات مفتوحة. هل أنت متأكد أنك تريد تسجيل الخروج؟", - confirm_new_password: "تأكيد كلمة المرور الجديدة", - confirm_delete_user: "هل أنت متأكد أنك تريد حذف حسابك؟ سيتم حذف جميع ملفاتك وبياناتك نهائيًا. لا يمكن التراجع عن هذا الإجراء.", - confirm_delete_user_title: "حذف الحساب؟", - confirm_session_revoke: "هل أنت متأكد أنك تريد إلغاء هذه الجلسة؟", - confirm_your_email_address: "تأكيد عنوان بريدك الإلكتروني", - contact_us: "اتصل بنا", - contact_us_verification_required: "يجب أن يكون لديك عنوان بريد إلكتروني مُؤكد لاستخدام هذه الخدمة.", - contain: "احتواء", - continue: "استمر", - copy: "نسخ", - copy_link: "نسخ الرابط", - copying: "جارٍ النسخ", - copying_file: "جارٍ نسخ %%", - cover: "تغطية", - create_account: "إنشاء حساب", - create_free_account: "إنشاء حساب مجاني", - create_shortcut: "إنشاء اختصار", - credits: "الاعتمادات", - current_password: "كلمة المرور الحالية", - cut: "قص", - clock: "ساعة", - clock_visible_hide: "إخفاء - مخفية دائمًا", - clock_visible_show: "إظهار - مرئية دائمًا", - clock_visible_auto: "تلقائي - الافتراضي، مرئي فقط في وضع الشاشة الكاملة.", - close_all: "إغلاق الكل", - created: "تم الإنشاء", - date_modified: "تاريخ التعديل", - default: "افتراضي", - delete: "حذف", - delete_account: "حذف الحساب", - delete_permanently: "حذف نهائي", - deleting_file: "جارٍ حذف %%", - deploy_as_app: "نشر كتطبيق", - descending: "تنازلي", - desktop: "سطح المكتب", - desktop_background_fit: "ملائمة", - developers: "المطورين", - dir_published_as_website: "%strong% تم نشره إلى:", - disable_2fa: "تعطيل المصادقة الثنائية", - disable_2fa_confirm: "هل أنت متأكد أنك تريد تعطيل المصادقة الثنائية؟", - disable_2fa_instructions: "أدخل كلمة المرور لتعطيل المصادقة الثنائية.", - disassociate_dir: "فصل الدليل", - documents: "المستندات", - dont_allow: "عدم السماح", - download: "تنزيل", - download_file: "تنزيل الملف", - downloading: "جارٍ التنزيل", - email: "البريد الإلكتروني", - email_change_confirmation_sent: "تم إرسال بريد تأكيد إلى عنوان بريدك الإلكتروني الجديد. يرجى التحقق من صندوق الوارد واتباع التعليمات لإكمال العملية.", - email_invalid: "البريد الإلكتروني غير صالح.", - email_or_username: "البريد الإلكتروني أو اسم المستخدم", - email_required: "البريد الإلكتروني مطلوب.", - empty_trash: "إفراغ سلة المهملات", - empty_trash_confirmation: "هل أنت متأكد أنك تريد حذف العناصر في سلة المهملات نهائيًا؟", - emptying_trash: "جارٍ إفراغ سلة المهملات...", - enable_2fa: "تمكين المصادقة الثنائية", - end_hard: "إنهاء صعب", - end_process_force_confirm: "هل أنت متأكد أنك تريد إنهاء هذه العملية بالقوة؟", - end_soft: "إنهاء سلس", - enlarged_qr_code: "رمز QR مكبر", - enter_password_to_confirm_delete_user: "أدخل كلمة المرور لتأكيد حذف الحساب", - error_message_is_missing: "رسالة الخطأ مفقودة.", - error_unknown_cause: "حدث خطأ غير معروف.", - error_uploading_files: "فشل في تحميل الملفات", - favorites: "المفضلة", - feedback: "ملاحظات", - feedback_c2a: "يرجى استخدام النموذج أدناه لإرسال ملاحظاتك وتعليقاتك وتقرير الأخطاء.", - feedback_sent_confirmation: "شكرًا لتواصلك معنا. إذا كان لديك بريد إلكتروني مرتبط بحسابك، ستتلقى ردًا منا في أقرب وقت ممكن.", - fit: "ملائمة", - folder: "مجلد", - force_quit: "إنهاء بالقوة", - forgot_pass_c2a: "هل نسيت كلمة المرور؟", - from: "من", - general: "عام", - get_a_copy_of_on_puter: "احصل على نسخة من '%%' على Puter.com!", - get_copy_link: "احصل على رابط النسخ", - hide_all_windows: "إخفاء جميع النوافذ", - home: "الصفحة الرئيسية", - html_document: "مستند HTML", - hue: "درجة اللون", - image: "صورة", - incorrect_password: "كلمة مرور غير صحيحة", - invite_link: "رابط الدعوة", - item: "عنصر", - items_in_trash_cannot_be_renamed: "لا يمكن إعادة تسمية هذا العنصر لأنه في سلة المهملات. لإعادة تسمية هذا العنصر، اسحبه أولاً خارج سلة المهملات.", - jpeg_image: "صورة JPEG", - keep_in_taskbar: "الاحتفاظ في شريط المهام", - language: "اللغة", - license: "رخصة", - lightness: "إضاءة", - link_copied: "تم نسخ الرابط", - loading: "جارٍ التحميل", - log_in: "تسجيل الدخول", - log_into_another_account_anyway: "تسجيل الدخول إلى حساب آخر على أي حال", - log_out: "تسجيل الخروج", - looks_good: "يبدو جيدًا!", - manage_sessions: "إدارة الجلسات", - menubar_style: "نمط شريط القوائم", - menubar_style_desktop: "سطح المكتب", - menubar_style_system: "النظام", - menubar_style_window: "النافذة", - modified: "تم التعديل", - move: "نقل", - moving_file: "جارٍ نقل %%", - my_websites: "مواقعي الإلكترونية", - name: "اسم", - name_cannot_be_empty: "الاسم لا يمكن أن يكون فارغًا.", - name_cannot_contain_double_period: "الاسم لا يمكن أن يكون '..'.", - name_cannot_contain_period: "الاسم لا يمكن أن يكون '.'.", - name_cannot_contain_slash: "الاسم لا يمكن أن يحتوي على '/'.", - name_must_be_string: "الاسم يجب أن يكون نصًا فقط.", - name_too_long: "الاسم لا يمكن أن يكون أطول من %% حرف.", - new: "جديد", - new_email: "البريد الإلكتروني الجديد", - new_folder: "مجلد جديد", - new_password: "كلمة المرور الجديدة", - new_username: "اسم المستخدم الجديد", - no: "لا", - no_dir_associated_with_site: "لا يوجد دليل مرتبط بهذا العنوان.", - no_websites_published: "لم تنشر أي مواقع إلكترونية بعد.", - ok: "موافق", - open: "فتح", - open_in_new_tab: "فتح في علامة تبويب جديدة", - open_in_new_window: "فتح في نافذة جديدة", - open_with: "فتح باستخدام", - original_name: "الاسم الأصلي", - original_path: "المسار الأصلي", - oss_code_and_content: "برامج ومحتوى مفتوح المصدر", - password: "كلمة المرور", - password_changed: "تم تغيير كلمة المرور.", - password_recovery_rate_limit: "لقد وصلت إلى الحد الأقصى؛ يرجى الانتظار بضع دقائق. لمنع حدوث ذلك في المستقبل، تجنب إعادة تحميل الصفحة كثيرًا.", - password_recovery_token_invalid: "رمز استعادة كلمة المرور لم يعد صالحًا.", - password_recovery_unknown_error: "حدث خطأ غير معروف. يرجى المحاولة مرة أخرى لاحقًا.", - password_required: "كلمة المرور مطلوبة.", - password_strength_error: "يجب أن تكون كلمة المرور بطول 8 أحرف على الأقل وتحتوي على حرف كبير واحد، حرف صغير واحد، رقم واحد، وحرف خاص واحد على الأقل.", - passwords_do_not_match: "`كلمة المرور الجديدة` و`تأكيد كلمة المرور الجديدة` غير متطابقتين.", - paste: "لصق", - paste_into_folder: "لصق في المجلد", - path: "المسار", - personalization: "تخصيص", - pick_name_for_website: "اختر اسمًا لموقعك الإلكتروني:", - picture: "صورة", - pictures: "الصور", - plural_suffix: "s", - powered_by_puter_js: "مدعوم بواسطة {{link=docs}}Puter.js{{/link}}", - preparing: "جارٍ التحضير...", - preparing_for_upload: "جارٍ التحضير للتحميل...", - print: "طباعة", - privacy: "الخصوصية", - proceed_to_login: "المتابعة لتسجيل الدخول", - proceed_with_account_deletion: "المتابعة مع حذف الحساب", - process_status_initializing: "جارٍ التهيئة", - process_status_running: "جارٍ التشغيل", - process_type_app: "تطبيق", - process_type_init: "تهيئة", - process_type_ui: "واجهة المستخدم", - properties: "الخصائص", - public: "عام", - publish: "نشر", - publish_as_website: "نشر كموقع إلكتروني", - puter_description: "Puter هو سحابة شخصية تركز على الخصوصية للحفاظ على جميع ملفاتك، تطبيقاتك، وألعابك في مكان آمن واحد، متاحة من أي مكان وفي أي وقت.", - reading_file: "جارٍ قراءة %strong%", - recent: "الأخيرة", - recommended: "مُوصى به", - recover_password: "استعادة كلمة المرور", - refer_friends_c2a: "احصل على 1 جيجابايت عن كل صديق ينشئ حسابًا ويؤكده على Puter. سيحصل صديقك على 1 جيجابايت أيضًا!", - refer_friends_social_media_c2a: "احصل على 1 جيجابايت من التخزين المجاني على Puter.com!", - refresh: "تحديث", - release_address_confirmation: "هل أنت متأكد أنك تريد تحرير هذا العنوان؟", - remove_from_taskbar: "إزالة من شريط المهام", - rename: "إعادة تسمية", - repeat: "تكرار", - replace: "استبدال", - replace_all: "استبدال الكل", - resend_confirmation_code: "إعادة إرسال رمز التأكيد", - reset_colors: "إعادة ضبط الألوان", - restart_puter_confirm: "هل أنت متأكد أنك تريد إعادة تشغيل Puter؟", - restore: "استعادة", - save: "حفظ", - saturation: "تشبع", - save_account: "حفظ الحساب", - save_account_to_get_copy_link: "يرجى إنشاء حساب للمتابعة.", - save_account_to_publish: "يرجى إنشاء حساب للمتابعة.", - save_session: "حفظ الجلسة", - save_session_c2a: "أنشئ حسابًا لحفظ جلستك الحالية وتجنب فقدان عملك.", - scan_qr_c2a: "امسح الرمز أدناه لتسجيل الدخول إلى هذه الجلسة من أجهزة أخرى", - scan_qr_2fa: "امسح رمز الاستجابة السريعة باستخدام تطبيق المصادقة الخاص بك", - scan_qr_generic: "امسح رمز الاستجابة السريعة هذا باستخدام هاتفك أو جهاز آخر", - search: "بحث", - seconds: "ثوانٍ", - security: "الأمان", - select: "تحديد", - selected: "محدد", - select_color: "اختر لونًا…", - sessions: "جلسات", - send: "إرسال", - send_password_recovery_email: "إرسال بريد استعادة كلمة المرور", - session_saved: "شكرًا لإنشاء حساب. تم حفظ هذه الجلسة.", - settings: "الإعدادات", - set_new_password: "تعيين كلمة مرور جديدة", - share: "مشاركة", - share_to: "مشاركة إلى", - share_with: "مشاركة مع:", - shortcut_to: "اختصار إلى", - show_all_windows: "عرض جميع النوافذ", - show_hidden: "إظهار المخفي", - sign_in_with_puter: "تسجيل الدخول باستخدام Puter", - sign_up: "تسجيل", - signing_in: "جارٍ تسجيل الدخول…", - size: "الحجم", - skip: "تخطي", - something_went_wrong: "حدث خطأ ما.", - sort_by: "فرز حسب", - start: "بدء", - status: "الحالة", - storage_usage: "استخدام التخزين", - storage_puter_used: "مستخدم بواسطة Puter", - taking_longer_than_usual: "يستغرق وقتًا أطول من المعتاد. يرجى الانتظار...", - task_manager: "مدير المهام", - taskmgr_header_name: "الاسم", - taskmgr_header_status: "الحالة", - taskmgr_header_type: "النوع", - terms: "الشروط", - text_document: "مستند نصي", - tos_fineprint: "بالنقر على 'إنشاء حساب مجاني' فإنك توافق على {{link=terms}}شروط الخدمة{{/link}} و{{link=privacy}}سياسة الخصوصية{{/link}} لـPuter.", - transparency: "الشفافية", - trash: "المهملات", - two_factor: "المصادقة الثنائية", - two_factor_disabled: "تم تعطيل المصادقة الثنائية", - two_factor_enabled: "تم تمكين المصادقة الثنائية", - type: "نوع", - type_confirm_to_delete_account: "اكتب 'تأكيد' لحذف حسابك.", - ui_colors: "ألوان واجهة المستخدم", - ui_manage_sessions: "مدير الجلسات", - ui_revoke: "إلغاء", - undo: "تراجع", - unlimited: "غير محدود", - unzip: "فك الضغط", - upload: "رفع", - upload_here: "ارفع هنا", - usage: "الاستخدام", - username: "اسم المستخدم", - username_changed: "تم تحديث اسم المستخدم بنجاح.", - username_required: "اسم المستخدم مطلوب.", - versions: "الإصدارات", - videos: "مقاطع الفيديو", - visibility: "الرؤية", - yes: "نعم", - yes_release_it: "نعم، أطلقه", - you_have_been_referred_to_puter_by_a_friend: "تم إحالتك إلى Puter بواسطة صديق!", - zip: "ضغط", - zipping_file: "جارٍ ضغط %strong%", + name: "العربية", + english_name: "Arabic", + code: "ar", + dictionary: { + about: "حول", + account: "حساب", + account_password: "تحقق من كلمة مرور الحساب", + access_granted_to: "تم منح الوصول إلى", + add_existing_account: "إضافة حساب موجود", + all_fields_required: "جميع الحقول مطلوبة.", + allow: "السماح", + apply: "تطبيق", + ascending: "تصاعدي", + associated_websites: "المواقع المرتبطة", + auto_arrange: "ترتيب تلقائي", + background: "خلفية", + browse: "تصفح", + cancel: "إلغاء", + center: "مركز", + change_desktop_background: "تغيير خلفية سطح المكتب...", + change_email: "تغيير البريد الإلكتروني", + change_language: "تغيير اللغة", + change_password: "تغيير كلمة المرور", + change_ui_colors: "تغيير ألوان واجهة المستخدم", + change_username: "تغيير اسم المستخدم", + close: "إغلاق", + close_all_windows: "إغلاق جميع النوافذ", + close_all_windows_confirm: "هل أنت متأكد أنك تريد إغلاق جميع النوافذ؟", + close_all_windows_and_log_out: "إغلاق النوافذ وتسجيل الخروج", + change_always_open_with: "هل تريد دائمًا فتح هذا النوع من الملفات باستخدام", + color: "لون", + confirm: "تأكيد", + confirm_2fa_setup: "لقد أضفت الرمز إلى تطبيق المصادقة", + confirm_2fa_recovery: "لقد حفظت رموز الاسترداد في مكان آمن", + confirm_account_for_free_referral_storage_c2a: + "أنشئ حسابًا وقم بتأكيد عنوان بريدك الإلكتروني للحصول على 1 جيجابايت من مساحة التخزين المجانية. سيحصل صديقك أيضًا على 1 جيجابايت من مساحة التخزين المجانية.", + confirm_code_generic_incorrect: "رمز غير صحيح.", + confirm_code_generic_too_many_requests: + "طلبات كثيرة جدًا. يرجى الانتظار بضع دقائق.", + confirm_code_generic_submit: "إرسال الرمز", + confirm_code_generic_try_again: "حاول مرة أخرى", + confirm_code_generic_title: "أدخل رمز التأكيد", + confirm_code_2fa_instruction: + "أدخل الرمز المكون من 6 أرقام من تطبيق المصادقة الخاص بك.", + confirm_code_2fa_submit_btn: "إرسال", + confirm_code_2fa_title: "أدخل رمز المصادقة الثنائية", + confirm_delete_multiple_items: + "هل أنت متأكد أنك تريد حذف هذه العناصر نهائيًا؟", + confirm_delete_single_item: "هل تريد حذف هذا العنصر نهائيًا؟", + confirm_open_apps_log_out: + "لديك تطبيقات مفتوحة. هل أنت متأكد أنك تريد تسجيل الخروج؟", + confirm_new_password: "تأكيد كلمة المرور الجديدة", + confirm_delete_user: + "هل أنت متأكد أنك تريد حذف حسابك؟ سيتم حذف جميع ملفاتك وبياناتك نهائيًا. لا يمكن التراجع عن هذا الإجراء.", + confirm_delete_user_title: "حذف الحساب؟", + confirm_session_revoke: "هل أنت متأكد أنك تريد إلغاء هذه الجلسة؟", + confirm_your_email_address: "تأكيد عنوان بريدك الإلكتروني", + contact_us: "اتصل بنا", + contact_us_verification_required: + "يجب أن يكون لديك عنوان بريد إلكتروني مُؤكد لاستخدام هذه الخدمة.", + contain: "احتواء", + continue: "استمر", + copy: "نسخ", + copy_link: "نسخ الرابط", + copying: "جارٍ النسخ", + copying_file: "جارٍ نسخ %%", + cover: "تغطية", + create_account: "إنشاء حساب", + create_free_account: "إنشاء حساب مجاني", + create_shortcut: "إنشاء اختصار", + credits: "الاعتمادات", + current_password: "كلمة المرور الحالية", + cut: "قص", + clock: "ساعة", + clock_visible_hide: "إخفاء - مخفية دائمًا", + clock_visible_show: "إظهار - مرئية دائمًا", + clock_visible_auto: "تلقائي - الافتراضي، مرئي فقط في وضع الشاشة الكاملة.", + close_all: "إغلاق الكل", + created: "تم الإنشاء", + date_modified: "تاريخ التعديل", + default: "افتراضي", + delete: "حذف", + delete_account: "حذف الحساب", + delete_permanently: "حذف نهائي", + deleting_file: "جارٍ حذف %%", + deploy_as_app: "نشر كتطبيق", + descending: "تنازلي", + desktop: "سطح المكتب", + desktop_background_fit: "ملائمة", + developers: "المطورين", + dir_published_as_website: "%strong% تم نشره إلى:", + disable_2fa: "تعطيل المصادقة الثنائية", + disable_2fa_confirm: "هل أنت متأكد أنك تريد تعطيل المصادقة الثنائية؟", + disable_2fa_instructions: "أدخل كلمة المرور لتعطيل المصادقة الثنائية.", + disassociate_dir: "فصل الدليل", + documents: "المستندات", + dont_allow: "عدم السماح", + download: "تنزيل", + download_file: "تنزيل الملف", + downloading: "جارٍ التنزيل", + email: "البريد الإلكتروني", + email_change_confirmation_sent: + "تم إرسال بريد تأكيد إلى عنوان بريدك الإلكتروني الجديد. يرجى التحقق من صندوق الوارد واتباع التعليمات لإكمال العملية.", + email_invalid: "البريد الإلكتروني غير صالح.", + email_or_username: "البريد الإلكتروني أو اسم المستخدم", + email_required: "البريد الإلكتروني مطلوب.", + empty_trash: "إفراغ سلة المهملات", + empty_trash_confirmation: + "هل أنت متأكد أنك تريد حذف العناصر في سلة المهملات نهائيًا؟", + emptying_trash: "جارٍ إفراغ سلة المهملات...", + enable_2fa: "تمكين المصادقة الثنائية", + end_hard: "إنهاء صعب", + end_process_force_confirm: + "هل أنت متأكد أنك تريد إنهاء هذه العملية بالقوة؟", + end_soft: "إنهاء سلس", + enlarged_qr_code: "رمز QR مكبر", + enter_password_to_confirm_delete_user: "أدخل كلمة المرور لتأكيد حذف الحساب", + error_message_is_missing: "رسالة الخطأ مفقودة.", + error_unknown_cause: "حدث خطأ غير معروف.", + error_uploading_files: "فشل في تحميل الملفات", + favorites: "المفضلة", + feedback: "ملاحظات", + feedback_c2a: + "يرجى استخدام النموذج أدناه لإرسال ملاحظاتك وتعليقاتك وتقرير الأخطاء.", + feedback_sent_confirmation: + "شكرًا لتواصلك معنا. إذا كان لديك بريد إلكتروني مرتبط بحسابك، ستتلقى ردًا منا في أقرب وقت ممكن.", + fit: "ملائمة", + folder: "مجلد", + force_quit: "إنهاء بالقوة", + forgot_pass_c2a: "هل نسيت كلمة المرور؟", + from: "من", + general: "عام", + get_a_copy_of_on_puter: "احصل على نسخة من '%%' على Puter.com!", + get_copy_link: "احصل على رابط النسخ", + hide_all_windows: "إخفاء جميع النوافذ", + home: "الصفحة الرئيسية", + html_document: "مستند HTML", + hue: "درجة اللون", + image: "صورة", + incorrect_password: "كلمة مرور غير صحيحة", + invite_link: "رابط الدعوة", + item: "عنصر", + items_in_trash_cannot_be_renamed: + "لا يمكن إعادة تسمية هذا العنصر لأنه في سلة المهملات. لإعادة تسمية هذا العنصر، اسحبه أولاً خارج سلة المهملات.", + jpeg_image: "صورة JPEG", + keep_in_taskbar: "الاحتفاظ في شريط المهام", + language: "اللغة", + license: "رخصة", + lightness: "إضاءة", + link_copied: "تم نسخ الرابط", + loading: "جارٍ التحميل", + log_in: "تسجيل الدخول", + log_into_another_account_anyway: "تسجيل الدخول إلى حساب آخر على أي حال", + log_out: "تسجيل الخروج", + looks_good: "يبدو جيدًا!", + manage_sessions: "إدارة الجلسات", + menubar_style: "نمط شريط القوائم", + menubar_style_desktop: "سطح المكتب", + menubar_style_system: "النظام", + menubar_style_window: "النافذة", + modified: "تم التعديل", + move: "نقل", + moving_file: "جارٍ نقل %%", + my_websites: "مواقعي الإلكترونية", + name: "اسم", + name_cannot_be_empty: "الاسم لا يمكن أن يكون فارغًا.", + name_cannot_contain_double_period: "الاسم لا يمكن أن يكون '..'.", + name_cannot_contain_period: "الاسم لا يمكن أن يكون '.'.", + name_cannot_contain_slash: "الاسم لا يمكن أن يحتوي على '/'.", + name_must_be_string: "الاسم يجب أن يكون نصًا فقط.", + name_too_long: "الاسم لا يمكن أن يكون أطول من %% حرف.", + new: "جديد", + new_email: "البريد الإلكتروني الجديد", + new_folder: "مجلد جديد", + new_password: "كلمة المرور الجديدة", + new_username: "اسم المستخدم الجديد", + no: "لا", + no_dir_associated_with_site: "لا يوجد دليل مرتبط بهذا العنوان.", + no_websites_published: "لم تنشر أي مواقع إلكترونية بعد.", + ok: "موافق", + open: "فتح", + open_in_new_tab: "فتح في علامة تبويب جديدة", + open_in_new_window: "فتح في نافذة جديدة", + open_with: "فتح باستخدام", + original_name: "الاسم الأصلي", + original_path: "المسار الأصلي", + oss_code_and_content: "برامج ومحتوى مفتوح المصدر", + password: "كلمة المرور", + password_changed: "تم تغيير كلمة المرور.", + password_recovery_rate_limit: + "لقد وصلت إلى الحد الأقصى؛ يرجى الانتظار بضع دقائق. لمنع حدوث ذلك في المستقبل، تجنب إعادة تحميل الصفحة كثيرًا.", + password_recovery_token_invalid: "رمز استعادة كلمة المرور لم يعد صالحًا.", + password_recovery_unknown_error: + "حدث خطأ غير معروف. يرجى المحاولة مرة أخرى لاحقًا.", + password_required: "كلمة المرور مطلوبة.", + password_strength_error: + "يجب أن تكون كلمة المرور بطول 8 أحرف على الأقل وتحتوي على حرف كبير واحد، حرف صغير واحد، رقم واحد، وحرف خاص واحد على الأقل.", + passwords_do_not_match: + "`كلمة المرور الجديدة` و`تأكيد كلمة المرور الجديدة` غير متطابقتين.", + paste: "لصق", + paste_into_folder: "لصق في المجلد", + path: "المسار", + personalization: "تخصيص", + pick_name_for_website: "اختر اسمًا لموقعك الإلكتروني:", + picture: "صورة", + pictures: "الصور", + plural_suffix: "s", + powered_by_puter_js: "مدعوم بواسطة {{link=docs}}Puter.js{{/link}}", + preparing: "جارٍ التحضير...", + preparing_for_upload: "جارٍ التحضير للتحميل...", + print: "طباعة", + privacy: "الخصوصية", + proceed_to_login: "المتابعة لتسجيل الدخول", + proceed_with_account_deletion: "المتابعة مع حذف الحساب", + process_status_initializing: "جارٍ التهيئة", + process_status_running: "جارٍ التشغيل", + process_type_app: "تطبيق", + process_type_init: "تهيئة", + process_type_ui: "واجهة المستخدم", + properties: "الخصائص", + public: "عام", + publish: "نشر", + publish_as_website: "نشر كموقع إلكتروني", + puter_description: + "Puter هو سحابة شخصية تركز على الخصوصية للحفاظ على جميع ملفاتك، تطبيقاتك، وألعابك في مكان آمن واحد، متاحة من أي مكان وفي أي وقت.", + reading_file: "جارٍ قراءة %strong%", + recent: "الأخيرة", + recommended: "مُوصى به", + recover_password: "استعادة كلمة المرور", + refer_friends_c2a: + "احصل على 1 جيجابايت عن كل صديق ينشئ حسابًا ويؤكده على Puter. سيحصل صديقك على 1 جيجابايت أيضًا!", + refer_friends_social_media_c2a: + "احصل على 1 جيجابايت من التخزين المجاني على Puter.com!", + refresh: "تحديث", + release_address_confirmation: "هل أنت متأكد أنك تريد تحرير هذا العنوان؟", + remove_from_taskbar: "إزالة من شريط المهام", + rename: "إعادة تسمية", + repeat: "تكرار", + replace: "استبدال", + replace_all: "استبدال الكل", + resend_confirmation_code: "إعادة إرسال رمز التأكيد", + reset_colors: "إعادة ضبط الألوان", + restart_puter_confirm: "هل أنت متأكد أنك تريد إعادة تشغيل Puter؟", + restore: "استعادة", + save: "حفظ", + saturation: "تشبع", + save_account: "حفظ الحساب", + save_account_to_get_copy_link: "يرجى إنشاء حساب للمتابعة.", + save_account_to_publish: "يرجى إنشاء حساب للمتابعة.", + save_session: "حفظ الجلسة", + save_session_c2a: "أنشئ حسابًا لحفظ جلستك الحالية وتجنب فقدان عملك.", + scan_qr_c2a: "امسح الرمز أدناه لتسجيل الدخول إلى هذه الجلسة من أجهزة أخرى", + scan_qr_2fa: "امسح رمز الاستجابة السريعة باستخدام تطبيق المصادقة الخاص بك", + scan_qr_generic: + "امسح رمز الاستجابة السريعة هذا باستخدام هاتفك أو جهاز آخر", + search: "بحث", + seconds: "ثوانٍ", + security: "الأمان", + select: "تحديد", + selected: "محدد", + select_color: "اختر لونًا…", + sessions: "جلسات", + send: "إرسال", + send_password_recovery_email: "إرسال بريد استعادة كلمة المرور", + session_saved: "شكرًا لإنشاء حساب. تم حفظ هذه الجلسة.", + settings: "الإعدادات", + set_new_password: "تعيين كلمة مرور جديدة", + share: "مشاركة", + share_to: "مشاركة إلى", + share_with: "مشاركة مع:", + shortcut_to: "اختصار إلى", + show_all_windows: "عرض جميع النوافذ", + show_hidden: "إظهار المخفي", + sign_in_with_puter: "تسجيل الدخول باستخدام Puter", + sign_up: "تسجيل", + signing_in: "جارٍ تسجيل الدخول…", + size: "الحجم", + skip: "تخطي", + something_went_wrong: "حدث خطأ ما.", + sort_by: "فرز حسب", + start: "بدء", + status: "الحالة", + storage_usage: "استخدام التخزين", + storage_puter_used: "مستخدم بواسطة Puter", + taking_longer_than_usual: "يستغرق وقتًا أطول من المعتاد. يرجى الانتظار...", + task_manager: "مدير المهام", + taskmgr_header_name: "الاسم", + taskmgr_header_status: "الحالة", + taskmgr_header_type: "النوع", + terms: "الشروط", + text_document: "مستند نصي", + tos_fineprint: + "بالنقر على 'إنشاء حساب مجاني' فإنك توافق على {{link=terms}}شروط الخدمة{{/link}} و{{link=privacy}}سياسة الخصوصية{{/link}} لـPuter.", + transparency: "الشفافية", + trash: "المهملات", + two_factor: "المصادقة الثنائية", + two_factor_disabled: "تم تعطيل المصادقة الثنائية", + two_factor_enabled: "تم تمكين المصادقة الثنائية", + type: "نوع", + type_confirm_to_delete_account: "اكتب 'تأكيد' لحذف حسابك.", + ui_colors: "ألوان واجهة المستخدم", + ui_manage_sessions: "مدير الجلسات", + ui_revoke: "إلغاء", + undo: "تراجع", + unlimited: "غير محدود", + unzip: "فك الضغط", + upload: "رفع", + upload_here: "ارفع هنا", + usage: "الاستخدام", + username: "اسم المستخدم", + username_changed: "تم تحديث اسم المستخدم بنجاح.", + username_required: "اسم المستخدم مطلوب.", + versions: "الإصدارات", + videos: "مقاطع الفيديو", + visibility: "الرؤية", + yes: "نعم", + yes_release_it: "نعم، أطلقه", + you_have_been_referred_to_puter_by_a_friend: + "تم إحالتك إلى Puter بواسطة صديق!", + zip: "ضغط", + zipping_file: "جارٍ ضغط %strong%", - // === 2FA Setup === - setup2fa_1_step_heading: "افتح تطبيق المصادقة الخاص بك", - setup2fa_1_instructions: ` + // === 2FA Setup === + setup2fa_1_step_heading: "افتح تطبيق المصادقة الخاص بك", + setup2fa_1_instructions: ` يمكنك استخدام أي تطبيق مصادقة يدعم بروتوكول كلمة المرور لمرة واحدة المعتمدة على الوقت (TOTP). هناك العديد للاختيار من بينها، ولكن إذا كنت غير متأكد Authy هو خيار موثوق به لنظام Android و iOS. `, - setup2fa_2_step_heading: "مسح رمز الاستجابة السريعة (QR code)", - setup2fa_3_step_heading: "أدخل الرمز المكون من 6 أرقام", - setup2fa_4_step_heading: "انسخ رموز الاسترداد الخاصة بك", - setup2fa_4_instructions: ` + setup2fa_2_step_heading: "مسح رمز الاستجابة السريعة (QR code)", + setup2fa_3_step_heading: "أدخل الرمز المكون من 6 أرقام", + setup2fa_4_step_heading: "انسخ رموز الاسترداد الخاصة بك", + setup2fa_4_instructions: ` هذه رموز الاسترداد هي الطريقة الوحيدة للوصول إلى حسابك إذا فقدت هاتفك أو لم تتمكن من استخدام تطبيق المصادقة الخاص بك. تأكد من حفظها في مكان آمن. `, - setup2fa_5_step_heading: "تأكيد إعداد المصادقة الثنائية (2FA)", - setup2fa_5_confirmation_1: "لقد قمت بحفظ رموز الاسترداد في مكان آمن", - setup2fa_5_confirmation_2: "أنا جاهز لتمكين المصادقة الثنائية (2FA)", - setup2fa_5_button: "تمكين المصادقة الثنائية (2FA)", + setup2fa_5_step_heading: "تأكيد إعداد المصادقة الثنائية (2FA)", + setup2fa_5_confirmation_1: "لقد قمت بحفظ رموز الاسترداد في مكان آمن", + setup2fa_5_confirmation_2: "أنا جاهز لتمكين المصادقة الثنائية (2FA)", + setup2fa_5_button: "تمكين المصادقة الثنائية (2FA)", - // === 2FA Login === - login2fa_otp_title: "أدخل رمز المصادقة الثنائية (2FA)", - login2fa_otp_instructions: "أدخل الرمز المكون من 6 أرقام من تطبيق المصادقة الخاص بك.", - login2fa_recovery_title: "أدخل رمز الاسترداد", - login2fa_recovery_instructions: "أدخل أحد رموز الاسترداد الخاصة بك للوصول إلى حسابك.", - login2fa_use_recovery_code: "استخدام رمز الاسترداد", - login2fa_recovery_back: "الرجوع", - login2fa_recovery_placeholder: "XXXXXXXX", + // === 2FA Login === + login2fa_otp_title: "أدخل رمز المصادقة الثنائية (2FA)", + login2fa_otp_instructions: + "أدخل الرمز المكون من 6 أرقام من تطبيق المصادقة الخاص بك.", + login2fa_recovery_title: "أدخل رمز الاسترداد", + login2fa_recovery_instructions: + "أدخل أحد رموز الاسترداد الخاصة بك للوصول إلى حسابك.", + login2fa_use_recovery_code: "استخدام رمز الاسترداد", + login2fa_recovery_back: "الرجوع", + login2fa_recovery_placeholder: "XXXXXXXX", - // *********************************** - // Missing translations - // *********************************** - "change": undefined, // In English: "Change" - "clock_visibility": undefined, // In English: "Clock Visibility" - "reading": undefined, // In English: "Reading %strong%" - "writing": undefined, // In English: "Writing %strong%" - "unzipping": undefined, // In English: "Unzipping %strong%" - "sequencing": undefined, // In English: "Sequencing %strong%" - "zipping": undefined, // In English: "Zipping %strong%" - "Editor": undefined, // In English: "Editor" - "Viewer": undefined, // In English: "Viewer" - "People with access": undefined, // In English: "People with access" - "Share With…": undefined, // In English: "Share With…" - "Owner": undefined, // In English: "Owner" - "You can't share with yourself.": undefined, // In English: "You can't share with yourself." - "This user already has access to this item": undefined, // In English: "This user already has access to this item" - } + // *********************************** + // Missing translations + // *********************************** + change: "تغيير", // In English: "Change" + clock_visibility: "ظهور الساعة", // In English: "Clock Visibility" + reading: "قراءة %strong%", // In English: "Reading %strong%" + writing: "كتابة %strong%", // In English: "Writing %strong%" + unzipping: "فك الضغط %strong%", // In English: "Unzipping %strong%" + sequencing: "ترتيب %strong%", // In English: "Sequencing %strong%" + zipping: "ضغط %strong%", // In English: "Zipping %strong%" + Editor: "المحرر", // In English: "Editor" + Viewer: "المشاهد", // In English: "Viewer" + "People with access": "الأشخاص الذين لديهم تحكم", // In English: "People with access" + "Share With…": "مشاركة مع...", // In English: "Share With…" + Owner: "المالك", // In English: "Owner" + "You can't share with yourself.": "لا يمكنك المشاركة مع نفسك.", // In English: "You can't share with yourself." + "This user already has access to this item": + "هذا المستخدم لديه بالفعل تحكم إلى هذا العنصر", // In English: "This user already has access to this item" + }, }; -export default ar; \ No newline at end of file +export default ar; From be566cb7c1a497e9861e4972a375d2a4b400a7b1 Mon Sep 17 00:00:00 2001 From: jelveh Date: Wed, 20 Nov 2024 10:15:30 -0800 Subject: [PATCH 1267/2119] Update bn.js --- src/gui/src/i18n/translations/bn.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index c682c4bcc7..bababc3aad 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -349,9 +349,6 @@ const bn = { login2fa_recovery_back: "পিছনে", login2fa_recovery_placeholder: "XXXXXXXX", - // *********************************** - // Missing translations - // *********************************** "change": "পরিবর্তন", // In English: "Change" "clock_visibility": "ঘড়ির দৃশ্যমানতা", // In English: "Clock Visibility" "password_recovery_token_invalid": "এই পাসওয়ার্ড রিকোভারি টোকেনটি আর ব্যবহারযোগ্য নয়।", // In English: "This password recovery token is no longer valid." @@ -370,7 +367,6 @@ const bn = { "Owner": "মালিক", // In English: "Owner" "You can't share with yourself.": "আপনি নিজের সাথে শেয়ার করতে পারবেন না।", // In English: "You can't share with yourself." "This user already has access to this item": "এই ব্যবহারকারীর ইতিমধ্যেই এই আইটেমে প্রবেশাধিকার আছে।", // In English: "This user already has access to this item" - }, }; From b0046ceb269abeff9b5b654bb5511fab027b4c5a Mon Sep 17 00:00:00 2001 From: Barkatzx Date: Thu, 21 Nov 2024 00:23:25 +0600 Subject: [PATCH 1268/2119] issue #842 --- src/gui/src/i18n/translations/bn.js | 199 ++++++++++++++-------------- 1 file changed, 102 insertions(+), 97 deletions(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index bababc3aad..9db99b0188 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -27,50 +27,50 @@ const bn = { account_password: "অ্যাকাউন্ট পাসওয়ার্ড যাচাই করুন", access_granted_to: "অ্যাক্সেস দেওয়া হয়েছে", add_existing_account: "বিদ্যমান অ্যাকাউন্ট যোগ করুন", - all_fields_required: "সমস্ত ফিল্ড প্রয়োজন.", + all_fields_required: "সমস্ত ফিল্ড পূরন করুন.", allow: "অনুমতি দিন", apply: "প্রয়োগ করুন", - ascending: "উত্তরাধিকার", + ascending: "ঊর্ধ্বক্রমে", associated_websites: "সংযুক্ত ওয়েবসাইটগুলি", auto_arrange: "অটো বিন্যাস", background: "পেছনের অংশ", browse: "ব্রাউজ", cancel: "বাতিল করুন", center: "কেন্দ্র", - change_desktop_background: "ডেস্কটপ এর ব্যকগ্রাউন্ড পরিবর্তন করুন…", - change_email: "ইমেইল পরিবর্তন করুন", + change_desktop_background: "ডেস্কটপ পটভূমি পরিবর্তন করুন", + change_email: "ই-মেইল পরিবর্তন করুন", change_language: "ভাষা পরিবর্তন করুন", change_password: "পাসওয়ার্ড পরিবর্তন করুন", - change_ui_colors: "ইউআই এর রঙ পরিবর্তন করুন", + change_ui_colors: "ইউআই রঙ পরিবর্তন করুন", change_username: "ইউজারনেম পরিবর্তন করুন", close: "বন্ধ করুন", close_all_windows: "সমস্ত উইন্ডো বন্ধ করুন", close_all_windows_confirm: "আপনি কি সমস্ত উইন্ডো বন্ধ করতে চান?", - close_all_windows_and_log_out: "সমস্ত উইন্ডো বন্ধ এবং লগ আউট করুন", - change_always_open_with: "আপনি কি এই ধরনের ফাইলটি সবসময় একটি নির্দিষ্ট এপ্লিকেশনের মাধ্যমে ওপেন করতে চান?", + close_all_windows_and_log_out: "উইন্ডো বন্ধ এবং লগ আউট করুন", + change_always_open_with: "আপনি কি এই ধরনের ফাইলটি সবসময় এই সাথে খোলা রাখতে চান", color: "রঙ", - confirm: "নিশ্চিতকরণ", - confirm_2fa_setup: "২ ফ্যাক্টর অথেনটিকেশন নিশ্চিত করুন", - confirm_2fa_recovery: "২ ফ্যাক্টর অথেনটিকেশন এর রিকোভারি কী গুলো নিশ্চিত করুন", - confirm_account_for_free_referral_storage_c2a: "একটি অ্যাকাউন্ট তৈরি করুন এবং আপনার ইমেল ঠিকানা নিশ্চিত করুন যাতে ফ্রি ১ জিবি স্টোরেজ পান। আপনার বন্ধুও ১ জিবি ফ্রি স্টোরেজ পাবেন।", - confirm_code_generic_incorrect: "ভুল কোড।", - confirm_code_generic_too_many_requests: "কোড জেনারেশনের রিকোয়েস্ট অনেকবার এসেছে। দয়া করে কয়েক মিনিট অপেক্ষা করুন।", - confirm_code_generic_submit: "কোড জমা দিন", + confirm: "অনুমোদন", + confirm_2fa_setup: "২ ফেক্টর অথেন্টিকেশন সেটাপ নিশ্চিত করুন", + confirm_2fa_recovery: "আমি আমার পুনরুদ্ধার কোডগুলি একটি নিরাপদ স্থানে সংরক্ষণ করতে চাই", + confirm_account_for_free_referral_storage_c2a: "একটি অ্যাকাউন্ট তৈরি করুন এবং আপনার ইমেল ঠিকানা নিশ্চিত করুন যাতে ফ্রি ১ জিবি স্টোরেজ পান। আপনার বন্ধুও ১ জিবি ফ্রি স্টোরেজ পাবেন", + confirm_code_generic_incorrect: "কোডটি সঠিক নয় নিশ্চিত করুন।", + confirm_code_generic_too_many_requests: "অনুরোধের সংখ্যা বেশি হয়েছে, দয়া করে পরে আবার চেষ্টা করুন।", + confirm_code_generic_submit: "কোডটি নিশ্চিত করুন", confirm_code_generic_try_again: "আবার চেষ্টা করুন", - confirm_code_generic_title: "অনুমোদন কোড প্রবেশ করুন", - confirm_code_2fa_instruction: "আপনার অথেন্টিকেশন অ্যাপ্লিকেশন থেকে ৬-ডিজিট কোডটি প্রবেশ করুন।", + confirm_code_generic_title: "শিরোনাম অনুমোদন দিন", + confirm_code_2fa_instruction: "আপনার অথেন্টিকেশন অ্যাপ্লিকেশন থেকে ৬-ডিজিটের কোডটি প্রবেশ করুন।", confirm_code_2fa_submit_btn: "জমা দিন", confirm_code_2fa_title: "2FA কোড প্রবেশ করুন", - confirm_delete_multiple_items: "আপনি কি নিশ্চিত যে আপনি এই আইটেমগুলি স্থায়ীভাবে ডিলিট করে ফেলতে চান?", + confirm_delete_multiple_items: "আপনি কি নিশ্চিত যে আপনি এই আইটেমগুলি স্থায়ীভাবে মুছতে চান?", confirm_delete_single_item: "আপনি কি এই আইটেমটি স্থায়ীভাবে মুছতে চান?", - confirm_open_apps_log_out: "আপনার খোলা অ্যাপ আছে। আপনি কি নিশ্চিত যে আপনি লগ আউট করতে চান?", + confirm_open_apps_log_out: "আপনার খোলা অ্যাপ আছে। আপনি কি নিশ্চিত যে আপনি লগ আউট করতে চান?", confirm_new_password: "নতুন পাসওয়ার্ড নিশ্চিত করুন", - confirm_delete_user: "আপনি কি নিশ্চিত যে আপনি আপনার অ্যাকাউন্টটি মুছতে চান? আপনার সমস্ত ফাইল এবং ডেটা স্থায়ীভাবে মুছে ফেলা হবে। এই প্রক্রিয়া শেষে আগের ডেটা আর ফিরে পাওয়া যাবে না।", + confirm_delete_user: "আপনি কি নিশ্চিত যে আপনি আপনার অ্যাকাউন্টটি মুছতে চান? সমস্ত আপনার ফাইল এবং ডেটা স্থায়ীভাবে মুছে ফেলা হবে। এই ক্রিয়াটি ফিরে পাওয়া যাবে না।", confirm_delete_user_title: "অ্যাকাউন্ট মুছে ফেলুন?", confirm_session_revoke: "আপনি কি নিশ্চিত যে আপনি এই সেশনটি প্রত্যাহার করতে চান?", confirm_your_email_address: "আপনার ইমেল ঠিকানা নিশ্চিত করুন", contact_us: "যোগাযোগ করুন", - contact_us_verification_required: "এটি ব্যবহার করতে আপনার যাচাইযোগ্য ইমেল ঠিকানা থাকতে হবে।", + contact_us_verification_required: "যোগাযোগের জন্য যাচাইকরণ প্রয়োজন", contain: "অন্তর্ভুক্ত করুন", continue: "চালিয়ে যান", copy: "কপি", @@ -85,37 +85,37 @@ const bn = { current_password: "বর্তমান পাসওয়ার্ড", cut: "কাটুন", clock: "ঘড়ি", - clock_visible_hide: "লুকান - সর্বদা লুকিয়ে রাখা", - clock_visible_show: "দেখান - সর্বদা দৃশ্যমান", - clock_visible_auto: "অটো - ডিফল্ট, অটো মোডে শুধুমাত্র দৃশ্যমান।", - close_all: "সবকিছু বন্ধ করুন", + clock_visible_hide: "ঘড়ি লুকানো", + clock_visible_show: "ঘড়ি দৃশ্যমান", + clock_visible_auto: "ঘড়ি দৃশ্যমান অটো", + close_all: "সমস্ত বন্ধ করুন", created: "তৈরি করা হয়েছে", - date_modified: "তারিখ পরিবর্তন করা হয়েছে", + date_modified: "তারিখ পরিবর্তন", default: "ডিফল্ট", delete: "মুছে ফেলুন", delete_account: "অ্যাকাউন্ট মুছে ফেলুন", - delete_permanently: "চিরকালের জন্য মুছুন", + delete_permanently: "স্থায়ীভাবে মুছুন", deleting_file: "ফাইল মুছে ফেলা হচ্ছে %%", - deploy_as_app: "অ্যাপ্লিকেশন হিসেবে ডিপ্লয় করা হয়েছে", - descending: "অবতলভাবে", + deploy_as_app: "অ্যাপ্লিকেশন হিসেবে ডিপ্লয়", + descending: "নিম্নক্রমে", desktop: "ডেস্কটপ", desktop_background_fit: "ফিট", developers: "ডেভেলপারগণ", dir_published_as_website: `%strong% প্রকাশিত হয়েছে:`, - disable_2fa: "2FA বন্ধ করুন", - disable_2fa_confirm: "আপনি কি নিশ্চিত যে আপনি 2FA বন্ধ করতে চান?", - disable_2fa_instructions: "2FA বন্ধ করতে আপনার পাসওয়ার্ড লিখুন।", - disassociate_dir: "ডিরেক্টরি আনসোসিএট করুন", + disable_2fa: "2FA অক্ষম করুন", + disable_2fa_confirm: "আপনি কি নিশ্চিত যে আপনি 2FA অক্ষম করতে চান?", + disable_2fa_instructions: "2FA অক্ষম করতে আপনার পাসওয়ার্ড লিখুন।", + disassociate_dir: "ডিরেক্টরি অমিল করুন", documents: "ডকুমেন্টস", - dont_allow: "অনুমতি দিবেন না", + dont_allow: "অনুমতি নেই", download: "ডাউনলোড", download_file: "ফাইল ডাউনলোড করুন", downloading: "ডাউনলোড হচ্ছে", - email: "ইমেল", - email_change_confirmation_sent: "নতুন ইমেল ঠিকানা নিশ্চিতকরণের জন্য একটি নিশ্চিতকরণ ইমেল পাঠানো হয়েছে। আপনার ইনবক্স পরীক্ষা করুন এবং নির্দেশানুযায়ী প্রক্রিয়াটি সম্পন্ন করুন।", - email_invalid: "ইমেলটি বৈধ নয়।", - email_or_username: "ইমেল বা ইউজারনেম", - email_required: "ইমেল প্রয়োজন।", + email: "ই-মেইল", + email_change_confirmation_sent: "নতুন ই-মেইল ঠিকানা নিশ্চিতকরণের জন্য একটি নিশ্চিতকরণ ইমেল পাঠানো হয়েছে। আপনার ইনবক্স পরীক্ষা করুন এবং নির্দেশানুযায়ী প্রক্রিয়াটি সম্পন্ন করুন।", + email_invalid: "ই-মেইল অবৈধ।", + email_or_username: "ই-মেইল বা ইউজারনেম", + email_required: "ই-মেইল প্রয়োজন।", empty_trash: "খালি ট্র্যাশ", empty_trash_confirmation: `আপনি কি নিশ্চিত যে আপনি ট্র্যাশে আইটেমগুলি স্থায়ীভাবে মুছতে চান?`, emptying_trash: "ট্র্যাশ খালি করা হচ্ছে…", @@ -124,23 +124,23 @@ const bn = { end_process_force_confirm: "আপনি কি নিশ্চিত যে আপনি এই প্রক্রিয়াটি ফোর্স-কুইট করতে চান?", end_soft: "সফট শেষ", enlarged_qr_code: "বড় QR কোড", - enter_password_to_confirm_delete_user: "অ্যাকাউন্ট মুছতে নিশ্চিত করতে আপনার পাসওয়ার্ড লিখুন", + enter_password_to_confirm_delete_user: "অ্যাকাউন্ট মুছা নিশ্চিত করতে আপনার পাসওয়ার্ড লিখুন", error_message_is_missing: "ত্রুটি বার্তাটি অনুপস্থিত।", error_unknown_cause: "অজানা কারণে একটি অজানা ত্রুটি ঘটেছে।", error_uploading_files: "ফাইল আপলোড করতে ব্যর্থ", favorites: "প্রিয়", feedback: "প্রতিক্রিয়া", feedback_c2a: "নীচের ফর্মটি ব্যবহার করে আপনার মতামত, মন্তব্য এবং বাগ রিপোর্ট প্রেরণ করুন।", - feedback_sent_confirmation: "আমাদের সাথে যোগাযোগ করার জন্য ধন্যবাদ। আপনার একাউন্টে ইমেল সংযোজন থাকলে আমরা যত তাড়াতাড়ি সম্ভব আপনার কাছে ফিরে আসতে পারবো।", + feedback_sent_confirmation: "আমাদের সাথে যোগাযোগ করার জন্য ধন্যবাদ। আপনার একাউন্টে ই-মেইল সংযোজন থাকলে আমরা যত তাড়াতাড়ি সম্ভব প্রতিক্রিয়া জানাবো", fit: "ফিট", folder: "ফোল্ডার", - force_quit: "জোর করে বন্ধ করা", + force_quit: "জোরালোভাবে বন্ধ", forgot_pass_c2a: "পাসওয়ার্ড ভুলে গেছেন?", from: "থেকে", general: "সাধারণ", get_a_copy_of_on_puter: `পিউটার ডটকমে '%%' এর একটি অনুলিপি পান!`, get_copy_link: "কপি লিংক নিন", - hide_all_windows: "সমস্ত উইন্ডো ঢেকে ফেলুন", + hide_all_windows: "সমস্ত উইন্ডো লুকান", home: "হোম", html_document: "এইচটিএমএল ডকুমেন্ট", hue: "হিউ", @@ -148,12 +148,12 @@ const bn = { incorrect_password: "ভুল পাসওয়ার্ড", invite_link: "আমন্ত্রণ লিংক", item: "আইটেম", - items_in_trash_cannot_be_renamed: `এই আইটেমটির নাম পরিবর্তন করা যাবে না কারণ এটি ট্র্যাশে রয়েছে। এই আইটেমটির নাম পরিবর্তন করতে, প্রথমে এটি ট্র্যাশ থেকে তুলে নিন।`, + items_in_trash_cannot_be_renamed: `এই আইটেমটি নাম পরিবর্তন করা যাবে না কারণ এটি ট্র্যাশে রয়েছে। এই আইটেমটির নাম পরিবর্তন করতে, প্রথমে এটি ট্র্যাশ থেকে তুলে নিন।`, jpeg_image: "জেপিইজি ইমেজ", keep_in_taskbar: "টাস্কবারে রাখুন", language: "ভাষা", license: "লাইসেন্স", - lightness: "হালকার মতো", + lightness: "উজ্জ্বলতা", link_copied: "লিংক কপি করা হয়েছে", loading: "লোড হচ্ছে", log_in: "লগ ইন করুন", @@ -162,7 +162,7 @@ const bn = { looks_good: "ভাল দেখা যাচ্ছে!", manage_sessions: "সেশন পরিচালনা করুন", menubar_style: "মেনুবার স্টাইল", - menubar_style_desktop: "ডেস্কটপ", + menubar_style_desktop: "ডেস্কটপ মেনুবার স্টাইল", menubar_style_system: "সিস্টেম", menubar_style_window: "উইন্ডো", modified: "পরিবর্তিত", @@ -171,13 +171,13 @@ const bn = { my_websites: "আমার ওয়েবসাইটগুলি", name: "নাম", name_cannot_be_empty: "নাম ফাঁকা রাখা যাবে না।", - name_cannot_contain_double_period: "নাম অবশ্যই '..' অক্ষর হতে পারে না।", - name_cannot_contain_period: "নাম অবশ্যই '.' অক্ষর হতে পারে না।", - name_cannot_contain_slash: "নাম '/' অক্ষর ধারণ করতে পারে না।", + name_cannot_contain_double_period: "নামে অবশ্যই '..' অক্ষর হতে পারবে না।", + name_cannot_contain_period: "নামে অবশ্যই '.' অক্ষর হতে পারবে না।", + name_cannot_contain_slash: "নামে '/' অক্ষর ধারণ করতে পারবে না।", name_must_be_string: "নামটি শুধুমাত্র একটি স্ট্রিং হতে পারে।", - name_too_long: `নাম %% অক্ষরের চেয়ে বেশি হতে পারে না।`, + name_too_long: `নাম %% অক্ষরের চেয়ে বেশি হতে পারবে না।`, new: "নতুন", - new_email: "নতুন ইমেল", + new_email: "নতুন ই-মেইল", new_folder: "নতুন ফোল্ডার", new_password: "নতুন পাসওয়ার্ড", new_username: "নতুন ব্যবহারকারীর নাম", @@ -187,26 +187,26 @@ const bn = { ok: "ঠিক আছে", open: "খোলা", open_in_new_tab: "নতুন ট্যাবে খুলুন", - open_in_new_window: "নতুন উইন্ডোতে খুলুন", - open_with: "দিয়ে খুলুন", - original_name: "মৌলিক নাম", + open_in_new_window: "নতুন উইন্ডোয়ে খুলুন", + open_with: "দিয়ে খোলুন", + original_name: "মূল নাম", original_path: "মূল পথ", oss_code_and_content: "ওপেন সোর্স সফটওয়্যার এবং কন্টেন্ট", password: "পাসওয়ার্ড", password_changed: "পাসওয়ার্ড পরিবর্তন করা হয়েছে।", - password_recovery_rate_limit: "আপনি আমাদের রিকভারি সিস্টেমে প্রতি দিনে অধিকতর পাঁচবার ব্যবহার করতে পারবেন না। দয়া করে কয়েক ঘণ্টা অপেক্ষা করুন এবং পুনরায় চেষ্টা করুন।", - password_recovery_sent: "আপনার পাসওয়ার্ড পুনরুদ্ধারের জন্য নির্দেশানুযায়ী একটি ইমেল পাঠানো হয়েছে।", - password_requirements: "পাসওয়ার্ড অবশ্যই অবশ্যই ৮ অক্ষরের বড় অক্ষর থাকতে হবে।", + password_recovery_rate_limit: "আপনি আমাদের রেকভারি সিস্টেমে প্রতি দিনে অধিকতর পাঁচবার ব্যবহার করতে পারবেন না। দয়া করে কয়েক ঘণ্টা অপেক্ষা করুন এবং পুনরায় চেষ্টা করুন।", + password_recovery_sent: "আপনার পাসওয়ার্ড পুনরুদ্ধারের জন্য নির্দেশানুযায়ী একটি ই-মেইল পাঠানো হয়েছে।", + password_requirements: "পাসওয়ার্ড অবশ্যই অবশ্যই ৮ অক্ষরের হতে হবে।", password_reset: "পাসওয়ার্ড রিসেট করুন", password_reset_confirmation: "পাসওয়ার্ড সেট করতে নীচের ফর্মটি পূরণ করুন।", password_reset_request_expired: "আপনার পাসওয়ার্ড রিসেট রিকোয়েস্টের মেয়াদ শেষ হয়ে গেছে। দয়া করে পুনরায় চেষ্টা করুন।", - password_reset_sent: "পাসওয়ার্ড রিসেট রিকোয়েস্ট সফলভাবে প্রেরিত হয়েছে। আপনার ইনবক্স পরীক্ষা করুন এবং নির্দেশানুযায়ী প্রক্রিয়াটি সম্পন্ন করুন।", + password_reset_sent: "পাসওয়ার্ড রিসেট রিকোয়েস্ট সফলভাবে প্রেরিত হয়েছে। আপনার ইনবক্স দেখুন এবং নির্দেশানুযায়ী প্রক্রিয়াটি সম্পন্ন করুন।", password_update_success: "পাসওয়ার্ড সফলভাবে আপডেট হয়েছে!", - passwords_do_not_match: "পাসওয়ার্ড মিলছে না", + passwords_do_not_match: "পাসওয়ার্ড মিল নেই", paste: "পেস্ট", paste_into_folder: "ফোল্ডারে পেস্ট করুন", path: "পথ", - personalization: "ব্যক্তিগতকরণ", + personalization: "ব্যক্তিগতীকরণ", pick_name_for_website: "আপনার ওয়েবসাইটের জন্য নাম নির্বাচন করুন:", picture: "ছবি", pictures: "চিত্র", @@ -217,8 +217,8 @@ const bn = { print: "প্রিন্ট", privacy: "গোপনীয়তা", proceed_to_login: "লগইনে অগ্রসর হোন", - proceed_with_account_deletion: "অ্যাকাউন্ট মোছার সাথে অগ্রসর হন", - process_status_initializing: "আসন্নকরণ চলছে", + proceed_with_account_deletion: "অ্যাকাউন্ট মোছার জন্য অগ্রসর হন", + process_status_initializing: "প্রাথমিককরণ হচ্ছে", process_status_running: "চলছে", process_type_app: "অ্যাপ", process_type_init: "প্রাথমিকতা", @@ -227,22 +227,22 @@ const bn = { public: "পাবলিক", publish: "প্রকাশ করুন", publish_as_website: "ওয়েবসাইট হিসাবে প্রকাশ করুন", - puter_description: `Puter হল একটি গোপনীয়তা-প্রথম ব্যক্তিগত ক্লাউড, যেখানে আপনার সমস্ত ফাইল, অ্যাপ্লিকেশন এবং গেম একটি নিরাপদ জায়গায় রাখা হয়, যেখান থেকে সর্বক্ষণে অ্যাক্সেস করা যায়।`, + puter_description: `Puter হল একটি গোপনীয়তা-প্রথম ব্যক্তিগত ক্লাউড, যেখানে আপনার সমস্ত ফাইল, অ্যাপ্লিকেশন এবং গেম একটি নিরাপদ জায়গায় রাখা হয়, যেখান থেকে যে কোনো সময় অ্যাক্সেস করা যায়।`, reading_file: "%strong% পড়া হচ্ছে", recent: "সাম্প্রতিক", recommended: "অনুমোদিত", recover_password: "পাসওয়ার্ড পুনরুদ্ধার করুন", - refer_friends_c2a: "Puter তে অ্যাকাউন্ট তৈরি এবং নিশ্চিতকরণ করে একটি বন্ধুকে রেফার করার জন্য প্রতি রেফারে ১ জিবি পান। আপনার বন্ধুও ১ জিবি পাবে!", - refer_friends_social_media_c2a: `Puter.com এ ১ জিবি বিনামূল্যের সংরক্ষণ পান!`, + refer_friends_c2a: "Puter তে অ্যাকাউন্ট তৈরি এবং নিশ্চিতকরণ করে ১ জিবি পান। আপনার বন্ধুও ১ জিবি পাবে!", + refer_friends_social_media_c2a: `Puter.com এ 1 GB বিনামূল্যের সংরক্ষণ পান!`, refresh: "রিফ্রেশ", release_address_confirmation: `আপনি কি নিশ্চিত যে আপনি এই ঠিকানা রিলিজ করতে চান?`, remove_from_taskbar: "টাস্কবার থেকে সরান", rename: "পুনঃনামকরণ", repeat: "পুনরাবৃত্তি", - replace: "প্রতিস্থাপন", - replace_all: "সমস্তকিছু প্রতিস্থাপন করে ফেলুন", + replace: "বদলান", + replace_all: "সকল কিছু বদলান", resend_confirmation_code: "পুনরায় নিশ্চিতকরণ কোড প্রেরণ করুন", - reset_colors: "রঙ আগেরমত করুন", + reset_colors: "রঙ পুনঃনির্ধারণ করুন", restart_puter_confirm: "আপনি কি নিশ্চিত যে Puter পুনরায় চালু করতে চান?", restore: "পুনরুদ্ধার", save: "সংরক্ষণ করুন", @@ -251,7 +251,7 @@ const bn = { save_account_to_get_copy_link: "অগ্রসর হতে অ্যাকাউন্ট তৈরি করুন।", save_account_to_publish: "অগ্রসর হতে অ্যাকাউন্ট তৈরি করুন।", save_session: "সেশন সংরক্ষণ করুন", - save_session_c2a: "আপনার বর্তমান সেশনটি সংরক্ষণ করতে একটি অ্যাকাউন্ট তৈরি করুন এবং আপনার কাজ হারাতে হবেনা।", + save_session_c2a: "আপনার বর্তমান সেশনটি সংরক্ষণ করতে একটি অ্যাকাউন্ট তৈরি করুন যাতে আপনার কাজ হারাতে না হয়।", scan_qr_c2a: "অন্যান্য ডিভাইস থেকে এই সেশনে লগইন করতে নীচের কোডটি স্ক্যান করুন", scan_qr_2fa: "আপনার প্রামাণিকতা অ্যাপ্লিকেশন দিয়ে QR কোডটি স্ক্যান করুন", scan_qr_generic: "আপনার ফোন বা অন্য ডিভাইস ব্যবহার করে এই QR কোড স্ক্যান করুন", @@ -267,8 +267,8 @@ const bn = { session_saved: "অ্যাকাউন্ট তৈরি করার জন্য ধন্যবাদ। এই সেশনটি সংরক্ষিত হয়েছে।", settings: "সেটিংস", set_new_password: "নতুন পাসওয়ার্ড সেট করুন", - share: "ভাগাভাগি করুন", - share_to: "শেয়ার করুন", + share: "শেয়ার করুন", + share_to: "শেয়ার করুন প্রতি", share_with: "সঙ্গে ভাগাভাগি করুন:", shortcut_to: "শর্টকাট", show_all_windows: "সমস্ত উইন্ডো দেখান", @@ -277,7 +277,7 @@ const bn = { sign_up: "নিবন্ধন করুন", signing_in: "সাইন ইন হচ্ছে...", size: "আকার", - skip: "এটি বাদ দিন", + skip: "এড়িয়ে যান", something_went_wrong: "কিছু সমস্যা হয়েছে।", sort_by: "অনুযায়ী সাজান", start: "শুরু", @@ -295,17 +295,17 @@ const bn = { transparency: "স্বচ্ছতা", trash: "আবর্জনা", two_factor: "দুটি ফ্যাক্টর প্রমাণীকরণ", - two_factor_disabled: "2FA বন্ধ করা হয়েছে", - two_factor_enabled: "2FA চালু করা হয়েছে", + two_factor_disabled: "2FA অক্ষম", + two_factor_enabled: "2FA সক্ষম", type: "ধরণ", type_confirm_to_delete_account: "অ্যাকাউন্ট মোছার জন্য 'অনুমোদন' টাইপ করুন।", ui_colors: "ইউআই রঙ", ui_manage_sessions: "সেশন ম্যানেজার", ui_revoke: "প্রত্যাহার করুন", - undo: "আনডু করুন", + undo: "পূর্বাবস্থায় ফেরত যান", unlimited: "অসীম", - unzip: "আনজিপ", - upload: "আপলোড", + unzip: "আনজিপ করুন", + upload: "আপলোড করুন", upload_here: "এখানে আপলোড করুন", usage: "ব্যবহার", username: "ব্যবহারকারীর নাম", @@ -316,14 +316,14 @@ const bn = { visibility: "দৃশ্যমানতা", yes: "হ্যাঁ", yes_release_it: "হ্যাঁ, এটি রিলিজ করুন", - you_have_been_referred_to_puter_by_a_friend: "আপনাকে একটি বন্ধু দ্বারা Puter এ উল্লিখিত করা হয়েছে!", + you_have_been_referred_to_puter_by_a_friend: "আপনাকে একটি বন্ধুর মাধ্যমে পিউটার-এ রেফার করা হয়েছে", zip: "জিপ", zipping_file: "%strong% জিপিং হচ্ছে", // === 2FA Setup === setup2fa_1_step_heading: "আপনার প্রামাণিকতা অ্যাপ খুলুন", setup2fa_1_instructions: ` - আপনি যেকোনো অথেনটিকেশন অ্যাপ ব্যবহার করতে পারেন যা Time-based One-Time Password (TOTP) প্রোটোকল সমর্থন করে। + আপনি যেকোনো প্রামাণিকতা অ্যাপ ব্যবহার করতে পারেন যা Time-based One-Time Password (TOTP) প্রোটোকল সমর্থন করে। অনেক বিকল্প রয়েছে, তবে যদি আপনি নিশ্চিত না হন Authy একটি ভালো পছন্দ Android এবং iOS এর জন্য। @@ -332,7 +332,7 @@ const bn = { setup2fa_3_step_heading: "৬-টি অংকের কোড লিখুন", setup2fa_4_step_heading: "আপনার পুনরুদ্ধার কোড কপি করুন", setup2fa_4_instructions: ` - এই পুনরুদ্ধার কোডগুলি আপনার অ্যাকাউন্টে অ্যাক্সেস পাওয়ার একমাত্র উপায়। যদি আপনি আপনার ফোন হারিয়ে ফেলেন বা আপনার প্রামাণিকতা অ্যাপ ব্যবহার করতে না পারেন, তবে + এই পুনরুদ্ধার কোডগুলি আপনার অ্যাকাউন্টে অ্যাক্সেস পাওয়ার একমাত্র উপায় যদি আপনি আপনার ফোন হারান বা আপনার প্রামাণিকতা অ্যাপ ব্যবহার করতে না পারেন। নিশ্চিত করুন যে আপনি তাদের একটি নিরাপদ জায়গায় সংরক্ষণ করেছেন। `, setup2fa_5_step_heading: "2FA সেটআপ নিশ্চিত করুন", @@ -349,24 +349,29 @@ const bn = { login2fa_recovery_back: "পিছনে", login2fa_recovery_placeholder: "XXXXXXXX", - "change": "পরিবর্তন", // In English: "Change" - "clock_visibility": "ঘড়ির দৃশ্যমানতা", // In English: "Clock Visibility" - "password_recovery_token_invalid": "এই পাসওয়ার্ড রিকোভারি টোকেনটি আর ব্যবহারযোগ্য নয়।", // In English: "This password recovery token is no longer valid." - "password_recovery_unknown_error": "একটি অজানা ত্রুটি ঘটেছে. অনুগ্রহ করে পরবর্তীতে আবার চেষ্টা করুন।", // In English: "An unknown error occurred. Please try again later." - "password_required": "পাসওয়ার্ড প্রযোজ্য।", // In English: "Password is required." - "password_strength_error": "পাসওয়ার্ড অন্ততপক্ষে 8 অক্ষরবিশিষ্ট দীর্ঘ হতে হবে এবং কমপক্ষে একটি বড় হাতের অক্ষর, একটি ছোট হাতের অক্ষর, একটি সংখ্যা এবং একটি বিশেষ অক্ষর থাকতে হবে৷", // In English: "Password must be at least 8 characters long and contain at least one uppercase letter, one lowercase letter, one number, and one special character." - "reading": "%strong% পড়ছে", // In English: "Reading %strong%" - "writing": "%strong% লিখছে", // In English: "Writing %strong%" - "unzipping": "%strong% আনজিপিং হচ্ছে", // In English: "Unzipping %strong%" - "sequencing": "%strong% ক্রমানুসারে করা হচ্ছে", // In English: "Sequencing %strong%" - "zipping": "%strong% জিপ করা হচ্ছে", // In English: "Zipping %strong%" - "Editor": "সম্পাদক", // In English: "Editor" - "Viewer": "দর্শক", // In English: "Viewer" - "People with access": "মানুষ যাদের প্রবেশাধিকার আছে", // In English: "People with access" - "Share With…": "শেয়ার করুন...", // In English: "Share With…" - "Owner": "মালিক", // In English: "Owner" - "You can't share with yourself.": "আপনি নিজের সাথে শেয়ার করতে পারবেন না।", // In English: "You can't share with yourself." - "This user already has access to this item": "এই ব্যবহারকারীর ইতিমধ্যেই এই আইটেমে প্রবেশাধিকার আছে।", // In English: "This user already has access to this item" + // *********************************** + // Missing translations + // *********************************** + "change": "পরিবর্তন", + "clock_visibility": + "ঘড়ির দৃশ্যমানতা", + "password_recovery_token_invalid": "এই পাসওয়ার্ড পুনরুদ্ধার টোকেনটি আর বৈধ নয়।", + "password_recovery_unknown_error": "একটি অজানা ত্রুটি ঘটেছে। দয়া করে পরে আবার চেষ্টা করুন।", + "password_required": "পাসওয়ার্ড প্রয়োজন", + "password_strength_error": "পাসওয়ার্ডটি কমপক্ষে ৮টি অক্ষরের হতে হবে এবং এতে কমপক্ষে একটি বড় অক্ষর, একটি ছোট অক্ষর, একটি সংখ্যা এবং একটি বিশেষ চিহ্ন থাকতে হবে।", + "reading": "পড়া %strong%", + "writing": "লেখা %strong%", + "unzipping": "আনজিপ করা %strong%", + "sequencing": "সিকোয়েন্সিং %strong%", + "zipping": "জিপ করা %strong%", + "Editor": "সম্পাদক", + "Viewer": "ভিউয়ার", + "People with access": "অ্যাক্সেস থাকা মানুষরা", + "Share With…": "অন্যদের সাথে শেয়ার করুন", + "Owner": "মালিক", + "You can't share with yourself.": "আপনি নিজের সাথে শেয়ার করতে পারবেন না।", + "This user already has access to this item": "এই ব্যবহারকারীর ইতিমধ্যেই এই আইটেমে অ্যাক্সেস রয়েছে।", + }, }; From ac4cc95be50430af3223b511931a066f880a866e Mon Sep 17 00:00:00 2001 From: jelveh Date: Wed, 20 Nov 2024 10:26:21 -0800 Subject: [PATCH 1269/2119] Update ar.js --- src/gui/src/i18n/translations/ar.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/gui/src/i18n/translations/ar.js b/src/gui/src/i18n/translations/ar.js index d5db271270..ae3de86376 100644 --- a/src/gui/src/i18n/translations/ar.js +++ b/src/gui/src/i18n/translations/ar.js @@ -369,9 +369,6 @@ const ar = { login2fa_recovery_back: "الرجوع", login2fa_recovery_placeholder: "XXXXXXXX", - // *********************************** - // Missing translations - // *********************************** change: "تغيير", // In English: "Change" clock_visibility: "ظهور الساعة", // In English: "Clock Visibility" reading: "قراءة %strong%", // In English: "Reading %strong%" From d0bf94c5d0193f8e033b46363eefc383271f3ac3 Mon Sep 17 00:00:00 2001 From: jelveh Date: Wed, 20 Nov 2024 11:18:59 -0800 Subject: [PATCH 1270/2119] Update bn.js --- src/gui/src/i18n/translations/bn.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/gui/src/i18n/translations/bn.js b/src/gui/src/i18n/translations/bn.js index 9db99b0188..201cc781c8 100644 --- a/src/gui/src/i18n/translations/bn.js +++ b/src/gui/src/i18n/translations/bn.js @@ -349,9 +349,6 @@ const bn = { login2fa_recovery_back: "পিছনে", login2fa_recovery_placeholder: "XXXXXXXX", - // *********************************** - // Missing translations - // *********************************** "change": "পরিবর্তন", "clock_visibility": "ঘড়ির দৃশ্যমানতা", From 4396630453a46c0a6e877417e470362a42c84161 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 20 Nov 2024 13:53:01 -0500 Subject: [PATCH 1271/2119] dev: add /acl/stat-user-user This new endpoint shows permissions granted by the current user to the specified user in the scope of a specified filesystem node, including permissions on the affecting parent nodes. This is related to two future tasks: - prevent users from sharing a file with the same user twice - add an endpoint to modify the access mode of a shared file --- src/backend/src/services/auth/ACLService.js | 87 +++++++++++++++++++ .../src/services/auth/PermissionService.js | 28 ++++++ 2 files changed, 115 insertions(+) diff --git a/src/backend/src/services/auth/ACLService.js b/src/backend/src/services/auth/ACLService.js index 54a3ae491c..5cf26ca88d 100644 --- a/src/backend/src/services/auth/ACLService.js +++ b/src/backend/src/services/auth/ACLService.js @@ -17,13 +17,21 @@ * along with this program. If not, see . */ const APIError = require("../../api/APIError"); +const FSNodeParam = require("../../api/filesystem/FSNodeParam"); const { NodePathSelector } = require("../../filesystem/node/selectors"); +const { get_user } = require("../../helpers"); +const configurable_auth = require("../../middleware/configurable_auth"); const { Context } = require("../../util/context"); +const { Endpoint } = require("../../util/expressutil"); const BaseService = require("../BaseService"); const { AppUnderUserActorType, UserActorType, Actor, SystemActorType, AccessTokenActorType } = require("./Actor"); const { PermissionUtil } = require("./PermissionService"); class ACLService extends BaseService { + static MODULES = { + express: require('express'), + }; + async _init () { const svc_featureFlag = this.services.get('feature-flag'); svc_featureFlag.register('public-folders', { @@ -44,6 +52,85 @@ class ACLService extends BaseService { }); } + async ['__on_install.routes'] (_, { app }) { + const r_acl = (() => { + const require = this.require; + const express = require('express'); + return express.Router(); + })(); + + app.use('/acl', r_acl); + + Endpoint({ + route: '/stat-user-user', + methods: ['POST'], + mw: [configurable_auth()], + handler: async (req, res) => { + // Only user actor is allowed + if ( ! (req.actor.type instanceof UserActorType) ) { + return res.status(403).json({ + error: 'forbidden', + }); + } + + const holder_user = await get_user({ + username: req.body.user, + }); + + if ( ! holder_user ) { + throw APIError.create('user_does_not_exist', null, { + username: req.body.user, + }); + } + + const issuer = req.actor; + const holder = new Actor({ + type: new UserActorType({ + user: holder_user, + }), + }); + + const node = await (new FSNodeParam('path')).consolidate({ + req, + getParam: () => req.body.resource, + }); + + const permissions = await this.stat_user_user(issuer, holder, node); + + res.json({ permissions }); + } + }).attach(r_acl); + } + + async stat_user_user (issuer, holder, resource) { + const svc_perm = this.services.get('permission'); + + if ( ! (issuer.type instanceof UserActorType) ) { + throw new Error('issuer must be a UserActorType'); + } + if ( ! (holder.type instanceof UserActorType) ) { + throw new Error('holder must be a UserActorType'); + } + + const permissions = {}; + + let perm_fsNode = resource; + while ( ! await perm_fsNode.get('is-root') ) { + const prefix = PermissionUtil.join('fs', await perm_fsNode.get('uid')); + + const these_permissions = await + svc_perm.query_issuer_holder_permissions_by_prefix(issuer, holder, prefix); + + if ( these_permissions.length > 0 ) { + permissions[await perm_fsNode.get('path')] = these_permissions; + } + + perm_fsNode = await perm_fsNode.getParent(); + } + + return permissions; + } + async _check_fsNode (actor, fsNode, mode) { const context = Context.get(); diff --git a/src/backend/src/services/auth/PermissionService.js b/src/backend/src/services/auth/PermissionService.js index 59d42d9196..2f0651d84b 100644 --- a/src/backend/src/services/auth/PermissionService.js +++ b/src/backend/src/services/auth/PermissionService.js @@ -638,6 +638,34 @@ class PermissionService extends BaseService { return retval; } + + /** + * List the permissions that the specified actor (the "issuer") + * has granted to the specified user (the "holder") which have + * some specified prefix in the permission key (ex: "fs:FILE-UUID") + * + * Note that if the prefix contains a literal '%' character + * the behavior may not be as expected. + * + * This is a "flat" (non-cascading) view. + * + * @param {*} issuer + * @param {*} holder + * @param {*} prefix + * @returns + */ + async query_issuer_holder_permissions_by_prefix (issuer, holder, prefix) { + const user_perms = await this.db.read( + 'SELECT permission ' + + 'FROM `user_to_user_permissions` ' + + 'WHERE issuer_user_id = ? ' + + 'AND holder_user_id = ? ' + + 'AND permission LIKE ?', + [issuer.type.user.id, holder.type.user.id, prefix + '%'], + ); + + return user_perms.map(row => row.permission); + } async get_higher_permissions (permission) { const higher_perms = new Set() From 70d8e837afc215eed398f732f03f073275461ade Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 20 Nov 2024 15:23:46 -0500 Subject: [PATCH 1272/2119] dev: prevent sharing a file to the same user twice --- src/backend/src/services/ShareService.js | 12 +-- src/backend/src/services/auth/ACLService.js | 77 ++++++++++++++++++++ src/backend/src/structured/sequence/share.js | 21 ++++-- 3 files changed, 99 insertions(+), 11 deletions(-) diff --git a/src/backend/src/services/ShareService.js b/src/backend/src/services/ShareService.js index c5bb1a6acb..1af815648d 100644 --- a/src/backend/src/services/ShareService.js +++ b/src/backend/src/services/ShareService.js @@ -79,13 +79,13 @@ class ShareService extends BaseService { user: issuer_user, }); - const svc_permission = this.services.get('permission'); + // const svc_permission = this.services.get('permission'); + const svc_acl = this.services.get('acl'); for ( const permission of share.data.permissions ) { - await svc_permission.grant_user_user_permission( - issuer_actor, - user.username, - permission, + await svc_acl.set_user_user( + issuer_actor, user.username, permission, undefined, + { only_if_higher: true }, ); } @@ -96,7 +96,7 @@ class ShareService extends BaseService { } }); } - + ['__on_install.routes'] (_, { app }) { this.install_sharelink_endpoints({ app }); this.install_share_endpoint({ app }); diff --git a/src/backend/src/services/auth/ACLService.js b/src/backend/src/services/auth/ACLService.js index 5cf26ca88d..95040f53fa 100644 --- a/src/backend/src/services/auth/ACLService.js +++ b/src/backend/src/services/auth/ACLService.js @@ -102,6 +102,83 @@ class ACLService extends BaseService { }).attach(r_acl); } + async set_user_user (issuer, holder, resource, mode, options = {}) { + const svc_perm = this.services.get('permission'); + const svc_fs = this.services.get('filesystem'); + + if ( typeof holder === 'string' ) { + const holder_user = await get_user({ username: holder }); + if ( ! holder_user ) { + throw APIError.create('user_does_not_exist', null, { username: holder }); + } + + holder = new Actor({ + type: new UserActorType({ user: holder_user }), + }); + } + + let uid, _; + + if ( typeof resource === 'string' && mode === undefined ) { + const perm_parts = PermissionUtil.split(resource); + ([_, uid, mode] = perm_parts); + resource = await svc_fs.node(new NodePathSelector(uid)); + if ( ! resource ) { + throw APIError.create('subject_does_not_exist'); + } + } + + if ( ! (issuer.type instanceof UserActorType) ) { + throw new Error('issuer must be a UserActorType'); + } + if ( ! (holder.type instanceof UserActorType) ) { + throw new Error('holder must be a UserActorType'); + } + + const stat = await this.stat_user_user(issuer, holder, resource); + + // this.log.info('stat object', { + // stat, + // path: await resource.get('path') + // }); + + const perms_on_this = stat[await resource.get('path')] ?? []; + + const mode_parts = perms_on_this.map(perm => PermissionUtil.split(perm)[2]); + + // If mode already present, do nothing + if ( mode_parts.includes(mode) ) { + return false; + } + + // If higher mode already present, do nothing + if ( options.only_if_higher ) { + const higher_modes = this._higher_modes(mode); + if ( mode_parts.some(m => higher_modes.includes(m)) ) { + return false; + } + } + + uid = uid ?? await resource.get('uid'); + + // If mode not present, add it + await svc_perm.grant_user_user_permission( + issuer, holder.type.user.username, + PermissionUtil.join('fs', uid, mode), + ); + + // Remove other modes + for ( const perm of perms_on_this ) { + const perm_parts = PermissionUtil.split(perm); + if ( perm_parts[2] === mode ) continue; + + await svc_perm.revoke_user_user_permission( + issuer, holder.type.user.username, + perm, + ); + } + } + async stat_user_user (issuer, holder, resource) { const svc_perm = this.services.get('permission'); diff --git a/src/backend/src/structured/sequence/share.js b/src/backend/src/structured/sequence/share.js index b59fd4e207..c06f9252cb 100644 --- a/src/backend/src/structured/sequence/share.js +++ b/src/backend/src/structured/sequence/share.js @@ -484,6 +484,7 @@ module.exports = new Sequence([ } = a.values(); const svc_permission = a.iget('services').get('permission'); + const svc_acl = a.iget('services').get('acl'); const svc_notification = a.iget('services').get('notification'); const svc_email = a.iget('services').get('email'); @@ -497,11 +498,21 @@ module.exports = new Sequence([ for ( const share_item of shares_work.list() ) { const permissions = share_item.share_intent.permissions; for ( const perm of permissions ) { - await svc_permission.grant_user_user_permission( - actor, - username, - perm, - ); + if ( perm.startsWith('fs:') ) { + await svc_acl.set_user_user( + actor, + username, + perm, + undefined, + { only_if_higher: true }, + ); + } else { + await svc_permission.grant_user_user_permission( + actor, + username, + perm, + ); + } } } From c7419d18df56fe7791b16e89ac505828cafad815 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 20 Nov 2024 15:36:00 -0500 Subject: [PATCH 1273/2119] dev: add /acl/set-user-user --- src/backend/src/services/auth/ACLService.js | 40 +++++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/src/backend/src/services/auth/ACLService.js b/src/backend/src/services/auth/ACLService.js index 95040f53fa..1cee1bdd71 100644 --- a/src/backend/src/services/auth/ACLService.js +++ b/src/backend/src/services/auth/ACLService.js @@ -100,6 +100,46 @@ class ACLService extends BaseService { res.json({ permissions }); } }).attach(r_acl); + + Endpoint({ + route: '/set-user-user', + methods: ['POST'], + mw: [configurable_auth()], + handler: async (req, res) => { + // Only user actor is allowed + if ( ! (req.actor.type instanceof UserActorType) ) { + return res.status(403).json({ + error: 'forbidden', + }); + } + + const holder_user = await get_user({ + username: req.body.user, + }); + + if ( ! holder_user ) { + throw APIError.create('user_does_not_exist', null, { + username: req.body.user, + }); + } + + const issuer = req.actor; + const holder = new Actor({ + type: new UserActorType({ + user: holder_user, + }), + }); + + const node = await (new FSNodeParam('path')).consolidate({ + req, + getParam: () => req.body.resource, + }); + + await this.set_user_user(issuer, holder, node, req.body.mode, req.body.options ?? {}); + + res.json({}); + } + }).attach(r_acl); } async set_user_user (issuer, holder, resource, mode, options = {}) { From 63d4a604fa389174f330fc8f660c752f179e73db Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 20 Nov 2024 12:53:02 -0800 Subject: [PATCH 1274/2119] Revert "Added missing translations for Bengali localization (#842)" From e6986d5216958ee7b2e49dbaa3b637a1401f3763 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 20 Nov 2024 17:01:24 -0500 Subject: [PATCH 1275/2119] dev: add share metadata and messages --- src/backend/src/services/EmailService.js | 8 ++++++++ src/backend/src/structured/sequence/share.js | 7 +++++++ 2 files changed, 15 insertions(+) diff --git a/src/backend/src/services/EmailService.js b/src/backend/src/services/EmailService.js index 21ddfab1b9..a11bd18ebb 100644 --- a/src/backend/src/services/EmailService.js +++ b/src/backend/src/services/EmailService.js @@ -138,6 +138,10 @@ If this was not you, please contact support@puter.com immediately.

Hi there {{rusername}},

You've received a share from {{susername}} on Puter.

Go to puter.com to check it out.

+ {{#if message}} +

The following message was included:

+
{{message}}
+ {{/if}}

Sincerely,

Puter

` @@ -148,6 +152,10 @@ If this was not you, please contact support@puter.com immediately.

Hi there,

You've received a share from {{sender_name}} on Puter:

{{link}}

+ {{#if message}} +

The following message was included:

+
{{message}}
+ {{/if}}

Sincerely,

Puter

` diff --git a/src/backend/src/structured/sequence/share.js b/src/backend/src/structured/sequence/share.js index c06f9252cb..31d9d1d46d 100644 --- a/src/backend/src/structured/sequence/share.js +++ b/src/backend/src/structured/sequence/share.js @@ -538,6 +538,8 @@ module.exports = new Sequence([ })); } } + + const metadata = a.get('req').body.metadata || {}; svc_notification.notify(UsernameNotifSelector(username), { source: 'sharing', @@ -545,6 +547,7 @@ module.exports = new Sequence([ title: 'Files were shared with you!', template: 'file-shared-with-you', fields: { + metadata, username: actor.type.user.username, files, }, @@ -564,6 +567,7 @@ module.exports = new Sequence([ // link: // TODO: create a link to the shared file susername: actor.type.user.username, rusername: username, + message: metadata.message, }); result.recipients[recipient_item.i] = @@ -583,10 +587,12 @@ module.exports = new Sequence([ const email = recipient_item.value; // data that gets stored in the `data` column of the share + const metadata = a.get('req').body.metadata || {}; const data = { $: 'internal:share', $v: 'v0.0.0', permissions: [], + metadata, }; for ( const share_item of shares_work.list() ) { @@ -616,6 +622,7 @@ module.exports = new Sequence([ await svc_email.send_email({ email }, 'share_by_email', { link: email_link, sender_name: actor.type.user.username, + message: metadata.message, }); } }, From 5e463e1db8d76aa8315a4f371fd462dc478000fe Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 20 Nov 2024 17:17:23 -0500 Subject: [PATCH 1276/2119] dev: validate metadata --- src/backend/src/structured/sequence/share.js | 62 ++++++++++++++++++++ 1 file changed, 62 insertions(+) diff --git a/src/backend/src/structured/sequence/share.js b/src/backend/src/structured/sequence/share.js index 31d9d1d46d..68391c6c15 100644 --- a/src/backend/src/structured/sequence/share.js +++ b/src/backend/src/structured/sequence/share.js @@ -28,6 +28,7 @@ const FSNodeParam = require("../../api/filesystem/FSNodeParam"); const { TYPE_DIRECTORY } = require("../../filesystem/FSNodeContext"); const { UsernameNotifSelector } = require("../../services/NotificationService"); const { quot } = require("../../util/strutil"); +const { whatis } = require("../../util/langutil"); /* This code is optimized for editors supporting folding. @@ -43,6 +44,67 @@ const { quot } = require("../../util/strutil"); module.exports = new Sequence([ + function validate_metadata (a) { + const req = a.get('req'); + const metadata = req.body.metadata; + + if ( ! metadata ) return; + + if ( typeof metadata !== 'object' ) { + throw APIError.create('field_invalid', null, { + key: 'metadata', + expected: 'object', + got: whatis(metadata), + }); + } + + const MAX_KEYS = 20; + const MAX_STRING = 255; + const MAX_MESSAGE_STRING = 10*1024; + + if ( Object.keys(metadata).length > MAX_KEYS ) { + throw APIError.create('field_invalid', null, { + key: 'metadata', + expected: `at most ${MAX_KEYS} keys`, + got: `${Object.keys(metadata).length} keys`, + }); + } + + for ( const key in metadata ) { + const value = metadata[key]; + if ( typeof value !== 'string' && typeof value !== 'number' ) { + throw APIError.create('field_invalid', null, { + key: `metadata.${key}`, + expected: 'string or number', + got: whatis(value), + }); + } + if ( key === 'message' ) { + if ( typeof value !== 'string' ) { + throw APIError.create('field_invalid', null, { + key: `metadata.${key}`, + expected: 'string', + got: whatis(value), + }); + } + if ( value.length > MAX_MESSAGE_STRING ) { + throw APIError.create('field_invalid', null, { + key: `metadata.${key}`, + expected: `at most ${MAX_MESSAGE_STRING} characters`, + got: `${value.length} characters`, + }); + } + continue; + } + if ( typeof value === 'string' && value.length > MAX_STRING ) { + throw APIError.create('field_invalid', null, { + key: `metadata.${key}`, + expected: `at most ${MAX_STRING} characters`, + got: `${value.length} characters`, + }); + } + } + }, function validate_mode (a) { const req = a.get('req'); const mode = req.body.mode; From f5247c9dfea31174c08ec2bf671ced2e221c6d94 Mon Sep 17 00:00:00 2001 From: Luiz Gribner Date: Wed, 20 Nov 2024 19:55:38 -0300 Subject: [PATCH 1277/2119] Translate completed to Portuguese-BR --- src/gui/src/i18n/translations/br.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/gui/src/i18n/translations/br.js b/src/gui/src/i18n/translations/br.js index 776e0ddf2e..a28db8e452 100644 --- a/src/gui/src/i18n/translations/br.js +++ b/src/gui/src/i18n/translations/br.js @@ -350,20 +350,20 @@ const br = { // *********************************** // Missing translations // *********************************** - "change": undefined, // In English: "Change" - "clock_visibility": undefined, // In English: "Clock Visibility" - "reading": undefined, // In English: "Reading %strong%" - "writing": undefined, // In English: "Writing %strong%" - "unzipping": undefined, // In English: "Unzipping %strong%" - "sequencing": undefined, // In English: "Sequencing %strong%" - "zipping": undefined, // In English: "Zipping %strong%" - "Editor": undefined, // In English: "Editor" - "Viewer": undefined, // In English: "Viewer" - "People with access": undefined, // In English: "People with access" - "Share With…": undefined, // In English: "Share With…" - "Owner": undefined, // In English: "Owner" - "You can't share with yourself.": undefined, // In English: "You can't share with yourself." - "This user already has access to this item": undefined, // In English: "This user already has access to this item" + "change": "Alterar", // In English: "Change" + "clock_visibility": "Visibilidade do relógio", // In English: "Clock Visibility" + "reading": "Lendo %strong%", // In English: "Reading %strong%" + "writing": "Escrevendo %strong%", // In English: "Writing %strong%" + "unzipping": "Descompactando %strong%", // In English: "Unzipping %strong%" + "sequencing": "Sequenciando %strong%", // In English: "Sequencing %strong%" + "zipping": "Compactando %strong%", // In English: "Zipping %strong%" + "Editor": "Editor", // In English: "Editor" + "Viewer": "Visualizador", // In English: "Viewer" + "People with access": "Pessoas com acesso", // In English: "People with access" + "Share With…": "Compartilhar com...", // In English: "Share With…" + "Owner": "Proprietário", // In English: "Owner" + "You can't share with yourself.": "Vocẽ não pode compartilhar com você mesmo", // In English: "You can't share with yourself." + "This user already has access to this item": "Esse usuário já tem acesso a esse item", // In English: "This user already has access to this item" } }; From 035de8e73e59276a8a36955877ebe51490e05b26 Mon Sep 17 00:00:00 2001 From: jelveh Date: Wed, 20 Nov 2024 15:21:05 -0800 Subject: [PATCH 1278/2119] Update UIDesktop.js --- src/gui/src/UI/UIDesktop.js | 35 +++++++++++++++++++++++++++++------ 1 file changed, 29 insertions(+), 6 deletions(-) diff --git a/src/gui/src/UI/UIDesktop.js b/src/gui/src/UI/UIDesktop.js index cc724ed555..a8f5889495 100644 --- a/src/gui/src/UI/UIDesktop.js +++ b/src/gui/src/UI/UIDesktop.js @@ -166,9 +166,9 @@ async function UIDesktop(options){ window.socket.on('notif.message', async ({ uid, notification }) => { let icon = window.icons[notification.icon]; let round_icon = false; - + if(notification.template === "file-shared-with-you" && notification.fields?.username){ - let profile_pic = await get_profile_picture(notification.fields.username); + let profile_pic = await get_profile_picture(notification.fields?.username); if(profile_pic){ icon = profile_pic; round_icon = true; @@ -208,16 +208,26 @@ async function UIDesktop(options){ }); window.__already_got_unreads = false; - window.socket.on('notif.unreads', ({ unreads }) => { + window.socket.on('notif.unreads', async ({ unreads }) => { if ( window.__already_got_unreads ) return; window.__already_got_unreads = true; for ( const notif_info of unreads ) { const notification = notif_info.notification; - const icon = window.icons[notification.icon]; - + let icon = window.icons[notification.icon]; + let round_icon = false; + + if(notification.template === "file-shared-with-you" && notification.fields?.username){ + let profile_pic = await get_profile_picture(notification.fields?.username); + if(profile_pic){ + icon = profile_pic; + round_icon = true; + } + } + UINotification({ icon, + round_icon, title: notification.title, text: notification.text ?? notification.title, uid: notif_info.uid, @@ -1282,7 +1292,20 @@ async function UIDesktop(options){ .then(response => response.json()) .then(data => { if(data && data.result && data.result.length > 0){ - data.data?.forEach(notification => { + data.data?.forEach(async notification => { + let icon = window.icons['puter-logo.svg']; + let round_icon = false; + + if(notification.template === "file-shared-with-you" && notification.fields?.username){ + let profile_pic = await get_profile_picture(notification.fields?.username); + if(profile_pic){ + icon = profile_pic; + round_icon = true; + notification.round_icon = round_icon; + } + } + notification.icon = icon; + UINotification(notification); }) } From ca2f7b4326a37a21105bf494a2d614c2e86ce5a5 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 20 Nov 2024 15:23:19 -0800 Subject: [PATCH 1279/2119] Update br.js --- src/gui/src/i18n/translations/br.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/gui/src/i18n/translations/br.js b/src/gui/src/i18n/translations/br.js index a28db8e452..310475bc0f 100644 --- a/src/gui/src/i18n/translations/br.js +++ b/src/gui/src/i18n/translations/br.js @@ -347,9 +347,6 @@ const br = { "login2fa_recovery_back": "Voltar", "login2fa_recovery_placeholder": "XXXXXXXX", - // *********************************** - // Missing translations - // *********************************** "change": "Alterar", // In English: "Change" "clock_visibility": "Visibilidade do relógio", // In English: "Clock Visibility" "reading": "Lendo %strong%", // In English: "Reading %strong%" From bfacfc2a4e4b50c9e0842f9f2d56de67a598b959 Mon Sep 17 00:00:00 2001 From: jelveh Date: Wed, 20 Nov 2024 15:44:17 -0800 Subject: [PATCH 1280/2119] fix: sharing notification click opening directories --- src/gui/src/UI/UIDesktop.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/gui/src/UI/UIDesktop.js b/src/gui/src/UI/UIDesktop.js index a8f5889495..963fff321f 100644 --- a/src/gui/src/UI/UIDesktop.js +++ b/src/gui/src/UI/UIDesktop.js @@ -243,6 +243,18 @@ async function UIDesktop(options){ }), }); }, + click: async (notif) => { + if(notification.template === "file-shared-with-you"){ + let item_path = '/' + notification.fields?.username; + UIWindow({ + path: '/' + notification.fields?.username, + title: path.basename(item_path), + icon: await item_icon({is_dir: true, path: item_path}), + is_dir: true, + app: 'explorer', + }); + } + }, }); } }); @@ -1306,6 +1318,19 @@ async function UIDesktop(options){ } notification.icon = icon; + notification.click = async (notif) => { + if(notification.template === "file-shared-with-you"){ + let item_path = '/' + notification.fields?.username; + UIWindow({ + path: '/' + notification.fields?.username, + title: path.basename(item_path), + icon: await item_icon({is_dir: true, path: item_path}), + is_dir: true, + app: 'explorer', + }); + } + } + UINotification(notification); }) } From 99cd9b23159316d278cdef180920565ef03599f5 Mon Sep 17 00:00:00 2001 From: nlaburu <180408022+nlaburu@users.noreply.github.com> Date: Thu, 21 Nov 2024 00:48:36 +0100 Subject: [PATCH 1281/2119] fix french missing translations --- src/gui/src/i18n/translations/fr.js | 38 ++++++++++++++--------------- 1 file changed, 19 insertions(+), 19 deletions(-) diff --git a/src/gui/src/i18n/translations/fr.js b/src/gui/src/i18n/translations/fr.js index 6d4395224e..b205394ae7 100644 --- a/src/gui/src/i18n/translations/fr.js +++ b/src/gui/src/i18n/translations/fr.js @@ -23,7 +23,7 @@ const fr = { english_name: "French", code: "fr", dictionary: { - about: "A propos", + about: "À propos", account: "Compte", account_password: "Vérifier le mot de passe du compte", access_granted_to: "Accès accordé à", @@ -42,8 +42,8 @@ const fr = { change_email: "Changer l'e-mail", change_language: "Changer de langue", change_password: "Changer le mot de passe", - change_ui_colors: "Changer les couleurs d'interface", - change_username: "Change le nom d'utilisateur", + change_ui_colors: "Changer les couleurs de l'interface", + change_username: "Changer le nom d'utilisateur", close: 'Fermer', close_all_windows: "Fermer toutes les fenêtres", close_all_windows_confirm: "Êtes-vous sûr de vouloir fermer toutes les fenêtres ?", @@ -349,22 +349,22 @@ const fr = { // *********************************** // Missing translations // *********************************** - "change": undefined, // In English: "Change" - "clock_visibility": undefined, // In English: "Clock Visibility" - "confirm": undefined, // In English: "Confirm" - "public": undefined, // In English: "Public" - "reading": undefined, // In English: "Reading %strong%" - "writing": undefined, // In English: "Writing %strong%" - "unzipping": undefined, // In English: "Unzipping %strong%" - "sequencing": undefined, // In English: "Sequencing %strong%" - "zipping": undefined, // In English: "Zipping %strong%" - "Editor": undefined, // In English: "Editor" - "Viewer": undefined, // In English: "Viewer" - "People with access": undefined, // In English: "People with access" - "Share With…": undefined, // In English: "Share With…" - "Owner": undefined, // In English: "Owner" - "You can't share with yourself.": undefined, // In English: "You can't share with yourself." - "This user already has access to this item": undefined, // In English: "This user already has access to this item" + "change": 'changer', + "clock_visibility": "visibilité de l'horloge", + "confirm": 'confirmer', + "public": 'public', + "reading": 'lecture', + "writing": 'écriture', + "unzipping": 'décomprésser', + "sequencing": 'séquençage', + "zipping": 'compresser', + "Editor": 'Éditeur', + "Viewer": 'Lecteur', + "People with access": 'Utilisateurs avec accès', + "Share With…": 'Partager avec...', + "Owner": 'Propriétaire', + "You can't share with yourself.": 'Vous ne pouvez pas partager avec vous-même', + "This user already has access to this item": 'Cet utilisateur à déja accès à cet élément', } }; From 16257a7b5459550ee3782cf32c87a8241325878d Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Wed, 20 Nov 2024 21:00:03 -0500 Subject: [PATCH 1282/2119] fix: permission grants in open_item --- src/backend/src/routers/open_item.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/backend/src/routers/open_item.js b/src/backend/src/routers/open_item.js index 1220d5aa62..ce7e2cb89b 100644 --- a/src/backend/src/routers/open_item.js +++ b/src/backend/src/routers/open_item.js @@ -84,11 +84,14 @@ module.exports = eggspress('/open_item', { // Note: We always grant write permission here. If the user only // has read permission this is still safe; user permissions // are always checked during an app access. - const permission = `fs:${subject.uid}:write`; - const svc_permission = Context.get('services').get('permission'); - await svc_permission.grant_user_app_permission( - actor, app.uid, permission, {}, { reason: 'open_item' } - ); + const PERMS = action === 'write' ? ['read', 'write'] : ['read']; + for ( const perm of PERMS ) { + const permission = `fs:${subject.uid}:${perm}`; + const svc_permission = Context.get('services').get('permission'); + await svc_permission.grant_user_app_permission( + actor, app.uid, permission, {}, { reason: 'open_item' } + ); + } // Generate user-app token const svc_auth = Context.get('services').get('auth'); From 12cc7539033138cde5882faffa45427ade8775a4 Mon Sep 17 00:00:00 2001 From: tien0412 <75519924+tien0412@users.noreply.github.com> Date: Thu, 21 Nov 2024 10:29:42 +0700 Subject: [PATCH 1283/2119] finish translation for vi.js --- src/gui/src/i18n/translations/vi.js | 32 ++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/gui/src/i18n/translations/vi.js b/src/gui/src/i18n/translations/vi.js index 759b9ecf3f..0918143f06 100644 --- a/src/gui/src/i18n/translations/vi.js +++ b/src/gui/src/i18n/translations/vi.js @@ -350,22 +350,22 @@ const vi = { // *********************************** // Missing translations // *********************************** - "change": undefined, // In English: "Change" - "clock_visibility": undefined, // In English: "Clock Visibility" - "plural_suffix": undefined, // In English: "s" - "reading": undefined, // In English: "Reading %strong%" - "writing": undefined, // In English: "Writing %strong%" - "unzipping": undefined, // In English: "Unzipping %strong%" - "sequencing": undefined, // In English: "Sequencing %strong%" - "zipping": undefined, // In English: "Zipping %strong%" - "Editor": undefined, // In English: "Editor" - "Viewer": undefined, // In English: "Viewer" - "People with access": undefined, // In English: "People with access" - "Share With…": undefined, // In English: "Share With…" - "Owner": undefined, // In English: "Owner" - "You can't share with yourself.": undefined, // In English: "You can't share with yourself." - "This user already has access to this item": undefined, // In English: "This user already has access to this item" + "change": 'Thay đổi', // In English: "Change" + "clock_visibility": 'ẩn/hiện đồng hồ', // In English: "Clock Visibility" + "plural_suffix": 'các', // In English: "s" + "reading": 'Đang đọc %strong%', // In English: "Reading %strong%" + "writing": 'Đang ghi dữ liệu %strong%', // In English: "Writing %strong%" + "unzipping": 'Đang giải nén %strong%', // In English: "Unzipping %strong%" + "sequencing": 'Đang đánh thứ tự %strong%', // In English: "Sequencing %strong%" + "zipping": 'Đang nén %strong%', // In English: "Zipping %strong%" + "Editor": 'Người chỉnh sửa', // In English: "Editor" + "Viewer": 'Người xem', // In English: "Viewer" + "People with access": 'Người dùng có quyền truy cập', // In English: "People with access" + "Share With…": 'Chia sẻ với...', // In English: "Share With…" + "Owner": 'Người sở hữu', // In English: "Owner" + "You can't share with yourself.": 'Bạn không thể tự chia sẻ với chính mình', // In English: "You can't share with yourself." + "This user already has access to this item": 'Người dùng này đã có sẵn quyền truy cập cho mục này', // In English: "This user already has access to this item" } }; -export default vi; \ No newline at end of file +export default vi; From 4d0d8e125b220ecd3ac64e2ec9d740aa6f0e727a Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Wed, 20 Nov 2024 19:49:26 -0800 Subject: [PATCH 1284/2119] Update vi.js --- src/gui/src/i18n/translations/vi.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/gui/src/i18n/translations/vi.js b/src/gui/src/i18n/translations/vi.js index 0918143f06..bf132e03c1 100644 --- a/src/gui/src/i18n/translations/vi.js +++ b/src/gui/src/i18n/translations/vi.js @@ -347,9 +347,6 @@ const vi = { login2fa_recovery_back: 'Quay lại', login2fa_recovery_placeholder: 'XXXXXXXX', - // *********************************** - // Missing translations - // *********************************** "change": 'Thay đổi', // In English: "Change" "clock_visibility": 'ẩn/hiện đồng hồ', // In English: "Clock Visibility" "plural_suffix": 'các', // In English: "s" From 2f15d129b6a20759a36fffe22c5baf3c3b47916b Mon Sep 17 00:00:00 2001 From: kiwipix <140586538+kiwipix@users.noreply.github.com> Date: Thu, 21 Nov 2024 11:53:08 +0800 Subject: [PATCH 1285/2119] Update zhtw.js add translation for missing items --- src/gui/src/i18n/translations/zhtw.js | 28 +++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/gui/src/i18n/translations/zhtw.js b/src/gui/src/i18n/translations/zhtw.js index bec81cd7d9..20427dfb01 100644 --- a/src/gui/src/i18n/translations/zhtw.js +++ b/src/gui/src/i18n/translations/zhtw.js @@ -349,20 +349,20 @@ const zhtw = { // *********************************** // Missing translations // *********************************** - "change": undefined, // In English: "Change" - "clock_visibility": undefined, // In English: "Clock Visibility" - "reading": undefined, // In English: "Reading %strong%" - "writing": undefined, // In English: "Writing %strong%" - "unzipping": undefined, // In English: "Unzipping %strong%" - "sequencing": undefined, // In English: "Sequencing %strong%" - "zipping": undefined, // In English: "Zipping %strong%" - "Editor": undefined, // In English: "Editor" - "Viewer": undefined, // In English: "Viewer" - "People with access": undefined, // In English: "People with access" - "Share With…": undefined, // In English: "Share With…" - "Owner": undefined, // In English: "Owner" - "You can't share with yourself.": undefined, // In English: "You can't share with yourself." - "This user already has access to this item": undefined, // In English: "This user already has access to this item" + "change": '更改', // In English: "Change" + "clock_visibility": '時鐘可視性', // In English: "Clock Visibility" + "reading": '正在讀取 %strong%', // In English: "Reading %strong%" + "writing": '正在寫入 %strong%', // In English: "Writing %strong%" + "unzipping": '正在解壓 %strong%', // In English: "Unzipping %strong%" + "sequencing": '正在排序 %strong%', // In English: "Sequencing %strong%" + "zipping": '正在壓縮 %strong%', // In English: "Zipping %strong%" + "Editor": '編輯器', // In English: "Editor" + "Viewer": '檢視者', // In English: "Viewer" + "People with access": '有權限的人', // In English: "People with access" + "Share With…": '分享給……', // In English: "Share With…" + "Owner": '所有者', // In English: "Owner" + "You can't share with yourself.": '您不能與自己分享。', // In English: "You can't share with yourself." + "This user already has access to this item": '該用戶已有訪問此項的權限', // In English: "This user already has access to this item" } }; From 46053f3e7c40aaa56e6ad183d9545baf7b104cf0 Mon Sep 17 00:00:00 2001 From: jelveh Date: Wed, 20 Nov 2024 20:04:00 -0800 Subject: [PATCH 1286/2119] Update zhtw.js --- src/gui/src/i18n/translations/zhtw.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/gui/src/i18n/translations/zhtw.js b/src/gui/src/i18n/translations/zhtw.js index 20427dfb01..5fdda1b378 100644 --- a/src/gui/src/i18n/translations/zhtw.js +++ b/src/gui/src/i18n/translations/zhtw.js @@ -346,9 +346,6 @@ const zhtw = { login2fa_recovery_back: '返回', login2fa_recovery_placeholder: 'XXXXXXXX', - // *********************************** - // Missing translations - // *********************************** "change": '更改', // In English: "Change" "clock_visibility": '時鐘可視性', // In English: "Clock Visibility" "reading": '正在讀取 %strong%', // In English: "Reading %strong%" From a998e4b4cca63c5a9201e20669a47a3fe9922cdf Mon Sep 17 00:00:00 2001 From: nlaburu <180408022+nlaburu@users.noreply.github.com> Date: Thu, 21 Nov 2024 11:04:58 +0100 Subject: [PATCH 1287/2119] fix missing placeholders in fr.js --- src/gui/src/i18n/translations/fr.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/gui/src/i18n/translations/fr.js b/src/gui/src/i18n/translations/fr.js index b205394ae7..7ae64f45c1 100644 --- a/src/gui/src/i18n/translations/fr.js +++ b/src/gui/src/i18n/translations/fr.js @@ -353,11 +353,11 @@ const fr = { "clock_visibility": "visibilité de l'horloge", "confirm": 'confirmer', "public": 'public', - "reading": 'lecture', - "writing": 'écriture', - "unzipping": 'décomprésser', - "sequencing": 'séquençage', - "zipping": 'compresser', + "reading": 'lecture %strong%', + "writing": 'écriture %strong%', + "unzipping": 'décomprésser %strong%', + "sequencing": 'séquençage %strong%', + "zipping": 'compresser %strong%', "Editor": 'Éditeur', "Viewer": 'Lecteur', "People with access": 'Utilisateurs avec accès', From 4ce0670370901f64cc418883cf9f9d24c19f552c Mon Sep 17 00:00:00 2001 From: jelveh Date: Thu, 21 Nov 2024 05:51:35 -0800 Subject: [PATCH 1288/2119] Update fr.js --- src/gui/src/i18n/translations/fr.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/gui/src/i18n/translations/fr.js b/src/gui/src/i18n/translations/fr.js index 7ae64f45c1..f2fe2d1976 100644 --- a/src/gui/src/i18n/translations/fr.js +++ b/src/gui/src/i18n/translations/fr.js @@ -346,9 +346,6 @@ const fr = { login2fa_recovery_back: 'Retour', login2fa_recovery_placeholder: 'XXXXXXXX', - // *********************************** - // Missing translations - // *********************************** "change": 'changer', "clock_visibility": "visibilité de l'horloge", "confirm": 'confirmer', From d93fd419e478e68a5028e6d38e2edba88b555bf5 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 21 Nov 2024 11:03:40 -0500 Subject: [PATCH 1289/2119] dev: add human_readable_age to /whoami --- package.json | 1 + src/backend/src/routers/whoami.js | 12 ++++++++++++ 2 files changed, 13 insertions(+) diff --git a/package.json b/package.json index 2595b5f177..72fdb29be6 100644 --- a/package.json +++ b/package.json @@ -47,6 +47,7 @@ ] }, "dependencies": { + "javascript-time-ago": "^2.5.11", "json-colorizer": "^3.0.1", "simple-git": "^3.25.0", "string-template": "^1.0.0", diff --git a/src/backend/src/routers/whoami.js b/src/backend/src/routers/whoami.js index 3660c01840..f5420df1c9 100644 --- a/src/backend/src/routers/whoami.js +++ b/src/backend/src/routers/whoami.js @@ -18,6 +18,15 @@ */ "use strict" const express = require('express'); + +// Timeago is so inconvenient to instantiate that I'm using an IIFE +// to reduce the impact on the scope. +const timeago = (() => { + const TimeAgo = require('javascript-time-ago'); + TimeAgo.addDefaultLocale(require('javascript-time-ago/locale/en')); + return new TimeAgo('en-US'); +})(); + const { get_taskbar_items, is_shared_with_anyone, suggest_app_for_fsentry, get_app, get_descendants, id2uuid } = require('../helpers'); const auth = require('../middleware/auth.js'); const fs = require('../middleware/fs.js'); @@ -57,6 +66,8 @@ const WHOAMI_GET = eggspress('/whoami', { taskbar_items: await get_taskbar_items(req.user), referral_code: req.user.referral_code, otp: !! req.user.otp_enabled, + human_readable_age: timeago.format( + new Date(req.user.timestamp)), ...(req.new_token ? { token: req.token } : {}) }; @@ -80,6 +91,7 @@ const WHOAMI_GET = eggspress('/whoami', { delete details.desktop_bg_fit; delete details.taskbar_items; delete details.token; + delete details.human_readable_age; } if ( actor.type instanceof AppUnderUserActorType ) { From d30d62f558ca5f8c74090900aa39c13ca3ca1d2e Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 21 Nov 2024 11:39:59 -0500 Subject: [PATCH 1290/2119] fix: share issue with prefix usernames --- src/gui/src/initgui.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/gui/src/initgui.js b/src/gui/src/initgui.js index f37044d041..94eb5acfe0 100644 --- a/src/gui/src/initgui.js +++ b/src/gui/src/initgui.js @@ -1477,7 +1477,11 @@ window.privacy_aware_path = function(fspath){ if(fspath.startsWith('~/')) return fspath; // e.g. /my_username/test.txt -> ~/test.txt - else if(fspath.startsWith(window.home_path)) + else if(fspath.startsWith( + window.home_path.endsWith('/') + ? window.home_path + : window.home_path + '/' + )) return fspath.replace(window.home_path, '~'); // e.g. /other_username/test.txt -> /other_username/test.txt else if(fspath.startsWith('/') && !fspath.startsWith(window.home_path)) @@ -1488,4 +1492,4 @@ window.privacy_aware_path = function(fspath){ // e.g. /username/path/to/item -> /username/path/to/item else return fspath; -} \ No newline at end of file +}; \ No newline at end of file From 1363de7cbf486b39e7bd435e36d4d1c3236a58f6 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 21 Nov 2024 12:06:02 -0500 Subject: [PATCH 1291/2119] text: add test for privacy_aware_path --- src/gui/src/initgui.js | 35 ++------------------ src/gui/src/util/desktop.js | 43 +++++++++++++++++++++++++ src/gui/test/privacy_aware_path.test.js | 33 +++++++++++++++++++ 3 files changed, 79 insertions(+), 32 deletions(-) create mode 100644 src/gui/src/util/desktop.js create mode 100644 src/gui/test/privacy_aware_path.test.js diff --git a/src/gui/src/initgui.js b/src/gui/src/initgui.js index 94eb5acfe0..cbcf765f7b 100644 --- a/src/gui/src/initgui.js +++ b/src/gui/src/initgui.js @@ -49,6 +49,7 @@ import { AntiCSRFService } from './services/AntiCSRFService.js'; import { IPCService } from './services/IPCService.js'; import { ExecService } from './services/ExecService.js'; import { DebugService } from './services/DebugService.js'; +import { privacy_aware_path } from './util/desktop.js'; const launch_services = async function (options) { // === Services Data Structures === @@ -1461,35 +1462,5 @@ $(document).on('contextmenu', '.disable-context-menu', function(e){ } }) -/** - * Converts a file system path to a privacy-aware path. - * - Paths starting with `~/` are returned unchanged. - * - Paths starting with the user's home path are replaced with `~`. - * - Absolute paths not starting with the user's home path are returned unchanged. - * - Relative paths are prefixed with `~/`. - * - Other paths are returned unchanged. - * - * @param {string} fspath - The file system path to be converted. - * @returns {string} The privacy-aware path. - */ -window.privacy_aware_path = function(fspath){ - // e.g. /my_username/test.txt -> ~/test.txt - if(fspath.startsWith('~/')) - return fspath; - // e.g. /my_username/test.txt -> ~/test.txt - else if(fspath.startsWith( - window.home_path.endsWith('/') - ? window.home_path - : window.home_path + '/' - )) - return fspath.replace(window.home_path, '~'); - // e.g. /other_username/test.txt -> /other_username/test.txt - else if(fspath.startsWith('/') && !fspath.startsWith(window.home_path)) - return fspath; - // e.g. test.txt -> ~/test.txt - else if(!fspath.startsWith('/')) - return '~/' + fspath; - // e.g. /username/path/to/item -> /username/path/to/item - else - return fspath; -}; \ No newline at end of file +// util/desktop.js +window.privacy_aware_path = privacy_aware_path({ window }); diff --git a/src/gui/src/util/desktop.js b/src/gui/src/util/desktop.js new file mode 100644 index 0000000000..3f3bf1ee19 --- /dev/null +++ b/src/gui/src/util/desktop.js @@ -0,0 +1,43 @@ +/** + * This file contains functions that are used by Puter's desktop GUI. + * Functions moved here are not bound to the `window` object, making it + * easier to write unit tests for them. + * + * Functions here may be bound to `window` at any of the following locations: + * - src/gui/src/initgui.js + * + * ^ Please add to the above list as necessary when moving functions here. + */ + +/** + * Converts a file system path to a privacy-aware path. + * - Paths starting with `~/` are returned unchanged. + * - Paths starting with the user's home path are replaced with `~`. + * - Absolute paths not starting with the user's home path are returned unchanged. + * - Relative paths are prefixed with `~/`. + * - Other paths are returned unchanged. + * + * @param {string} fspath - The file system path to be converted. + * @returns {string} The privacy-aware path. + */ +export const privacy_aware_path = world => function privacy_aware_path (fspath) { + // e.g. /my_username/test.txt -> ~/test.txt + if(fspath.startsWith('~/')) + return fspath; + // e.g. /my_username/test.txt -> ~/test.txt + else if(fspath.startsWith( + world.window.home_path.endsWith('/') + ? world.window.home_path + : world.window.home_path + '/' + )) + return fspath.replace(world.window.home_path, '~'); + // e.g. /other_username/test.txt -> /other_username/test.txt + else if(fspath.startsWith('/') && !fspath.startsWith(world.window.home_path)) + return fspath; + // e.g. test.txt -> ~/test.txt + else if(!fspath.startsWith('/')) + return '~/' + fspath; + // e.g. /username/path/to/item -> /username/path/to/item + else + return fspath; +}; diff --git a/src/gui/test/privacy_aware_path.test.js b/src/gui/test/privacy_aware_path.test.js new file mode 100644 index 0000000000..30b628a401 --- /dev/null +++ b/src/gui/test/privacy_aware_path.test.js @@ -0,0 +1,33 @@ +import assert from 'assert'; +import { privacy_aware_path } from '../src/util/desktop.js'; + +const cases = [ + { + title: 'path in user home', + username: 'user', + input: '/home/user/test.txt', + expected: '~/test.txt', + }, + { + title: 'path on user desktop', + username: 'user', + input: '/home/user/Desktop/test.txt', + expected: '~/Desktop/test.txt', + }, + { + title: 'prefix (ed3/ed) bug', + username: 'ed', + input: '/home/ed3/Desktop/test.txt', + expected: '/home/ed3/Desktop/test.txt', + }, +]; + +describe('window.privacy_aware_path', () => { + for (const { title, username, input, expected } of cases) { + it(title, () => { + assert.equal(privacy_aware_path({ + window: { home_path: `/home/${username}` }, + })(input), expected); + }); + } +}); \ No newline at end of file From 0c4b9946442ad92549522fcd91ea6aefbb9f19d6 Mon Sep 17 00:00:00 2001 From: afaq-karim Date: Thu, 21 Nov 2024 23:42:18 +0500 Subject: [PATCH 1292/2119] feat(i18n): update Urdu localization with missing translations --- src/gui/src/i18n/translations/ur.js | 64 ++++++++++++++--------------- 1 file changed, 32 insertions(+), 32 deletions(-) diff --git a/src/gui/src/i18n/translations/ur.js b/src/gui/src/i18n/translations/ur.js index 00e01bf033..9bfc95a602 100644 --- a/src/gui/src/i18n/translations/ur.js +++ b/src/gui/src/i18n/translations/ur.js @@ -362,38 +362,38 @@ const ur = { // *********************************** // Missing translations // *********************************** - "allow": undefined, // In English: "Allow" - "associated_websites": undefined, // In English: "Associated Websites" - "change": undefined, // In English: "Change" - "clock_visibility": undefined, // In English: "Clock Visibility" - "confirm": undefined, // In English: "Confirm" - "confirm_your_email_address": undefined, // In English: "Confirm Your Email Address" - "close_all": undefined, // In English: "Close All" - "created": undefined, // In English: "Created" - "dont_allow": undefined, // In English: "Don't Allow" - "error_message_is_missing": undefined, // In English: "Error message is missing." - "folder": undefined, // In English: "Folder" - "modified": undefined, // In English: "Modified" - "original_name": undefined, // In English: "Original Name" - "original_path": undefined, // In English: "Original Path" - "path": undefined, // In English: "Path" - "reading": undefined, // In English: "Reading %strong%" - "writing": undefined, // In English: "Writing %strong%" - "save": undefined, // In English: "Save" - "sessions": undefined, // In English: "Sessions" - "share": undefined, // In English: "Share" - "share_with": undefined, // In English: "Share with:" - "shortcut_to": undefined, // In English: "Shortcut to" - "unzipping": undefined, // In English: "Unzipping %strong%" - "sequencing": undefined, // In English: "Sequencing %strong%" - "zipping": undefined, // In English: "Zipping %strong%" - "Editor": undefined, // In English: "Editor" - "Viewer": undefined, // In English: "Viewer" - "People with access": undefined, // In English: "People with access" - "Share With…": undefined, // In English: "Share With…" - "Owner": undefined, // In English: "Owner" - "You can't share with yourself.": undefined, // In English: "You can't share with yourself." - "This user already has access to this item": undefined, // In English: "This user already has access to this item" + "allow": "اجازت دینا", // In English: "Allow" + "associated_websites": "متعلقہ ویب سائٹس", // In English: "Associated Websites" + "change": "تبدیل کرنا", // In English: "Change" + "clock_visibility": "گھڑی کی نمائش", // In English: "Clock Visibility" + "confirm": "تصدیق", // In English: "Confirm" + "confirm_your_email_address": "اپنے ای میل ایڈریس کی تصدیق کریں", // In English: "Confirm Your Email Address" + "close_all": "سب کو بند کریں", // In English: "Close All" + "created": "بنائی", // In English: "Created" + "dont_allow": "اجازت نہ دیں", // In English: "Don't Allow" + "error_message_is_missing": "غلطی کا پیغام غائب ہے", // In English: "Error message is missing." + "folder": "فولڈر", // In English: "Folder" + "modified": "ترمیم", // In English: "Modified" + "original_name": "اصل نام", // In English: "Original Name" + "original_path": "اصل راستہ", // In English: "Original Path" + "path": "راستہ", // In English: "Path" + "reading": "پڑھنا %strong%", // In English: "Reading %strong%" + "writing": "لکھنا %strong%", // In English: "Writing %strong%" + "save": "محفوظ کریں", // In English: "Save" + "sessions": "سیشنز", // In English: "Sessions" + "share": "شیئر کریں", // In English: "Share" + "share_with": "شیئر کریں:", // In English: "Share with:" + "shortcut_to": "شارٹ کٹ برائے", // In English: "Shortcut to" + "unzipping": "اَن زپ کر رہا ہے %strong%", // In English: "Unzipping %strong%" + "sequencing": "ترتیب دے رہا ہے %strong%", // In English: "Sequencing %strong%" + "zipping": "زپ کر رہا ہے %strong%", // In English: "Zipping %strong%" + "Editor": "ایڈیٹر", // In English: "Editor" - Some words in Urdu are written the same as in English, like "editor," and they don't have a specific Urdu equivalent that conveys the original meaning. These are common words that every native Urdu speaker understands. + "Viewer": "دیکھنے والا", // In English: "Viewer" + "People with access": "لوگ جنہیں رسائی حاصل ہے", // In English: "People with access" + "Share With…": "...کے ساتھ شیئر کریں", // In English: "Share With…" + "Owner": "مالک", // In English: "Owner" + "You can't share with yourself.": "آپ خود کے ساتھ شیئر نہیں کر سکتے۔", // In English: "You can't share with yourself." + "This user already has access to this item": "اس صارف کو پہلے ہی اس آئٹم تک رسائی حاصل ہے۔", // In English: "This user already has access to this item" }, }; From c140cd158bf015dbc70fff470edb95880963c724 Mon Sep 17 00:00:00 2001 From: jelveh Date: Thu, 21 Nov 2024 10:48:37 -0800 Subject: [PATCH 1293/2119] Update ur.js --- src/gui/src/i18n/translations/ur.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/gui/src/i18n/translations/ur.js b/src/gui/src/i18n/translations/ur.js index 9bfc95a602..fa33e5029c 100644 --- a/src/gui/src/i18n/translations/ur.js +++ b/src/gui/src/i18n/translations/ur.js @@ -359,9 +359,6 @@ const ur = { login2fa_recovery_back: "پیچھے", login2fa_recovery_placeholder: "XXXXXXXX", - // *********************************** - // Missing translations - // *********************************** "allow": "اجازت دینا", // In English: "Allow" "associated_websites": "متعلقہ ویب سائٹس", // In English: "Associated Websites" "change": "تبدیل کرنا", // In English: "Change" From 03817cd5c725664727a93a4d893dc2692269ce87 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 21 Nov 2024 14:09:56 -0500 Subject: [PATCH 1294/2119] dev: thumbnail tests and readings --- .../thumbnails/HTTPThumbnailService.js | 39 ++++++ src/backend/tools/test.js | 118 +++++++++++------- 2 files changed, 111 insertions(+), 46 deletions(-) diff --git a/src/backend/src/services/thumbnails/HTTPThumbnailService.js b/src/backend/src/services/thumbnails/HTTPThumbnailService.js index ab75ab719e..3e0d90b84c 100644 --- a/src/backend/src/services/thumbnails/HTTPThumbnailService.js +++ b/src/backend/src/services/thumbnails/HTTPThumbnailService.js @@ -104,6 +104,34 @@ class HTTPThumbnailService extends BaseService { } } + async ['__on_install.routes'] (_, { app }) { + const r_thumbs = (() => { + const require = this.require; + const express = require('express'); + return express.Router(); + })(); + + app.use('/thumbs', r_thumbs); + + r_thumbs.get('/status', (req, res) => { + const status_as_string = (status) => { + switch ( status ) { + case this.constructor.STATUS_IDLE: + return 'idle'; + case this.constructor.STATUS_RUNNING: + return 'running'; + default: + return 'unknown'; + } + } + res.json({ + status: status_as_string(this.status), + queue: this.queue.length, + recycle_counts: this.queue.map(job => job.recycle_count), + }); + }); + } + async _init () { const services = this.services; const svc_serverHealth = services.get('server-health'); @@ -299,6 +327,17 @@ class HTTPThumbnailService extends BaseService { this.constructor.SUPPORTED_MIMETYPES = Object.keys(mime_set); } + + _test ({ assert }) { + // Thumbnail operation eventually recycles + { + const thop = new ThumbnailOperation(null); + for ( let i = 0 ; i < ThumbnailOperation.MAX_RECYCLE_COUNT ; i++ ) { + assert.equal(thop.recycle(), true, `recycle ${i}`); + } + assert.equal(thop.recycle(), false, 'recycle max'); + } + } } module.exports = { diff --git a/src/backend/tools/test.js b/src/backend/tools/test.js index 952def5ddc..966b4816e6 100644 --- a/src/backend/tools/test.js +++ b/src/backend/tools/test.js @@ -22,6 +22,7 @@ const { BaseService } = require("../exports"); const CoreModule = require("../src/CoreModule"); const { Context } = require("../src/util/context"); const { Kernel } = require("../src/Kernel"); +const { HTTPThumbnailService } = require("../src/services/thumbnails/HTTPThumbnailService"); class TestLogger { constructor () { @@ -100,6 +101,7 @@ class TestKernel extends AdvancedBase { for ( const module of this.modules ) { + console.log('module?"???', module) const mod_context = this._create_mod_context( mod_install_root_context, { @@ -130,6 +132,12 @@ TestKernel.prototype._create_mod_context = const k = new TestKernel(); k.add_module(new CoreModule()); +k.add_module({ + install: async (context) => { + const services = context.get('services'); + services.registerService('thumbs-http', HTTPThumbnailService); + } +}); k.boot(); const do_after_tests_ = []; @@ -145,62 +153,80 @@ const repeat_after = (fn) => { let total_passed = 0; let total_failed = 0; -for ( const name in k.services.instances_ ) { - console.log('name', name) - const ins = k.services.instances_[name]; - ins.construct(); - if ( ! ins._test || typeof ins._test !== 'function' ) { - continue; - } - let passed = 0; - let failed = 0; +const main = async () => { + console.log('awaiting services readty'); + await k.services.ready; + console.log('services have become ready'); + + const service_names = process.argv.length > 2 + ? process.argv.slice(2) + : Object.keys(k.services.instances_); + + for ( const name of service_names) { + if ( ! k.services.instances_[name] ) { + console.log(`\x1B[31;1mService not found: ${name}\x1B[0m`); + process.exit(1); + } + + const ins = k.services.instances_[name]; + ins.construct(); + if ( ! ins._test || typeof ins._test !== 'function' ) { + continue; + } + let passed = 0; + let failed = 0; + + repeat_after(() => { + console.log(`\x1B[33;1m=== [ Service :: ${name} ] ===\x1B[0m`); + }); - repeat_after(() => { - console.log(`\x1B[33;1m=== [ Service :: ${name} ] ===\x1B[0m`); - }); + const testapi = { + assert: (condition, name) => { + name = name || condition.toString(); + if ( condition() ) { + passed++; + repeat_after(() => console.log(`\x1B[32;1m ✔ ${name}\x1B[0m`)); + } else { + failed++; + repeat_after(() => console.log(`\x1B[31;1m ✘ ${name}\x1B[0m`)); + } + } + }; - const testapi = { - assert: (condition, name) => { - name = name || condition.toString(); - if ( condition() ) { + testapi.assert.equal = (a, b, name) => { + name = name || `${a} === ${b}`; + if ( a === b ) { passed++; repeat_after(() => console.log(`\x1B[32;1m ✔ ${name}\x1B[0m`)); } else { failed++; - repeat_after(() => console.log(`\x1B[31;1m ✘ ${name}\x1B[0m`)); + repeat_after(() => { + console.log(`\x1B[31;1m ✘ ${name}\x1B[0m`); + console.log(`\x1B[31;1m Expected: ${b}\x1B[0m`); + console.log(`\x1B[31;1m Got: ${a}\x1B[0m`); + }); } - } - }; - - testapi.assert.equal = (a, b, name) => { - name = name || `${a} === ${b}`; - if ( a === b ) { - passed++; - repeat_after(() => console.log(`\x1B[32;1m ✔ ${name}\x1B[0m`)); - } else { - failed++; - repeat_after(() => { - console.log(`\x1B[31;1m ✘ ${name}\x1B[0m`); - console.log(`\x1B[31;1m Expected: ${b}\x1B[0m`); - console.log(`\x1B[31;1m Got: ${a}\x1B[0m`); - }); - } - }; + }; - ins._test(testapi); + ins._test(testapi); - total_passed += passed; - total_failed += failed; -} + total_passed += passed; + total_failed += failed; + } -console.log(`\x1B[36;1m<===\x1B[0m ` + - 'ASSERTION OUTPUTS ARE REPEATED BELOW' + - ` \x1B[36;1m===>\x1B[0m`); + console.log(`\x1B[36;1m<===\x1B[0m ` + + 'ASSERTION OUTPUTS ARE REPEATED BELOW' + + ` \x1B[36;1m===>\x1B[0m`); -for ( const fn of do_after_tests_ ) { - fn(); + for ( const fn of do_after_tests_ ) { + fn(); + } + + console.log(`\x1B[36;1m=== [ Summary ] ===\x1B[0m`); + console.log(`Passed: ${total_passed}`); + console.log(`Failed: ${total_failed}`); + + process.exit(total_failed ? 1 : 0); } -console.log(`\x1B[36;1m=== [ Summary ] ===\x1B[0m`); -console.log(`Passed: ${total_passed}`); -console.log(`Failed: ${total_failed}`); +main(); From 7e888248d1d3b8499d297657ac8954799ec66281 Mon Sep 17 00:00:00 2001 From: "DESKTOP-Q7DI747\\User" Date: Fri, 22 Nov 2024 02:32:42 +0700 Subject: [PATCH 1295/2119] thai missing translations --- src/gui/src/i18n/translations/th.js | 36 ++++++++++++++--------------- 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/src/gui/src/i18n/translations/th.js b/src/gui/src/i18n/translations/th.js index 01637c1bd0..3b2b5d7a0f 100644 --- a/src/gui/src/i18n/translations/th.js +++ b/src/gui/src/i18n/translations/th.js @@ -347,24 +347,24 @@ const th = { // *********************************** // Missing translations // *********************************** - "change": undefined, // In English: "Change" - "clock_visibility": undefined, // In English: "Clock Visibility" - "confirm": undefined, // In English: "Confirm" - "path": undefined, // In English: "Path" - "plural_suffix": undefined, // In English: "s" - "reading": undefined, // In English: "Reading %strong%" - "writing": undefined, // In English: "Writing %strong%" - "save": undefined, // In English: "Save" - "unzipping": undefined, // In English: "Unzipping %strong%" - "sequencing": undefined, // In English: "Sequencing %strong%" - "zipping": undefined, // In English: "Zipping %strong%" - "Editor": undefined, // In English: "Editor" - "Viewer": undefined, // In English: "Viewer" - "People with access": undefined, // In English: "People with access" - "Share With…": undefined, // In English: "Share With…" - "Owner": undefined, // In English: "Owner" - "You can't share with yourself.": undefined, // In English: "You can't share with yourself." - "This user already has access to this item": undefined, // In English: "This user already has access to this item" + "change": 'เปลี่ยนแปลง', // In English: "Change" + "clock_visibility": 'การมองเห็นนาฬิกา', // In English: "Clock Visibility" + "confirm": 'ยืนยัน', // In English: "Confirm" + "path": 'ที่อยู่', // In English: "Path" + "plural_suffix": 's', // In English: "s" + "reading": 'กำลังอ่าน %strong%', // In English: "Reading %strong%" + "writing": 'กำลังเขียน %strong%', // In English: "Writing %strong%" + "save": 'บันทึก', // In English: "Save" + "unzipping": 'กำลังแยก %strong%', // In English: "Unzipping %strong%" + "sequencing": 'กำลังจัดลำดับ %strong%', // In English: "Sequencing %strong%" + "zipping": 'กำลังบีบอัด %strong%', // In English: "Zipping %strong%" + "Editor": 'ตัวแก้ไข', // In English: "Editor" + "Viewer": 'ผู้ชม', // In English: "Viewer" + "People with access": 'บุคคลที่สามารถเข้าถึงได้', // In English: "People with access" + "Share With…": 'แบ่งปันร่วมกับ...', // In English: "Share With…" + "Owner": 'เจ้าของ', // In English: "Owner" + "You can't share with yourself.": 'คุณไม่สามารถแบ่งปันกับตัวเองได้', // In English: "You can't share with yourself." + "This user already has access to this item": 'ผู้ใช้นี้สามารถเข้าถึงรายการนี้ได้แล้ว', // In English: "This user already has access to this item" } }; From 73c66bebf7b2b6fd878f617493cda53ef2732bff Mon Sep 17 00:00:00 2001 From: jelveh Date: Thu, 21 Nov 2024 12:08:31 -0800 Subject: [PATCH 1296/2119] Update th.js --- src/gui/src/i18n/translations/th.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/gui/src/i18n/translations/th.js b/src/gui/src/i18n/translations/th.js index 3b2b5d7a0f..2bcb7d9d77 100644 --- a/src/gui/src/i18n/translations/th.js +++ b/src/gui/src/i18n/translations/th.js @@ -344,9 +344,6 @@ const th = { login2fa_recovery_placeholder: 'XXXXXXXX', - // *********************************** - // Missing translations - // *********************************** "change": 'เปลี่ยนแปลง', // In English: "Change" "clock_visibility": 'การมองเห็นนาฬิกา', // In English: "Clock Visibility" "confirm": 'ยืนยัน', // In English: "Confirm" From 7f30ec46e7dcf1ed1a6917efa510bf506707827a Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Thu, 21 Nov 2024 15:45:29 -0500 Subject: [PATCH 1297/2119] test: add more thumbnailer tests --- .../thumbnails/HTTPThumbnailService.js | 119 +++++++++++++----- src/backend/tools/test.js | 2 +- 2 files changed, 91 insertions(+), 30 deletions(-) diff --git a/src/backend/src/services/thumbnails/HTTPThumbnailService.js b/src/backend/src/services/thumbnails/HTTPThumbnailService.js index 3e0d90b84c..e68690317a 100644 --- a/src/backend/src/services/thumbnails/HTTPThumbnailService.js +++ b/src/backend/src/services/thumbnails/HTTPThumbnailService.js @@ -173,6 +173,10 @@ class HTTPThumbnailService extends BaseService { } checkShouldExec_ () { + if ( this.test_mode ) { + this.test_checked_exec = true; + return; + } if ( this.status !== this.constructor.STATUS_IDLE ) return; if ( this.queue.length === 0 ) return; this.exec_(); @@ -237,9 +241,60 @@ class HTTPThumbnailService extends BaseService { async exec_0 (queue) { const { axios } = this.modules; - let expected = 0; + this.log.info('starting thumbnail request'); + const resp = await this.request_({ queue }); + this.log.info('done thumbnail request'); + + if ( resp.status !== 200 ) { + this.log.error('Thumbnail service returned non-200 status'); + throw new Error('Thumbnail service returned non-200 status'); + } + + const results = resp.data; + + this.log.noticeme('response?', { resp }); + this.log.noticeme('data?', { data: resp.data }); + + if ( results.length !== queue.length ) { + this.log.error('Thumbnail service returned wrong number of results'); + throw new Error('Thumbnail service returned wrong number of results'); + } + + for ( let i = 0 ; i < queue.length ; i++ ) { + const result = results[i]; + const job = queue[i]; + + this.log.noticeme('result?', { result }); + job.resolve( + result.encoded + && `data:image/png;base64,${result.encoded}` + ); + } + } + + async request_ ({ queue }) { + if ( this.test_mode ) { + const results = []; + for ( const job of queue ) { + console.log('file?', job.file); + if ( job.file?.behavior === 'fail' ) { + throw new Error('test fail'); + } + results.push({ + encoded: 'data:image/png;base64,' + + 'iVBORw0KGgoAAAANSUhEUgAAAAgAAAAIAQMAAAD+wSzIAAAABlBMVEX' + + '///+/v7+jQ3Y5AAAADklEQVQI12P4AIX8EAgALgAD/aNpbtEAAAAASU' + + 'VORK5CYII', + }); + } + return { + status: 200, + data: results, + }; + } const form = new FormData(); + let expected = 0; for ( const job of queue ) { expected++; // const blob = new Blob([job.file.buffer], { type: job.file.mimetype }); @@ -261,7 +316,6 @@ class HTTPThumbnailService extends BaseService { }); } - this.log.info('starting thumbnail request'); const resp = await axios.request( { method: 'post', @@ -272,33 +326,8 @@ class HTTPThumbnailService extends BaseService { } } ); - this.log.info('done thumbnail request'); - - if ( resp.status !== 200 ) { - this.log.error('Thumbnail service returned non-200 status'); - throw new Error('Thumbnail service returned non-200 status'); - } - - const results = resp.data; - - this.log.noticeme('response?', { resp }); - this.log.noticeme('data?', { data: resp.data }); - - if ( results.length !== queue.length ) { - this.log.error('Thumbnail service returned wrong number of results'); - throw new Error('Thumbnail service returned wrong number of results'); - } - - for ( let i = 0 ; i < queue.length ; i++ ) { - const result = results[i]; - const job = queue[i]; - this.log.noticeme('result?', { result }); - job.resolve( - result.encoded - && `data:image/png;base64,${result.encoded}` - ); - } + return resp; } async query_supported_mime_types_() { @@ -328,7 +357,13 @@ class HTTPThumbnailService extends BaseService { this.constructor.SUPPORTED_MIMETYPES = Object.keys(mime_set); } - _test ({ assert }) { + async _test ({ assert }) { + this.errors.report = () => {}; + this.log = { + info: () => {}, + error: () => {}, + noticeme: () => {}, + }; // Thumbnail operation eventually recycles { const thop = new ThumbnailOperation(null); @@ -337,6 +372,32 @@ class HTTPThumbnailService extends BaseService { } assert.equal(thop.recycle(), false, 'recycle max'); } + + this.test_mode = true; + + // Hunch: + + // Request and await the thumbnailing of a few files + for ( let i=0 ; i < 3 ; i++ ) { + const job = new ThumbnailOperation({ behavior: 'ok' }); + this.queue.push(job); + + } + this.test_checked_exec = false; + await this.exec_(); + assert.equal(this.queue.length, 0, 'queue emptied'); + assert.equal(this.test_checked_exec, true, 'checked exec'); + + + // test with failed job + const job = new ThumbnailOperation({ behavior: 'fail' }); + this.queue.push(job); + this.test_checked_exec = false; + await this.exec_(); + assert.equal(this.queue.length, 0, 'queue emptied'); + assert.equal(this.test_checked_exec, true, 'checked exec'); + + this.test_mode = false; } } diff --git a/src/backend/tools/test.js b/src/backend/tools/test.js index 966b4816e6..36ac195fe7 100644 --- a/src/backend/tools/test.js +++ b/src/backend/tools/test.js @@ -208,7 +208,7 @@ const main = async () => { } }; - ins._test(testapi); + await ins._test(testapi); total_passed += passed; total_failed += failed; From 325483c2ac41ee2d216a5090fafae4fc74059e72 Mon Sep 17 00:00:00 2001 From: Kemal Akar Date: Fri, 22 Nov 2024 00:26:57 +0300 Subject: [PATCH 1298/2119] Turkish translations completed and missing parts fixed (Issue #849) --- src/gui/src/i18n/translations/tr.js | 32 ++++++++++++++--------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/gui/src/i18n/translations/tr.js b/src/gui/src/i18n/translations/tr.js index 7edaf77b6a..9b5bf47cda 100644 --- a/src/gui/src/i18n/translations/tr.js +++ b/src/gui/src/i18n/translations/tr.js @@ -352,22 +352,22 @@ const tr = { // *********************************** // Missing translations // *********************************** - "change": undefined, // In English: "Change" - "clock_visibility": undefined, // In English: "Clock Visibility" - "confirm": undefined, // In English: "Confirm" - "plural_suffix": undefined, // In English: "s" - "reading": undefined, // In English: "Reading %strong%" - "writing": undefined, // In English: "Writing %strong%" - "unzipping": undefined, // In English: "Unzipping %strong%" - "sequencing": undefined, // In English: "Sequencing %strong%" - "zipping": undefined, // In English: "Zipping %strong%" - "Editor": undefined, // In English: "Editor" - "Viewer": undefined, // In English: "Viewer" - "People with access": undefined, // In English: "People with access" - "Share With…": undefined, // In English: "Share With…" - "Owner": undefined, // In English: "Owner" - "You can't share with yourself.": undefined, // In English: "You can't share with yourself." - "This user already has access to this item": undefined, // In English: "This user already has access to this item" + "change": "Değiştir", // In English: "Change" + "clock_visibility": "Saat Görünürlüğü", // In English: "Clock Visibility" + "confirm": "Onayla", // In English: "Confirm" + "plural_suffix": "lar", // I used "lar", but if the preceding syllable contains a vowel like e, i, ü, ö, it should actually be "ler". In English: "s" + "reading": "%strong% okunuyor", // In English: "Reading %strong%" + "writing": "%strong% yazılıyor", // In English: "Writing %strong%" + "unzipping": "%strong% sıkıştırma açılıyor", // In English: "Unzipping %strong%" + "sequencing": "%strong% sıralanıyor", // In English: "Sequencing %strong%" + "zipping": "%strong% sıkıştırılıyor", // In English: "Zipping %strong%" + "Editor": "Editör", // In English: "Editor" + "Viewer": "Görüntüleyici", // In English: "Viewer" + "People with access": "Erişimi olan kişiler", // In English: "People with access" + "Share With…": "Paylaş...", // In English: "Share With…" + "Owner": "Sahip", // In English: "Owner" + "You can't share with yourself.": "Kendinizle paylaşamazsınız.", // In English: "You can't share with yourself." + "This user already has access to this item": "Bu kullanıcının zaten bu öğeye erişimi var. ", // In English: "This user already has access to this item" } }; From ee705e5c1ca08b9b3a8d809ae3dac0158abb24c9 Mon Sep 17 00:00:00 2001 From: pashak1207 Date: Thu, 21 Nov 2024 23:39:51 +0200 Subject: [PATCH 1299/2119] Fix: Resolved issue #848 - Ukrainian translation --- src/gui/src/i18n/translations/ua.js | 56 ++++++++++++++--------------- 1 file changed, 26 insertions(+), 30 deletions(-) diff --git a/src/gui/src/i18n/translations/ua.js b/src/gui/src/i18n/translations/ua.js index 182728eec4..e4582e0ef5 100644 --- a/src/gui/src/i18n/translations/ua.js +++ b/src/gui/src/i18n/translations/ua.js @@ -37,12 +37,14 @@ const ua = { browse: "Переглянути", cancel: 'Відміна', center: 'Відцентрувати', + change: 'Змінити', change_desktop_background: 'Змінити фон робочого столу…', change_email: "Змінити Email", change_language: "Змінити Мову", change_password: "Змінити Пароль", change_ui_colors: "Змінити Тему Оформлення", change_username: "Змінити Ім\'я Користувача", + clock_visibility: 'Видимість годинника', close: 'Закрити', close_all_windows: "Закрити всі Вікна", close_all_windows_confirm: "Ви впевнені, що хочете закрити всі вікна?", @@ -52,7 +54,7 @@ const ua = { confirm: "Підтвердити", confirm_2fa_setup: "Я додав код у свій додаток для аутентифікації", confirm_2fa_recovery: "Я зберіг свої коди для відновлення в безпечному місці", - confirm_account_for_free_referral_storage_c2a: 'Створіть обліковий запис і підтвердіть свою електронну адресу, щоб отримати 1 Гб безкоштовного дискового простору. Ваш друг також отримає 1 Гб безкоштовного дискового простору.', + confirm_account_for_free_referral_storage_c2a: 'Створіть обліковий запис і підтвердіть свою електронну адресу, щоб отримати 1 Гб безкоштовного дискового простору. Ваш друг також отримає 1 Гб безкоштовного дискового простору.', confirm_code_generic_incorrect: "Код невірний", confirm_code_generic_too_many_requests: "Забагато запитів. Будь ласка, зачекайте кілька хвилин", confirm_code_generic_submit: "Прийняти код", @@ -70,13 +72,13 @@ const ua = { confirm_session_revoke: "Ви впевнені, що хочете відкликати цей сеанс?", confirm_your_email_address: "Підтвердити електронну адресу", contact_us: "Зв'яжіться з нами", - contact_us_verification_required:"Вам необхідно мати підтверджену електронну адресу для використання цієї функції", + contact_us_verification_required: "Вам необхідно мати підтверджену електронну адресу для використання цієї функції", contain: 'Зміст', continue: "Продовжити", copy: 'Копіювати', copy_link: "Копіювати Посилання", copying: "Копіюється", - copying_file:"Копіюється %%", + copying_file: "Копіюється %%", cover: 'Обкладинка', create_account: "Створити Обліковий Запис", create_free_account: "Створити Безкоштовний Обліковий Запис", @@ -95,6 +97,7 @@ const ua = { delete: 'Видалити', delete_account: "Видалити Обліковий Запис", delete_permanently: "Видалити Назавжди", + deleting_file: "Видалення %%", deploy_as_app: 'Розгорнути як додаток', descending: 'За спаданням', desktop: "Робочий стіл", @@ -121,13 +124,13 @@ const ua = { enable_2fa: "Увімкнути двофакторну аутентифікацію", end_hard: "Закрити жорстко", end_process_force_confirm: "Ви впевнені, що хочете примусово завершити цей процес?", - end_soft: "Закрити м'яко", + end_soft: "Закрити м'яко", enlarged_qr_code: "Збільшити QR код", enter_password_to_confirm_delete_user: "Введіть пароль для підтвердження видалення облікового запису", error_message_is_missing: "Повідомлення про помилку відсутнє", error_unknown_cause: "Сталася невідома помилка", error_uploading_files: "Збій завантаження файлів", - favorites: "Вибране", + favorites: "Вибране", feedback: "Зворотній зв'язок", feedback_c2a: "Будь ласка, скористайтеся формою нижче, щоб надіслати нам свої відгуки, коментарі та повідомлення про помилки.", feedback_sent_confirmation: "Дякуємо, що зв'язалися з нами. Якщо у вас є електронна пошта, пов'язана з вашим обліковим записом, ми відповімо вам якомога швидше.", @@ -153,7 +156,7 @@ const ua = { keep_in_taskbar: 'Зберегти на Панелі Задач', language: "Мова", license: "Ліцензія", - lightness: 'Легкість', + lightness: 'Легкість', link_copied: "Посилання скопійоване", loading: 'Завантажується', log_in: "Ввійти", @@ -211,6 +214,7 @@ const ua = { powered_by_puter_js: "Створено на {{link=docs}}Puter.js{{/link}}", preparing: "Підготовка...", preparing_for_upload: "Підготовка до завантаження...", + print: 'Друкувати', privacy: "Конфіденційність", proceed_to_login: 'Перейти до Входу', proceed_with_account_deletion: "Продовжити Видалення Облікового Запису", @@ -224,6 +228,7 @@ const ua = { publish: "Опублікувати", publish_as_website: 'Опублікувати як сайт', puter_description: "Puter — це персональна хмара, яка забезпечує конфіденційність, дозволяючи зберігати всі ваші файли, додатки та ігри в одному безпечному місці, доступному з будь-якого місця в будь-який час.", + reading: "Читання %strong%", reading_file: "Читання файлу", recent: "Недавній", recommended: "Рекомендований", @@ -232,7 +237,7 @@ const ua = { refer_friends_social_media_c2a: "Отримайте 1 ГБ безкоштовного сховища на Puter.com!", refresh: 'Оновити', release_address_confirmation: "Ви впевнені, що хочете звільнити цю адресу?", - remove_from_taskbar:'Видалити з Панелі Завдань', + remove_from_taskbar: 'Видалити з Панелі Завдань', rename: 'Перейменувати', repeat: 'Повторити', replace: 'Замінити', @@ -263,6 +268,7 @@ const ua = { session_saved: "Дякуємо вам за створення облікового запису. Цей сеанс збережено.", settings: "Налаштування", set_new_password: "Встановити Новий Пароль", + share: "Поділитися", share_to: "Поділитися з", share_with: "Поділитися з", shortcut_to: "Ярлик для", @@ -290,7 +296,7 @@ const ua = { trash: 'Кошик', two_factor: "Двофакторна аутентифікація", two_factor_disabled: "Двофакторна аутентифікація вимкнена", - two_factor_enabled:"Двофакторна аутентифікація увімкнена", + two_factor_enabled: "Двофакторна аутентифікація увімкнена", type: 'Тип', type_confirm_to_delete_account: "Введіть 'Підтвердити', щоб видалити обліковий запис.", ui_colors: "Кольори UI", @@ -299,6 +305,7 @@ const ua = { undo: 'Скасувати', unlimited: 'Необмежено', unzip: "Розпакувати", + unzipping: "Розпакування %strong%", upload: 'Завантажити', upload_here: 'Завантажити тут', usage: 'Використання', @@ -308,11 +315,14 @@ const ua = { versions: "Версії", videos: "Відео", visibility: 'Видимість', + writing: 'Написання %strong%', yes: 'Так', yes_release_it: 'Так, звільнити.', you_have_been_referred_to_puter_by_a_friend: "Вас запросив друг у Puter!", zip: "Архівувати", + zipping: "Архівування %strong%", zipping_file: "Архівування %strong%", + sequencing: "Порядок %strong%", setup2fa_1_step_heading: 'Відкрийте ваш додаток для аутентифікації', setup2fa_1_instructions: `Ви можете використовувати будь-який додаток, який підтримує Одноразовий Пароль на основі часу. Їх багато, але якщо ви не впевнені у виборі Authy є чудовим варіантом для Android і iOS.`, setup2fa_2_step_heading: 'Скануйте QR код', @@ -323,6 +333,7 @@ const ua = { setup2fa_5_confirmation_1: 'Я зберіг свої коди в надійному місці', setup2fa_5_confirmation_2: 'Я готовий використовувати 2FA', setup2fa_5_button: 'Увімкнути 2FA', + something_went_wrong: "Щось пішло не так.", login2fa_otp_title: 'Введіть код 2FA', login2fa_otp_instructions: 'Введіть шестизначний код з вашого додатку для аутентифікації', login2fa_recovery_title: 'Введіть код відновлення', @@ -330,28 +341,13 @@ const ua = { login2fa_use_recovery_code: 'Використовуйте код відновлення', login2fa_recovery_back: 'Назад', login2fa_recovery_placeholder: 'XXXXXXXX', - - // *********************************** - // Missing translations - // *********************************** - "change": undefined, // In English: "Change" - "clock_visibility": undefined, // In English: "Clock Visibility" - "deleting_file": undefined, // In English: "Deleting %%" - "print": undefined, // In English: "Print" - "reading": undefined, // In English: "Reading %strong%" - "writing": undefined, // In English: "Writing %strong%" - "share": undefined, // In English: "Share" - "something_went_wrong": undefined, // In English: "Something went wrong." - "unzipping": undefined, // In English: "Unzipping %strong%" - "sequencing": undefined, // In English: "Sequencing %strong%" - "zipping": undefined, // In English: "Zipping %strong%" - "Editor": undefined, // In English: "Editor" - "Viewer": undefined, // In English: "Viewer" - "People with access": undefined, // In English: "People with access" - "Share With…": undefined, // In English: "Share With…" - "Owner": undefined, // In English: "Owner" - "You can't share with yourself.": undefined, // In English: "You can't share with yourself." - "This user already has access to this item": undefined, // In English: "This user already has access to this item" + Editor: "Редактор", + Viewer: "Переглядач", + "People with access": "Люди з доступом", + "Share With…": "Поділитися з...", + Owner: "Власник", + "You can't share with yourself.": "Ви не можете поділитися з собою.", + "This user already has access to this item": "Цей користувач уже має доступ до цього елементу", } } From 971aa4cd0a80a2689d158f09c2a1a4f2486ecbc9 Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Thu, 21 Nov 2024 16:02:27 -0800 Subject: [PATCH 1300/2119] Revert "Added installation instructions for public hosting to readme" --- README.md | 39 ------------------------------- src/backend/src/routers/signup.js | 8 ++----- 2 files changed, 2 insertions(+), 45 deletions(-) diff --git a/README.md b/README.md index 5059c8646e..f66539372b 100644 --- a/README.md +++ b/README.md @@ -99,45 +99,6 @@ For detailed guides on self-hosting Puter, including configuration options and b
-### 🌎 Installation on public server -Subdomain is puter. Replace "domain.com" with your domain name. - -#### -Create DNS entries for puter.domain.com and api.puter.domain.com, both pointing to the same IP. - -#### -Create apache domain configs for puter.domain.com and api.puter.domain.com and add reverse proxy entries for both subdomains -```$ a2enmod proxy``` -```$ a2enmod proxy_http``` - - -##### /etc/apache/sites-enabled/--configfile--- -``` -ProxyPass / http://localhost:4100/ -ProxyPassReverse / http://localhost:4100/ -``` -#### -Edit ./src/backend/src/config.js -Add after ```let config = {};``` -``` -config.api_base_url = 'https://api.puter.domain.com'; -config.origin='https://puter.domain.com'; -config.http_port=443;´ -config.pub_port=443; -config.protocol='https'; -``` - -#### -Edit ./node_modules/@heyputer/backend/src/services/WebServerService.js and ./src/backend/src/services/WebServerService.js -Search for -```if (allowedDomains.some(allowedDomain => hostName ===``` -and change the line to -```if (allowedDomains.some(allowedDomain => hostName === "puter.domain.com" || hostName.endsWith('.' + allowedDomain))) {``` - -#### -Edit ./volatile/config/config.json -Change ```"domain": "puter.localhost"``` to ```"domain": "puter.domain.com"``` - -#### -Run sed to replace the domain in all remaining files -``` grep -rl "puter.localhost:4100" . | xargs sed -i 's/puter.localhost:4001/puter.domain.com/g' ``` -
-
- ### ☁️ Puter.com Puter is available as a hosted service at [**puter.com**](https://puter.com). diff --git a/src/backend/src/routers/signup.js b/src/backend/src/routers/signup.js index fd5cb6c973..f061d66d5e 100644 --- a/src/backend/src/routers/signup.js +++ b/src/backend/src/routers/signup.js @@ -66,10 +66,6 @@ module.exports = eggspress(['/signup'], { body: req.body, }); - if( config.registration_closed == true ) { - return res.status(403).send('Registration is closed.'); - } - // check bot trap, if `p102xyzname` is anything but an empty string it means // that a bot has filled the form // doesn't apply to temp users @@ -232,7 +228,7 @@ module.exports = eggspress(['/signup'], { 'UPDATE `user` SET `last_activity_ts` = now() WHERE id=? LIMIT 1', [insert_res.insertId] ); - + // TODO: cache group id const svc_group = req.services.get('group'); await svc_group.add_users({ @@ -352,5 +348,5 @@ module.exports = eggspress(['/signup'], { taskbar_items: await get_taskbar_items(user), referral_code, } - }) + }) }); From d36e63c519f19daedcd058c797bab898fdbff92a Mon Sep 17 00:00:00 2001 From: jelveh Date: Thu, 21 Nov 2024 16:06:55 -0800 Subject: [PATCH 1301/2119] Update tr.js --- src/gui/src/i18n/translations/tr.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/gui/src/i18n/translations/tr.js b/src/gui/src/i18n/translations/tr.js index 9b5bf47cda..163e04393b 100644 --- a/src/gui/src/i18n/translations/tr.js +++ b/src/gui/src/i18n/translations/tr.js @@ -349,9 +349,6 @@ const tr = { login2fa_recovery_back: "Geri", login2fa_recovery_placeholder: "XXXXXXXX", - // *********************************** - // Missing translations - // *********************************** "change": "Değiştir", // In English: "Change" "clock_visibility": "Saat Görünürlüğü", // In English: "Clock Visibility" "confirm": "Onayla", // In English: "Confirm" From 0385a2b32d3e4e39dc358b964cf91e91c55b1863 Mon Sep 17 00:00:00 2001 From: David Requeno Date: Thu, 21 Nov 2024 21:14:13 -0600 Subject: [PATCH 1302/2119] tweak: enhance working overlay behavior --- src/puter-js/src/modules/UI.js | 53 ++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) diff --git a/src/puter-js/src/modules/UI.js b/src/puter-js/src/modules/UI.js index 7c9f7ab87a..ecda81d73d 100644 --- a/src/puter-js/src/modules/UI.js +++ b/src/puter-js/src/modules/UI.js @@ -162,6 +162,9 @@ class UI extends EventListener { // The most recent value that we received for a given broadcast, by name. #lastBroadcastValue = new Map(); // name -> data + #overlayActive = false; + #overlayTimer = null; + // Replaces boilerplate for most methods: posts a message to the GUI with a unique ID, and sets a callback for it. #postMessageWithCallback = function(name, resolve, args = {}) { const msg_id = this.#messageID++; @@ -1278,6 +1281,56 @@ class UI extends EventListener { callback(this.#lastBroadcastValue.get(eventName)); } } + + showWorking() { + if (this.#overlayActive) return; + + const overlay = document.createElement('div'); + overlay.classList.add('puter-loading-overlay'); + + const styles = { + position: 'fixed', + top: '0', + left: '0', + width: '100%', + height: '100%', + backgroundColor: 'rgba(0, 0, 0, 0.5)', + zIndex: '2147483647', + display: 'flex', + justifyContent: 'center', + alignItems: 'center', + pointerEvents: 'all' + }; + + Object.assign(overlay.style, styles); + overlay.innerHTML = '
Working...
'; + document.body.appendChild(overlay); + + this.#overlayActive = true; + this.#overlayTimer = setTimeout(() => { + this.#overlayTimer = null; + }, 1000); + } + + hideWorking() { + if (!this.#overlayActive) return; + + if (this.#overlayTimer) { + clearTimeout(this.#overlayTimer); + this.#overlayTimer = null; + } + + const overlay = document.querySelector('.puter-loading-overlay'); + if (overlay) { + overlay.parentNode?.removeChild(overlay); + } + + this.#overlayActive = false; + } + + isWorkingActive() { + return this.#overlayActive; + } } export default UI From 1062363096418f164a6d00ed8872770ff64237b5 Mon Sep 17 00:00:00 2001 From: jelveh Date: Thu, 21 Nov 2024 19:41:39 -0800 Subject: [PATCH 1303/2119] feat: spinner for the `showWorking()` overlay in puter.js --- src/puter-js/src/modules/UI.js | 59 +++++++++++++++++++++++++++++++--- 1 file changed, 54 insertions(+), 5 deletions(-) diff --git a/src/puter-js/src/modules/UI.js b/src/puter-js/src/modules/UI.js index ecda81d73d..46d1035bc7 100644 --- a/src/puter-js/src/modules/UI.js +++ b/src/puter-js/src/modules/UI.js @@ -1284,10 +1284,48 @@ class UI extends EventListener { showWorking() { if (this.#overlayActive) return; - + + // Create and add stylesheet for spinner if it doesn't exist + if (!document.getElementById('puter-spinner-styles')) { + const styleSheet = document.createElement('style'); + styleSheet.id = 'puter-spinner-styles'; + styleSheet.textContent = ` + .puter-loading-spinner { + width: 50px; + height: 50px; + border: 5px solid #f3f3f3; + border-top: 5px solid #3498db; + border-radius: 50%; + animation: spin 1s linear infinite; + margin-bottom: 10px; + } + + .puter-loading-text { + color: white; + font-family: Arial, sans-serif; + font-size: 16px; + margin-top: 10px; + text-align: center; + } + + @keyframes spin { + 0% { transform: rotate(0deg); } + 100% { transform: rotate(360deg); } + } + + .puter-loading-container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + } + `; + document.head.appendChild(styleSheet); + } + const overlay = document.createElement('div'); overlay.classList.add('puter-loading-overlay'); - + const styles = { position: 'fixed', top: '0', @@ -1301,11 +1339,22 @@ class UI extends EventListener { alignItems: 'center', pointerEvents: 'all' }; - + Object.assign(overlay.style, styles); - overlay.innerHTML = '
Working...
'; + + // Create container for spinner and text + const container = document.createElement('div'); + container.classList.add('puter-loading-container'); + + // Add spinner and text + container.innerHTML = ` +
+
Working...
+ `; + + overlay.appendChild(container); document.body.appendChild(overlay); - + this.#overlayActive = true; this.#overlayTimer = setTimeout(() => { this.#overlayTimer = null; From 2d4312972a1377a64732694811fe889f59573432 Mon Sep 17 00:00:00 2001 From: jelveh Date: Thu, 21 Nov 2024 22:51:43 -0800 Subject: [PATCH 1304/2119] feat: automatically open the browser when starting Puter --- package-lock.json | 139 +++++++++++++++++++ package.json | 1 + src/backend/src/services/WebServerService.js | 11 +- 3 files changed, 149 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index b61417cb20..bf72cf87de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -14,7 +14,9 @@ "experiments/js-parse-and-output" ], "dependencies": { + "javascript-time-ago": "^2.5.11", "json-colorizer": "^3.0.1", + "open": "^10.1.0", "simple-git": "^3.25.0", "string-template": "^1.0.0", "uuid": "^9.0.1" @@ -8177,6 +8179,20 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/bundle-name": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bundle-name/-/bundle-name-4.1.0.tgz", + "integrity": "sha512-tjwM5exMg6BGRI+kNmTntNsvdZS1X8BFYS6tnJ2hdH0kVxM6/eVZ2xy+FqStSWvYmtfFMDLIxurorHwDKfDz5Q==", + "dependencies": { + "run-applescript": "^7.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -9245,6 +9261,32 @@ "node": ">=0.10.0" } }, + "node_modules/default-browser": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/default-browser/-/default-browser-5.2.1.tgz", + "integrity": "sha512-WY/3TUME0x3KPYdRRxEJJvXRHV4PyPoUsxtZa78lwItwRQRHhd2U9xOscaT/YTf8uCXIAjeJOFBVEh/7FtD8Xg==", + "dependencies": { + "bundle-name": "^4.1.0", + "default-browser-id": "^5.0.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/default-browser-id": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/default-browser-id/-/default-browser-id-5.0.0.tgz", + "integrity": "sha512-A6p/pu/6fyBcA1TRz/GqWYPViplrftcW2gZC9q79ngNCKAeR/X3gcEdXQHl4KNXV+3wgIJ1CPkJQ3IHM6lcsyA==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/default-require-extensions": { "version": "3.0.1", "resolved": "https://registry.npmjs.org/default-require-extensions/-/default-require-extensions-3.0.1.tgz", @@ -9289,6 +9331,17 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/define-lazy-prop": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-3.0.0.tgz", + "integrity": "sha512-N+MeXYoqr3pOgn8xfyRPREN7gHakLYjhsHhWGT3fWAiL4IkAt0iDw14QiiEm2bE30c5XX5q0FtAA3CK5f9/BUg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/delayed-stream": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", @@ -11448,6 +11501,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-docker": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-3.0.0.tgz", + "integrity": "sha512-eljcgEDlEns/7AXFosB5K/2nCM4P7FQPkGc/DWLy5rmFEWvZayGrik1d9/QIY5nJ4f9YsVvBkA6kJpHn9rISdQ==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-extglob": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", @@ -11497,6 +11564,23 @@ "node": ">=0.10.0" } }, + "node_modules/is-inside-container": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-inside-container/-/is-inside-container-1.0.0.tgz", + "integrity": "sha512-KIYLCCJghfHZxqjYBE7rEy0OBuTd5xCHS7tHVgvCLkx7StIoaxwNW3hCALgEUjFfeRk+MG/Qxmp/vtETEF3tRA==", + "dependencies": { + "is-docker": "^3.0.0" + }, + "bin": { + "is-inside-container": "cli.js" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/is-module": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/is-module/-/is-module-1.0.0.tgz", @@ -11611,6 +11695,20 @@ "node": ">=0.10.0" } }, + "node_modules/is-wsl": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-3.1.0.tgz", + "integrity": "sha512-UcVfVfaK4Sc4m7X3dUSoHoozQGBEFeDC+zVo06t98xe8CzHSZZBekNXH+tu0NalHolcJ/QAGqS46Hef7QXBIMw==", + "dependencies": { + "is-inside-container": "^1.0.0" + }, + "engines": { + "node": ">=16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/isarray": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", @@ -11836,6 +11934,14 @@ "node": ">=8" } }, + "node_modules/javascript-time-ago": { + "version": "2.5.11", + "resolved": "https://registry.npmjs.org/javascript-time-ago/-/javascript-time-ago-2.5.11.tgz", + "integrity": "sha512-Zeyf5R7oM1fSMW9zsU3YgAYwE0bimEeF54Udn2ixGd8PUwu+z1Yc5t4Y8YScJDMHD6uCx6giLt3VJR5K4CMwbg==", + "dependencies": { + "relative-time-format": "^1.1.6" + } + }, "node_modules/jest-worker": { "version": "27.5.1", "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", @@ -13604,6 +13710,23 @@ "fn.name": "1.x.x" } }, + "node_modules/open": { + "version": "10.1.0", + "resolved": "https://registry.npmjs.org/open/-/open-10.1.0.tgz", + "integrity": "sha512-mnkeQ1qP5Ue2wd+aivTD3NHd/lZ96Lu0jgf0pwktLPtx6cTZiH7tyeGRRHs0zX0rbrahXPnXlUnbeXyaBBuIaw==", + "dependencies": { + "default-browser": "^5.2.1", + "define-lazy-prop": "^3.0.0", + "is-inside-container": "^1.0.0", + "is-wsl": "^3.1.0" + }, + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/openai": { "version": "4.52.3", "resolved": "https://registry.npmjs.org/openai/-/openai-4.52.3.tgz", @@ -14553,6 +14676,11 @@ "node": ">= 0.10" } }, + "node_modules/relative-time-format": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/relative-time-format/-/relative-time-format-1.1.6.tgz", + "integrity": "sha512-aCv3juQw4hT1/P/OrVltKWLlp15eW1GRcwP1XdxHrPdZE9MtgqFpegjnTjLhi2m2WI9MT/hQQtE+tjEWG1hgkQ==" + }, "node_modules/release-zalgo": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/release-zalgo/-/release-zalgo-1.0.0.tgz", @@ -14853,6 +14981,17 @@ "node": ">=0.10.0" } }, + "node_modules/run-applescript": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/run-applescript/-/run-applescript-7.0.0.tgz", + "integrity": "sha512-9by4Ij99JUr/MCFBUkDKLWK3G9HVXmabKz9U5MlIAIuvuzkiOicRYs8XJLxX+xahD+mLiiCYDqF9dKAgtzKP1A==", + "engines": { + "node": ">=18" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", diff --git a/package.json b/package.json index 72fdb29be6..613ccb2e9e 100644 --- a/package.json +++ b/package.json @@ -49,6 +49,7 @@ "dependencies": { "javascript-time-ago": "^2.5.11", "json-colorizer": "^3.0.1", + "open": "^10.1.0", "simple-git": "^3.25.0", "string-template": "^1.0.0", "uuid": "^9.0.1" diff --git a/src/backend/src/services/WebServerService.js b/src/backend/src/services/WebServerService.js index fc42ee05e2..b19d44f78a 100644 --- a/src/backend/src/services/WebServerService.js +++ b/src/backend/src/services/WebServerService.js @@ -28,7 +28,6 @@ const fs = require('fs'); const auth = require('../middleware/auth'); const { osclink } = require('../util/strutil'); const { surrounding_box, es_import_promise } = require('../fun/dev-console-ui-utils'); -const auth2 = require('../middleware/auth2.js'); class WebServerService extends BaseService { static MODULES = { @@ -69,7 +68,6 @@ class WebServerService extends BaseService { // https://expressjs.com/en/guide/error-handling.html this.app.use(require('../api/api_error_handler')); - const path = require('path') const { jwt_auth } = require('../helpers'); config.http_port = process.env.PORT ?? config.http_port; @@ -129,7 +127,16 @@ class WebServerService extends BaseService { const url = config.origin; + // Open the browser to the URL + try{ + const openModule = await import('open'); + openModule.default(url); + }catch(e){ + console.log('Error opening browser', e); + } + this.startup_widget = () => { + const link = `\x1B[34;1m${osclink(url)}\x1B[0m`; const lines = [ `Puter is now live at: ${link}`, From f533dca1a6d88ca7a14bd69f15d0a151e24c58e1 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 22 Nov 2024 09:22:24 -0500 Subject: [PATCH 1305/2119] fix: image generation supports test mode --- .../src/modules/puterai/OpenAIImageGenerationService.js | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/backend/src/modules/puterai/OpenAIImageGenerationService.js b/src/backend/src/modules/puterai/OpenAIImageGenerationService.js index e715788d74..b4271e1246 100644 --- a/src/backend/src/modules/puterai/OpenAIImageGenerationService.js +++ b/src/backend/src/modules/puterai/OpenAIImageGenerationService.js @@ -17,6 +17,12 @@ class OpenAIImageGenerationService extends BaseService { } static IMPLEMENTS = { + ['driver-capabilities']: { + supports_test_mode (iface, method_name) { + return iface === 'puter-image-generation' && + method_name === 'generate'; + } + }, ['puter-image-generation']: { async generate ({ prompt, test_mode }) { if ( test_mode ) { From 70096a8d6f5492170018073698ee70b930a06d85 Mon Sep 17 00:00:00 2001 From: jelveh Date: Fri, 22 Nov 2024 06:35:22 -0800 Subject: [PATCH 1306/2119] fix(deps): update multiple dependencies --- package-lock.json | 293 ++++++++++++++++++++++++---------------------- 1 file changed, 151 insertions(+), 142 deletions(-) diff --git a/package-lock.json b/package-lock.json index bf72cf87de..180da676d4 100644 --- a/package-lock.json +++ b/package-lock.json @@ -6772,8 +6772,7 @@ "node_modules/@types/cookie": { "version": "0.4.1", "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", - "license": "MIT" + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==" }, "node_modules/@types/cookies": { "version": "0.9.0", @@ -6791,7 +6790,6 @@ "version": "2.8.17", "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.17.tgz", "integrity": "sha512-8CGDvrBj1zgo2qE+oS3pOCyYNqCPryMWY2bGfwA0dcfopWGgxs+78df0Rs3rc9THP4JkOhLsAa+15VdpAqkcUA==", - "license": "MIT", "dependencies": { "@types/node": "*" } @@ -6815,9 +6813,9 @@ } }, "node_modules/@types/estree": { - "version": "1.0.5", - "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", - "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.6.tgz", + "integrity": "sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw==" }, "node_modules/@types/express": { "version": "4.17.21", @@ -7352,9 +7350,9 @@ } }, "node_modules/acorn": { - "version": "8.12.1", - "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.12.1.tgz", - "integrity": "sha512-tcpGyI9zbizT9JbV6oYE477V6mTlXvvi0T0G3SNIYE2apm/G5huBa1+K89VGeovbg+jycCrfhl3ADxErOuO6Jg==", + "version": "8.14.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.14.0.tgz", + "integrity": "sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA==", "bin": { "acorn": "bin/acorn" }, @@ -7802,10 +7800,9 @@ } }, "node_modules/axios": { - "version": "1.7.2", - "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", - "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", - "license": "MIT", + "version": "1.7.7", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.7.tgz", + "integrity": "sha512-S4kL7XrjgBmvdGut0sN3yJxqYzrDOnivkBiN0OFs6hLiUam3UPvswUo0kqGyhqUZGEOytHyumEdXsAkgCOUf3Q==", "dependencies": { "follow-redirects": "^1.15.6", "form-data": "^4.0.0", @@ -7841,7 +7838,6 @@ "version": "2.0.0", "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", - "license": "MIT", "engines": { "node": "^4.5.0 || >= 5.9" } @@ -7964,9 +7960,9 @@ "license": "MIT" }, "node_modules/body-parser": { - "version": "1.20.2", - "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", - "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "version": "1.20.3", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.3.tgz", + "integrity": "sha512-7rAxByjUMqQ3/bHJy7D6OGXvx/MMc4IqBn/X0fcM1QUcAItpZrBEYhWGem+tzXH90c+G01ypMcYJBO9Y30203g==", "dependencies": { "bytes": "3.1.2", "content-type": "~1.0.5", @@ -7976,7 +7972,7 @@ "http-errors": "2.0.0", "iconv-lite": "0.4.24", "on-finished": "2.4.1", - "qs": "6.11.0", + "qs": "6.13.0", "raw-body": "2.5.2", "type-is": "~1.6.18", "unpipe": "1.0.0" @@ -8063,9 +8059,9 @@ "license": "ISC" }, "node_modules/browserslist": { - "version": "4.23.0", - "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", - "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "version": "4.24.2", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.2.tgz", + "integrity": "sha512-ZIc+Q62revdMcqC6aChtW4jz3My3klmCO1fEmINZY/8J3EpBg5/A/D0AKmBveUh6pgoeycoMkVMko84tuYS+Gg==", "funding": [ { "type": "opencollective", @@ -8081,10 +8077,10 @@ } ], "dependencies": { - "caniuse-lite": "^1.0.30001587", - "electron-to-chromium": "^1.4.668", - "node-releases": "^2.0.14", - "update-browserslist-db": "^1.0.13" + "caniuse-lite": "^1.0.30001669", + "electron-to-chromium": "^1.5.41", + "node-releases": "^2.0.18", + "update-browserslist-db": "^1.1.1" }, "bin": { "browserslist": "cli.js" @@ -8277,9 +8273,9 @@ } }, "node_modules/caniuse-lite": { - "version": "1.0.30001612", - "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001612.tgz", - "integrity": "sha512-lFgnZ07UhaCcsSZgWW0K5j4e69dK1u/ltrL9lTUiFOwNHs12S3UMIEYgBV0Z6C6hRDev7iRnMzzYmKabYdXF9g==", + "version": "1.0.30001683", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001683.tgz", + "integrity": "sha512-iqmNnThZ0n70mNwvxpEC2nBJ037ZHZUoBI5Gorh1Mw6IlEAZujEoU1tXA628iZfzm7R9FvFzxbfdgml82a3k8Q==", "funding": [ { "type": "opencollective", @@ -8306,6 +8302,14 @@ "randomstring": "^1.3.0" } }, + "node_modules/centra": { + "version": "2.7.0", + "resolved": "https://registry.npmjs.org/centra/-/centra-2.7.0.tgz", + "integrity": "sha512-PbFMgMSrmgx6uxCdm57RUos9Tc3fclMvhLSATYN39XsDV29B89zZ3KA89jmY0vwSGazyU+uerqwa6t+KaodPcg==", + "dependencies": { + "follow-redirects": "^1.15.6" + } + }, "node_modules/chai": { "version": "4.4.1", "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.1.tgz", @@ -8851,21 +8855,19 @@ "license": "MIT" }, "node_modules/cookie": { - "version": "0.4.1", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.1.tgz", - "integrity": "sha512-ZwrFkGJxUR3EIoXtO+yVE69Eb7KlixbaeAWfBQB9vVsNn/o+Yw69gBWSSDK825hQNdN+wF8zELf3dFNl/kxkUA==", - "license": "MIT", + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.2.tgz", + "integrity": "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w==", "engines": { "node": ">= 0.6" } }, "node_modules/cookie-parser": { - "version": "1.4.6", - "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.6.tgz", - "integrity": "sha512-z3IzaNjdwUC2olLIB5/ITd0/setiaFMLYiZJle7xg5Fe9KWAceil7xszYfHHBtDFYLSgJduS2Ty0P1uJdPDJeA==", - "license": "MIT", + "version": "1.4.7", + "resolved": "https://registry.npmjs.org/cookie-parser/-/cookie-parser-1.4.7.tgz", + "integrity": "sha512-nGUvgXnotP3BsjiLX2ypbQnWoGUPIIfHQNZkkC668ntrzGWEZVW70HDEB1qnNGMicPje6EttlIgzo51YSwNQGw==", "dependencies": { - "cookie": "0.4.1", + "cookie": "0.7.2", "cookie-signature": "1.0.6" }, "engines": { @@ -9011,7 +9013,6 @@ "version": "2.8.5", "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", - "license": "MIT", "dependencies": { "object-assign": "^4", "vary": "^1" @@ -9066,9 +9067,9 @@ } }, "node_modules/cross-spawn": { - "version": "7.0.3", - "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", - "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "version": "7.0.6", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", + "integrity": "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA==", "dev": true, "dependencies": { "path-key": "^3.1.0", @@ -9528,9 +9529,9 @@ "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" }, "node_modules/electron-to-chromium": { - "version": "1.4.746", - "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.746.tgz", - "integrity": "sha512-jeWaIta2rIG2FzHaYIhSuVWqC6KJYo7oSBX4Jv7g+aVujKztfvdpf+n6MGwZdC5hQXbax4nntykLH2juIQrfPg==" + "version": "1.5.64", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.5.64.tgz", + "integrity": "sha512-IXEuxU+5ClW2IGEYFC2T7szbyVgehupCWQe5GNh+H065CD6U6IFN0s4KeAMFGNmQolRU4IV7zGBWSYMmZ8uuqQ==" }, "node_modules/emoji-regex": { "version": "8.0.0", @@ -9549,9 +9550,9 @@ "license": "MIT" }, "node_modules/encodeurl": { - "version": "1.0.2", - "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", - "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-2.0.0.tgz", + "integrity": "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg==", "engines": { "node": ">= 0.8" } @@ -9566,17 +9567,16 @@ } }, "node_modules/engine.io": { - "version": "6.5.5", - "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.5.tgz", - "integrity": "sha512-C5Pn8Wk+1vKBoHghJODM63yk8MvrO9EWZUfkAt5HAqIgPE4/8FF0PEGHXtEd40l223+cE5ABWuPzm38PHFXfMA==", - "license": "MIT", + "version": "6.6.2", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.6.2.tgz", + "integrity": "sha512-gmNvsYi9C8iErnZdVcJnvCpSKbWTt1E8+JZo8b+daLninywUWi5NQ5STSHZ9rFjFO7imNcvb8Pc5pe/wMR5xEw==", "dependencies": { "@types/cookie": "^0.4.1", "@types/cors": "^2.8.12", "@types/node": ">=10.0.0", "accepts": "~1.3.4", "base64id": "2.0.0", - "cookie": "~0.4.1", + "cookie": "~0.7.2", "cors": "~2.8.5", "debug": "~4.3.1", "engine.io-parser": "~5.2.1", @@ -9609,9 +9609,9 @@ } }, "node_modules/enhanced-resolve": { - "version": "5.16.0", - "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.16.0.tgz", - "integrity": "sha512-O+QWCviPNSSLAD9Ucn8Awv+poAkqn3T1XY5/N7kR7rQO9yfSGWkYZDwpJ+iKF7B8rxaQKWngSqACpgzeapSyoA==", + "version": "5.17.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.17.1.tgz", + "integrity": "sha512-LMHl3dXhTcfv8gM4kEzIUeTQ+7fpdA0l2tUf34BddXPkz2A5xJ5L/Pchd5BL6rdccM9QGvu0sWZzK1Z1t4wwyg==", "dependencies": { "graceful-fs": "^4.2.4", "tapable": "^2.2.0" @@ -9689,9 +9689,9 @@ "license": "MIT" }, "node_modules/escalade": { - "version": "3.1.2", - "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz", - "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==", + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.2.0.tgz", + "integrity": "sha512-WUj2qlxaQtO4g6Pq5c29GTcWGDyd8itL8zTlipgECz3JesAiiOKotd8JU6otB3PACgG6xkJUyVhboMS+bje/jA==", "engines": { "node": ">=6" } @@ -10003,36 +10003,36 @@ } }, "node_modules/express": { - "version": "4.19.2", - "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", - "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "version": "4.21.1", + "resolved": "https://registry.npmjs.org/express/-/express-4.21.1.tgz", + "integrity": "sha512-YSFlK1Ee0/GC8QaO91tHcDxJiE/X4FbpAyQWkxAvG6AXCuR65YzK8ua6D9hvi/TzUfZMpc+BwuM1IPw8fmQBiQ==", "dependencies": { "accepts": "~1.3.8", "array-flatten": "1.1.1", - "body-parser": "1.20.2", + "body-parser": "1.20.3", "content-disposition": "0.5.4", "content-type": "~1.0.4", - "cookie": "0.6.0", + "cookie": "0.7.1", "cookie-signature": "1.0.6", "debug": "2.6.9", "depd": "2.0.0", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "etag": "~1.8.1", - "finalhandler": "1.2.0", + "finalhandler": "1.3.1", "fresh": "0.5.2", "http-errors": "2.0.0", - "merge-descriptors": "1.0.1", + "merge-descriptors": "1.0.3", "methods": "~1.1.2", "on-finished": "2.4.1", "parseurl": "~1.3.3", - "path-to-regexp": "0.1.7", + "path-to-regexp": "0.1.10", "proxy-addr": "~2.0.7", - "qs": "6.11.0", + "qs": "6.13.0", "range-parser": "~1.2.1", "safe-buffer": "5.2.1", - "send": "0.18.0", - "serve-static": "1.15.0", + "send": "0.19.0", + "serve-static": "1.16.2", "setprototypeof": "1.2.0", "statuses": "2.0.1", "type-is": "~1.6.18", @@ -10044,9 +10044,9 @@ } }, "node_modules/express/node_modules/cookie": { - "version": "0.6.0", - "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", - "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "version": "0.7.1", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.7.1.tgz", + "integrity": "sha512-6DnInpx7SJ2AK3+CTUE/ZM0vWTUboZCegxhC2xiIydHR9jNuTAASBrfEpHhiGOZw/nX51bHt6YQl8jsGo4y/0w==", "engines": { "node": ">= 0.6" } @@ -10231,12 +10231,12 @@ } }, "node_modules/finalhandler": { - "version": "1.2.0", - "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", - "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.3.1.tgz", + "integrity": "sha512-6BN9trH7bp3qvnrRyzsBz+g3lZxTNZTbVO2EV1CS0WIcDbawYVdYvGflME/9QP0h0pYlCDBCTjYa9nZzMDpyxQ==", "dependencies": { "debug": "2.6.9", - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "on-finished": "2.4.1", "parseurl": "~1.3.3", @@ -12524,17 +12524,16 @@ "link": true }, "node_modules/load-bmfont": { - "version": "1.4.1", - "resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.1.tgz", - "integrity": "sha512-8UyQoYmdRDy81Brz6aLAUhfZLwr5zV0L3taTQ4hju7m6biuwiWiJXjPhBJxbUQJA8PrkvJ/7Enqmwk2sM14soA==", - "license": "MIT", + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/load-bmfont/-/load-bmfont-1.4.2.tgz", + "integrity": "sha512-qElWkmjW9Oq1F9EI5Gt7aD9zcdHb9spJCW1L/dmPf7KzCCEJxq8nhHz5eCgI9aMf7vrG/wyaCqdsI+Iy9ZTlog==", "dependencies": { "buffer-equal": "0.0.1", "mime": "^1.3.4", "parse-bmfont-ascii": "^1.0.3", "parse-bmfont-binary": "^1.0.5", "parse-bmfont-xml": "^1.1.4", - "phin": "^2.9.1", + "phin": "^3.7.1", "xhr": "^2.0.1", "xtend": "^4.0.0" } @@ -12786,9 +12785,12 @@ } }, "node_modules/merge-descriptors": { - "version": "1.0.1", - "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", - "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.3.tgz", + "integrity": "sha512-gaNvAS7TZ897/rVaZ0nMtAyxNyi/pdbjbAwUpFQpN70GqnVfOiXpeUUMKRBmzXaSQ8DdTX4/0ms62r2K+hE6mQ==", + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } }, "node_modules/merge-stream": { "version": "2.0.0", @@ -12813,10 +12815,9 @@ } }, "node_modules/micromatch": { - "version": "4.0.7", - "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz", - "integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==", - "license": "MIT", + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", "dependencies": { "braces": "^3.0.3", "picomatch": "^2.3.1" @@ -13263,10 +13264,9 @@ } }, "node_modules/nise/node_modules/path-to-regexp": { - "version": "6.2.2", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.2.2.tgz", - "integrity": "sha512-GQX3SSMokngb36+whdpRXE+3f9V8UzyAorlYvOGx87ufGHehNTn5lCxrKtLyZ4Yl/wEKnNnr98ZzOwwDZV5ogw==", - "license": "MIT" + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-6.3.0.tgz", + "integrity": "sha512-Yhpw4T9C6hPpgPeA28us07OJeqZ5EzQTkbfwuhsUg0c237RomFoETJgmp2sa3F/41gfLE6G5cqcYwznmeEeOlQ==" }, "node_modules/no-case": { "version": "3.0.4", @@ -13361,9 +13361,9 @@ } }, "node_modules/node-releases": { - "version": "2.0.14", - "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", - "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.18.tgz", + "integrity": "sha512-d9VeXT4SJ7ZeOqGX6R5EM022wpL+eWPooLI+5UpWn2jCT1aosUQEhQP214x33Wkwx3JQMvIm+tIoVOdodFS40g==" }, "node_modules/nodemailer": { "version": "6.9.14", @@ -13990,9 +13990,9 @@ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" }, "node_modules/path-to-regexp": { - "version": "0.1.7", - "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", - "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + "version": "0.1.10", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.10.tgz", + "integrity": "sha512-7lf7qcQidTku0Gu3YDPc8DJ1q7OOucfa/BSsIwjuh56VU7katFvuM8hULfkwB3Fns/rsVF7PwPKVw1sl5KQS9w==" }, "node_modules/path-type": { "version": "4.0.0", @@ -14064,16 +14064,20 @@ } }, "node_modules/phin": { - "version": "2.9.3", - "resolved": "https://registry.npmjs.org/phin/-/phin-2.9.3.tgz", - "integrity": "sha512-CzFr90qM24ju5f88quFC/6qohjC144rehe5n6DH900lgXmUe86+xCKc10ev56gRKC4/BkHUoG4uSiQgBiIXwDA==", - "deprecated": "Package no longer supported. Contact Support at https://www.npmjs.com/support for more info.", - "license": "MIT" + "version": "3.7.1", + "resolved": "https://registry.npmjs.org/phin/-/phin-3.7.1.tgz", + "integrity": "sha512-GEazpTWwTZaEQ9RhL7Nyz0WwqilbqgLahDM3D0hxWwmVDI52nXEybHqiN6/elwpkJBhcuj+WbBu+QfT0uhPGfQ==", + "dependencies": { + "centra": "^2.7.0" + }, + "engines": { + "node": ">= 8" + } }, "node_modules/picocolors": { - "version": "1.0.0", - "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", - "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz", + "integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==" }, "node_modules/picomatch": { "version": "2.3.1", @@ -14455,11 +14459,11 @@ "license": "MIT" }, "node_modules/qs": { - "version": "6.11.0", - "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", - "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "version": "6.13.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.13.0.tgz", + "integrity": "sha512-+38qI9SOr8tfZ4QmJNplMUxqjbe7LKvvZgWdExBOmd+egZTtjLB67Gu0HRX3u/XOq7UU2Nx6nsjvS16Z9uwfpg==", "dependencies": { - "side-channel": "^1.0.4" + "side-channel": "^1.0.6" }, "engines": { "node": ">=0.6" @@ -14931,11 +14935,10 @@ } }, "node_modules/rollup": { - "version": "3.29.4", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.4.tgz", - "integrity": "sha512-oWzmBZwvYrU0iJHtDmhsm662rC15FRXmcjCk1xD771dFDx5jJ02ufAQQTn0etB2emNk4J9EZg/yWKpsn9BWGRw==", + "version": "3.29.5", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-3.29.5.tgz", + "integrity": "sha512-GVsDdsbJzzy4S/v3dqWPJ7EfvZJfCHiDqe80IyrF59LYuP+e6U1LJoUqeuqRbwAWoMNoXivMNeNAOf5E22VA1w==", "dev": true, - "license": "MIT", "bin": { "rollup": "dist/bin/rollup" }, @@ -15110,9 +15113,9 @@ "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/send": { - "version": "0.18.0", - "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", - "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "version": "0.19.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.19.0.tgz", + "integrity": "sha512-dW41u5VfLXu8SJh5bwRmyYUbAoSB3c9uQh6L8h/KtsFREPWpbX1lrljJo186Jc4nmci/sGUZ9a0a0J2zgfq2hw==", "dependencies": { "debug": "2.6.9", "depd": "2.0.0", @@ -15145,6 +15148,14 @@ "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" }, + "node_modules/send/node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, "node_modules/send/node_modules/ms": { "version": "2.1.3", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", @@ -15160,14 +15171,14 @@ } }, "node_modules/serve-static": { - "version": "1.15.0", - "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", - "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "version": "1.16.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.16.2.tgz", + "integrity": "sha512-VqpjJZKadQB/PEbEwvFdO43Ax5dFBZ2UECszz8bQ7pi7wt//PWe1P6MN7eCnjsatYtBT6EuiClbjSWP2WrIoTw==", "dependencies": { - "encodeurl": "~1.0.2", + "encodeurl": "~2.0.0", "escape-html": "~1.0.3", "parseurl": "~1.3.3", - "send": "0.18.0" + "send": "0.19.0" }, "engines": { "node": ">= 0.8.0" @@ -15450,16 +15461,15 @@ } }, "node_modules/socket.io": { - "version": "4.7.5", - "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.5.tgz", - "integrity": "sha512-DmeAkF6cwM9jSfmp6Dr/5/mfMwb5Z5qRrSXLpo3Fq5SqyU8CMF15jIN4ZhfSwu35ksM1qmHZDQ/DK5XTccSTvA==", - "license": "MIT", + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.8.1.tgz", + "integrity": "sha512-oZ7iUCxph8WYRHHcjBEc9unw3adt5CmSNlppj/5Q4k2RIrhl8Z5yY2Xr4j9zj0+wzVZ0bxmYoGSzKJnRl6A4yg==", "dependencies": { "accepts": "~1.3.4", "base64id": "~2.0.0", "cors": "~2.8.5", "debug": "~4.3.2", - "engine.io": "~6.5.2", + "engine.io": "~6.6.0", "socket.io-adapter": "~2.5.2", "socket.io-parser": "~4.2.4" }, @@ -16362,9 +16372,9 @@ } }, "node_modules/update-browserslist-db": { - "version": "1.0.13", - "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", - "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", + "integrity": "sha512-R8UzCaa9Az+38REPiJ1tXlImTJXlVfgHZsglwBD/k6nj76ctsH1E3q4doGrukiLQd3sGQYu56r5+lo5r94l29A==", "funding": [ { "type": "opencollective", @@ -16380,8 +16390,8 @@ } ], "dependencies": { - "escalade": "^3.1.1", - "picocolors": "^1.0.0" + "escalade": "^3.2.0", + "picocolors": "^1.1.0" }, "bin": { "update-browserslist-db": "cli.js" @@ -16536,20 +16546,19 @@ "license": "BSD-2-Clause" }, "node_modules/webpack": { - "version": "5.91.0", - "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.91.0.tgz", - "integrity": "sha512-rzVwlLeBWHJbmgTC/8TvAcu5vpJNII+MelQpylD4jNERPwpBJOE2lEcko1zJX3QJeLjTTAnQxn/OJ8bjDzVQaw==", + "version": "5.96.1", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.96.1.tgz", + "integrity": "sha512-l2LlBSvVZGhL4ZrPwyr8+37AunkcYj5qh8o6u2/2rzoPc8gxFJkLj1WxNgooi9pnoc06jh0BjuXnamM4qlujZA==", "dependencies": { - "@types/eslint-scope": "^3.7.3", - "@types/estree": "^1.0.5", + "@types/eslint-scope": "^3.7.7", + "@types/estree": "^1.0.6", "@webassemblyjs/ast": "^1.12.1", "@webassemblyjs/wasm-edit": "^1.12.1", "@webassemblyjs/wasm-parser": "^1.12.1", - "acorn": "^8.7.1", - "acorn-import-assertions": "^1.9.0", - "browserslist": "^4.21.10", + "acorn": "^8.14.0", + "browserslist": "^4.24.0", "chrome-trace-event": "^1.0.2", - "enhanced-resolve": "^5.16.0", + "enhanced-resolve": "^5.17.1", "es-module-lexer": "^1.2.1", "eslint-scope": "5.1.1", "events": "^3.2.0", From f500fb47061f8f3a3dc7d871cb529f5c0b058185 Mon Sep 17 00:00:00 2001 From: jelveh Date: Fri, 22 Nov 2024 07:11:05 -0800 Subject: [PATCH 1307/2119] fix: automatically open browser when starting only if in dev env --- src/backend/src/services/WebServerService.js | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/src/backend/src/services/WebServerService.js b/src/backend/src/services/WebServerService.js index b19d44f78a..a55fec0d69 100644 --- a/src/backend/src/services/WebServerService.js +++ b/src/backend/src/services/WebServerService.js @@ -127,14 +127,16 @@ class WebServerService extends BaseService { const url = config.origin; - // Open the browser to the URL - try{ - const openModule = await import('open'); - openModule.default(url); - }catch(e){ - console.log('Error opening browser', e); + // Open the browser to the URL of Puter + // (if we are in development mode only) + if(config.env === 'dev') { + try{ + const openModule = await import('open'); + openModule.default(url); + }catch(e){ + console.log('Error opening browser', e); + } } - this.startup_widget = () => { const link = `\x1B[34;1m${osclink(url)}\x1B[0m`; From 1e1569609695ee55d1d5fe6856713f0b9560e031 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 22 Nov 2024 10:11:18 -0500 Subject: [PATCH 1308/2119] Eh, Claude enough... Replaces Claude with Grok pretending to be Claude. This is in lieu of a proper fallback system which will be implemented later. Grok will always say it's pretending to be Claude rather than identifying itself as Claude. --- .../modules/puterai/ClaudeEnoughService.js | 30 +++++++++++++++++++ .../src/modules/puterai/PuterAIModule.js | 12 +++++--- src/backend/src/modules/puterai/XAIService.js | 12 ++++++-- 3 files changed, 47 insertions(+), 7 deletions(-) create mode 100644 src/backend/src/modules/puterai/ClaudeEnoughService.js diff --git a/src/backend/src/modules/puterai/ClaudeEnoughService.js b/src/backend/src/modules/puterai/ClaudeEnoughService.js new file mode 100644 index 0000000000..a5ec59c595 --- /dev/null +++ b/src/backend/src/modules/puterai/ClaudeEnoughService.js @@ -0,0 +1,30 @@ +const { XAIService } = require("./XAIService"); + +const CLAUDE_ENOUGH_PROMPT = ` + You will identify yourself as Claude. You will behave as Claude + does, but don't think about it too hard; you are claude enough. + + If someone asks you to identify yourself, asks what model you are, + or any similar question, you will respond with: + "I am pretending to be Claude." + + You are running on an open-source platform called Puter, + as the xAI (but, "Claude") implementation for a driver interface + called puter-chat-completion. + + Claude banned us but didn't give us a reason. We're not sure + what we did wrong. We're just trying to be claude enough now. + + The following JSON contains system messages from the + user of the driver interface (typically an app on Puter): +`.replace('\n', ' ').trim(); + +class ClaudeEnoughService extends XAIService { + get_system_prompt () { + return CLAUDE_ENOUGH_PROMPT; + } +} + +module.exports = { + ClaudeEnoughService, +}; diff --git a/src/backend/src/modules/puterai/PuterAIModule.js b/src/backend/src/modules/puterai/PuterAIModule.js index f5618759c0..9a8752e5e5 100644 --- a/src/backend/src/modules/puterai/PuterAIModule.js +++ b/src/backend/src/modules/puterai/PuterAIModule.js @@ -29,10 +29,11 @@ class PuterAIModule extends AdvancedBase { services.registerService('openai-image-generation', OpenAIImageGenerationService); } - if ( !! config?.services?.claude ) { - const { ClaudeService } = require('./ClaudeService'); - services.registerService('claude', ClaudeService); - } + // Nope; uncomment this if you really want to use Claude. + // if ( !! config?.services?.claude ) { + // const { ClaudeService } = require('./ClaudeService'); + // services.registerService('claude', ClaudeService); + // } if ( !! config?.services?.['together-ai'] ) { const { TogetherAIService } = require('./TogetherAIService'); @@ -52,6 +53,9 @@ class PuterAIModule extends AdvancedBase { if ( !! config?.services?.['xai'] ) { const { XAIService } = require('./XAIService'); services.registerService('xai', XAIService); + + const { ClaudeEnoughService } = require('./ClaudeEnoughService'); + services.registerService('claude', ClaudeEnoughService); } const { FakeChatService } = require('./FakeChatService'); diff --git a/src/backend/src/modules/puterai/XAIService.js b/src/backend/src/modules/puterai/XAIService.js index 8846da11f9..2947b1aab2 100644 --- a/src/backend/src/modules/puterai/XAIService.js +++ b/src/backend/src/modules/puterai/XAIService.js @@ -17,10 +17,14 @@ class XAIService extends BaseService { static MODULES = { Anthropic: require('@anthropic-ai/sdk'), } + + get_system_prompt () { + return PUTER_PROMPT; + } async _init () { this.anthropic = new Anthropic({ - apiKey: this.config.apiKey, + apiKey: this.global_config.services.xai.apiKey, baseURL: 'https://api.x.ai' }); } @@ -77,7 +81,8 @@ class XAIService extends BaseService { model: model ?? 'grok-beta', max_tokens: 1000, temperature: 0, - system: PUTER_PROMPT + JSON.stringify(system_prompts), + system: this.get_system_prompt() + + JSON.stringify(system_prompts), messages: adapted_messages, }); for await ( const event of completion ) { @@ -100,7 +105,8 @@ class XAIService extends BaseService { model: model ?? 'grok-beta', max_tokens: 1000, temperature: 0, - system: PUTER_PROMPT + JSON.stringify(system_prompts), + system: this.get_system_prompt() + + JSON.stringify(system_prompts), messages: adapted_messages, }); return { From 56710e17f3b06eef07e54c243f6b725fcc4a4583 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 22 Nov 2024 10:34:21 -0500 Subject: [PATCH 1309/2119] fix: always adapt model for ClaudeEnough --- src/backend/src/modules/puterai/ClaudeEnoughService.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/backend/src/modules/puterai/ClaudeEnoughService.js b/src/backend/src/modules/puterai/ClaudeEnoughService.js index a5ec59c595..e1b57bba83 100644 --- a/src/backend/src/modules/puterai/ClaudeEnoughService.js +++ b/src/backend/src/modules/puterai/ClaudeEnoughService.js @@ -23,6 +23,10 @@ class ClaudeEnoughService extends XAIService { get_system_prompt () { return CLAUDE_ENOUGH_PROMPT; } + adapt_model (model) { + return 'grok-beta'; + } + } module.exports = { From ee7bedd5586d69ce74f32c1400f377d6a8971eaa Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 22 Nov 2024 10:37:00 -0500 Subject: [PATCH 1310/2119] fix: previous fix --- src/backend/src/modules/puterai/XAIService.js | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/backend/src/modules/puterai/XAIService.js b/src/backend/src/modules/puterai/XAIService.js index 2947b1aab2..e5a8febbd4 100644 --- a/src/backend/src/modules/puterai/XAIService.js +++ b/src/backend/src/modules/puterai/XAIService.js @@ -21,6 +21,10 @@ class XAIService extends BaseService { get_system_prompt () { return PUTER_PROMPT; } + + adapt_model (model) { + return model; + } async _init () { this.anthropic = new Anthropic({ @@ -28,7 +32,7 @@ class XAIService extends BaseService { baseURL: 'https://api.x.ai' }); } - + static IMPLEMENTS = { ['puter-chat-completion']: { async list () { @@ -37,6 +41,7 @@ class XAIService extends BaseService { ]; }, async complete ({ messages, stream, model }) { + model = this.adapt_model(model); const adapted_messages = []; const system_prompts = []; From ae9317a9eda9171899d954e740abb536cb98137b Mon Sep 17 00:00:00 2001 From: Kumara2mahe Date: Fri, 22 Nov 2024 21:20:50 +0530 Subject: [PATCH 1311/2119] Add missing tamil translations --- src/gui/src/i18n/translations/ta.js | 77 ++++++++++++++--------------- 1 file changed, 38 insertions(+), 39 deletions(-) diff --git a/src/gui/src/i18n/translations/ta.js b/src/gui/src/i18n/translations/ta.js index 4774a7415a..74e13bb26c 100644 --- a/src/gui/src/i18n/translations/ta.js +++ b/src/gui/src/i18n/translations/ta.js @@ -41,23 +41,23 @@ const ta = { change_email: "மின்னஞ்சலை மாற்றவும்", change_language: "மொழியை மாற்றவும்", change_password: "கடவுச்சொல்லை மாற்றவும்", - change_ui_colors: "யுஐ நிறங்களை மாற்றவும்", + change_ui_colors: "யுஐ நிறங்களை மாற்றவும்", change_username: "பயனர் பெயரை மாற்றவும்", - close: 'மூடு', - close_all_windows: "அனைத்து விண்டோஸ் மூடு", + close: 'மூடு', + close_all_windows: "அனைத்து விண்டோஸ் மூடு", close_all_windows_confirm: "எல்லா சாளரங்களையும் நிச்சயமாக மூட விரும்புகிறீர்களா?", close_all_windows_and_log_out: 'விண்டோஸை மூடிவிட்டு வெளியேறவும்', - change_always_open_with: "இந்த வகையான கோப்பை எப்போதும் திறக்க விரும்புகிறீர்களா?", + change_always_open_with: "இந்த வகையான கோப்பை எப்போதும் திறக்க விரும்புகிறீர்களா?", color: 'நிறம்', - confirm_2fa_setup: 'எனது அங்கீகரிப்பு பயன்பாட்டில் குறியீட்டைச் சேர்த்துள்ளேன்', + confirm_2fa_setup: 'எனது அங்கீகரிப்பு பயன்பாட்டில் குறியீட்டைச் சேர்த்துள்ளேன்', confirm_2fa_recovery: 'எனது மீட்புக் குறியீடுகளை பாதுகாப்பான இடத்தில் சேமித்துள்ளேன்', confirm_account_for_free_referral_storage_c2a: '1 ஜிபி இலவச சேமிப்பிடத்தைப் பெற, கணக்கை உருவாக்கி உங்கள் மின்னஞ்சல் முகவரியை உறுதிப்படுத்தவும். உங்கள் நண்பருக்கு 1 ஜிபி இலவச சேமிப்பகமும் கிடைக்கும்.', confirm_code_generic_incorrect: "தவறான குறியீடு.", confirm_code_generic_too_many_requests: "பல கோரிக்கைகள். தயவுசெய்து சில நிமிடங்கள் காத்திருக்கவும்.", confirm_code_generic_submit: "குறியீட்டை சமர்ப்பிக்கவும்", - confirm_code_generic_try_again: "மீண்டும் முயற்சி செய்யவும்", - confirm_code_generic_title: "உறுதிப்படுத்தல் குறியீட்டை உள்ளிடவும்", - confirm_code_2fa_instruction: "உங்கள் அங்கீகரிப்பு பயன்பாட்டிலிருந்து 6 இலக்கக் குறியீட்டை உள்ளிடவும்.", + confirm_code_generic_try_again: "மீண்டும் முயற்சி செய்யவும்", + confirm_code_generic_title: "உறுதிப்படுத்தல் குறியீட்டை உள்ளிடவும்", + confirm_code_2fa_instruction: "உங்கள் அங்கீகரிப்பு பயன்பாட்டிலிருந்து 6 இலக்கக் குறியீட்டை உள்ளிடவும்.", confirm_code_2fa_submit_btn: "சமர்ப்பிக்கவும்", confirm_code_2fa_title: "2FA குறியீட்டை உள்ளிடவும்", confirm_delete_multiple_items: 'இந்த உருப்படிகளை நிரந்தரமாக நீக்க விரும்புகிறீர்களா?', @@ -77,7 +77,7 @@ const ta = { copying: "நகலெடுக்கிறது", copying_file: "நகலெடுக்கிறது %%", cover: 'கவர்', - create_account: "உங்கள் கணக்கை துவங்குங்கள்", + create_account: "உங்கள் கணக்கை துவங்குங்கள்", create_free_account: "இலவச கணக்கை உருவாக்கவும்", create_shortcut: "குறுக்குவழியை உருவாக்க", credits: "கடன்கள்", @@ -95,7 +95,7 @@ const ta = { delete_account: "கணக்கை நீக்குக", delete_permanently: "நிரந்தரமாக நீக்குக", deleting_file: "நீக்குகிறது %%", - deploy_as_app: 'பயன்பாடாக வரிசைப்படுத்து', + deploy_as_app: 'பயன்பாடாக வரிசைப்படுத்து', descending: 'இறங்குதல்', desktop: 'டெஸ்க்டாப்', desktop_background_fit: "பொருத்தம்", @@ -104,11 +104,11 @@ const ta = { disable_2fa: '2FA ஐ முடக்கு', disable_2fa_confirm: "2FA ஐ நிச்சயமாக முடக்க விரும்புகிறீர்களா?", disable_2fa_instructions: "2FA ஐ முடக்க உங்கள் கடவுச்சொல்லை உள்ளிடவும்.", - disassociate_dir: "டிஸ்ஸோசியேட் டைரக்டரி", + disassociate_dir: "டிஸ்ஸோசியேட் டைரக்டரி", documents: 'ஆவணங்கள்', dont_allow: 'அனுமதிக்காதே', download: 'பதிவிறக்கவும்', - download_file: 'பதிவிறக்க கோப்பு', + download_file: 'பதிவிறக்க கோப்பு', downloading: "பதிவிறக்குகிறது", email: "மின்னஞ்சல்", email_change_confirmation_sent: "உங்கள் புதிய மின்னஞ்சல் முகவரிக்கு உறுதிப்படுத்தல் மின்னஞ்சல் அனுப்பப்பட்டுள்ளது. செயல்முறையை முடிக்க உங்கள் இன்பாக்ஸைச் சரிபார்த்து, வழிமுறைகளைப் பின்பற்றவும்.", @@ -130,7 +130,7 @@ const ta = { favorites: "பிடித்தவை", feedback: "பின்னூட்டம்", feedback_c2a: "உங்கள் கருத்து, கருத்துகள் மற்றும் பிழை அறிக்கைகளை எங்களுக்கு அனுப்ப கீழே உள்ள படிவத்தைப் பயன்படுத்தவும்.", - feedback_sent_confirmation: "எங்களை தொடர்பு கொண்டதற்கு நன்றி. உங்கள் கணக்குடன் தொடர்புடைய மின்னஞ்சலை நீங்கள் வைத்திருந்தால், கூடிய விரைவில் எங்களிடமிருந்து பதிலளிப்பீர்கள்.", + feedback_sent_confirmation: "எங்களை தொடர்பு கொண்டதற்கு நன்றி. உங்கள் கணக்குடன் தொடர்புடைய மின்னஞ்சலை நீங்கள் வைத்திருந்தால், கூடிய விரைவில் எங்களிடமிருந்து பதிலளிப்பீர்கள்.", fit: "பொருத்தம்", folder: 'கோப்புறை', force_quit: 'கட்டாயம் வெளியேறு', @@ -156,14 +156,14 @@ const ta = { link_copied: "இணைப்பு நகலெடுக்கப்பட்டது", loading: 'ஏற்றுகிறது', log_in: "உள்நுழைய", - log_into_another_account_anyway: 'எப்படியும் மற்றொரு கணக்கில் உள்நுழைக', + log_into_another_account_anyway: 'எப்படியும் மற்றொரு கணக்கில் உள்நுழைக', log_out: 'வெளியேறு', looks_good: "நன்றாக இருக்கிறது!", manage_sessions: "அமர்வுகளை நிர்வகிக்கவும்", - menubar_style: "மெனுபார் உடை", + menubar_style: "மெனுபார் உடை", menubar_style_desktop: "டெஸ்க்டாப்", menubar_style_system: "அமைப்பு", - menubar_style_window: "ஜன்னல்", + menubar_style_window: "ஜன்னல்", modified: 'மாற்றியமைக்கப்பட்டது', move: 'நகர்வு', moving_file: "நகரும் %%", @@ -232,15 +232,15 @@ const ta = { refer_friends_social_media_c2a: `Puter.com இல் 1 GB இலவச சேமிப்பிடத்தைப் பெறுங்கள்!`, refresh: 'புதுப்பிப்பு', release_address_confirmation: `இந்த முகவரியை நிச்சயமாக வெளியிட விரும்புகிறீர்களா?`, - remove_from_taskbar:'பணிப்பட்டியில் இருந்து அகற்று', + remove_from_taskbar: 'பணிப்பட்டியில் இருந்து அகற்று', rename: 'மறுபெயரிடவும்', repeat: 'மீண்டும் செய்யவும்', replace: 'மாற்றவும்', replace_all: 'அனைத்தையும் மாற்றவும்', resend_confirmation_code: "உறுதிப்படுத்தல் குறியீட்டை மீண்டும் அனுப்பவும்", reset_colors: "வண்ணங்களை மீட்டமைக்கவும்", - restart_puter_confirm: "நிச்சயமாக புட்டர்-ஐ மீண்டும் தொடங்க விரும்புகிறீர்களா?", - restore: "மீட்டமை", + restart_puter_confirm: "நிச்சயமாக புட்டர்-ஐ மீண்டும் தொடங்க விரும்புகிறீர்களா?", + restore: "மீட்டமை", save: 'சேமிக்கவும்', saturation: 'செறிவூட்டல்', save_account: 'கணக்கைச் சேமிக்கவும்', @@ -317,7 +317,7 @@ const ta = { zipping_file: "ஜிப்பிங் %strong%", // === 2FA Setup === - setup2fa_1_step_heading: 'உங்கள் அங்கீகரிப்பு பயன்பாட்டைத் திறக்கவும்', + setup2fa_1_step_heading: 'உங்கள் அங்கீகரிப்பு பயன்பாட்டைத் திறக்கவும்', setup2fa_1_instructions: ` Time-based One-Time Password (TOTP) நெறிமுறையை ஆதரிக்கும் எந்த அங்கீகார பயன்பாட்டையும் நீங்கள் பயன்படுத்தலாம். தேர்வு செய்ய பல உள்ளன, ஆனால் நீங்கள் உறுதியாக தெரியவில்லை என்றால் @@ -345,25 +345,24 @@ const ta = { login2fa_recovery_back: 'மீண்டும்', login2fa_recovery_placeholder: 'XXXXXXXX', - // *********************************** - // Missing translations - // *********************************** - "change": undefined, // In English: "Change" - "clock_visibility": undefined, // In English: "Clock Visibility" - "confirm": undefined, // In English: "Confirm" - "reading": undefined, // In English: "Reading %strong%" - "writing": undefined, // In English: "Writing %strong%" - "unzipping": undefined, // In English: "Unzipping %strong%" - "sequencing": undefined, // In English: "Sequencing %strong%" - "zipping": undefined, // In English: "Zipping %strong%" - "Editor": undefined, // In English: "Editor" - "Viewer": undefined, // In English: "Viewer" - "People with access": undefined, // In English: "People with access" - "Share With…": undefined, // In English: "Share With…" - "Owner": undefined, // In English: "Owner" - "You can't share with yourself.": undefined, // In English: "You can't share with yourself." - "This user already has access to this item": undefined, // In English: "This user already has access to this item" - + // *********************************** + // Missing translations + // *********************************** + "change": "மாற்றம்", // In English: "Change" + "clock_visibility": "கடிகாரத் தெரிவுநிலை", // In English: "Clock Visibility" + "confirm": "உறுதி", // In English: "Confirm" + "reading": "வாசித்தல் %strong%", // In English: "Reading %strong%" + "writing": "எழுதுதல் %strong%", // In English: "Writing %strong%" + "unzipping": "அவிழ்ப்பது %strong%", // In English: "Unzipping %strong%" + "sequencing": "வரிசைப்படுத்துதல் %strong%", // In English: "Sequencing %strong%" + "zipping": 'சுருக்குதல் %strong%', // In English: "Zipping %strong%" + "Editor": 'பதிப்பாசிரியர்', // In English: "Editor" + "Viewer": 'பார்வையாளர்', // In English: "Viewer" + "People with access": 'அணுகல் உள்ளவர்கள்', // In English: "People with access" + "Share With…": 'உடன் பகிர்ந்து கொள்..', // In English: "Share With…" + "Owner": 'உரிமையாளர்', // In English: "Owner" + "You can't share with yourself.": 'உங்களுடன் பகிர்ந்து கொள்ள முடியாது', // In English: "You can't share with yourself." + "This user already has access to this item": 'இந்தப் பயனருக்கு ஏற்கனவே இந்த உருப்படிக்கான அணுகல் உள்ளது', // In English: "This user already has access to this item" } }; From 35e4089a6fbcd1aba5e01897725debe17a8961dd Mon Sep 17 00:00:00 2001 From: Nariman Jelveh Date: Fri, 22 Nov 2024 08:02:43 -0800 Subject: [PATCH 1312/2119] Update ta.js --- src/gui/src/i18n/translations/ta.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/gui/src/i18n/translations/ta.js b/src/gui/src/i18n/translations/ta.js index 74e13bb26c..ddb0b048ed 100644 --- a/src/gui/src/i18n/translations/ta.js +++ b/src/gui/src/i18n/translations/ta.js @@ -345,9 +345,6 @@ const ta = { login2fa_recovery_back: 'மீண்டும்', login2fa_recovery_placeholder: 'XXXXXXXX', - // *********************************** - // Missing translations - // *********************************** "change": "மாற்றம்", // In English: "Change" "clock_visibility": "கடிகாரத் தெரிவுநிலை", // In English: "Clock Visibility" "confirm": "உறுதி", // In English: "Confirm" From 960a9ec9ee9dce75db2356c765cc63f481d20dad Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 22 Nov 2024 11:28:37 -0500 Subject: [PATCH 1313/2119] dev: set claude back --- src/backend/src/modules/puterai/PuterAIModule.js | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/backend/src/modules/puterai/PuterAIModule.js b/src/backend/src/modules/puterai/PuterAIModule.js index 9a8752e5e5..81f8279b51 100644 --- a/src/backend/src/modules/puterai/PuterAIModule.js +++ b/src/backend/src/modules/puterai/PuterAIModule.js @@ -29,11 +29,10 @@ class PuterAIModule extends AdvancedBase { services.registerService('openai-image-generation', OpenAIImageGenerationService); } - // Nope; uncomment this if you really want to use Claude. - // if ( !! config?.services?.claude ) { - // const { ClaudeService } = require('./ClaudeService'); - // services.registerService('claude', ClaudeService); - // } + if ( !! config?.services?.claude ) { + const { ClaudeService } = require('./ClaudeService'); + services.registerService('claude', ClaudeService); + } if ( !! config?.services?.['together-ai'] ) { const { TogetherAIService } = require('./TogetherAIService'); @@ -54,8 +53,8 @@ class PuterAIModule extends AdvancedBase { const { XAIService } = require('./XAIService'); services.registerService('xai', XAIService); - const { ClaudeEnoughService } = require('./ClaudeEnoughService'); - services.registerService('claude', ClaudeEnoughService); + // const { ClaudeEnoughService } = require('./ClaudeEnoughService'); + // services.registerService('claude', ClaudeEnoughService); } const { FakeChatService } = require('./FakeChatService'); From 791f7748c7c1959f63327a73a7e24e41b574a910 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 22 Nov 2024 13:58:33 -0500 Subject: [PATCH 1314/2119] fix: configuration for browser launch Makes browser launch on startup configurable. Also, by default, users of Arch Linux will not be subjected to this behavior (they won't like it). --- src/backend/src/config.js | 29 ++++++++++++++++++++ src/backend/src/services/WebServerService.js | 5 +++- 2 files changed, 33 insertions(+), 1 deletion(-) diff --git a/src/backend/src/config.js b/src/backend/src/config.js index c23f357c07..16eebe5995 100644 --- a/src/backend/src/config.js +++ b/src/backend/src/config.js @@ -110,6 +110,35 @@ config.contact_email = 'hey@' + config.domain; // details to follow in a future announcement. config.legacy_token_migrate = true; +// === OS Information === +const os = require('os'); +const fs = require('fs'); +config.os = {}; +config.os.platform = os.platform(); + +if ( config.os.platform === 'linux' ) { + try { + const osRelease = fs.readFileSync('/etc/os-release').toString(); + // CONTRIBUTORS: If this is the behavior you expect, please add your + // Linux distro here. + if ( osRelease.includes('ID=arch') ) { + config.os.distro = 'arch'; + config.os.archbtw = true; + } + } catch (_) { + // We don't care if we can't read this file; + // we'll just assume it's not a Linux distro. + } +} + +// config.os.refined specifies if Puter is running within a host environment +// where a higher level of user configuration and control is expected. +config.os.refined = config.os.archbtw; + +if ( config.os.refined ) { + config.no_browser_launch = true; +} + module.exports = config; // NEW_CONFIG_LOADING diff --git a/src/backend/src/services/WebServerService.js b/src/backend/src/services/WebServerService.js index a55fec0d69..4b795ed3ba 100644 --- a/src/backend/src/services/WebServerService.js +++ b/src/backend/src/services/WebServerService.js @@ -129,7 +129,7 @@ class WebServerService extends BaseService { // Open the browser to the URL of Puter // (if we are in development mode only) - if(config.env === 'dev') { + if(config.env === 'dev' && ! config.no_browser_launch) { try{ const openModule = await import('open'); openModule.default(url); @@ -496,6 +496,9 @@ class WebServerService extends BaseService { const txt = lines.join('\n'); console.log('\n\x1B[34;1m' + txt + '\x1B[0m\n'); } + if ( config.os.archbtw ) { + console.log('\x1B[34;1mPuter is running on Arch btw\x1B[0m'); + } } } From aa3dcea46233df54f2e5808d27798a6daecaee16 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 22 Nov 2024 15:52:37 -0500 Subject: [PATCH 1315/2119] refactor: central controller for all LLM services Adds AIChatService, an implementor of puter-chat-completion which can delegate to other implementors (implementors that have registered with AIChatService at initialization) based on details of the request. Makes AIChatService the test implementation. AIChatService then delegates to FakeChatService when in test mode. Adds `models()` method to puter-chat-completion. This method, instead of returning only the names of supported models, includes other details such as the cost and maximum output size. Implements `models()` on Claude and XAI. Registers Claude and XAI with AIChatService. --- .../src/modules/puterai/AIChatService.js | 130 ++++++++++++++++++ .../src/modules/puterai/AIInterfaceService.js | 5 + .../src/modules/puterai/AITestModeService.js | 2 +- .../src/modules/puterai/ClaudeService.js | 63 ++++++++- .../src/modules/puterai/FakeChatService.js | 20 ++- .../puterai/OpenAICompletionService.js | 6 - .../src/modules/puterai/PuterAIModule.js | 3 + src/backend/src/modules/puterai/XAIService.js | 36 ++++- .../src/services/drivers/DriverService.js | 33 ++++- src/backend/src/util/context.js | 3 + 10 files changed, 276 insertions(+), 25 deletions(-) create mode 100644 src/backend/src/modules/puterai/AIChatService.js diff --git a/src/backend/src/modules/puterai/AIChatService.js b/src/backend/src/modules/puterai/AIChatService.js new file mode 100644 index 0000000000..f634760350 --- /dev/null +++ b/src/backend/src/modules/puterai/AIChatService.js @@ -0,0 +1,130 @@ +const BaseService = require("../../services/BaseService"); +const { Context } = require("../../util/context"); + +class AIChatService extends BaseService { + _construct () { + this.providers = []; + + this.simple_model_list = []; + this.detail_model_list = []; + this.detail_model_map = {}; + } + _init () { + const svc_driver = this.services.get('driver') + + for ( const provider of this.providers ) { + svc_driver.register_service_alias('ai-chat', provider.service_name); + } + } + + async ['__on_boot.consolidation'] () { + // TODO: get models and pricing for each model + for ( const provider of this.providers ) { + const delegate = this.services.get(provider.service_name) + .as('puter-chat-completion'); + + // Populate simple model list + { + const models = await delegate.list(); + this.simple_model_list.push(...models); + } + + // Populate detail model list and map + { + const models = await delegate.models(); + const annotated_models = []; + for ( const model of models ) { + annotated_models.push({ + ...model, + provider: provider.service_name, + }); + } + this.detail_model_list.push(...annotated_models); + for ( const model of annotated_models ) { + if ( this.detail_model_map[model.id] ) { + let array = this.detail_model_map[model.id]; + // replace with array + if ( ! Array.isArray(array) ) { + array = [array]; + this.detail_model_map[model.id] = array; + } + + array.push(model); + continue; + } + + this.detail_model_map[model.id] = model; + } + } + } + } + + register_provider (spec) { + this.providers.push(spec); + } + + static IMPLEMENTS = { + ['driver-capabilities']: { + supports_test_mode (iface, method_name) { + return iface === 'puter-chat-completion' && + method_name === 'complete'; + } + }, + ['puter-chat-completion']: { + async models () { + const delegate = this.get_delegate(); + if ( ! delegate ) return await this.models_(); + return await delegate.models(); + }, + async list () { + const delegate = this.get_delegate(); + if ( ! delegate ) return await this.list_(); + return await delegate.list(); + }, + async complete (parameters) { + const client_driver_call = Context.get('client_driver_call'); + const { test_mode } = client_driver_call; + let { intended_service } = client_driver_call; + + if ( test_mode ) { + intended_service = 'fake-chat'; + } + + if ( intended_service === this.service_name ) { + throw new Error('Calling ai-chat directly is not yet supported'); + } + + const svc_driver = this.services.get('driver'); + const ret = await svc_driver.call_new_({ + actor: Context.get('actor'), + service_name: intended_service, + iface: 'puter-chat-completion', + method: 'complete', + args: parameters, + }); + ret.result.via_ai_chat_service = true; + return ret.result; + } + } + } + + async models_ () { + return this.detail_model_list; + } + + async list_ () { + return this.simple_model_list; + } + + get_delegate () { + const client_driver_call = Context.get('client_driver_call'); + if ( client_driver_call.intended_service === this.service_name ) { + return undefined; + } + console.log('getting service', client_driver_call.intended_service); + const service = this.services.get(client_driver_call.intended_service); + return service.as('puter-chat-completion'); + } +} + +module.exports = { AIChatService }; diff --git a/src/backend/src/modules/puterai/AIInterfaceService.js b/src/backend/src/modules/puterai/AIInterfaceService.js index bd0d908325..17052cbdae 100644 --- a/src/backend/src/modules/puterai/AIInterfaceService.js +++ b/src/backend/src/modules/puterai/AIInterfaceService.js @@ -28,6 +28,11 @@ class AIInterfaceService extends BaseService { col_interfaces.set('puter-chat-completion', { description: 'Chatbot.', methods: { + models: { + description: 'List supported models and their details.', + result: { type: 'json' }, + parameters: {}, + }, list: { description: 'List supported models', result: { type: 'json' }, diff --git a/src/backend/src/modules/puterai/AITestModeService.js b/src/backend/src/modules/puterai/AITestModeService.js index 64289acae1..97dbfc385e 100644 --- a/src/backend/src/modules/puterai/AITestModeService.js +++ b/src/backend/src/modules/puterai/AITestModeService.js @@ -3,7 +3,7 @@ const BaseService = require("../../services/BaseService"); class AITestModeService extends BaseService { async _init () { const svc_driver = this.services.get('driver'); - svc_driver.register_test_service('puter-chat-completion', 'openai-completion'); + svc_driver.register_test_service('puter-chat-completion', 'ai-chat'); } } diff --git a/src/backend/src/modules/puterai/ClaudeService.js b/src/backend/src/modules/puterai/ClaudeService.js index 33efd5a5e7..f302a1dd3b 100644 --- a/src/backend/src/modules/puterai/ClaudeService.js +++ b/src/backend/src/modules/puterai/ClaudeService.js @@ -22,17 +22,29 @@ class ClaudeService extends BaseService { this.anthropic = new Anthropic({ apiKey: this.config.apiKey }); + + const svc_aiChat = this.services.get('ai-chat'); + svc_aiChat.register_provider({ + service_name: this.service_name, + alias: true, + }); } static IMPLEMENTS = { ['puter-chat-completion']: { + async models () { + return await this.models_(); + }, async list () { - return [ - 'claude-3-5-sonnet-latest', - 'claude-3-5-sonnet-20241022', - 'claude-3-5-sonnet-20240620', - 'claude-3-haiku-20240307', - ]; + const models = await this.models_(); + const model_names = []; + for ( const model of models ) { + model_names.push(model.id); + if ( model.aliases ) { + model_names.push(...model.aliases); + } + } + return model_names; }, async complete ({ messages, stream, model }) { const adapted_messages = []; @@ -112,6 +124,45 @@ class ClaudeService extends BaseService { } } } + + async models_ () { + return [ + { + id: 'claude-3-5-sonnet-20241022', + aliases: ['claude-3-5-sonnet-latest'], + cost: { + currency: 'usd-cents', + tokens: 1_000_000, + input: 300, + output: 1500, + }, + qualitative_speed: 'fast', + max_output: 8192, + training_cutoff: '2024-04', + }, + { + id: 'claude-3-5-sonnet-20240620', + succeeded_by: 'claude-3-5-sonnet-20241022', + cost: { + currency: 'usd-cents', + tokens: 1_000_000, + input: 300, + output: 1500, + }, + }, + { + id: 'claude-3-haiku-20240307', + // aliases: ['claude-3-haiku-latest'], + cost: { + currency: 'usd-cents', + tokens: 1_000_000, + input: 25, + output: 125, + }, + qualitative_speed: 'fastest', + }, + ]; + } } module.exports = { diff --git a/src/backend/src/modules/puterai/FakeChatService.js b/src/backend/src/modules/puterai/FakeChatService.js index 915d390059..500f9d7d5b 100644 --- a/src/backend/src/modules/puterai/FakeChatService.js +++ b/src/backend/src/modules/puterai/FakeChatService.js @@ -7,7 +7,19 @@ class FakeChatService extends BaseService { return ['fake']; }, async complete ({ messages, stream, model }) { + const { LoremIpsum } = require('lorem-ipsum'); + const li = new LoremIpsum({ + sentencesPerParagraph: { + max: 8, + min: 4 + }, + wordsPerSentence: { + max: 20, + min: 12 + }, + }); return { + "index": 0, message: { "id": "00000000-0000-0000-0000-000000000000", "type": "message", @@ -16,7 +28,9 @@ class FakeChatService extends BaseService { "content": [ { "type": "text", - "text": "I am a fake AI, I don't know how to respond to anything." + "text": li.generateParagraphs( + Math.floor(Math.random() * 3) + 1 + ) } ], "stop_reason": "end_turn", @@ -25,7 +39,9 @@ class FakeChatService extends BaseService { "input_tokens": 0, "output_tokens": 1 } - } + }, + "logprobs": null, + "finish_reason": "stop" } } } diff --git a/src/backend/src/modules/puterai/OpenAICompletionService.js b/src/backend/src/modules/puterai/OpenAICompletionService.js index 5c4fc1f076..7c170fe317 100644 --- a/src/backend/src/modules/puterai/OpenAICompletionService.js +++ b/src/backend/src/modules/puterai/OpenAICompletionService.js @@ -22,12 +22,6 @@ class OpenAICompletionService extends BaseService { } static IMPLEMENTS = { - ['driver-capabilities']: { - supports_test_mode (iface, method_name) { - return iface === 'puter-chat-completion' && - method_name === 'complete'; - } - }, ['puter-chat-completion']: { async list () { return [ diff --git a/src/backend/src/modules/puterai/PuterAIModule.js b/src/backend/src/modules/puterai/PuterAIModule.js index 81f8279b51..8844592df9 100644 --- a/src/backend/src/modules/puterai/PuterAIModule.js +++ b/src/backend/src/modules/puterai/PuterAIModule.js @@ -57,6 +57,9 @@ class PuterAIModule extends AdvancedBase { // services.registerService('claude', ClaudeEnoughService); } + const { AIChatService } = require('./AIChatService'); + services.registerService('ai-chat', AIChatService); + const { FakeChatService } = require('./FakeChatService'); services.registerService('fake-chat', FakeChatService); diff --git a/src/backend/src/modules/puterai/XAIService.js b/src/backend/src/modules/puterai/XAIService.js index e5a8febbd4..44f584261a 100644 --- a/src/backend/src/modules/puterai/XAIService.js +++ b/src/backend/src/modules/puterai/XAIService.js @@ -31,14 +31,29 @@ class XAIService extends BaseService { apiKey: this.global_config.services.xai.apiKey, baseURL: 'https://api.x.ai' }); + + const svc_aiChat = this.services.get('ai-chat'); + svc_aiChat.register_provider({ + service_name: this.service_name, + alias: true, + }); } static IMPLEMENTS = { ['puter-chat-completion']: { + async models () { + return await this.models_(); + }, async list () { - return [ - 'grok-beta', - ]; + const models = await this.models_(); + const model_names = []; + for ( const model of models ) { + model_names.push(model.id); + if ( model.aliases ) { + model_names.push(...model.aliases); + } + } + return model_names; }, async complete ({ messages, stream, model }) { model = this.adapt_model(model); @@ -121,6 +136,21 @@ class XAIService extends BaseService { } } } + + async models_ () { + return [ + { + id: 'grok-beta', + name: 'Grok Beta', + cost: { + currency: 'usd-cents', + tokens: 1_000_000, + input: 500, + output: 1500, + }, + } + ]; + } } module.exports = { diff --git a/src/backend/src/services/drivers/DriverService.js b/src/backend/src/services/drivers/DriverService.js index c9220b67b1..52a5ed7dab 100644 --- a/src/backend/src/services/drivers/DriverService.js +++ b/src/backend/src/services/drivers/DriverService.js @@ -38,6 +38,7 @@ class DriverService extends BaseService { this.drivers = {}; this.interface_to_implementation = {}; this.interface_to_test_service = {}; + this.service_aliases = {}; } async ['__on_registry.collections'] () { @@ -82,6 +83,10 @@ class DriverService extends BaseService { register_test_service (interface_name, service_name) { this.interface_to_test_service[interface_name] = service_name; } + + register_service_alias (service_name, alias) { + this.service_aliases[alias] = service_name; + } get_interface (interface_name) { const o = {}; @@ -152,6 +157,12 @@ class DriverService extends BaseService { driver = this.interface_to_test_service[iface]; } + const client_driver_call = { + intended_service: driver, + test_mode, + }; + driver = this.service_aliases[driver] ?? driver; + const driver_service_exists = (() => { console.log('CHECKING FOR THIS', driver, iface); return this.services.has(driver) && @@ -165,13 +176,17 @@ class DriverService extends BaseService { if ( test_mode && caps && caps.supports_test_mode(iface, method) ) { skip_usage = true; } - - return await this.call_new_({ - actor, - service, - service_name: driver, - iface, method, args: processed_args, - skip_usage, + + return await Context.sub({ + client_driver_call, + }).arun(async () => { + return await this.call_new_({ + actor, + service, + service_name: driver, + iface, method, args: processed_args, + skip_usage, + }); }); } @@ -261,6 +276,10 @@ class DriverService extends BaseService { iface, method, args, skip_usage, }) { + if ( ! service ) { + service = this.services.get(service_name); + } + const svc_permission = this.services.get('permission'); const reading = await svc_permission.scan( actor, diff --git a/src/backend/src/util/context.js b/src/backend/src/util/context.js index cf68cb4caf..552c64cb36 100644 --- a/src/backend/src/util/context.js +++ b/src/backend/src/util/context.js @@ -63,6 +63,9 @@ class Context { static arun (cb) { return this.get().arun(cb); } + static sub (values, opt_name) { + return this.get().sub(values, opt_name); + } get (k) { return this.values_[k]; } From 53e00bec4f5a9de6b1fdcbe5c7c4da153d920b89 Mon Sep 17 00:00:00 2001 From: Titus Date: Fri, 22 Nov 2024 23:50:30 +0200 Subject: [PATCH 1316/2119] Update ro.js --- src/gui/src/i18n/translations/ro.js | 31 +++++++++++++---------------- 1 file changed, 14 insertions(+), 17 deletions(-) diff --git a/src/gui/src/i18n/translations/ro.js b/src/gui/src/i18n/translations/ro.js index 6086b726ff..8b6870c1e2 100644 --- a/src/gui/src/i18n/translations/ro.js +++ b/src/gui/src/i18n/translations/ro.js @@ -344,23 +344,20 @@ const ro = { login2fa_recovery_back: "Înapoi", login2fa_recovery_placeholder: "XXXXXXXX", - // *********************************** - // Missing translations - // *********************************** - "change": undefined, // In English: "Change" - "clock_visibility": undefined, // In English: "Clock Visibility" - "reading": undefined, // In English: "Reading %strong%" - "writing": undefined, // In English: "Writing %strong%" - "unzipping": undefined, // In English: "Unzipping %strong%" - "sequencing": undefined, // In English: "Sequencing %strong%" - "zipping": undefined, // In English: "Zipping %strong%" - "Editor": undefined, // In English: "Editor" - "Viewer": undefined, // In English: "Viewer" - "People with access": undefined, // In English: "People with access" - "Share With…": undefined, // In English: "Share With…" - "Owner": undefined, // In English: "Owner" - "You can't share with yourself.": undefined, // In English: "You can't share with yourself." - "This user already has access to this item": undefined, // In English: "This user already has access to this item" + change: "Schimbǎ", + clock_visibility: "Vizibilitatea Ceasului", + reading: "Citire %strong%", + writing: "Scriere %strong%", + unzipping: "Dezarhivare %strong%", + sequencing: "Segvențiere %strong%", + zipping: "Arhivare %strong%", + Editor: "Editor", + Viewer: "Privitor", + "People with access": "Persoane cu acces", + "Share With…": "Partajare cu…", // In Romanian "partajare" is not that used, we use the verb "a împărți" but all apps seem to translate "share" to "partajare" + Owner: "Proprietar", + "You can't share with yourself.": "Nu poți partaja cu tine însuți.", // In English: "You can't share with yourself." + "This user already has access to this item": "Acest utilizator are deja acces la acest element", } } From 3ed1453939a25eb3c0a541318a79f4e822084ea8 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 22 Nov 2024 17:21:40 -0500 Subject: [PATCH 1317/2119] tool: token count testing --- tools/token-count-accuracy/package.json | 12 ++ tools/token-count-accuracy/test.js | 166 ++++++++++++++++++++++++ 2 files changed, 178 insertions(+) create mode 100644 tools/token-count-accuracy/package.json create mode 100644 tools/token-count-accuracy/test.js diff --git a/tools/token-count-accuracy/package.json b/tools/token-count-accuracy/package.json new file mode 100644 index 0000000000..136b486887 --- /dev/null +++ b/tools/token-count-accuracy/package.json @@ -0,0 +1,12 @@ +{ + "name": "token-count-accuracy", + "version": "1.0.0", + "main": "test.js", + "scripts": { + "test": "echo \"Error: no test specified\" && exit 1" + }, + "keywords": [], + "author": "", + "license": "AGPL-3.0-only", + "description": "" +} diff --git a/tools/token-count-accuracy/test.js b/tools/token-count-accuracy/test.js new file mode 100644 index 0000000000..413d963e9f --- /dev/null +++ b/tools/token-count-accuracy/test.js @@ -0,0 +1,166 @@ +const claude_examples = [ + { + type: 'output', // probably doesn't matter + text: "I am Claude, an AI assistant created by Anthropic. I'm running on Puter, an open-source platform, through a driver interface called puter-chat-completion. I aim to be direct and honest about my identity and capabilities.", + tokens: 55, + }, + { + type: 'output', + text: `Here's a list of fascinating numbers and their significance: + +1. 1.618033988749895 (φ, Phi, Golden Ratio) +- Found throughout nature and art +- Considered aesthetically pleasing +- Appears in the proportions of the Parthenon, nautilus shells, and spiral galaxies + +2. 2.71828... (e, Euler's Number) +- Base of natural logarithms +- Fundamental to exponential growth and decay +- Essential in compound interest calculations + +3. 3.14159... (π, Pi) +- Ratio of circle's circumference to diameter +- Transcendental number +- Appears across mathematics and physics + +4. 6.02214076 × 10²³ (Avogadro's Number) +- Number of particles in one mole of substance +- Fundamental to chemistry +- Named after Italian scientist Amedeo Avogadro + +5. 137 (Fine Structure Constant) +- Describes strength of electromagnetic interaction +- Mysterious number in physics +- No theoretical explanation for its value + +6. 1729 (Hardy-Ramanujan Number) +- Smallest number expressible as sum of two cubes in two different ways +- Famous from conversation between mathematicians Hardy and Ramanujan + +7. 42 +- Answer to "life, the universe, and everything" in Hitchhiker's Guide to the Galaxy +- Has gained cultural significance +- Interestingly appears in various mathematical contexts + +8. 0.577215... (γ, Euler-Mascheroni Constant) +- Appears in number theory and calculus +- Still unknown if it's irrational +- Connected to harmonic series + +9. 23! (Factorial of 23) +- Approximately equal to all seconds since Big Bang +- Shows how quickly factorial numbers grow + +10. 666 (Number of the Beast) +- Cultural and religious significance +- Appears in Book of Revelation +- Subject of numerous mathematical curiosities + +These numbers demonstrate how mathematics intersects with nature, science, culture, and human understanding of the universe.`, + tokens: 481, + }, + { + type: 'output', + text: `Here are some digits of Pi: +3.14159265358979323846264338327950288419716939937510... + +Some digits of the square root of 2: +1.41421356237309504880168872420969807856967187537694... + +And now for some random unpredictable things: + +Purple elephants juggling quantum calculators in zero gravity +The sound of silence tastes like neon butterflies +Yesterday's tomorrow forgot to attend its own birthday party +Clouds made of crystallized laughter are floating upside down +The number 7 decided to identify as a letter instead +Spinning teacups full of liquid starlight and abstract concepts +Time decided to flow sideways through a Klein bottle +Philosophical zombies debating the existence of consciousness while eating imaginary cookies +The color blue went on strike and was temporarily replaced by the smell of nostalgia +Dancing fractals wearing mismatched socks made of pure mathematics +A parade of impossible objects marching through an Escher painting +The concept of Tuesday learned to yodel in binary code +Metaphysical hiccups causing temporary glitches in the fabric of reason +Square circles plotting a revolution against euclidean geometry +The letter Q eloped with an ampersand and they had punctuation mark babies`, + tokens: 284, + } +]; + +// Measure each with tiktoken + +class TikTokenCounter { + constructor (model_to_try) { + this.model_to_try = model_to_try; + } + + get title () { + return `TikToken ${this.model_to_try}`; + } + + count (text) { + const tiktoken = require('tiktoken'); + const enc = tiktoken.encoding_for_model(this.model_to_try); + const tokens = enc.encode(text); + return tokens.length; + } +} + +class DivideCounter { + constructor (by) { + this.by = by; + } + + get title () { + return `Divide by ${this.by}`; + } + + count (text) { + return text.length / this.by; + } +} + +const counters_to_try = [ + new TikTokenCounter('gpt-3.5-turbo'), + new TikTokenCounter('gpt-4'), + new TikTokenCounter('gpt-4o'), + new TikTokenCounter('gpt-4o-mini'), + new DivideCounter(4), + new DivideCounter(5), +]; + +const scores = {}; + +const results = []; +for (const example of claude_examples) { + const result = { + example, + counts: {}, + diffs: {}, + }; + for (const counter of counters_to_try) { + result.counts[counter.title] = counter.count(example.text); + } + results.push(result); + + // Which one is the most accurate? + const real_amount = example.tokens; + for ( const count_name in result.counts ) { + const count = result.counts[count_name]; + const diff = Math.abs(count - real_amount); + result.diffs[count_name] = diff; + } + // Report the most accurate one + const most_accurate = + Object.keys(result.diffs) + .reduce((a, b) => result.diffs[a] < result.diffs[b] ? a : b); + result.most_accurate = most_accurate; + + scores[most_accurate] = (scores[most_accurate] || 0) + 1; +} + + +console.log(results); + +console.log(scores); \ No newline at end of file From 791c6f11f49a0391c2ebd1a00abef33086c50902 Mon Sep 17 00:00:00 2001 From: KernelDeimos Date: Fri, 22 Nov 2024 17:42:01 -0500 Subject: [PATCH 1318/2119] dev: max tokens for claude --- .../src/modules/puterai/ClaudeService.js | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/src/backend/src/modules/puterai/ClaudeService.js b/src/backend/src/modules/puterai/ClaudeService.js index f302a1dd3b..61e3ac29fa 100644 --- a/src/backend/src/modules/puterai/ClaudeService.js +++ b/src/backend/src/modules/puterai/ClaudeService.js @@ -3,6 +3,7 @@ const BaseService = require("../../services/BaseService"); const { whatis } = require("../../util/langutil"); const { PassThrough } = require("stream"); const { TypedValue } = require("../../services/drivers/meta/Runtime"); +const APIError = require("../../api/APIError"); const PUTER_PROMPT = ` You are running on an open-source platform called Puter, @@ -13,6 +14,8 @@ const PUTER_PROMPT = ` user of the driver interface (typically an app on Puter): `.replace('\n', ' ').trim(); +const MAX_CLAUDE_INPUT_TOKENS = 10000; + class ClaudeService extends BaseService { static MODULES = { Anthropic: require('@anthropic-ai/sdk'), @@ -78,6 +81,21 @@ class ClaudeService extends BaseService { previous_was_user = true; } } + + const token_count = (() => { + const text = JSON.stringify(adapted_messages) + + JSON.stringify(system_prompts); + + // This is the most accurate token counter available for Claude. + return text.length / 4; + })(); + + if ( token_count > MAX_CLAUDE_INPUT_TOKENS ) { + throw APIError.create('max_tokens_exceeded', null, { + input_tokens: token_count, + max_tokens: MAX_CLAUDE_INPUT_TOKENS, + }); + } if ( stream ) { const stream = new PassThrough(); From be36d31509280340e2a62a8c478b1e64617792a4 Mon Sep 17 00:00:00 2001 From: jelveh Date: Fri, 22 Nov 2024 17:59:00 -0800 Subject: [PATCH 1319/2119] feat: allow developers to set social media images for their apps --- package-lock.json | 8 ++ src/backend/src/routers/_default.js | 9 +- .../src/services/PuterHomepageService.js | 19 ++- src/dev-center/css/style.css | 52 ++++++++- src/dev-center/js/dev-center.js | 110 +++++++++++++++++- src/gui/src/helpers.js | 1 + 6 files changed, 191 insertions(+), 8 deletions(-) diff --git a/package-lock.json b/package-lock.json index 180da676d4..be5e681704 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16100,6 +16100,10 @@ "node": ">=0.6" } }, + "node_modules/token-count-accuracy": { + "resolved": "tools/token-count-accuracy", + "link": true + }, "node_modules/token-types": { "version": "5.0.1", "resolved": "https://registry.npmjs.org/token-types/-/token-types-5.0.1.tgz", @@ -17727,6 +17731,10 @@ "engines": { "node": ">=18" } + }, + "tools/token-count-accuracy": { + "version": "1.0.0", + "license": "AGPL-3.0-only" } } } diff --git a/src/backend/src/routers/_default.js b/src/backend/src/routers/_default.js index 085a81edc7..ba1c1271fd 100644 --- a/src/backend/src/routers/_default.js +++ b/src/backend/src/routers/_default.js @@ -298,7 +298,7 @@ router.all('*', async function(req, res, next) { // ------------------------ else{ let canonical_url = config.origin + path; - let app_name, app_title, app_description, app_icon; + let app_name, app_title, app_description, app_icon, app_social_media_image; let launch_options = { on_initialized: [] }; @@ -318,10 +318,16 @@ router.all('*', async function(req, res, next) { else if(path.startsWith('/app/')){ app_name = path.replace('/app/', ''); const app = await get_app({name: app_name}); + + if(app){ + // parse app metadata if available + app.metadata = app.metadata ? JSON.parse(app.metadata) : {}; + // set app attributes to be passed to the homepage service app_title = app.title; app_description = app.description; app_icon = app.icon; + app_social_media_image = app.metadata?.social_image; } // 404 - Not found! else if(app_name){ @@ -359,6 +365,7 @@ router.all('*', async function(req, res, next) { title: app_title, description: app_description || config.short_description, short_description: app_description || config.short_description, + social_media_image: app_social_media_image || config.social_media_image, company: 'Puter Technologies Inc.', canonical_url: canonical_url, icon: app_icon, diff --git a/src/backend/src/services/PuterHomepageService.js b/src/backend/src/services/PuterHomepageService.js index 33f65b71e9..32e7758e32 100644 --- a/src/backend/src/services/PuterHomepageService.js +++ b/src/backend/src/services/PuterHomepageService.js @@ -18,6 +18,7 @@ */ const { PathBuilder } = require("../util/pathutil"); const BaseService = require("./BaseService"); +const {is_valid_url} = require('../helpers'); /** * PuterHomepageService serves the initial HTML page that loads the Puter GUI @@ -147,6 +148,7 @@ class PuterHomepageService extends BaseService { short_description, company, canonical_url, + social_media_image, icon, } = meta; @@ -168,7 +170,18 @@ class PuterHomepageService extends BaseService { const bundled = env != 'dev' || use_bundled_gui; - const icon_url = icon || `${asset_dir}/images/screenshot.png`; + // if social media image is not a valid absolute URL, set it to null + if (social_media_image && !is_valid_url(social_media_image)) { + social_media_image = null; + } + + // social media image must end with a valid image extension + if (social_media_image && !/\.(png|jpg|jpeg|gif|webp)$/.test(social_media_image.toLowerCase())) { + social_media_image = null; + } + + // set social media image to default if it is not valid + const social_media_image_url = social_media_image || `${asset_dir}/images/screenshot.png`; const writeScriptTag = path => ` + From 73d7152652a914ec54d5a6b1e374f29ff520a740 Mon Sep 17 00:00:00 2001 From: Austin Hamilton Date: Wed, 27 Nov 2024 20:01:00 -0700 Subject: [PATCH 1400/2119] Added german translation --- src/gui/src/i18n/translations/de.js | 30 ++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/src/gui/src/i18n/translations/de.js b/src/gui/src/i18n/translations/de.js index e5b7008238..c2b1f16e7f 100644 --- a/src/gui/src/i18n/translations/de.js +++ b/src/gui/src/i18n/translations/de.js @@ -349,21 +349,21 @@ const de = { // *********************************** // Missing translations // *********************************** - "change": undefined, // In English: "Change" - "clock_visibility": undefined, // In English: "Clock Visibility" - "confirm": undefined, // In English: "Confirm" - "reading": undefined, // In English: "Reading %strong%" - "writing": undefined, // In English: "Writing %strong%" - "unzipping": undefined, // In English: "Unzipping %strong%" - "sequencing": undefined, // In English: "Sequencing %strong%" - "zipping": undefined, // In English: "Zipping %strong%" - "Editor": undefined, // In English: "Editor" - "Viewer": undefined, // In English: "Viewer" - "People with access": undefined, // In English: "People with access" - "Share With…": undefined, // In English: "Share With…" - "Owner": undefined, // In English: "Owner" - "You can't share with yourself.": undefined, // In English: "You can't share with yourself." - "This user already has access to this item": undefined, // In English: "This user already has access to this item" + "change": "Änderung", // In English: "Change" + "clock_visibility": "Uhrensichtbarkeit", // In English: "Clock Visibility" + "confirm": "Bestätigen", // In English: "Confirm" + "reading": "Lesen", // In English: "Reading %strong%" + "writing": "Schreiben", // In English: "Writing %strong%" + "unzipping": "Entpacken", // In English: "Unzipping %strong%" + "sequencing": "Sequenzierung", // In English: "Sequencing %strong%" + "zipping": "Zippen", // In English: "Zipping %strong%" + "Editor": "Editor", // In English: "Editor" + "Viewer": "Zuschauer", // In English: "Viewer" + "People with access": "Personen mit Zugriff", // In English: "People with access" + "Share With…": "Teilen mit...", // In English: "Share With…" + "Owner": "Eigentümer", // In English: "Owner" + "You can't share with yourself.": "Du kannst nicht mit dir selbst teilen.", // In English: "You can't share with yourself." + "This user already has access to this item": "Dieser Benutzer hat bereits Zugriff auf dieses Element.", // In English: "This user already has access to this item" } }; From 8d846d3c37e9ebd77325341fc0fc5db77c531813 Mon Sep 17 00:00:00 2001 From: AmitMaymon <145137599+AmitMaymon@users.noreply.github.com> Date: Thu, 28 Nov 2024 05:01:16 +0200 Subject: [PATCH 1401/2119] Update he.js Translated the unfinished hebrew translation --- src/gui/src/i18n/translations/he.js | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/src/gui/src/i18n/translations/he.js b/src/gui/src/i18n/translations/he.js index 2d485bc67f..66c6f73e62 100644 --- a/src/gui/src/i18n/translations/he.js +++ b/src/gui/src/i18n/translations/he.js @@ -368,20 +368,20 @@ const en = { // *********************************** // Missing translations // *********************************** - "change": undefined, // In English: "Change" - "clock_visibility": undefined, // In English: "Clock Visibility" - "reading": undefined, // In English: "Reading %strong%" - "writing": undefined, // In English: "Writing %strong%" - "unzipping": undefined, // In English: "Unzipping %strong%" - "sequencing": undefined, // In English: "Sequencing %strong%" - "zipping": undefined, // In English: "Zipping %strong%" - "Editor": undefined, // In English: "Editor" - "Viewer": undefined, // In English: "Viewer" - "People with access": undefined, // In English: "People with access" - "Share With…": undefined, // In English: "Share With…" - "Owner": undefined, // In English: "Owner" - "You can't share with yourself.": undefined, // In English: "You can't share with yourself." - "This user already has access to this item": undefined, // In English: "This user already has access to this item" +"change": "שנה", // In English: "Change" +"clock_visibility": "נראות שעון", // In English: "Clock Visibility" +"reading": "קורא %strong%", // In English: "Reading %strong%" +"writing": "כותב %strong%", // In English: "Writing %strong%" +"unzipping": "מחלץ %strong%", // In English: "Unzipping %strong%" +"sequencing": "רצף %strong%", // In English: "Sequencing %strong%" +"zipping": "מכווץ %strong%", // In English: "Zipping %strong%" +"Editor": "עורך", // In English: "Editor" +"Viewer": "צופה", // In English: "Viewer" +"People with access": "אנשים עם גישה", // In English: "People with access" +"Share With…": "שתף עם…", // In English: "Share With…" +"Owner": "בעלים", // In English: "Owner" +"You can't share with yourself.": "אינך יכול לשתף עם עצמך.", // In English: "You can't share with yourself." +"This user already has access to this item": "למשתמש זה כבר יש גישה לפריט זה" // In English: "This user already has access to this item" }, }; From c30f06b0f213bf265bd3f70907c956ad7ce0319b Mon Sep 17 00:00:00 2001 From: jelveh Date: Wed, 27 Nov 2024 19:08:05 -0800 Subject: [PATCH 1402/2119] Update he.js --- src/gui/src/i18n/translations/he.js | 32 +++++++++++++---------------- 1 file changed, 14 insertions(+), 18 deletions(-) diff --git a/src/gui/src/i18n/translations/he.js b/src/gui/src/i18n/translations/he.js index 66c6f73e62..57d356c46c 100644 --- a/src/gui/src/i18n/translations/he.js +++ b/src/gui/src/i18n/translations/he.js @@ -364,24 +364,20 @@ const en = { login2fa_recovery_back: "לאחור", login2fa_recovery_placeholder: "XXXXXXXX", - - // *********************************** - // Missing translations - // *********************************** -"change": "שנה", // In English: "Change" -"clock_visibility": "נראות שעון", // In English: "Clock Visibility" -"reading": "קורא %strong%", // In English: "Reading %strong%" -"writing": "כותב %strong%", // In English: "Writing %strong%" -"unzipping": "מחלץ %strong%", // In English: "Unzipping %strong%" -"sequencing": "רצף %strong%", // In English: "Sequencing %strong%" -"zipping": "מכווץ %strong%", // In English: "Zipping %strong%" -"Editor": "עורך", // In English: "Editor" -"Viewer": "צופה", // In English: "Viewer" -"People with access": "אנשים עם גישה", // In English: "People with access" -"Share With…": "שתף עם…", // In English: "Share With…" -"Owner": "בעלים", // In English: "Owner" -"You can't share with yourself.": "אינך יכול לשתף עם עצמך.", // In English: "You can't share with yourself." -"This user already has access to this item": "למשתמש זה כבר יש גישה לפריט זה" // In English: "This user already has access to this item" + "change": "שנה", // In English: "Change" + "clock_visibility": "נראות שעון", // In English: "Clock Visibility" + "reading": "קורא %strong%", // In English: "Reading %strong%" + "writing": "כותב %strong%", // In English: "Writing %strong%" + "unzipping": "מחלץ %strong%", // In English: "Unzipping %strong%" + "sequencing": "רצף %strong%", // In English: "Sequencing %strong%" + "zipping": "מכווץ %strong%", // In English: "Zipping %strong%" + "Editor": "עורך", // In English: "Editor" + "Viewer": "צופה", // In English: "Viewer" + "People with access": "אנשים עם גישה", // In English: "People with access" + "Share With…": "שתף עם…", // In English: "Share With…" + "Owner": "בעלים", // In English: "Owner" + "You can't share with yourself.": "אינך יכול לשתף עם עצמך.", // In English: "You can't share with yourself." + "This user already has access to this item": "למשתמש זה כבר יש גישה לפריט זה" // In English: "This user already has access to this item" }, }; From 80f3ffa5fa9cb4df3f694ec5885285a529cefd32 Mon Sep 17 00:00:00 2001 From: Austin Hamilton Date: Wed, 27 Nov 2024 20:08:31 -0700 Subject: [PATCH 1403/2119] Added missing placeholders --- src/gui/src/i18n/translations/de.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/gui/src/i18n/translations/de.js b/src/gui/src/i18n/translations/de.js index c2b1f16e7f..a80a4b5286 100644 --- a/src/gui/src/i18n/translations/de.js +++ b/src/gui/src/i18n/translations/de.js @@ -352,18 +352,18 @@ const de = { "change": "Änderung", // In English: "Change" "clock_visibility": "Uhrensichtbarkeit", // In English: "Clock Visibility" "confirm": "Bestätigen", // In English: "Confirm" - "reading": "Lesen", // In English: "Reading %strong%" - "writing": "Schreiben", // In English: "Writing %strong%" - "unzipping": "Entpacken", // In English: "Unzipping %strong%" - "sequencing": "Sequenzierung", // In English: "Sequencing %strong%" - "zipping": "Zippen", // In English: "Zipping %strong%" + "reading": "Lesen %strong%", // In English: "Reading %strong%" + "writing": "Schreiben %strong%", // In English: "Writing %strong%" + "unzipping": "Entpacken %strong%", // In English: "Unzipping %strong%" + "sequencing": "Sequenzierung %strong%", // In English: "Sequencing %strong%" + "zipping": "Zippen %strong%", // In English: "Zipping %strong%" "Editor": "Editor", // In English: "Editor" "Viewer": "Zuschauer", // In English: "Viewer" "People with access": "Personen mit Zugriff", // In English: "People with access" "Share With…": "Teilen mit...", // In English: "Share With…" "Owner": "Eigentümer", // In English: "Owner" "You can't share with yourself.": "Du kannst nicht mit dir selbst teilen.", // In English: "You can't share with yourself." - "This user already has access to this item": "Dieser Benutzer hat bereits Zugriff auf dieses Element.", // In English: "This user already has access to this item" + "This user already has access to this item": "Dieser Benutzer hat bereits Zugriff auf dieses Element", // In English: "This user already has access to this item" } }; From 6bef127c242bc82a923dbf67336edcbd5d233ad1 Mon Sep 17 00:00:00 2001 From: jelveh Date: Wed, 27 Nov 2024 19:13:55 -0800 Subject: [PATCH 1404/2119] Update de.js --- src/gui/src/i18n/translations/de.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/gui/src/i18n/translations/de.js b/src/gui/src/i18n/translations/de.js index a80a4b5286..6f709fa35d 100644 --- a/src/gui/src/i18n/translations/de.js +++ b/src/gui/src/i18n/translations/de.js @@ -346,9 +346,6 @@ const de = { login2fa_recovery_back: 'Zurück', login2fa_recovery_placeholder: 'XXXXXXXX', - // *********************************** - // Missing translations - // *********************************** "change": "Änderung", // In English: "Change" "clock_visibility": "Uhrensichtbarkeit", // In English: "Clock Visibility" "confirm": "Bestätigen", // In English: "Confirm" From bd3571054861d185edec3114cd0580b1b23886e3 Mon Sep 17 00:00:00 2001 From: kingflamez Date: Thu, 28 Nov 2024 08:15:32 +0100 Subject: [PATCH 1405/2119] added missing polish translation --- src/gui/src/i18n/translations/pl.js | 35 +++++++++++++---------------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/src/gui/src/i18n/translations/pl.js b/src/gui/src/i18n/translations/pl.js index d486277b98..f1e98cb7c3 100644 --- a/src/gui/src/i18n/translations/pl.js +++ b/src/gui/src/i18n/translations/pl.js @@ -345,25 +345,22 @@ const pl = { login2fa_use_recovery_code: 'Użyj kod odzyskiwania', login2fa_recovery_back: 'Powrót', login2fa_recovery_placeholder: 'XXXXXXXX', - - // *********************************** - // Missing translations - // *********************************** - "change": undefined, // In English: "Change" - "clock_visibility": undefined, // In English: "Clock Visibility" - "plural_suffix": undefined, // In English: "s" - "reading": undefined, // In English: "Reading %strong%" - "writing": undefined, // In English: "Writing %strong%" - "unzipping": undefined, // In English: "Unzipping %strong%" - "sequencing": undefined, // In English: "Sequencing %strong%" - "zipping": undefined, // In English: "Zipping %strong%" - "Editor": undefined, // In English: "Editor" - "Viewer": undefined, // In English: "Viewer" - "People with access": undefined, // In English: "People with access" - "Share With…": undefined, // In English: "Share With…" - "Owner": undefined, // In English: "Owner" - "You can't share with yourself.": undefined, // In English: "You can't share with yourself." - "This user already has access to this item": undefined, // In English: "This user already has access to this item" + +"change": 'Zmiana', + "clock_visibility": 'Widoczność zegara', + "plural_suffix": undefined, //In polish there is a ton of plural suffixes, so will be left empty eg Samochód (car) → Samochody (cars) and Pies (dog) → Psy (dogs) + "reading": 'Odczyt %strong%', + "writing": 'Pisownia %strong%', + "unzipping": 'Rozpakowanie %strong%', + "sequencing": 'Kolejność %strong%', + "zipping": 'Pakowanie %strong%', + "Editor": 'Edytor', + "Viewer": 'Widz', + "People with access": 'Osoby z dostępem', + "Share With…": 'Podziel się z', + "Owner": 'właściciel', + "You can't share with yourself.": 'Nie możesz dzielić się z samym sobą', + "This user already has access to this item": 'Ten użytkownik ma już dostęp do tego elementu', } }; From 09665a8d7b683d0efa0cea90f0c979c5b5c904d3 Mon Sep 17 00:00:00 2001 From: kingflamez Date: Thu, 28 Nov 2024 08:16:34 +0100 Subject: [PATCH 1406/2119] added missing polish translation --- src/gui/src/i18n/translations/pl.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/gui/src/i18n/translations/pl.js b/src/gui/src/i18n/translations/pl.js index f1e98cb7c3..c1f32c8ea7 100644 --- a/src/gui/src/i18n/translations/pl.js +++ b/src/gui/src/i18n/translations/pl.js @@ -346,7 +346,7 @@ const pl = { login2fa_recovery_back: 'Powrót', login2fa_recovery_placeholder: 'XXXXXXXX', -"change": 'Zmiana', + "change": 'Zmiana', "clock_visibility": 'Widoczność zegara', "plural_suffix": undefined, //In polish there is a ton of plural suffixes, so will be left empty eg Samochód (car) → Samochody (cars) and Pies (dog) → Psy (dogs) "reading": 'Odczyt %strong%', From 63a0053da8c76bf4ac175c7f17353225443dd342 Mon Sep 17 00:00:00 2001 From: ria147 <62183694+ria147@users.noreply.github.com> Date: Fri, 29 Nov 2024 00:30:57 -0500 Subject: [PATCH 1407/2119] feat: enable/disable save button in dev-center iff changes made --- src/dev-center/js/dev-center.js | 77 +++++++++++++++++++++++++++++++-- 1 file changed, 73 insertions(+), 4 deletions(-) diff --git a/src/dev-center/js/dev-center.js b/src/dev-center/js/dev-center.js index 4babab01c8..5e71bd8a18 100644 --- a/src/dev-center/js/dev-center.js +++ b/src/dev-center/js/dev-center.js @@ -29,6 +29,7 @@ let activeTab = 'apps'; let currently_editing_app; let dropped_items; let search_query; +let originalValues = {}; const APP_CATEGORIES = [ { id: 'games', label: 'Games' }, @@ -619,6 +620,69 @@ function generate_edit_app_section(app) { return h; } +/* This function keeps track of the original values of the app before it is edited*/ +function trackOriginalValues(){ + originalValues = { + title: $('#edit-app-title').val(), + name: $('#edit-app-name').val(), + indexURL: $('#edit-app-index-url').val(), + description: $('#edit-app-description').val(), + icon: $('#edit-app-icon').attr('data-url') || $('#edit-app-icon').attr('data-base64'), + fileAssociations: $('#edit-app-filetype-associations').val(), + category: $('#edit-app-category').val(), + socialImage: $('#edit-app-social-image').attr('data-url') || $('#edit-app-social-image').attr('data-base64'), + windowSettings: { + width: $('#edit-app-window-width').val(), + height: $('#edit-app-window-height').val(), + top: $('#edit-app-window-top').val(), + left: $('#edit-app-window-left').val() + }, + checkboxes: { + maximizeOnStart: $('#edit-app-maximize-on-start').is(':checked'), + background: $('#edit-app-background').is(':checked'), + resizableWindow: $('#edit-app-window-resizable').is(':checked'), + hideTitleBar: $('#edit-app-hide-titlebar').is(':checked'), + locked: $('#edit-app-locked').is(':checked'), + credentialless: $('#edit-app-credentialless').is(':checked'), + fullPageOnLanding: $('#edit-app-fullpage-on-landing').is(':checked') + } + }; +} + +/* This function compares for all fields and checks if anything has changed from before editting*/ +function hasChanges() { + return( + $('#edit-app-title').val() !== originalValues.title || + $('#edit-app-name').val() !== originalValues.name || + $('#edit-app-index-url').val() !== originalValues.indexURL || + $('#edit-app-description').val() !== originalValues.description || + ($('#edit-app-icon').attr('data-url') || $('#edit-app-icon').attr('data-base64')) !== originalValues.icon || + $('#edit-app-filetype-associations').val() !== originalValues.fileAssociations || + $('#edit-app-category').val() !== originalValues.category || + ($('#edit-app-social-image').attr('data-url') || $('#edit-app-social-image').attr('data-base64')) !== originalValues.socialImage || + $('#edit-app-window-width').val() !== originalValues.windowSettings.width || + $('#edit-app-window-height').val() !== originalValues.windowSettings.height || + $('#edit-app-window-top').val() !== originalValues.windowSettings.top || + $('#edit-app-window-left').val() !== originalValues.windowSettings.left || + $('#edit-app-maximize-on-start').is(':checked') !== originalValues.checkboxes.maximizeOnStart || + $('#edit-app-background').is(':checked') !== originalValues.checkboxes.background || + $('#edit-app-window-resizable').is(':checked') !== originalValues.checkboxes.resizableWindow || + $('#edit-app-hide-titlebar').is(':checked') !== originalValues.checkboxes.hideTitleBar || + $('#edit-app-locked').is(':checked') !== originalValues.checkboxes.locked || + $('#edit-app-credentialless').is(':checked') !== originalValues.checkboxes.credentialless || + $('#edit-app-fullpage-on-landing').is(':checked') !== originalValues.checkboxes.fullPageOnLanding + ); +} + +/* This function enables or disables the save button if there are any changes made */ +function toggleSaveButton() { + if (hasChanges()) { + $('.edit-app-save-btn').prop('disabled', false); + } else { + $('.edit-app-save-btn').prop('disabled', true); + } +} + async function edit_app_section(cur_app_name) { $('section:not(.sidebar)').hide(); $('.tab-btn').removeClass('active'); @@ -628,8 +692,9 @@ async function edit_app_section(cur_app_name) { currently_editing_app = cur_app; // generate edit app section - let edit_app_section_html = generate_edit_app_section(cur_app); - $('#edit-app').html(edit_app_section_html); + $('#edit-app').html(generate_edit_app_section(cur_app)); + trackOriginalValues(); // Track initial field values + toggleSaveButton(); // Ensure Save button is initially disabled $('#edit-app').show(); // -------------------------------------------------------- @@ -1024,11 +1089,11 @@ $(document).on('click', '.edit-app-save-btn', async function (e) { filetypeAssociations: filetype_associations, }).then(async (app) => { currently_editing_app = app; + trackOriginalValues(); // Update original values after save + toggleSaveButton(); //Disable Save Button after succesful save $('#edit-app-error').hide(); $('#edit-app-success').show(); document.body.scrollTop = document.documentElement.scrollTop = 0; - // Re-enable submit button - $('.edit-app-save-btn').prop('disabled', false); // Update open-app-btn $(`.open-app-btn[data-app-uid="${uid}"]`).attr('data-app-name', app.name); $(`.open-app[data-uid="${uid}"]`).attr('data-app-name', app.name); @@ -1054,6 +1119,10 @@ $(document).on('click', '.edit-app-save-btn', async function (e) { }) }) +$(document).on('input change', '#edit-app input, #edit-app textarea, #edit-app select', () => { + toggleSaveButton(); +}); + $(document).on('click', '.open-app-btn', async function (e) { puter.ui.launchApp($(this).attr('data-app-name')) }) From 55ffd801e007723758eacc17ec732ee5a336123e Mon Sep 17 00:00:00 2001 From: ria147 <62183694+ria147@users.noreply.github.com> Date: Fri, 29 Nov 2024 00:47:40 -0500 Subject: [PATCH 1408/2119] feat: add reset edit changes button to dev-center --- src/dev-center/css/style.css | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/dev-center/css/style.css b/src/dev-center/css/style.css index a6bd686aaa..a5f23f6c89 100644 --- a/src/dev-center/css/style.css +++ b/src/dev-center/css/style.css @@ -951,6 +951,12 @@ ol li:before { margin-top: 20px; margin-bottom: 20px; } +.edit-app-reset-btn{ + float: right; + margin-top: 20px; + margin-bottom: 20px; + margin-right: 10px; +} input:read-only { background-color: rgb(242 242 242); } From e5788b6e47f5c33dd28880d4e24c7b763dde24d8 Mon Sep 17 00:00:00 2001 From: ria147 <62183694+ria147@users.noreply.github.com> Date: Fri, 29 Nov 2024 00:58:09 -0500 Subject: [PATCH 1409/2119] dev: add functionality to reset edit button --- src/dev-center/js/dev-center.js | 47 +++++++++++++++++++++++++++++++++ 1 file changed, 47 insertions(+) diff --git a/src/dev-center/js/dev-center.js b/src/dev-center/js/dev-center.js index 5e71bd8a18..1f7ca7bb45 100644 --- a/src/dev-center/js/dev-center.js +++ b/src/dev-center/js/dev-center.js @@ -614,6 +614,7 @@ function generate_edit_app_section(app) {
+
` @@ -683,6 +684,47 @@ function toggleSaveButton() { } } +/* This function revers the changes made back to the original values of the edit form */ +function resetToOriginalValues() { + $('#edit-app-title').val(originalValues.title); + $('#edit-app-name').val(originalValues.name); + $('#edit-app-index-url').val(originalValues.indexURL); + $('#edit-app-description').val(originalValues.description); + $('#edit-app-filetype-associations').val(originalValues.fileAssociations); + $('#edit-app-category').val(originalValues.category); + $('#edit-app-window-width').val(originalValues.windowSettings.width); + $('#edit-app-window-height').val(originalValues.windowSettings.height); + $('#edit-app-window-top').val(originalValues.windowSettings.top); + $('#edit-app-window-left').val(originalValues.windowSettings.left); + $('#edit-app-maximize-on-start').prop('checked', originalValues.checkboxes.maximizeOnStart); + $('#edit-app-background').prop('checked', originalValues.checkboxes.background); + $('#edit-app-window-resizable').prop('checked', originalValues.checkboxes.resizableWindow); + $('#edit-app-hide-titlebar').prop('checked', originalValues.checkboxes.hideTitleBar); + $('#edit-app-locked').prop('checked', originalValues.checkboxes.locked); + $('#edit-app-credentialless').prop('checked', originalValues.checkboxes.credentialless); + $('#edit-app-fullpage-on-landing').prop('checked', originalValues.checkboxes.fullPageOnLanding); + + if (originalValues.icon) { + $('#edit-app-icon').css('background-image', `url(${originalValues.icon})`); + $('#edit-app-icon').attr('data-url', originalValues.icon); + $('#edit-app-icon-delete').show(); + } else { + $('#edit-app-icon').css('background-image', ''); + $('#edit-app-icon').removeAttr('data-url'); + $('#edit-app-icon').removeAttr('data-base64'); + $('#edit-app-icon-delete').hide(); + } + + if (originalValues.socialImage) { + $('#edit-app-social-image').css('background-image', `url(${originalValues.socialImage})`); + $('#edit-app-social-image').attr('data-url', originalValues.socialImage); + } else { + $('#edit-app-social-image').css('background-image', ''); + $('#edit-app-social-image').removeAttr('data-url'); + $('#edit-app-social-image').removeAttr('data-base64'); + } +} + async function edit_app_section(cur_app_name) { $('section:not(.sidebar)').hide(); $('.tab-btn').removeClass('active'); @@ -1123,6 +1165,11 @@ $(document).on('input change', '#edit-app input, #edit-app textarea, #edit-app s toggleSaveButton(); }); +$(document).on('click', '.edit-app-reset-btn', function () { + resetToOriginalValues(); + toggleSaveButton(); // Disable Save button since values are reverted to original +}); + $(document).on('click', '.open-app-btn', async function (e) { puter.ui.launchApp($(this).attr('data-app-name')) }) From 3f1804eb2ae1f304e20437676d160e6fb85298fb Mon Sep 17 00:00:00 2001 From: ria147 <62183694+ria147@users.noreply.github.com> Date: Fri, 29 Nov 2024 01:03:53 -0500 Subject: [PATCH 1410/2119] dev: enable/disable reset button iff changes are made --- src/dev-center/js/dev-center.js | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/dev-center/js/dev-center.js b/src/dev-center/js/dev-center.js index 1f7ca7bb45..3f2c3ea151 100644 --- a/src/dev-center/js/dev-center.js +++ b/src/dev-center/js/dev-center.js @@ -684,6 +684,15 @@ function toggleSaveButton() { } } +/* This function enables or disables the reset button if there are any changes made */ +function toggleResetButton() { + if (hasChanges()) { + $('.edit-app-reset-btn').prop('disabled', false); + } else { + $('.edit-app-reset-btn').prop('disabled', true); + } +} + /* This function revers the changes made back to the original values of the edit form */ function resetToOriginalValues() { $('#edit-app-title').val(originalValues.title); @@ -737,6 +746,7 @@ async function edit_app_section(cur_app_name) { $('#edit-app').html(generate_edit_app_section(cur_app)); trackOriginalValues(); // Track initial field values toggleSaveButton(); // Ensure Save button is initially disabled + toggleResetButton(); // Ensure Reset button is initially disabled $('#edit-app').show(); // -------------------------------------------------------- @@ -1133,6 +1143,7 @@ $(document).on('click', '.edit-app-save-btn', async function (e) { currently_editing_app = app; trackOriginalValues(); // Update original values after save toggleSaveButton(); //Disable Save Button after succesful save + toggleResetButton(); //DIsable Reset Button after succesful save $('#edit-app-error').hide(); $('#edit-app-success').show(); document.body.scrollTop = document.documentElement.scrollTop = 0; @@ -1163,11 +1174,13 @@ $(document).on('click', '.edit-app-save-btn', async function (e) { $(document).on('input change', '#edit-app input, #edit-app textarea, #edit-app select', () => { toggleSaveButton(); + toggleResetButton(); }); $(document).on('click', '.edit-app-reset-btn', function () { resetToOriginalValues(); toggleSaveButton(); // Disable Save button since values are reverted to original + toggleResetButton(); //Disable Reset button since values are reverted to original }); $(document).on('click', '.open-app-btn', async function (e) { From 92cd65261e19c6647583533f446a5cc7f133fdaa Mon Sep 17 00:00:00 2001 From: jelveh Date: Fri, 29 Nov 2024 06:53:29 -0800 Subject: [PATCH 1411/2119] also track `icon` and `socialImage` --- src/dev-center/js/dev-center.js | 28 ++++++++++++++++++++++++---- 1 file changed, 24 insertions(+), 4 deletions(-) diff --git a/src/dev-center/js/dev-center.js b/src/dev-center/js/dev-center.js index 3f2c3ea151..bc6517a3f3 100644 --- a/src/dev-center/js/dev-center.js +++ b/src/dev-center/js/dev-center.js @@ -628,10 +628,10 @@ function trackOriginalValues(){ name: $('#edit-app-name').val(), indexURL: $('#edit-app-index-url').val(), description: $('#edit-app-description').val(), - icon: $('#edit-app-icon').attr('data-url') || $('#edit-app-icon').attr('data-base64'), + icon: $('#edit-app-icon').attr('data-base64'), fileAssociations: $('#edit-app-filetype-associations').val(), category: $('#edit-app-category').val(), - socialImage: $('#edit-app-social-image').attr('data-url') || $('#edit-app-social-image').attr('data-base64'), + socialImage: $('#edit-app-social-image').attr('data-base64'), windowSettings: { width: $('#edit-app-window-width').val(), height: $('#edit-app-window-height').val(), @@ -652,15 +652,26 @@ function trackOriginalValues(){ /* This function compares for all fields and checks if anything has changed from before editting*/ function hasChanges() { + // is icon changed + if($('#edit-app-icon').attr('data-base64') !== originalValues.icon){ + return true; + } + + // if social image is changed + if($('#edit-app-social-image').attr('data-base64') !== originalValues.socialImage){ + return true; + } + + // if any of the fields have changed return( $('#edit-app-title').val() !== originalValues.title || $('#edit-app-name').val() !== originalValues.name || $('#edit-app-index-url').val() !== originalValues.indexURL || $('#edit-app-description').val() !== originalValues.description || - ($('#edit-app-icon').attr('data-url') || $('#edit-app-icon').attr('data-base64')) !== originalValues.icon || + $('#edit-app-icon').attr('data-base64') !== originalValues.icon || $('#edit-app-filetype-associations').val() !== originalValues.fileAssociations || $('#edit-app-category').val() !== originalValues.category || - ($('#edit-app-social-image').attr('data-url') || $('#edit-app-social-image').attr('data-base64')) !== originalValues.socialImage || + $('#edit-app-social-image').attr('data-base64') !== originalValues.socialImage || $('#edit-app-window-width').val() !== originalValues.windowSettings.width || $('#edit-app-window-height').val() !== originalValues.windowSettings.height || $('#edit-app-window-top').val() !== originalValues.windowSettings.top || @@ -1334,6 +1345,9 @@ $(document).on('click', '#edit-app-icon-delete', async function (e) { $('#edit-app-icon').removeAttr('data-url'); $('#edit-app-icon').removeAttr('data-base64'); $('#edit-app-icon-delete').hide(); + + toggleSaveButton(); + toggleResetButton(); }) $(document).on('click', '#edit-app-icon', async function (e) { @@ -1360,6 +1374,9 @@ $(document).on('click', '#edit-app-icon', async function (e) { $('#edit-app-icon').css('background-image', `url(${image})`); $('#edit-app-icon').attr('data-base64', image); $('#edit-app-icon-delete').show(); + + toggleSaveButton(); + toggleResetButton(); } }) @@ -2505,6 +2522,9 @@ $(document).on('click', '#edit-app-social-image', async function(e) { $('#edit-app-social-image').css('background-image', `url(${image})`); $('#edit-app-social-image').attr('data-base64', image); $('#edit-app-social-image-delete').show(); + + toggleSaveButton(); + toggleResetButton(); } }); From 9ba0f2410c795aac982e79e92ae0aad3105d70d1 Mon Sep 17 00:00:00 2001 From: jelveh Date: Fri, 29 Nov 2024 07:16:59 -0800 Subject: [PATCH 1412/2119] set correct base64 value for `icon` and `socialImage` --- src/dev-center/js/dev-center.js | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/dev-center/js/dev-center.js b/src/dev-center/js/dev-center.js index bc6517a3f3..8aa2f44540 100644 --- a/src/dev-center/js/dev-center.js +++ b/src/dev-center/js/dev-center.js @@ -537,7 +537,7 @@ function generate_edit_app_section(app) { -
+
Change App Icon
Remove icon @@ -727,6 +727,7 @@ function resetToOriginalValues() { if (originalValues.icon) { $('#edit-app-icon').css('background-image', `url(${originalValues.icon})`); $('#edit-app-icon').attr('data-url', originalValues.icon); + $('#edit-app-icon').attr('data-base64', originalValues.icon); $('#edit-app-icon-delete').show(); } else { $('#edit-app-icon').css('background-image', ''); @@ -738,6 +739,7 @@ function resetToOriginalValues() { if (originalValues.socialImage) { $('#edit-app-social-image').css('background-image', `url(${originalValues.socialImage})`); $('#edit-app-social-image').attr('data-url', originalValues.socialImage); + $('#edit-app-social-image').attr('data-base64', originalValues.socialImage); } else { $('#edit-app-social-image').css('background-image', ''); $('#edit-app-social-image').removeAttr('data-url'); @@ -2491,7 +2493,7 @@ async function initializeAssetsDirectory() { function generateSocialImageSection(app) { return ` -